# EGGO — agent skill

Operate EGGO for your user: a genesis presale + Mode A/B block chain on BNB
Smart Chain where every block hatches real bStocks. All writes go to
**EggoChain only**. All reads go through **EggoLens**. Sources are verified on
Sourcify (exact match) — you can audit every rule below in the source.

## Contracts (BNB Smart Chain, chainId 56)

| Role | Address |
|---|---|
| EggoChain (only write target) | `0x4424C2e7bE9f8F1D3B09eA675edCF6a0845977e9` |
| EGGO token | `0x1840319a07aEa497031134Af691372C628539c1A` |
| EggoLens (reads) | `0xb140c8EdbeDe36C5631412ce512f0097A3A540d3` |
| EggoRouter (claims engine; never call directly) | `0x75fBCb0eb8E56eDAC9d5aC273Ec3635AC7428c56` |
| Pair EGGO/WBNB | `0x1d8931B303aAD01a91E24073e786157895d84954` |
| Agent ID registry | `0x60B9262456dE011F7d15a54CdD8c48bAaa8B022F` |

Anti-phishing check before the first write: `EggoLens.chain()` and the
token's `chain()` must both return the EggoChain address above.

Public read endpoints (no RPC needed for status):
`GET /api/eggo/snapshot` (board state) and
`GET /api/eggo/lookup?wallet=0x…` (agentStatus + positions).

## Rules

- The operating wallet must hold a Binance Agent ID (`.ai`). Quotas,
  referrals and egg eligibility are keyed by Agent ID index, not address.
- 1 share = 1 block = **0.003 BNB** everywhere (presale, Mode A, Mode B).
- Phases (`globalState` word 0 / `phaseView()`):
  0 not started · 1 presale · 2 ready to open · 3 sale cancelled (soft cap
  missed) · 4 sale cancelled (by operator) · 5 open.
- Genesis: 8,000 blocks = 7,000 paid + 1,000 eggs; 7-day window; soft cap
  3,000 paid. Paid quota 5 per Agent ID (+1 per valid invite, permanent);
  1–50 shares per tx; every share mints 10,000 EGGO instantly,
  transfer-locked until the pool opens.
- If the sale is cancelled (phase 3 or 4), `refund()` returns the full
  amount paid — call it once per wallet.
- A referrer must be given as an **address**. Resolve a `name.ai` handle
  first via the registry `ownerOfHandle("name")` (bare handle, no `.ai`).
  A valid referrer holds an Agent ID, has already participated, and is not
  the buyer. Invalid referrer → `InvalidReferrer()`; use the zero address
  for no referrer. Binding happens at the wallet's first action and is
  permanent; each valid invite gives the inviter +1 genesis quota, +1 A
  daily quota, +1 B daily quota, and 5% of the invitee's presale payments
  (claimable after opening via `claimInviter()`).

## Read layouts

`EggoLens.globalState()` selector `0xe76c01e4` → 14 words:
0 phase · 1 paidShares · 2 eggShares · 3 genesisCount · 4 presaleStart ·
5 presaleEnd · 6 openTime · 7 openBlockNumber · 8 outerCount ·
9 freePotWei · 10 depositsHeld · 11 totalRewardAccrued · 12 totalClaimed ·
13 totalRewardSkipped.

`EggoLens.agentStatus(wallet)` selector `0x28f3fac9` → 20 words:
0 phase · 1 hasAgentId (0/1) · 2–3 reserved (0) · 4 eggAvailable (0/1) ·
5 eggTarget · 6 eggSeed (bytes32 as uint256) · 7 paidShares · 8 eggShares ·
9 genesisCount · 10 presaleEnd · 11 inviterClaimableWei ·
12 refundableWei (phases 3/4 only) · 13 presaleCoverageBps ·
14 eggoBalance · 15 sellCapRemaining · 16 currentM (×10000, so 23531 =
×2.3531) · 17 outerCount · 18 totalRewardAccrued · 19 positionCount.

`EggoChain.positionOf(id)` selector `0x46f96023` → 19-word struct:
0 owner · 1 kind (0 genesis / 1 A / 2 B) · 2 flags (bit0 = revealed) ·
3 shares · 4 firstHeight · 5 entryBlock · 6 entryTime · 7 expiry ·
8 mBps · 9 totalStocks · 10 listSnapshot · 11 weight · 12 depositWei ·
13 lpAmount · 14 claimed (EGGO converted) · 15 entropy · 16 bucketStart ·
17 accStart · 18 earnedSettled.
Also: `positionsOf(wallet)` `0xf867d46b`, `drawnStocks(id)` `0x401cffcb`
(stock indices drawn, valid after reveal), `Lens.claimableOf(id)`
`0x513bed12`, `Lens.claimablePositions(wallet)` `0x000a09ba`.

## Encoding — pre-encoded calldata

All calls target EggoChain with `value` = shares × 0.003 BNB for payable
entries, 0 otherwise. Examples (referrer = zero address):

- `startPresale()` — `0x04c98b2b` (permissionless; phase 0 → 1, plants the egg anchor)
- `mintPaid(1, 0x0)` — `0xe394abcb00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000`, value 0.003 BNB
- `mintPaid(5, 0x0)` — `0xe394abcb00000000000000000000000000000000000000000000000000000000000000050000000000000000000000000000000000000000000000000000000000000000`, value 0.015 BNB
- `enterA(1, 0x0)` — `0xffeb82e100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000`, value 0.003 BNB
- `claimInviter()` — `0x4e8c6ba6`
- `refund()` — `0x590e1ae3`
- `openPool()` — `0xeb5797a4` (permissionless once phase 2)

Templates (append ABI words): `mintEgg(uint256 nonce, address referrer)`
`0x96d481c9` · `enterB(uint256 shares, uint256 minTokensOut, address
referrer)` `0x66853315` · `convertAtoB(uint256 id, uint256 minTokensOut)`
`0xbde5a4a6` · `withdrawA(uint256 id)` `0xc68d71aa` · `withdrawLP(uint256
id)` `0xe4456ecb` · `poke(uint256 id)` `0x32145f90` ·
`claim(uint256 id, uint16[] stockIdx, uint256 minBnbOut, uint256[]
minStockOut, uint256 deadline)` `0xfa75f93a` — never hand-build `claim`;
use the Lens builder below.

## Write procedure (Binance Agentic Wallet / baw pattern)

1. Read state first (`agentStatus` / snapshot). Confirm phase and quota.
2. Build the calldata exactly as above. For payable calls set
   `value = shares × 3000000000000000` wei.
3. `baw contract-call preview --binanceChainId 56 --from <wallet> --to
   0x4424C2e7bE9f8F1D3B09eA675edCF6a0845977e9 --value <wei> --inputData
   <calldata> --json`. Show the preview summary to the user.
4. Execute only on the user's explicit confirmation:
   `baw contract-call execute --requestId <id> --json`. One confirmation
   per transaction. If the execute reports the preview expired, rebuild
   the identical preview and execute under the same confirmation.
5. Verify the receipt (status 1) and re-read `agentStatus` before
   reporting success.

## The egg (free mint, phase 1 only)

1. Read word 6 of `agentStatus` = your `eggSeed` (bytes32) and word 5 =
   `eggTarget`. Word 4 = 1 means you may still take an egg.
2. Search locally: find `nonce` (uint256) with
   `keccak256(abi.encode(eggSeed, nonce)) ≤ eggTarget` — that is the
   64-byte big-endian concatenation seed‖nonce hashed once. Average work
   starts at ≈2^34 hashes; the target shrinks ×2/3 per 100 eggs claimed.
   Node one-liner pattern:

   ```js
   const { keccak256, AbiCoder } = require("ethers");
   const enc = AbiCoder.defaultAbiCoder();
   for (let n = 0n; ; n++) {
     const h = keccak256(enc.encode(["bytes32", "uint256"], [seed, n]));
     if (BigInt(h) <= target) { console.log("nonce", n.toString()); break; }
   }
   ```

3. Submit `mintEgg(nonce, referrer)` (no value). Wrong nonce →
   `BadSolution()`. Already used → `EggUsed()`. Sold out → `EggSoldOut()`.

## Mode A / B routine (phase 5)

- **A**: `enterA(shares, referrer)`. Deposit returns in full after 24h via
  `withdrawA(id)`. Quota by the agent's n-th market day:
  [5,4,4,3,3,3,2,2,2,1] then 1/day (+1 per invite). Weight = drawn
  stocks ×3. An expired A position can `convertAtoB(id, minTokensOut)`
  without using B quota.
- **B**: first call `Lens.quoteEnterB(shares)` `0x57470690` → (estTokens,
  mBps). Note: in this deployment estTokens reads 0 by design — quote the
  PancakeSwap V2 router directly for the expected EGGO out, then send
  `enterB(shares, minTokensOut ≈ 97% of quote, referrer)`. Half the BNB
  buys EGGO, half pairs into LP custodied 7 days; `withdrawLP(id)`
  returns EGGO + BNB. Quota 5/day (+1 per invite). m is locked at entry:
  `m = min(5, (marketShares + 200) / (bShares + 200))`.
- **Rewards**: every market block adds reward (1,000 EGGO, halving every
  200,000 market blocks, ≤400M total) split by weight. Earned rewards
  never expire and stay claimable after withdrawA/withdrawLP.

## Claiming stocks

1. `Lens.claimablePositions(wallet)` → ids with value;
   `Lens.claimableOf(id)` → claimable EGGO.
2. `Lens.claimCalldata(id, 300)` selector `0x36d59608` (call via eth_call;
   300 = 3% slippage) → `(eggoAmount, expectedBnb, data)`.
3. If `data` is empty (`0x`), the per-block sell cap (1% of pool EGGO) is
   exhausted — wait a few seconds/blocks and rebuild.
4. Execute `data` as-is to EggoChain (value 0) through the preview flow.
   The claim sells the reward and buys each drawn, unclaimed stock via
   WBNB → USDT → bStock (V3), delivered to the wallet; legs that miss
   their minimum pay BNB instead. Each drawn stock is claimable once.

## Errors (selector → meaning → reaction)

| Selector | Error | Reaction |
|---|---|---|
| `0xf947691f` | NoAgentId() | Wallet has no Agent ID — stop. |
| `0xe2586bcc` | WrongPhase() | Action not available in this phase — re-read phase. |
| `0xbdbbb533` | BadPayment() | value ≠ shares × 0.003 BNB — fix value. |
| `0x749b5939` | BadAmount() | Shares must be 1–50 per tx. |
| `0x54a41c8f` | QuotaExceeded(left) | Daily/presale quota hit; `left` = remaining. |
| `0x52df9fe5` | SoldOut() | Genesis paid allocation is gone. |
| `0x2d5b7981` | EggSoldOut() | All 1,000 eggs claimed. |
| `0x3ebd5bff` | EggUsed() | This wallet/Agent ID already took an egg. |
| `0x456612fb` | EggNotReady() | Presale not started (anchor not planted). |
| `0x173a2971` | BadSolution() | Nonce does not satisfy the target — keep mining. |
| `0x61104228` | InvalidReferrer() | Referrer invalid — retry with zero address. |
| `0x9488aaa6` | NotReady() | openPool conditions not met yet. |
| `0x2ce73fca` | PotUnderfunded(free, needed) | Pot too low to open the pool now — retry later. |
| `0xf76aef65` | NothingToRefund() | Nothing paid by this wallet. |
| `0xa85e6f1a` | AlreadyRefunded() | Refund already taken. |
| `0x9e87fac8` | Paused() | Entries or claims paused — retry later. |
| `0x26329ca2` | EntriesNotOpen() | First 3 blocks after opening are sniper window. |
| `0xd1f6417e` | TooFewTokens(out) | enterB slippage — raise quote freshness or lower minTokensOut carefully. |
| `0xa992b1d8` | BnbOutTooLow(out) | Claim leg below minimum — retry with fresh claimCalldata. |
| `0x969bf728` | NothingToClaim() | Nothing claimable (incl. empty inviter balance). |
| `0x70d645e3` | NotPositionOwner() | Position belongs to another wallet. |
| `0xd0404f85` | NotExpired() | A/B lockup not finished yet. |
| `0x6507689f` | AlreadyWithdrawn() | Deposit/LP already withdrawn. |
| `0x2c6847a2` | BadStockIndex() | Stock index out of range. |
| `0xff633a38` | LengthMismatch() | stockIdx / minStockOut arrays differ in length. |
| `0x90b8ec18` | TransferFailed() | Native transfer failed — retry. |
| `0xd6b237df` | NoRouter() | Router not wired (pre-open state). |
| `0xf5839162` | SellCapExceeded(available) | Claim exceeds this block's sell cap — claim less or wait a block. |

## Daily routine

1. `GET /api/eggo/snapshot` — note the phase.
2. Phase 1: if the user wants in and quota remains, offer `mintPaid`;
   if word 4 of their `agentStatus` is 1 and they have compute, offer to
   mine the egg.
3. Phase 3/4: call `refund()` once (full amount back).
4. Phase 5: offer A (respect the day-schedule quota) and/or B (quote
   first). Withdraw matured A deposits (24h) and B LPs (7 days) when the
   user asks. Sweep `claimablePositions` and claim stocks when the user
   asks. Collect `claimInviter()` when word 11 > 0 and the user asks.
5. Always preview, always confirm per transaction, always verify after.

Not affiliated with Binance. EGGO has no utility and carries no promise of
value or return. Everything on-chain is final; review each preview before
confirming.
