MemeFolioTaxHook

0x29a2a39143f5aafba61bb8c649bc7c7d50b1e0cc

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
7,863 bytes
ABI entries
44
18 read · 12 write
License
none

Contract information

Address
0x29a2a39143f5aafba61bb8c649bc7c7d50b1e0cc
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xb4259e0665…a6fa637c12

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (18)

BPS_DENOMINATOR()uint256
BUYBACK_BPS()uint256
POOL_LP_FEE()uint24
TAX_BPS()uint256
TREASURY_BPS()uint256
buybackWallet()address
calculateTax(uint256)uint256
getHookPermissions()tuple
initialSqrtPriceX96()uint160
launchAuthority()address
pendingBuybackTax()uint256
pendingNativeTax()uint256
pendingTreasuryTax()uint256
poolManager()address
poolTickSpacing()int24
projectToken()address
splitTax(uint256)uint256, uint256
treasuryWallet()address

Events (2)

NativeTaxAccruedNativeTaxForwarded

ABI

[
  {
    "inputs": [
      {
        "internalType": "contract IPoolManager",
        "name": "poolManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "projectToken_",
        "type": "address"
      },
      {
        "internalType": "address payable",
        "name": "buybackWallet_",
        "type": "address"
      },
      {
        "internalType": "address payable",
        "name": "treasuryWallet_",
        "type": "address"
      },
      {
        "internalType": "int24",
        "name": "poolTickSpacing_",
        "type": "int24"
      },
      {
        "internalType": "address",
        "name": "launchAuthority_",
        "type": "address"
      },
      {
        "internalType": "uint160",
        "name": "initialSqrtPriceX96_",
        "type": "uint160"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "FailedCall",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "HookNotImplemented",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPool",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTickSpacing",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotPoolManager",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "token",
        "type": "address"
      }
    ],
    "name": "SafeERC20FailedOperation",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnauthorizedInitialization",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "chargedBeforeSwap",
        "type": "bool"
      }
    ],
    "name": "NativeTaxAccrued",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "buybackWallet",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "buybackAmount",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "treasuryWallet",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "treasuryAmount",
        "type": "uint256"
      }
    ],
    "name": "NativeTaxForwarded",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "BUYBACK_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POOL_LP_FEE",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TAX_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TREASURY_BPS",
    "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 ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta0",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta1",
        "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 ModifyLiquidityParams",
        "name": "params",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta0",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "delta1",
        "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 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 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 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 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": "buybackWallet",
    "outputs": [
      {
        "internalType": "address payable",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "nativeAmount",
        "type": "uint256"
      }
    ],
    "name": "calculateTax",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "collectNativeTax",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "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": "permissions",
        "type": "tuple"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initialSqrtPriceX96",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launchAuthority",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingBuybackTax",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingNativeTax",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingTreasuryTax",
    "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": [],
    "name": "poolTickSpacing",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "projectToken",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "taxAmount",
        "type": "uint256"
      }
    ],
    "name": "splitTax",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "buybackAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "treasuryAmount",
        "type": "uint256"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "treasuryWallet",
    "outputs": [
      {
        "internalType": "address payable",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "unlockCallback",
    "outputs": [
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import { BaseHook } from "@openzeppelin/uniswap-hooks/base/BaseHook.sol";
import { CurrencySettler } from "@openzeppelin/uniswap-hooks/utils/CurrencySettler.sol";
import { Address } from "@openzeppelin/contracts/utils/Address.sol";
import { ReentrancyGuard } from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import { SignedMath } from "@openzeppelin/contracts/utils/math/SignedMath.sol";
import { IHooks } from "@uniswap/v4-core/src/interfaces/IHooks.sol";
import { IPoolManager } from "@uniswap/v4-core/src/interfaces/IPoolManager.sol";
import { Hooks } from "@uniswap/v4-core/src/libraries/Hooks.sol";
import { FullMath } from "@uniswap/v4-core/src/libraries/FullMath.sol";
import { SafeCast } from "@uniswap/v4-core/src/libraries/SafeCast.sol";
import { BalanceDelta } from "@uniswap/v4-core/src/types/BalanceDelta.sol";
import { BeforeSwapDelta, toBeforeSwapDelta } from "@uniswap/v4-core/src/types/BeforeSwapDelta.sol";
import { Currency, CurrencyLibrary } from "@uniswap/v4-core/src/types/Currency.sol";
import { PoolKey } from "@uniswap/v4-core/src/types/PoolKey.sol";
import { SwapParams } from "@uniswap/v4-core/src/types/PoolOperation.sol";

/// @title MemeFolioTaxHook
/// @notice Immutable 3% native-ETH swap tax for one exact Meme ETF Uniswap v4 pool.
/// @dev The fee is taken in ETH on both buys and sells, stored as gas-efficient PoolManager claims,
///      and split 2:1 between the buyback and treasury wallets on collection. Redemption is
///      permissionless and both destinations are immutable. No owner, proxy, setter, exemption
///      list, pause or alternate withdrawal path exists.
contract MemeFolioTaxHook is BaseHook, ReentrancyGuard {
    using Address for address payable;
    using CurrencyLibrary for Currency;
    using CurrencySettler for Currency;
    using SafeCast for uint256;

    uint256 public constant BPS_DENOMINATOR = 10_000;
    uint256 public constant TAX_BPS = 300;
    uint256 public constant BUYBACK_BPS = 200;
    uint256 public constant TREASURY_BPS = 100;
    uint24 public constant POOL_LP_FEE = 0;

    address public immutable projectToken;
    address payable public immutable buybackWallet;
    address payable public immutable treasuryWallet;
    int24 public immutable poolTickSpacing;
    uint160 public immutable initialSqrtPriceX96;
    address public launchAuthority;

    error InvalidAddress();
    error InvalidPool();
    error InvalidTickSpacing();
    error UnauthorizedInitialization();

    event NativeTaxAccrued(uint256 amount, bool chargedBeforeSwap);
    event NativeTaxForwarded(
        address indexed buybackWallet,
        uint256 buybackAmount,
        address indexed treasuryWallet,
        uint256 treasuryAmount
    );

    receive() external payable {
        if (msg.sender != address(poolManager)) revert NotPoolManager();
    }

    constructor(
        IPoolManager poolManager_,
        address projectToken_,
        address payable buybackWallet_,
        address payable treasuryWallet_,
        int24 poolTickSpacing_,
        address launchAuthority_,
        uint160 initialSqrtPriceX96_
    ) BaseHook(poolManager_) {
        if (
            projectToken_ == address(0) || buybackWallet_ == address(0)
                || treasuryWallet_ == address(0) || buybackWallet_ == treasuryWallet_
                || launchAuthority_ == address(0) || initialSqrtPriceX96_ == 0
        ) revert InvalidAddress();
        if (poolTickSpacing_ <= 0) revert InvalidTickSpacing();

        projectToken = projectToken_;
        buybackWallet = buybackWallet_;
        treasuryWallet = treasuryWallet_;
        poolTickSpacing = poolTickSpacing_;
        launchAuthority = launchAuthority_;
        initialSqrtPriceX96 = initialSqrtPriceX96_;
    }

    function getHookPermissions()
        public
        pure
        override
        returns (Hooks.Permissions memory permissions)
    {
        permissions.beforeInitialize = true;
        permissions.beforeSwap = true;
        permissions.afterSwap = true;
        permissions.beforeSwapReturnDelta = true;
        permissions.afterSwapReturnDelta = true;
    }

    function _beforeInitialize(address sender, PoolKey calldata key, uint160 sqrtPriceX96)
        internal
        override
        returns (bytes4)
    {
        _validatePool(key);
        if (sender != launchAuthority || sqrtPriceX96 != initialSqrtPriceX96) {
            revert UnauthorizedInitialization();
        }
        launchAuthority = address(0);
        return IHooks.beforeInitialize.selector;
    }

    function _beforeSwap(address, PoolKey calldata key, SwapParams calldata params, bytes calldata)
        internal
        override
        returns (bytes4, BeforeSwapDelta, uint24)
    {
        _validatePool(key);

        // The specified currency is ETH for exact-input buys and exact-output sells.
        bool nativeIsSpecified = (params.amountSpecified < 0) == params.zeroForOne;
        if (!nativeIsSpecified) return (IHooks.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        uint256 tax = calculateTax(_absolute(params.amountSpecified));
        if (tax == 0) return (IHooks.beforeSwap.selector, toBeforeSwapDelta(0, 0), 0);

        key.currency0.take(poolManager, address(this), tax, true);
        emit NativeTaxAccrued(tax, true);
        return (IHooks.beforeSwap.selector, toBeforeSwapDelta(tax.toInt128(), 0), 0);
    }

    function _afterSwap(
        address,
        PoolKey calldata key,
        SwapParams calldata params,
        BalanceDelta delta,
        bytes calldata
    ) internal override returns (bytes4, int128) {
        _validatePool(key);

        bool nativeIsSpecified = (params.amountSpecified < 0) == params.zeroForOne;
        if (nativeIsSpecified) return (IHooks.afterSwap.selector, 0);

        uint256 tax = calculateTax(_absolute(int256(delta.amount0())));
        if (tax == 0) return (IHooks.afterSwap.selector, 0);

        key.currency0.take(poolManager, address(this), tax, true);
        emit NativeTaxAccrued(tax, false);
        return (IHooks.afterSwap.selector, tax.toInt128());
    }

    /// @notice Returns total ETH tax currently claimable by both immutable destinations.
    function pendingNativeTax() public view returns (uint256) {
        return poolManager.balanceOf(address(this), CurrencyLibrary.ADDRESS_ZERO.toId());
    }

    function pendingBuybackTax() external view returns (uint256) {
        (uint256 buybackAmount,) = splitTax(pendingNativeTax());
        return buybackAmount;
    }

    function pendingTreasuryTax() external view returns (uint256) {
        (, uint256 treasuryAmount) = splitTax(pendingNativeTax());
        return treasuryAmount;
    }

    /// @notice Permissionlessly forwards all accrued ETH tax in an immutable 2:1 split.
    /// @dev A keeper calls this immediately before the hourly buy-and-distribute cycle.
    function collectNativeTax() external nonReentrant returns (uint256 amount) {
        amount = pendingNativeTax();
        if (amount == 0) return 0;

        (uint256 buybackAmount, uint256 treasuryAmount) = splitTax(amount);
        poolManager.unlock(abi.encode(amount));
        if (buybackAmount != 0) buybackWallet.sendValue(buybackAmount);
        if (treasuryAmount != 0) treasuryWallet.sendValue(treasuryAmount);
        emit NativeTaxForwarded(
            buybackWallet, buybackAmount, treasuryWallet, treasuryAmount
        );
    }

    /// @notice PoolManager callback used only to burn this hook's accrued native-ETH claims.
    function unlockCallback(bytes calldata data) external onlyPoolManager returns (bytes memory) {
        uint256 amount = abi.decode(data, (uint256));
        Currency nativeCurrency = CurrencyLibrary.ADDRESS_ZERO;
        nativeCurrency.settle(poolManager, address(this), amount, true);
        nativeCurrency.take(poolManager, address(this), amount, false);
        return "";
    }

    function calculateTax(uint256 nativeAmount) public pure returns (uint256) {
        return FullMath.mulDiv(nativeAmount, TAX_BPS, BPS_DENOMINATOR);
    }

    /// @notice Splits an already charged 3% tax amount into 2% buyback and 1% treasury shares.
    /// @dev The treasury receives the at-most-one-wei division remainder, so no ETH is stranded.
    function splitTax(uint256 taxAmount)
        public
        pure
        returns (uint256 buybackAmount, uint256 treasuryAmount)
    {
        buybackAmount = FullMath.mulDiv(taxAmount, BUYBACK_BPS, TAX_BPS);
        treasuryAmount = taxAmount - buybackAmount;
    }

    function _validatePool(PoolKey calldata key) internal view {
        if (
            !key.currency0.isAddressZero() || Currency.unwrap(key.currency1) != projectToken
                || key.fee != POOL_LP_FEE || key.tickSpacing != poolTickSpacing
                || address(key.hooks) != address(this)
        ) revert InvalidPool();
    }

    function _absolute(int256 amount) private pure returns (uint256) {
        return SignedMath.abs(amount);
    }
}
Chain explorer2243msChain node79ms