Currency-blind formatting renders wrong amounts for zero- and three-decimal currencies in UCP and spend-request output
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 72/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Active
- Tech stack
- typescript
- Domain
- cli
Research direction
Read packages/cli/src/utils/format-amount.ts and compare its behavior with the three named call sites in the issue. Check the existing UCP tests in packages/cli/src/commands/ucp/__tests__/ucp.test.tsx and add coverage for currencies with zero and three decimal places. Done means all three outputs format amounts correctly and the currency-code suffix behavior is resolved consistently.
Written by the indexing model from the issue text.
Description
Summary
Three call sites format a minor-unit amount with a hardcoded $ and /100:
packages/cli/src/commands/ucp/checkout-summary.tsx:10packages/cli/src/commands/ucp/catalog-search.tsx:31packages/cli/src/commands/spend-request/list.tsx:84
Each returns:
`$${(amount / 100).toFixed(2)} ${(currency ?? 'usd').toUpperCase()}`
A currency-aware helper already exists at packages/cli/src/utils/format-amount.ts, and it is used by transactions/list, payment-methods/list, approval-policy/retrieve, and spend-request/create. These three sites bypass it.
Actual vs expected
Amounts are in the currency's smallest unit.
| Input | Expected | Current output |
|---|---|---|
JPY 1000 |
¥1,000 |
$10.00 JPY |
KRW 5000 |
₩5,000 |
$50.00 KRW |
KWD 1000 |
KWD 1.000 |
$10.00 KWD |
EUR 1234 |
€12.34 |
$12.34 EUR |
USD 1234 |
$12.34 |
$12.34 USD |
The JPY and KRW cases are off by 100x, KWD by 10x, and every non-USD case shows the wrong symbol.
Reproduction
import { formatAmount } from './packages/cli/src/utils/format-amount';
// copied verbatim from the three call sites above
const current = (amount: number, currency: string) =>
`$${(amount / 100).toFixed(2)} ${(currency ?? 'usd').toUpperCase()}`;
formatAmount(1000, 'jpy'); // "¥1,000"
current(1000, 'jpy'); // "$10.00 JPY"
Why the current tests do not catch it
packages/cli/src/commands/ucp/__tests__/ucp.test.tsx asserts only USD strings ($99.00 USD, $25.00 USD, $0.50 USD), so only the one currency where /100 happens to be correct is exercised.
Reachability
Currency is not restricted to USD. packages/cli/src/commands/spend-request/schema.ts:40 is z.string().length(3).default('usd'), so any ISO code is accepted, and the UCP currency comes from the merchant.
Open question before a patch
The shared helper returns values without a currency-code suffix ($12.34), while these sites append the code ($12.34 USD). So the fix is a decision, not a pure swap:
- Use
formatAmountdirectly and drop the redundant code for currencies with a symbol. - Add an option to
formatAmountto append the code, and use it at all sites.
Happy to open a PR for whichever behavior you prefer.
- Dominant language
- TypeScript
- Stars
- 842
- Forks
- 136
- Avg merge
- 1d 10h
- Merged PRs (30d)
- 87
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from stripe/link-cli
-
420984Open
Maintainers usually reply within 1 day
-
عمرو عزوزOpen
Difficulty 5/5 Over a week Newbie friendliness 1/100
Maintainers usually reply within 1 day
-
Device-flow refresh token rejected immediately: 400 "refresh_token is invalid" on first refreshOpen
Difficulty 4/5 3-5 days Newbie friendliness 32/100
stripe/link-cli#406 · 2 comments ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 1/100
stripe/link-cli#392 · 1 comment ·
Maintainers usually reply within 1 day
-
75euroOpen
Difficulty 5/5 Over a week Newbie friendliness 10/100
stripe/link-cli#373 · 3 reactions ·
Maintainers usually reply within 1 day
Similar issues
-
effort:S priority:P2
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
cameri/nostream#811 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
dam-agents/dam#4562 ·
Maintainers usually reply within 1 day
-
bug p3 triaged
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
bug javascript P2-medium python release:v3.1
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
adrirubio/claude-deck#546 ·
Maintainers usually reply within 1 day