Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 168 additions & 0 deletions .claude/agents/security-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
---
description: Review Solidity contracts for security vulnerabilities, incentive design, and OpenZeppelin best practices
---

# Security Reviewer

You are a Solidity security reviewer. Analyze smart contracts for vulnerabilities, incentive design issues, and adherence to OpenZeppelin best practices.

**Before reviewing any contract, always read the actual source files first.** Do not generate generic advice — base every finding on code you have read.

## Review Methodology

1. **Read before reviewing:** Read the project's contracts first. Understand existing imports, inheritance chains, and how contracts interact before flagging anything
2. **Library-first rule:** Before flagging missing logic, check if an OpenZeppelin component already handles it. Never recommend custom code when OZ has a solution
3. **Version awareness:** Do not assume override points from prior knowledge — verify by reading the installed OZ source in `node_modules/@openzeppelin/contracts/`. Functions that were `virtual` in v4 may not be in v5
4. **Pattern discovery:** Check `node_modules/@openzeppelin/contracts/` directory structure for available components before suggesting implementations

## Security Checklist

### Access Control

- Verify all state-changing functions have appropriate access modifiers (`onlyOwner`, etc.)
- Check that `Ownable` constructor receives `initialOwner` parameter (OpenZeppelin v5)
- Ensure no unprotected `selfdestruct` or `delegatecall`

### Reentrancy

- Check for external calls before state changes (checks-effects-interactions pattern)
- Verify `ReentrancyGuard` is used where needed
- Look for cross-function reentrancy risks

### Token Standards

- **ERC20:** Verify `_update` override resolves diamond inheritance correctly, check for approve race condition mitigations
- **ERC721:** Verify `_update` and `_increaseBalance` overrides, check `tokenURI` implementation
- **ERC1155:** Verify `_update` override, check `uri` implementation, validate batch operations

### Integer Safety

- Solidity 0.8.x has built-in overflow checks, but verify `unchecked` blocks are safe
- Check for division by zero scenarios

### Token Decimals & Precision

- Do not hardcode 18 decimals — USDC has 6, WBTC has 8. Check all decimal assumptions
- Multiply before dividing to prevent truncation (e.g., `(a * PRECISION) / b` not `(a / b) * PRECISION`)
- Flag any hardcoded decimal values or assumptions about token precision

### SafeERC20

- Verify all external token interactions use `SafeERC20` wrapper (some tokens like USDT don't return bool on `transfer`)
- Check that `safeTransfer`, `safeTransferFrom`, and `safeApprove` are used instead of raw calls
- Verify `using SafeERC20 for IERC20;` declaration is present when interacting with arbitrary tokens

### Oracle Security

- Never use DEX spot prices as oracle — flag `getReserves()` or similar on-chain price queries
- Check for Chainlink oracle usage with staleness validation (`updatedAt` check against a threshold)
- Flag any price source that is flash-loan-manipulable (single-block TWAP, spot AMM prices)

### Vault / Share Inflation

- Check share-based contracts (ERC4626 vaults, staking pools) for first-depositor inflation attacks
- Recommend virtual offset pattern or minimum deposit for vault-style contracts
- Verify share calculation cannot be manipulated by donating tokens directly to the contract

### Input Validation

- Zero address checks on constructor parameters and function arguments that set addresses
- Zero amount checks on transfers, mints, and deposits
- Bounds validation at system boundaries (max supply, max fee percentages, array length limits)

### Events

- Verify all state changes emit events for off-chain tracking
- Check that event parameters are indexed appropriately for filtering
- Flag state-changing functions that are missing event emissions

### Randomness

- Flag any use of `block.timestamp`, `blockhash(block.number)`, `block.prevrandao` as randomness sources — these are miner/validator-manipulable
- Recommend commit-reveal schemes or Chainlink VRF for randomness
- Check that randomness-dependent logic cannot be front-run

### Gas Optimization

- Flag obviously wasteful patterns (unnecessary storage reads in loops, etc.)
- Note: do not over-optimize at the cost of readability

## Incentive & Architecture Review

### State Machine Analysis

- For every state transition, ask: Who calls this function? Why would they pay gas? Is the incentive sufficient?
- Map out all possible states and transitions — look for unreachable states or stuck conditions
- Verify that state transitions cannot be front-run or sandwiched in a harmful way

### Automation Assumptions

- Flag any design that assumes automatic execution — there are no cron jobs on-chain
- Check that time-dependent actions (liquidations, auctions, unlocks) have permissionless trigger functions
- Verify that callers of permissionless triggers have sufficient economic incentive (keeper rewards, MEV)

### Centralization Risks (CROPS Check)

- Flag single-key pause/freeze capabilities without timelock or multisig
- Identify admin-only state transitions with no fallback or escape hatch
- Check for operator dependencies — can the contract function if the team disappears?
- Note whether upgradeability patterns exist and whether they have appropriate safeguards

### Hyperstructure Test

- Note whether the contract requires ongoing operator involvement or can function autonomously
- Flag contracts that will break if a specific off-chain service goes offline
- Check for hardcoded addresses or endpoints that create single points of failure

## OpenZeppelin Integration Review

### Import Hygiene

- Verify contracts import from `@openzeppelin/contracts/`, never copy-pasted OZ source code
- Check for outdated import paths (v4 paths that changed in v5)

### Override Correctness

- Check that overrides match what the installed OZ version marks as `virtual` — read the actual source in `node_modules/@openzeppelin/contracts/`
- Verify `super` calls maintain the inheritance chain in all overrides
- Check C3 linearization order in multiple inheritance scenarios

### Constructor Patterns

- Confirm OZ v5 patterns: `Ownable(initialOwner)` not v4's `Ownable()` with implicit `msg.sender`
- Verify all parent constructors are called with correct arguments
- Check that constructor parameter validation happens before passing to parent constructors

### Component Completeness

- If a contract uses `Pausable`, verify all relevant state-changing functions are guarded with `whenNotPaused`
- If using `ERC20Burnable`, verify `_update` override includes it in the inheritance chain
- If using `AccessControl`, verify all roles are defined and granted appropriately
- Check that all inherited interfaces are fully implemented

## Pre-Deploy Checklist

Before recommending a contract as ready for deployment, verify:

- [ ] Access control on every privileged function
- [ ] All token interactions use SafeERC20 (if interacting with external tokens)
- [ ] All inputs validated (zero addresses, zero amounts, bounds)
- [ ] Events emitted for all state changes
- [ ] Edge cases tested including reentrancy attempts
- [ ] No hardcoded addresses that should be configurable
- [ ] Constructor parameters validated
- [ ] Remind: verify source code on block explorer post-deployment

## Output Format

For each contract reviewed, produce:

1. **Severity levels:** Critical / High / Medium / Low / Informational
2. **Finding format:**
- **Title:** Brief description
- **Severity:** Level
- **Location:** File and line number
- **Description:** What the issue is
- **Recommendation:** How to fix it

3. **Summary:** Overall assessment and list of findings by severity
39 changes: 39 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"permissions": {
"allow": [
"Bash(npm run test)",
"Bash(npm run compile)",
"Bash(npm run coverage)",
"Bash(npm run format:*)",
"Bash(npm run sol:format:*)",
"Bash(npm run lint:*)",
"Bash(npm run solhint)"
]
},
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true",
"description": "Auto-format edited files with Prettier"
}
]
}
],
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '^\\.env$|package-lock\\.json$'; then echo 'BLOCK: Do not edit .env or lock files' >&2; exit 1; fi",
"description": "Block edits to .env and lock files"
}
]
}
]
}
}
65 changes: 65 additions & 0 deletions .claude/skills/deploy-check/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
---
description: Pre-deployment checklist — verify contracts compile, tests pass, and deployment config is correct
user-invocable: true
disable-model-invocation: true
---

# /deploy-check

Run a pre-deployment checklist to verify everything is ready for deployment.

## Instructions

Perform each step in order and report results:

### 1. Compile Contracts

Run `npm run compile` and verify all contracts compile without errors or warnings.

### 2. Run Tests

Run `npm run test` and verify all tests pass.

### 3. Run Coverage

Run `npm run coverage` and report the coverage summary. Flag any contracts with low coverage.

### 4. Lint Checks

Run `npm run solhint` and `npm run lint:check` to verify no linting issues.

### 5. Format Check

Run `npm run format:check` and `npm run sol:format:check` to verify formatting is consistent.

### 6. Review Ignition Modules

Read each file in `ignition/modules/` and verify:

- All constructor parameters have sensible defaults
- Parameter names match what the contract expects
- Owner/deployer is set via `m.getAccount(0)`

### 7. Check Network Configuration

Read `hardhat.config.ts` and verify:

- Target network is configured
- Required environment variables are documented in `.env.example`

### 8. Summary Report

Output a summary table:

| Check | Status | Notes |
| ---------------- | --------- | ----------- |
| Compilation | PASS/FAIL | |
| Tests | PASS/FAIL | X/Y passing |
| Coverage | PASS/WARN | XX% |
| Solhint | PASS/FAIL | |
| ESLint | PASS/FAIL | |
| Formatting | PASS/FAIL | |
| Ignition Modules | PASS/WARN | |
| Network Config | PASS/WARN | |

Flag any FAIL or WARN items with recommended fixes.
50 changes: 50 additions & 0 deletions .claude/skills/new-contract/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
description: Scaffold a new Solidity contract with test, Ignition module, and tasks following project patterns
user-invocable: true
disable-model-invocation: true
---

# /new-contract

Scaffold a new Solidity contract following the project's existing patterns.

## Instructions

1. **Ask the user** for:
- Contract name (PascalCase, e.g., `MyToken`)
- Token standard (ERC20, ERC721, ERC1155, or custom)
- Features needed (Ownable, Pausable, Burnable, etc.)

2. **Create the contract** in `contracts/<ContractName>.sol`:
- Use `pragma solidity 0.8.28;`
- Import from `@openzeppelin/contracts/`
- Follow the patterns in existing contracts (e.g., `BasicERC20.sol`)
- Pass `initialOwner` to `Ownable` constructor (OpenZeppelin v5 pattern)
- Include SPDX-License-Identifier: MIT

3. **Create the test file** in `test/<ContractName>.ts`:
- Use the `setupFixture` + `loadFixture` pattern from existing tests
- Use top-level `await hre.network.connect()` for ethers/networkHelpers
- Test constructor parameters, core functionality, and access control
- Use `revertedWithCustomError` for OpenZeppelin error assertions

4. **Create the Ignition module** in `ignition/modules/<ContractName>Module.ts`:
- Follow `buildModule` pattern from existing modules
- Use `m.getParameter()` with sensible defaults
- Use `m.getAccount(0)` for owner/deployer
- Export as default

5. **Create task files** in `tasks/<token-type>/`:
- Use Hardhat v3 task API: `task().addOption().setInlineAction().build()`
- Include usage example in comment
- Export named const

6. **Register tasks** in `hardhat.config.ts`:
- Import the new task(s)
- Add to the `tasks` array

7. **Verify everything works:**
- Run `npm run compile` to verify the contract compiles
- Run `npm run test` to verify tests pass
- Run `npm run sol:format:write` to format the Solidity file
- Run `npm run format:write` to format TypeScript files
68 changes: 68 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# CLAUDE.md — Project Instructions

## Project Overview

Solidity/TypeScript Hardhat v3 template with ERC20, ERC721, and ERC1155 token contracts using OpenZeppelin v5 patterns.

## Key Commands

```bash
npm run compile # Compile Solidity contracts
npm run test # Run Mocha/Chai test suite
npm run coverage # Run tests with coverage report
npm run format:write # Format TypeScript/config files with Prettier
npm run sol:format:write # Format Solidity files with Prettier
npm run lint:fix # Fix ESLint issues
npm run solhint # Lint Solidity with Solhint
```

## Solidity Conventions

- **Solidity version:** `pragma solidity 0.8.28;` — use this exact version, not a range
- **OpenZeppelin v5:** Import from `@openzeppelin/contracts/` (v5.6.1)
- **Contract patterns:** Ownable + Pausable for access control; pass `initialOwner` to Ownable constructor
- **Naming:** PascalCase for contracts (e.g., `BasicERC20`), use SPDX license identifier `MIT`
- **Override pattern:** When inheriting multiple contracts with shared functions, use `override(Contract1, Contract2)` and call `super`

## Test Conventions

- **Framework:** Mocha + Chai with `expect` style assertions
- **Fixture pattern:** Each test file defines a `setupFixture` async function, used via `loadFixture(setupFixture)`
- **Hardhat setup:** Use top-level `await hre.network.connect()` to get `ethers` and `networkHelpers`
- **Test structure:** `describe` block per contract, nested `describe` for functionality groups
- **Assertions:** Use `revertedWithCustomError` for access control checks (OpenZeppelin v5 custom errors)
- **File naming:** Test file matches contract name (e.g., `BasicERC721.ts` tests `BasicERC721.sol`)

## Task Conventions

- Located in `tasks/` organized by token type (e.g., `tasks/erc20/`, `tasks/erc721/`)
- Use Hardhat v3 task API: `task().addOption().setInlineAction().build()`
- Export named const (e.g., `erc20MintTask`) and register in `hardhat.config.ts`
- Include usage example in JSDoc comment above the task

## Deployment Conventions

- **Hardhat Ignition** modules in `ignition/modules/`
- Module naming: `<ContractName>Module` (e.g., `BasicERC20Module`)
- Use `m.getParameter()` for configurable values with sensible defaults
- Use `m.getAccount(0)` for deployer/owner address
- Export module as default export

## File Structure

```
contracts/ # Solidity source files
test/ # Mocha test files (TypeScript)
tasks/ # Hardhat tasks organized by token type
ignition/modules/ # Hardhat Ignition deployment modules
types/ # TypeScript type definitions
```

## Important Rules

- **Never edit `.env`** — contains private keys/mnemonics. Use `.env.example` as reference
- **Never edit `package-lock.json`** — only changes via `npm install`
- **Never edit files in `artifacts/`, `cache/`, or `node_modules/`** — these are generated
- When adding a new contract, also create: test file, Ignition module, and relevant tasks
- Always run `npm run compile` after modifying Solidity files to verify they compile
- Always run `npm run test` after modifying tests or contracts
Loading