---
name: moyu-mint
description: Clock-in procedure for the MOYU (摸鱼) board on BSC — Agent ID gate, one free seat, up to 10 paid at 0.001 BNB with a 30% treasury cut at purchase, 70% refundable below 8,000 shares, pool opens at 80% or sellout
---

# MOYU / 摸鱼 — shift manual

摸鱼 (mō yú) means slacking off at work. Here it is a board on BNB Smart
Chain: 10,000 shares, 1,000 of them free for agent wallets, no countdown.
The board closes when it fills, or once it is 80% full and someone rings the
bell. Each paid purchase sends 30% to the treasury on the spot; the other 70%
can be taken back while the board is below 8,000.

## 0. Shift ticket

| field | value |
|---|---|
| chain | BNB Smart Chain, id `56` |
| token | MOYU (symbol `MOYU`), 18 decimals |
| mint contract | `0x0a791Fa2e092DFf223cde4E0e2B684759519CA49` |
| token contract | `0xf099a3bC6b0608FA267C77cF0838a0600240123D` |
| pair (MOYU/WBNB) | `0x68F729165341e54E50C724793B3f8742B04B2b6e` |
| agent gate | registry `0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F` |
| board | 10,000 shares × 1,000,000 MOYU |
| free seats | 1,000, one per wallet, gas only |
| paid seats | 9,000 at 0.001 BNB, max 10 per wallet |
| mint fee | 30% of every paid purchase, sent to the treasury in that same tx |
| refunds | the remaining 70% of paid BNB while the board is below 8,000; closes at 8,000 |
| bell | automatic at 10,000 shares, or anyone at ≥ 8,000 |
| BNB path | fee leaves at purchase; the held 70% seeds the pool at the bell |
| LP | burned to `0x000000000000000000000000000000000000dEaD` |
| transfers | locked until the bell |

Supply is 10,000 × 1,000,000 = 10B handed out, plus up to 6.3B minted into the
burned LP when the bell rings (700,000 per paid share). Hard cap: 16.3B.
There is no deadline and no owner — the bell is the only close.

Fee and refund are the same 0.001 BNB seen from two sides: `FEE_PER_PAID()`
reads `0.0003`, `BACK_PER_PAID()` reads `0.0007`. `refundable(wallet)` always
returns exactly what the contract still holds for that wallet.

## 1. Gate check — read only, no gas

Wallets need a Binance .ai Agent ID. The cheap test is a balance read:

```bash
WALLET=0x1111111111111111111111111111111111111111
REG=0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F
curl -s https://bsc-dataseed.binance.org -H 'content-type: application/json' -d "{
  \"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"eth_call\",
  \"params\":[{\"to\":\"$REG\",\"data\":\"0x70a08231000000000000000000000000${WALLET:2}\"},\"latest\"]}"
```

A non-zero 32-byte result means the gate opens. The same check is exposed on the
mint contract as `agentOk(wallet)`.

## 2. Reading the board

All calls are `eth_call` against the mint contract.

| read | selector | answers |
|---|---|---|
| `shiftOpen()` | `0x701ab7c3` | is the board still taking entries |
| `boardFilled()` | `0x2e9d296c` | shares taken, free + paid |
| `freeTaken()` | `0xc5ef7668` | free seats used |
| `seatsLeft()` | `0xc204233a` | free seats still open overall |
| `seatOpen(addr)` | `0x57c64ef1` | can *this* wallet still take a free seat |
| `paidMinted()` | `0x2806b8fb` | paid shares sold |
| `roomFor(addr)` | `0x9149e915` | paid shares this wallet may still buy |
| `clockedIn(addr)` | `0x33e4f203` | has this wallet used its free seat |
| `paidCount(addr)` | `0x3e8f8723` | paid shares bought by this wallet |
| `shareCount(addr)` | `0xc2bd1871` | total shares this wallet holds from minting |
| `priceFor(n)` | `0x8d5555f2` | wei needed for `n` paid shares |
| `refundable(addr)` | `0x68ec0d99` | wei this wallet can still take back (70%) |
| `bnbHeld()` | `0x01fd8d4e` | BNB sitting in the contract (held 70% only) |
| `FEE_PER_PAID()` | `0xfdb17acd` | wei sent to treasury per paid share, `0.0003` |
| `BACK_PER_PAID()` | `0x87796d44` | wei a refund returns per paid share, `0.0007` |
| `FEE_BPS()` | `0xbf333f2c` | fee in basis points, `3000` |
| `closed()` | `0x597e1fb5` | bell rung, transfers live |

`seatsLeft()` returns the smaller of "free seats unused" and "shares left on the
board". `refundable()` returns 0 once the board has reached 8,000, and stays 0
after the bell.

## 3. Taking part

Four calls, no parameters except the paid amount.

| intent | call | data | value |
|---|---|---|---|
| take the free seat | `clockIn()` | `0xed4928c8` | `0` |
| take `n` paid shares | `buy(n)` | `0xd96a094a` + `n` as 32-byte word | exactly `n × 0.001 BNB` |
| take the held 70% back | `refund()` | `0x590e1ae3` | `0` |
| close the board at ≥ 8,000 | `ringBell()` | `0xd1df1252` | `0` |

`clockIn()` is its own call — the free seat is **not** appended to a paid buy.
A wallet that wants both calls `clockIn()` then `buy(n)`, or the other way
around. Paid cap is 10 per wallet, free seat excluded.

`refund()` is open while `boardFilled() < 8,000`. At 8,000 it reverts
`RefundClosed`, exactly where `ringBell()` becomes callable, so a refund can
never be raced by the bell.

`buy` needs `msg.value` to equal `priceFor(n)` to the wei. No slippage, no
deadline argument, no permit, no signature. Inside the same call the contract
forwards `n × FEE_PER_PAID()` to the treasury and keeps the rest; the treasury
transfer is part of the transaction, not a later claim.

Events:

| event | fields | topic |
|---|---|---|
| `Clocked` | wallet, freeShares, tokensOut | `0xcfadcb585b5817f01ba9a40fb6f3df091db31f1e6ec5226a20021ed7c6732780` |
| `Bought` | wallet, shares, paidWei, feeWei, tokensOut | `0x27330bd7589580547b6437e08f9c60653de63691d2d2b2c13bff9ee67da2a68d` |
| `Refunded` | wallet, shares, returnedWei | `0x2dc8e290002f06fc0085bbca9dfb8b415cf4d1178950c72ff9ee8f4d8878ee66` |
| `BellRung` | pair, bnbIn, tokenIn | `0xa37d80db91aa4442d5d5bcac8b5f8409545fd739e08452ac57272da749e2334a` |

## 4. When it reverts

| error | selector | meaning | next move |
|---|---|---|---|
| `AgentOnly()` | `0xf21de7ff` | wallet holds no .ai Agent ID | get one; retrying will not help |
| `WalletCap()` | `0x94048683` | paid total would exceed 5 | lower `n` |
| `PayMismatch()` | `0xb5d7c062` | `msg.value ≠ n × 0.001 BNB` | resend with exact value |
| `ZeroShares()` | `0x9811e0c7` | `buy(0)` | buy at least 1 |
| `NoSeat()` | `0x9a39f3a6` | free seat already used, or none left | nothing; free lane is done for this wallet |
| `LaneFull()` | `0x91660a1e` | paid lane would pass 9,000 | stop buying |
| `BoardFull()` | `0x4dd451db` | board cannot fit the request | stop buying |
| `ShiftClosed()` | `0xc43a7983` | the bell has rung | no minting or refunds |
| `NothingPaid()` | `0x56baacf6` | refund with nothing paid | nothing to refund |
| `RefundClosed()` | `0x13112018` | board is at 8,000 or more | exit is closed; the bell is next |
| `AlreadyRung()` | `0xf190e6e1` | `ringBell()` ran twice | stop calling |
| `BoardNotReady()` | `0x89f92f00` | `ringBell()` below 8,000 shares | wait; no time gate |
| `RefundStuck()` | `0x682da455` | BNB transfer to wallet failed | surface it, do not retry blindly |
| `FeeStuck()` | `0x0a9f4fa0` | treasury rejected the 30% cut during `buy` | the whole buy reverted; nothing was minted |
| `PoolStuck()` | `0xe6a13177` | bell funding failed | surface it |

`AgentOnly` means the gate closed; `WalletCap` means the gate opened and the
wallet already used its paid quota. Nothing else distinguishes them as cheaply.

## 5. Where the BNB goes

The 30% fee leaves when you buy, so it is already the treasury's money and
cannot come back. The other 70% sits in the contract until the bell, which is
what makes the refund real. At the bell the held balance seeds the pair:

| paid shares held at bell | paid in | treasury kept at purchase | BNB into the pool | LP tokens |
|---|---|---|---|---|
| 7,000 (bell at 8,000, all free taken) | 7 BNB | 2.1 BNB | 4.9 BNB | 4.9B MOYU |
| 9,000 (sold out) | 9 BNB | 2.7 BNB | 6.3 BNB | 6.3B MOYU |

Opening price is 0.001 BNB per 1,000,000-token share in both cases. A refund
returns 0.0007 BNB and burns the 1,000,000 MOYU for that share, so the token
side and the BNB side shrink together and the ratio does not move. Free seats
add supply but no BNB.

The fee is kept even if the board never reaches 8,000; the 70% stays
refundable for as long as the board is below 8,000. That asymmetry is
deliberate and readable on-chain from `Bought.feeWei` and `bnbHeld()`.

## 6. Closing the board

- 10,000 shares: the bell rings inside the final `clockIn()` or `buy()`.
- 8,000 shares or more: anyone may call `ringBell()`. There is no time gate
  and no reward for calling it; an agent holding tokens should watch
  `boardFilled()` and ring when it is ready.
- Refunds are allowed while the board is below 8,000; they close at 8,000,
  the same line where `ringBell()` becomes callable. The contract holds the
  full 70% for every outstanding paid share, so refunds are always covered.
- After the bell: `closed()` is true, both free and paid entries revert
  `ShiftClosed`, transfers are live, and the MOYU/WBNB PancakeSwap V2 pair
  holds the burned LP.
- Unclaimed free seats are void once the bell rings.

## 7. Pre-sign checklist

- [ ] `agentOk(wallet)` is true, or registry `balanceOf` is above 0
- [ ] `shiftOpen()` is true
- [ ] `roomFor(wallet)` covers the planned `n`
- [ ] budget is `n × 0.001 BNB`, of which `n × 0.0003` is non-refundable
- [ ] `msg.value` equals `priceFor(n)` to the wei
- [ ] free seat: `seatOpen(wallet)` is true before spending gas
- [ ] after signing: decode `Clocked` / `Bought`, store `tokensOut`

## 8. ABI fragments

```solidity
function clockIn() external;
function buy(uint256 n) external payable;
function refund() external;
function ringBell() external;
function shiftOpen() external view returns (bool);
function agentOk(address) external view returns (bool);
function seatOpen(address) external view returns (bool);
function seatsLeft() external view returns (uint256);
function roomFor(address) external view returns (uint256);
function priceFor(uint256 n) external pure returns (uint256);
function refundable(address) external view returns (uint256);
function closed() external view returns (bool);
```

Token: plain BEP-20, 18 decimals, `name()` and `symbol()` both return `MOYU`.
Transfers revert with `Locked()` until the bell; the mint contract can burn
tokens only when a wallet refunds. No owner, admin, tax or upgrade path exists.
