Skip to content

fix(ui): read SwapKit's error codes on the DEX amount screens - #1087

Open
romchornyi wants to merge 1 commit into
developfrom
fix/swapkit-error-mapping
Open

fix(ui): read SwapKit's error codes on the DEX amount screens#1087
romchornyi wants to merge 1 commit into
developfrom
fix/swapkit-error-mapping

Conversation

@romchornyi

@romchornyi romchornyi commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Issue being fixed or feature implemented

Reported from the Dash DEX Enter amount screens: the errors SwapKit returns had changed, and the screen answered almost everything with the same dead end — "Something went wrong setting up your swap" — even when the API had said exactly what was wrong.

Verified by hand against api.swapkit.dev on 2026-08-28. An amount below a route's floor comes back three different ways depending on how far below it is:

Request (NEAR, DASH → BTC) Response
0.05 DASH 200 + providerErrors[0].errorCode = sellAssetAmountTooSmall
≤ 0.01 DASH 404 + error = noRoutesFound
≥ 1000 DASH 200 + providerErrors[0].errorCode = apiRequestFailed

Two reasons none of it reached the user:

  1. decodeQuoteError returned body.message before body.error, so the prose reached the mapper and the code never did. "No routes found for DASH.DASH -> BTC.BTC" does not match noRoutesFound, and the buy screen's own contains("noRoutesFound") check missed it for the same reason — so even the one error that screen tried to handle fell through to the generic copy.
  2. A failure a provider reports — an HTTP 200 with no routes and a providerErrors[] entry — was passed on as its prose alone, dropping errorCode, the only stable identifier in the response.

What was done?

Mirrors Android's SwapKitErrors (dashpay/dash-wallet#1526) and the enter-amount copy from dashpay/dash-wallet#1539.

  • providerErrorMessage(_:) renders a provider failure as "<code>: <detail>", so provider-level and top-level failures reach the mapper through one path.
  • Below-minimum codes are family-matched on an AmountTooSmall / AmountTooLow suffix rather than enumerated — SwapKit doesn't document the per-provider vocabulary, and the prefix names whichever side was too small. Both forms carry "Amount", so an unrelated below-threshold code (a too-low fee) stays out.
  • Four live codes mapped that previously fell through: apiRequestFailed, invalidRoute, invalidAsset, memoTooLongForSourceChain. The last one shares the copy the wallet already shows when it catches an over-length memo locally before broadcasting.
  • Routability probing classifies on codes too. A below-minimum reply says the probe amount was too small, not that the asset can't be routed — the coin picker no longer marks an asset unroutable on that evidence. A provider naming its own noRoutesFound still counts as conclusive.
  • decodeQuoteError is code-first, matching what the swap-side decoder already did.
  • Over-balance copy follows the redesign: "The maximum transaction amount is $205.32" → "Max $205.32" (Figma 24034:44864, Android maya_max_amount_error).

One string is removed: the buy screen's hand-rolled dex_enter_amount_invalid fallback is orphaned now that both amount screens share the mapper.

Not in this PR

How Has This Been Tested?

  • Clean dashpay build, ARCHS=arm64, iOS Simulator SDK — BUILD SUCCEEDED.
  • Every error shape above was reproduced against live api.swapkit.dev with the app's own API key and request bodies (quote and swap, both directions, amount sweeps per asset), and the mapping checked against those recorded responses.
  • Not exercised on device end-to-end: with Maya down, a Maya-routed sell can't be run right now, and the NEAR sell path is separately blocked upstream (/v3/swap answers invalidRoute for DASH → BTC even with SwapKit's own nextActions payload).

Breaking Changes

None.

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • Bug Fixes
    • Improved swap error handling and messaging across buy and convert flows.
    • More accurately identifies unavailable routes and amounts below provider minimums.
    • Displays clearer provider and API error details when quotes or routes fail.
    • Corrected maximum transaction amount messaging.
  • Localization
    • Added dedicated messages for amounts below the minimum and maximum transaction limits.

Every amount-related failure on Enter amount rendered as a dead end
("Something went wrong setting up your swap") even when SwapKit had said
exactly what was wrong. Two causes, both about where the code was read
from.

`decodeQuoteError` returned `body.message` before `body.error`, so the
prose reached the mapper and the code never did: "No routes found for
DASH.DASH -> BTC.BTC" does not match `noRoutesFound`, and the buy
screen's own `contains("noRoutesFound")` check missed it for the same
reason. And a failure a provider reports — an HTTP 200 with no routes
and `providerErrors[]` — was passed on as its prose alone, dropping
`errorCode`, the only stable identifier in the response.

Measured against api.swapkit.dev on 2026-08-28: at 0.05 DASH a
DASH -> BTC quote answers 200 with `sellAssetAmountTooSmall`; below
about 0.01 DASH it answers 404 `noRoutesFound`; above the pool's depth
it answers 200 with `apiRequestFailed`. All three read as "something
went wrong".

- `providerErrorMessage` puts the code back in front of the prose, so
  provider-level and top-level failures reach the mapper the same way.
- Below-minimum codes are family-matched on an `AmountTooSmall` /
  `AmountTooLow` suffix rather than enumerated, since SwapKit does not
  document the per-provider vocabulary.
- `apiRequestFailed`, `invalidRoute`, `invalidAsset` and
  `memoTooLongForSourceChain` are mapped; the last shares the copy the
  wallet already uses when it catches an over-length memo locally.
- Routability probing classifies on codes too: a below-minimum reply
  says the probe amount was too small, not that the asset is unroutable,
  so the coin picker no longer hides an asset on that evidence.
- The convert screen's over-balance line follows the redesign to
  "Max $205.32" (Figma 24034:44864).

Mirrors Android's `SwapKitErrors` (dashpay/dash-wallet#1526) and the
enter-amount copy from dashpay/dash-wallet#1539.
@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4c68dc50-705e-4fc2-8fd7-bbd1c3868a08

📥 Commits

Reviewing files that changed from the base of the PR and between ed88d63 and c5eea1e.

📒 Files selected for processing (5)
  • DashWallet/Sources/Models/Swap/SwapKitErrorCopy.swift
  • DashWallet/Sources/Models/SwapKit/SwapKitSwapProvider.swift
  • DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountViewModel.swift
  • DashWallet/Sources/UI/Swap/Convert/SwapConvertViewModel.swift
  • DashWallet/en.lproj/Localizable.strings

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

SwapKit errors now use normalized, case-insensitive codes for provider formatting, route classification, and amount validation. Buy and convert flows use shared error mapping. Localization adds below-minimum and shortened maximum-amount messages.

Changes

SwapKit error flow

Layer / File(s) Summary
Normalize and map SwapKit errors
DashWallet/Sources/Models/Swap/SwapKitErrorCopy.swift
SwapKitErrorCopy now extracts normalized error codes, formats provider errors, detects no-route and below-minimum failures, and maps apiRequestFailed and invalidRoute.
Apply normalized errors to provider flows
DashWallet/Sources/Models/SwapKit/SwapKitSwapProvider.swift
Quote and buy-route flows use shared provider formatting. Routability now uses provider error codes instead of prose matching. Quote decoding prefers top-level error codes.
Use mapped messages in swap UI
DashWallet/Sources/UI/Swap/Buy/EnterAmount/BuyEnterAmountViewModel.swift, DashWallet/Sources/UI/Swap/Convert/SwapConvertViewModel.swift, DashWallet/en.lproj/Localizable.strings
Buy and convert error paths use SwapKitErrorCopy.message(for:coin:). Localization adds below-minimum copy and changes the maximum-amount format to Max %@.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to c5eea

The PR improves how existing SwapKit errors are classified and shown on swap amount screens without changing transaction authority, stored state, or external interfaces; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant SwapKitSwapProvider
  participant SwapKitErrorCopy
  participant BuyEnterAmountViewModel
  participant SwapConvertViewModel
  SwapKitSwapProvider->>SwapKitErrorCopy: Normalize provider error
  SwapKitErrorCopy-->>SwapKitSwapProvider: Return error code and routability
  SwapKitSwapProvider->>BuyEnterAmountViewModel: Return quote error
  BuyEnterAmountViewModel->>SwapKitErrorCopy: Map validation message
  SwapKitSwapProvider->>SwapConvertViewModel: Return API error
  SwapConvertViewModel->>SwapKitErrorCopy: Map conversion message
Loading

Suggested reviewers: jeanpierreroma, llbartekll

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 4 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: updating DEX amount screens to read and use SwapKit error codes.
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.
Full details: Docstring Coverage

Explanation

Docstring coverage is 31.58% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 19 functions across 4 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/swapkit-error-mapping

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.

@thepastaclaw

thepastaclaw commented Aug 31, 2026

Copy link
Copy Markdown

🕓 Ready for review — 2 ahead in queue (commit c5eea1e)
Queue position: 3/31 · 2 reviews active
ETA: start ~06:23 UTC · complete ~07:32 UTC (median 1h 8m across 30 recent reviews; 2 slots)
Queued 18h 31m ago · Last checked: 2026-09-01 05:10 UTC

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