diff --git a/.github/workflows/regenerate.yml b/.github/workflows/regenerate.yml index ad36a5a4..5d0fccd9 100644 --- a/.github/workflows/regenerate.yml +++ b/.github/workflows/regenerate.yml @@ -44,6 +44,6 @@ jobs: git config user.name "hook-registry-bot[bot]" git config user.email "hook-registry-bot[bot]@users.noreply.github.com" git remote set-url origin "https://x-access-token:${APP_TOKEN}@github.com/${{ github.repository }}.git" - git add hooklist.json + git add hooklist.json hooklist-vanilla-swap.json git diff --staged --quiet || git commit -m "chore: regenerate hooklist.json" git push diff --git a/hooklist-vanilla-swap.json b/hooklist-vanilla-swap.json new file mode 100644 index 00000000..e9c05ced --- /dev/null +++ b/hooklist-vanilla-swap.json @@ -0,0 +1,101 @@ +[ + { + "hook": { + "address": "0xc5a48b447f01e9ce3ede71e4c1c2038c38bd9000", + "chain": "base", + "chainId": 8453, + "name": "Graduation Hook (Base)", + "description": "Restricts pool initialization to a designated Moxie bonding curve address, ensuring Uniswap v4 pools can only be initialized through the authorized bonding curve as part of a token graduation process.", + "deployer": "", + "verifiedSource": true, + "auditUrl": "" + }, + "flags": { + "beforeInitialize": false, + "afterInitialize": true, + "beforeAddLiquidity": false, + "afterAddLiquidity": false, + "beforeRemoveLiquidity": false, + "afterRemoveLiquidity": false, + "beforeSwap": false, + "afterSwap": false, + "beforeDonate": false, + "afterDonate": false, + "beforeSwapReturnsDelta": false, + "afterSwapReturnsDelta": false, + "afterAddLiquidityReturnsDelta": false, + "afterRemoveLiquidityReturnsDelta": false + }, + "properties": { + "dynamicFee": false, + "upgradeable": false, + "requiresCustomSwapData": false + } + }, + { + "hook": { + "address": "0xd3c1f2174f37f88811f99b1b1b4c1356c0246000", + "chain": "base", + "chainId": 8453, + "name": "Aquinas Hook (Base)", + "description": "Restricts Uniswap v4 pool initialization to factory-authorized Safe addresses for Aquinas DAOs, preventing frontrunning of LP initialization by requiring the caller to be pre-approved by the Aquinas factory.", + "deployer": "", + "verifiedSource": true, + "auditUrl": "" + }, + "flags": { + "beforeInitialize": true, + "afterInitialize": false, + "beforeAddLiquidity": false, + "afterAddLiquidity": false, + "beforeRemoveLiquidity": false, + "afterRemoveLiquidity": false, + "beforeSwap": false, + "afterSwap": false, + "beforeDonate": false, + "afterDonate": false, + "beforeSwapReturnsDelta": false, + "afterSwapReturnsDelta": false, + "afterAddLiquidityReturnsDelta": false, + "afterRemoveLiquidityReturnsDelta": false + }, + "properties": { + "dynamicFee": false, + "upgradeable": false, + "requiresCustomSwapData": false + } + }, + { + "hook": { + "address": "0xde400595199e6dae55a1bcb742b3eb249af00800", + "chain": "ethereum", + "chainId": 1, + "name": "M0 Tick Range Hook", + "description": "Restricts liquidity provision to a configurable tick range by reverting in beforeAddLiquidity if the position's ticks fall outside the allowed bounds. An authorized manager role can update the tick range.", + "deployer": "", + "verifiedSource": true, + "auditUrl": "" + }, + "flags": { + "beforeInitialize": false, + "afterInitialize": false, + "beforeAddLiquidity": true, + "afterAddLiquidity": false, + "beforeRemoveLiquidity": false, + "afterRemoveLiquidity": false, + "beforeSwap": false, + "afterSwap": false, + "beforeDonate": false, + "afterDonate": false, + "beforeSwapReturnsDelta": false, + "afterSwapReturnsDelta": false, + "afterAddLiquidityReturnsDelta": false, + "afterRemoveLiquidityReturnsDelta": false + }, + "properties": { + "dynamicFee": false, + "upgradeable": false, + "requiresCustomSwapData": false + } + } +] diff --git a/scripts/__pycache__/aggregate.cpython-312.pyc b/scripts/__pycache__/aggregate.cpython-312.pyc index ce127620..2094beb6 100644 Binary files a/scripts/__pycache__/aggregate.cpython-312.pyc and b/scripts/__pycache__/aggregate.cpython-312.pyc differ diff --git a/scripts/__pycache__/test_aggregate.cpython-312-pytest-8.3.5.pyc b/scripts/__pycache__/test_aggregate.cpython-312-pytest-8.3.5.pyc index 8e6b969e..17a5b203 100644 Binary files a/scripts/__pycache__/test_aggregate.cpython-312-pytest-8.3.5.pyc and b/scripts/__pycache__/test_aggregate.cpython-312-pytest-8.3.5.pyc differ diff --git a/scripts/aggregate.py b/scripts/aggregate.py index 34c6d5aa..990ec260 100644 --- a/scripts/aggregate.py +++ b/scripts/aggregate.py @@ -32,11 +32,20 @@ def aggregate_hooks(hooks_dir: str, schema: dict | None = None) -> list[dict]: return hooks +SWAP_FLAGS = ("beforeSwap", "afterSwap", "beforeSwapReturnsDelta", "afterSwapReturnsDelta") + + +def filter_vanilla_swap(hooks: list[dict]) -> list[dict]: + """Return hooks that have no swap-related flags enabled.""" + return [h for h in hooks if not any(h["flags"][f] for f in SWAP_FLAGS)] + + def main(): repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) hooks_dir = os.path.join(repo_root, "hooks") schema_path = os.path.join(repo_root, "schema.json") hooklist_path = os.path.join(repo_root, "hooklist.json") + vanilla_path = os.path.join(repo_root, "hooklist-vanilla-swap.json") with open(schema_path) as f: schema = json.load(f) @@ -47,7 +56,13 @@ def main(): json.dump(hooks, f, indent=2) f.write("\n") + vanilla = filter_vanilla_swap(hooks) + with open(vanilla_path, "w") as f: + json.dump(vanilla, f, indent=2) + f.write("\n") + print(f"Aggregated {len(hooks)} hooks into hooklist.json") + print(f"Filtered {len(vanilla)} vanilla-swap hooks into hooklist-vanilla-swap.json") if __name__ == "__main__": diff --git a/scripts/test_aggregate.py b/scripts/test_aggregate.py index f5a4b4fb..65a98376 100644 --- a/scripts/test_aggregate.py +++ b/scripts/test_aggregate.py @@ -2,7 +2,7 @@ import os import tempfile import pytest -from aggregate import aggregate_hooks +from aggregate import aggregate_hooks, filter_vanilla_swap SCHEMA = { @@ -172,6 +172,29 @@ def test_aggregate_with_schema_missing_flag(): aggregate_hooks(tmpdir, schema=SCHEMA) +def test_filter_vanilla_swap_excludes_swap_hooks(): + swap_hook = _valid_hook() # has beforeSwap=True + vanilla_hook = _valid_hook(address="0x00000000000000000000000000000000000000A0") + vanilla_hook["flags"]["beforeSwap"] = False + vanilla_hook["flags"]["beforeInitialize"] = False + result = filter_vanilla_swap([swap_hook, vanilla_hook]) + assert len(result) == 1 + assert result[0]["hook"]["address"] == vanilla_hook["hook"]["address"] + + +def test_filter_vanilla_swap_excludes_returns_delta(): + hook = _valid_hook() + hook["flags"]["beforeSwap"] = False + hook["flags"]["afterSwap"] = False + hook["flags"]["afterSwapReturnsDelta"] = True + result = filter_vanilla_swap([hook]) + assert result == [] + + +def test_filter_vanilla_swap_empty(): + assert filter_vanilla_swap([]) == [] + + def test_aggregate_with_schema_wrong_type(): with tempfile.TemporaryDirectory() as tmpdir: hook = _valid_hook()