-
Notifications
You must be signed in to change notification settings - Fork 40
feat(bob): Non-interactive transfer proof #818
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
I wanted to replace the transfer proof validation logic with |
6d296bb to
d15aa9c
Compare
…cept the DLEQ proof system
…ransaction verification
…, add new XmrLockTransactionSeen, extract helpers into common.rs, use monero-wallet-ng helpers, add new TransferProofMaybeWithTxKey
1709cbe to
cd48523
Compare
|
bugbot run |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: Frontend missing XmrLockTransactionSeen in cancellable/refundable states
The new XmrLockTransactionSeen state is added to the BobStateName enum but is not included in the BobStateNamePossiblyCancellableSwap or BobStateNamePossiblyRefundableSwap types and their corresponding isBobStateNamePossiblyCancellableSwap and isBobStateNamePossiblyRefundableSwap functions. This causes the UI to incorrectly indicate that swaps in this state cannot be cancelled or refunded, even though the backend is intended to support these operations.
src-gui/src/models/tauriModelExt.ts#L162-L196
core/src-gui/src/models/tauriModelExt.ts
Lines 162 to 196 in cd48523
| export type BobStateNamePossiblyCancellableSwap = | |
| | BobStateName.BtcLocked | |
| | BobStateName.XmrLockCandidateFound | |
| | BobStateName.XmrLocked | |
| | BobStateName.EncSigSent | |
| | BobStateName.CancelTimelockExpired | |
| | BobStateName.BtcRefundPublished | |
| | BobStateName.BtcEarlyRefundPublished; | |
| /** | |
| Checks if a swap is in a state where it can possibly be cancelled | |
| The following conditions must be met: | |
| - The bitcoin must be locked | |
| - The bitcoin must not be redeemed | |
| - The bitcoin must not be cancelled | |
| - The bitcoin must not be refunded | |
| - The bitcoin must not be punished | |
| - The bitcoin must not be early refunded | |
| See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/cancel.rs#L16-L35 | |
| */ | |
| export function isBobStateNamePossiblyCancellableSwap( | |
| state: BobStateName, | |
| ): state is BobStateNamePossiblyCancellableSwap { | |
| return [ | |
| BobStateName.BtcLocked, | |
| BobStateName.XmrLockCandidateFound, | |
| BobStateName.XmrLocked, | |
| BobStateName.EncSigSent, | |
| BobStateName.CancelTimelockExpired, | |
| BobStateName.BtcRefundPublished, | |
| BobStateName.BtcEarlyRefundPublished, | |
| ].includes(state); |
src-gui/src/models/tauriModelExt.ts#L198-L232
core/src-gui/src/models/tauriModelExt.ts
Lines 198 to 232 in cd48523
| export type BobStateNamePossiblyRefundableSwap = | |
| | BobStateName.BtcLocked | |
| | BobStateName.XmrLockCandidateFound | |
| | BobStateName.XmrLocked | |
| | BobStateName.EncSigSent | |
| | BobStateName.CancelTimelockExpired | |
| | BobStateName.BtcCancelled | |
| | BobStateName.BtcRefundPublished | |
| | BobStateName.BtcEarlyRefundPublished; | |
| /** | |
| Checks if a swap is in a state where it can possibly be refunded (meaning it's not impossible) | |
| The following conditions must be met: | |
| - The bitcoin must be locked | |
| - The bitcoin must not be redeemed | |
| - The bitcoin must not be refunded | |
| - The bitcoin must not be punished | |
| See: https://github.com/comit-network/xmr-btc-swap/blob/7023e75bb51ab26dff4c8fcccdc855d781ca4b15/swap/src/cli/refund.rs#L16-L34 | |
| */ | |
| export function isBobStateNamePossiblyRefundableSwap( | |
| state: BobStateName, | |
| ): state is BobStateNamePossiblyRefundableSwap { | |
| return [ | |
| BobStateName.BtcLocked, | |
| BobStateName.XmrLockCandidateFound, | |
| BobStateName.XmrLocked, | |
| BobStateName.EncSigSent, | |
| BobStateName.CancelTimelockExpired, | |
| BobStateName.BtcCancelled, | |
| BobStateName.BtcRefundPublished, | |
| BobStateName.BtcEarlyRefundPublished, | |
| ].includes(state); |
…for_xmr_lock_confirmation(...), never go into XmrLockTransactionSeen directly
… indefinitely upon cooperative redeem
…equisite check before sending enc sig
3b846f0 to
715992a
Compare
|
bugbot run |
|
@Einliterflasche This is ready for a final review. I think it is ready to be merged. |
|
5f33dfe to
f626bbb
Compare
|
Half broken alice locks wrong Monero amount integration test: pub mod harness;
use harness::FastCancelConfig;
use swap::asb::FixedRate;
use swap::protocol::alice::AliceState;
use swap::protocol::bob::BobState;
use swap::protocol::{alice, bob};
use swap_core::monero::Amount;
use crate::harness::SlowCancelConfig;
#[tokio::test]
async fn given_alice_locks_wrong_xmr_amount_bob_rejects() {
harness::setup_test(SlowCancelConfig, None, |mut ctx| async move {
// Run Bob until he gives up on the swap
let (bob_swap, bob_join_handle) = ctx.bob_swap().await;
let bob_swap_id = bob_swap.id;
let bob_swap = tokio::spawn(bob::run_until(bob_swap, |s| {
matches!(s, BobState::WaitingForCancelTimelockExpiration { .. })
}));
// Run until Alice detects the Bitcoin as having been locked
let alice_swap = ctx.alice_next_swap().await;
let alice_state = alice::run_until(
alice_swap,
|s| matches!(s, AliceState::BtcLocked { .. }),
FixedRate::default(),
)
.await?;
// Resume Alice such that she locks the wrong amount of Monero
ctx.restart_alice().await;
let mut alice_swap = ctx.alice_next_swap().await;
// Modify Alice such that she locks the wrong amount of Monero
alice_swap.state = alice_state.lower_by_one_piconero();
let alice_swap = tokio::spawn(alice::run(alice_swap, FixedRate::default()));
// Run until Bob detects the wrong amount of Monero and gives up
// He gives up by waiting for the cancel timelock to expire
let bob_state = bob_swap.await??;
assert!(matches!(bob_state, BobState::WaitingForCancelTimelockExpiration { .. }));
// Resume Bob and wait run until completion
let (bob_swap, _) = ctx
.stop_and_resume_bob_from_db(bob_join_handle, bob_swap_id)
.await;
let bob_state = bob::run_until(bob_swap, |s| {
matches!(s, BobState::BtcRefunded(..))
})
.await?;
// Assert that both Bob and Alice refunded
ctx.assert_bob_refunded(bob_state).await;
let alice_state = alice_swap.await??;
ctx.assert_alice_refunded(alice_state).await;
Ok(())
})
.await;
}
trait FakeModifyMoneroAmount {
/// Reduces the Monero amount by one piconero
fn lower_by_one_piconero(self) -> Self;
}
impl FakeModifyMoneroAmount for AliceState {
fn lower_by_one_piconero(self) -> Self {
let AliceState::BtcLocked { mut state3 } = self else {
panic!("Expected BtcLocked state to be able to modify the Monero amount");
};
let one_piconero = Amount::from_piconero(1);
state3.xmr = state3.xmr.checked_sub(one_piconero).unwrap();
Self::BtcLocked { state3 }
}
} |
Previously Bob had to receive the transfer proof from Alice to transition from
BtcLocked -> ... -> XmrLocked. This required interactivity meaning that if the peer-to-peer networking had issues, Bob might not detect that Alice locked the funds. This could cause unnecessary refunds of swaps that could have otherwise succeded.This PR changes:
wait_until_confirmedfunction which was based onwallet2with an implementation that usesmonero-oxide, skipping FFI completely.XmrLockProofReceivedtoXmrLockCandidateFoundwhile remaining backwards compatible on the storage layer.XmrLockProofReceivedinto two states (XmrLockCandidateFoundandXmrLockTransactionSeen).XmrLockCandidateFoundis entered either by receiving the transfer proof from Alice or when we detect an incoming transfer into the view-only wallet.XmrLockCandidateFoundintoXmrLockTransactionSeenwe verify that that the transaction transfer the correct amount. We do this using a newverify_transfer_ngfunction that usesmonero-oxide, skipping FFI completely. This does not rely at all on thetx_key. It only uses the view-key to decode the transaction.We also extract some common behaviour in the state machines into external traits to make it more readable.
Note
Bob now detects and verifies the Monero lock non‑interactively via the view key and uses monero‑oxide for confirmations, with new intermediate states/UI, a new test, and a Rust toolchain bump.
monero-oxide.XmrLockProofReceivedwithXmrLockTransactionCandidateandXmrLockTransactionSeen; keep storage compatibility.monero-wallet-ng(confirmations,scanner,verify) and refactormonero-walletto use it (remove wallet2/FFIwait_until_confirmed).verify_transfer/wait_until_confirmedinWalletsvia oxide.TransferProofMaybeWithTxKey; removeWatchRequest; add scalar compat; tweak key handling.Written by Cursor Bugbot for commit f626bbb. This will update automatically on new commits. Configure here.