Add TxBuilder coin selection methods
This commit is contained in:
parent
1a5a628a5d
commit
5f12900c6d
16
src/bdk.udl
16
src/bdk.udl
@ -210,8 +210,24 @@ interface TxBuilder {
|
|||||||
|
|
||||||
TxBuilder add_recipient(string address, u64 amount);
|
TxBuilder add_recipient(string address, u64 amount);
|
||||||
|
|
||||||
|
TxBuilder add_unspendable(OutPoint unspendable);
|
||||||
|
|
||||||
|
TxBuilder add_utxo(OutPoint outpoint);
|
||||||
|
|
||||||
|
TxBuilder add_utxos(sequence<OutPoint> outpoints);
|
||||||
|
|
||||||
|
TxBuilder do_not_spend_change();
|
||||||
|
|
||||||
|
TxBuilder manually_selected_only();
|
||||||
|
|
||||||
|
TxBuilder only_spend_change();
|
||||||
|
|
||||||
|
TxBuilder unspendable(sequence<OutPoint> unspendable);
|
||||||
|
|
||||||
TxBuilder fee_rate(float sat_per_vbyte);
|
TxBuilder fee_rate(float sat_per_vbyte);
|
||||||
|
|
||||||
|
TxBuilder fee_absolute(u64 fee_amount);
|
||||||
|
|
||||||
TxBuilder drain_wallet();
|
TxBuilder drain_wallet();
|
||||||
|
|
||||||
TxBuilder drain_to(string address);
|
TxBuilder drain_to(string address);
|
||||||
|
100
src/lib.rs
100
src/lib.rs
@ -1,7 +1,7 @@
|
|||||||
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::psbt::PartiallySignedTransaction;
|
use bdk::bitcoin::util::psbt::PartiallySignedTransaction;
|
||||||
use bdk::bitcoin::{Address, Network, Script, Txid};
|
use bdk::bitcoin::{Address, Network, OutPoint as BdkOutPoint, Script, Txid};
|
||||||
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
use bdk::blockchain::any::{AnyBlockchain, AnyBlockchainConfig};
|
||||||
use bdk::blockchain::{
|
use bdk::blockchain::{
|
||||||
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
|
electrum::ElectrumBlockchainConfig, esplora::EsploraBlockchainConfig, ConfigurableBlockchain,
|
||||||
@ -12,13 +12,15 @@ use bdk::database::{AnyDatabaseConfig, ConfigurableDatabase};
|
|||||||
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
use bdk::keys::bip39::{Language, Mnemonic, WordCount};
|
||||||
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
use bdk::keys::{DerivableKey, ExtendedKey, GeneratableKey, GeneratedKey};
|
||||||
use bdk::miniscript::BareCtx;
|
use bdk::miniscript::BareCtx;
|
||||||
|
use bdk::wallet::tx_builder::ChangeSpendPolicy;
|
||||||
use bdk::wallet::AddressIndex as BdkAddressIndex;
|
use bdk::wallet::AddressIndex as BdkAddressIndex;
|
||||||
use bdk::wallet::AddressInfo as BdkAddressInfo;
|
use bdk::wallet::AddressInfo as BdkAddressInfo;
|
||||||
use bdk::{
|
use bdk::{
|
||||||
BlockTime, Error, FeeRate, KeychainKind, SignOptions, SyncOptions as BdkSyncOptions,
|
BlockTime, Error, FeeRate, KeychainKind, SignOptions, SyncOptions as BdkSyncOptions,
|
||||||
Wallet as BdkWallet,
|
Wallet as BdkWallet,
|
||||||
};
|
};
|
||||||
use std::convert::{From, TryFrom};
|
use std::collections::HashSet;
|
||||||
|
use std::convert::{From, TryFrom, TryInto};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
@ -173,11 +175,21 @@ struct Wallet {
|
|||||||
wallet_mutex: Mutex<BdkWallet<AnyDatabase>>,
|
wallet_mutex: Mutex<BdkWallet<AnyDatabase>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct OutPoint {
|
pub struct OutPoint {
|
||||||
txid: String,
|
txid: String,
|
||||||
vout: u32,
|
vout: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&OutPoint> for BdkOutPoint {
|
||||||
|
fn from(x: &OutPoint) -> BdkOutPoint {
|
||||||
|
BdkOutPoint {
|
||||||
|
txid: Txid::from_str(&x.txid).unwrap(),
|
||||||
|
vout: x.vout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct TxOut {
|
pub struct TxOut {
|
||||||
value: u64,
|
value: u64,
|
||||||
address: String,
|
address: String,
|
||||||
@ -394,7 +406,12 @@ enum RbfValue {
|
|||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct TxBuilder {
|
struct TxBuilder {
|
||||||
recipients: Vec<(String, u64)>,
|
recipients: Vec<(String, u64)>,
|
||||||
|
utxos: Vec<OutPoint>,
|
||||||
|
unspendable: HashSet<OutPoint>,
|
||||||
|
change_policy: ChangeSpendPolicy,
|
||||||
|
manually_selected_only: bool,
|
||||||
fee_rate: Option<f32>,
|
fee_rate: Option<f32>,
|
||||||
|
fee_absolute: Option<u64>,
|
||||||
drain_wallet: bool,
|
drain_wallet: bool,
|
||||||
drain_to: Option<String>,
|
drain_to: Option<String>,
|
||||||
rbf: Option<RbfValue>,
|
rbf: Option<RbfValue>,
|
||||||
@ -405,7 +422,12 @@ impl TxBuilder {
|
|||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
TxBuilder {
|
TxBuilder {
|
||||||
recipients: Vec::new(),
|
recipients: Vec::new(),
|
||||||
|
utxos: Vec::new(),
|
||||||
|
unspendable: HashSet::new(),
|
||||||
|
change_policy: ChangeSpendPolicy::ChangeAllowed,
|
||||||
|
manually_selected_only: false,
|
||||||
fee_rate: None,
|
fee_rate: None,
|
||||||
|
fee_absolute: None,
|
||||||
drain_wallet: false,
|
drain_wallet: false,
|
||||||
drain_to: None,
|
drain_to: None,
|
||||||
rbf: None,
|
rbf: None,
|
||||||
@ -422,6 +444,56 @@ impl TxBuilder {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn add_unspendable(&self, unspendable: OutPoint) -> Arc<Self> {
|
||||||
|
let mut unspendable_hash_set = self.unspendable.clone();
|
||||||
|
unspendable_hash_set.insert(unspendable);
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
unspendable: unspendable_hash_set,
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_utxo(&self, outpoint: OutPoint) -> Arc<Self> {
|
||||||
|
self.add_utxos(vec![outpoint])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_utxos(&self, mut outpoints: Vec<OutPoint>) -> Arc<Self> {
|
||||||
|
let mut utxos = self.utxos.to_vec();
|
||||||
|
utxos.append(&mut outpoints);
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
utxos,
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn do_not_spend_change(&self) -> Arc<Self> {
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
change_policy: ChangeSpendPolicy::ChangeForbidden,
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn manually_selected_only(&self) -> Arc<Self> {
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
manually_selected_only: true,
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn only_spend_change(&self) -> Arc<Self> {
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
change_policy: ChangeSpendPolicy::OnlyChange,
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unspendable(&self, unspendable: Vec<OutPoint>) -> Arc<Self> {
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
unspendable: unspendable.into_iter().collect(),
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn fee_rate(&self, sat_per_vb: f32) -> Arc<Self> {
|
fn fee_rate(&self, sat_per_vb: f32) -> Arc<Self> {
|
||||||
Arc::new(TxBuilder {
|
Arc::new(TxBuilder {
|
||||||
fee_rate: Some(sat_per_vb),
|
fee_rate: Some(sat_per_vb),
|
||||||
@ -429,6 +501,13 @@ impl TxBuilder {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fee_absolute(&self, fee_amount: u64) -> Arc<Self> {
|
||||||
|
Arc::new(TxBuilder {
|
||||||
|
fee_absolute: Some(fee_amount),
|
||||||
|
..self.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn drain_wallet(&self) -> Arc<Self> {
|
fn drain_wallet(&self) -> Arc<Self> {
|
||||||
Arc::new(TxBuilder {
|
Arc::new(TxBuilder {
|
||||||
drain_wallet: true,
|
drain_wallet: true,
|
||||||
@ -470,9 +549,26 @@ impl TxBuilder {
|
|||||||
for (address, amount) in &self.recipients {
|
for (address, amount) in &self.recipients {
|
||||||
tx_builder.add_recipient(to_script_pubkey(address)?, *amount);
|
tx_builder.add_recipient(to_script_pubkey(address)?, *amount);
|
||||||
}
|
}
|
||||||
|
tx_builder.change_policy(self.change_policy);
|
||||||
|
if !self.utxos.is_empty() {
|
||||||
|
let bdk_utxos: Vec<BdkOutPoint> = self.utxos.iter().map(BdkOutPoint::from).collect();
|
||||||
|
let utxos: &[BdkOutPoint] = bdk_utxos[..].try_into().unwrap();
|
||||||
|
tx_builder.add_utxos(utxos)?;
|
||||||
|
}
|
||||||
|
if !self.unspendable.is_empty() {
|
||||||
|
let bdk_unspendable: Vec<BdkOutPoint> =
|
||||||
|
self.unspendable.iter().map(BdkOutPoint::from).collect();
|
||||||
|
tx_builder.unspendable(bdk_unspendable);
|
||||||
|
}
|
||||||
|
if self.manually_selected_only {
|
||||||
|
tx_builder.manually_selected_only();
|
||||||
|
}
|
||||||
if let Some(sat_per_vb) = self.fee_rate {
|
if let Some(sat_per_vb) = self.fee_rate {
|
||||||
tx_builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
|
tx_builder.fee_rate(FeeRate::from_sat_per_vb(sat_per_vb));
|
||||||
}
|
}
|
||||||
|
if let Some(fee_amount) = self.fee_absolute {
|
||||||
|
tx_builder.fee_absolute(fee_amount);
|
||||||
|
}
|
||||||
if self.drain_wallet {
|
if self.drain_wallet {
|
||||||
tx_builder.drain_wallet();
|
tx_builder.drain_wallet();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user