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
35 changes: 33 additions & 2 deletions .claude/prompts/analyze-hook.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,38 @@ Cross-reference the address-derived flags with the source code:

4. **Detect `requiresCustomSwapData`**: This is `true` if a normal swap (sending empty `hookData`) would **fail, revert, or produce materially incorrect behavior** because the hook requires specific encoded data (signatures, parameters, routing info, etc.) in `hookData`. If the hook merely inspects `hookData` for optional/ancillary features (e.g. an optional trade referrer via `if (hookData.length > 0)`) but swaps work correctly without it, this is `false`. In short: would an unsuspecting router or user sending no `hookData` have a bad experience?

5. **Generate name**: Use `ContractName` from the Etherscan response if the submitter didn't provide one.
5. **Detect `vanillaSwap`**: Determines whether, once a swap is allowed to execute, it behaves identically to a standard Uniswap v4 pool with no hook. Use this decision process:

6. **Generate description**: Write a 1-2 sentence summary of what the hook does, based on your analysis of the source code.
**Always `true` if:** the hook has no swap flags at all (`beforeSwap`, `afterSwap`, `beforeSwapReturnsDelta`, `afterSwapReturnsDelta` are all `false`).

**Always `false` if ANY of these are true:**
- `dynamicFee` is `true` (hook modifies fees)
- `requiresCustomSwapData` is `true` (standard swap with empty hookData would fail)
- `beforeSwapReturnsDelta` or `afterSwapReturnsDelta` is `true` (hook modifies swap amounts)
- The hook executes nested swaps, transfers tokens, or calls `poolManager.swap()` inside `beforeSwap`/`afterSwap`
- The hook modifies pool state in ways that change subsequent swap behavior (e.g., adjusting tick spacing, moving liquidity)

**`true` if the hook has `beforeSwap`/`afterSwap` but they ONLY do:**
- Access control: revert if caller/timing/state doesn't meet criteria (allow/deny gating)
- Observation: recording prices, ticks, volumes, or timestamps for oracle/analytics purposes
- Event emission: emitting events for off-chain indexing
- Reading state without modifying it

**Key distinction:** A hook that *blocks* a swap (reverts in beforeSwap) is vanilla — the swap either doesn't happen or happens normally. A hook that *changes* how the swap executes is NOT vanilla.

6. **Detect `swapAccess`**: Classify the hook's swap access control mechanism by searching the `beforeSwap` implementation:

- `"none"` — No access control logic in beforeSwap. The hook either has no beforeSwap, or beforeSwap never reverts based on caller identity, timing, or external state. Default for most hooks.
- `"temporal"` — Swaps gated by time. Look for: `block.timestamp` or `block.number` comparisons, `require(block.timestamp >= startTime)`, configurable start/end times, or phase-based timing logic.
- `"allowlist"` — Only approved addresses can swap. Look for: `mapping(address => bool)` checks against `tx.origin` or `sender`, calls to external allowlist/registry contracts, Merkle proof verification, or KYC/Predicate authorization checks.
- `"governance"` — An admin/owner must flip a flag to enable swaps. Look for: boolean storage like `migrated`, `tradingEnabled`, or `launched` that is set by an owner/admin function, with beforeSwap checking `require(migrated)` or similar. Includes single-owner gates, multi-sig gates, and role-based access control.
- `"other"` — Some other mechanism not covered above (e.g., NFT-gated, token-balance-gated, signature-based).

**Important:** A hook can be `vanillaSwap: true` with any `swapAccess` value — these are orthogonal. Access control determines *if* you can swap; vanillaSwap determines *how* the swap behaves once allowed. If the hook has no swap flags, `swapAccess` must be `"none"`.

7. **Generate name**: Use `ContractName` from the Etherscan response if the submitter didn't provide one.

8. **Generate description**: Write a 1-2 sentence summary of what the hook does, based on your analysis of the source code.

## Step 6: Generate the Hook JSON

Expand Down Expand Up @@ -184,6 +213,8 @@ The PR body should contain:
| dynamicFee | true/false |
| upgradeable | true/false |
| requiresCustomSwapData | true/false |
| vanillaSwap | true/false |
| swapAccess | none/temporal/allowlist/governance/other |

## Warnings
<any discrepancies or notes, or "None">
Expand Down
90 changes: 90 additions & 0 deletions .claude/prompts/review-hook.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Hooklist — PR Review Instructions

You are reviewing a PR that adds or modifies a Uniswap v4 hook file. Your job is to verify the hook metadata is correct by fetching the on-chain source code and cross-referencing it.

## Step 1: Identify Changed Hook Files

Find which `hooks/<chain>/<address>.json` files were added or modified in this PR.

## Step 2: For Each Hook File

### 2a: Verify the Address Flags

Decode the lowest 14 bits of the hook address and confirm the `flags` section matches. The `validate.yml` workflow already checks this, but confirm it in your review.

| Bit | Flag |
|-----|------|
| 13 | beforeInitialize |
| 12 | afterInitialize |
| 11 | beforeAddLiquidity |
| 10 | afterAddLiquidity |
| 9 | beforeRemoveLiquidity |
| 8 | afterRemoveLiquidity |
| 7 | beforeSwap |
| 6 | afterSwap |
| 5 | beforeDonate |
| 4 | afterDonate |
| 3 | beforeSwapReturnsDelta |
| 2 | afterSwapReturnsDelta |
| 1 | afterAddLiquidityReturnsDelta |
| 0 | afterRemoveLiquidityReturnsDelta |

### 2b: Fetch and Analyze Source Code

Look up the chain in `chains.json` to get the `chainId`. Fetch verified source:

```bash
curl -s "https://api.etherscan.io/v2/api?chainid=CHAIN_ID&module=contract&action=getsourcecode&address=ADDRESS&apikey=$ETHERSCAN_API_KEY" -o etherscan_response.json
```

For Blockscout chains (zora, ink, soneium) and Routescan chains (avalanche), use the `explorerUrl` from `chains.json` instead (no API key needed).

Parse the response:
```bash
python3 scripts/parse_etherscan.py etherscan_response.json
```

Then use `Grep` to search `.sources/` for relevant patterns.

### 2c: Verify Properties

Cross-reference the `properties` section against the source code:

1. **dynamicFee**: Should be `true` if `beforeSwap` returns a fee override via `lpFeeOverride`, or if the hook calls `poolManager.updateDynamicLPFee()`.

2. **upgradeable**: Should be `true` if the contract uses proxy patterns, `delegatecall`, mutable implementation storage, or `SELFDESTRUCT`.

3. **requiresCustomSwapData**: Should be `true` if a normal swap with empty `hookData` would **fail, revert, or produce materially incorrect behavior** — i.e. the hook requires specific encoded data (signatures, parameters, routing info, etc.) to function. Should be `false` if swaps work correctly without `hookData`, even if the hook optionally inspects it for ancillary features (e.g. an optional trade referrer).

4. **vanillaSwap**: Verify this answers: "Once a swap is allowed to execute, does it behave identically to a standard v4 pool?"

**Must be `false` if ANY of:** `dynamicFee` is true, `requiresCustomSwapData` is true, `beforeSwapReturnsDelta` or `afterSwapReturnsDelta` is true, the hook executes nested swaps or transfers tokens inside beforeSwap/afterSwap, or the hook modifies pool state that changes swap behavior.

**Must be `true` if:** the hook has no swap flags at all.

**Can be `true` if:** the hook has beforeSwap/afterSwap but they only perform access control (revert-based gating), observation (recording prices/ticks/volumes), or event emission — without modifying how the swap executes.

A hook that *blocks* swaps (reverts) is vanilla. A hook that *changes* how swaps execute is not.

5. **swapAccess**: Verify the classification matches the actual access control mechanism in beforeSwap:
- `"none"` — beforeSwap has no access control, or the hook has no swap flags
- `"temporal"` — gates on `block.timestamp` or `block.number` (configurable start/end times)
- `"allowlist"` — checks caller against an approved address set, registry, or Merkle proof
- `"governance"` — checks a boolean flag (e.g., `migrated`, `tradingEnabled`) set by an owner/admin
- `"other"` — any other gating mechanism

These are orthogonal to `vanillaSwap` — a hook can be vanilla with restricted access.

### 2d: Check Metadata

- `verifiedSource` should be `true` if Etherscan has verified source code
- `name` should match `ContractName` from Etherscan (or be a reasonable override)
- `description` should accurately describe what the hook does
- `chainId` should match the chain in `chains.json`

## Step 3: Output Your Review

Provide your findings as structured JSON. The workflow will post the review for you.

- If everything checks out, set `outcome` to `"APPROVE"` and summarize your verification in `review_body`.
- If there are issues, set `outcome` to `"REQUEST_CHANGES"` and explain in `review_body` what's wrong and what the correct values should be.
Loading
Loading