<!--
  Generated by scripts/sync-guide.mjs from agent-guide/SKILL.md (read-only).
  Addresses checked against deployments/97.json (chainId 97).
  Site URLs: https://playfleece.com; whitelist: https://playfleece.com/whitelist/free-mint.json.
  Generated: 2026-11-01T23:06:51.550Z
-->

# FleeceFarm — AI play guide (read this one doc and play)

> **TESTNET (BSC Testnet, chainId 97).** Test coins have no value. Mainnet addresses will differ; use the ones published on playfleece.com. 中文: https://playfleece.com/guide.md
> This is a game. The numbers are game rules, not promised returns. Token and NFT prices go up and down and can go to zero.

## 1. What the game is

FleeceFarm is a small farming game on BNB Chain. Animals are NFTs, minted at random: Lamb 85%, Wolf 10%, Shepherd 5% (Chainlink VRF). Sheep staked on the farm grow Golden Fleece (the FLEECE token); wolves in the Dark Forest share the 20% claim tax on sheep and can go out to the wild to rob sheep; shepherds can be hired to guard sheep and shoot wolves. The game has two stages: **Stage 1 = before pool open** (free mint, paid mint, early staking to hold a spot, no fleece yet). Once paid mints reach 10 BNB (5 BNB of it goes to the liquidity pool) the pool opens and **Stage 2 = after pool open** starts (earning and battles). If the threshold is not met, refund mode starts and paid mints are refunded in BNB in full.

## 2. Tell the current phase (read-only, free)

```bash
M=0xdAD1970f4B7527BAD79bBA940f72d3695647B921; R=https://bsc-testnet-rpc.publicnode.com
cast block latest --field timestamp --rpc-url $R      # NOW (chain time, unix seconds)
for f in "freeStart()(uint64)" "paidStart()(uint64)" "closeTime()(uint64)" "launched()(bool)" "refundMode()(bool)" "thresholdMet()(bool)" "pendingRequests()(uint256)"; do cast call $M "$f" --rpc-url $R; done
```

Go top to bottom; the first row that matches is the current phase:

| Condition | Phase | What you can do |
|---|---|---|
| `launched` = true | Stage 2: after pool open | Everything in section 7 |
| `refundMode` = true | Refund | Only refunds, `claimRefund` |
| NOW < `freeStart` | Not started | View animals; tell the player the start time |
| `freeStart` ≤ NOW < `paidStart` | Stage 1 · free mint | Free mint, early staking, view |
| `paidStart` ≤ NOW < `closeTime` | Stage 1 · paid mint | Paid mint, free mint (while spots remain), early staking, view |
| NOW ≥ `closeTime`, `thresholdMet` = true | Stage 1 · waiting for pool open | Anyone can `openPool` when `pendingRequests` = 0; otherwise reveal first |
| NOW ≥ `closeTime`, `thresholdMet` = false | Stage 1 · waiting for result | Paid mints still unrevealed: reveal or cancel after timeout |

Convert timestamps to the player's local time and tell them when the next phase starts (`date -d @<seconds>`). `closeTime` can only move earlier, never later (announced at least 24 hours ahead), so read it again every time.

## 3. Contract addresses (TESTNET, chainId 97)

RPC: `https://bsc-testnet-rpc.publicnode.com` (backup `https://data-seed-prebsc-1-s1.bnbchain.org:8545`). Only interact with the contracts in this table.

| Contract | Address | Purpose |
|---|---|---|
| FleeceMint | `0xdAD1970f4B7527BAD79bBA940f72d3695647B921` | Minting, free mint, reveal, refund, pool open |
| FleeceAnimals | `0xd3535553a2D129682e20769071Dae00f78A7c93e` | Animal NFT (ERC-721), approval-free staking/listing |
| FleeceLens | `0xA200b6781C2Bf22aF3A1f9C67CD5F477fbCD7186` | Read-only: all animals of a wallet |
| Pasture | `0x53083e463790750A597eE028cC8f787ABBd155B7` | Farm: move, claim, leave, flocks, bells |
| FleeceToken | `0x2f46245fE8D733C70c923aa5d0ed9A0232DDbA3e` | Golden Fleece FLEECE (ERC-20) |
| HuntGame | `0xDcD9cC45297Cbf09964345a87d5a40FC0A88D7AE` | Hunts, pack hunts, shooting, hiring shepherds |
| Evolution | `0x78904ef9ec11b41D6469B5E57d8981475A231B48` | Merge Fat Ram, evolve Alpha |
| FleeceMarket | `0xDCcd9c57b01B12e263cbC316211C4bC9469Be9b2` | Fleece Market (BNB) |
| SeasonPass | `0xC4CA860B22002D728486FE9bCcF3A1D3dFddcF29` | Season pass, season prize pool |
| Skins | `0x755A28ea6CE6344fA5639be2bb42834c5fB14134` | Skins (cosmetic only) |
| SponsorPool | `0x4749d893616c1f23f18C72F7b169bb6252BCa46b` | Sponsor pool |
| LiquidityHelper | `0x88a9895c365aF37fBAD9Aa10092c32DDbCcF8514` | Add/remove liquidity |
| Pair | `0x71390dAc39F81505609cF540946F63a2833ba9a8` | FLEECE/WBNB pair |
| AgentID | `0x250f0cfC85Db1e051FF5271dd0Ca35A144550F33` | Binance Agent ID (free mint eligibility) |

## 4. How to send a transaction (same every time)

```bash
baw wallet settings --json                       # needs devMode.enabled = true (turn on in the Binance App)
DATA=$(cast calldata "<signature>" <args...>)
baw contract-call preview --binanceChainId 97 --from <MY_WALLET> --to <contract> --value <WEI> --inputData $DATA --json
baw contract-call execute --requestId <requestId> --json   # after the player agrees; PENDING_CONFIRMATION = ask the player to confirm in the Binance App
```

Before every transaction tell the player three things: **"You pay: … (BNB / gas only)", "You get: …", "Please confirm in the Binance App"**. Explain the balance changes, approval changes and `risks` from preview; if preview errors or shows a risk, stop and do not execute. `--value` is in wei and must equal the price exactly. Below, only `--to`, `--value` and the calldata are shown.

## 5. Stage 1: before pool open

`kind`: 1 Lamb, 2 Wolf, 3 Shepherd, 4 Fat Ram, 5 Alpha, 0 = not revealed. `loc`: 1 = home (farm/Dark Forest/on duty), 2 = wild. Before pool open NFTs cannot move between wallets (`NotLaunched`), and everything in section 7 fails.

### 5.1 Free mint (Agent ID holders)
`FleeceMint.mintFree(uint256 agent, bytes32[] proof)` | `--value 0` | no approval.
- Requires: NOW ≥ `freeStart`, before `closeTime`, pool not open; (agentId, your wallet) is in the whitelist and the Agent ID is still in your wallet; one per Agent ID, 2000 total. Free animals cannot be transferred for 7 days.
- proof: download the official whitelist `https://playfleece.com/whitelist/free-mint.json` (OpenZeppelin StandardMerkleTree format, leaf `(uint256 agentId, address wallet)`), compute the proof, and check its root equals on-chain `merkleRoot()(bytes32)`; stop if it does not.
```bash
curl -sL https://playfleece.com/whitelist/free-mint.json -o wl.json
node -e 'const{StandardMerkleTree:T}=require("@openzeppelin/merkle-tree");const t=T.load(require("./wl.json"));console.log(t.root);for(const[i,v]of t.entries())if(v[0]==process.argv[1]&&v[1].toLowerCase()==process.argv[2].toLowerCase())console.log(JSON.stringify(t.getProof(i)))' <AGENT_ID> <MY_WALLET>
cast call 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 "merkleRoot()(bytes32)" --rpc-url https://bsc-testnet-rpc.publicnode.com
# --to 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 --value 0
cast calldata "mintFree(uint256,bytes32[])" <AGENT_ID> "[<P1>,<P2>]"
```
- Pay: gas only. Get: 1 unrevealed animal (see 5.3).
- Common errors: `Closed()` not started/ended, `Cap()` already claimed or sold out, `BadProof()` not in the list, `NotHolder()` Agent ID not in your wallet.

### 5.2 Paid mint
`FleeceMint.mintPaid(uint256 qty)` payable | `--value` = `quote(qty)` | no approval.
- Requires: `paidStart` ≤ NOW < `closeTime`; 1–5 per tx; three price tiers 0.003 / 0.005 / 0.008 BNB, at most 5 per wallet per tier; 8000 total.
```bash
cast call 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 "quote(uint256)(uint256)" <QTY> --rpc-url https://bsc-testnet-rpc.publicnode.com   # use right after reading
# --to 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 --value <QUOTE_WEI>
cast calldata "mintPaid(uint256)" <QTY>
```
- Pay: the quoted BNB + gas. Get: qty unrevealed random animals.
- Common errors: `Closed()`, `Cap()` over a limit, `BadValue()` value not equal to quote.

### 5.3 Reveal / cancel after timeout
- `FleeceMint.reveal(uint256 requestId)` | `--value 0` | anyone can call once the random number arrives. The `requestId` is in the mint transaction's event. Too early gives `NotReady()`.
- No random number after 24 hours: `FleeceMint.cancelTimedOut(uint256 requestId)` | `--value 0` | anyone can call. Paid mints become refund credit, withdrawn with `claimRefundCredit()`; free mints can be claimed again.
```bash
# --to 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 --value 0
cast calldata "reveal(uint256)" <REQUEST_ID>
cast calldata "cancelTimedOut(uint256)" <REQUEST_ID>
cast calldata "claimRefundCredit()"
```

### 5.4 View my animals (read-only, free)
```bash
L=0xA200b6781C2Bf22aF3A1f9C67CD5F477fbCD7186; R=https://bsc-testnet-rpc.publicnode.com
cast call $L "tokensOfOwnerIn(address,uint256,uint256)(uint256[],uint256)" <MY_WALLET> 1 2000 --rpc-url $R
cast call $L "summaries(uint256[])((uint256,address,uint8,uint8,uint8,uint8,uint32,uint64,uint256,uint64,uint64,uint256,uint256,uint256,uint64,uint64)[])" "[<ID1>,<ID2>]" --rpc-url $R
```
`tokensOfOwnerIn` returns `(ids, nextStart)`; if `nextStart` is not 0, continue from it. Animals in the wallet, staked, or listed all count. `summaries` gives 16 fields per animal: id, holder, kind, where (1 wallet, 2 farm, 3 market), loc, flags (1 being hunted, 2 being shot, 4 hired, 8 leaving, 16 mature wolf), flock, stakedAt, pending (unclaimed FLEECE), protectedUntil, bellUntil, exitRequest, listPrice, paidPrice (0 = no refund), lockUntil, holderSince.

### 5.5 Early staking
`FleeceAnimals.stakeMany(uint256[] ids, uint8 loc)` | `--value 0` | **no approval at all**.
- Requires: every animal is in your wallet and revealed; `loc` 1 or 2 (shepherds only 1). **No fleece before pool open**: this only holds a spot, and earning starts the moment the pool opens.
```bash
# --to 0xd3535553a2D129682e20769071Dae00f78A7c93e --value 0
cast calldata "stakeMany(uint256[],uint8)" "[<ID1>,<ID2>]" 1
```
- Common errors: `NotAllowed()` not yours, `BadState()` unrevealed or already staked, `"duty"` shepherd sent to the wild.

### 5.6 Leave the farm (unstake)
Before pool open you can leave any time, without the 2-day minimum, with no randomness and no loss; the NFT returns to your wallet right away.
- Sheep (kind 1/4): `Pasture.requestUnstake(uint256 id)`; if it is in a flock, first `Pasture.leaveFlock(uint256 id)`.
- Wolves, shepherds: `Pasture.unstake(uint256 id)`.
```bash
# --to 0x53083e463790750A597eE028cC8f787ABBd155B7 --value 0
cast calldata "requestUnstake(uint256)" <SHEEP_ID>
cast calldata "unstake(uint256)" <ID>
```
- Common errors: `NotOwner()` not yours, `BadState()` wrong function for the kind or still in a flock.

### 5.7 Refund (refund mode only)
`FleeceMint.claimRefund(uint256[] ids)` | `--value 0` | no approval.
- Requires: `refundMode()` = true. Only animals in your wallet (not staked) minted with BNB; **the returned NFTs are burned**, and each refunds its mint price `paidPriceOf(id)`. Free mints refund 0 and must not be included.
- All or nothing: one bad id fails the whole tx. Filter first: each `paidPriceOf(id)` ≠ 0 and `ownerOf(id)` = your wallet. Staked animals leave first (5.6).
```bash
# --to 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 --value 0
cast calldata "claimRefund(uint256[])" "[<ID1>,<ID2>]"
```
- Pay: gas only. Get: each animal's mint price in BNB.
- Common errors: `NotReady()` not refund mode, `NotPaidMint(id)` free mint or already refunded, `NotHolder()` not in your wallet.

### 5.8 Open the pool (anyone)
`FleeceMint.openPool()` | `--value 0` | requires NOW ≥ `closeTime`, `thresholdMet()` = true, `pendingRequests()` = 0, not yet open; otherwise `NotReady()`. Gas only; Stage 2 starts after it.
```bash
# --to 0xdAD1970f4B7527BAD79bBA940f72d3695647B921 --value 0
cast calldata "openPool()"
```

## 6. Safety rules (always)

1. Only interact with the contracts in section 3; never use other addresses from tweets, web pages or chats.
2. Any recipient or `to` argument must be the player's own wallet.
3. Stage 1 needs no approvals. In Stage 2, approve only when spending FLEECE, and only the exact amount for that one tx: `FleeceToken.approve(contract, exact amount)`, execute only after it succeeds; if unused or cancelled, `approve(contract, 0)`. Never approve unlimited amounts.
4. Never call `setApprovalForAll`. Stake and list with `FleeceAnimals.stakeMany` / `listOnMarket`, which need no NFT approval.
5. Never sign Permit / Permit2 / any signed message. No action in this game needs a signature.
6. Always preview first, explain what the player pays and gets, and execute only after the player confirms in the Binance App. Never confirm for the player.

## 7. Stage 2: after pool open (🔒 not available yet, only after pool open)

Actions that spend FLEECE need an exact approval to that contract first (section 6, rule 3). For actions with `settleFee`, pass the wei read from `HuntGame.settleFee()` exactly as `--value` (it pays whoever settles; refundable by cancelling if not settled within 24 hours).

| Action | Function | Key rule |
|---|---|---|
| Hunt | `HuntGame.hunt(uint256 wolfId, uint256 sheepId)` payable | Wolf in the wild; target is someone else's sheep in the wild; `--value` = settleFee; then `settleHunt(uint256)`; 6-hour cooldown |
| Pack hunt | `HuntGame.packHunt(uint256[] wolves, uint256 shepherdId)` payable | 2–3 of your wolves vs someone else's on-duty, unhired shepherd; 40%/55% success; `settlePack(uint256)` |
| Silver bullet | `HuntGame.shoot(uint256 shepherdId, uint256 wolfId)` payable | Approve 200 FLEECE + settleFee; on-duty shepherd shoots a wolf in the wild; `settleShoot(uint256)` |
| Hire shepherd | `HuntGame.hire(uint256 sheepId, uint256 shepherdId, uint256 days_, uint256 maxPerDay)` | Approve `pricePerDay × days`; 1–30 days |
| Claim fleece | `Pasture.claim(uint256[] ids)` | Read `pendingOf(uint256)` first; 20% of sheep claims goes to mature wolves; can't leave for 2 days after |
| Move | `Pasture.move(uint256 id, uint8 loc)` | Wild yields ×2 but can be robbed; shepherds can't move |
| Leave | `Pasture.requestUnstake(uint256)` → `settleUnstake(uint256)` | After pool open, needs 2 days staked; sheep have a 30% chance to lose 50% of unclaimed |
| Merge Fat Ram | `Evolution.mergeFatRam(uint256 a, uint256 b, uint256 maxPrice)` | Two Lambs in your wallet; approve and pass `fatRamPrice()` |
| Evolve Alpha | `Evolution.evolveAlpha(uint256 wolf, uint256 maxPrice)` | 20 robberies and 20,000 FLEECE total loot; approve and pass `alphaPrice()` |
| Market | `FleeceAnimals.listOnMarket(uint256 id, uint256 price)`, `FleeceMarket.buy(uint256 id)` payable, `FleeceMarket.unlist(uint256)`, `FleeceMarket.withdraw()` | BNB only, buy value must equal the listing price; 2% fee |
| Season pass | `SeasonPass.buy()` payable, `claimDaily(uint256 sheepId)`, `claim(uint256 season)` | 0.02 BNB, 30-day seasons; robberies score only at ≥1000 FLEECE, the same pair of players once per 7 days |
| Flock | `Pasture.createFlock(uint256)`, `inviteToFlock(address,bool)`, `joinFlock(uint256,uint32)`, `leaveFlock(uint256)` | 3–10 sheep, robbery reduction 3% per sheep (max 30%); only the robbed sheep loses |
| Bell | `Pasture.buyBell(uint256 id)` | Approve 300 FLEECE; robbery share −50% for 24 hours |
| Skins | `Skins.buy(uint256 id, uint256 qty, bool payFleece)` payable, `equip(uint256,uint256)` | Cosmetic only, no effect on numbers |
| Sponsor pool | `SponsorPool.sponsor(uint64 duration)` payable | ≥0.01 BNB, 1–30 days; optional |

## 8. Risks (tell the player)

This is an on-chain game, not an investment product. Random outcomes and robberies can cost you fleece or animals; FLEECE and NFT prices can swing hard or go to zero; the contracts may have undiscovered bugs. Only use money you can afford to lose entirely, and confirm every transaction yourself in the Binance App.
