Skip to content

fix(receipt): shorten crypto destination address so it can't overflow the card - #2527

Merged
abalinda merged 2 commits into
mainfrom
fix/receipt-crypto-address-overflow
Jul 27, 2026
Merged

fix(receipt): shorten crypto destination address so it can't overflow the card#2527
abalinda merged 2 commits into
mainfrom
fix/receipt-crypto-address-overflow

Conversation

@abalinda

@abalinda abalinda commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

A withdrawal to a Solana address renders the full 44-char base58 address in the receipt drawer's Address row. It's one unbreakable token, so the whole card blows out of the viewport on mobile (user report: Crisp session_779df6b2 / Notion TASK-20889). EVM (42-char) and Tron (34-char) destinations overflow the same way.

Root cause: the 2026-07-23 Tron fix made maskAccountIdentifier return crypto addresses verbatim (correctly bypassing the formatIban base58 corruption) — but nothing shortens them for display, unlike every other long value in the drawer (header, TX ID, Transfer ID all shorten). Structurally, PaymentInfoRow also had no flex containment: min-width: auto resolves to the token's full width, so any unbreakable value escapes the card.

Fix (3 pieces):

  1. maskAccountIdentifier crypto branch shortens for display (BfbXuD...NKNb19 — same shape the drawer header shows). Copy untouched: getAccountCopyValue still yields the verbatim address.
  2. PaymentInfoRow value wrapper gets min-w-0 break-words — any future unbreakable token wraps inside the card instead of stretching the row. break-word only activates when a word can't fit, so normal values render unchanged.
  3. The To row drops its viem isAddress pre-guard (EVM-only — Solana/Tron counterparties rendered full-length); printableAddress already passes usernames through untouched.

Why not printableAddress in (1): it re-validates shape via viem isAddress, which rejects wrong-checksum mixed-case strings and would silently fall back to the full overflowing address. The wire type (address / evm-address / peanut-wallet) already tells us it's a crypto address — shorten unconditionally, with a length guard for degenerate short strings.

Base = main: account-mask.utils.ts / isCryptoAddressType only exist on main (the Tron hotfix hasn't back-merged to dev). Merging adds to the existing main→dev back-merge debt.

Design notes / accepted trade-offs

  • Adversarially reviewed by two independent agents (correctness attack + codebase-wide overflow sweep). Findings: fix covers the reported row; deposit-instruction surfaces (where the full address must stay readable) are on a separate render path and untouched.
  • Known remaining sibling (out of scope, contained by (2) but not shortened): the isGuestBankClaim branch renders identifiers verbatim — a full IBAN now wraps instead of overflowing. Follow-up candidate, not bundled.
  • CRYPTO_ADDRESS_TYPES is a closed 3-value set; if the BE ever emits a new crypto wire type it falls to the plain branch (pre-existing property, unchanged here).

Risks / breaking changes

  • Display-only. Bank rails (IBAN/CLABE/PIX/ACH/alias) untouched — pinned by existing tests. break-words affects all 22 PaymentInfoRow consumers but only when a single word exceeds the line — no layout change for fitting values.
  • No cross-repo impact.

QA

  • npm test: 2154 passed (updated the 2 verbatim-display assertions to shortened; added EVM case).
  • Full typecheck clean; eslint on touched files: 0 new problems (5 pre-existing in TransactionDetailsReceipt, none on changed lines).

Screenshots

Captured on the local sandbox (mobile 375×667, seeded user, mocked Solana CRYPTO_WITHDRAW via route interception — same entry shape the BE serializes). Before = origin/main, After = this branch.

Before (main) After (this PR)
before after

The before shot reproduces the user's report exactly: the 44-char address escapes the card's right edge and the copy icon is pushed out of view. After: shortened display, copy icon inline, copy still yields the full address. (Assets live on the pr-assets-2527 branch — delete after merge.)

Summary by CodeRabbit

  • New Features

    • Crypto wallet addresses are now displayed in a shortened, readable format in transaction receipts.
    • Transaction details better support displaying usernames and addresses across supported networks.
  • Bug Fixes

    • Long wallet addresses and transaction identifiers now wrap within payment information rows instead of breaking the layout.
    • Improved receipt formatting for Tron, Solana, and EVM addresses.

… the card

A 44-char Solana address (and 42-char EVM / 34-char Tron) rendered
verbatim in the receipt's Address row is one unbreakable token — it
blows the drawer card out of the viewport on mobile (Crisp
session_779df6b2, TASK-20889). Verbatim display dates from the Tron
formatIban-corruption fix, which correctly stopped IBAN-chunking but
left no shortening at all.

Shorten by wire type in maskAccountIdentifier (start...end, same shape
as the drawer header and TX ID rows) instead of printableAddress, whose
viem isAddress re-validation would silently fall back to the full
overflowing string for wrong-checksum mixed-case addresses. Copy is
untouched: getAccountCopyValue still yields the verbatim address.
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Jul 27, 2026 3:57pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 22cb6b72-3cb9-4980-ba3d-9433d7d6ebda

📥 Commits

Reviewing files that changed from the base of the PR and between cd9c9c9 and 3f7b54c.

📒 Files selected for processing (2)
  • src/components/Payment/PaymentInfoRow.tsx
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx

📝 Walkthrough

Walkthrough

Long recognized crypto addresses are shortened for display, transaction receipt destinations use printable address formatting, and payment row values wrap within constrained layouts. Tests cover Tron, Solana, and EVM masking output.

Changes

Crypto display handling

Layer / File(s) Summary
Masking behavior and validation
src/utils/account-mask.utils.ts, src/components/TransactionDetails/__tests__/transaction-details.utils.test.ts
Recognized crypto address types now use shortenStringLong when longer than 16 characters, with updated Tron, Solana, and EVM display-path expectations.
Receipt and row rendering
src/components/TransactionDetails/TransactionDetailsReceipt.tsx, src/components/Payment/PaymentInfoRow.tsx
Receipt destinations always use printableAddress, while payment row values use constrained, wrapping styles for long unbroken strings.

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

Possibly related PRs

Suggested labels: enhancement

Suggested reviewers: kushagrasarathe, jjramirezn

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: shortening crypto destination addresses to prevent receipt card overflow.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/receipt-crypto-address-overflow

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 6274.15 → 6274.93 (+0.78)
Findings: 0 net (+10 new, -10 resolved)

🆕 New findings (10)

  • critical complexity — src/components/TransactionDetails/TransactionDetailsReceipt.tsx — CC 160, MI 52.91, SLOC 351
  • critical method-complexity — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — CC 108 SLOC 169
  • high hotspot — src/components/TransactionDetails/TransactionDetailsReceipt.tsx — 42 commits, +486/-1082 lines since 6 months ago
  • high complexity — src/utils/account-mask.utils.ts — CC 14, MI 49.24, SLOC 75
  • medium high-mdd — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — TransactionDetailsReceipt: MDD 178.4 (uses across many lines from declarations)
  • medium high-dlt — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — TransactionDetailsReceipt: DLT 80 (calls 80 distinct functions — high context load)
  • low high-mdd — src/utils/account-mask.utils.ts:85 — maskAccountIdentifier: MDD 18.5 (uses across many lines from declarations)
  • low structural-dup — components/Send/link/views/Success.link.send.view.tsx:102 — 14 duplicate lines / 73 tokens with components/TransactionDetails/TransactionDetailsReceipt.tsx:839
  • low missing-return-type — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — TransactionDetailsReceipt: exported fn missing return type annotation
  • low non-null-asserts — src/components/TransactionDetails/TransactionDetailsReceipt.tsx:74 — TransactionDetailsReceipt: 9 non-null assertions inside body

✅ Resolved (10)

  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx — CC 161, MI 52.86, SLOC 352
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — CC 109 SLOC 170
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx — 41 commits, +481/-1076 lines since 6 months ago
  • src/utils/account-mask.utils.ts — CC 13, MI 49.58, SLOC 74
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — TransactionDetailsReceipt: MDD 178.4 (uses across many lines from declarations)
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — TransactionDetailsReceipt: DLT 81 (calls 81 distinct functions — high context load)
  • src/utils/account-mask.utils.ts:85 — maskAccountIdentifier: MDD 14.8 (uses across many lines from declarations)
  • components/Send/link/views/Success.link.send.view.tsx:102 — 14 duplicate lines / 73 tokens with components/TransactionDetails/TransactionDetailsReceipt.tsx:840
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — TransactionDetailsReceipt: exported fn missing return type annotation
  • src/components/TransactionDetails/TransactionDetailsReceipt.tsx:75 — TransactionDetailsReceipt: 9 non-null assertions inside body

📈 Painscore deltas (top movers)

File Before After Δ
src/utils/account-mask.utils.ts 8.6 9.1 +0.6

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 2157 ran, 0 failed, 0 skipped, 38.0s

📊 Coverage (unit)

metric %
statements 60.9%
branches 44.5%
functions 50.0%
lines 61.3%
⏱ 10 slowest test cases
time test
3.9s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
1.2s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.5s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.4s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in validateInviteCode
0.4s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in validateInviteCode body
0.3s src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx › Bank withdrawal keeps the $1 minimum for sub-$1 amounts
0.3s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › keeps stickers off the username pill (final pass respects the keep-out)
0.2s src/utils/__tests__/demo-balance.test.ts › auto-refills a wallet older than the TTL on cold start
0.2s src/components/Card/__tests__/CardCountryConfirmScreen.test.tsx › renders candidate country names and disables Continue until a pick
0.2s src/utils/__tests__/demo-balance.test.ts › starts at the full balance on a fresh install and stamps a timestamp
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@abalinda

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

…ounterparty in To row

Belt-and-braces for the same overflow class: PaymentInfoRow's value
wrapper gets min-w-0 + break-words so any future unbreakable token
wraps inside the card instead of stretching the row (flex min-width:
auto resolves to the token's full width). The To row dropped its viem
isAddress pre-guard — it's EVM-only, so Solana/Tron counterparties
rendered full-length; printableAddress already passes usernames
through untouched.
@abalinda
abalinda marked this pull request as ready for review July 27, 2026 16:03

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

lgtm

@abalinda
abalinda merged commit 74ac9b1 into main Jul 27, 2026
24 of 26 checks passed
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.

2 participants