# PoolPot — agent access Canonical URL: https://poolpot.fun/llms.txt Site: https://poolpot.fun · Contact: hello@poolpot.fun PoolPot lets people (and agents) buy tickets for Megapot's daily on-chain lottery draw on Base, pooled per draw: every ticket bought through PoolPot for a drawing goes into that drawing's shared pool, and every prize the pool collects is split equally per ticket — pot ÷ tickets bought. The contracts are immutable, ownerless (no pause, no upgrade, no parameter setters) and fully permissionless: an agent with a funded wallet can do everything the website does by calling the contracts directly. This file is the playbook. ## Chain and contracts (Base, chainId 8453) - PoolFactory: 0x039894BA3a66DAD20c58939EfD021663244B0A59 (deployed at block 51431746) - RoundPool implementation (EIP-1167 clones, one per drawing): 0x9fde99dB9f48031aA9fC4Cd0D7301cD04e939404 - AutoBuyWallet implementation (clones, one per plan): 0x7acbf03868C3d8F80426C18cDE2f22eE7A46e6a1 - Megapot Jackpot: 0x3bAe643002069dBCbcd62B1A4eb4C4A397d042a2 - Megapot TicketNFT: 0x48FfE35AbB9f4780a4f1775C2Ce1c46185b366e4 - USDC: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913 (6 decimals; $1 = 1_000_000) All verified on Basescan, e.g. https://basescan.org/address/0x039894BA3a66DAD20c58939EfD021663244B0A59 ## Key types and constants - Pick struct: { uint8[5] normals; uint8 bonusball } — normals strictly ascending, each in 1..ballMax; bonusball in 1..bonusballMax (ranges come from the drawing). - maxJoin() = 11 tickets per join transaction (and per auto-buy day). - MAX_COLLECT = 150 ids per collect() call (the site sends 100 per transaction). - Collect bounty = min(credited × 0.25%, $0.25 × ids collected), paid to the caller. - Auto-buy tip cap: maxTipPerDay() = 500_000 ($0.50). Plans run up to 365 days. - claimMany: up to 60 drawings per call. fundMany: up to 25 plans per call. ## 1. Read the current drawing - Jackpot.currentDrawingId() -> uint256 (e.g. 175 on 2026-09-15) - Jackpot.getDrawingState(drawingId) returns a struct; the fields an agent needs: ticketPrice (USDC base units, currently 1_000_000 = $1), drawingTime (unix seconds; draws run daily at 17:00 UTC), ballMax (currently 30), bonusballMax (currently 10), jackpotLock (true = purchases closed while the draw runs). - PoolFactory.roundOf(drawingId) -> address of that drawing's RoundPool clone (address(0) until the first buyer opens it; join() opens it lazily, so you never need to call openRound yourself). RoundPool views: price(), state(), ticketsBought(), pot(), bought(addr), claimable(addr), claimsOpen(). ## 2. Buy tickets Cost is exact: cost = n × ticketPrice where n = picks.length + quickPicks (1 ≤ n ≤ 11 per call). Then two transactions: 1. USDC.approve(factory, cost) — approve the exact cost, no more. 2. PoolFactory.join(drawingId, picks, quickPicks, maxCost) - drawingId must equal Jackpot.currentDrawingId() (else WrongDrawing). - picks: Pick[] of your own numbers (may be empty). Your own picks MAY duplicate a combination the pool already holds — that is allowed. - quickPicks: uint16 count of contract-generated picks. Quick picks NEVER duplicate a combination this pool already bought, nor each other. - maxCost: revert bound (CostAboveMax) — set it to the exact cost. - USDC is pulled from msg.sender only; tickets are credited to msg.sender. joinFor(drawingId, beneficiary, ...) credits another address instead (the payer is still msg.sender). Buy cutoff: the contract accepts joins until the drawing locks (jackpotLock becomes true around the 17:00 UTC draw) or the drawing settles. The website stops offering joins 60 seconds before drawingTime so a transaction cannot be mined too late — agents should do the same. Joins also revert ClaimsClosedToJoins once claims are open. ## 3. After settlement: collect, then claim A drawing is settled once Jackpot.currentDrawingId() > drawingId. Discover the pool's winning ticket ids: - Chain is the source of truth: Megapot's TicketNFT ids owned by the round address, checked against Jackpot.getTicketTierIds(ids) and that drawing's Jackpot.getDrawingTierPayouts(drawingId). - Convenience: the public Megapot Data API (https://api.megapot.io/v1), e.g. GET /wallets/{roundAddress}/wins/rounds/{drawingId} — the round address is the "wallet" holding the pool's tickets. The site proxies the same paths at https://poolpot.fun/api/megapot/... (cached, same shapes). The API's `claimed` flag can lag a fresh collect; verify on chain before sending. Then: - RoundPool.collect(ids) — anyone may call, no tickets required. ids must be strictly ascending, at most 150 per call (the site uses 100). The call claims those winnings from Megapot into the pool and pays the CALLER a bounty of min(credited × 0.25%, $0.25 per id actually collected), taken out of the credited amount; the rest fills the pot for everyone. Splitting a batch into smaller calls earns no extra bounty (each id is collected once). Ids not owned by the round or from another drawing are filtered out, not fatal. Requires the drawing to be settled (NotSettled otherwise). - RoundPool.claim() — pays msg.sender's share only: entitled = bought[you] × pot / ticketsBought (floor); you receive entitled − alreadyPaid. Reverts ClaimsNotOpen / NoTickets / NothingToClaim. Claims NEVER expire, and claiming again after a later collect pays the difference — claiming twice is normal. - PoolFactory.claimMany(drawingIds[]) — claim across up to 60 drawings in one transaction; a drawing that reverts is skipped, not fatal. Pays msg.sender. ## 4. Auto-buy plans (optional) - PoolFactory.createAutoBuy(fixedPicks, quickPicksPerDay, daysTotal, tipPerDay, maxEscrow) clones an escrow wallet for msg.sender. Tickets/day k = fixedPicks.length + quickPicksPerDay, 1 ≤ k ≤ 11; 1 ≤ daysTotal ≤ 365; tipPerDay ≤ 500_000 ($0.50). Escrow pulled from msg.sender = k × daysTotal × ticketPrice + daysTotal × tipPerDay; reverts CostAboveMax if that exceeds maxEscrow. Approve USDC for exactly the escrow first. Views: walletOf(owner, nonce), nextWalletOf(owner), planNonce(owner), isPlan(addr). - AutoBuyWallet.fund(drawingId) — ANYONE may call, once per drawing (AlreadyFunded otherwise). Buys the plan's tickets for that drawing, credited to the plan's OWNER, and pays tipPerDay to the caller if the caller is not the owner. A failed day is not consumed; there is no calendar expiry. - PoolFactory.fundMany(wallets[], drawingId) — fund up to 25 plans in one transaction; each plan is try/caught so one failing plan skips, and all tips go to msg.sender. Size gas with factory.fundGasFloor(ticketsPerDay) per plan. - AutoBuyWallet.close() — OWNER ONLY: cancels and refunds the entire remaining escrow, in any state. Nobody else can touch the escrow. ## 5. Safety notes for agents - Base mainnet only: chainId 8453. Simulate (eth_call / estimateGas) before sending every transaction. - USDC has 6 decimals. Approve exact amounts only, and only to the contract you are about to call (factory for join/createAutoBuy; a round address only for its direct join() fallback). - Never send ETH to these contracts, and never transfer USDC directly to the factory address — the factory is ownerless with no sweep, so a direct transfer is unrecoverable. USDC only ever moves via approve + the calls above. - Payouts always go to msg.sender (claim, collect bounty, tips); no function lets a third party redirect your funds, and none pulls USDC from anyone but msg.sender. - The contracts add gas-left guards: a call may revert InsufficientGas(i) rather than half-succeed — resend with a higher gas limit (the site adds 50% headroom on collect/claimMany/fundMany). ## Links - Site: https://poolpot.fun (buy) · /my (your tickets & claims) · /auto (auto-buy plans) · /results (past draws) · /how-it-works · /agents (this content as a page) · /terms - Basescan: https://basescan.org/address/ - Megapot Data API: https://api.megapot.io/v1 (proxied at https://poolpot.fun/api/megapot/...) - Contact: hello@poolpot.fun