fix(sign-tx): show asset issuer for value-bearing operations#2882
Conversation
On Stellar a non-native asset is identified by (code, issuer), not by code alone, so an attacker-issued USDC:<attacker> and legitimate Circle USDC both render as "USDC". The signing UI showed only the asset code for value-bearing operations, hiding the issuer at the point the user decides whether to sign, while changeTrust and the path-hop list already show it. Render the issuer alongside the code for every non-native asset in payment, path payments, DEX offers, and createClaimableBalance, reusing the existing CopyValue/KeyValueLine pattern. Native XLM has no issuer and renders no row. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
PR Preview build is ready: https://github.com/stellar/freighter/releases/tag/untagged-48978532d4ae95c07bb1 (SDF collaborators only — install instructions in the release description) |
Manual verification — Transaction Details now shows the asset issuerScreenshots of the Transaction Details view (the per-operation breakdown) for every value-bearing operation, captured by driving the built extension through the playground The key demonstration is #1 vs #3: same asset code Issuer legend (truncation shown in UI =
payment — non-native vs native vs look-alike1. Payment of non-native USDC → issuer 2. Payment of native XLM → no 3. Payment of look-alike USDC → issuer path payments — two assets, two issuer rows4. pathPaymentStrictSend (USDC → EURT) 5. pathPaymentStrictReceive (USDC → EURT) offers6. manageSellOffer — sell XLM (native, no row) / buy USDC (one issuer row) 7. manageBuyOffer (USDC / EURT) 8. createPassiveSellOffer (USDC / EURT) claimable balance9. createClaimableBalance of non-native USDC → issuer How these were captured
|
30f381c
into
fix/sign-tx-show-all-operation-fields
…r rows) Integrates the remote branch's asset-issuer work that landed after this worktree was branched. Resolutions: - Operations/index.tsx payment case: keep both #2882's KeyValueAssetIssuer row and master's amount-with-code / "Token Code" label. - Operations.test.tsx: keep both new describe suites (mobile-parity labels and the asset-issuer security regression tests). The #2882 payment issuer tests now assert the "Token Code" label master renamed it to; the issuer row is unaffected by that rename. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>









TL;DR
On Stellar, a non-native asset is identified by both its code and its issuer — two different assets can share the same code (e.g. a real
USDCand a look-alikeUSDCfrom a different issuer). The transaction signing screen showed only the asset code for operations that move or trade value (payments, path payments, DEX offers, claimable balances), so two assets with the same code looked identical at the moment you decide whether to sign.This PR shows the issuer alongside the code for every non-native asset in those operations, so what you see matches what you sign — consistent with the trustline and path-hop screens, which already show the issuer. Native XLM has no issuer and is unchanged. Presentational only.
Implementation details (for agents)
What changed — two files, presentational only; the issuer was already present on every parsed op object and is unchanged in the XDR.
extension/src/popup/components/signTransaction/Operations/index.tsxKeyValueAssetIssuer({ issuer?: string })that renders an "Asset Issuer" row using the existing copy-value pattern, ornullwhen there is no issuer (native XLM → no row):freighter/extension/src/popup/components/signTransaction/Operations/index.tsx
Lines 79 to 94 in 9e8b2c0
<CopyValue value={issuer} displayValue={truncateString(issuer)} />pattern thatchangeTrustalready uses for its issuer row (seeKeyVal'sKeyValueLine), so the new rows render and copy identically to what's already shipped.payment,pathPaymentStrictReceive,pathPaymentStrictSend,createPassiveSellOffer,manageSellOffer,manageBuyOffer,createClaimableBalance(12 rows total; path-payment and offer ops carry two assets each).clawback, the trust-flag ops, and liquidity-pool ops are intentionally excluded (issuer's own asset, or no(code, issuer)exposed on the op).extension/src/popup/components/__tests__/Operations.test.tsx— three regression tests:freighter/extension/src/popup/components/__tests__/Operations.test.tsx
Lines 252 to 346 in 9e8b2c0
manageSellOfferrenders exactly one issuer row (native selling side renders none),paymentrenders the issuer row,paymentrenders no issuer row.Verification
Operations.test.tsxsuite green (6/6, output reviewed).prettier --checkclean on both files.Operation-union diagnostics on this stack are unchanged base→head and resolve at current master).Follow-ups / out of scope
(code, issuer)to a verified, human-readable label (e.g.USDC · centre.io) and warning on look-alike collisions — separate defense-in-depth work.wallet-eng-monorepo#5).master). Two pre-existing stack conditions — ajest.config.jsesModulesgap and raw-tscunion-narrowing noise — are not introduced here and clear when the stack reachesmaster. On retarget, re-confirm the 12 insertion points still sit after the correct code rows, since Show all operation fields in the transaction signing details view #2829 restructured thesecaseblocks.