Skip to content

feat(swaps): move cancellation into activity receipts - #827

Merged
tiero merged 4 commits into
claude/swap-ui-mutinynet-yktp51from
wt-swap-activity-controls-20260720
Jul 22, 2026
Merged

tiero merged 4 commits into
claude/swap-ui-mutinynet-yktp51from
wt-swap-activity-controls-20260720

Conversation

@sahilc0

@sahilc0 sahilc0 commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Remove historical and pending swaps from the swap composer so it stays focused on creating a new swap.
  • Keep every swap status in Recent activity and the full Activity screen.
  • Add an explicit All/Swaps Activity filter that appears only when visible swap activity exists.
  • Reuse the same filter on individual asset pages, scoped to swaps involving the selected asset.
  • Move pending-swap cancellation to the transaction receipt with confirmation, cancelling/retry states, and an in-place cancelled receipt.
  • Persist the cancellation transaction ID and classify cancellation-versus-solver spend races before updating the stored terminal status.

This is a focused follow-up to #784 for #796 and #806. Those issues are intentionally referenced without closing keywords because they should close only after this work is merged into the parent branch. This asset-page follow-up closes #830 when the PR merges.

User-visible behavior

  • The Swap screen no longer contains a “Your swaps” history section or inline cancellation controls.
  • Recent activity continues to show swap rows on the wallet home screen.
  • Activity defaults to All and can switch to Swaps; the filter resets when the screen is left.
  • Individual asset pages show the same All/Swaps chips when that asset has swap history, and Swaps keeps only transactions involving that asset.
  • The filter is hidden when there are no visible swap transactions.
  • Swaps includes pending, completed, cancelled, and failed swap activity.
  • Opening a pending swap shows a bottom “Cancel swap” action.
  • Cancellation requires confirmation, displays progress and retry states, and leaves the user on the updated receipt after success.
  • The cancelled receipt includes the cancellation transaction ID.
  • Broader recoverable-swap behavior remains unchanged.

Visual proof

Pending receipt with cancellation
Pending swap receipt with Cancel swap action
Clean swap composer
Swap composer without historical swap activity
Swaps activity filter
Activity page filtered to swap transactions
Cancelled receipt
Cancelled swap transaction receipt
bitcoin asset swaps filter
bitcoin asset page filtered to swap transactions

Mutinynet preview: https://wt-swap-activity-controls-20.arkade-wallet.pages.dev

Verification

  • bun run test — 61 files passed, 441 tests passed, 3 skipped.
  • bun run lint
  • bun run format:check
  • bunx tsc --noEmit
  • Production service-worker and Vite builds.
  • git diff --check
  • Focused Mutinynet UI verification covering pending activity, receipt cancellation, full Activity filtering, asset-page filtering, composer cleanup, and the cancelled receipt.
  • Public Mutinynet and bitcoin Cloudflare deployments passed.
  • Public Mutinynet deployment loaded and rendered the wallet in the Codex in-app browser.
  • The original PR scope received Codex review approval. The asset-page follow-up passed manual cruft, simplify, and Ponytail full reviews; an external re-review was blocked by the current environment.
  • Resolved both valid CodeRabbit review threads in 56e8daea: hidden swap visibility/filter reset and stale cancellation status protection.
  • Haptics were not hardware-verified on physical iOS and Android devices.

Complete file scope

  • src/components/ActivityFilter.tsx — share the existing accessible, animated, haptic All/Swaps chip control across activity surfaces.
  • src/components/TransactionsList.tsx — add optional transaction-type filtering after the existing visibility filters and expose the existing asset and visibility matchers for consistent swap detection.
  • src/index.css — add token-based Activity filter styling and remove obsolete composer cancellation styles.
  • src/lib/swap/restore.ts — expose cancellation-spend classification for live reconciliation.
  • src/lib/swap/store.ts — update the outdated consumer comment.
  • src/providers/assetSwaps.tsx — persist cancellation transaction IDs, reconcile terminal cancellation states, and prevent stale recovery results from overwriting newer terminal states.
  • src/screens/Wallet/Activity.tsx — use the shared conditional All/Swaps filter while preserving selection feedback, animation, and reduced-motion handling; gate it with the list visibility rule and reset stale selection when visible swaps disappear.
  • src/screens/Wallet/BitcoinDetail.tsx — make composer entry depend on live swap availability and add asset-scoped All/Swaps filtering to Recent activity with the same visibility gating and stale-selection reset.
  • src/screens/Wallet/HomeQuickActions.tsx — apply the same composer availability behavior.
  • src/screens/Wallet/Swap/Index.tsx — remove swap history and inline cancellation from the composer.
  • src/screens/Wallet/Transaction.tsx — add receipt cancellation confirmation, progress, retry, error, success, and live reconciliation states.
  • src/test/components/transactions-list.test.tsx — cover transaction-type filtering.
  • src/test/providers/assetSwaps.test.tsx — cover cancellation persistence, reload behavior, and protection against stale cancellation recovery writes.
  • src/test/screens/wallet/activity.test.tsx — cover the default filter, swap-only results, conditional visibility, and reset behavior when the last visible swap disappears.
  • src/test/screens/wallet/bitcoin-detail.test.tsx — verify All shows mixed bitcoin activity and Swaps keeps only bitcoin-involving swaps.
  • src/test/screens/wallet/index.test.tsx — verify historical swaps do not enter an unavailable composer.
  • src/test/screens/wallet/swap.test.tsx — verify the composer excludes history and cancellation controls.
  • src/test/screens/wallet/transaction.test.tsx — cover confirmation, progress, success, retry, and stale-error reconciliation.

No dependencies or unrelated product behavior are changed. Local environment data, test-wallet credentials, screenshots, and review transcripts are not committed to the product branch.

Base

This PR intentionally targets claude/swap-ui-mutinynet-yktp51, the current head branch of #784, rather than master.

Remove historical swaps and cancellation controls from the swap composer, keeping swap history in recent and full Activity instead.

Add the All/Swaps Activity filter and a confirmed receipt-level cancellation flow that persists the cancellation transaction ID and reconciles spend races. Cover filtering, composer access, receipt states, and cancellation persistence with focused tests.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

Changes

Wallet swap flow

Layer / File(s) Summary
Activity type filtering
src/components/TransactionsList.tsx, src/screens/Wallet/Activity.tsx, src/index.css, src/test/components/transactions-list.test.tsx, src/test/screens/wallet/activity.test.tsx
Adds transaction type filtering and an animated All/Swaps activity selector.
Swap availability and composer
src/screens/Wallet/BitcoinDetail.tsx, src/screens/Wallet/HomeQuickActions.tsx, src/screens/Wallet/Swap/Index.tsx, src/index.css, src/test/screens/wallet/index.test.tsx, src/test/screens/wallet/swap.test.tsx
Restricts swap navigation to available swaps and removes pending swap history and cancellation controls from the composer.
Cancellation reconciliation
src/providers/assetSwaps.tsx, src/lib/swap/restore.ts, src/lib/swap/store.ts, src/test/providers/assetSwaps.test.tsx
Persists cancellation transaction ids and classifies spent funding transactions using wallet history.
Transaction cancellation UI
src/screens/Wallet/Transaction.tsx, src/test/screens/wallet/transaction.test.tsx
Adds live swap status handling, cancellation confirmation, progress, retry, and receipt states.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Wallet as Wallet screen
  participant Transaction as Transaction screen
  participant AssetSwapsProvider
  participant SwapStore
  Wallet->>Transaction: open swap transaction
  Transaction->>AssetSwapsProvider: read live swap status
  Transaction->>AssetSwapsProvider: cancelSwap
  AssetSwapsProvider->>SwapStore: persist cancellation status and spentTxid
  SwapStore-->>Transaction: updated cancellation state
  Transaction-->>Wallet: render cancelled receipt
Loading

Possibly related PRs

Suggested reviewers: claude, bordalix

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: moving swap cancellation into activity receipts.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch wt-swap-activity-controls-20260720

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sahilc0
sahilc0 requested a review from bordalix July 21, 2026 19:50
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 21, 2026 •

Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 56e8dae
Status: ✅  Deploy successful!
Preview URL: https://af75d18f.wallet-bitcoin.pages.dev
Branch Preview URL: https://wt-swap-activity-controls-20.wallet-bitcoin.pages.dev

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 21, 2026 •

Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 56e8dae
Status: ✅  Deploy successful!
Preview URL: https://293cf7bd.arkade-wallet.pages.dev
Branch Preview URL: https://wt-swap-activity-controls-20.arkade-wallet.pages.dev

View logs

@sahilc0

sahilc0 commented Jul 21, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/test/providers/assetSwaps.test.tsx (1)

37-66: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Missing coverage for the race-reconciliation path.

Only the direct-success cancelOffer flow is tested. The new resolveCancellingSpend classification (spent-but-ambiguous cancel-vs-fill, and the monitor's SSE reconciliation) is the core new behavior for this cohort and isn't exercised here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/providers/assetSwaps.test.tsx` around lines 37 - 66, The
AssetSwapsProvider cancellation tests only cover direct cancelOffer success and
omit resolveCancellingSpend reconciliation. Add tests that exercise the
spent-but-ambiguous cancel-versus-fill classification and the monitor’s SSE
reconciliation path, asserting the resulting swap status and transaction data
while preserving the existing direct-success coverage.
src/providers/assetSwaps.tsx (1)

166-181: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

No guard against overlapping cancelOffer calls for the same swap.

cancelSwap doesn't check whether an invocation for id is already in flight, so a remount + "Retry cancel" while a previous call is still resolving would issue a second cancelOffer call. The catch's resolveCancellingSpend fallback covers the case where the deposit is already provably spent, but not other concurrent-call failure modes. Consider an in-flight guard (e.g. a ref-keyed Set) for defense-in-depth, and confirm cancelOffer tolerates being invoked twice for the same offer.

const inFlightRef = useRef(new Set<string>())
// in cancelSwap: if (inFlightRef.current.has(id)) return; inFlightRef.current.add(id); ...finally { inFlightRef.current.delete(id) }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/providers/assetSwaps.tsx` around lines 166 - 181, Prevent overlapping
cancellation requests in cancelSwap by adding a ref-backed Set keyed by swap ID,
returning immediately when the ID is already in flight, and registering it
before invoking cancelOffer. Ensure the ID is removed in a finally block so
retries remain possible after success or failure, while preserving the existing
cancellation and error-handling flow.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/providers/assetSwaps.tsx`:
- Around line 190-197: Update the state-revert branch in the asset-swap monitor
around resolveCancellingSpend so it only writes swap.status when the current
swap status is still cancelling. Reuse the same freshness guard used by the
success path and resolveCancellingSpend, preventing stale polling results from
overwriting a newer terminal status.

In `@src/screens/Wallet/Activity.tsx`:
- Around line 15-25: Update the hasSwaps calculation in Activity to use the same
dev-asset visibility criteria as TransactionsList before checking for swap
transactions, so the Swaps toggle only appears when a visible swap exists. Also
ensure the selected filter cannot remain swaps when no visible swaps are
available by resetting it to all, preserving the existing filter-selection
behavior.

---

Nitpick comments:
In `@src/providers/assetSwaps.tsx`:
- Around line 166-181: Prevent overlapping cancellation requests in cancelSwap
by adding a ref-backed Set keyed by swap ID, returning immediately when the ID
is already in flight, and registering it before invoking cancelOffer. Ensure the
ID is removed in a finally block so retries remain possible after success or
failure, while preserving the existing cancellation and error-handling flow.

In `@src/test/providers/assetSwaps.test.tsx`:
- Around line 37-66: The AssetSwapsProvider cancellation tests only cover direct
cancelOffer success and omit resolveCancellingSpend reconciliation. Add tests
that exercise the spent-but-ambiguous cancel-versus-fill classification and the
monitor’s SSE reconciliation path, asserting the resulting swap status and
transaction data while preserving the existing direct-success coverage.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5376c859-b237-4fa3-95b9-e0f4dfbcaa43

📥 Commits

Reviewing files that changed from the base of the PR and between efe4229 and 8aff954.

📒 Files selected for processing (16)
  • src/components/TransactionsList.tsx
  • src/index.css
  • src/lib/swap/restore.ts
  • src/lib/swap/store.ts
  • src/providers/assetSwaps.tsx
  • src/screens/Wallet/Activity.tsx
  • src/screens/Wallet/BitcoinDetail.tsx
  • src/screens/Wallet/HomeQuickActions.tsx
  • src/screens/Wallet/Swap/Index.tsx
  • src/screens/Wallet/Transaction.tsx
  • src/test/components/transactions-list.test.tsx
  • src/test/providers/assetSwaps.test.tsx
  • src/test/screens/wallet/activity.test.tsx
  • src/test/screens/wallet/index.test.tsx
  • src/test/screens/wallet/swap.test.tsx
  • src/test/screens/wallet/transaction.test.tsx

Comment thread src/providers/assetSwaps.tsx Resolved
Comment thread src/screens/Wallet/Activity.tsx Resolved
@tiero

tiero commented Jul 21, 2026

Copy link
Copy Markdown
Member

un-aligned on dekstop
image

@tiero

tiero commented Jul 21, 2026

Copy link
Copy Markdown
Member

also on mobile
image

@bordalix

Copy link
Copy Markdown
Collaborator

@tiero should be fixed by bf33233

@tiero

tiero commented Jul 22, 2026

Copy link
Copy Markdown
Member

Perfect thanks!

Remaining task for me
Is to show strike through on the canceled swap row instead of red which seems money lost/scary for user @sahilc0

Reuse the Activity filter control on individual asset pages and scope swap visibility to the selected asset. Cover the bitcoin asset history filtering path with a focused screen test.

Closes #830
Use the transaction list visibility rule when exposing swap filters and reset stale selections when visible swaps disappear. Prevent cancellation recovery from overwriting a newer terminal status and cover both regressions.
@tiero
tiero merged commit 53ea744 into claude/swap-ui-mutinynet-yktp51 Jul 22, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants