From e6686b7aa12bbff0d10f5ebeb8fcd7466066cf01 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Mon, 3 Jun 2024 23:31:16 +0200 Subject: [PATCH] fix (Bob): Check if Bitcoin redeem transaction was published before transitioning to CancelTimelockExpired --- swap/src/protocol/bob/state.rs | 12 ++++++------ swap/src/protocol/bob/swap.rs | 19 +++++++++++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/swap/src/protocol/bob/state.rs b/swap/src/protocol/bob/state.rs index 9bb5f8a3..4e042a20 100644 --- a/swap/src/protocol/bob/state.rs +++ b/swap/src/protocol/bob/state.rs @@ -489,12 +489,6 @@ pub struct State4 { } impl State4 { - pub fn tx_redeem_encsig(&self) -> bitcoin::EncryptedSignature { - let tx_redeem = - bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); - self.b.encsign(self.S_a_bitcoin, tx_redeem.digest()) - } - pub async fn check_for_tx_redeem( &self, bitcoin_wallet: &bitcoin::Wallet, @@ -519,6 +513,12 @@ impl State4 { }) } + pub fn tx_redeem_encsig(&self) -> bitcoin::EncryptedSignature { + let tx_redeem = + bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); + self.b.encsign(self.S_a_bitcoin, tx_redeem.digest()) + } + pub async fn watch_for_redeem_btc(&self, bitcoin_wallet: &bitcoin::Wallet) -> Result { let tx_redeem = bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee); diff --git a/swap/src/protocol/bob/swap.rs b/swap/src/protocol/bob/swap.rs index 1fed6e56..a641f17e 100644 --- a/swap/src/protocol/bob/swap.rs +++ b/swap/src/protocol/bob/swap.rs @@ -183,12 +183,16 @@ async fn next_state( } } BobState::XmrLocked(state) => { + // In case we send the encrypted signature to Alice, but she doesn't give us a confirmation + // We need to check if she still published the Bitcoin redeem transaction + // Otherwise we risk staying stuck in "XmrLocked" + if let Ok(state5) = state.check_for_tx_redeem(bitcoin_wallet).await { + return Ok(BobState::BtcRedeemed(state5)); + } + let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await; - if let Ok(state5) = state.check_for_tx_redeem(bitcoin_wallet).await { - // this is in case we send the encrypted signature to alice, but we don't get confirmation that she received it. alice would be able to redeem the btc, but we would be stuck in xmrlocked, never being able to redeem the xmr. - BobState::BtcRedeemed(state5) - } else if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? { + if let ExpiredTimelocks::None = state.expired_timelock(bitcoin_wallet).await? { // Alice has locked Xmr // Bob sends Alice his key @@ -210,6 +214,13 @@ async fn next_state( } } BobState::EncSigSent(state) => { + // We need to make sure that Alice did not publish the redeem transaction while we were offline + // Even if the cancel timelock expired, if Alice published the redeem transaction while we were away we cannot miss it + // If we do we cannot refund and will never be able to leave the "CancelTimelockExpired" state + if let Ok(state5) = state.check_for_tx_redeem(bitcoin_wallet).await { + return Ok(BobState::BtcRedeemed(state5)); + } + let tx_lock_status = bitcoin_wallet.subscribe_to(state.tx_lock.clone()).await; if let ExpiredTimelocks::None { .. } = state.expired_timelock(bitcoin_wallet).await? {