Repository navigation
fix(payments): reject lossy mint conversions and enforce exact u64 amounts - #2453
multipletwigs wants to merge 11 commits into
Conversation
[Critical impact] The PR appears safe to merge with the verified fixes in stacked PR #2473. SummaryPayments now reject interest-bearing, scaled-UI, and non-transferable mints. Amounts stay exact through conversion and instruction construction.
Reviews (7) · Last reviewed commit: "Merge remote-tracking branch 'origin/mai..." · Reviewed by Greptile |
|
React Doctor skipped this pull request — it changed no React files. Reviewed by React Doctor for commit |
…batches and recurring
…est or scale Single transfers, batches and payment requests convert through one loadPaymentAmountConverter per mint, so TransferChecked debits the requested UI amount on InterestBearing and ScaledUiAmount mints (APE-355, APE-399). Recurring payments and subscription plans refuse those mints, since their per-period cap is fixed in base units. A batch recipient that converts to zero base units is refused.
Cancel is an exit: run the start-admission token check only on resume, so a schedule on a paused, archived, or scaled/interest-bearing issued token can still be stopped.
…the cluster RPC from scope The UI-amount mint read answers a well-known mint declared on the open scope's cluster from the catalogue, skipping the RPC read; check:well-known-mints now also pins that no catalogue mint carries an interest-bearing or scaled UI amount extension. The converter and static-decimals read take the cluster RPC from scope instead of a caller-passed client.
1339d06 to
beedcbe
Compare
…-token-2022-ui-amounts
|
@greptileai please review again! |
G1de0n
left a comment
There was a problem hiding this comment.
Approving, refusing these mints fail-closed is a safer call than float/Clock-dependent conversion, and the exact u64 parse looks right. One thing to settle before merge: SDP issuance itself offers interestBearing / scaledUiAmount / nonTransferable on the stablecoin templates and interestBearing on securities (SUPPORT_MATRIX.md:44-50), so tokens we issue can't be paid after this, and an active recurring payment on one would 400 every cycle. Worth a prod query for issued tokens with those extensions that have active recurring payments or subscriptions, and either confirm it's zero or decide what happens to them. Smaller:
check:well-known-mintsis the guard for the catalogue shortcut inloadPaymentMint, but no workflow runs it. Worth wiring into CI onwell-known-tokens.tschanges.decodeMintwith token-2022 0.16.0 is a closed union, so a mint with a newer extension now 400s wheregetTokenSupplyused to work. Fine if accepted.- Stale "static scaling" comment and a redundant re-parse in
transfer-batches/resolve.ts:146-155.
G1de0n
left a comment
There was a problem hiding this comment.
Adding to the issuance point: the public docs present scaledUiAmount as part of the tokenized-security template (issuance-token-types.mdx:12, and the regulated-stablecoin tutorial :149 lists it under "Required extensions"), while definitions.ts only requires permanentDelegate + pausable. So anyone following the tutorial issues a security token that this PR then refuses for transfers, batches, pay-links and recurring, and nothing tells them at issuance time. Probably worth either fixing the docs or warning at token creation that these extensions aren't payable through SDP.
Small test gaps: /pay/:token/tx has no case for the extension refusal, and the NonTransferable refusal isn't covered in token-amount.test.ts.
…-token-2022-ui-amounts
Payments now reject interest-bearing, scaled-UI and non-transferable mints instead of converting a requested amount through floating-point rounding or truncation (APE-355, APE-399). Ordinary amounts use Kit strict decimal fixed-points and remain bigint through instruction construction.
parseTokenAmountenforces exact precision and the full unsigned 64-bit range; excess precision or overflow returns 400 through the payment converter. Values above 2^53 stay exact.RPC budget (mint/source reads only): a custom SPL send or batch goes from 3 calls to 2; a catalogue SPL send goes from 2 to 1. Unsupported interest/scaled mints are rejected after one mint read, with no clock read. Recurring builds reuse mint facts for the ATA lookup rather than fetching token supply separately.
Verification: 213-test initial payment/batch/recurring/subscription suite, final 147 recurring tests after mint-read cleanup, 18 mint-admission tests, 15 pay-link tests, 6 ramp-funding tests and 25 shared amount tests; API and shared-package typechecks; Biome; value-movement boundary check. The strengthened live catalogue check initially exposed transfer-fee extensions on USDG/PYUSD; its final policy checks interest, scale and non-transferability and passes all 22 catalogue mints.
Compatibility: interest-bearing, scaled-UI and non-transferable mints now return 400 on new payment builds. No schema migration or new dependency.