← Ethereum (ethskills)CONTENT HISTORY
WHAT CHANGED
Update to Ethereum (ethskills)
Snapshot Oct 24, 2026 · 13:33 UTC · version 0.1.1
Collection source: downloaded plugin package.
First saved snapshot
No earlier snapshot is available to establish a change.
Save Ethereum (ethskills) and check future changes in Following.
Up to 10 plugins free · no card required.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"description": "The complete build-to-production pipeline for Ethereum dApps. Fork mode setup, IPFS deployment, Vercel config, ENS subdomain setup, and the full production checklist. Built around Scaffold-ETH 2 but applicable to any Ethereum frontend project. Use when deploying any dApp to production.",
"included_files": [],
"name": "frontend-playbook",
"skill_md_contents": "---\nname: frontend-playbook\ndescription: The complete build-to-production pipeline for Ethereum dApps. Fork mode setup, IPFS deployment, Vercel config, ENS subdomain setup, and the full production checklist. Built around Scaffold-ETH 2 but applicable to any Ethereum frontend project. Use when deploying any dApp to production.\n---\n\n# Frontend Playbook\n\n## What You Probably Got Wrong\n\n**\"I'll use `yarn chain`.\"** Wrong. `yarn chain` gives you an empty local chain with no protocols, no tokens, no state. `yarn fork --network base` gives you a copy of real Base with Uniswap, Aave, USDC, real whale balances — everything (verified addresses: `addresses/SKILL.md`). Always fork.\n\n**\"I deployed to IPFS and it works.\"** Did the CID change? If not, you deployed stale output. Did routes work? Without `trailingSlash: true`, every route except `/` returns 404. Did you check the OG image? Without `NEXT_PUBLIC_PRODUCTION_URL`, it points to `localhost:3000`.\n\n**\"I'll set up the project manually.\"** Don't. `npx create-eth@latest` handles everything — Foundry, Next.js, RainbowKit, scaffold hooks. Never run `forge init` or create Next.js projects from scratch.\n\n---\n\n## Fork Mode Setup\n\n### Why Fork, Not Chain\n\n```\nyarn chain (WRONG) yarn fork --network base (CORRECT)\n└─ Empty local chain └─ Fork of real Base mainnet\n└─ No protocols └─ Uniswap, Aave, etc. available\n└─ No tokens └─ Real USDC, WETH exist\n└─ Testing in isolation └─ Test against REAL state\n```\n\n### Setup\n\n```bash\nnpx create-eth@latest # Select: foundry, target chain, name\ncd <project-name>\nyarn install\nyarn fork --network base # Terminal 1: fork of real Base\nyarn deploy # Terminal 2: deploy contracts to fork\nyarn start # Terminal 3: Next.js frontend\n```\n\n### Critical: Chain ID Gotcha\n\n**When using fork mode, the frontend target network MUST be `chains.foundry` (chain ID 31337), NOT the chain you're forking.**\n\nThe fork runs locally on Anvil with chain ID 31337. Even if you're forking Base:\n\n```typescript\n// scaffold.config.ts during development\ntargetNetworks: [chains.foundry], // ✅ NOT chains.base!\n```\n\nOnly switch to `chains.base` when deploying contracts to the REAL network.\n\n### Enable Block Mining\n\n```bash\n# In a new terminal — REQUIRED for time-dependent logic\ncast rpc anvil_setIntervalMining 1\n```\n\nWithout this, `block.timestamp` stays FROZEN. Any contract logic using timestamps (deadlines, expiry, vesting) will break silently.\n\n**Make it permanent** by editing `packages/foundry/package.json` to add `--block-time 1` to the fork script.\n\n---\n\n## Deploying to IPFS (Recommended)\n\nIPFS is the recommended deploy path for SE2. Avoids Vercel's memory limits entirely. Produces a fully decentralized static site.\n\n### Full Build Command\n\n```bash\ncd packages/nextjs\nrm -rf .next out # ALWAYS clean first\n\nNEXT_PUBLIC_PRODUCTION_URL=\"https://yourapp.yourname.eth.link\" \\\n NODE_OPTIONS=\"--require ./polyfill-localstorage.cjs\" \\\n NEXT_PUBLIC_IPFS_BUILD=true \\\n NEXT_PUBLIC_IGNORE_BUILD_ERROR=true \\\n yarn build\n\n# Upload to BuidlGuidl IPFS\nyarn bgipfs upload out\n# Save the CID!\n```\n\n### Node 25+ localStorage Polyfill (REQUIRED)\n\nNode.js 25+ ships a built-in `localStorage` object that's MISSING standard WebStorage API methods (`getItem`, `setItem`). This breaks `next-themes`, RainbowKit, and any library that calls `localStorage.getItem()` during static page generation.\n\n**Error you'll see:**\n```\nTypeError: localStorage.getItem is not a function\nError occurred prerendering page \"/_not-found\"\n```\n\n**The fix:** Create `polyfill-localstorage.cjs` in `packages/nextjs/`:\n```javascript\nif (typeof globalThis.localStorage !== \"undefined\" &&\n typeof globalThis.localStorage.getItem !== \"function\") {\n const store = new Map();\n globalThis.localStorage = {\n getItem: (key) => store.get(key) ?? null,\n setItem: (key, value) => store.set(key, String(value)),\n removeItem: (key) => store.delete(key),\n clear: () => store.clear(),\n key: (index) => [...store.keys()][index] ?? null,\n get length() { return store.size; },\n };\n}\n```\n\n**Why `--require` and not `instrumentation.ts`?** Next.js spawns a separate build worker process for prerendering. `--require` injects into EVERY Node process (including workers). `next.config.ts` polyfill only runs in the main process. `instrumentation.ts` doesn't run in the build worker. Only `--require` works.\n\n### IPFS Routing — Why Routes Break\n\nIPFS gateways serve static files. No server handles routing. Three things MUST be true:\n\n**1. `output: \"export\"` in next.config.ts** — generates static HTML files.\n\n**2. `trailingSlash: true` (CRITICAL)** — This is the #1 reason routes break:\n- `trailingSlash: false` (default) → generates `debug.html`\n- `trailingSlash: true` → generates `debug/index.html`\n- IPFS gateways resolve directories to `index.html` automatically, but NOT bare filenames\n- Without trailing slash: `/debug` → 404 ❌\n- With trailing slash: `/debug` → `debug/` → `debug/index.html` ✅\n\n**3. Pages must survive static prerendering** — any page that crashes during `yarn build` (browser APIs at import time, localStorage) gets skipped silently → 404 on IPFS.\n\n**The complete IPFS-safe next.config.ts pattern:**\n```typescript\nconst isIpfs = process.env.NEXT_PUBLIC_IPFS_BUILD === \"true\";\nif (isIpfs) {\n nextConfig.output = \"export\";\n nextConfig.trailingSlash = true;\n nextConfig.images = { unoptimized: true };\n}\n```\n\n**SE2's block explorer pages** use `localStorage` at import time and crash during static export. Rename `app/blockexplorer` to `app/_blockexplorer-disabled` if not needed.\n\n### Stale Build Detection\n\n**The #1 IPFS footgun:** You edit code, then deploy the OLD build.\n\n```bash\n# MANDATORY after ANY code change:\nrm -rf .next out # 1. Delete old artifacts\n# ... run full build command ... # 2. Rebuild from scratch\ngrep -l \"YOUR_STRING\" out/_next/static/chunks/app/*.js # 3. Verify changes present\n\n# Timestamp check:\nstat -f '%Sm' app/page.tsx # Source modified time\nstat -f '%Sm' out/ # Build output time\n# Source NEWER than out/ = STALE BUILD. Rebuild first!\n```\n\n**The CID is proof:** If the IPFS CID didn't change after a deploy, you deployed the same content. A real code change ALWAYS produces a new CID.\n\n### Verify Routes After Deploy\n\n```bash\nls out/*/index.html # Each route has a directory + index.html\ncurl -s -o /dev/null -w \"%{http_code}\" -L \"https://GATEWAY/ipfs/CID/debug/\"\n# Should return 200, not 404\n```\n\n---\n\n## Deploying to Vercel (Alternative)\n\nSE2 is a monorepo — Vercel needs special configuration.\n\n### Configuration\n\n1. **Root Directory:** `packages/nextjs`\n2. **Install Command:** `cd ../.. && yarn install`\n3. **Build Command:** leave default (`next build`)\n4. **Output Directory:** leave default (`.next`)\n\n```bash\n# Via API:\ncurl -X PATCH \"https://api.vercel.com/v9/projects/PROJECT_ID\" \\\n -H \"Authorization: Bearer $VERCEL_TOKEN\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"rootDirectory\": \"packages/nextjs\", \"installCommand\": \"cd ../.. && yarn install\"}'\n```\n\n### Common Failures\n\n| Error | Cause | Fix |\n|-------|-------|-----|\n| \"No Next.js version detected\" | Root Directory not set | Set to `packages/nextjs` |\n| \"cd packages/nextjs: No such file\" | Build command has `cd` | Clear it — root dir handles this |\n| OOM / exit code 129 | SE2 monorepo exceeds 8GB | Use IPFS instead, or `vercel --prebuilt` |\n\n### Decision Tree\n\n```\nWant to deploy SE2?\n├─ IPFS (recommended) → yarn ipfs / manual build + upload\n│ └─ Fully decentralized, no memory limits, works with ENS\n├─ Vercel → Set rootDirectory + installCommand\n│ └─ Fast CDN, but centralized. May OOM on large projects\n└─ vercel --prebuilt → Build locally, push artifacts to Vercel\n └─ Best of both: local build power + Vercel CDN\n```\n\n---\n\n## ENS Subdomain Setup\n\nTwo mainnet transactions to point an ENS subdomain at your IPFS deployment.\n\n### Transaction 1: Create Subdomain (new apps only)\n\n1. Open `https://app.ens.domains/yourname.eth`\n2. Go to \"Subnames\" tab → \"New subname\"\n3. Enter the label (e.g. `myapp`) → Next → Skip profile → Open Wallet → Confirm\n4. If gas is stuck: switch MetaMask to Ethereum → Activity tab → \"Speed up\"\n\n### Transaction 2: Set IPFS Content Hash\n\n1. Navigate to `https://app.ens.domains/myapp.yourname.eth`\n2. \"Records\" tab → \"Edit Records\" → \"Other\" tab\n3. Paste in Content Hash field: `ipfs://<CID>`\n4. Save → Open Wallet → Confirm in MetaMask\n\nFor **updates** to an existing app: skip Tx 1, only do Tx 2.\n\n### Verify\n\n```bash\n# 1. Onchain content hash matches\nRESOLVER=$(cast call 0x00000000000C2e074eC69A0dFb2997BA6C7d2e1e \\\n \"resolver(bytes32)(address)\" $(cast namehash myapp.yourname.eth) \\\n --rpc-url https://eth.llamarpc.com)\ncast call $RESOLVER \"contenthash(bytes32)(bytes)\" \\\n $(cast namehash myapp.yourname.eth) --rpc-url https://eth.llamarpc.com\n\n# 2. Gateway responds (may take 5-15 min for cache)\ncurl -s -o /dev/null -w \"%{http_code}\" -L \"https://myapp.yourname.eth.link\"\n\n# 3. OG metadata correct (not localhost)\ncurl -s -L \"https://myapp.yourname.eth.link\" | grep 'og:image'\n```\n\n**Use `.eth.link` NOT `.eth.limo`** — `.eth.link` works better on mobile.\n\n---\n\n## Go to Production — Complete Checklist\n\nWhen the user says \"ship it\", follow this EXACT sequence.\n\n### Step 1: Final Code Review 🤖\n- All feedback incorporated\n- No duplicate h1, no raw addresses, no shared isLoading\n- `scaffold.config.ts` has `rpcOverrides` and `pollingInterval: 3000`\n\n### Step 2: Choose Domain 👤\nAsk: *\"What subdomain do you want? e.g. `myapp.yourname.eth` → `myapp.yourname.eth.link`\"*\n\n### Step 3: Generate OG Image + Fix Metadata 🤖\n- Create 1200×630 PNG (`public/thumbnail.png`) — NOT the stock SE2 thumbnail\n- Set `NEXT_PUBLIC_PRODUCTION_URL` to the live domain\n- Verify `og:image` will resolve to an absolute production URL\n\n### Step 4: Clean Build + IPFS Deploy 🤖\n```bash\ncd packages/nextjs && rm -rf .next out\nNEXT_PUBLIC_PRODUCTION_URL=\"https://myapp.yourname.eth.link\" \\\n NODE_OPTIONS=\"--require ./polyfill-localstorage.cjs\" \\\n NEXT_PUBLIC_IPFS_BUILD=true NEXT_PUBLIC_IGNORE_BUILD_ERROR=true \\\n yarn build\n\n# Verify before uploading:\nls out/*/index.html # Routes exist\ngrep 'og:image' out/index.html # Not localhost\nstat -f '%Sm' app/page.tsx # Source older than out/\nstat -f '%Sm' out/\n\nyarn bgipfs upload out # Save the CID\n```\n\n### Step 5: Share for Approval 👤\nSend: *\"Build ready for review: `https://community.bgipfs.com/ipfs/<CID>`\"*\n**Wait for approval before touching ENS.**\n\n### Step 6: Set ENS 🤖\nCreate subdomain (if new) + set IPFS content hash. Two mainnet transactions.\n\n### Step 7: Verify 🤖\n- Content hash matches onchain\n- `.eth.link` gateway responds with 200\n- OG image loads correctly\n- Routes work (`/debug/`, etc.)\n\n### Step 8: Report 👤\n*\"Live at `https://myapp.yourname.eth.link` — ENS content hash confirmed onchain, unfurl metadata set.\"*\n\n---\n\n## Build Verification Process\n\nA build is NOT done when the code compiles. It's done when you've tested it like a real user.\n\n### Phase 1: Code QA (Automated)\n- Scan `.tsx` files for raw address strings (should use `<Address/>`)\n- Scan for shared `isLoading` state across multiple buttons\n- Scan for missing `disabled` props on transaction buttons\n- Verify RPC config and polling interval\n- Verify OG metadata with absolute URLs\n- Verify no public RPCs in any file\n\n### Phase 2: Smart Contract Testing\n```bash\nforge test # All tests pass\nforge test --fuzz-runs 10000 # Fuzz testing\n```\nTest edge cases: zero amounts, max amounts, unauthorized callers, reentrancy attempts.\n\n### Phase 3: Browser Testing (THE REAL TEST)\n\nOpen the app and do a FULL walkthrough:\n\n1. **Load the app** — does it render correctly?\n2. **Check page title** — is it correct, not \"Scaffold-ETH 2\"?\n3. **Connect wallet** — does the connect flow work?\n4. **Wrong network** — connect on wrong chain, verify \"Switch to Base\" appears\n5. **Switch network** — click the switch button, verify it works\n6. **Approve flow** — verify approve button shows, click it, wait for tx, verify action button appears\n7. **Main action** — click primary action, verify loader, wait for tx, verify state updates\n8. **Error handling** — reject a transaction in wallet, verify UI recovers\n9. **Address displays** — all addresses showing ENS/blockies, not raw hex?\n10. **Share URL** — check OG unfurl (image, title, description)\n\n### Phase 4: QA Sub-Agent (Complex Builds)\nFor bigger projects, spawn a sub-agent with fresh context. Give it the repo path and deployed URL. It reads all code against the UX rules, opens a browser, clicks through independently, and reports issues.\n\n---\n\n## Don't Do These\n\n- ❌ `yarn chain` — use `yarn fork --network <chain>`\n- ❌ `forge init` — use `npx create-eth@latest`\n- ❌ Manual Next.js setup — SE2 handles it\n- ❌ Manual wallet connection — SE2 has RainbowKit pre-configured\n- ❌ Edit `deployedContracts.ts` — it's auto-generated by `yarn deploy`\n- ❌ Hardcode API keys in `scaffold.config.ts` — use `.env.local`\n- ❌ Use `mainnet.base.org` in production — use Alchemy or similar\n\n---\n\n## Resources\n\n- **SE2 Docs:** https://docs.scaffoldeth.io/\n- **UI Components:** https://ui.scaffoldeth.io/\n- **SpeedRun Ethereum:** https://speedrunethereum.com/\n- **ETH Tech Tree:** https://www.ethtechtree.com\n- **BuidlGuidl IPFS:** https://upload.bgipfs.com\n"
}SHA-256 of public snapshot: 9253223ba2437e1c05102399eec0c146f993cfd390609f1bd295f54cc6caa16a