HoodsHook

0x530e7d4e760163d5d0a33ef20655b1a7af08e0cc

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
8,656 bytes
ABI entries
44
17 read · 17 write
License
none

Contract information

Address
0x530e7d4e760163d5d0a33ef20655b1a7af08e0cc
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xf4e6d83442…68a9faf8b9

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (17)

BPS()uint256
MAX_FEE_BPS()uint256
TOTAL_SUPPLY()uint256
deployer()address
factory()address
feeFor(uint256)uint256, uint256
feeTierCount()uint256
feeTiers(uint256)uint128, uint16, uint16
getHookPermissions()tuple
launches(bytes32)bool, bool, int24
marketCapWei(tuple)uint256
owner()address
poolDeploymentBlock(bytes32)uint256
poolManager()address
splitter()address
treasury()address
treasuryEscrow()uint256

Events (6)

FeeChargedFeeTiersUpdatedGraduatedLaunchRegisteredOwnerChangedTreasuryChanged

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "_poolManager",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "treasury_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "splitter_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "wirer_",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "HookNotImplemented",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotPoolManager",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "poolId",
        "type": "bytes32"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "isBuy",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "feeAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "platformShare",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "creatorShare",
        "type": "uint256"
      }
    ],
    "name": "FeeCharged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "count",
        "type": "uint256"
      }
    ],
    "name": "FeeTiersUpdated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "poolId",
        "type": "bytes32"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "tick",
        "type": "int24"
      }
    ],
    "name": "Graduated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "bytes32",
        "name": "poolId",
        "type": "bytes32"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "token",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "int24",
        "name": "graduationTick",
        "type": "int24"
      }
    ],
    "name": "LaunchRegistered",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "previousOwner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "OwnerChanged",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "treasury",
        "type": "address"
      }
    ],
    "name": "TreasuryChanged",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TOTAL_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "int24",
            "name": "tickLower",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickUpper",
            "type": "int24"
          },
          {
            "internalType": "int256",
            "name": "liquidityDelta",
            "type": "int256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IPoolManager.ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "feesAccrued",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "afterAddLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "amount0",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "amount1",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "afterDonate",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "internalType": "uint160",
        "name": "sqrtPriceX96",
        "type": "uint160"
      },
      {
        "internalType": "int24",
        "name": "tick",
        "type": "int24"
      }
    ],
    "name": "afterInitialize",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "int24",
            "name": "tickLower",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickUpper",
            "type": "int24"
          },
          {
            "internalType": "int256",
            "name": "liquidityDelta",
            "type": "int256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IPoolManager.ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "feesAccrued",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "afterRemoveLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "bool",
            "name": "zeroForOne",
            "type": "bool"
          },
          {
            "internalType": "int256",
            "name": "amountSpecified",
            "type": "int256"
          },
          {
            "internalType": "uint160",
            "name": "sqrtPriceLimitX96",
            "type": "uint160"
          }
        ],
        "internalType": "struct IPoolManager.SwapParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "afterSwap",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "int128",
        "name": "",
        "type": "int128"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "int24",
            "name": "tickLower",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickUpper",
            "type": "int24"
          },
          {
            "internalType": "int256",
            "name": "liquidityDelta",
            "type": "int256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IPoolManager.ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "beforeAddLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "amount0",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "amount1",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "beforeDonate",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "internalType": "uint160",
        "name": "sqrtPriceX96",
        "type": "uint160"
      }
    ],
    "name": "beforeInitialize",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "int24",
            "name": "tickLower",
            "type": "int24"
          },
          {
            "internalType": "int24",
            "name": "tickUpper",
            "type": "int24"
          },
          {
            "internalType": "int256",
            "name": "liquidityDelta",
            "type": "int256"
          },
          {
            "internalType": "bytes32",
            "name": "salt",
            "type": "bytes32"
          }
        ],
        "internalType": "struct IPoolManager.ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "beforeRemoveLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "components": [
          {
            "internalType": "bool",
            "name": "zeroForOne",
            "type": "bool"
          },
          {
            "internalType": "int256",
            "name": "amountSpecified",
            "type": "int256"
          },
          {
            "internalType": "uint160",
            "name": "sqrtPriceLimitX96",
            "type": "uint160"
          }
        ],
        "internalType": "struct IPoolManager.SwapParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "hookData",
        "type": "bytes"
      }
    ],
    "name": "beforeSwap",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "BeforeSwapDelta",
        "name": "",
        "type": "int256"
      },
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "deployer",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "factory",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "mcapWei",
        "type": "uint256"
      }
    ],
    "name": "feeFor",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "totalBps",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "platformBps",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeTierCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "name": "feeTiers",
    "outputs": [
      {
        "internalType": "uint128",
        "name": "mcapThresholdWei",
        "type": "uint128"
      },
      {
        "internalType": "uint16",
        "name": "totalBps",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "platformBps",
        "type": "uint16"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getHookPermissions",
    "outputs": [
      {
        "components": [
          {
            "internalType": "bool",
            "name": "beforeInitialize",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterInitialize",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "beforeAddLiquidity",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterAddLiquidity",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "beforeRemoveLiquidity",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterRemoveLiquidity",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "beforeSwap",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterSwap",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "beforeDonate",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterDonate",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "beforeSwapReturnDelta",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterSwapReturnDelta",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterAddLiquidityReturnDelta",
            "type": "bool"
          },
          {
            "internalType": "bool",
            "name": "afterRemoveLiquidityReturnDelta",
            "type": "bool"
          }
        ],
        "internalType": "struct Hooks.Permissions",
        "name": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "name": "launches",
    "outputs": [
      {
        "internalType": "bool",
        "name": "exists",
        "type": "bool"
      },
      {
        "internalType": "bool",
        "name": "graduated",
        "type": "bool"
      },
      {
        "internalType": "int24",
        "name": "graduationTick",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      }
    ],
    "name": "marketCapWei",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      }
    ],
    "name": "poke",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "name": "poolDeploymentBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "poolManager",
    "outputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "Currency",
            "name": "currency0",
            "type": "address"
          },
          {
            "internalType": "Currency",
            "name": "currency1",
            "type": "address"
          },
          {
            "internalType": "uint24",
            "name": "fee",
            "type": "uint24"
          },
          {
            "internalType": "int24",
            "name": "tickSpacing",
            "type": "int24"
          },
          {
            "internalType": "contract IHooks",
            "name": "hooks",
            "type": "address"
          }
        ],
        "internalType": "struct PoolKey",
        "name": "key",
        "type": "tuple"
      },
      {
        "internalType": "int24",
        "name": "graduationTick",
        "type": "int24"
      }
    ],
    "name": "registerLaunch",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "factory_",
        "type": "address"
      }
    ],
    "name": "setFactory",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "components": [
          {
            "internalType": "uint128",
            "name": "mcapThresholdWei",
            "type": "uint128"
          },
          {
            "internalType": "uint16",
            "name": "totalBps",
            "type": "uint16"
          },
          {
            "internalType": "uint16",
            "name": "platformBps",
            "type": "uint16"
          }
        ],
        "internalType": "struct HoodsHook.FeeTier[]",
        "name": "tiers",
        "type": "tuple[]"
      }
    ],
    "name": "setFeeTiers",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "newOwner",
        "type": "address"
      }
    ],
    "name": "setOwner",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "t",
        "type": "address"
      }
    ],
    "name": "setTreasury",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "splitter",
    "outputs": [
      {
        "internalType": "contract IHoodsSplitter",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "treasury",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "treasuryEscrow",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "withdrawTreasury",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

/*
█   █  ███   ███  ████   ████     █   █ █████ █   █ █████
█   █ █   █ █   █ █   █ █         ██ ██ █     ██ ██ █
█████ █   █ █   █ █   █  ███      █ █ █ ████  █ █ █ ████
█   █ █   █ █   █ █   █     █  █  █   █ █     █   █ █
█   █  ███   ███  ████  ████   █  █   █ █████ █   █ █████

   The most rewarding place to launch and trade.
   Fixed supply · LP burned forever · fees flow to creators.

   web  https://hoods.meme
   x    https://x.com/hoodsmeme
   tg   https://t.me/hoods_meme
*/


import { BaseHook } from "./vendor/BaseHook.sol";
import { Hooks } from "v4-core/src/libraries/Hooks.sol";
import { IPoolManager } from "v4-core/src/interfaces/IPoolManager.sol";
import { PoolKey } from "v4-core/src/types/PoolKey.sol";
import { PoolId } from "v4-core/src/types/PoolId.sol";
import { Currency } from "v4-core/src/types/Currency.sol";
import { BalanceDelta } from "v4-core/src/types/BalanceDelta.sol";
import { BeforeSwapDelta, toBeforeSwapDelta } from "v4-core/src/types/BeforeSwapDelta.sol";
import { StateLibrary } from "v4-core/src/libraries/StateLibrary.sol";
import { PoolIdLibrary } from "v4-core/src/types/PoolId.sol";
import { FullMath } from "v4-core/src/libraries/FullMath.sol";

interface IHoodsSplitter {
    function credit(address token) external payable;
}

/// @title HoodsHook — singleton fee hook for every hoods.meme pool (arc §2.3)
/// @notice Pool LP fee = 0; this hook takes an ETH fee on every swap, sized by a MARKET-CAP tier curve:
/// high at launch (anti-snipe economics + revenue), decaying at scale so a lower-fee clone pool can't
/// undercut the canonical one. The fee splits platform → treasury, creator → HoodsSplitter (current
/// Creator NFT holder). Launch LIMITS live in HoodsToken (tx.origin-based, non-spoofable), not here.
///
/// Fee-taking follows the verified production pattern (native ETH is always currency0):
///   • ETH is the SPECIFIED currency (buy exactIn) → take in beforeSwap, return +delta on specified.
///   • ETH is the UNSPECIFIED currency (buy exactOut, sell exactIn) → take in afterSwap, return +delta.
///   • sell exactOut is rejected (would need a pre-swap price lookup to size the ETH fee).
///
/// Bounded owner: may retune the tier table (each total ≤ 1%, always), the treasury, and the owner. It
/// CANNOT mint, move LP, seize tokens, redirect the creator share, or halt trading — no such code.
contract HoodsHook is BaseHook {
    using StateLibrary for IPoolManager;
    using PoolIdLibrary for PoolKey;

    uint256 public constant BPS = 10_000;
    uint256 public constant MAX_FEE_BPS = 100; // 1% — the hard cap the owner can never exceed
    uint256 public constant TOTAL_SUPPLY = 1_000_000_000e18; // 1B (mirrors the factory) — for mcap
    uint256 private constant Q96 = 0x1000000000000000000000000; // 2^96

    /// Market-cap fee tier. `totalBps` = fee as bps of the ETH swapped; `platformBps` = the platform's
    /// slice of that fee (creator gets total − platform). Tiers ascending by threshold; the LAST tier
    /// has threshold 0 — the floor that catches every mcap above the previous bound.
    struct FeeTier {
        uint128 mcapThresholdWei; // upper bound in ETH wei (exclusive); ignored on the last tier
        uint16 totalBps;
        uint16 platformBps;
    }

    FeeTier[] public feeTiers;

    address public treasury; // platform fee sink (owner-settable)
    uint256 public treasuryEscrow; // platform ETH that couldn't be pushed to treasury — pull via withdrawTreasury
    IHoodsSplitter public immutable splitter;
    address public immutable deployer; // one-shot setFactory authority (hook is CREATE2-deployed, M-1)
    address public owner; // bounded admin (see contract notice)

    // Launch registry (set once per pool by the factory) — drives the UI/indexer "graduated" flag.
    address public factory; // set-once binding (deploy ordering: hook before factory)
    struct Launch {
        bool exists;
        bool graduated; // one-way latch; UI/indexer "graduated"
        int24 graduationTick;
    }
    mapping(bytes32 => Launch) public launches; // poolId => launch data
    mapping(bytes32 => uint256) public poolDeploymentBlock; // no fee on the launch block

    event LaunchRegistered(bytes32 indexed poolId, address indexed token, int24 graduationTick);
    event Graduated(bytes32 indexed poolId, address indexed token, int24 tick);
    event FeeCharged(
        bytes32 indexed poolId, address indexed token, bool isBuy, uint256 feeAmount, uint256 platformShare, uint256 creatorShare
    );
    event FeeTiersUpdated(uint256 count);
    event TreasuryChanged(address indexed treasury);
    event OwnerChanged(address indexed previousOwner, address indexed newOwner);

    constructor(IPoolManager _poolManager, address treasury_, address splitter_, address wirer_) BaseHook(_poolManager) {
        require(treasury_ != address(0) && splitter_ != address(0) && wirer_ != address(0), "zero");
        treasury = treasury_;
        splitter = IHoodsSplitter(splitter_);
        deployer = wirer_; // the EOA allowed to wire `factory` — hook is CREATE2-deployed so ctor
            // msg.sender is the deterministic CREATE2 factory, not the deployer (M-1).
        owner = wirer_;
        emit OwnerChanged(address(0), wirer_);
        _initDefaultFeeTiers();
    }

    /// Default 6-tier curve. Thresholds ETH-denominated (about $4k/ETH: $2.5M to $25M); total 1% to
    /// 0.25%; platform share slides 60% to ~28% as the token grows.
    function _initDefaultFeeTiers() private {
        feeTiers.push(FeeTier(625e18, 100, 60)); // < ~$2.5M — 1.00%, 60/40
        feeTiers.push(FeeTier(1250e18, 85, 46)); // < ~$5M   — 0.85%, 54/46
        feeTiers.push(FeeTier(2500e18, 70, 34)); // < ~$10M  — 0.70%, 49/51
        feeTiers.push(FeeTier(4000e18, 55, 23)); // < ~$16M  — 0.55%, 42/58
        feeTiers.push(FeeTier(6250e18, 40, 14)); // < ~$25M  — 0.40%, 35/65
        feeTiers.push(FeeTier(0, 25, 7)); // ≥ ~$25M  — 0.25%, 28/72 (floor)
    }

    // ── bounded owner ──
    modifier onlyOwner() {
        require(msg.sender == owner, "not owner");
        _;
    }

    /// Replace the fee tier table. Each total ≤ 1% (MAX_FEE_BPS) and platform ≤ total — the owner can
    /// only ever lower/reshape fees, never gouge. Ascending thresholds; last tier is the floor.
    function setFeeTiers(FeeTier[] calldata tiers) external onlyOwner {
        require(tiers.length > 0, "empty");
        delete feeTiers;
        uint256 prev = 0;
        for (uint256 i = 0; i < tiers.length; i++) {
            require(tiers[i].totalBps <= MAX_FEE_BPS, "fee > 1%");
            require(tiers[i].platformBps <= tiers[i].totalBps, "platform > total");
            if (i < tiers.length - 1) {
                require(tiers[i].mcapThresholdWei > prev, "not ascending");
                prev = tiers[i].mcapThresholdWei;
            }
            feeTiers.push(tiers[i]);
        }
        emit FeeTiersUpdated(tiers.length);
    }

    function setTreasury(address t) external onlyOwner {
        require(t != address(0), "zero");
        treasury = t;
        emit TreasuryChanged(t);
    }

    /// Pull platform ETH that couldn't be pushed at swap time (e.g. treasury temporarily unpayable).
    /// Permissionless — funds only ever go to the CURRENT treasury.
    function withdrawTreasury() external {
        uint256 amount = treasuryEscrow;
        require(amount > 0, "nothing");
        treasuryEscrow = 0;
        (bool ok,) = payable(treasury).call{ value: amount }("");
        require(ok, "send failed");
    }

    function setOwner(address newOwner) external onlyOwner {
        emit OwnerChanged(owner, newOwner);
        owner = newOwner;
    }

    function feeTierCount() external view returns (uint256) {
        return feeTiers.length;
    }

    /// One-shot binding of the factory (breaks the hook↔factory deploy cycle). Deployer-only so it can't
    /// be front-run into a griefing address before the real factory binds (would brick trading, M-1).
    function setFactory(address factory_) external {
        require(msg.sender == deployer, "not deployer");
        require(factory == address(0) && factory_ != address(0), "factory set");
        factory = factory_;
    }

    /// Factory-only, once per pool: record the graduation latch tick.
    function registerLaunch(PoolKey calldata key, int24 graduationTick) external {
        require(msg.sender == factory, "not factory");
        bytes32 id = PoolId.unwrap(_toId(key));
        require(!launches[id].exists, "registered");
        launches[id] = Launch({ exists: true, graduated: false, graduationTick: graduationTick });
        emit LaunchRegistered(id, _token(key), graduationTick);
    }

    /// Permissionless: latch graduation from the current tick without needing a swap (keeper/indexer).
    function poke(PoolKey calldata key) external {
        _updateLatch(key);
    }

    /// One-way latch: sets graduated once the pool tick has fallen to/through graduationTick (buys move
    /// the tick DOWN). Purely informational now — limits live in the token on a time window.
    function _updateLatch(PoolKey calldata key) internal {
        bytes32 id = PoolId.unwrap(_toId(key));
        Launch storage L = launches[id];
        if (!L.exists || L.graduated) return;
        (, int24 tick,,) = poolManager.getSlot0(key.toId());
        if (tick <= L.graduationTick) {
            L.graduated = true;
            emit Graduated(id, _token(key), tick);
        }
    }

    // ── fee sizing (market-cap tiered) ──

    /// Fully-diluted market cap in ETH wei from the current pool price (ETH is currency0). Zero if the
    /// pool is uninitialised. mcap = totalSupply × ethPerToken, where ethPerToken = (2^96 / sqrtP)^2.
    function marketCapWei(PoolKey calldata key) public view returns (uint256) {
        (uint160 sqrtP,,,) = poolManager.getSlot0(key.toId());
        if (sqrtP == 0) return 0;
        uint256 inv = FullMath.mulDiv(Q96, Q96, sqrtP); // = sqrt(ethPerToken) × 2^96
        return FullMath.mulDiv(FullMath.mulDiv(TOTAL_SUPPLY, inv, Q96), inv, Q96);
    }

    /// (totalBps, platformBps) for a market cap — first tier it's under, else the floor (last tier).
    function feeFor(uint256 mcapWei) public view returns (uint256 totalBps, uint256 platformBps) {
        uint256 n = feeTiers.length;
        for (uint256 i = 0; i < n; i++) {
            if (i == n - 1 || mcapWei < feeTiers[i].mcapThresholdWei) {
                return (feeTiers[i].totalBps, feeTiers[i].platformBps);
            }
        }
        return (0, 0); // unreachable while tiers are non-empty
    }

    function _feeBps(PoolKey calldata key) private view returns (uint256 totalBps, uint256 platformBps) {
        return feeFor(marketCapWei(key));
    }

    // ── permissions ──
    function getHookPermissions() public pure override returns (Hooks.Permissions memory) {
        return Hooks.Permissions({
            beforeInitialize: true,
            afterInitialize: false,
            beforeAddLiquidity: false,
            afterAddLiquidity: false,
            beforeRemoveLiquidity: false,
            afterRemoveLiquidity: false,
            beforeSwap: true,
            afterSwap: true,
            beforeDonate: false,
            afterDonate: false,
            beforeSwapReturnDelta: true,
            afterSwapReturnDelta: true,
            afterAddLiquidityReturnDelta: false,
            afterRemoveLiquidityReturnDelta: false
        });
    }

    function _beforeInitialize(address, PoolKey calldata key, uint160) internal override returns (bytes4) {
        poolDeploymentBlock[PoolId.unwrap(_toId(key))] = block.number;
        return BaseHook.beforeInitialize.selector;
    }

    // ─────────────────────────────── fee taking ───────────────────────────────

    /// ETH-specified path: buy exactIn (fee peeled from the ETH input). Sell exactOut is rejected.
    function _beforeSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, bytes calldata)
        internal
        override
        returns (bytes4, BeforeSwapDelta, uint24)
    {
        address token = _token(key);
        if (token == address(0)) return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);
        // Only charge fees on factory-registered pools. A rogue ETH/X pool that attaches this hook would
        // otherwise accrue creator `pending` for a token with no Creator NFT → stranded forever (M-3).
        if (!launches[PoolId.unwrap(_toId(key))].exists) return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        _updateLatch(key); // one-way graduation check from the pre-swap tick

        bool isBuy = _isBuy(key, params);
        bool isExactInput = params.amountSpecified < 0;
        // sell exactOut: ETH is specified but sizing the fee needs a pre-swap price lookup → reject.
        require(isBuy || isExactInput, "exactOutput sells unsupported");

        // handled in afterSwap when ETH is the unspecified side (buy exactOut, sell exactIn)
        if (!(isBuy && isExactInput)) return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        uint256 ethIn = uint256(-params.amountSpecified);
        if (_noFee(key)) return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        (uint256 totalBps, uint256 platformBps) = _feeBps(key);
        uint256 feeAmount = (ethIn * totalBps) / BPS;
        if (feeAmount == 0) return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        poolManager.take(key.currency0, address(this), feeAmount); // currency0 == ETH
        _distribute(key, token, feeAmount, true, platformBps, totalBps);

        return (BaseHook.beforeSwap.selector, toBeforeSwapDelta(int128(int256(feeAmount)), 0), 0);
    }

    /// ETH-unspecified path: buy exactOut or sell exactIn (fee peeled from the ETH leg of the delta).
    function _afterSwap(address, PoolKey calldata key, IPoolManager.SwapParams calldata params, BalanceDelta delta, bytes calldata)
        internal
        override
        returns (bytes4, int128)
    {
        address token = _token(key);
        if (token == address(0)) return (BaseHook.afterSwap.selector, 0);
        if (!launches[PoolId.unwrap(_toId(key))].exists) return (BaseHook.afterSwap.selector, 0); // unregistered pool — no fee (M-3)

        // Latch graduation from the POST-swap tick so the crossing trade graduates instantly.
        // (_beforeSwap latches from the pre-swap tick, which is one trade late for the crosser;
        // cheap once latched — _updateLatch early-returns on the one-way flag.)
        _updateLatch(key);

        bool isBuy = _isBuy(key, params);
        // ETH is specified iff (isBuy == isExactInput); the fee for those was already taken in beforeSwap.
        if (isBuy == (params.amountSpecified < 0)) return (BaseHook.afterSwap.selector, 0);

        int128 ethDelta = delta.amount0(); // currency0 == ETH
        uint256 ethMoved = ethDelta < 0 ? uint256(int256(-ethDelta)) : uint256(int256(ethDelta));
        if (_noFee(key)) return (BaseHook.afterSwap.selector, 0);

        (uint256 totalBps, uint256 platformBps) = _feeBps(key);
        uint256 feeAmount = (ethMoved * totalBps) / BPS;
        if (feeAmount == 0) return (BaseHook.afterSwap.selector, 0);

        poolManager.take(key.currency0, address(this), feeAmount);
        _distribute(key, token, feeAmount, false, platformBps, totalBps);

        return (BaseHook.afterSwap.selector, int128(int256(feeAmount)));
    }

    // ── internals ──

    function _distribute(PoolKey calldata key, address token, uint256 feeAmount, bool isBuy, uint256 platformBps, uint256 totalBps)
        private
    {
        uint256 platformShare = totalBps == 0 ? 0 : (feeAmount * platformBps) / totalBps;
        uint256 creatorShare = feeAmount - platformShare;
        if (platformShare > 0) {
            // NEVER revert the swap on a bad/unpayable treasury (audit H-1): a reverting treasury would
            // brick ALL trading. Escrow-on-failure; pull via withdrawTreasury().
            (bool ok,) = payable(treasury).call{ value: platformShare }("");
            if (!ok) treasuryEscrow += platformShare;
        }
        if (creatorShare > 0) {
            splitter.credit{ value: creatorShare }(token);
        }
        emit FeeCharged(PoolId.unwrap(_toId(key)), token, isBuy, feeAmount, platformShare, creatorShare);
    }

    /// No fee on the pool's launch block (the atomic dev-buy is free).
    function _noFee(PoolKey calldata key) private view returns (bool) {
        return block.number == poolDeploymentBlock[PoolId.unwrap(_toId(key))];
    }

    /// Token is the non-ETH currency; our pools always have currency0 == native ETH.
    function _token(PoolKey calldata key) private pure returns (address) {
        if (Currency.unwrap(key.currency0) == address(0)) return Currency.unwrap(key.currency1);
        if (Currency.unwrap(key.currency1) == address(0)) return Currency.unwrap(key.currency0);
        return address(0);
    }

    function _isBuy(PoolKey calldata key, IPoolManager.SwapParams calldata params) private pure returns (bool) {
        // buy = acquiring the token with ETH. ETH is currency0 ⇒ zeroForOne is a buy.
        return Currency.unwrap(key.currency0) == address(0) ? params.zeroForOne : !params.zeroForOne;
    }

    function _toId(PoolKey calldata key) private pure returns (PoolId) {
        return PoolId.wrap(keccak256(abi.encode(key)));
    }

    receive() external payable { }
}
Chain explorer2840msChain node100ms