qa
Pre-ship audit checklist for Ethereum dApps built with Scaffold-ETH 2. Give this to a separate reviewer agent (or fresh context) AFTER the build is complete. Use this skill whenever you are finalizing a dApp built with Scaffold-ETH 2.
What this skill does
# dApp QA β Pre-Ship Audit For Scaffold-ETH 2 Builds
## What You Probably Got Wrong
**"The app deployed, so we are done."** For SE2 builds, shipping includes UX correctness, metadata, RPC reliability, contract verification, and branding cleanup.
**"The flow is obvious."** If Connect, Network, Approve, and Action are not strictly one-at-a-time with proper pending states, users will make duplicate or failing transactions.
**"SE2 defaults are fine in production."** Default README/footer/title/favicon and default RPC fallbacks are template scaffolding, not production decisions.
**"Pass means no console errors."** QA pass/fail here is behavioral and user-facing: real wallet flow, mobile deep-link behavior, readable errors, and trust signals must be validated.
Give this to a fresh agent after the dApp is built. The reviewer should:
1. Read the source code (`app/`, `components/`, `contracts/`)
2. Open the app in a browser and click through every flow
3. Check every item below β report PASS/FAIL, don't fix
---
## π¨ Critical: Wallet Flow β Button Not Text
Open the app with NO wallet connected.
- β **FAIL:** Text saying "Connect your wallet to play" / "Please connect to continue" / any paragraph telling the user to connect
- β
**PASS:** A big, obvious Connect Wallet **button** is the primary UI element
**This is the most common AI agent mistake.** Every stock LLM writes a `<p>Please connect your wallet</p>` instead of rendering `<RainbowKitCustomConnectButton />`.
---
## π¨ Critical: Four-State Button Flow
The app must show exactly ONE primary button at a time, progressing through:
```
1. Not connected β Connect Wallet button
2. Wrong network β Switch to [Chain] button
3. Needs approval β Approve button
4. Ready β Action button (Stake/Deposit/Swap)
```
Check specifically:
- β **FAIL:** Approve and Action buttons both visible simultaneously
- β **FAIL:** No network check β app tries to work on wrong chain and fails silently
- β **FAIL:** Main onchain CTA renders instead of a "Switch to [Chain]" button when the connected wallet is on the wrong network. SE-2's header `WrongNetworkDropdown` is **not sufficient** β the action button itself must become the switch CTA, or the user clicks Sign/Stake/Deposit on the wrong chain and eats a silent wagmi error.
- β **FAIL:** User can click Approve, sign in wallet, come back, and click Approve again while tx is pending
- β
**PASS:** One button at a time. Approve button shows spinner, stays disabled until block confirms onchain. Then switches to the action button.
- β
**PASS:** Action button's render path branches on `useChainId() === targetNetwork.id` (or equivalent); mismatch renders a `useSwitchChain`-driven "Switch to [Chain]" button in the **same slot** as the primary CTA.
**In the code:** the button's `disabled` prop must be tied to `isPending` from `useScaffoldWriteContract`. Verify it uses `useScaffoldWriteContract` (waits for block confirmation), NOT raw wagmi `useWriteContract` (resolves on wallet signature):
```
grep -rn "useWriteContract" packages/nextjs/
```
Any match outside scaffold-eth internals β bug.
**Watch out: two gaps, both allow double-approve.**
`isPending` from wagmi drops to `false` when the wallet returns the tx hash β not when the tx confirms. `writeContractAsync` is still awaiting confirmation. During that window `isPending = false` AND `approveCooldown = false` β button re-enables mid-flight.
Fix requires TWO states:
- `approvalSubmitting` β set at top of handler, cleared in `finally {}` (covers clickβhash gap)
- `approveCooldown` β set after `await` resolves, cleared after 4s + refetch (covers confirmβcache gap)
```tsx
const [approvalSubmitting, setApprovalSubmitting] = useState(false);
const [approveCooldown, setApproveCooldown] = useState(false);
const handleApprove = async () => {
if (approvalSubmitting || approveCooldown) return;
setApprovalSubmitting(true);
try {
await approveWrite({ functionName: "approve", args: [spender, amount] });
setApproveCooldown(true);
setTimeout(() => { setApproveCooldown(false); refetchAllowance(); }, 4000);
} catch (e) {
notifyError("Approval failed");
} finally {
setApprovalSubmitting(false); // must be finally β releases on rejection too
}
};
<button disabled={isPending || approvalSubmitting || approveCooldown}>
```
- β **FAIL:** Button `disabled` only reads `isPending` or only `approveCooldown`
- β **FAIL:** No `approvalSubmitting` state, or it's not cleared in `finally {}`
- β
**PASS:** `disabled={isPending || approvalSubmitting || approveCooldown}` with both states managed correctly
---
## π¨ Critical: SE2 Branding Removal
AI agents treat the scaffold as sacred and leave all default branding in place.
- [ ] **Footer:** Remove BuidlGuidl links, "Built with ποΈ SE2", "Fork me" link, support links. Replace with project's own repo link or clean it out
- [ ] **Tab title:** Must be the app name, NOT "Scaffold-ETH 2" or "SE-2 App" or "App Name | Scaffold-ETH 2"
- [ ] **README:** Must describe THIS project. Not the SE2 template README. Remove "Built with Scaffold-ETH 2" sections and SE2 doc links
- [ ] **Favicon:** Must not be the SE2 default
---
## Important: Contract Address Display
- β **FAIL:** The deployed contract address appears nowhere on the page
- β
**PASS:** Contract address displayed using `<Address/>` component (blockie, ENS, copy, explorer link)
Agents display the connected wallet address but forget to show the contract the user is interacting with.
---
## Important: Address Input β Always `<AddressInput/>`
**EVERY input that accepts an Ethereum address must use `<AddressInput/>`, not a plain `<input type="text">`.**
- β **FAIL:** `<input type="text" placeholder="0x..." value={addr} onChange={e => setAddr(e.target.value)} />`
- β
**PASS:** `<AddressInput value={addr} onChange={setAddr} placeholder="0x... or ENS name" />`
`<AddressInput/>` gives you ENS resolution (type "vitalik.eth" β resolves to address), blockie avatar preview, validation, and paste handling. A raw text input is unacceptable for address collection.
**In SE2, it's in `@scaffold-ui/components`:**
```typescript
import { AddressInput } from "@scaffold-ui/components";
// or
import { AddressInput } from "~~/components/scaffold-eth"; // if re-exported
```
**Quick check:**
```bash
grep -rn 'type="text"' packages/nextjs/app/ | grep -i "addr\|owner\|recip\|0x"
grep -rn 'placeholder="0x' packages/nextjs/app/
```
Any match β **FAIL**. Replace with `<AddressInput/>`.
The pair: `<Address/>` for **display**, `<AddressInput/>` for **input**. Always.
---
## Important: USD Values
- β **FAIL:** Token amounts shown as "1,000 TOKEN" or "0.5 ETH" with no dollar value
- β
**PASS:** "0.5 ETH (~$1,250)" with USD conversion
Agents never add USD values unprompted. Check every place a token or ETH amount is displayed, including inputs.
---
## Important: OG Image Must Be Absolute URL
- β **FAIL:** `images: ["/thumbnail.jpg"]` β relative path, breaks unfurling everywhere
- β
**PASS:** `images: ["https://yourdomain.com/thumbnail.jpg"]` β absolute production URL
Quick check:
```
grep -n "og:image\|images:" packages/nextjs/app/layout.tsx
```
---
## Important: RPC & Polling Config
Open `packages/nextjs/scaffold.config.ts`:
- β **FAIL:** `pollingInterval: 30000` (default β makes the UI feel broken, 30 second update lag)
- β
**PASS:** `pollingInterval: 3000`
- β **FAIL:** Using default Alchemy API key that ships with SE2
- β **FAIL:** Code references `process.env.NEXT_PUBLIC_*` but the variable isn't actually set in the deployment environment (Vercel/hosting). Falls back to public RPC like `mainnet.base.org` which is rate-limited
- β
**PASS:** `rpcOverrides` uses `process.env.NEXT_PUBLIC_*` variables AND the env var is confirmed set on the hosting platform
- β **FAIL:** `services/web3/wagmiConfig.tsx` still includes bare `http()` fallback transport (silently hits public RPCs in parallel, causing rate limits)
- β
**PASRelated in AI Agents
skill-development
IncludedComprehensive meta-skill for creating, managing, validating, auditing, and distributing Claude Code skills and slash commands (unified in v2.1.3+). Provides skill templates, creation workflows, validation patterns, audit checklists, naming conventions, YAML frontmatter guidance, progressive disclosure examples, and best practices lookup. Use when creating new skills, validating existing skills, auditing skill quality, understanding skill architecture, needing skill templates, learning about YAML frontmatter requirements, progressive disclosure patterns, tool restrictions (allowed-tools), skill composition, skill naming conventions, troubleshooting skill activation issues, creating custom slash commands, configuring command frontmatter, using command arguments ($ARGUMENTS, $1, $2), bash execution in commands, file references in commands, command namespacing, plugin commands, MCP slash commands, Skill tool configuration, or deciding between skills vs slash commands. Delegates to docs-management skill for official documentation.
reprompter
IncludedTransform messy prompts into well-structured, effective prompts β single or multi-agent. Use when: "reprompt", "reprompt this", "clean up this prompt", "structure my prompt", rough text needing XML tags and best practices, "reprompter teams", "repromptception", "run with quality", "smart run", "smart agents", multi-agent tasks, audits, parallel work, anything going to agent teams. Don't use when: simple Q&A, pure chat, immediate execution-only tasks. See "Don't Use When" section for details. Outputs: Structured XML/Markdown prompt, quality score (before/after), optional team brief + per-agent sub-prompts, agent team output files. Success criteria: Single mode quality score β₯ 7/10; Repromptception per-agent prompt quality score 8+/10; all required sections present, actionable and specific.
adaptive-compaction
IncludedAdaptive add-on policy and recovery layer that decides WHEN to compact, prune, snapshot, or fork -- replacing fixed-percent auto-compaction across Claude Code, Codex, and MCP-capable hosts. Trigger on auto-compact timing or damage: "when should I compact", "is it safe to compact now or start a fresh session", "auto-compact fires too early/mid-task", "switching to an unrelated task but the window still has space", "context rot", "answers get worse the longer the session runs", "the agent forgot the plan or my decisions after it summarized", "add a layer on top that manages context without changing the agent", raising autoCompactWindow to give the policy room, or installing/tuning a cross-tool compaction policy or PreCompact hook -- even when "compaction" is never said but the problem is context-window pressure or post-summarization memory loss. Do NOT use to summarize a conversation, build RAG, write a summarization prompt (decides WHEN not HOW), or answer max-context-length trivia.
agent-skill-creator
IncludedCreate cross-platform agent skills from workflow descriptions. Activates when users ask to create an agent, automate a repetitive workflow, create a custom skill, or need advanced agent creation. Triggers on phrases like create agent for, automate workflow, create skill for, every day I have to, daily I need to, turn process into agent, need to automate, create a cross-platform skill, validate this skill, export this skill, migrate this skill. Supports single skills, multi-agent suites, transcript processing, template-based creation, interactive configuration, cross-platform export, and spec validation.
llm-wiki
IncludedUse when building or maintaining a persistent personal knowledge base (second brain) in Obsidian where an LLM incrementally ingests sources, updates entity/concept pages, maintains cross-references, and keeps a synthesis current. Triggers include "second brain", "Obsidian wiki", "personal knowledge management", "ingest this paper/article/book", "build a research wiki", "compound knowledge", "Memex", or whenever the user wants knowledge to accumulate across sessions instead of being re-derived by RAG on every query.
skill-master
IncludedAgent Skills authoring, evaluation, and optimization. Create, edit, validate, benchmark, and improve skills following the agentskills.io specification. Use when designing SKILL.md files, structuring skill folders (references, scripts, assets), ingesting external documentation into skills, running trigger evals, benchmarking skill quality, optimizing descriptions, or performing blind A/B comparisons. Keywords: agentskills.io, SKILL.md, skill authoring, eval, benchmark, trigger optimization.