# Bounce coverage — every outbound message's failure path GAUNTLET.md D7. TON delivers no failure synchronously: a send the destination refuses comes back as a **bounce**, a separate inbound message arriving later at the sender. Every outbound message therefore has a second code path. The two modes make opposite promises, and both are used deliberately: - **RichBounce** — the message can come back, carrying enough of the original body to identify it. The sender must handle it, or the effect is silently half-applied: state advanced on the way out, never reversed on the way back. - **NoBounce** — the message cannot come back. Value credited to an uninitialised address accumulates as its balance rather than vanishing, which is what a payment to a possibly-dormant wallet wants. Choosing NoBounce is a statement that there is nothing to reverse. So there are two failure classes: a RichBounce whose opcode the sender does not handle, and a NoBounce carrying state the sender would need to reverse. The first is mechanical and detected here; the second is a judgement call, enumerated in `BounceCoverage.spec.ts`. **Totals:** 112 outbound sends · 38 RichBounce · 74 NoBounce · 15 contracts whose bounce handler does real work. ## RichBounce sends — these can come back | contract | line | function | body | value | sender's bounce handler | |---|---|---|---|---|---| | `primes_bounty_vault.tolk` | 512 | `payOut` | `JettonTransfer` | `TRANSFER_GAS` | dispatches 1 (0x0f8a7ea5) | | `primes_collection.tolk` | 349 | `onInternalMessage` | `Populate` | `msg.heldSplit == null ? 0 : msg.mintValue` | **empty** | | `primes_constellations_collection.tolk` | 206 | `onInternalMessage` | `Populate` | `CON_ITEM_DEPLOY_VALUE + CON_CONFIRM_GAS` | **empty** | | `primes_generators_collection.tolk` | 417 | `onInternalMessage` | `Populate` | `0` | **empty** | | `primes_item.tolk` | 446 | `onInternalMessage` | `LedgerClaimTribute` | `ton("0.02")` | single-message | | `primes_jetton_master.tolk` | 162 | `deployAndCredit` | `InternalTransfer` | `ton("0.010") + forwardTonAmount` | dispatches 1 (0x178d4519) | | `primes_jetton_wallet.tolk` | 248 | `onInternalMessage` | `InternalTransfer` | `0` | dispatches 2 (0x178d4519, 0x7bdd97de) | | `primes_jetton_wallet.tolk` | 275 | `onInternalMessage` | `BurnNotification` | `0` | dispatches 2 (0x178d4519, 0x7bdd97de) | | `primes_ledger.tolk` | 2664 | `handleRetryItem` | `(unknown)` | `ITEM_DEPLOY_VALUE + held` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 3173 | `handleClaimDividend` | `CreditDividend` | `0` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 3218 | `handleRetryCredit` | `CreditTribute` | `CREDIT_TRIBUTE_VALUE` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 3253 | `handleRetryMint` | `JettonMint` | `DONATE_MINT_GAS` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 3346 | `handleIgnite` | `MintItem` | `ITEM_DEPLOY_VALUE` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 3725 | `handleDonateFloor` | `JettonMint` | `DONATE_MINT_GAS` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 4105 | `handleCardMint` | `DeployGenerator` | `ITEM_DEPLOY_VALUE` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 4282 | `payHeldSplit` | `CreditTribute` | `CREDIT_TRIBUTE_VALUE` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 4932 | `executeMint` | `MintItem` | `itemValue + heldSplitValue` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_ledger.tolk` | 4953 | `executeMint` | `JettonMint` | `REBATE_MINT_GAS` | dispatches 4 (0xc0000001, 0xb0000030, 0xb0000036, 0xd0000001) | | `primes_lp_position.tolk` | 352 | `forwardToTreasury` | `(unknown)` | `0` | single-message | | `primes_market.tolk` | 2026 | `closeLot` | `SettlePrimeClearing` | `MINT_PRICE + SETTLE_GAS` | dispatches 3 (0xb0000020, 0xb0000024, 0xb0000009) | | `primes_market.tolk` | 2044 | `closeLot` | `MintWonLot` | `MINT_PRICE + SETTLE_GAS` | dispatches 3 (0xb0000020, 0xb0000024, 0xb0000009) | | `primes_market.tolk` | 2469 | `onInternalMessage` | `ClearingCleared` | `returned` | dispatches 3 (0xb0000020, 0xb0000024, 0xb0000009) | | `primes_market.tolk` | 2535 | `onInternalMessage` | `ClearingCleared` | `premium + PREMIUM_HOP_GAS` | dispatches 3 (0xb0000020, 0xb0000024, 0xb0000009) | | `primes_minter_card.tolk` | 178 | `onInternalMessage` | `CardMint` | `0` | single-message | | `primes_ratchet.tolk` | 834 | `sendTstonWithdraw` | `JettonBurn` | `TSTON_EXIT_GAS` | dispatches 4 (DEDUST_SWAP_OP, TONSTAKERS_DEPOSIT_OP, TSTON_BURN_OP, TEP74_TRANSFER_OP) | | `primes_ratchet.tolk` | 874 | `sendTstonTransfer` | `(unknown)` | `value` | dispatches 4 (DEDUST_SWAP_OP, TONSTAKERS_DEPOSIT_OP, TSTON_BURN_OP, TEP74_TRANSFER_OP) | | `primes_ratchet.tolk` | 1543 | `handleStake` | `TonstakersDeposit` | `amount + TONSTAKERS_DEPOSIT_FEE + STAKE_GAS` | dispatches 4 (DEDUST_SWAP_OP, TONSTAKERS_DEPOSIT_OP, TSTON_BURN_OP, TEP74_TRANSFER_OP) | | `primes_ratchet.tolk` | 1914 | `handleFlush` | `(inline)` | `amount + DEDUST_SWAP_GAS` | dispatches 4 (DEDUST_SWAP_OP, TONSTAKERS_DEPOSIT_OP, TSTON_BURN_OP, TEP74_TRANSFER_OP) | | `primes_registrar.tolk` | 2482 | `onInternalMessage` | `ProveOwnership` | `REG_PROVE_GAS` | dispatches 1 (0x93000001) | | `primes_registrar.tolk` | 2640 | `onInternalMessage` | `MintConstellation` | `REG_MINT_CON_GAS` | dispatches 1 (0x93000001) | | `primes_stake.tolk` | 439 | `sendJetton` | `JettonTransfer` | `TRANSFER_GAS` | single-message | | `primes_stake_position.tolk` | 229 | `forwardSettle` | `Settle` | `0` | single-message | | `primes_treasury.tolk` | 610 | `sendJetton` | `JettonTransfer` | `gas` | dispatches 1 (0x96000014) | | `primes_treasury.tolk` | 957 | `onInternalMessage` | `TonPayout` | `prop.amount` | dispatches 1 (0x96000014) | | `primes_treasury.tolk` | 1009 | `onInternalMessage` | `JettonTransfer` | `0` | dispatches 1 (0x96000014) | | `primes_venue_timelock.tolk` | 200 | `sendUpdateVenue` | `UpdateVenue` | `value` | **empty** | | `primes_vesting.tolk` | 246 | `onInternalMessage` | `JettonTransfer` | `TRANSFER_GAS + NOTIFY_GAS` | dispatches 1 (0x0f8a7ea5) | | `primes_voucher.tolk` | 325 | `onInternalMessage` | `PayProgramBounty` | `0` | single-message | ## NoBounce sends — these cannot come back | contract | line | function | body | value | |---|---|---|---|---| | `primes_claim_receipt.tolk` | 80 | `refundExcess` | `(unknown)` | `0` | | `primes_claim_receipt.tolk` | 104 | `onInternalMessage` | `ReceiptDelta` | `0` | | `primes_collection.tolk` | 304 | `onInternalMessage` | `ItemAnnotate` | `0` | | `primes_collection.tolk` | 322 | `onInternalMessage` | `(inline)` | `0` | | `primes_collection.tolk` | 405 | `onInternalMessage` | `MintConfirmed` | `0` | | `primes_collection.tolk` | 499 | `onInternalMessage` | `RoyaltyToRatchet` | `ratchetShare + ROYALTY_LEDGER_HOP_GAS` | | `primes_collection.tolk` | 518 | `onInternalMessage` | `(empty)` | `operatorShare` | | `primes_constellation_item.tolk` | 192 | `onInternalMessage` | `ConstellationBuilt` | `CON_CONFIRM_GAS` | | `primes_constellation_item.tolk` | 219 | `onInternalMessage` | `OwnershipAssigned` | `msg.forwardAmount` | | `primes_constellation_item.tolk` | 232 | `onInternalMessage` | `Excesses` | `0` | | `primes_constellation_item.tolk` | 250 | `onInternalMessage` | `OwnershipProof` | `0` | | `primes_constellation_item.tolk` | 266 | `onInternalMessage` | `ReportStaticData` | `0` | | `primes_constellations_collection.tolk` | 186 | `onInternalMessage` | `(inline)` | `0` | | `primes_generator_item.tolk` | 196 | `onInternalMessage` | `OwnershipAssigned` | `msg.forwardAmount` | | `primes_generator_item.tolk` | 209 | `onInternalMessage` | `Excesses` | `0` | | `primes_generator_item.tolk` | 225 | `onInternalMessage` | `Excesses` | `0` | | `primes_generator_item.tolk` | 235 | `onInternalMessage` | `ReportStaticData` | `0` | | `primes_generators_collection.tolk` | 382 | `onInternalMessage` | `(inline)` | `0` | | `primes_generators_collection.tolk` | 509 | `onInternalMessage` | `RoyaltyToRatchet` | `ratchetShare + ROYALTY_LEDGER_HOP_GAS` | | `primes_generators_collection.tolk` | 528 | `onInternalMessage` | `(empty)` | `operatorShare` | | `primes_item.tolk` | 419 | `onInternalMessage` | `DividendCredited` | `0` | | `primes_item.tolk` | 477 | `onInternalMessage` | `OwnershipAssigned` | `msg.forwardAmount` | | `primes_item.tolk` | 490 | `onInternalMessage` | `Excesses` | `0` | | `primes_item.tolk` | 501 | `onInternalMessage` | `ReportStaticData` | `0` | | `primes_item.tolk` | 526 | `onInternalMessage` | `(empty)` | `0` | | `primes_item.tolk` | 542 | `onInternalMessage` | `OwnershipProof` | `0` | | `primes_jetton_master.tolk` | 247 | `onInternalMessage` | `Excesses` | `0` | | `primes_jetton_master.tolk` | 270 | `onInternalMessage` | `TakeWalletAddress` | `0` | | `primes_jetton_wallet.tolk` | 196 | `onInternalMessage` | `TransferNotification` | `msg.forwardTonAmount` | | `primes_jetton_wallet.tolk` | 214 | `onInternalMessage` | `Excesses` | `0` | | `primes_ledger.tolk` | 3092 | `refund` | `(inline)` | `amount` | | `primes_ledger.tolk` | 3372 | `handleIgnite` | `LaunchOpenMarket` | `LAUNCH_HOP_GAS` | | `primes_ledger.tolk` | 3403 | `handleSyncLaunch` | `LaunchOpenMarket` | `0` | | `primes_ledger.tolk` | 3548 | `handleClearingCleared` | `(empty)` | `treasuryDue` | | `primes_ledger.tolk` | 3811 | `handleMarkOffHead` | `MarkRejected` | `0` | | `primes_ledger.tolk` | 3835 | `handleSyncHead` | `HeadUpdate` | `0` | | `primes_ledger.tolk` | 3853 | `handleOpenBuild` | `RelayOpenBuild` | `0` | | `primes_ledger.tolk` | 3890 | `handleAdvanceHead` | `(inline)` | `0` | | `primes_ledger.tolk` | 3961 | `onInternalMessage` | `SettleConfirmed` | `15000000` | | `primes_ledger.tolk` | 3980 | `onInternalMessage` | `FloorQuote` | `0` | | `primes_ledger.tolk` | 4027 | `handleCardMint` | `CardMintRefunded` | `0` | | `primes_ledger.tolk` | 4200 | `handleSettle` | `SettleConfirmed` | `15000000` | | `primes_ledger.tolk` | 4218 | `forwardToRatchet` | `PoolInject` | `amount + RATCHET_HOP_GAS` | | `primes_ledger.tolk` | 4296 | `payHeldSplit` | `ForwardToOwner` | `REFERRAL_AMOUNT` | | `primes_ledger.tolk` | 4333 | `payHeldSplit` | `(empty)` | `TREASURY_AMOUNT + forfeitToTreasury + opMeters.treasuryHeld` | | `primes_ledger.tolk` | 4345 | `payHeldSplit` | `(empty)` | `operatorDue` | | `primes_ledger.tolk` | 4707 | `executeMint` | `CardAddRecruit` | `CARD_RECRUIT_GAS` | | `primes_ledger.tolk` | 4757 | `executeMint` | `CardPrimeMinted` | `CARD_PRIME_GAS` | | `primes_ledger.tolk` | 4977 | `executeMint` | `PayEraBounty` | `15000000` | | `primes_ledger.tolk` | 5037 | `executeMint` | `PaySpecialNumberRebate` | `15000000` | | `primes_ledger.tolk` | 5084 | `executeMint` | `AwardEraTrophy` | `REGISTRAR_HOP_GAS` | | `primes_ledger.tolk` | 5118 | `executeMint` | `RecordMint` | `REGISTRAR_HOP_GAS` | | `primes_market.tolk` | 1955 | `sendRefund` | `(inline)` | `amount` | | `primes_market.tolk` | 2212 | `onInternalMessage` | `MarkOffHead` | `OPEN_RESERVE_GAS` | | `primes_minter_card.tolk` | 197 | `onInternalMessage` | `(unknown)` | `0` | | `primes_minter_card.tolk` | 214 | `onInternalMessage` | `CardRecruitCounted` | `0` | | `primes_minter_card.tolk` | 253 | `onBouncedMessage` | `(unknown)` | `0` | | `primes_ratchet.tolk` | 898 | `returnCallerChange` | `Excesses` | `0` | | `primes_ratchet.tolk` | 1307 | `onInternalMessage` | `JettonBurn` | `0` | | `primes_registrar.tolk` | 2114 | `returnGenerator` | `ReturnGenerator` | `0` | | `primes_registrar.tolk` | 2142 | `burnGenerator` | `BurnGenerator` | `REG_BASE_GAS` | | `primes_registrar.tolk` | 2363 | `onInternalMessage` | `RelayAnnotation` | `0` | | `primes_registrar.tolk` | 2712 | `onInternalMessage` | `AccrueDiscovery` | `REG_ACCRUE_GAS` | | `primes_sink.tolk` | 299 | `sendBurn` | `JettonBurn` | `carryAll ? 0 : SINK_BURN_GAS` | | `primes_sink.tolk` | 312 | `sendRefund` | `JettonTransfer` | `0` | | `primes_sink.tolk` | 333 | `sendRefundAll` | `JettonTransfer` | `0` | | `primes_sink.tolk` | 398 | `onInternalMessage` | `QuoteFloor` | `0` | | `primes_sink.tolk` | 443 | `onInternalMessage` | `SinkAnnotate` | `change > 0 ? SINK_ANNOTATE_GAS : 0` | | `primes_stake.tolk` | 463 | `sendToChild` | `(unknown)` | `CHILD_GAS` | | `primes_stake.tolk` | 545 | `onInternalMessage` | `StakeCredit` | `0` | | `primes_treasury.tolk` | 633 | `sendToChild` | `(unknown)` | `gas` | | `primes_treasury.tolk` | 715 | `onInternalMessage` | `LpCredit` | `0` | | `primes_voucher.tolk` | 306 | `onInternalMessage` | `ReceiptAdvance` | `0` | | `primes_voucher.tolk` | 384 | `onBouncedMessage` | `ReceiptRestore` | `0` | ## Self-named response addresses — the reply must have an arm GAUNTLET.md G56, `CLAUDE.md`'s rule: a contract that writes its **own** address into a standard message's response field will be sent that standard's reply, and the catch-all `else => assert (in.body.isEmpty()) throw 101` eats it unless an arm exists. The reply is non-bounceable, so the value lands and only the trace goes red. Every response field here is TEP-74's `response_destination`, answered with `excesses#d53276db`. **A row with no arm fails this generator in every mode.** | contract | line | written via | arm | |---|---|---|---| | `primes_bounty_vault.tolk` | 617 | `payOut(… respondTo …)` | `Excesses =>` | | `primes_bounty_vault.tolk` | 669 | `payOut(… respondTo …)` | `Excesses =>` | | `primes_bounty_vault.tolk` | 691 | `payOut(… respondTo …)` | `Excesses =>` | | `primes_bounty_vault.tolk` | 810 | `payOut(… respondTo …)` | `Excesses =>` | | `primes_jetton_master.tolk` | 178 | `responseAddr:` | `Excesses =>` | | `primes_ratchet.tolk` | 841 | `responseAddr:` | `Excesses =>` | | `primes_ratchet.tolk` | 971 | `sendTstonTransfer(… responseAddr …)` | `Excesses =>` | | `primes_ratchet.tolk` | 1314 | `responseAddr:` | `Excesses =>` | | `primes_sink.tolk` | 306 | `responseAddr:` | `Excesses =>` | | `primes_treasury.tolk` | 977 | `sendJetton(… responseTo …)` | `Excesses =>` | ## Limits Lexical. It records which opcodes a bounce handler *inspects*, not whether the reversal it performs is correct — that is what the per-contract suites and the three escalated findings (D-51, D-52, D-53) are for. It also cannot tell whether a NoBounce was the right choice; the spec enumerates the value-bearing ones so each is a decision on the record rather than a default.