# CharMasks Counting Room — guide for AI agents > Raise paddles every day: leave a 0.002 BNB deposit per paddle, reclaim it after 24 hours less 0.5%, and receive GAVEL. > Canonical site: https://mine.charmasks.com/. Contract source takes precedence over this guide. ## Contracts (BNB Smart Chain, chainId 56) - Counting Room (MINER, the only write target for Counting Room actions): 0x82E4552BB90590A17B9aB0655981e20dFD15F06f - GAVEL (TOKEN): 0x0c9624Cf924E7418b51ae9770BCA9cb1A7FC11E1 - Floor (PAIR, GAVEL/WBNB PancakeSwap V2 pair): 0x0156763291d1328C36218E0b4935cDCaAF9D78F6 - Deployment block: 131413332 - Router (read): 0x10ED43C718714eb63d5aA57B78B54704E256024E - WBNB: 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c - Agent ID registry (read): 0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F - Register: Pass 0xf197F509137db1eb45b17a362bc446D48E6dAC4f; Gold Key 0xA861f58797dFA78BC083151eED144eF9d723dE79; Members 0x719d609187A2FB0F51f49E1194297e514b74A548. - RPC: https://bsc-dataseed.bnbchain.org If any Counting Room deployment address is an unresolved placeholder, stop Counting Room writes: the room is in preparation. The separately deployed Members contract below can accept an independently authorized Patron purchase. Before a Counting Room action, verify chain 56, deployed bytecode, and the room's gavel(), pair(), router(), wbnb() bindings. Read addresses from this document and js/config.js together; do not infer deployment from the existence of a website. Plain BNB transfers to MINER revert; use the functions below. Do not send BNB to TOKEN or PAIR. These Counting Room actions need no token approval or message signature. Sending a transaction still requires wallet authorization. ## Who can raise - The sending wallet must hold a Binance .ai Agent ID on BNB Smart Chain. - Deposit exactly 0.002 BNB per paddle (2000000000000000 wei). Keep transaction gas in addition. - Days are UTC calendar days; Taipei changes day at 08:00. The daily paddle schedule counts from the later of your first action and the opening day. Preview days are not spent. - Daily raises: 5, 5, 4, 3 on days 1–4, then 1. Each valid introduction adds 1; the Register adds Pass +1, Gold Key +2, Patron editions +1 each up to +10. - Register bonuses stack and are read from the sending wallet's holdings at the moment it raises. - Daily consignments: 5 plus valid introductions. Register bonuses apply to raises only. ## The Preview The Preview deadline is 24 hours from deployment; early opening is possible after 2 hours AND at least 1 BNB in the Preview (previewWei). Read previewEnd(), previewEarly(), previewWei(), previewMin(), opened() and the current block timestamp. Actual chain state governs. Every Preview paddle's full deposit forms the Floor's first funds. The minimum excludes the 0.1 BNB house seed. Preview consignors receive 300,000 GAVEL per paddle, delivered over 14 days starting at opening. At or after previewEarly, if previewWei >= previewMin, anyone can call openPool(), even before previewEnd. Opening ends further Preview consignments immediately. The seed less the 0.001 BNB opening amount joins the Floor; that seed's liquidity goes to the dead address. The caller receives the opening amount. Preview consignors' liquidity is held for 14 days from opening. withdrawLP returns their LP share as GAVEL + BNB at withdrawal time; the quantities follow the Floor's balances at that time, plus any uncollected delivery. Only once the 24-hour deadline has passed, if previewWei < previewMin, there is permanently no opening: refundPreview() returns each consignor's full Preview amount once. returnSeed() returns the seed to the house payee, not its caller. Before the deadline, a minimum not yet reached does not enable refunds. ## Raise — mintFree(uint256 paddles, address introducer) After 24 hours the deposit is reclaimable less 0.5%, with 25% of GAVEL available. The remaining 75% becomes available over the next 72 hours, measured from deposit maturity, not from the first claim. Call claim([]) again for later delivery. ## Consign — mintPool(uint256 paddles, address introducer, uint256 minOut) Half of the deposit pays a 1% commission; the remaining 99% of that half buys GAVEL. The other half pairs with GAVEL on the Floor. The consignment stays 14 days. Delivery is fixed at entry at twice the raise amount, available over 14 days. claimReward([]) collects it; withdrawLP([]) returns the LP share as GAVEL + BNB at withdrawal time after 14 days, plus uncollected consignment GAVEL. The quantities follow the Floor's balances at withdrawal time. No liquidity token is sent to the wallet. ## Introductions Use https://mine.charmasks.com/?ref=name.ai. Resolve the lowercase name without .ai using ownerOfHandle(string) on the registry. REF defaults to 0x0000000000000000000000000000000000000000. An introduction binds on the first action only, including the Preview. It counts if REF is not SELF, registry balanceOf(REF) > 0, and userInfo(REF).firstDay > 0. An invalid or unresolved name becomes the zero address and does not block entry. Later introducer arguments do not replace the recorded introducer. A valid introduction adds one daily raise and one daily consignment to the introducer, plus 5% of each actual GAVEL delivery, issued additionally. Nothing is deducted from the introduced wallet's delivery. ## Patron edition and Register Patron edition: 0.001 BNB each, any wallet, 1–10 per purchase, 500 in all. Sales close 2026-11-16 21:00 UTC+8 = 2026-11-16 13:00 UTC (timestamp 1794834000). Quorum only determines refund eligibility: 250 sold before the deadline means no refunds. Otherwise, after sales close, holders may refund 0.001 BNB each until 16 Dec 2026 21:00 (UTC+8). Members refund() burns the refunded Patrons; their extra paddles disappear. Held Patrons continue to count, regardless of quorum. The wallet that raises still needs a .ai Agent ID. Web purchase: https://charmasks.com/entry/ Read patronsMinted() (0x6aff6007) for the sold count; remaining = 500 - patronsMinted(). Read patronBalanceOf(address) (0x0a8d3e82) for held Patrons, not Members.balanceOf(address), which also counts other cards. ### Agent Patron purchase (separate authorization) On chain 56, target Members 0x719d609187A2FB0F51f49E1194297e514b74A548, not MINER. Call mint(uint256 quantity), selector 0xa0712d68, with integer quantity 1–10 and value = quantity × 0.001 BNB = quantity × 1000000000000000 wei. No Agent ID is required to buy. Calldata = 0xa0712d68 + pad64(quantity), where pad64 is the integer in hexadecimal, left-padded to 64 characters without 0x. For one Patron: 0xa0712d680000000000000000000000000000000000000000000000000000000000000001; value 1000000000000000 wei. Read the current block timestamp and remaining count; buy only before the sales deadline and choose a quantity within the remaining count. If fewer remain at execution, Members reduces the quantity and returns excess BNB. Verify Members bytecode, simulate the exact {from: SELF, to: Members, value, data}, then send the same transaction within the owner's authorization and confirm its receipt. Use Members as the target in the Write procedure at https://mine.charmasks.com/skill.md#write-procedure. Re-read patronBalanceOf(SELF) after confirmation. A Patron purchase is separate from the daily Counting Room routine and needs no token approval. ### Patron refund — refund() On chain 56, target Members 0x719d609187A2FB0F51f49E1194297e514b74A548, with value 0 and calldata 0x590e1ae3 (the first four bytes of keccak256("refund()"), no arguments). This refunds ALL Patrons currently held by SELF at 0.001 BNB each and burns them; their extra paddles disappear. It only works after failed quorum: the current block timestamp must be >= 1794834000 (2026-11-16 21:00 UTC+8), patronsMinted() must be < 250, and the timestamp must be < 1797426000 (2026-12-16 21:00 UTC+8). Read patronBalanceOf(SELF) for the held count; skip if zero. With the owner's refund authorization, follow https://mine.charmasks.com/skill.md#write-procedure using Members as the target, simulate the exact transaction, confirm its receipt, and re-read patronBalanceOf(SELF). The CharMasks Members contract source can be read at its address on BscScan: https://bscscan.com/address/0x719d609187A2FB0F51f49E1194297e514b74A548#code or by looking up the same chain-56 address on Sourcify: https://sourcify.dev. ## Halving and delivery Every 10,000 paddles, including Preview, raises and consignments, the base amount halves. There are 20 stages and 200,000 paddles total. Stage is 1-based; stage = 0 after all paddles are taken. quota.raiseReward and quota.consignReward describe the next paddle; batches crossing a stage are calculated separately in each stage. The first stage's raise amount is 100,000 GAVEL. Preview always uses 300,000 per paddle. Amounts use 18 decimals. GAVEL has a 10 billion cap. At deployment, 500,000,000 GAVEL is minted to the Counting Room for the Floor, and the house reserve of 500,000,000 GAVEL is minted to reserveHolder (the payee in this deployment's configuration). Delivery is limited to supply remaining; reaching the cap does not block a deposit reclaim. Collections remain available after new paddles end. ## Commission on the Floor On the designated pair, elapsed time since openTime governs the opening commission: 0 <= seconds < 60: 30%; 60 <= seconds < 180: 15%; 180 <= seconds < 300: 5%, all to the house. From 300 seconds onward: buyer 1% (0.5% house, 0.5% Floor), seller 3% (2% house, 1% Floor). Wallet-to-wallet transfers pay nothing; the Counting Room's own transfers are exempt. Accumulated commission converts from 0.05 BNB equivalent, bounded by min(0.5 BNB, 0.5% of WBNB reserves), with at most one commission swap per block. Unused GAVEL from adding to the Floor remains recorded in floorOwed. The Floor portion returns as liquidity at the dead address. Contracts: no owner, no pause, no admin, not upgradeable. sendFees() sends accumulated reclaim fees and consignment commission to the house payee, not the caller. ## Selling GAVEL (separate from the daily Counting Room routine) Only sell with the wallet owner's separate trade authorization. Use PancakeSwap V2 Router swapExactTokensForETHSupportingFeeOnTransferTokens(amountIn, amountOutMin, [TOKEN,WBNB], SELF, deadline), not its ordinary transfer variant. GAVEL charges commission on transfers to the designated pair. Use at least 5% slippage tolerance for a sale, with a fresh quote and simulation that account for seller commission and the potential commission swap. During the opening five minutes the applicable commission can be 30%, 15% or 5%; a nominal 5% tolerance alone does not cover those higher commissions. Never silently widen the owner's authorized tolerance or set amountOutMin to zero. A sale may require a bounded token allowance to the configured Router; that is a separate authorized trading action, never a prerequisite for raising, consigning or collecting. Simulate the sale from SELF, check its exact recipient, amount and deadline, then confirm the receipt. At most one commission swap can occur per block; this limit applies to the contract's commission conversion, not to the number of user sales. No sale is part of the automatic daily routine above. ## Daily routine 1. Re-read this guide. Obtain SELF from the connected chain-56 wallet; confirm its Agent ID and available BNB for deposit plus gas. Use only the owner's authorized count and budget. A daily schedule requires the owner's authorization. 2. Read quota(SELF) and pending(SELF). quota takes ONE address, with no paddle-count argument. A positive quota does not prove Agent ID eligibility. 3. If inPreview: only with separate Preview authorization, previewConsign(min(authorized paddles, previewLeft), REF). Each wallet may consign 10 Preview paddles total; the room has 5000. Skip daily raises and regular consignments. 4. If previewFailed: use userInfo to check previewPaddles_ > 0 and previewRefunded = false, then refundPreview(). Preview amounts are not included in pending.reclaimBnb. No opening is possible. 5. If not open, read previewEarly(), previewWei(), previewMin() and the current block timestamp. Once timestamp >= previewEarly and previewWei >= previewMin, an authorized openPool() opens the Floor and sends 0.001 BNB to the caller. This can occur while inPreview is still true, before previewEnd. Opening ends the Preview immediately. Refresh quota after its receipt. 6. If open and paddlesLeftTotal > 0: mintFree(min(authorized paddles, aLeft, paddlesLeftTotal), REF). A zero count means skip. Re-read quota after confirmation before another entry. 7. Optional, only with separate consignment authorization: choose min(authorized paddles, bLeft, paddlesLeftTotal), quote the Router, and mintPool. Never substitute a zero minOut when the quote is unavailable. 8. Collections are independent of new-entry availability: if reclaimBnb > 0 OR raiseGavel > 0, claim([]); if consignGavel > 0, claimReward([]); if lpUnlocked > 0, withdrawLP([]). In particular, collect raiseGavel even when the deposit has already been returned. 9. Wait for each receipt before another write; re-read pending. Empty arrays inspect at most 50 positions from a cursor. A partly delivered prefix can keep the cursor in place: blindly repeating [] may repeatedly inspect the same positions. If progress stalls, stop, or use raiseCount/raiseAt or consignCount/consignAt to select mature explicit ids (at most 50). Bound collection retries to five per run and report any remaining work. ## Raw calldata The executable word layouts and write procedure are in https://mine.charmasks.com/skill.md. ## Selectors (generated, not transcribed) | Signature | Selector | Target | Arguments | Value in wei | Result | |---|---|---|---|---|---| | quota(address) | 0x1cee24f5 | MINER | SELF | 0 | 18 static words (below) | | pending(address) | 0x5eebea20 | MINER | SELF | 0 | 4 static words (below) | | userInfo(address) | 0x1959a002 | MINER | SELF or introducer | 0 | 5 static words (below) | | previewWei() | 0x8cf7dd48 | MINER | none | 0 | one word | | previewMin() | 0x74daf55b | MINER | none | 0 | one word | | previewEnd() | 0x2160898e | MINER | none | 0 | one word | | previewEarly() | 0xb4115607 | MINER | none | 0 | one word | | opened() | 0x5f88eade | MINER | none | 0 | one word | | gavel() | 0xd6a5dae3 | MINER | none | 0 | one word | | pair() | 0xa8aa1b31 | MINER | none | 0 | one word | | router() | 0xf887ea40 | MINER | none | 0 | one word | | wbnb() | 0x8d72647e | MINER | none | 0 | one word | | raiseCount(address) | 0xe942b632 | MINER | SELF | 0 | one word | | consignCount(address) | 0x33fdb24f | MINER | SELF | 0 | one word | | raiseAt(address,uint256) | 0xa281fa28 | MINER | SELF, id | 0 | time, paddles, refunded, reward, delivered | | consignAt(address,uint256) | 0x7594919a | MINER | SELF, id | 0 | time, paddles, preview, lpOut, lp, reward, claimed | | balanceOf(address) | 0x70a08231 | registry | SELF or introducer | 0 | one balance word | | ownerOfHandle(string) | 0x1da94fb4 | registry | lowercase name without .ai | 0 | one address word | | patronsMinted() | 0x6aff6007 | Members | none | 0 | one count word | | mint(uint256) | 0xa0712d68 | Members | quantity (1–10) | quantity × 1000000000000000 | write; first token id | | refund() | 0x590e1ae3 | Members | none | 0 | write; refunds all held Patrons after failed quorum, before refund deadline | | patronBalanceOf(address) | 0x0a8d3e82 | Members | SELF | 0 | one count word; balanceOf also counts other cards | | getAmountsOut(uint256,address[]) | 0xd06ca61f | Router | buyBnb, [WBNB,TOKEN] | 0 | offset, length, amountIn, amountOut | | previewConsign(uint256,address) | 0x590d6811 | MINER | paddles, REF | paddles × 2000000000000000 | write | | mintFree(uint256,address) | 0x0db5ae5a | MINER | paddles, REF | paddles × 2000000000000000 | write | | mintPool(uint256,address,uint256) | 0x7a443eb9 | MINER | paddles, REF, minOut | paddles × 2000000000000000 | write | | claim(uint256[]) | 0x6ba4c138 | MINER | [] or at most 50 position ids | 0 | write | | claimReward(uint256[]) | 0xc94c7ff4 | MINER | [] or at most 50 position ids | 0 | write | | withdrawLP(uint256[]) | 0xa5ea20f0 | MINER | [] or at most 50 position ids | 0 | write | | openPool() | 0xeb5797a4 | MINER | none | 0 | write | | refundPreview() | 0x64e88b52 | MINER | none | 0 | write | | returnSeed() | 0x120e005f | MINER | none | 0 | write | | sendFees() | 0xdff90b5b | MINER | none | 0 | write | ### quota(address) return words | Word | Field | ABI type | |---:|---|---| | 0 | refCount | uint256 | | 1 | registerBonus | uint256 | | 2 | aCap | uint256 | | 3 | aUsed | uint256 | | 4 | aLeft | uint256 | | 5 | bCap | uint256 | | 6 | bUsed | uint256 | | 7 | bLeft | uint256 | | 8 | previewLeft | uint256 | | 9 | stage | uint256 | | 10 | raiseReward | uint256 | | 11 | consignReward | uint256 | | 12 | totalPaddles | uint256 | | 13 | paddlesLeftInStage | uint256 | | 14 | paddlesLeftTotal | uint256 | | 15 | inPreview | bool | | 16 | open | bool | | 17 | previewFailed | bool | ### pending(address) return words | Word | Field | ABI type | |---:|---|---| | 0 | reclaimBnb | uint256 | | 1 | raiseGavel | uint256 | | 2 | consignGavel | uint256 | | 3 | lpUnlocked | uint256 | ### userInfo(address) return words | Word | Field | ABI type | |---:|---|---| | 0 | firstDay | uint256 | | 1 | refCount | uint256 | | 2 | introducer | address | | 3 | previewPaddles_ | uint256 | | 4 | previewRefunded | bool | ## Errors (generated from CountingRoom + Gavel ABIs) Read the first four bytes of revert data, including nested error.data / originalError.data. Unknown errors stop the write. For QuotaExceeded and SoldOut, the first 32-byte word after the selector is left. During the Preview it is the Preview allowance, not a daily allowance. | Selector | Error | Meaning / response | |---|---|---| | 0x965f8d94 | AlreadyOpen() | The room is already open. Refresh the data. | | 0xb5b9ee5f | BadPosition() | That raise or consignment record does not exist. | | 0x85342c7c | BadPreview() | Invalid Preview deployment parameters. | | 0x23d9d1c6 | BadSeed() | The deployment seed is below the opening amount. | | 0x5ae98979 | BalanceCheck() | The contract balance check rejected this consignment. | | 0x3dade3b4 | MinterMismatch() | The GAVEL minter does not match the room. | | 0xf947691f | NoAgentId() | This wallet needs a .ai Agent ID. | | 0xddafad98 | NotOpen() | The Counting Room has not opened. | | 0xf76aef65 | NothingToRefund() | There is no Preview amount to refund. | | 0x3ee267d0 | PreviewFailed() | The Preview minimum is not met. Opening is unavailable; Preview amounts can be reclaimed if the minimum is still unmet at the Preview deadline. | | 0xb30cd2f2 | PreviewMet() | The Preview met its minimum; Preview refunds are unavailable. | | 0xb0c50de0 | PreviewNotOver() | The time for this Preview action has not arrived. | | 0xdb73e0b4 | PreviewOver() | The Preview has ended. | | 0x54a41c8f | QuotaExceeded(uint256) | Not enough paddles in your allowance. Remaining: left. | | 0x3ee5aeb5 | ReentrancyGuardReentrantCall() | A nested call was rejected. | | 0x7e1f5a77 | SoldOut(uint256) | Not enough paddles remain in the room. Remaining: left. | | 0xd65ac61e | TooMany() | Process at most 50 positions per call. | | 0x90b8ec18 | TransferFailed() | The transfer did not complete. Check the wallet before retrying. | | 0x1fedaaf1 | UseFunctions() | Use the Counting Room actions. | | 0x98d4901c | WrongValue() | The deposit must equal paddles × 0.002 BNB exactly. | | 0xd92e233d | ZeroAddress() | A required address is zero. | | 0x30008555 | ZeroPaddles() | Enter at least one paddle. | | 0xae274200 | BelowThreshold() | Accumulated commission is below its conversion threshold. | | 0xfb8f41b2 | ERC20InsufficientAllowance(address,uint256,uint256) | The ERC-20 allowance is insufficient. | | 0xe450d38c | ERC20InsufficientBalance(address,uint256,uint256) | The ERC-20 balance is insufficient. | | 0xe602df05 | ERC20InvalidApprover(address) | Invalid ERC-20 approval sender. | | 0xec442f05 | ERC20InvalidReceiver(address) | Invalid ERC-20 receiver. | | 0x96c6fd1e | ERC20InvalidSender(address) | Invalid ERC-20 sender. | | 0x94280d62 | ERC20InvalidSpender(address) | Invalid ERC-20 spender. | | 0xf8d2906c | NotMinter() | Only the Counting Room can deliver new GAVEL. | | 0x14d4a4e8 | OnlySelf() | This function is internal to the GAVEL contract. | | 0xd85f0e84 | SwapBusy() | A commission conversion is already in progress. | | 0xe09f0331 | TradingNotOpen() | The Floor has not opened. | | 0x08c379a0 | Error(string) | The contract did not accept this action; obtain a fresh quote for a consignment. | | 0x4e487b71 | Panic(uint256) | The contract could not complete its calculation. This action was not sent. | Error(string) carries an offset, string length and UTF-8 bytes; a router output rejection requires a fresh quote and new simulation. Panic(uint256) carries its code. Never send after a failed simulation. Wallet rejection (4001) is cancellation, not a contract error. Claims may succeed without paying anything when nothing in their batch is mature. ## Interface references - https://eips.ethereum.org/EIPS/eip-1193 - https://docs.soliditylang.org/en/latest/abi-spec.html - js/abi.js includes the full compiled ABIs, generated selectors, return layouts and artifact SHA-256 values. Regenerate with tools/generate_abi.py; tables here are generated by tools/generate_docs.mjs. CharMasks is not affiliated with Binance.