diff --git a/swap/src/bitcoin/cancel.rs b/swap/src/bitcoin/cancel.rs index e54bc988..d1d0bc43 100644 --- a/swap/src/bitcoin/cancel.rs +++ b/swap/src/bitcoin/cancel.rs @@ -1,12 +1,12 @@ +use crate::bitcoin; use crate::bitcoin::wallet::Watchable; use crate::bitcoin::{ build_shared_output_descriptor, Address, Amount, BlockHeight, PublicKey, Transaction, TxLock, TX_FEE, }; use ::bitcoin::util::bip143::SigHashCache; -use ::bitcoin::{OutPoint, SigHash, SigHashType, TxIn, TxOut, Txid}; +use ::bitcoin::{OutPoint, Script, SigHash, SigHashType, TxIn, TxOut, Txid}; use anyhow::Result; -use bitcoin::Script; use ecdsa_fun::Signature; use miniscript::{Descriptor, DescriptorTrait}; use serde::{Deserialize, Serialize}; @@ -149,7 +149,39 @@ impl TxCancel { OutPoint::new(self.inner.txid(), 0) } - pub fn add_signatures( + pub fn complete_as_alice( + self, + a: bitcoin::SecretKey, + B: bitcoin::PublicKey, + tx_cancel_sig_B: bitcoin::Signature, + ) -> Result { + let sig_a = a.sign(self.digest()); + let sig_b = tx_cancel_sig_B; + + let tx_cancel = self + .add_signatures((a.public(), sig_a), (B, sig_b)) + .expect("sig_{a,b} to be valid signatures for tx_cancel"); + + Ok(tx_cancel) + } + + pub fn complete_as_bob( + self, + A: bitcoin::PublicKey, + b: bitcoin::SecretKey, + tx_cancel_sig_A: bitcoin::Signature, + ) -> Result { + let sig_a = tx_cancel_sig_A; + let sig_b = b.sign(self.digest()); + + let tx_cancel = self + .add_signatures((A, sig_a), (b.public(), sig_b)) + .expect("sig_{a,b} to be valid signatures for tx_cancel"); + + Ok(tx_cancel) + } + + fn add_signatures( self, (A, sig_a): (PublicKey, Signature), (B, sig_b): (PublicKey, Signature), diff --git a/swap/src/protocol/alice/steps.rs b/swap/src/protocol/alice/steps.rs index 85075f8d..ef222da8 100644 --- a/swap/src/protocol/alice/steps.rs +++ b/swap/src/protocol/alice/steps.rs @@ -1,6 +1,6 @@ use crate::bitcoin; use crate::bitcoin::{CancelTimelock, PunishTimelock, TxCancel, TxLock, TxRefund}; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; pub async fn publish_cancel_transaction( tx_lock: TxLock, @@ -25,15 +25,12 @@ pub async fn publish_cancel_transaction( // TODO(Franck): Maybe the cancel transaction is already mined, in this case, // the broadcast will error out. - let sig_a = a.sign(tx_cancel.digest()); - let sig_b = tx_cancel_sig_bob.clone(); - - let tx_cancel = tx_cancel - .add_signatures((a.public(), sig_a), (B, sig_b)) - .expect("sig_{a,b} to be valid signatures for tx_cancel"); + let transaction = tx_cancel + .complete_as_alice(a, B, tx_cancel_sig_bob) + .context("Failed to complete Bitcoin cancel transaction")?; // TODO(Franck): Error handling is delicate, why can't we broadcast? - let (..) = bitcoin_wallet.broadcast(tx_cancel, "cancel").await?; + let (..) = bitcoin_wallet.broadcast(transaction, "cancel").await?; // TODO(Franck): Wait until transaction is mined and returned mined // block height diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 7d288a2e..9db3f852 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -8,7 +8,7 @@ use crate::monero_ext::ScalarExt; use crate::protocol::alice::{Message1, Message3}; use crate::protocol::bob::{EncryptedSignature, Message0, Message2, Message4}; use crate::protocol::CROSS_CURVE_PROOF_SYSTEM; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, Context, Result}; use ecdsa_fun::adaptor::{Adaptor, HashTranscript}; use ecdsa_fun::nonce::Deterministic; use ecdsa_fun::Signature; @@ -441,20 +441,12 @@ impl State4 { } pub async fn submit_tx_cancel(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result { - let tx_cancel = - bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public()); + let transaction = + bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public()) + .complete_as_bob(self.A, self.b.clone(), self.tx_cancel_sig_a.clone()) + .context("Failed to complete Bitcoin cancel transaction")?; - let sig_a = self.tx_cancel_sig_a.clone(); - let sig_b = self.b.sign(tx_cancel.digest()); - - let tx_cancel = tx_cancel - .add_signatures((self.A, sig_a), (self.b.public(), sig_b)) - .expect( - "sig_{a,b} to be valid signatures for - tx_cancel", - ); - - let (tx_id, _) = bitcoin_wallet.broadcast(tx_cancel, "cancel").await?; + let (tx_id, _) = bitcoin_wallet.broadcast(transaction, "cancel").await?; Ok(tx_id) }