diff --git a/src/bitcoin/wallet.rs b/src/bitcoin/wallet.rs index aff8c38..169d6c2 100644 --- a/src/bitcoin/wallet.rs +++ b/src/bitcoin/wallet.rs @@ -7,7 +7,8 @@ use wasm_bindgen::{prelude::wasm_bindgen, JsError}; use crate::{ result::JsResult, types::{ - AddressInfo, Balance, ChangeSet, CheckPoint, FullScanRequest, KeychainKind, Network, Psbt, SyncRequest, Update, + AddressInfo, Balance, ChangeSet, CheckPoint, FullScanRequest, KeychainKind, LocalOutput, Network, Psbt, + SyncRequest, Update, }, }; @@ -104,10 +105,18 @@ impl Wallet { .collect() } + pub fn list_unspent(&self) -> Vec { + self.0.borrow().list_unspent().map(Into::into).collect() + } + pub fn latest_checkpoint(&self) -> CheckPoint { self.0.borrow().latest_checkpoint().into() } + pub fn staged(&self) -> Option { + self.0.borrow().staged().map(Into::into) + } + pub fn take_staged(&self) -> Option { self.0.borrow_mut().take_staged().map(Into::into) } diff --git a/src/types/address.rs b/src/types/address.rs index a0712ee..884b8c8 100644 --- a/src/types/address.rs +++ b/src/types/address.rs @@ -58,7 +58,7 @@ impl From for AddressInfo { } } -/// An owned, growable script. +/// A Bitcoin address. #[wasm_bindgen] #[derive(Debug, Clone)] pub struct Address(BdkAddress); @@ -73,13 +73,13 @@ impl Deref for Address { #[wasm_bindgen] impl Address { - pub fn new(address_str: &str, network: Network) -> JsResult { + pub fn from_str(address_str: &str, network: Network) -> JsResult { let address = BdkAddress::from_str(address_str)?.require_network(network.into())?; Ok(Address(address)) } #[wasm_bindgen(js_name = toString)] - pub fn address(&self) -> String { + pub fn display(&self) -> String { self.0.to_string() } } diff --git a/src/types/changeset.rs b/src/types/changeset.rs index 46eea5a..aba7ee6 100644 --- a/src/types/changeset.rs +++ b/src/types/changeset.rs @@ -63,6 +63,12 @@ impl From for ChangeSet { } } +impl From<&BdkChangeSet> for ChangeSet { + fn from(inner: &BdkChangeSet) -> Self { + ChangeSet(inner.clone()) + } +} + impl From for BdkChangeSet { fn from(changeset: ChangeSet) -> Self { changeset.0 diff --git a/src/types/mod.rs b/src/types/mod.rs index fa761fd..7ff9db5 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -8,6 +8,7 @@ mod checkpoint; mod fee; mod keychain; mod network; +mod output; mod psbt; mod slip10; mod transaction; @@ -22,6 +23,7 @@ pub use checkpoint::*; pub use fee::*; pub use keychain::*; pub use network::*; +pub use output::*; pub use psbt::*; pub use slip10::*; pub use transaction::*; diff --git a/src/types/output.rs b/src/types/output.rs new file mode 100644 index 0000000..37b0532 --- /dev/null +++ b/src/types/output.rs @@ -0,0 +1,149 @@ +use bdk_wallet::LocalOutput as BdkLocalOutput; +use std::ops::Deref; +use wasm_bindgen::prelude::wasm_bindgen; + +use bitcoin::{OutPoint as BdkOutpoint, TxOut as BdkTxOut}; + +use crate::types::{Amount, KeychainKind}; + +use super::Txid; + +/// A reference to a transaction output. +#[wasm_bindgen] +#[derive(Debug, PartialEq, Eq)] +pub struct Outpoint(BdkOutpoint); + +impl Deref for Outpoint { + type Target = BdkOutpoint; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[wasm_bindgen] +impl Outpoint { + #[wasm_bindgen(constructor)] + pub fn new(txid: Txid, vout: u32) -> Self { + BdkOutpoint::new(txid.into(), vout).into() + } + + /// The index of the referenced output in its transaction's vout. + #[wasm_bindgen(getter)] + pub fn vout(&self) -> u32 { + self.0.vout + } + + /// The referenced transaction's txid. + #[wasm_bindgen(getter)] + pub fn txid(&self) -> Txid { + self.0.txid.into() + } + + #[wasm_bindgen(js_name = toString)] + pub fn display(&self) -> String { + self.0.to_string() + } +} + +impl From for Outpoint { + fn from(inner: BdkOutpoint) -> Self { + Outpoint(inner) + } +} + +impl From for BdkOutpoint { + fn from(outpoint: Outpoint) -> Self { + outpoint.0 + } +} + +/// Bitcoin transaction output. +/// +/// Defines new coins to be created as a result of the transaction, +/// along with spending conditions ("script", aka "output script"), +/// which an input spending it must satisfy. +/// +/// An output that is not yet spent by an input is called Unspent Transaction Output ("UTXO"). +#[wasm_bindgen] +pub struct TxOut(BdkTxOut); + +impl Deref for TxOut { + type Target = BdkTxOut; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[wasm_bindgen] +impl TxOut { + /// The value of the output, in satoshis. + #[wasm_bindgen(getter)] + pub fn value(&self) -> Amount { + self.0.value.into() + } +} + +impl From for TxOut { + fn from(inner: BdkTxOut) -> Self { + TxOut(inner) + } +} + +impl From for BdkTxOut { + fn from(txout: TxOut) -> Self { + txout.0 + } +} + +/// A reference to a transaction output. +#[wasm_bindgen] +pub struct LocalOutput(BdkLocalOutput); + +impl Deref for LocalOutput { + type Target = BdkLocalOutput; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[wasm_bindgen] +impl LocalOutput { + /// Transaction output + #[wasm_bindgen(getter)] + pub fn txout(&self) -> TxOut { + self.0.txout.clone().into() + } + + /// The derivation index for the script pubkey in the wallet + #[wasm_bindgen(getter)] + pub fn derivation_index(&self) -> u32 { + self.0.derivation_index + } + + /// Reference to a transaction output + #[wasm_bindgen(getter)] + pub fn outpoint(&self) -> Outpoint { + self.0.outpoint.into() + } + + /// Type of keychain + #[wasm_bindgen(getter)] + pub fn keychain(&self) -> KeychainKind { + self.0.keychain.into() + } +} + +impl From for LocalOutput { + fn from(inner: BdkLocalOutput) -> Self { + LocalOutput(inner) + } +} + +impl From for BdkLocalOutput { + fn from(output: LocalOutput) -> Self { + output.0 + } +} diff --git a/src/types/transaction.rs b/src/types/transaction.rs index 46a9674..b78116e 100644 --- a/src/types/transaction.rs +++ b/src/types/transaction.rs @@ -1,7 +1,7 @@ use std::{ops::Deref, str::FromStr}; use wasm_bindgen::prelude::wasm_bindgen; -use bitcoin::{OutPoint as BdkOutpoint, Transaction as BdkTransaction, Txid as BdkTxid}; +use bitcoin::{Transaction as BdkTransaction, Txid as BdkTxid}; use crate::result::JsResult; @@ -9,7 +9,6 @@ use crate::result::JsResult; /// /// An authenticated movement of coins. #[wasm_bindgen] -#[derive(Debug)] pub struct Transaction(BdkTransaction); impl Deref for Transaction { @@ -39,41 +38,8 @@ impl From for BdkTransaction { } } -/// A reference to a transaction output. -#[wasm_bindgen] -pub struct Outpoint(BdkOutpoint); - -impl Deref for Outpoint { - type Target = BdkOutpoint; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -#[wasm_bindgen] -impl Outpoint { - #[wasm_bindgen(constructor)] - pub fn new(txid: Txid, vout: u32) -> Self { - BdkOutpoint::new(txid.into(), vout).into() - } -} - -impl From for Outpoint { - fn from(inner: BdkOutpoint) -> Self { - Outpoint(inner) - } -} - -impl From for BdkOutpoint { - fn from(outpoint: Outpoint) -> Self { - outpoint.0 - } -} - /// A bitcoin transaction hash/transaction ID. #[wasm_bindgen] -#[derive(Debug)] pub struct Txid(BdkTxid); impl Deref for Txid { diff --git a/tests/esplora.rs b/tests/esplora.rs index a361b26..cc7f9db 100644 --- a/tests/esplora.rs +++ b/tests/esplora.rs @@ -70,7 +70,7 @@ async fn test_esplora_client() { let initial_derivation_index = wallet.derivation_index(KeychainKind::Internal).unwrap(); let fees = blockchain_client.get_fee_estimates().await.expect("get_fee_estimates"); - let recipient = Address::new(RECIPIENT_ADDRESS, NETWORK).expect("recipient_address"); + let recipient = Address::from_str(RECIPIENT_ADDRESS, NETWORK).expect("recipient_address"); let amount = Amount::from_sat(SEND_ADMOUNT); let fee_rate = fees.get(CONFIRMATION_TARGET).expect("fee_estimation"); let mut psbt = loaded_wallet @@ -115,7 +115,7 @@ async fn test_drain() { wallet.apply_update(update).expect("full_scan apply_update"); // No need to test actual values as we are just wrapping BDK and assume the underlying package is computing fees properly - let recipient = Address::new(RECIPIENT_ADDRESS, NETWORK).expect("recipient_address"); + let recipient = Address::from_str(RECIPIENT_ADDRESS, NETWORK).expect("recipient_address"); let psbt = wallet .build_tx() .drain_wallet()