Add a mandatory --change-address parameter to buy-xmr

Fixes #513.
This commit is contained in:
Thomas Eizinger 2021-07-06 19:17:17 +10:00
parent 683d565679
commit 5463bde4f8
No known key found for this signature in database
GPG key ID: 651AC83A6C6C8B96
12 changed files with 135 additions and 13 deletions

View file

@ -24,6 +24,7 @@ impl TxLock {
amount: Amount,
A: PublicKey,
B: PublicKey,
change: bitcoin::Address,
) -> Result<Self>
where
C: EstimateFeeRate,
@ -34,7 +35,9 @@ impl TxLock {
.address(wallet.get_network())
.expect("can derive address from descriptor");
let psbt = wallet.send_to_address(address, amount).await?;
let psbt = wallet
.send_to_address(address, amount, Some(change))
.await?;
Ok(Self {
inner: psbt,
@ -251,7 +254,11 @@ mod tests {
wallet: &Wallet<(), bdk::database::MemoryDatabase, StaticFeeRate>,
amount: Amount,
) -> PartiallySignedTransaction {
TxLock::new(&wallet, amount, A, B).await.unwrap().into()
let change = wallet.new_address().await.unwrap();
TxLock::new(&wallet, amount, A, B, change)
.await
.unwrap()
.into()
}
fn alice_and_bob() -> (PublicKey, PublicKey) {

View file

@ -309,11 +309,18 @@ where
&self,
address: Address,
amount: Amount,
change_override: Option<Address>,
) -> Result<PartiallySignedTransaction> {
if self.network != address.network {
bail!("Cannot build PSBT because network of given address is {} but wallet is on network {}", address.network, self.network);
}
if let Some(change) = change_override.as_ref() {
if self.network != change.network {
bail!("Cannot build PSBT because network of given address is {} but wallet is on network {}", change.network, self.network);
}
}
let wallet = self.wallet.lock().await;
let client = self.client.lock().await;
let fee_rate = client.estimate_feerate(self.target_block)?;
@ -340,6 +347,15 @@ where
_ => bail!("Unexpected transaction layout"),
}
if let ([_, change], [_, psbt_output], Some(change_override)) = (
&mut psbt.global.unsigned_tx.output.as_mut_slice(),
&mut psbt.outputs.as_mut_slice(),
change_override,
) {
change.script_pubkey = change_override.script_pubkey();
psbt_output.bip32_derivation.clear();
}
Ok(psbt)
}
@ -1059,7 +1075,8 @@ mod tests {
// if the change output is below dust it will be dropped by the BDK
for amount in above_dust..(balance - (above_dust - 1)) {
let (A, B) = (PublicKey::random(), PublicKey::random());
let txlock = TxLock::new(&wallet, bitcoin::Amount::from_sat(amount), A, B)
let change = wallet.new_address().await.unwrap();
let txlock = TxLock::new(&wallet, bitcoin::Amount::from_sat(amount), A, B, change)
.await
.unwrap();
let txlock_output = txlock.script_pubkey();
@ -1074,4 +1091,30 @@ mod tests {
);
}
}
#[tokio::test]
async fn can_override_change_address() {
let wallet = Wallet::new_funded_default_fees(50_000);
let custom_change = "bcrt1q08pfqpsyrt7acllzyjm8q5qsz5capvyahm49rw"
.parse::<Address>()
.unwrap();
let psbt = wallet
.send_to_address(
wallet.new_address().await.unwrap(),
Amount::from_sat(10_000),
Some(custom_change.clone()),
)
.await
.unwrap();
let transaction = wallet.sign_and_finalize(psbt).await.unwrap();
match transaction.output.as_slice() {
[first, change] => {
assert_eq!(first.value, 10_000);
assert_eq!(change.script_pubkey, custom_change.script_pubkey());
}
_ => panic!("expected exactly two outputs"),
}
}
}