# Outbound message surface — where TON can leave a contract CONCEPT.md §8: **no admin withdraw path on any TON balance, not timelocked, not multisig.** TON only leaves a contract through an outbound message, so the set of `createMessage` sites is the set of ways money can move. This is all of them, across all 25 contracts, classified by who the destination is. `NoAdminWithdraw.spec.ts` asserts this table's shape: every destination must fall in a known class, and the `operator` class — the only one §8 is about — must be exactly the sites listed below, each paying a formula-fixed amount. A new send to an unrecognised destination fails that spec rather than being assumed benign. **§8 is a claim about moving TON, and that is narrower than "no privileged keys".** Three standing credentials do exist — the venue timelock's proposer and two signing keys — none of which can move a TON balance. They are listed, with what each can and cannot do, in [privileged-credentials.md](privileged-credentials.md), kept honest by `PrivilegedCredentials.spec.ts`. **That page also carries the governance disclosure** (`GAUNTLET.md` X5): who controls this money in year three is the treasury's electorate, a vote is a simple majority with **no quorum**, and what bounds it is what the treasury cannot reach — not `T`, `S`, `pending`, `owed`, `k`, `K_CEIL` or the split. **Totals:** peer 62 · player 32 · deploy 10 · operator 3 · via-helper 2 · venue 2 · governed 1 — 112 sites. | contract | line | handler | destination | class | value | |---|---|---|---|---|---| | `primes_bounty_vault.tolk` | 512 | payOut | `b.jettonWalletAddr` | peer | `TRANSFER_GAS` | | `primes_claim_receipt.tolk` | 80 | refundExcess | `storage.claimant` | player | `0` | | `primes_claim_receipt.tolk` | 104 | ReceiptAdvance → onInternalMessage | `storage.voucherAddr` | peer | `0` | | `primes_collection.tolk` | 304 | RelayAnnotation → onInternalMessage | `itemAddr` | peer | `0` | | `primes_collection.tolk` | 322 | GetRoyaltyParams → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_collection.tolk` | 349 | MintItem → onInternalMessage | `AutoDeployAddress { ... }` | deploy | `msg.heldSplit == null ? 0 : msg.mintValue` | | `primes_collection.tolk` | 405 | MintItem → onInternalMessage | `storage.ledgerAddr` | peer | `0` | | `primes_collection.tolk` | 499 | MintItem → onInternalMessage | `storage.ledgerAddr` | peer | `ratchetShare + ROYALTY_LEDGER_HOP_GAS` | | `primes_collection.tolk` | 518 | MintItem → onInternalMessage | `aux.royaltyDest` | operator | `operatorShare` | | `primes_constellation_item.tolk` | 192 | Populate → onInternalMessage | `msg.registrar` | peer | `CON_CONFIRM_GAS` | | `primes_constellation_item.tolk` | 219 | Transfer → onInternalMessage | `msg.newOwner` | player | `msg.forwardAmount` | | `primes_constellation_item.tolk` | 232 | Transfer → onInternalMessage | `respondTo` | player | `0` | | `primes_constellation_item.tolk` | 250 | ProveOwnership → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_constellation_item.tolk` | 266 | GetStaticData → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_constellations_collection.tolk` | 186 | GetRoyaltyParams → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_constellations_collection.tolk` | 206 | MintConstellation → onInternalMessage | `AutoDeployAddress { ... }` | deploy | `CON_ITEM_DEPLOY_VALUE + CON_CONFIRM_GAS` | | `primes_generator_item.tolk` | 196 | Transfer → onInternalMessage | `msg.newOwner` | player | `msg.forwardAmount` | | `primes_generator_item.tolk` | 209 | Transfer → onInternalMessage | `respondTo` | player | `0` | | `primes_generator_item.tolk` | 225 | Burn → onInternalMessage | `msg.responseDestination` | player | `0` | | `primes_generator_item.tolk` | 235 | GetStaticData → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_generators_collection.tolk` | 382 | GetRoyaltyParams → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_generators_collection.tolk` | 417 | DeployGenerator → onInternalMessage | `AutoDeployAddress { ... }` | deploy | `0` | | `primes_generators_collection.tolk` | 509 | DeployGenerator → onInternalMessage | `storage.ledgerAddr` | peer | `ratchetShare + ROYALTY_LEDGER_HOP_GAS` | | `primes_generators_collection.tolk` | 528 | DeployGenerator → onInternalMessage | `aux.royaltyDest` | operator | `operatorShare` | | `primes_item.tolk` | 419 | CreditDividend → onInternalMessage | `storage.ledgerAddr` | peer | `0` | | `primes_item.tolk` | 446 | ClaimTribute → onInternalMessage | `storage.ledgerAddr` | peer | `ton("0.02")` | | `primes_item.tolk` | 477 | Transfer → onInternalMessage | `msg.newOwner` | player | `msg.forwardAmount` | | `primes_item.tolk` | 490 | Transfer → onInternalMessage | `respondTo` | player | `0` | | `primes_item.tolk` | 501 | GetStaticData → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_item.tolk` | 526 | ForwardToOwner → onInternalMessage | `m.owner` | player | `0` | | `primes_item.tolk` | 542 | ProveOwnership → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_jetton_master.tolk` | 162 | deployAndCredit | `AutoDeployAddress { ... }` | deploy | `ton("0.010") + forwardTonAmount` | | `primes_jetton_master.tolk` | 247 | BurnNotification → onInternalMessage | `respondTo` | player | `0` | | `primes_jetton_master.tolk` | 270 | ProvideWalletAddress → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_jetton_wallet.tolk` | 196 | InternalTransfer → onInternalMessage | `storage.owner` | player | `msg.forwardTonAmount` | | `primes_jetton_wallet.tolk` | 214 | InternalTransfer → onInternalMessage | `respondTo` | player | `0` | | `primes_jetton_wallet.tolk` | 248 | Transfer → onInternalMessage | `AutoDeployAddress { ... }` | deploy | `0` | | `primes_jetton_wallet.tolk` | 275 | Burn → onInternalMessage | `storage.jettonMaster` | peer | `0` | | `primes_ledger.tolk` | 2664 | handleRetryItem | `configA.collectionAddr` | peer | `ITEM_DEPLOY_VALUE + held` | | `primes_ledger.tolk` | 3092 | refund | `dest` | via-helper | `amount` | | `primes_ledger.tolk` | 3173 | handleClaimDividend | `itemAddress(configA, msg.p)` | peer | `0` | | `primes_ledger.tolk` | 3218 | handleRetryCredit | `itemAddress(configA, credit.p)` | peer | `CREDIT_TRIBUTE_VALUE` | | `primes_ledger.tolk` | 3253 | handleRetryMint | `configA.jettonMasterAddr` | peer | `DONATE_MINT_GAS` | | `primes_ledger.tolk` | 3346 | handleIgnite | `configA.collectionAddr` | peer | `ITEM_DEPLOY_VALUE` | | `primes_ledger.tolk` | 3372 | handleIgnite | `d.marketAddr` | peer | `LAUNCH_HOP_GAS` | | `primes_ledger.tolk` | 3403 | handleSyncLaunch | `d.marketAddr` | peer | `0` | | `primes_ledger.tolk` | 3548 | handleClearingCleared | `feeDests.treasuryAddr` | peer | `treasuryDue` | | `primes_ledger.tolk` | 3725 | handleDonateFloor | `configA.jettonMasterAddr` | peer | `DONATE_MINT_GAS` | | `primes_ledger.tolk` | 3811 | handleMarkOffHead | `senderAddress` | player | `0` | | `primes_ledger.tolk` | 3835 | handleSyncHead | `d.marketAddr` | peer | `0` | | `primes_ledger.tolk` | 3853 | handleOpenBuild | `bCfg.registrarAddr` | peer | `0` | | `primes_ledger.tolk` | 3890 | handleAdvanceHead | `senderAddress` | player | `0` | | `primes_ledger.tolk` | 3961 | SettlePrimeClearing → onInternalMessage | `in.senderAddress` | player | `15000000` | | `primes_ledger.tolk` | 3980 | QuoteFloor → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_ledger.tolk` | 4027 | handleCardMint | `senderAddress` | player | `0` | | `primes_ledger.tolk` | 4105 | handleCardMint | `sCfg.generatorsCollectionAddr` | peer | `ITEM_DEPLOY_VALUE` | | `primes_ledger.tolk` | 4200 | handleSettle | `senderAddress` | player | `15000000` | | `primes_ledger.tolk` | 4218 | forwardToRatchet | `b.ratchetAddr` | peer | `amount + RATCHET_HOP_GAS` | | `primes_ledger.tolk` | 4282 | payHeldSplit | `itemAddressWith(configA, itemDefault, p)` | peer | `CREDIT_TRIBUTE_VALUE` | | `primes_ledger.tolk` | 4296 | payHeldSplit | `itemAddressWith(configA, itemDefault, referralKey)` | peer | `REFERRAL_AMOUNT` | | `primes_ledger.tolk` | 4333 | payHeldSplit | `feeDests.treasuryAddr` | peer | `TREASURY_AMOUNT + forfeitToTreasury + opMeters.treasuryHeld` | | `primes_ledger.tolk` | 4345 | payHeldSplit | `feeDests.operatorAddr` | operator | `operatorDue` | | `primes_ledger.tolk` | 4707 | executeMint | `cardStateInit(configA.cardCode, payer)` | deploy | `CARD_RECRUIT_GAS` | | `primes_ledger.tolk` | 4757 | executeMint | `cardStateInit(configA.cardCode, beneficiary)` | deploy | `CARD_PRIME_GAS` | | `primes_ledger.tolk` | 4932 | executeMint | `configA.collectionAddr` | peer | `itemValue + heldSplitValue` | | `primes_ledger.tolk` | 4953 | executeMint | `configA.jettonMasterAddr` | peer | `REBATE_MINT_GAS` | | `primes_ledger.tolk` | 4977 | executeMint | `dCfg.bountyVaultAddr` | peer | `15000000` | | `primes_ledger.tolk` | 5037 | executeMint | `dCfg.bountyVaultAddr` | peer | `15000000` | | `primes_ledger.tolk` | 5084 | executeMint | `bCfg.registrarAddr` | peer | `REGISTRAR_HOP_GAS` | | `primes_ledger.tolk` | 5118 | executeMint | `bCfg.registrarAddr` | peer | `REGISTRAR_HOP_GAS` | | `primes_lp_position.tolk` | 352 | forwardToTreasury | `treasuryAddr` | peer | `0` | | `primes_market.tolk` | 1955 | sendRefund | `dest` | via-helper | `amount` | | `primes_market.tolk` | 2026 | closeLot | `cfg.ledgerAddr` | peer | `MINT_PRICE + SETTLE_GAS` | | `primes_market.tolk` | 2044 | closeLot | `cfg.ledgerAddr` | peer | `MINT_PRICE + SETTLE_GAS` | | `primes_market.tolk` | 2212 | OpenLot → onInternalMessage | `cfg.ledgerAddr` | peer | `OPEN_RESERVE_GAS` | | `primes_market.tolk` | 2469 | RetryPremiumForward → onInternalMessage | `cfg.ledgerAddr` | peer | `returned` | | `primes_market.tolk` | 2535 | SettleConfirmed → onInternalMessage | `cfg.ledgerAddr` | peer | `premium + PREMIUM_HOP_GAS` | | `primes_minter_card.tolk` | 178 | Mint → onInternalMessage | `storage.ledgerAddr` | peer | `0` | | `primes_minter_card.tolk` | 197 | CardMintRefunded → onInternalMessage | `msg.payer` | player | `0` | | `primes_minter_card.tolk` | 214 | CardAddRecruit → onInternalMessage | `storage.ledgerAddr` | peer | `0` | | `primes_minter_card.tolk` | 253 | onBouncedMessage | `payer` | player | `0` | | `primes_ratchet.tolk` | 834 | sendTstonWithdraw | `walletAddr` | peer | `TSTON_EXIT_GAS` | | `primes_ratchet.tolk` | 874 | sendTstonTransfer | `walletAddr` | peer | `value` | | `primes_ratchet.tolk` | 898 | returnCallerChange | `caller` | player | `0` | | `primes_ratchet.tolk` | 1307 | TransferNotification → onInternalMessage | `in.senderAddress` | player | `0` | | `primes_ratchet.tolk` | 1543 | handleStake | `vs.tonstakersPool` | venue | `amount + TONSTAKERS_DEPOSIT_FEE + STAKE_GAS` | | `primes_ratchet.tolk` | 1914 | handleFlush | `venue.dedustNativeVault` | venue | `amount + DEDUST_SWAP_GAS` | | `primes_registrar.tolk` | 2114 | returnGenerator | `generatorAddr` | player | `0` | | `primes_registrar.tolk` | 2142 | burnGenerator | `generatorItemAddress(b2, rec.generatorId, rec.op)` | peer | `REG_BASE_GAS` | | `primes_registrar.tolk` | 2363 | SinkAnnotate → onInternalMessage | `cfg.collectionAddr` | peer | `0` | | `primes_registrar.tolk` | 2482 | ProveInput → onInternalMessage | `inputItemAddress(storage, cfg, rec, msg.inputIndex, n)` | peer | `REG_PROVE_GAS` | | `primes_registrar.tolk` | 2640 | CloseBuild → onInternalMessage | `aux.conCollectionAddr` | peer | `REG_MINT_CON_GAS` | | `primes_registrar.tolk` | 2712 | ConstellationBuilt → onInternalMessage | `b2.bountyVaultAddr` | peer | `REG_ACCRUE_GAS` | | `primes_sink.tolk` | 299 | sendBurn | `walletAddr` | peer | `carryAll ? 0 : SINK_BURN_GAS` | | `primes_sink.tolk` | 312 | sendRefund | `walletAddr` | peer | `0` | | `primes_sink.tolk` | 333 | sendRefundAll | `walletAddr` | peer | `0` | | `primes_sink.tolk` | 398 | TransferNotification → onInternalMessage | `cfg.ledgerAddr` | peer | `0` | | `primes_sink.tolk` | 443 | FloorQuote → onInternalMessage | `cfg.registrarAddr` | peer | `change > 0 ? SINK_ANNOTATE_GAS : 0` | | `primes_stake.tolk` | 439 | sendJetton | `walletAddr` | peer | `TRANSFER_GAS` | | `primes_stake.tolk` | 463 | sendToChild | `positionAddress(cfg, owner)` | peer | `CHILD_GAS` | | `primes_stake.tolk` | 545 | TransferNotification → onInternalMessage | `positionStateInit(cfg, msg.sender)` | deploy | `0` | | `primes_stake_position.tolk` | 229 | forwardSettle | `storage.stakeAddr` | peer | `0` | | `primes_treasury.tolk` | 610 | sendJetton | `walletAddr` | peer | `gas` | | `primes_treasury.tolk` | 633 | sendToChild | `positionAddress(cfg, owner)` | peer | `gas` | | `primes_treasury.tolk` | 715 | TransferNotification → onInternalMessage | `positionStateInit(cfg, msg.sender)` | deploy | `0` | | `primes_treasury.tolk` | 957 | Execute → onInternalMessage | `prop.dest` | governed | `prop.amount` | | `primes_treasury.tolk` | 1009 | Distribute → onInternalMessage | `w.primesJettonWallet` | peer | `0` | | `primes_venue_timelock.tolk` | 200 | sendUpdateVenue | `ratchetAddr` | peer | `value` | | `primes_vesting.tolk` | 246 | Release → onInternalMessage | `b.jettonWalletAddr` | peer | `TRANSFER_GAS + NOTIFY_GAS` | | `primes_voucher.tolk` | 306 | ClaimVoucher → onInternalMessage | `receiptStateInit(storage.receiptCode, in.senderAddress)` | deploy | `0` | | `primes_voucher.tolk` | 325 | ReceiptDelta → onInternalMessage | `storage.vaultAddr` | peer | `0` | | `primes_voucher.tolk` | 384 | onBouncedMessage | `receiptAddress(storage.receiptCode, beneficiary)` | peer | `0` | ## Reading the classes - **peer** — another protocol contract, at a deploy-fixed or derived address. Money here has not left the protocol; the receiving contract's rules still apply and its own sends appear in this same table. - **player** — the counterparty of the message being handled: whoever sent it, whoever owns the item, whoever is owed a refund. Never an address an operator chooses. - **operator** — an address the team controls. The whole of §8's question lives here. - **deploy** — a state-init deploy of a child contract. - **venue** — the DeDust vault, fixed through the venue timelock rather than settable at will. - **governed** — an address a **passed proposal** named (D-100 point 8). `primes_treasury.tolk` has no owner, no admin opcode, no key and no pause; a transfer leaves it only after a proposal opened, ran a 1-day vote of LP holders in the ≥ 30-day tiers, closed with more yes than no, and was pushed by a permissionless `Execute`. That is not an admin withdraw path — it is the opposite shape: money moves to an arbitrary address precisely *because* no single role can move it. Kept as its own class rather than folded into `operator` (which would overstate §8's count) or `player` (which would understate what it is). - **via-helper** — the destination is a helper's parameter; resolved at the call sites, which the spec enumerates by hand.