feat: add new types module

This commit is contained in:
thunderbiscuit 2023-12-06 11:38:34 -05:00
parent 05ce7dad31
commit 6b177f0893
No known key found for this signature in database
GPG Key ID: 88253696EB836462
6 changed files with 228 additions and 289 deletions

View File

@ -1,7 +1,7 @@
namespace bdk {};
// ------------------------------------------------------------------------
// bdk crate - root module
// bdk crate - types module
// ------------------------------------------------------------------------
enum KeychainKind {
@ -9,6 +9,45 @@ enum KeychainKind {
"Internal",
};
dictionary AddressInfo {
u32 index;
Address address;
KeychainKind keychain;
};
[Enum]
interface AddressIndex {
New();
LastUnused();
Peek(u32 index);
};
dictionary Balance {
u64 immature;
u64 trusted_pending;
u64 untrusted_pending;
u64 confirmed;
u64 trusted_spendable;
u64 total;
};
dictionary LocalUtxo {
OutPoint outpoint;
TxOut txout;
KeychainKind keychain;
boolean is_spent;
};
dictionary TxOut {
u64 value;
Script script_pubkey;
};
// ------------------------------------------------------------------------
// bdk crate - wallet module
// ------------------------------------------------------------------------
@ -49,33 +88,6 @@ enum ChangeSpendPolicy {
"ChangeForbidden"
};
dictionary Balance {
u64 immature;
u64 trusted_pending;
u64 untrusted_pending;
u64 confirmed;
u64 trusted_spendable;
u64 total;
};
dictionary AddressInfo {
u32 index;
Address address;
KeychainKind keychain;
};
[Enum]
interface AddressIndex {
New();
LastUnused();
Peek(u32 index);
};
interface Wallet {
[Name=new_no_persist, Throws=BdkError]
constructor(Descriptor descriptor, Descriptor? change_descriptor, Network network);

View File

@ -1,5 +1,6 @@
use bdk::bitcoin::address::{NetworkChecked, NetworkUnchecked};
use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
use bdk::bitcoin::blockdata::transaction::TxOut as BdkTxOut;
use bdk::bitcoin::consensus::Decodable;
use bdk::bitcoin::network::constants::Network as BdkNetwork;
use bdk::bitcoin::psbt::PartiallySignedTransaction as BdkPartiallySignedTransaction;
@ -309,3 +310,21 @@ impl From<&OutPoint> for BdkOutPoint {
}
}
}
/// A transaction output, which defines new coins to be created from old ones.
#[derive(Debug, Clone)]
pub struct TxOut {
/// The value of the output, in satoshis.
pub value: u64,
/// The address of the output.
pub script_pubkey: Arc<Script>,
}
impl From<&BdkTxOut> for TxOut {
fn from(tx_out: &BdkTxOut) -> Self {
TxOut {
value: tx_out.value,
script_pubkey: Arc::new(Script(tx_out.script_pubkey.clone())),
}
}
}

View File

@ -284,9 +284,12 @@ impl Descriptor {
mod test {
use crate::*;
use assert_matches::assert_matches;
use bdk::descriptor::DescriptorError::Key;
use bdk::keys::KeyError::InvalidNetwork;
use std::sync::Arc;
fn get_descriptor_secret_key() -> DescriptorSecretKey {
let mnemonic = Mnemonic::from_string("chaos fabric time speed sponsor all flat solution wisdom trophy crack object robot pave observe combine where aware bench orient secret primary cable detect".to_string()).unwrap();
DescriptorSecretKey::new(Network::Testnet, Arc::new(mnemonic), None)

View File

@ -2,278 +2,38 @@ mod bitcoin;
mod descriptor;
mod esplora;
mod keys;
mod types;
mod wallet;
// TODO 6: Why are these imports required?
use crate::bitcoin::Address;
use crate::bitcoin::Network;
use crate::bitcoin::OutPoint;
use crate::bitcoin::PartiallySignedTransaction;
use crate::bitcoin::Script;
use crate::bitcoin::Transaction;
use crate::bitcoin::TxOut;
use crate::descriptor::Descriptor;
use crate::esplora::EsploraClient;
use crate::keys::DerivationPath;
use crate::keys::DescriptorPublicKey;
use crate::keys::DescriptorSecretKey;
use crate::keys::Mnemonic;
use crate::types::AddressIndex;
use crate::types::AddressInfo;
use crate::types::Balance;
use crate::types::LocalUtxo;
use crate::types::ScriptAmount;
use crate::wallet::TxBuilder;
use crate::wallet::Update;
use crate::wallet::Wallet;
use bdk::keys::bip39::WordCount;
use bdk::wallet::tx_builder::ChangeSpendPolicy;
use bdk::wallet::AddressIndex as BdkAddressIndex;
use bdk::wallet::AddressInfo as BdkAddressInfo;
use bdk::wallet::Balance as BdkBalance;
use bdk::Error as BdkError;
use bdk::KeychainKind;
use std::sync::Arc;
uniffi::include_scaffolding!("bdk");
/// A output script and an amount of satoshis.
pub struct ScriptAmount {
pub script: Arc<Script>,
pub amount: u64,
}
/// A derived address and the index it was found at.
pub struct AddressInfo {
/// Child index of this address.
pub index: u32,
/// Address.
pub address: Arc<Address>,
/// Type of keychain.
pub keychain: KeychainKind,
}
impl From<BdkAddressInfo> for AddressInfo {
fn from(address_info: BdkAddressInfo) -> Self {
AddressInfo {
index: address_info.index,
address: Arc::new(address_info.address.into()),
keychain: address_info.keychain,
}
}
}
/// The address index selection strategy to use to derived an address from the wallet's external
/// descriptor.
pub enum AddressIndex {
/// Return a new address after incrementing the current descriptor index.
New,
/// Return the address for the current descriptor index if it has not been used in a received
/// transaction. Otherwise return a new address as with AddressIndex::New.
/// Use with caution, if the wallet has not yet detected an address has been used it could
/// return an already used address. This function is primarily meant for situations where the
/// caller is untrusted; for example when deriving donation addresses on-demand for a public
/// web page.
LastUnused,
/// Return the address for a specific descriptor index. Does not change the current descriptor
/// index used by `AddressIndex::New` and `AddressIndex::LastUsed`.
/// Use with caution, if an index is given that is less than the current descriptor index
/// then the returned address may have already been used.
Peek { index: u32 },
}
impl From<AddressIndex> for BdkAddressIndex {
fn from(address_index: AddressIndex) -> Self {
match address_index {
AddressIndex::New => BdkAddressIndex::New,
AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
AddressIndex::Peek { index } => BdkAddressIndex::Peek(index),
}
}
}
// TODO 9: Peek is not correctly implemented
impl From<&AddressIndex> for BdkAddressIndex {
fn from(address_index: &AddressIndex) -> Self {
match address_index {
AddressIndex::New => BdkAddressIndex::New,
AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
AddressIndex::Peek { index } => BdkAddressIndex::Peek(*index),
}
}
}
impl From<BdkAddressIndex> for AddressIndex {
fn from(address_index: BdkAddressIndex) -> Self {
match address_index {
BdkAddressIndex::New => AddressIndex::New,
BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
_ => panic!("Mmmm not working"),
}
}
}
impl From<&BdkAddressIndex> for AddressIndex {
fn from(address_index: &BdkAddressIndex) -> Self {
match address_index {
BdkAddressIndex::New => AddressIndex::New,
BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
_ => panic!("Mmmm not working"),
}
}
}
// /// A wallet transaction
// #[derive(Debug, Clone, PartialEq, Eq, Default)]
// pub struct TransactionDetails {
// pub transaction: Option<Arc<Transaction>>,
// /// Transaction id.
// pub txid: String,
// /// Received value (sats)
// /// Sum of owned outputs of this transaction.
// pub received: u64,
// /// Sent value (sats)
// /// Sum of owned inputs of this transaction.
// pub sent: u64,
// /// Fee value (sats) if confirmed.
// /// The availability of the fee depends on the backend. It's never None with an Electrum
// /// Server backend, but it could be None with a Bitcoin RPC node without txindex that receive
// /// funds while offline.
// pub fee: Option<u64>,
// /// If the transaction is confirmed, contains height and timestamp of the block containing the
// /// transaction, unconfirmed transaction contains `None`.
// pub confirmation_time: Option<BlockTime>,
// }
//
// impl From<BdkTransactionDetails> for TransactionDetails {
// fn from(tx_details: BdkTransactionDetails) -> Self {
// let optional_tx: Option<Arc<Transaction>> =
// tx_details.transaction.map(|tx| Arc::new(tx.into()));
//
// TransactionDetails {
// transaction: optional_tx,
// fee: tx_details.fee,
// txid: tx_details.txid.to_string(),
// received: tx_details.received,
// sent: tx_details.sent,
// confirmation_time: tx_details.confirmation_time,
// }
// }
// }
//
// /// A reference to a transaction output.
// #[derive(Clone, Debug, PartialEq, Eq, Hash)]
// pub struct OutPoint {
// /// The referenced transaction's txid.
// txid: String,
// /// The index of the referenced output in its transaction's vout.
// vout: u32,
// }
//
// impl From<&OutPoint> for BdkOutPoint {
// fn from(outpoint: &OutPoint) -> Self {
// BdkOutPoint {
// txid: Txid::from_str(&outpoint.txid).unwrap(),
// vout: outpoint.vout,
// }
// }
// }
pub struct Balance {
// All coinbase outputs not yet matured
pub immature: u64,
/// Unconfirmed UTXOs generated by a wallet tx
pub trusted_pending: u64,
/// Unconfirmed UTXOs received from an external wallet
pub untrusted_pending: u64,
/// Confirmed and immediately spendable balance
pub confirmed: u64,
/// Get sum of trusted_pending and confirmed coins
pub trusted_spendable: u64,
/// Get the whole balance visible to the wallet
pub total: u64,
}
impl From<BdkBalance> for Balance {
fn from(bdk_balance: BdkBalance) -> Self {
Balance {
immature: bdk_balance.immature,
trusted_pending: bdk_balance.trusted_pending,
untrusted_pending: bdk_balance.untrusted_pending,
confirmed: bdk_balance.confirmed,
trusted_spendable: bdk_balance.trusted_spendable(),
total: bdk_balance.total(),
}
}
}
// /// A transaction output, which defines new coins to be created from old ones.
// #[derive(Debug, Clone)]
// pub struct TxOut {
// /// The value of the output, in satoshis.
// value: u64,
// /// The address of the output.
// script_pubkey: Arc<Script>,
// }
//
// impl From<&BdkTxOut> for TxOut {
// fn from(tx_out: &BdkTxOut) -> Self {
// TxOut {
// value: tx_out.value,
// script_pubkey: Arc::new(Script {
// inner: tx_out.script_pubkey.clone(),
// }),
// }
// }
// }
//
// pub struct LocalUtxo {
// outpoint: OutPoint,
// txout: TxOut,
// keychain: KeychainKind,
// is_spent: bool,
// }
//
// impl From<BdkLocalUtxo> for LocalUtxo {
// fn from(local_utxo: BdkLocalUtxo) -> Self {
// LocalUtxo {
// outpoint: OutPoint {
// txid: local_utxo.outpoint.txid.to_string(),
// vout: local_utxo.outpoint.vout,
// },
// txout: TxOut {
// value: local_utxo.txout.value,
// script_pubkey: Arc::new(Script {
// inner: local_utxo.txout.script_pubkey,
// }),
// },
// keychain: local_utxo.keychain,
// is_spent: local_utxo.is_spent,
// }
// }
// }
//
// /// Trait that logs at level INFO every update received (if any).
// pub trait Progress: Send + Sync + 'static {
// /// Send a new progress update. The progress value should be in the range 0.0 - 100.0, and the message value is an
// /// optional text message that can be displayed to the user.
// fn update(&self, progress: f32, message: Option<String>);
// }
//
// struct ProgressHolder {
// progress: Box<dyn Progress>,
// }
//
// impl BdkProgress for ProgressHolder {
// fn update(&self, progress: f32, message: Option<String>) -> Result<(), BdkError> {
// self.progress.update(progress, message);
// Ok(())
// }
// }
//
// impl Debug for ProgressHolder {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// f.debug_struct("ProgressHolder").finish_non_exhaustive()
// }
// }
//
// #[derive(Debug, Clone)]
// pub struct TxIn {
// pub previous_output: OutPoint,
@ -314,18 +74,6 @@ impl From<BdkBalance> for Balance {
// },
// }
// impl From<BdkScript> for Script {
// fn from(bdk_script: BdkScript) -> Self {
// Script { inner: bdk_script }
// }
// }
//
// #[derive(Clone, Debug)]
// enum RbfValue {
// Default,
// Value(u32),
// }
//
// /// The result after calling the TxBuilder finish() function. Contains unsigned PSBT and
// /// transaction details.
// pub struct TxBuilderResult {

148
bdk-ffi/src/types.rs Normal file
View File

@ -0,0 +1,148 @@
use crate::bitcoin::{Address, OutPoint, Script, TxOut};
use bdk::wallet::AddressIndex as BdkAddressIndex;
use bdk::wallet::AddressInfo as BdkAddressInfo;
use bdk::wallet::Balance as BdkBalance;
use bdk::KeychainKind;
use bdk::LocalUtxo as BdkLocalUtxo;
use std::sync::Arc;
/// A output script and an amount of satoshis.
pub struct ScriptAmount {
pub script: Arc<Script>,
pub amount: u64,
}
/// A derived address and the index it was found at.
pub struct AddressInfo {
/// Child index of this address.
pub index: u32,
/// Address.
pub address: Arc<Address>,
/// Type of keychain.
pub keychain: KeychainKind,
}
impl From<BdkAddressInfo> for AddressInfo {
fn from(address_info: BdkAddressInfo) -> Self {
AddressInfo {
index: address_info.index,
address: Arc::new(address_info.address.into()),
keychain: address_info.keychain,
}
}
}
/// The address index selection strategy to use to derived an address from the wallet's external
/// descriptor.
pub enum AddressIndex {
/// Return a new address after incrementing the current descriptor index.
New,
/// Return the address for the current descriptor index if it has not been used in a received
/// transaction. Otherwise return a new address as with AddressIndex::New.
/// Use with caution, if the wallet has not yet detected an address has been used it could
/// return an already used address. This function is primarily meant for situations where the
/// caller is untrusted; for example when deriving donation addresses on-demand for a public
/// web page.
LastUnused,
/// Return the address for a specific descriptor index. Does not change the current descriptor
/// index used by `AddressIndex::New` and `AddressIndex::LastUsed`.
/// Use with caution, if an index is given that is less than the current descriptor index
/// then the returned address may have already been used.
Peek { index: u32 },
}
impl From<AddressIndex> for BdkAddressIndex {
fn from(address_index: AddressIndex) -> Self {
match address_index {
AddressIndex::New => BdkAddressIndex::New,
AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
AddressIndex::Peek { index } => BdkAddressIndex::Peek(index),
}
}
}
impl From<BdkAddressIndex> for AddressIndex {
fn from(address_index: BdkAddressIndex) -> Self {
match address_index {
BdkAddressIndex::New => AddressIndex::New,
BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
_ => panic!("Mmmm not working"),
}
}
}
// TODO 9: Peek is not correctly implemented
impl From<&AddressIndex> for BdkAddressIndex {
fn from(address_index: &AddressIndex) -> Self {
match address_index {
AddressIndex::New => BdkAddressIndex::New,
AddressIndex::LastUnused => BdkAddressIndex::LastUnused,
AddressIndex::Peek { index } => BdkAddressIndex::Peek(*index),
}
}
}
impl From<&BdkAddressIndex> for AddressIndex {
fn from(address_index: &BdkAddressIndex) -> Self {
match address_index {
BdkAddressIndex::New => AddressIndex::New,
BdkAddressIndex::LastUnused => AddressIndex::LastUnused,
_ => panic!("Mmmm not working"),
}
}
}
pub struct Balance {
// All coinbase outputs not yet matured
pub immature: u64,
/// Unconfirmed UTXOs generated by a wallet tx
pub trusted_pending: u64,
/// Unconfirmed UTXOs received from an external wallet
pub untrusted_pending: u64,
/// Confirmed and immediately spendable balance
pub confirmed: u64,
/// Get sum of trusted_pending and confirmed coins
pub trusted_spendable: u64,
/// Get the whole balance visible to the wallet
pub total: u64,
}
impl From<BdkBalance> for Balance {
fn from(bdk_balance: BdkBalance) -> Self {
Balance {
immature: bdk_balance.immature,
trusted_pending: bdk_balance.trusted_pending,
untrusted_pending: bdk_balance.untrusted_pending,
confirmed: bdk_balance.confirmed,
trusted_spendable: bdk_balance.trusted_spendable(),
total: bdk_balance.total(),
}
}
}
pub struct LocalUtxo {
pub outpoint: OutPoint,
pub txout: TxOut,
pub keychain: KeychainKind,
pub is_spent: bool,
}
impl From<BdkLocalUtxo> for LocalUtxo {
fn from(local_utxo: BdkLocalUtxo) -> Self {
LocalUtxo {
outpoint: OutPoint {
txid: local_utxo.outpoint.txid.to_string(),
vout: local_utxo.outpoint.vout,
},
txout: TxOut {
value: local_utxo.txout.value,
script_pubkey: Arc::new(Script(local_utxo.txout.script_pubkey)),
},
keychain: local_utxo.keychain,
is_spent: local_utxo.is_spent,
}
}
}

View File

@ -1,7 +1,9 @@
use crate::bitcoin::{OutPoint, PartiallySignedTransaction};
use crate::descriptor::Descriptor;
use crate::{AddressIndex, AddressInfo, Network, ScriptAmount};
use crate::{Balance, Script};
use crate::types::Balance;
use crate::types::ScriptAmount;
use crate::Script;
use crate::{AddressIndex, AddressInfo, Network};
use std::collections::HashSet;
use bdk::bitcoin::blockdata::script::ScriptBuf as BdkScriptBuf;
@ -11,6 +13,7 @@ use bdk::{Error as BdkError, FeeRate};
use bdk::{SignOptions, Wallet as BdkWallet};
use bdk::wallet::tx_builder::ChangeSpendPolicy;
use std::sync::{Arc, Mutex, MutexGuard};
#[derive(Debug)]
@ -609,6 +612,12 @@ impl TxBuilder {
// }
// }
// #[derive(Clone, Debug)]
// enum RbfValue {
// Default,
// Value(u32),
// }
// // The goal of these tests to to ensure `bdk-ffi` intermediate code correctly calls `bdk` APIs.
// // These tests should not be used to verify `bdk` behavior that is already tested in the `bdk`
// // crate.