Skip to content

feat: integrate USDC + USDm + USAT + 4-card BalanceCard (Phases 1 + 2)#148

Merged
TuCopFi merged 18 commits into
Developmentfrom
feat/integrate-usdc-usdm-usat-phase1
Jun 4, 2026
Merged

feat: integrate USDC + USDm + USAT + 4-card BalanceCard (Phases 1 + 2)#148
TuCopFi merged 18 commits into
Developmentfrom
feat/integrate-usdc-usdm-usat-phase1

Conversation

@TuCopFi

@TuCopFi TuCopFi commented Jun 3, 2026

Copy link
Copy Markdown
Member

Summary

Phases 1 and 2 of the dollar-tokens-and-balance-cards plan ship together.

Phase 1 (data layer): integrate USDC, USDm (cUSD alias) and USAT into the wallet on Celo mainnet.
Phase 2 (UI): refactor the home/wallet BalanceCard from 3 cards to 4 (Pesos / Dolares / Oro / Inversiones), and collapse individual dollar tokens into a single "Dolares" row in TabWallet.

The new "Dolares" total aggregates USDT + USDC + USDm + USAT. Pesos disponibles is the white front card by default (non-expandable). The new Dolares card uses a muted Tether-green gradient ['#26A17B', '#1A6F55', '#0F4733'] that matches DollarsIcon and the rest of the wallet palette. Expanding Dolares shows a per-token breakdown filtered by USD-value dust threshold (>= STABLE_TRANSACTION_MIN_AMOUNT, same threshold as tokensWithUsdValueSelector).

Verified visually (Android Pixel 8 emulator)

Tested with wallet 0xEa510ecA6966208499cDEc4552211F3C3Ca0df4e:

  • Home stack renders 4 cards in correct order (Inversiones / Oro / Dolares / Pesos)
  • Pesos front by default, non-expandable
  • Dolares expandable, per-token breakdown excludes USDm dust (25047 wei) and zero USAT correctly
  • TabWallet shows single "Dolares" aggregate row instead of 4 individual rows
  • USDC and USDm balance and price feed working
  • USAT priceUsd override returns "1" when backend returns NaN

Changes

Phase 1 (data layer)

  • src/web3/networkConfig.ts: three new token-ID constants + interface fields + both config objects + currencyToTokenId mappings (USDC + USAT)
  • src/tokens/constants.ts: USDC + USDm + USAT added to ALLOWED_TOKEN_IDS. USAT guarded by if (networkConfig.usatTokenId) for Sepolia
  • src/utils/currencies.ts: USDC + USAT added to Currency, CiCoCurrency, CURRENCIES, resolvers
  • src/components/TokenDisplay.tsx: getTokenSymbol covers the three new tokens
  • src/tokens/hooks.ts: useUSDC / useUSDm / useUSAT convenience hooks
  • src/tokens/saga.ts: USAT priceUsd override (NaN -> 1) since the Valora upstream backend has USAT metadata but no price oracle. TODO to remove when upstream publishes a real feed
  • src/tokens/selectors.ts: extend tokensByCurrencySelector for the new enum values
  • i18n: per-token name keys (usdCoin, mentoDollar, tetherUsd, tetherAmericaUsd)

Phase 2 (UI)

  • docs/adr/0014-home-balance-cards-layout.md: ADR for the 4-card layout decision
  • src/tokens/dollarGroup.ts: DOLLAR_TOKEN_IDS set + isDollarToken() + getDollarTokenIds()
  • src/tokens/hooks.ts: useDollarTokensWithBalance (returns array with usdValue + localValue, dust-filtered), useDollarBalance (sum in local currency), useDollarUsdBalance (sum in USD)
  • src/components/BalanceCard.tsx: refactor from 3 cards to 4 (CardId enum, default activeCard = 'pesos', baseOrder, per-token Dolares breakdown, non-expandable Pesos)
  • src/tokens/TabWallet.tsx: collapse individual dollar tokens into a single "Dolares" row showing aggregate USD + COP value

Verification

  • yarn build:ts - pass
  • yarn lint - pass
  • yarn test - 368 suites, 3997 pass, 44 skipped, 0 fail (Phase 1) + snapshot updates (Phase 2)
  • Visual QA on Android Pixel 8 mainnet emulator - all 4 cards render correctly

Pre-existing bugs surfaced during QA (not introduced by this PR, but worth fixing separately)

  1. UpgradeScreen does not call SplashScreen.hide(). When shouldForceUpgrade is true at cold start, NavigatorWrapper renders <UpgradeScreen> early and MainStackScreen (which holds the only SplashScreen.hide() call) never mounts. Result: app stuck on splash forever instead of showing the upgrade prompt. Hit during my QA because Development branch is at 1.118.4 while Statsig minRequiredVersion = 1.118.5 (PRs chore: bump version to 1.118.5 #146/fix(ios): wire Info.plist version keys to build-setting template vars #147 are only on main). Fix is to add SplashScreen.hide() inside UpgradeScreen.componentDidMount (or a useEffect at the top of NavigatorWrapper).
  2. RN 0.77 + iOS 18+ simulator crash: facebook::react::jsinspector_modern::HostTarget::registerInstance assertion failure during [RCTBridge setUp]. iOS simulator-only, debug-only. Production builds are unaffected. Visual QA on iOS sim needs either iPhone 15 Pro Max iOS 17.5 (works) or a release build.

Known gaps / follow-ups (Phase 3)

  • Collapse the Dolares aggregate into the swap and gold-buy token pickers (currently still show individual tokens)
  • Implement spend order priority USAT > USDm > USDC > USDT when consuming "Dolares" through swap/gold-buy (may require multi-step swap execution if a single token does not cover the requested amount)
  • Mainnet spendTokenIds pre-existing inconsistency [CUSD_TOKEN_ID_MAINNET, CELO_TOKEN_ID_MAINNET] (no USDT) is NOT modified by this PR
  • USAT priceUsd hardcoded to 1.0 at the saga layer until Valora upstream publishes a real feed

Test plan

  • Visual QA on Android Pixel 8 emulator (mainnetdev) with wallet 0xEa510ecA6966208499cDEc4552211F3C3Ca0df4e
  • Visual QA on iOS 17.5 simulator or real device (iOS 18+ sim hits the jsinspector_modern crash unrelated to this PR)
  • Test with a wallet that has positive USAT balance once the wallet team has one funded
  • Verify Pesos card non-expandable behavior
  • Verify hide-balances toggle masks all 4 cards and the breakdown

TuCopFi added 17 commits June 3, 2026 16:22
Expose DOLLAR_TOKEN_IDS, isDollarToken, and getDollarTokenIds for the
home-screen Dolares card. USAT is filtered out on Sepolia where
networkConfig.usatTokenId is empty.
New hooks aggregate all DOLLAR_TOKEN_IDS entries that have balance > 0,
compute their local-currency value, and sort by value descending.
useDollarBalance sums all entries for use as the Dolares card total.
…d/Investments)

Replace the single 'available' card with two dedicated cards:
- Pesos (white, non-expandable, COPm only, front by default)
- Dolares (green gradient, expandable, per-token breakdown for USD stables with balance > 0)

Update TabWallet.test.tsx testIDs to reference the new card ID.
…let Dolares row

Three small follow-ups after Phase 2 visual QA:

1. BalanceCard Dolares gradient: switch from vivid emerald (#22C55E -> #137211) to muted Tether green (#26A17B -> #1A6F55 -> #0F4733). Matches DollarsIcon hue and reads less neon against the rest of the wallet palette.

2. useDollarTokensWithBalance: filter out dust by USD value (>= STABLE_TRANSACTION_MIN_AMOUNT = 0.01 USD) instead of just balance.gt(0). Was showing USDm rows with 25047 wei = 0.000000000000025 USDm rounded to COP$0.00. Threshold matches what tokensWithUsdValueSelector already uses, so row counts agree across screens.

3. TabWallet: collapse all individual dollar tokens (USDT/USDC/USDm/USAT) into a single 'Dolares' row showing the aggregate USD + COP value, mirroring how 'Pesos' is shown. Uses DollarsIcon + same row layout as the Gold item. Hidden when sum is 0.

Also exposes useDollarUsdBalance hook for the USD aggregate, mirroring useDollarBalance for COP.
@TuCopFi TuCopFi changed the title feat: integrate USDC + USDm + USAT (Phase 1, data layer) feat: integrate USDC + USDm + USAT + 4-card BalanceCard (Phases 1 + 2) Jun 4, 2026
@TuCopFi TuCopFi merged commit 3ad9414 into Development Jun 4, 2026
8 checks passed
TuCopFi added a commit that referenced this pull request Jun 4, 2026
feat: dollar tokens Phase 3 foundation (stacked on PR #148)
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.

1 participant