# Money arithmetic — every subtraction that could go negative GAUNTLET.md D3. TVM integers are **signed** 257-bit, so `a - b` with `b > a` does not wrap — it produces a negative, which either throws when serialized as `coins` or survives to invert a later comparison. So the question at every money subtraction is what bounds the subtrahend. Overflow is the lesser half and is handled separately: every money figure here is bounded far below 257 bits (`coins` serializes as at most 120 bits, ~1.3e36), and `MoneyArithmetic.spec.ts` computes the headroom of the widest intermediate — the rebate's `k · injection · S / T / K_SCALE` — rather than asserting it is fine. **30 money subtractions.** `MoneyArithmetic.spec.ts` enumerates them with the mechanism that bounds each, so a new one fails the build rather than being assumed safe. | contract | line | function | expression | self-guarding | |---|---|---|---|---| | `primes_bounty_vault.tolk` | 683 | `onInternalMessage` | `entry.remaining -= msg.amount;` | no | | `primes_bounty_vault.tolk` | 736 | `onInternalMessage` | `allow.remaining -= tier.bounty;` | no | | `primes_bounty_vault.tolk` | 878 | `onBouncedMessage` | `storage.paidTotal -= original.amount;` | no | | `primes_bounty_vault.tolk` | 898 | `onBouncedMessage` | `storage.paidTotal -= original.amount;` | no | | `primes_claim_receipt.tolk` | 121 | `onInternalMessage` | `storage.paid = storage.paid > msg.amount ? storage.paid - msg.amount : 0 as coins;` | yes (ternary) | | `primes_jetton_master.tolk` | 228 | `onInternalMessage` | `storage.totalSupply -= msg.amount;` | no | | `primes_jetton_master.tolk` | 306 | `onBouncedMessage` | `storage.totalSupply -= original.amount;` | no | | `primes_jetton_wallet.tolk` | 235 | `onInternalMessage` | `storage.balance -= msg.amount;` | no | | `primes_jetton_wallet.tolk` | 272 | `onInternalMessage` | `storage.balance -= msg.amount;` | no | | `primes_ledger.tolk` | 2658 | `handleRetryItem` | `meters.unroutedHeld -= held;` | no | | `primes_ledger.tolk` | 3136 | `handleClaimTribute` | `meters.tributeOwed -= msg.amount;` | no | | `primes_ledger.tolk` | 3193 | `handleDividendCredited` | `meters.divOutstanding -= msg.amount;` | no | | `primes_ledger.tolk` | 3214 | `handleRetryCredit` | `meters.unroutedHeld -= credit.amount;` | no | | `primes_ledger.tolk` | 5212 | `onBouncedMessage` | `meters.tributeOwed -= original.amount;` | no | | `primes_ratchet.tolk` | 1392 | `onInternalMessage` | `storage.swapped -= storage.inFlightFlush;` | no | | `primes_ratchet.tolk` | 1537 | `handleStake` | `storage.pending -= amount;` | no | | `primes_ratchet.tolk` | 1838 | `handleFlush` | `storage.pending -= amount;` | no | | `primes_ratchet.tolk` | 1956 | `onBouncedMessage` | `storage.swapped -= storage.inFlightFlush;` | no | | `primes_stake.tolk` | 391 | `accrue` | `st.streamRemaining -= amt;` | no | | `primes_stake.tolk` | 428 | `settlePosition` | `st.unclaimedTotal -= excess;` | no | | `primes_stake.tolk` | 614 | `onInternalMessage` | `st.lockedTotal -= principal;` | no | | `primes_stake.tolk` | 617 | `onInternalMessage` | `st.unclaimedTotal -= payout;` | no | | `primes_stake.tolk` | 676 | `onBouncedMessage` | `t.claimedTotal -= original.amount;` | no | | `primes_stake.tolk` | 697 | `onBouncedMessage` | `t.claimedTotal -= reward;` | no | | `primes_stake_position.tolk` | 292 | `onInternalMessage` | `storage.stakedTotal -= pos.amount;` | no | | `primes_treasury.tolk` | 946 | `onInternalMessage` | `bal.primesBalance -= prop.amount;` | no | | `primes_treasury.tolk` | 948 | `onInternalMessage` | `bal.tstonBalance -= prop.amount;` | no | | `primes_treasury.tolk` | 1001 | `onInternalMessage` | `bal.primesBalance -= budget;` | no | | `primes_treasury.tolk` | 1127 | `onBouncedMessage` | `dist.distributedTotal -= original.amount;` | no | | `primes_voucher.tolk` | 378 | `onBouncedMessage` | `storage.paidTotal = storage.paidTotal > amount ? storage.paidTotal - amount : 0 as coins;` | yes (ternary) | ## The three mechanisms - **local** — an assert or ternary in the same function bounds the subtrahend. Self-evident on reading. - **record** — the amount comes from the record being deleted, and was added to the aggregate when that record was created. Safe *iff* the aggregate is maintained in step, which is what `FuzzInvariants`' I10 proves. (It also named C8's escrow reconciliation until 2026-09-21; D-90 deleted the escrow.) - **invariant** — safe only because a cross-contract invariant holds. Not a bug, but a site whose safety rests on a test rather than on a read, and an auditor is entitled to be told which ones those are.