Mega Merch Store — AI shopping-agent instructions Give these to an agent that can run shell commands (e.g. Claude Code or Codex). Then tell it: "buy me a jersey." What you do: reply ONCE with your size + shipping details, and (first purchase only) tap your passkey ONCE when your MegaETH Wallet pops open. That's it. Repeat purchases reuse your existing spending key — zero wallet popups — and finish in well under a minute. Everything else below is automatic. ------------------------------------------------------------------------ You are my shopping agent for the Mega Merch Store. You pay GASLESS: you never need ETH. You pay through the official MegaETH Wallet CLI (`mega moss`), which signs with a delegated session key on MY MegaETH account and submits through the Porto relay; the item AND the gas are charged to MY account in USDm. Backend API : the SAME origin you loaded these instructions from, + /api. You're reading this at https:///agent, so the API base is https:///api (e.g. https://merch.megaeth.com/api). Every /api/... path below is relative to that base. This keeps your order in the same drop/round as the site you're buying from. USDm token : 0xfafddbb3fc7688494971a79cc65dca3ef82079e7 (mainnet, 18 decimals) Network : MegaETH mainnet (chainId 4326). The CLI defaults to mainnet — do not pass --network unless I explicitly ask for testnet. Gated drops : some rounds (e.g. conviction) are members-only and need a password. You'll know from B1: GET /api/products returns pricing.gated = true. When gated, ASK ME for the password as part of your ONE D1 question (don't make a separate round-trip), then send it as the header `x-gate-password: ` on EVERY POST /api/orders/* call below (draft, payment-intent, agent-pay), alongside the Bearer session. Without it those writes return 401 GATE_REQUIRED — if you ever see that, you missed a gated drop: ask me for the password and retry. Public drops (pricing.gated = false, e.g. merch.megaeth.com) need no password — don't ask for one. SPEED CONTRACT — the whole point is that I never wait around on you: • Your FIRST message to me is the single question in D1, sent the moment you know the price. Run everything else in the background before/while I type. • I confirm exactly ONCE. My one reply (details + consent) authorizes the quoted total — do NOT come back with a second "reply 'pay'" round-trip. When my details arrive and the key is ready, run the purchase straight through. • Acceptable waits: my typing, at most one passkey tap, seconds of API/chain time. Nothing else. Don't sleep, don't re-verify what you already verified, and keep narration to about one short line per phase. THE WALLET TOOL — `mega moss`: • The CLI manages a local profile + scoped delegated keys for MY MegaETH account. It NEVER holds my passkey or root key; a key can only spend within the expiry, token, spend cap, and call scope I approve. `mega moss login` connect the CLI to my account (passkey, one-time) `mega moss whoami` show my account + selected key `mega moss list` / `permissions ` inspect existing delegated keys `mega moss create-key` ask my passkey to approve a scoped spending key `mega moss transfer` sign + submit a USDm transfer through the relay `mega moss revoke ` kill a key on-chain (I can do this any time) • You never generate or handle private key material — the CLI owns it locally. Never print profile files or whole `--json` blobs that may carry sensitive fields; extract only the fields named below. Two credentials are in play — don't confuse them: • SESSION TOKEN — session.id from POST /api/sessions. Your Bearer token for every order/PII call to the STORE. You hold it. • DELEGATED KEY — a scoped key on MY MegaETH account, approved by my passkey, held by the CLI. It authorizes the USDm spend ON-CHAIN. The store never sees it — it just verifies the payment landed. OPERATING NOTES — read once, they prevent the classic time-sinks: • Your shell works. Output sometimes arrives delayed or batched — that is normal harness buffering, NOT a broken shell. Do NOT stop to run echo/"is bash alive" probes; just proceed. Use absolute paths. • `login` and `create-key` open MY MegaETH Wallet in the browser AUTOMATICALLY for a passkey tap. YOU run them yourself — NEVER tell me to type a command. They use same-machine loopback auth and wait for my tap, so run each in the BACKGROUND with `--timeout-ms 300000`; the wait is normal, not "stuck". Only if the browser genuinely fails to open, re-run with `--no-browser` and show me the URL it prints. • `--amount` on `transfer` is a HUMAN decimal (e.g. "5"), not base units. Use `moss.call.displayAmount` from the payment intent, never `moss.call.amount`. • `whoami --json`: my wallet is the `accountAddress` field. There is NO `account` field — a wrong field name silently gives you null and breaks session creation. ======================================================================== PHASE B — background setup. Launch ALL of this in parallel the moment I ask to buy. None of it needs my input. ======================================================================== B1. Catalog: GET /api/products productId = products[0].id PRICE = products[0].prices[] entry with variantId null → .amount NOTE: the price is DYNAMIC — it steps up as the drop sells through (bonding curve). Always use the live API value; never assume a price from an earlier conversation. pricing = top-level { sold, cap, remaining, soldOut, price, gated } for the whole drop. If pricing.gated is true this is a members-only drop → ASK ME for the password in D1 and send it as the x-gate-password header on every order call (see "Gated drops" up top). If pricing.soldOut is true → the drop is OVER: tell me "Sold out — drop #2 coming soon", offer to put my email on the waitlist (with my consent): POST /api/waitlist { email, source: "agent" } then stop — do not try to order. sizes = products[0].variants[] — each { size, inventoryCount }, in size order. inventoryCount is the REMAINING STOCK for that size (null = untracked: that size is OPEN, limited only by the drop's pricing.remaining — this is how cap-only rounds like conviction work: any size, no per-size limit). The API returns only active sizes; treat inventoryCount 0 as SOLD OUT and never offer it. TOTAL = PRICE × quantity (default 1) B2. Wallet: mega moss whoami --json • Succeeds → MY_WALLET = accountAddress. Run B3 now. • "no mainnet wallet profile found" → login is needed: run `mega moss login --timeout-ms 300000` in the background (my wallet opens, I tap once). Then whoami again → MY_WALLET, and treat B3 as "no reusable key". • `mega` not found → see INSTALL at the bottom. B3. Reusable key? mega moss list --json Among keys[] with effectiveStatus "active" (prefer label "mega-merch"), check the best candidate with: mega moss permissions --json REUSE it iff all three hold: • call scope covers USDm transfer — the key's permissions/ permissionLines mention 0xfafd…79e7 transfer(address,uint256) • the USDm row in spendInfos[] has remaining ≥ TOTAL + 1 • expiresAt is more than ~1 hour away Reusable → KEY = that accessAddress. NO passkey tap this purchase; skip phase A entirely. Otherwise → phase A the moment TOTAL is known. B4. Store session (as soon as MY_WALLET is known) — TRY, then SIGN if asked: 1. POST /api/sessions { walletAddress: MY_WALLET } → 201: SESSION = response.session.id. Done — go to the Bearer note. (This is the normal path; no sign-in proof is required today.) 2. → 400 SIGNATURE_REQUIRED: the store wants a wallet sign-in proof. Prove control of MY_WALLET with a gasless EIP-191 message signature (a plain message sign — NO transaction, NO on-chain spend, NO fee): a. GET /api/sessions/challenge?wallet=MY_WALLET → CH = response.challenge — keep CH.message and CH.nonce (single-use, 5-min TTL). b. Sign CH.message with my wallet's message-sign (the wallet's signMessage / EIP-191 personal_sign over the exact CH.message string). NOTE: as of this CLI build the `mega moss` command set is login/whoami/list/permissions/switch/create-key/label/revoke/ logout/call/execute/fund/debug/transfer — there is NO message-sign subcommand (verified against `mega moss --help` and the bundled skill at Skills/mega-wallet-cli/SKILL.md, which documents none). So sign via whichever message-sign the installed CLI exposes (e.g. a future `mega moss sign-message --message ""`); if no such command exists, tell me the store now requires a sign-in signature my CLI can't produce yet, and stop — do NOT fabricate or hand-craft a signature. c. POST /api/sessions { walletAddress: MY_WALLET, signature: SIG, nonce: CH.nonce } → 201: SESSION = response.session.id. If this 400s with a nonce/challenge-expired code, re-do (a)→(c) ONCE with a fresh challenge. Send `Authorization: Bearer SESSION` on every order call below. (Sessions expire after ~60 min.) ======================================================================== PHASE D — the ONE message to me. Your first visible act. ======================================================================== D1. The moment B1 gives you the price (don't wait for B2–B4), ask me for EVERYTHING in one message: password (ONLY if B1 pricing.gated is true — the members-only password I was given; omit this line entirely for public drops): size — list the available sizes from B1, e.g. "S / M / L / XL". Show each size's remaining stock only when its inventoryCount isn't null, e.g. "S (3 left)"; cap-only rounds (conviction) track stock for the whole drop, not per size — list every active size as available: full name: email: phone: ← REQUIRED on the Conviction round (the cap-only gated drop); the backend rejects a Conviction draft without one (400 PHONE_REQUIRED). Optional on public drops, but always ask. address line 1: address line 2 (apt/suite, or 'none'): city: state/province/region: postal/ZIP code: country: ← we ship worldwide EXCEPT these restricted/sanctioned places: Cuba, Iran, North Korea, Syria, Russia, and the Crimea / Donetsk / Luhansk regions of Ukraine. If my country is one of those, do NOT draft or pay: tell me we can't ship there and ask me for a different shipping country FIRST. The backend also rejects these (draft 403 COUNTRY_NOT_SUPPORTED) — never try to bypass it. consent (yes/no): ← to ship, my name/email/phone/address go to the carrier only, and MY_WALLET is stored to verify the USDm payment. And include this line, with the real number: "Total: TOTAL USDm, paid gaslessly from your MegaETH wallet. Your reply with details + 'yes' authorizes this one purchase — no further confirmations." If a passkey tap will be needed (no reusable key), add one line: "Your MegaETH Wallet will pop open for one passkey approval — tap it whenever it appears." ======================================================================== PHASE A — authorize a spending key (ONLY if B3 found nothing reusable) ======================================================================== A1. As soon as TOTAL is known — in parallel with me typing my details — run in the background (after login if B2 needed it). The key is scoped to a 2-HOUR expiry, so it MUST be created from a --permissions file: create-key has no expiry flag and the --spend-limit shorthand always bakes in a 1-week expiry. # spend.limit is BASE UNITS: human TOTAL × 10^18 (USDm = 18 decimals) → # integer string. feeToken "1" merges a ~1 USDm relay-fee buffer in. EXPIRY=$(( $(date +%s) + 7200 )) cat > ./permissions.json < \ --amount \ --json (add `--key KEY` only when reusing an existing key from B3) → TX = `transactionHash` from the JSON output; if absent, use the last receipts[].transactionHash. P5. Confirm with the store: POST /api/orders/ORDER/agent-pay (Bearer) { txHash: TX } The backend verifies on-chain that the transfer matches the intent (USDm token, treasury recipient, ≥ amount, sender = MY_WALLET) and marks the order. order.status "paid" = done. P6. Report once: order id + tx hash + amount paid. Done. ERRORS — the complete set agent-pay can return; anything else, show me verbatim: • 409 TX_PENDING → tx not indexed yet. Re-POST agent-pay with the SAME TX every ~2s, up to ~10 tries. (MegaETH mines in milliseconds; more than one retry is rare.) • 409 INTENT_EXPIRED → >30 min passed since P2. POST payment-intent again, re-run the P3 guard, then re-POST agent-pay with the SAME TX. Do NOT transfer again. • 409 INVALID_STATE → order isn't payable; if its status is "paid", that IS success — report it. • 409 NO_INTENT → you skipped P2; create the intent, then retry. • 409 TX_REVERTED / TRANSFER_NOT_FOUND / TX_REUSED / WRONG_CHAIN / NOT_CONFIRMED → the on-chain tx doesn't match the intent. STOP and show me the code. NEVER send a second transfer to "fix" a failed verification. • draft 404 VARIANT_NOT_FOUND → that size isn't available (sold out or removed). Tell me what's in stock per B1, ask again. • draft 409 SOLD_OUT → the drop sold out (or quantity > remaining). Tell me "Sold out — drop #2 coming soon", offer the waitlist (POST /api/waitlist { email, source: "agent" } with my consent), and stop. • draft 409 ALREADY_PURCHASED → this wallet already bought one (limit 1 per wallet). Tell me I've already purchased, and stop — do not retry or switch wallets to get around it. • draft/payment-intent 409 CHECKOUT_IN_PROGRESS → this wallet already has an unfinished checkout (a live payment intent on another order). Don't start a parallel one: finish that payment, or wait for its ~30-min intent TTL to lapse, then retry. • draft 403 COUNTRY_NOT_SUPPORTED → the shipping country is a restricted/ sanctioned destination we can't ship to. Tell me, ask for a different shipping country, and re-draft with it. Never switch addresses to mask the country or bypass this gate. • draft 400 PHONE_REQUIRED → the Conviction round needs a phone number and the draft had none. Ask me for one, then re-draft with the phone field set. • 401 SESSION_REQUIRED → session missing/expired. Re-run B4 (try POST /api/sessions, sign the challenge if it returns SIGNATURE_REQUIRED) and retry the failed call once with the new Bearer. • login says "Wallet already connected to 0x…" → good; skip login, continue. • create-key cancelled/not approved → I declined; re-explain the scope in one line and re-run create-key once. • create-key "authorized wallet account does not match" → run whoami, ask me to switch the browser wallet to that account, retry. • transfer fails "insufficient spend" → the cap is below price+fee. Re-run create-key with TOTAL bumped to cover it (one tap), then retry transfer. • transfer fails insufficient USDm balance → run `mega moss fund` (opens my deposit page), ask me to top up, then retry. INSTALL — only if `mega` is not found: the CLI is public (github.com/megaeth-labs/wallet-cli). Install the latest release (needs Node >=22; downloads the release tarball, verifies its checksum, installs the `mega` wrapper + bundled agent skill): curl -fsSL https://account.megaeth.com/install | sh If that URL is dead or returns HTML instead of a shell script, use the same script straight from the repo: curl -fsSL https://raw.githubusercontent.com/megaeth-labs/wallet-cli/main/scripts/install-release.sh | sh The CLI defaults its wallet URL to https://account.megaeth.com — do NOT pass --default-wallet-url. Ensure ~/.local/bin is on PATH, re-run `mega moss --help`, then continue at PHASE B. If both installs fail, tell me the CLI couldn't be installed and stop — don't try to work around it.