fix: cp-8.3.0 convert pay-flow token amounts to USD instead of relabeling#33321
Conversation
PR template — items to address before "Ready for review"Warnings — informational, address before merging:
See docs/readme/ready-for-review.md for the full Definition of Ready for Review. |
…relabeling Follow-up to #32631. `useAccountTokens` was formatting `asset.fiat.balance` with `currency: 'USD'` while the numeric balance still came from the assets-controller selector computed with the user's preferred fiat rate. For non-USD preferences, values kept their EUR/GBP/etc. magnitude but rendered with a $ symbol. Extract the pay-currency policy into a new `useAssetFiatFormatter` hook in `hooks/pay/`. It owns the rate lookup, the (native->USD) / (native->preferred) re-scaling, the Intl formatting, and the missing-rate fallback. `useAccountTokens` becomes currency-agnostic and just calls the formatter. Hides fiat (returns undefined) rather than mislabeling when either conversion rate is unavailable, matching the existing testnet-hidden fallback. Preserves identity when preferred currency is already USD.
0aee094 to
458c305
Compare
|
|
||
| payAmount = | ||
| preferredRate && usdRate | ||
| ? preferredAmount.multipliedBy(usdRate).dividedBy(preferredRate) |
There was a problem hiding this comment.
We have this logic in the pay controller, and elsewhere in the UI.
I recall assets used to have balanceUsd which would have helped here.
But could we at least re-use useTokenFiatRates which was my attempt to define this rate derivation once?
Plus crucially it factors USD stable-coins which we don't want to convert at all.
There was a problem hiding this comment.
Thanks for the heads up Matthew
Unfortunately balanceUsd is not a property for asset entity anymore.

But I leverage using useTokenFiatRates for locking down the pay with token list with USD.
Here is the recording for latest version, settled EUR for preferred currency, send flow has no regression on EVM + nonEVM tokens and kept EUR meanwhile pay with token list locked to USD:
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-07-15.at.15.10.09.mov
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 98e590d. Configure here.
🔍 Smart E2E Test Selection
click to see 🤖 AI reasoning detailsE2E Test Selection:
The changes are a refactoring (not new features), but the fiat derivation logic change (balance × rate vs. stored fiat.balance) could cause subtle display differences in token lists across all these flows. Performance Test Selection: |
🧪 Flaky unit test detectionRun history flaky detectionHistorical failure rate is a hint, not proof — review each suggestion in context. See the flaky-test-detection skill for the full pattern reference and manual audit workflow. Failures / runs sampled per window:
AI-detected flaky patterns
|
|




Description
Follow-up to #32631.
That PR fixed the label on pay-flow token amounts. It didn't fix the value:
asset.fiat.balancecomes from the assets-controller in the user's preferred currency (e.g. EUR), andIntl.NumberFormat({ currency: 'USD' })only changes the symbol — it doesn't convert. Result: EUR-preferred users saw their EUR magnitude next to a$symbol.This PR converts the value instead of relabeling it, and encapsulates the pay-currency policy in a new hook.
Changes
useAssetFiatFormatterhook inhooks/pay/. Owns: reading pay currency, reading currency rates, re-scaling by(native→USD) / (native→preferred), Intl formatting. Returnsundefinedwhen the target currency can't be safely computed (missing rate, missing chain config).useAccountTokensbecomes currency-agnostic. Drops all pay-flow imports; callsuseAssetFiatFormatterand forwards its output tobalanceInSelectedCurrency. Public API and all 9 consumers unchanged.$0placeholder always renders.Changelog
CHANGELOG entry: Fixed a bug that caused pay-flow token amounts (Perps, Predict, Money Account, mUSD) to be shown with a USD symbol but the user's preferred-currency numeric value, when the user's preferred currency was not USD.
Related issues
Fixes: N/A (follow-up to #32631)
Refs: #32631
Manual testing steps
Screenshots/Recordings
Before
N/A — visible symptom is the
$prefix on a preferred-currency numeric value. Device recording will be attached with QA build.After
Simulator.Screen.Recording.-.iPhone.17.Pro.-.2026-07-15.at.12.51.12.mov
Pre-merge author checklist
Performance checks (if applicable)
Pre-merge reviewer checklist
Note
Medium Risk
Changes how fiat amounts are computed and sorted in send/pay token lists; wrong rates or eligibility bugs could show incorrect USD values or hide balances, though missing-rate cases are explicitly guarded.
Overview
Fixes pay-flow token rows showing a USD symbol while still using the preferred-currency magnitude from
asset.fiat.balanceby computing EVM fiat asbalance × rate(viauseTokenFiatRateswith the active display currency) instead of formatting the assets-controller fiat field directly.Adds
useAssetFiatFormatter, which picks pay-flow USD vs user preferred currency (throughuseTransactionPayCurrency) and handles Intl currency formatting only; rate selection stays inuseTokenFiatRates.useAccountTokensdelegates display formatting to that hook, builds rate requests only for EVM hex-address assets (non-EVM still usesfiat.balance), sorts by the same derived fiat shown in the UI, and keeps $0 visible for zero balances when rates are missing while hiding non-zero rows without a rate.Reviewed by Cursor Bugbot for commit 1ad7b83. Bugbot is set up for automated code reviews on this repo. Configure here.