diff --git a/.claude/agents/security-reviewer.md b/.claude/agents/security-reviewer.md new file mode 100644 index 0000000..3868ae6 --- /dev/null +++ b/.claude/agents/security-reviewer.md @@ -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 diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..773b5b2 --- /dev/null +++ b/.claude/settings.json @@ -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" + } + ] + } + ] + } +} diff --git a/.claude/skills/deploy-check/SKILL.md b/.claude/skills/deploy-check/SKILL.md new file mode 100644 index 0000000..7b64491 --- /dev/null +++ b/.claude/skills/deploy-check/SKILL.md @@ -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. diff --git a/.claude/skills/new-contract/SKILL.md b/.claude/skills/new-contract/SKILL.md new file mode 100644 index 0000000..038abe1 --- /dev/null +++ b/.claude/skills/new-contract/SKILL.md @@ -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/.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/.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/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//`: + - 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 diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..ab922db --- /dev/null +++ b/CLAUDE.md @@ -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: `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 diff --git a/README.md b/README.md index 0724665..bf0a195 100644 --- a/README.md +++ b/README.md @@ -207,6 +207,40 @@ npm run sol:format:write npm run solhint ``` +--- + +## Claude Code + +This repo is configured for [Claude Code](https://github.com/anthropics/claude-code) with project conventions, automated agents, and skills. Claude follows the instructions in [`CLAUDE.md`](./CLAUDE.md) when working in this project. + +### Getting Started + +```shell +npm install -g @anthropic-ai/claude-code +claude +``` + +Run `claude` in the project root — it automatically reads `CLAUDE.md` for project conventions. + +### Available Skills (Slash Commands) + +| Command | Description | +| --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `/new-contract` | Scaffolds a new Solidity contract with test file, Ignition module, and Hardhat tasks. Asks for contract name, token standard, and features, then generates all files following project conventions. | +| `/deploy-check` | Runs a pre-deployment checklist: compile, test, coverage, lint, format check, Ignition module review, and network config verification. Outputs a PASS/FAIL/WARN summary table. | + +### Available Agents + +- **Security Reviewer** — Comprehensive security review agent that analyzes contracts for vulnerabilities, incentive design issues, and OpenZeppelin v5 best practices. Invoke with: + ```shell + claude "review BasicERC20.sol for security" --agent security-reviewer + ``` + +### Configured Hooks + +- **Auto-format on save** — Edited `.ts` and `.sol` files are automatically formatted with Prettier after each edit. +- **Protected files** — `.env` and `package-lock.json` are blocked from direct edits. +
## Contact Protokol