Conversation
Add price fetching, icon, mint address, and rate handling for XAUt following the same pattern as USDY but with standard (non-animated) balance display. Co-authored-by: Cursor <cursoragent@cursor.com>
feat: add XAUt (Tether Gold) Solana token support for Holders accounts
📝 WalkthroughWalkthroughAdds support for XAUT: new mint constant, image asset, icon mapping, and extends price handling (context, API type, hook) plus components to derive and use XAUT pricing; also increments app and iOS version numbers and VERSION_CODE. Changes
Sequence Diagram(s)sequenceDiagram
participant Component as UI Component
participant Hook as usePriceQuery
participant Context as PriceContext
participant API as fetchPrice
Component->>Hook: call usePriceQuery()
Hook->>Context: read context/defaults
Hook->>API: request price data
API-->>Hook: return { usdyPrice, xautPrice, ... }
Hook-->>Component: return [price, currency, usdyPrice, otherPrice, xautPrice]
Component->>Component: compute rate using usdyPrice or xautPrice based on mint
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
app/components/products/savings/SolanaTokenProduct.tsx (1)
67-67:⚠️ Potential issue | 🟡 MinorStale
displayName— should be'SolanaTokenProduct'.The component is named
SolanaTokenProductbut thedisplayNameis still'SolanaUSDCProduct', likely a leftover from before the component was generalized. This will be misleading in React DevTools and error traces.Proposed fix
-SolanaTokenProduct.displayName = 'SolanaUSDCProduct'; +SolanaTokenProduct.displayName = 'SolanaTokenProduct';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/products/savings/SolanaTokenProduct.tsx` at line 67, The component's displayName is stale—update SolanaTokenProduct.displayName (currently set to 'SolanaUSDCProduct') to 'SolanaTokenProduct' so React DevTools and error traces reflect the correct component name; locate the assignment to SolanaTokenProduct.displayName and change the string to 'SolanaTokenProduct'.
🧹 Nitpick comments (4)
app/fragments/wallet/views/solana/SolanaTokenInfoView.tsx (1)
15-19: Consider naming the token info IDs as constants.
'29256'and'29257'are opaque identifiers. Extracting them as named constants (e.g.USDY_TOKEN_INFO_ID/XAUT_TOKEN_INFO_ID) would make the mapping intent explicit and easier to extend.♻️ Suggested refactor
+const USDY_TOKEN_INFO_ID = '29256'; +const XAUT_TOKEN_INFO_ID = '29257'; + const tokenId = mint === usdyMintAddress - ? '29256' + ? USDY_TOKEN_INFO_ID : mint === xautMintAddress - ? '29257' + ? XAUT_TOKEN_INFO_ID : undefined;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/fragments/wallet/views/solana/SolanaTokenInfoView.tsx` around lines 15 - 19, The literal IDs '29256' and '29257' used when computing tokenId are opaque; define named constants (e.g. USDY_TOKEN_INFO_ID and XAUT_TOKEN_INFO_ID) near the top of SolanaTokenInfoView.tsx and replace the inline literals in the tokenId assignment (the expression using mint, usdyMintAddress, xautMintAddress) with those constants so the mapping intent is explicit and easier to maintain/extend.app/utils/holders/resolveHoldersIcon.tsx (1)
27-27:XAUT0icon branch is placed after theimageguard — consistent withUSDYbut diverges fromUSDT/USDC.The current control flow means a card with
ticker === 'XAUT0'that also carries animageURL will render the API image instead ofxautIcon. This matches howUSDYalready works (likely intentional), but is worth documenting so future maintainers understand the precedence is deliberate.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/utils/holders/resolveHoldersIcon.tsx` at line 27, The branch ordering causes ticker 'XAUT0' to be handled after the image URL guard (so an image URL wins), which is intentional for parity with 'USDY' but differs from 'USDT'/'USDC'; update resolveHoldersIcon to clarify this by adding a concise inline comment near the xautIcon declaration and the image-guard branch explaining that 'XAUT0' intentionally yields to an external image URL (mentioning 'USDY' parity and divergence from 'USDT'/'USDC') so future maintainers understand the precedence decision.app/components/products/savings/SolanaTokenProduct.tsx (1)
28-31: Duplicated rate-resolution logic — extract a shared helper.The pattern
mint === usdyMintAddress ? usdyPrice : mint === xautMintAddress ? xautPrice : 1is repeated in at least three places (SolanaTokenProduct,SolanaTokenHeader,SolanaTokenWalletComponent). As more tokens are onboarded, each site must be updated in lockstep.Consider extracting a helper, e.g.:
♻️ Suggested helper
// e.g. in a shared utils file export function resolveTokenRate( mint: string, usdyPrice: number, xautPrice: number ): number { if (mint === usdyMintAddress) return usdyPrice; if (mint === xautMintAddress) return xautPrice; return 1; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/components/products/savings/SolanaTokenProduct.tsx` around lines 28 - 31, Extract the duplicated mint-to-rate logic into a shared helper (e.g., resolveTokenRate) and replace the inline ternary in SolanaTokenProduct (the expression using token.address, usdyMintAddress, xautMintAddress, usdyPrice, xautPrice) with a call to that helper; implement the helper to accept mint, usdyPrice and xautPrice and return the appropriate rate (usdyPrice for usdyMintAddress, xautPrice for xautMintAddress, otherwise 1), export it from a common utils module and update the other callers (SolanaTokenHeader, SolanaTokenWalletComponent) to use the same helper so the logic is centralized.app/engine/PriceContext.tsx (1)
4-10: Consider replacing the positional tuple with a named record type.The context tuple has grown to 5 elements (
[Price, string, Price, Price, Price]), making it easy to mix up indices at consumption sites. A named object (e.g.,{ tonPrice, currency, solanaPrice, usdyPrice, xautPrice }) would be self-documenting and resilient to future additions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/engine/PriceContext.tsx` around lines 4 - 10, PriceContext currently uses a positional tuple type createContext<[Price, string, Price, Price, Price]> which is brittle; change it to a named record (e.g., createContext<{ tonPrice: Price; currency: string; solanaPrice: Price; usdyPrice: Price; xautPrice: Price }>) and update the default value to an object with those keys, then update all consumers that destructure the tuple to access the named properties (references: PriceContext and createContext in this file and any components that import PriceContext) so callers use context.tonPrice, context.currency, context.solanaPrice, context.usdyPrice, and context.xautPrice instead of positional indices.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (13)
VERSION_CODEapp/components/products/savings/SolanaTokenProduct.tsxapp/engine/PriceContext.tsxapp/engine/api/fetchPrice.tsapp/engine/hooks/currency/usePriceQuery.tsapp/fragments/wallet/SolanaTokenWalletFragment.tsxapp/fragments/wallet/views/solana/SolanaTokenInfoView.tsxapp/secure/KnownWallets.tsapp/utils/holders/resolveHoldersIcon.tsxassets/known/ic-xaut.webpassets/known/index.tsios/wallet/Info.plistpackage.json
🧰 Additional context used
🧬 Code graph analysis (5)
app/engine/PriceContext.tsx (1)
app/engine/hooks/currency/usePriceQuery.ts (1)
Price(7-7)
app/engine/hooks/currency/usePriceQuery.ts (1)
app/engine/hooks/currency/index.ts (1)
usePriceQuery(1-1)
app/components/products/savings/SolanaTokenProduct.tsx (2)
app/engine/PriceContext.tsx (1)
usePrice(23-29)app/secure/KnownWallets.ts (2)
usdyMintAddress(830-830)xautMintAddress(831-831)
app/fragments/wallet/SolanaTokenWalletFragment.tsx (2)
app/engine/PriceContext.tsx (1)
usePrice(23-29)app/secure/KnownWallets.ts (2)
usdyMintAddress(830-830)xautMintAddress(831-831)
app/fragments/wallet/views/solana/SolanaTokenInfoView.tsx (1)
app/secure/KnownWallets.ts (2)
usdyMintAddress(830-830)xautMintAddress(831-831)
🔇 Additional comments (9)
VERSION_CODE (1)
1-1: LGTM — version bump aligns withios/wallet/Info.plist(CFBundleVersion 283) andpackage.json(2.5.36).package.json (1)
3-3: LGTM — version bump consistent withVERSION_CODEandInfo.plist.app/engine/api/fetchPrice.ts (1)
9-9: LGTM — optionalxautPricefield is backward-compatible and consistent with the existingsolanaPrice/usdyPriceshape.ios/wallet/Info.plist (1)
22-46: LGTM —CFBundleShortVersionString(2.5.36) andCFBundleVersion(283) are consistent withpackage.jsonandVERSION_CODE.assets/known/index.ts (1)
58-58: No action needed—ic-xaut.webpis committed toassets/known/and properly referenced in bothassets/known/index.tsandresolveHoldersIcon.tsx.The asset file exists and is accessible via both
require('./ic-xaut.webp')andrequire('@assets/known/ic-xaut.webp'), so the Metro bundler will resolve the module correctly at build time.app/utils/holders/resolveHoldersIcon.tsx (1)
40-41: Verify the ticker string'XAUT0'matches the backend API response.The code checks for an exact match on
'XAUT0', but if the backend returns any variant (e.g.,'XAUT','XAUT0', or another format), it will silently fall through to the defaulttonIconwithout error. The API schema accepts any string without validation, and there is no test data or documentation confirming this value. Verify against the actual ticker value emitted by the Holders backend for this token.app/engine/hooks/currency/usePriceQuery.ts (1)
42-55: LGTM — consistent with the existing price object pattern.The
xautPriceconstruction mirrors the established structure forsolanaPriceandusdyPrice, and the return tuple is correctly extended.app/fragments/wallet/SolanaTokenWalletFragment.tsx (2)
203-232: LGTM — XAUT rate integration inSolanaTokenWalletComponentis consistent.The price data retrieval and rate calculation follow the same pattern established in
SolanaTokenHeader. The!!rateguard on line 254 correctly hides the subtitle when the rate is unavailable (i.e., 0).
121-168: XAUT tokens fall through to the generic balance view — verify this is intentional.The
isUsdycheck on line 121 means only USDy tokens get the animated rate display (USDYRateAmination). XAUT and all other tokens render the standardValueComponent+PriceComponent. This seems reasonable since the animation is USDy-specific, but worth confirming that no special display is needed for XAUT (e.g., gold price ticker).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@app/secure/KnownWallets.ts`:
- Around line 830-831: The export xautMintAddress currently points to the Solana
SPL mint for Tether Gold but needs an inline clarifying comment: above the
export xautMintAddress (and optionally near usdyMintAddress) add a comment
stating this address is for XAUt0 — the omnichain wrapped Tether Gold (LayerZero
OFT / USDT0 ecosystem), not Tether's native XAUT, and that it is not directly
issued or redeemable by Tether; keep the message brief and mention "XAUt0
(omnichain, LayerZero OFT) — not native XAUT" so future readers won't confuse
the supported mint.
---
Outside diff comments:
In `@app/components/products/savings/SolanaTokenProduct.tsx`:
- Line 67: The component's displayName is stale—update
SolanaTokenProduct.displayName (currently set to 'SolanaUSDCProduct') to
'SolanaTokenProduct' so React DevTools and error traces reflect the correct
component name; locate the assignment to SolanaTokenProduct.displayName and
change the string to 'SolanaTokenProduct'.
---
Duplicate comments:
In `@app/fragments/wallet/SolanaTokenWalletFragment.tsx`:
- Around line 63-73: Create a shared hook (e.g., useTokenRate) that encapsulates
the usePrice() destructuring and the rate resolution logic currently duplicated
in SolanaTokenWalletFragment and SolanaTokenProduct: inside the hook call
usePrice(), derive usdyPrice and xautPrice, compute rate using the same mint
checks (usdyMintAddress, xautMintAddress) and return the numeric rate; then
replace the local destructuring/usdyPrice/xautPrice/rate logic in
SolanaTokenWalletFragment (variables usdyPrice, xautPrice, rate) with a single
call to useTokenRate(mint) to remove duplication.
---
Nitpick comments:
In `@app/components/products/savings/SolanaTokenProduct.tsx`:
- Around line 28-31: Extract the duplicated mint-to-rate logic into a shared
helper (e.g., resolveTokenRate) and replace the inline ternary in
SolanaTokenProduct (the expression using token.address, usdyMintAddress,
xautMintAddress, usdyPrice, xautPrice) with a call to that helper; implement the
helper to accept mint, usdyPrice and xautPrice and return the appropriate rate
(usdyPrice for usdyMintAddress, xautPrice for xautMintAddress, otherwise 1),
export it from a common utils module and update the other callers
(SolanaTokenHeader, SolanaTokenWalletComponent) to use the same helper so the
logic is centralized.
In `@app/engine/PriceContext.tsx`:
- Around line 4-10: PriceContext currently uses a positional tuple type
createContext<[Price, string, Price, Price, Price]> which is brittle; change it
to a named record (e.g., createContext<{ tonPrice: Price; currency: string;
solanaPrice: Price; usdyPrice: Price; xautPrice: Price }>) and update the
default value to an object with those keys, then update all consumers that
destructure the tuple to access the named properties (references: PriceContext
and createContext in this file and any components that import PriceContext) so
callers use context.tonPrice, context.currency, context.solanaPrice,
context.usdyPrice, and context.xautPrice instead of positional indices.
In `@app/fragments/wallet/views/solana/SolanaTokenInfoView.tsx`:
- Around line 15-19: The literal IDs '29256' and '29257' used when computing
tokenId are opaque; define named constants (e.g. USDY_TOKEN_INFO_ID and
XAUT_TOKEN_INFO_ID) near the top of SolanaTokenInfoView.tsx and replace the
inline literals in the tokenId assignment (the expression using mint,
usdyMintAddress, xautMintAddress) with those constants so the mapping intent is
explicit and easier to maintain/extend.
In `@app/utils/holders/resolveHoldersIcon.tsx`:
- Line 27: The branch ordering causes ticker 'XAUT0' to be handled after the
image URL guard (so an image URL wins), which is intentional for parity with
'USDY' but differs from 'USDT'/'USDC'; update resolveHoldersIcon to clarify this
by adding a concise inline comment near the xautIcon declaration and the
image-guard branch explaining that 'XAUT0' intentionally yields to an external
image URL (mentioning 'USDY' parity and divergence from 'USDT'/'USDC') so future
maintainers understand the precedence decision.
| export const usdyMintAddress = 'A1KLoBrKBde8Ty9qtNQUtq3C2ortoC3u7twggz7sEto6'; | ||
| export const xautMintAddress = 'AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P'; No newline at end of file |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n app/secure/KnownWallets.ts | sed -n '825,835p'Repository: tonwhales/wallet
Length of output: 295
🌐 Web query:
XAUT Tether Gold official Solana SPL mint address
💡 Result:
The Solana SPL mint address for Tether Gold (XAUT / XAUt0) is:
AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P [1] [2]
Sources: Solflare token page [1] and Phantom token page (URL uses the mint address) [2].
🌐 Web query:
Solana XAUT AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P
💡 Result:
AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P is the Solana SPL mint address for XAUt0 (ticker often shown as XAUT0) — an omnichain / cross-chain version of Tether Gold (XAUT) (built using LayerZero’s OFT model via the USDT0 ecosystem). [1][3][4]
Notable confirmations:
- Solflare lists this mint as “Tether Gold (XAUT0)”. [1]
- Bitfinex announced XAUT0 deposits/withdrawals on Solana (Nov 21, 2025) and notes XAUT0 is not directly issued or redeemable by Tether. [2]
- The USDT0 ecosystem announced native omnichain deployments on Solana (Oct 2025) including XAUt0. [5]
- This same mint address is referenced by other on-chain dashboards as XAUT0. [6]
Sources: [1] Solflare token page, [2] Bitfinex release, [3] CoinDesk, [4] Cointelegraph, [5] XT press-release repost, [6] Midas Protocol dashboard.
Add a comment clarifying that xautMintAddress is for XAUt0 (omnichain Tether Gold), not native XAUT.
The hardcoded address AymATz4TCL9sWNEEV9Kvyz45CHVhDZ6kUgjTJPzLpU9P is the correct official Solana SPL mint for Tether Gold on Solana. However, it represents XAUt0 — an omnichain wrapped version built via LayerZero's OFT model — not Tether's native XAUT token. Add a comment above the export to clarify this distinction, noting that XAUt0 is not directly issued or redeemable by Tether and is maintained as part of the USDT0 ecosystem. This prevents user confusion about which XAUT variant is supported.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@app/secure/KnownWallets.ts` around lines 830 - 831, The export
xautMintAddress currently points to the Solana SPL mint for Tether Gold but
needs an inline clarifying comment: above the export xautMintAddress (and
optionally near usdyMintAddress) add a comment stating this address is for XAUt0
— the omnichain wrapped Tether Gold (LayerZero OFT / USDT0 ecosystem), not
Tether's native XAUT, and that it is not directly issued or redeemable by
Tether; keep the message brief and mention "XAUt0 (omnichain, LayerZero OFT) —
not native XAUT" so future readers won't confuse the supported mint.
Add swapUnsupportedMints set to filter out tokens that don't support swap functionality yet. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
app/fragments/wallet/SwapFragment.tsx (1)
113-118: Arrow function parametertshadows the outert(i18n) import.The
.filter((t) => ...)/.map((t) => ...)parameters shadow thettranslation function imported at line 5. While harmless today, any future change that needst()inside this chain will silently resolve to the wrongt. Rename the parameter to something liketokenorsolToken.♻️ Proposed fix — rename shadow parameter
- ...solanaTokens - .filter((t) => !swapUnsupportedMints.has(t.address)) - .map((t) => ({ - type: AssetType.SOLANA_TOKEN as AssetType.SOLANA_TOKEN, - token: t - })) + ...solanaTokens + .filter((token) => !swapUnsupportedMints.has(token.address)) + .map((token) => ({ + type: AssetType.SOLANA_TOKEN as AssetType.SOLANA_TOKEN, + token + }))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@app/fragments/wallet/SwapFragment.tsx` around lines 113 - 118, The arrow-function parameter `t` in the solanaTokens pipeline shadows the imported translation function `t`; rename the parameter in the .filter and .map callbacks (e.g., to `token` or `solToken`) so the chain uses unique names and avoids shadowing the `t` import; update occurrences in that expression referencing the parameter (the .filter and .map callbacks that produce { type: AssetType.SOLANA_TOKEN, token: ... }) to the new name to preserve behavior.
📜 Review details
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
app/fragments/wallet/SwapFragment.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
app/fragments/wallet/SwapFragment.tsx (1)
app/secure/KnownWallets.ts (1)
xautMintAddress(831-831)
🔇 Additional comments (1)
app/fragments/wallet/SwapFragment.tsx (1)
24-28: LGTM — correct and efficient use ofSetfor unsupported mint lookup.Module-level initialization is appropriate since
xautMintAddressis a compile-time constant, andSet.has()keeps the filter path O(1) regardless of how many entries are eventually added.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@app/fragments/wallet/SwapFragment.tsx`:
- Around line 113-118: The arrow-function parameter `t` in the solanaTokens
pipeline shadows the imported translation function `t`; rename the parameter in
the .filter and .map callbacks (e.g., to `token` or `solToken`) so the chain
uses unique names and avoids shadowing the `t` import; update occurrences in
that expression referencing the parameter (the .filter and .map callbacks that
produce { type: AssetType.SOLANA_TOKEN, token: ... }) to the new name to
preserve behavior.
Summary by CodeRabbit