Skip to content

Restrict currency treatment to verified asset IDs - #790

Merged
tiero merged 7 commits into
masterfrom
claude/asset-id-verification-1wpjke
Jul 17, 2026
Merged

tiero merged 7 commits into
masterfrom
claude/asset-id-verification-1wpjke

Conversation

@tiero

@tiero tiero commented Jul 17, 2026 •

Copy link
Copy Markdown
Member

It fixes #791

Summary

This change implements a security measure to prevent unverified assets from claiming currency identity (official logos, fiat pricing, fiat-style formatting) based on self-reported tickers. Currency treatment is now restricted to asset IDs that are either in the curated verified assets list or approved by the icon approval manager.

Key Changes

  • Added isVerifiedAsset function to WalletContext: Checks if an asset ID is in the curated list (via AssetsContext.isRegistered) or approved by the icon approval manager
  • Updated AssetCard component: Only shows official token logos and applies fiat-style formatting for verified assets
  • Updated TransactionsList component: Restricts currency treatment (logos, fiat formatting) to verified asset IDs; unverified assets display their ticker without currency formatting
  • Updated Transaction detail view: Applies the same verification logic for asset display
  • Updated SendForm: Only shows official token logos for verified assets in the asset selector
  • Updated usePortfolioFiat hook: Only assigns fiat prices to verified assets, preventing unverified assets from claiming fiat conversion rates
  • Added comprehensive test coverage: New test for AssetCard verification behavior and additional test case for usePortfolioFiat with unverified assets

Implementation Details

  • The isVerifiedAsset function is centralized in WalletProvider and checks both the icon approval manager and the assets registry
  • A new trustedTicker variable is introduced throughout the codebase to distinguish between self-reported tickers and tickers that have earned currency treatment through verification
  • The native Bitcoin asset (empty assetId) is always considered trusted
  • All token logo rendering now uses trustedTicker instead of raw ticker values
  • Fiat amount calculations in portfolio views are gated behind the verification check

https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added verification-aware asset handling across wallet screens.
    • Send and transaction views now reflect verified status with trusted formatting and an “Unverified” badge.
    • Send asset picker now focuses on verified options when selecting assets.
  • Bug Fixes

    • Unverified assets no longer receive official token logos, trusted ticker rendering, or fiat price inclusion.
  • Tests

    • Expanded automated coverage for verified vs unverified asset display and portfolio/fiat calculations.

Tickers are self-reported metadata: anyone can mint an asset with ticker
"EUR" and the wallet would render the official flag logo, format its
balance as fiat, and apply the EUR exchange rate to the portfolio total.

Add isVerifiedAsset(assetId) to WalletContext, backed by the curated
asset registry and the verified-assets list (both keyed by asset ID),
and require it before a ticker earns any currency treatment:

- usePortfolioFiat: no fiat price or sats-equivalent for unverified
  assets, so they no longer inflate the portfolio total
- AssetCard, TransactionsList, Transaction, Send form: official token
  logos and fiat-style amount formatting only for verified asset IDs;
  unverified assets fall back to the generic avatar and plain amounts

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
@coderabbitai

coderabbitai Bot commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@tiero, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 25 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f2818ac9-d82a-4333-a516-7a24cb516100

📥 Commits

Reviewing files that changed from the base of the PR and between 2f7cb75 and 0846ceb.

📒 Files selected for processing (7)
  • src/components/AssetCard.tsx
  • src/components/TokenLogo.tsx
  • src/components/TransactionsList.tsx
  • src/components/UnverifiedBadge.tsx
  • src/screens/Wallet/Send/Form.tsx
  • src/screens/Wallet/Transaction.tsx
  • src/test/e2e/send.test.ts

Walkthrough

The wallet now exposes asset verification status and uses it to gate ticker-based formatting, token logos, send-form icons, transaction labels, and fiat portfolio calculations. Tests cover verified and unverified asset behavior.

Changes

Verified asset handling

Layer / File(s) Summary
Verification provider contract
src/providers/wallet.tsx
WalletContext exposes isVerifiedAsset, based on registered assets and approved icons.
Trusted asset display rendering
src/components/AssetCard.tsx, src/components/TransactionsList.tsx, src/screens/Wallet/Transaction.tsx
Asset amounts, labels, and token logos use trusted tickers only for verified assets, while native Bitcoin remains supported.
Verified send asset selection
src/screens/Wallet/Send/Form.tsx
The send selector lists verified assets and marks selected unverified assets.
Fiat gating and validation
src/hooks/usePortfolioFiat.ts, src/test/components/AssetCard.test.tsx, src/test/hooks/usePortfolioFiat.test.tsx, src/test/screens/mocks.ts
Unverified assets receive no fiat pricing, with tests covering formatting, logo visibility, totals, and updated wallet mocks.

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

Sequence Diagram(s)

sequenceDiagram
  participant AssetsContext
  participant WalletProvider
  participant WalletViews
  participant PortfolioHook
  AssetsContext->>WalletProvider: provide asset registration
  WalletProvider->>WalletProvider: combine registration and icon approval
  WalletProvider-->>WalletViews: return isVerifiedAsset(assetId)
  WalletProvider-->>PortfolioHook: return isVerifiedAsset(assetId)
  WalletViews->>WalletViews: derive trusted ticker, labels, and logos
  PortfolioHook->>PortfolioHook: compute fiat only for verified assets
Loading

Possibly related PRs

  • arkade-os/wallet#628: Modifies overlapping token-logo ticker mapping in AssetCard and transaction rendering.
  • arkade-os/wallet#771: Modifies overlapping portfolio fiat and transaction asset ticker derivation paths.

Suggested reviewers: pietro909, arkanaai, sahilc0

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title concisely describes the main change: restricting currency treatment to verified asset IDs.
Linked Issues check ✅ Passed The changes stop unverified tickers from driving icons, fiat pricing, sats equivalents, and total-balance treatment, matching #791.
Out of Scope Changes check ✅ Passed The diff stays focused on verification-aware asset rendering, pricing, and tests with no clear unrelated code paths.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/asset-id-verification-1wpjke

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.

@tiero
tiero marked this pull request as ready for review July 17, 2026 14:49

@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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/screens/Wallet/Transaction.tsx (1)

151-175: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Include ticker in the label fallback sequence to prevent redundant names.

In TransactionsList.tsx, the label falls back to ticker before name (accountTicker ?? ticker ?? meta?.name). However, in Transaction.tsx, ticker is omitted from the label fallback:

const label = accountTicker ?? name ?? `${a.assetId.slice(0, 8)}...`

For unverified assets, accountTicker is undefined. If the asset has both a name and a ticker, label will evaluate to name. This causes the asset amount to display as {amount} {name}, and immediately below it, the secondary text will also render {name} (because name && ticker && !accountTicker evaluates to true).

Adding ticker to the fallback sequence ensures consistency with the list view and prevents displaying the name twice.

🐛 Proposed fix
-                const label = accountTicker ?? name ?? `${a.assetId.slice(0, 8)}...`
+                const label = accountTicker ?? ticker ?? name ?? `${a.assetId.slice(0, 8)}...`
                 const tokenLogoTicker = tokenLogoTickerForTicker(trustedTicker)
                 return (
🤖 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/screens/Wallet/Transaction.tsx` around lines 151 - 175, Update the label
fallback in the asset rendering block of Transaction.tsx to use ticker before
name, matching the fallback order used by TransactionsList.tsx. Preserve the
existing accountTicker priority and assetId truncation fallback so unverified
assets with both a name and ticker display the ticker as the primary label
without duplicating the name.
🤖 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/components/TransactionsList.tsx`:
- Around line 113-124: Convert a.amount to BigInt at the
prettyCurrencyAssetAmount call in the transaction row rendering, matching the
existing pattern in Transaction.tsx while leaving the label and trustedTicker
handling unchanged.

In `@src/screens/Wallet/Send/Form.tsx`:
- Around line 943-946: Update the asset selector and selected-asset summary
around AssetIcon to gate ticker display with isVerifiedAsset(asset.assetId). For
unverified assets, render the asset name and amount without any ticker suffix;
retain the existing ticker-based labels only for verified assets.
- Around line 69-71: Update AssetIcon so every asset visual is gated by
verified, not only the ticker used by TokenLogo. Restrict the asset.icon branch
and fallback/initial rendering to verified assets, ensuring unverified assets
render no misleading icon or ticker-derived initial while preserving verified
behavior.

---

Outside diff comments:
In `@src/screens/Wallet/Transaction.tsx`:
- Around line 151-175: Update the label fallback in the asset rendering block of
Transaction.tsx to use ticker before name, matching the fallback order used by
TransactionsList.tsx. Preserve the existing accountTicker priority and assetId
truncation fallback so unverified assets with both a name and ticker display the
ticker as the primary label without duplicating the name.
🪄 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: f401d68e-2fb0-4ab0-843a-8aab16199010

📥 Commits

Reviewing files that changed from the base of the PR and between 82403d3 and 443e4bb.

📒 Files selected for processing (9)
  • src/components/AssetCard.tsx
  • src/components/TransactionsList.tsx
  • src/hooks/usePortfolioFiat.ts
  • src/providers/wallet.tsx
  • src/screens/Wallet/Send/Form.tsx
  • src/screens/Wallet/Transaction.tsx
  • src/test/components/AssetCard.test.tsx
  • src/test/hooks/usePortfolioFiat.test.tsx
  • src/test/screens/mocks.ts

Comment thread src/components/TransactionsList.tsx Resolved
Comment thread src/screens/Wallet/Send/Form.tsx Resolved
Comment thread src/screens/Wallet/Send/Form.tsx Resolved
…ting

Address review feedback on the verified-asset gating:

- Show an "Unverified" badge next to the asset name in AssetCard rows and
  the send-form asset selector, so a self-reported ticker ("USD", "EUR")
  is visibly flagged instead of silently trusted
- AssetIcon now reads isVerifiedAsset from WalletContext itself instead of
  prop-drilling a verified flag through three call sites (same pattern as
  AssetCard)
- Transaction detail: fall back to ticker before name for the asset label,
  matching TransactionsList and avoiding the name rendering twice
- Add a regression test pinning that an unverified asset with ticker "BTC"
  is not rendered as native bitcoin; drop a redundant test wrapper

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying wallet-mutinynet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0846ceb
Status: ✅  Deploy successful!
Preview URL: https://9aa952ae.arkade-wallet.pages.dev
Branch Preview URL: https://claude-asset-id-verification.arkade-wallet.pages.dev

View logs

@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying tmp-boltz-upstream-mainnet-arkade-wallet with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0846ceb
Status: ✅  Deploy successful!
Preview URL: https://aea9abbc.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev
Branch Preview URL: https://claude-asset-id-verification.tmp-boltz-upstream-mainnet-arkade-wallet.pages.dev

View logs

@cloudflare-workers-and-pages

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

Copy link
Copy Markdown

Deploying wallet-bitcoin with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0846ceb
Status: ✅  Deploy successful!
Preview URL: https://cae6580b.wallet-bitcoin.pages.dev
Branch Preview URL: https://claude-asset-id-verification.wallet-bitcoin.pages.dev

View logs

The asset selector now only offers verified assets. Unverified assets can
still be sent deliberately via the Assets app detail screen, which preselects
the asset in the send form — the trigger keeps its "Unverified" badge for
that case, and the dropdown badge is gone since every listed option is
verified. Holding only unverified assets no longer surfaces the selector.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/screens/Wallet/Transaction.tsx (1)

167-169: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Gate unverified asset text with an explicit "Unverified" badge.

While official logos and fiat formatting are correctly restricted, the unverified ticker or name is still displayed here as the primary label without an indicator. This allows a self-reported ticker (like USD) to appear trusted in the receipt view.

Please import Badge at the top of the file (import { Badge } from '../../components/ui/badge') and append the badge next to the label when the asset is not trusted.

Based on learnings, if an asset is unverified, it may be shown as plain text only when accompanied by an explicit “Unverified” badge.

🛡️ Proposed fix to add the badge
-                      <span className='transaction-detail-asset__amount'>
-                        {prettyCurrencyAssetAmount(BigInt(a.amount), decimals, trustedTicker)} {label}
-                      </span>
+                      <span className='transaction-detail-asset__amount'>
+                        {prettyCurrencyAssetAmount(BigInt(a.amount), decimals, trustedTicker)} {label}
+                        {!trusted ? (
+                          <Badge variant='outline' className='ml-1.5'>
+                            Unverified
+                          </Badge>
+                        ) : null}
+                      </span>
🤖 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/screens/Wallet/Transaction.tsx` around lines 167 - 169, Update the
transaction asset amount rendering in Transaction to import and use Badge,
appending an explicit “Unverified” badge beside label whenever the asset is not
trusted. Preserve the existing label and amount rendering for trusted assets,
and ensure unverified labels are never shown without the badge.

Source: Learnings

🤖 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.

Outside diff comments:
In `@src/screens/Wallet/Transaction.tsx`:
- Around line 167-169: Update the transaction asset amount rendering in
Transaction to import and use Badge, appending an explicit “Unverified” badge
beside label whenever the asset is not trusted. Preserve the existing label and
amount rendering for trusted assets, and ensure unverified labels are never
shown without the badge.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ae68d8e2-665a-49f1-9787-951ed616860a

📥 Commits

Reviewing files that changed from the base of the PR and between 443e4bb and 2f7cb75.

📒 Files selected for processing (4)
  • src/components/AssetCard.tsx
  • src/screens/Wallet/Send/Form.tsx
  • src/screens/Wallet/Transaction.tsx
  • src/test/components/AssetCard.test.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/components/AssetCard.test.tsx
  • src/components/AssetCard.tsx

claude added 4 commits July 17, 2026 17:03
The receipt view showed an unverified asset's self-reported ticker or name
as the label with no indicator. Append the same Unverified badge used in
asset cards and the send selector, so unverified labels are never shown
without it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
Apply review cleanups, behavior-identical except one addition:

- Extract the Unverified badge into a shared UnverifiedBadge component
  (was copy-pasted verbatim in AssetCard, the send selector, and the
  transaction receipt)
- Add trustedAssetTickers() next to the other ticker helpers in
  TokenLogo.tsx as the single sanctioned derivation of accountTicker /
  trustedTicker, replacing the duplicated inline trio in TransactionsList
  and Transaction
- Drop the dead `assetId &&` conjunct in AssetCard's badge condition and
  the identity BigInt() wrap in the receipt (Asset.amount is bigint)
- Show the Unverified badge on activity-list asset rows too — the one
  surface still printing self-reported tickers without it

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
For asset transfers tx.amount is only the dust carrying the asset; rendering
it fiat-converted as Amount/Total reads as a price for the asset. Omit both
rows on asset receipts (Table already skips empty values), keeping fees.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
The send picker now only lists verified assets, and nothing is verifiable
on regtest, so the e2e asset-send test timed out waiting for the selector.
Route both sends through the Arkade Mint asset detail screen, which
preselects the asset in the send form — the sanctioned path for unverified
assets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EUQWiNVnjj2dtcLLFR9pWf
@tiero
tiero merged commit acc6e5b into master Jul 17, 2026
6 checks passed
tiero pushed a commit that referenced this pull request Jul 18, 2026
Takes #790's isVerifiedAsset as the single trust gate: portfolio
designations, receipt asset rows, the send-form picker/logos, and
activity rows all require a verified asset ID before a ticker earns
currency treatment, with the Unverified badge on anything self-reported.
Asset transfers that can't be valued as an account hide Amount/Total
(master semantics) instead of showing the dust carrier as a price.
Also picks up the Virtual Coins asset-id display improvements.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UewCGCJveUjTUgmBxMk3Ps
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.

Don't use ticker to derive icon or adding to total balance.

2 participants