feat(bob): concurrent swaps#971
Conversation
|
We should display the final state of the swap until the user acknowledges it. |
|
We should move the "cancel timeline" from the "history" page to the "swaps" page and hide it somewhat (make it expandable). |
|
Issue:
|
|
The interaction with the |
Yes you are right but the whole watcher should become redundant anyway... It should not be required if the state machine is properly working. The watcher should be abolished at some point. |
|
I have 2 swaps where I had to do the XMR redeem manually which are now always automatically resumed - and keep failing. There needs to be a solution to this. Some kind of manually marking swaps as "do not resume" which is persisted across restarts. Apart from that, I think we should change "Suspend" in the GUI to something like "Stop" or "Halt". |
"Stop" or "Halt" seems like this actually stop the timelocks from counting down or does something on a protocol level. I dont see them being clearer than "suspend". |
Suspend has the same issue, except I have a much harder time imagining what "suspend" means. It's technical jargon. |
|
I'll remove the watcher. What do you propose for the manually-finished-swap problem? We could just add a new db table with columns like |
We could also bundle it with #932 |
|
Not sure if removing the watcher is the move yet... its a reasonable safety fallback mechanism. |
|
It also turns out we use the watcher for balance and timelock updates. I'll keep the watcher and make it interact with the swap manager.
Yes. Although there still should be an option to stop a swap from resuming without fully deleting it. It needs to be done as part of this PR though. Otherwise it gets really annoying for people in this situation of which there are a few. |
|
@Einliterflasche I will merge this today. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b04ebf0. Configure here.
| .await?; | ||
|
|
||
| Ok(()) | ||
| } |
There was a problem hiding this comment.
Missing database migration for auto_resume table
High Severity
The new get_auto_resume and set_auto_resume methods query an auto_resume table, but no migration file exists in swap/migrations/ to create it. The database uses sqlx::migrate!("./migrations") to manage schema. Without a migration, any call to these methods will fail with a "table not found" error at runtime, breaking both resume_all_swaps (which reads auto_resume) and suspend_swap with disable_auto_resume: true.
Reviewed by Cursor Bugbot for commit b04ebf0. Configure here.
| .await | ||
| .context("Failed to release initiation lock")?; | ||
| result | ||
| } |
There was a problem hiding this comment.
Initiation lock released before UTXO selection completes
High Severity
run_exclusive_initiation releases the initiation lock as soon as manager.start() returns, but start() only spawns the state-machine task — it doesn't wait for TxLock creation (UTXO selection). Two concurrent buy_xmr calls can therefore both pass determine_btc_to_swap sequentially, spawn their tasks, and then both tasks select UTXOs from the same unspent set concurrently, risking double-spend attempts or transaction failures.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit b04ebf0. Configure here.
| let seller_addresses = db.get_addresses(seller_peer_id).await?; | ||
|
|
||
| let mut event_loop_handle = context.try_get_event_loop_handle().await?; | ||
| db.set_auto_resume(swap_id, true).await?; |
There was a problem hiding this comment.
Manual resume silently re-enables auto-resume preference
Medium Severity
resume_swap unconditionally calls db.set_auto_resume(swap_id, true), overwriting a user's explicit "Don't auto resume on startup" preference. A user who disabled auto-resume for a problematic swap and later manually resumes it to check progress will unknowingly re-enable auto-resume, causing the swap to resume on every restart — the exact problem the PR discussion identifies users are experiencing.
Reviewed by Cursor Bugbot for commit b04ebf0. Configure here.
| const swap = state.swap.swaps[swapId]; | ||
| return swap != null && swap.curr.type !== "Released"; | ||
| }); | ||
| } |
There was a problem hiding this comment.
useIsSpecificSwapRunning ignores retry-backoff state inconsistently
Low Severity
useIsSpecificSwapRunning treats any Released event as "not running," but the codebase's isSwapInFlight helper (used by useIsSwapRunning, useRunningSwapsCount, badge counts) correctly treats a Released with next_auto_resume_at_unix_ms as still in flight. This inconsistency means a swap in retry-backoff is counted as running for badges but not for the per-swap check, which could cause subtle UI contradictions.
Reviewed by Cursor Bugbot for commit b04ebf0. Configure here.
|
We definitely need a docker test which spawns multiple swaps. Also get the ui mock system to work again, it's pretty broken now. |


No description provided.