WithdrawOps
Ask AI
WithdrawOps pushes the whole ops pot to opsVaultAddr and returns the amount moved. PERMISSIONLESS.
THE DEFECT IT CLOSES IS AUDIT-2026-09-28.md FINDING 6, and it is in this file from the start rather than added later: without it opsPot only ever increases — the 5% cut on every ticket (the product's entire revenue), every swept donation, and anything SweepDrawlessWindow ever moves — and all of it would be permanently unreachable by every path in the realm while checkInvariant and AuditFailure both stayed green, because both count opsPot as money the realm holds and neither has an opinion about whether anybody can reach it.
PERMISSIONLESS, AND THAT IS SAFE PRECISELY BECAUSE THE DESTINATION IS FIXED AT COMPILE TIME. A reader will look for a caller check here and there is none, on purpose: opsVaultAddr is a const, so the caller does not choose where the money goes, cannot name themselves, and cannot name a window's pot. All they can do is push the house's money to the house — and paying the gas to do somebody else's bookkeeping is a favour, not an attack. Gating it on an operator key would buy nothing and would put a liveness dependency for the realm's revenue onto one key, exactly as it would for Commit, Capture and Resolve. The property that makes it sound is the one tools/speed_addr_test.go exists to keep true.
IT NEVER REACHES A PLAYER'S MONEY. No Draw is touched: not Pot, not spendOf, not a ticket. The only book that moves is opsPot, which by construction holds nothing any buyer can claim — the fee in it was EARNED BY A WINDOW THAT ACTUALLY DREW (Resolve releases that window's escrow; a window that fails refunds it with the gross) and a donation belongs to whoever chose to give it away.
THE CITATION THAT USED TO STAND HERE IS RETIRED: this paragraph said "the cut was taken at sale time (see Refund's 'THE HOUSE CUT IS NOT REFUNDED')", and neither half survives — finding 25 stopped the fee being taken at sale time and deleted that section of Refund. A citation that outlives the thing it cites is how a reader ends up trusting a rule the code stopped following. AUDIT-2026-09-28.md finding 29.
sweepDonations RUNS FIRST, as in every other mutator, so a donation that arrived since the last state change is included in this withdrawal rather than left behind.
BOOKS FIRST, TRANSFER SECOND, exactly as Resolve and Refund do it: opsPot is zeroed BEFORE the wugnot leaves, so a re-entrant call — which wugnot's Transfer cannot cause today, having no hook or callback, but a future GRC20 might — finds an empty pot and panics rather than a balance it can take twice.
THE INVARIANT IS EXACT ACROSS IT, not merely preserved one-sidedly: checkInvariant asserts heldPots + opsPot == balance, and this call reduces both sides by the same amount. heldPots is deliberately untouched.
Panics if there is nothing to withdraw.
Command
# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.
gnokey maketx call -pkgpath "gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/arcade/speed/v2" -func "WithdrawOps" -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -chainid "onyx-1" -remote "https://rpc.onyx.testnets.gno.land" ADDRESSgnokey query -remote "https://rpc.onyx.testnets.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/g1r4aw43kagaaquhegxw6xr346h9f2qu2ezf0jar/arcade/speed/v2" -func "WithdrawOps" -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "onyx-1" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.onyx.testnets.gno.land" call.tx