Skip to content

feat!: adopt SDK v3 — bigint money, dollar display, pre-sign verification - #1

Merged
MehranMazhar merged 1 commit into
mainfrom
treasury-break
Jul 30, 2026
Merged

feat!: adopt SDK v3 — bigint money, dollar display, pre-sign verification#1
MehranMazhar merged 1 commit into
mainfrom
treasury-break

Conversation

@MehranMazhar

Copy link
Copy Markdown
Member

Companion to clutchprotocol/clutch-hub-sdk-js#4 (and the node/hub PRs behind it). This app consumes the SDK via file:../clutch-hub-sdk-js, so it moves in lockstep.

Why this was forced, not optional

SDK v3 makes fare, farePaid, amount and balances bigint. In JavaScript, mixing bigint and number under + or < throws a TypeError at runtime — so a partial migration is a crash, not a rounding bug. Every money path had to move together.

The underlying reason for bigint: JSON.parse silently rounds integers above 2^53, and at the peg of 1 USD = 1,000,000 CLT a number fare was lossy before it was ever signed — the user would sign one amount believing they had approved another.

What changed

chainId is now passed to every ClutchHubSdk construction (six sites), sourced from src/config.js — the app's own config, never from the hub's chainInfo response. Asking the untrusted party which chain it is would defeat the check entirely. It is also required for the chain-bound auth challenge, so without it the app cannot obtain a token at all.

All six signTransaction calls now pass expected, so the SDK's new verification actually runs. The expectation is the values the app itself asked for, not values read back from the hub's reply — otherwise it would be verifying the hub against itself. A compromised hub altering a fare is now caught before the user signs.

The hub-injected referrer is displayed before signing. The client cannot verify it (that needs the signed-quote flow a later plan adds), so verifyUnsignedTransaction returns it and the confirm UI renders it. This is the user's only defence against a hub swapping in its own referrer address, and it is worthless if never shown.

Money display and input:

  • Everything user-facing goes through formatUsd$5.00, not 5000000. Raw CLT only as secondary detail.
  • Dollar input goes through parseUsdToClt in the new src/utils/money.js, integer-only. It pads the fraction to six digits, not two: a naive dollars-and-cents split turns "5.005" into $5.05. Input not matching ^\d+(\.\d{1,6})?$ is rejected rather than silently coerced.

The surviving toFixed calls are on latitude/longitude, which are genuinely floats — not money.

Deliberately not included

The plan for this app also described a top-up / redeem UI (deposit intents, payment instructions, redemption status). It is not here: those screens call a payment-orchestrator service that does not exist yet, and a UI against a non-existent backend is speculative code. They land with the plan that builds the orchestrator. The SDK's orchestrator client was cut for the same reason.

Verification

npm run build passes. Note its prebuild rebuilds the SDK from source, so this also proves the SDK v3 ↔ app integration compiles rather than just this app in isolation.

Lint: zero new errors and zero new warnings. Verified against the same files on main rather than assumed — this repo carries pre-existing eslint errors, and the two in TransactionHistory.jsx plus the react-hooks/exhaustive-deps warning in PassengerView.jsx all exist on main at shifted line numbers. None were introduced here, and none unrelated were "fixed" along the way.

The 595 kB bundle-size warning is also pre-existing.

🤖 Generated with Claude Code

…tion

The SDK's breaking v3 makes fares, balances and amounts bigint and adds
optional verification of the hub-returned unsigned transaction, so this
app had to move with it: mixing bigint and number under + or < throws at
runtime, which would have been a crash rather than a rounding bug.

Every ClutchHubSdk construction now passes chainId from src/config.js -
the app's own config, never the hub's chainInfo, since the hub is the
untrusted party the verification defends against. Without it the
chain-bound auth challenge cannot produce a valid token at all.

All six signTransaction calls now pass the values the app itself asked
for as `expected`, so a compromised hub altering a fare is caught before
the user signs. The hub-injected referrer cannot be verified, so it is
now displayed before signing instead - the only defence the user has
against a swapped referrer address.

Money is shown via formatUsd ($5.00, not 5000000), and dollar input goes
through parseUsdToClt in src/utils/money.js, which pads the fraction to
six digits: a naive dollars-and-cents split turns "5.005" into $5.05.

Deliberately NOT included: the top-up/redeem screens from the plan. They
call a payment orchestrator that does not exist yet, so they land with
the plan that builds it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MehranMazhar
MehranMazhar merged commit 8dcf139 into main Jul 30, 2026
2 of 3 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.

1 participant