Skip to content

Commit ca05064

Browse files
committed
tx_builder: allow creating change output with current (or any other) AddressIndex
1 parent 1a16897 commit ca05064

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

src/wallet/mod.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,10 +103,14 @@ pub struct Wallet<D> {
103103

104104
/// The address index selection strategy to use to derived an address from the wallet's external
105105
/// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
106-
#[derive(Debug)]
106+
#[derive(Debug, Clone)]
107107
pub enum AddressIndex {
108108
/// Return a new address after incrementing the current descriptor index.
109109
New,
110+
/// Return address for the current descriptor index.
111+
///
112+
/// Use with caution, address may have already been used.
113+
Current,
110114
/// Return the address for the current descriptor index if it has not been used in a received
111115
/// transaction. Otherwise return a new address as with [`AddressIndex::New`].
112116
///
@@ -268,6 +272,24 @@ where
268272
.map_err(|_| Error::ScriptDoesntHaveAddressForm)
269273
}
270274

275+
// Return derived address at the current index (ie. without incrementing the index) for the specified `keychain`.
276+
fn get_current_address(&self, keychain: KeychainKind) -> Result<AddressInfo, Error> {
277+
let current_index = self.fetch_index(keychain)?;
278+
279+
let address_result = self
280+
.get_descriptor_for_keychain(keychain)
281+
.at_derivation_index(current_index)
282+
.address(self.network);
283+
284+
address_result
285+
.map(|address| AddressInfo {
286+
address,
287+
index: current_index,
288+
keychain,
289+
})
290+
.map_err(|_| Error::ScriptDoesntHaveAddressForm)
291+
}
292+
271293
// Return the the last previously derived address for `keychain` if it has not been used in a
272294
// received transaction. Otherwise return a new address using [`Wallet::get_new_address`].
273295
fn get_unused_address(&self, keychain: KeychainKind) -> Result<AddressInfo, Error> {
@@ -354,6 +376,7 @@ where
354376
) -> Result<AddressInfo, Error> {
355377
match address_index {
356378
AddressIndex::New => self.get_new_address(keychain),
379+
AddressIndex::Current => self.get_current_address(keychain),
357380
AddressIndex::LastUnused => self.get_unused_address(keychain),
358381
AddressIndex::Peek(index) => self.peek_address(index, keychain),
359382
AddressIndex::Reset(index) => self.reset_address(index, keychain),
@@ -839,7 +862,12 @@ where
839862
let drain_script = match params.drain_to {
840863
Some(ref drain_recipient) => drain_recipient.clone(),
841864
None => self
842-
.get_internal_address(AddressIndex::New)?
865+
.get_internal_address(
866+
params
867+
.change_address_index
868+
.clone()
869+
.unwrap_or(AddressIndex::New),
870+
)?
843871
.address
844872
.script_pubkey(),
845873
};

src/wallet/tx_builder.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,13 @@ use bitcoin::util::psbt::{self, PartiallySignedTransaction as Psbt};
4545
use bitcoin::{LockTime, OutPoint, Script, Sequence, Transaction};
4646

4747
use super::coin_selection::{CoinSelectionAlgorithm, DefaultCoinSelectionAlgorithm};
48+
use crate::wallet::AddressIndex;
4849
use crate::{database::BatchDatabase, Error, Utxo, Wallet};
4950
use crate::{
5051
types::{FeeRate, KeychainKind, LocalUtxo, WeightedUtxo},
5152
TransactionDetails,
5253
};
54+
5355
/// Context in which the [`TxBuilder`] is valid
5456
pub trait TxBuilderContext: std::fmt::Debug + Default + Clone {}
5557

@@ -129,6 +131,7 @@ pub(crate) struct TxParams {
129131
pub(crate) recipients: Vec<(Script, u64)>,
130132
pub(crate) drain_wallet: bool,
131133
pub(crate) drain_to: Option<Script>,
134+
pub(crate) change_address_index: Option<AddressIndex>,
132135
pub(crate) fee_policy: Option<FeePolicy>,
133136
pub(crate) internal_policy_path: Option<BTreeMap<String, Vec<usize>>>,
134137
pub(crate) external_policy_path: Option<BTreeMap<String, Vec<usize>>>,
@@ -567,6 +570,12 @@ impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>, Ctx: TxBuilderContext>
567570
self.params.allow_dust = allow_dust;
568571
self
569572
}
573+
574+
/// Set what address index to use for the change output
575+
pub fn change_address_index(&mut self, change_address_index: AddressIndex) -> &mut Self {
576+
self.params.change_address_index = Some(change_address_index);
577+
self
578+
}
570579
}
571580

572581
impl<'a, D: BatchDatabase, Cs: CoinSelectionAlgorithm<D>> TxBuilder<'a, D, Cs, CreateTx> {

0 commit comments

Comments
 (0)