Allow TxBuilder.add_recipient() to take Script
This commit is contained in:
parent
2cbb314d0b
commit
3fefd3c1fb
21
src/bdk.udl
21
src/bdk.udl
@ -173,8 +173,8 @@ dictionary LocalUtxo {
|
|||||||
boolean is_spent;
|
boolean is_spent;
|
||||||
};
|
};
|
||||||
|
|
||||||
dictionary AddressAmount {
|
dictionary ScriptAmount {
|
||||||
string address;
|
Script script;
|
||||||
u64 amount;
|
u64 amount;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -211,6 +211,8 @@ interface PartiallySignedBitcoinTransaction {
|
|||||||
|
|
||||||
string txid();
|
string txid();
|
||||||
|
|
||||||
|
sequence<u8> extract_tx();
|
||||||
|
|
||||||
[Throws=Error]
|
[Throws=Error]
|
||||||
PartiallySignedBitcoinTransaction combine(PartiallySignedBitcoinTransaction other);
|
PartiallySignedBitcoinTransaction combine(PartiallySignedBitcoinTransaction other);
|
||||||
};
|
};
|
||||||
@ -218,7 +220,7 @@ interface PartiallySignedBitcoinTransaction {
|
|||||||
interface TxBuilder {
|
interface TxBuilder {
|
||||||
constructor();
|
constructor();
|
||||||
|
|
||||||
TxBuilder add_recipient(string address, u64 amount);
|
TxBuilder add_recipient(Script script, u64 amount);
|
||||||
|
|
||||||
TxBuilder add_unspendable(OutPoint unspendable);
|
TxBuilder add_unspendable(OutPoint unspendable);
|
||||||
|
|
||||||
@ -248,7 +250,7 @@ interface TxBuilder {
|
|||||||
|
|
||||||
TxBuilder add_data(sequence<u8> data);
|
TxBuilder add_data(sequence<u8> data);
|
||||||
|
|
||||||
TxBuilder set_recipients(sequence<AddressAmount> recipients);
|
TxBuilder set_recipients(sequence<ScriptAmount> recipients);
|
||||||
|
|
||||||
[Throws=Error]
|
[Throws=Error]
|
||||||
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
|
PartiallySignedBitcoinTransaction finish([ByRef] Wallet wallet);
|
||||||
@ -296,3 +298,14 @@ interface DescriptorPublicKey {
|
|||||||
|
|
||||||
string as_string();
|
string as_string();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface Address {
|
||||||
|
[Throws=Error]
|
||||||
|
constructor(string address);
|
||||||
|
|
||||||
|
Script script_pubkey();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface Script {
|
||||||
|
constructor(sequence<u8> raw_output_script);
|
||||||
|
};
|
||||||
|
77
src/lib.rs
77
src/lib.rs
@ -1,8 +1,10 @@
|
|||||||
|
use bdk::bitcoin::blockdata::script::Script as BdkScript;
|
||||||
use bdk::bitcoin::hashes::hex::ToHex;
|
use bdk::bitcoin::hashes::hex::ToHex;
|
||||||
use bdk::bitcoin::secp256k1::Secp256k1;
|
use bdk::bitcoin::secp256k1::Secp256k1;
|
||||||
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
|
use bdk::bitcoin::util::bip32::DerivationPath as BdkDerivationPath;
|
||||||
|
use bdk::bitcoin::util::psbt::serialize::Serialize;
|
||||||
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||||
use bdk::bitcoin::{Address, Network, OutPoint as BdkOutPoint, Script, Txid};
|
use bdk::bitcoin::{Address as BdkAddress, Network, OutPoint as BdkOutPoint, Txid};
|
||||||
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
||||||
use bdk::blockchain::GetBlockHash;
|
use bdk::blockchain::GetBlockHash;
|
||||||
use bdk::blockchain::GetHeight;
|
use bdk::blockchain::GetHeight;
|
||||||
@ -35,8 +37,9 @@ use std::sync::{Arc, Mutex, MutexGuard};
|
|||||||
|
|
||||||
uniffi_macros::include_scaffolding!("bdk");
|
uniffi_macros::include_scaffolding!("bdk");
|
||||||
|
|
||||||
pub struct AddressAmount {
|
/// A output script and an amount of satoshis.
|
||||||
pub address: String,
|
pub struct ScriptAmount {
|
||||||
|
pub script: Arc<Script>,
|
||||||
pub amount: u64,
|
pub amount: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -302,7 +305,7 @@ impl NetworkLocalUtxo for LocalUtxo {
|
|||||||
},
|
},
|
||||||
txout: TxOut {
|
txout: TxOut {
|
||||||
value: x.txout.value,
|
value: x.txout.value,
|
||||||
address: Address::from_script(&x.txout.script_pubkey, network)
|
address: BdkAddress::from_script(&x.txout.script_pubkey, network)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
},
|
},
|
||||||
@ -360,6 +363,16 @@ impl PartiallySignedBitcoinTransaction {
|
|||||||
txid.to_hex()
|
txid.to_hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return the transaction as bytes.
|
||||||
|
fn extract_tx(&self) -> Vec<u8> {
|
||||||
|
self.internal
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.extract_tx()
|
||||||
|
.serialize()
|
||||||
|
}
|
||||||
|
|
||||||
/// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
|
/// Combines this PartiallySignedTransaction with other PSBT as described by BIP 174.
|
||||||
///
|
///
|
||||||
/// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
|
/// In accordance with BIP 174 this function is commutative i.e., `A.combine(B) == B.combine(A)`
|
||||||
@ -471,12 +484,44 @@ impl Wallet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_script_pubkey(address: &str) -> Result<Script, Error> {
|
fn to_script_pubkey(address: &str) -> Result<BdkScript, Error> {
|
||||||
Address::from_str(address)
|
BdkAddress::from_str(address)
|
||||||
.map(|x| x.script_pubkey())
|
.map(|x| x.script_pubkey())
|
||||||
.map_err(|e| Error::Generic(e.to_string()))
|
.map_err(|e| Error::Generic(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A Bitcoin address.
|
||||||
|
struct Address {
|
||||||
|
address: BdkAddress,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Address {
|
||||||
|
fn new(address: String) -> Result<Self, Error> {
|
||||||
|
BdkAddress::from_str(address.as_str())
|
||||||
|
.map(|a| Address { address: a })
|
||||||
|
.map_err(|e| Error::Generic(e.to_string()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_pubkey(&self) -> Arc<Script> {
|
||||||
|
Arc::new(Script {
|
||||||
|
script: self.address.script_pubkey(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A Bitcoin script.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Script {
|
||||||
|
script: BdkScript,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Script {
|
||||||
|
fn new(raw_output_script: Vec<u8>) -> Self {
|
||||||
|
let script: BdkScript = BdkScript::from(raw_output_script);
|
||||||
|
Script { script }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum RbfValue {
|
enum RbfValue {
|
||||||
Default,
|
Default,
|
||||||
@ -488,7 +533,7 @@ enum RbfValue {
|
|||||||
/// Each method on the TxBuilder returns an instance of a new TxBuilder with the option set/added.
|
/// Each method on the TxBuilder returns an instance of a new TxBuilder with the option set/added.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct TxBuilder {
|
struct TxBuilder {
|
||||||
recipients: Vec<(String, u64)>,
|
recipients: Vec<(BdkScript, u64)>,
|
||||||
utxos: Vec<OutPoint>,
|
utxos: Vec<OutPoint>,
|
||||||
unspendable: HashSet<OutPoint>,
|
unspendable: HashSet<OutPoint>,
|
||||||
change_policy: ChangeSpendPolicy,
|
change_policy: ChangeSpendPolicy,
|
||||||
@ -519,19 +564,19 @@ impl TxBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Add a recipient to the internal list.
|
/// Add a recipient to the internal list.
|
||||||
fn add_recipient(&self, recipient: String, amount: u64) -> Arc<Self> {
|
fn add_recipient(&self, script: Arc<Script>, amount: u64) -> Arc<Self> {
|
||||||
let mut recipients = self.recipients.to_vec();
|
let mut recipients: Vec<(BdkScript, u64)> = self.recipients.clone();
|
||||||
recipients.append(&mut vec![(recipient, amount)]);
|
recipients.append(&mut vec![(script.script.clone(), amount)]);
|
||||||
Arc::new(TxBuilder {
|
Arc::new(TxBuilder {
|
||||||
recipients,
|
recipients,
|
||||||
..self.clone()
|
..self.clone()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_recipients(&self, recipients: Vec<AddressAmount>) -> Arc<Self> {
|
fn set_recipients(&self, recipients: Vec<ScriptAmount>) -> Arc<Self> {
|
||||||
let recipients = recipients
|
let recipients = recipients
|
||||||
.iter()
|
.iter()
|
||||||
.map(|address_amount| (address_amount.address.clone(), address_amount.amount))
|
.map(|script_amount| (script_amount.script.script.clone(), script_amount.amount))
|
||||||
.collect();
|
.collect();
|
||||||
Arc::new(TxBuilder {
|
Arc::new(TxBuilder {
|
||||||
recipients,
|
recipients,
|
||||||
@ -671,8 +716,8 @@ impl TxBuilder {
|
|||||||
fn finish(&self, wallet: &Wallet) -> Result<Arc<PartiallySignedBitcoinTransaction>, Error> {
|
fn finish(&self, wallet: &Wallet) -> Result<Arc<PartiallySignedBitcoinTransaction>, Error> {
|
||||||
let wallet = wallet.get_wallet();
|
let wallet = wallet.get_wallet();
|
||||||
let mut tx_builder = wallet.build_tx();
|
let mut tx_builder = wallet.build_tx();
|
||||||
for (address, amount) in &self.recipients {
|
for (script, amount) in &self.recipients {
|
||||||
tx_builder.add_recipient(to_script_pubkey(address)?, *amount);
|
tx_builder.add_recipient(script.clone(), *amount);
|
||||||
}
|
}
|
||||||
tx_builder.change_policy(self.change_policy);
|
tx_builder.change_policy(self.change_policy);
|
||||||
if !self.utxos.is_empty() {
|
if !self.utxos.is_empty() {
|
||||||
@ -780,7 +825,7 @@ impl BumpFeeTxBuilder {
|
|||||||
tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate));
|
tx_builder.fee_rate(FeeRate::from_sat_per_vb(self.fee_rate));
|
||||||
if let Some(allow_shrinking) = &self.allow_shrinking {
|
if let Some(allow_shrinking) = &self.allow_shrinking {
|
||||||
let address =
|
let address =
|
||||||
Address::from_str(allow_shrinking).map_err(|e| Error::Generic(e.to_string()))?;
|
BdkAddress::from_str(allow_shrinking).map_err(|e| Error::Generic(e.to_string()))?;
|
||||||
let script = address.script_pubkey();
|
let script = address.script_pubkey();
|
||||||
tx_builder.allow_shrinking(script)?;
|
tx_builder.allow_shrinking(script)?;
|
||||||
}
|
}
|
||||||
@ -1010,7 +1055,6 @@ mod test {
|
|||||||
let tx_builder = TxBuilder::new()
|
let tx_builder = TxBuilder::new()
|
||||||
.drain_wallet()
|
.drain_wallet()
|
||||||
.drain_to(drain_to_address.clone());
|
.drain_to(drain_to_address.clone());
|
||||||
//dbg!(&tx_builder);
|
|
||||||
assert!(tx_builder.drain_wallet);
|
assert!(tx_builder.drain_wallet);
|
||||||
assert_eq!(tx_builder.drain_to, Some(drain_to_address));
|
assert_eq!(tx_builder.drain_to, Some(drain_to_address));
|
||||||
|
|
||||||
@ -1128,7 +1172,6 @@ mod test {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_derive_and_extend_descriptor_secret_key() {
|
fn test_derive_and_extend_descriptor_secret_key() {
|
||||||
let master_dsk = get_descriptor_secret_key();
|
let master_dsk = get_descriptor_secret_key();
|
||||||
|
|
||||||
// derive DescriptorSecretKey with path "m/0" from master
|
// derive DescriptorSecretKey with path "m/0" from master
|
||||||
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
|
let derived_dsk: &DescriptorSecretKey = &derive_dsk(&master_dsk, "m/0").unwrap();
|
||||||
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
|
assert_eq!(derived_dsk.as_string(), "[d1d04177/0]tprv8d7Y4JLmD25jkKbyDZXcdoPHu1YtMHuH21qeN7mFpjfumtSU7eZimFYUCSa3MYzkEYfSNRBV34GEr2QXwZCMYRZ7M1g6PUtiLhbJhBZEGYJ/*");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user