MineableToken

0xd69be8d7c6d0e8216dc2c151834e4150313260cc

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
16,792 bytes
ABI entries
89
49 read · 9 write
License
none

Contract information

Address
0xd69be8d7c6d0e8216dc2c151834e4150313260cc
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0xb9331e6043…07179587ce

Token

Name
HashWood
Symbol
HASH
Decimals
18
Holders
146

Read contract (49)

HALVING_INTERVAL()uint256
INITIAL_REWARD()uint256
INITIAL_SWAP_FEE_BPS()uint256
MAXIMUM_TARGET()uint256
MAX_ADJUSTMENT_FACTOR()uint256
MAX_SUPPLY()uint256
MINIMUM_TARGET()uint256
MINT_FEE_BPS()uint256
MINT_PRICE()uint256
MIN_SWAP_FEE_BPS()uint256
POST_SALE_SWAP_FEE_BPS()uint256
READJUSTMENT_INTERVAL()uint256
SWAP_FEE_DECAY_BPS()uint256
afterAddLiquidity(address, tuple, tuple, int256, int256, bytes)bytes4, int256
afterDonate(address, tuple, uint256, uint256, bytes)bytes4
afterInitialize(address, tuple, uint160, int24)bytes4
afterRemoveLiquidity(address, tuple, tuple, int256, int256, bytes)bytes4, int256
allowance(address, address)uint256
balanceOf(address)uint256
beforeAddLiquidity(address, tuple, tuple, bytes)bytes4
beforeDonate(address, tuple, uint256, uint256, bytes)bytes4
beforeInitialize(address, tuple, uint160)bytes4
beforeRemoveLiquidity(address, tuple, tuple, bytes)bytes4
canonicalPoolKey()tuple
challengeNumber()bytes32
checkMintSolution(uint256, address)bool
decimals()uint8
epochCount()uint256
feeRecipient()address
getChallengeNumber()bytes32
getMiningDifficulty()uint256
getMiningReward()uint256
getMiningTarget()uint256
initSqrtPriceX96()uint160
lastMintBlock()uint256
lastRetargetTime()uint256
miningTarget()uint256
name()string
onERC721Received(address, address, uint256, bytes)bytes4
permit2()address
polReserve()uint256
poolManager()address
positionManager()address
seedThreshold()uint256
swapFeeBps()uint256
symbol()string
targetMintTime()uint256
tokensMinted()uint256
totalSupply()uint256

Events (7)

ApprovalDifficultyAdjustedFeeCollectedFeesClaimedLiquiditySeededMintTransfer

ABI

[
  {
    "inputs": [
      {
        "internalType": "string",
        "name": "name_",
        "type": "string"
      },
      {
        "internalType": "string",
        "name": "symbol_",
        "type": "string"
      },
      {
        "internalType": "uint256",
        "name": "initialMiningTarget",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "targetMintTime_",
        "type": "uint256"
      },
      {
        "internalType": "contract IPoolManager",
        "name": "poolManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "feeRecipient_",
        "type": "address"
      },
      {
        "internalType": "contract IPositionManager",
        "name": "positionManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "permit2_",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "mintPrice_",
        "type": "uint256"
      },
      {
        "internalType": "uint160",
        "name": "initSqrtPriceX96_",
        "type": "uint160"
      },
      {
        "internalType": "uint256",
        "name": "seedEveryNMints_",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "BlockAlreadyMined",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "allowance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientAllowance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "balance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "needed",
        "type": "uint256"
      }
    ],
    "name": "ERC20InsufficientBalance",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "approver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidApprover",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "receiver",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidReceiver",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "sender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSender",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "ERC20InvalidSpender",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "EthTransferFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientGasForSeed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientLiquidity",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InsufficientPayment",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAction",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidDigest",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "MiningFinished",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NotPoolManager",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NothingToClaim",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "NothingToSeed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PoolNotInitialized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "ReentrancyGuardReentrantCall",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "SolutionAboveTarget",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnsupportedSwapMode",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "WrongPool",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Approval",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "newMiningTarget",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "elapsedSeconds",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "expectedSeconds",
        "type": "uint256"
      }
    ],
    "name": "DifficultyAdjusted",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "sender",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "bool",
        "name": "isBuy",
        "type": "bool"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethAmount",
        "type": "uint256"
      }
    ],
    "name": "FeeCollected",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethAmount",
        "type": "uint256"
      }
    ],
    "name": "FeesClaimed",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "ethAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "tokenAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint128",
        "name": "liquidity",
        "type": "uint128"
      }
    ],
    "name": "LiquiditySeeded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "rewardAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "epochCount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "bytes32",
        "name": "newChallengeNumber",
        "type": "bytes32"
      }
    ],
    "name": "Mint",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "Transfer",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "HALVING_INTERVAL",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_REWARD",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_SWAP_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAXIMUM_TARGET",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_ADJUSTMENT_FACTOR",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_SUPPLY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MINIMUM_TARGET",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MINT_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MINT_PRICE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_SWAP_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POST_SALE_SWAP_FEE_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "READJUSTMENT_INTERVAL",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "SWAP_FEE_DECAY_BPS",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "afterAddLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "afterDonate",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      },
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "name": "afterInitialize",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "afterRemoveLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "BalanceDelta",
        "name": "",
        "type": "int256"
      }
    ],
    "stateMutability": "pure",
    "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": "",
        "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": "",
        "type": "bytes"
      }
    ],
    "name": "afterSwap",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      },
      {
        "internalType": "int128",
        "name": "",
        "type": "int128"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "owner",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      }
    ],
    "name": "allowance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "spender",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "approve",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "autoSeed",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "account",
        "type": "address"
      }
    ],
    "name": "balanceOf",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "beforeAddLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "beforeDonate",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "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": "",
        "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": "",
        "type": "tuple"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "beforeRemoveLiquidity",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "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": "",
        "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": "",
        "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": "canonicalPoolKey",
    "outputs": [
      {
        "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": "",
        "type": "tuple"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "challengeNumber",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "nonce",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "minter",
        "type": "address"
      }
    ],
    "name": "checkMintSolution",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "claimFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "decimals",
    "outputs": [
      {
        "internalType": "uint8",
        "name": "",
        "type": "uint8"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "epochCount",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "feeRecipient",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getChallengeNumber",
    "outputs": [
      {
        "internalType": "bytes32",
        "name": "",
        "type": "bytes32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getMiningDifficulty",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getMiningReward",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "getMiningTarget",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initSqrtPriceX96",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastMintBlock",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastRetargetTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "miningTarget",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "nonce",
        "type": "uint256"
      },
      {
        "internalType": "bytes32",
        "name": "challengeDigest",
        "type": "bytes32"
      }
    ],
    "name": "mint",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "payable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "name",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      },
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "name": "onERC721Received",
    "outputs": [
      {
        "internalType": "bytes4",
        "name": "",
        "type": "bytes4"
      }
    ],
    "stateMutability": "pure",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "permit2",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "polReserve",
    "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": "positionManager",
    "outputs": [
      {
        "internalType": "contract IPositionManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "seedLiquidity",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "seedThreshold",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "swapFeeBps",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "symbol",
    "outputs": [
      {
        "internalType": "string",
        "name": "",
        "type": "string"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "targetMintTime",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tokensMinted",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalSupply",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transfer",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "value",
        "type": "uint256"
      }
    ],
    "name": "transferFrom",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import {Math} from "@openzeppelin/contracts/utils/math/Math.sol";
import {ReentrancyGuard} from "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

import {IHooks} from "v4-core/src/interfaces/IHooks.sol";
import {IPoolManager} from "v4-core/src/interfaces/IPoolManager.sol";
import {Hooks} from "v4-core/src/libraries/Hooks.sol";
import {PoolKey} from "v4-core/src/types/PoolKey.sol";
import {Currency, CurrencyLibrary} from "v4-core/src/types/Currency.sol";
import {BalanceDelta} from "v4-core/src/types/BalanceDelta.sol";
import {
    BeforeSwapDelta, BeforeSwapDeltaLibrary, toBeforeSwapDelta
} from "v4-core/src/types/BeforeSwapDelta.sol";
import {ModifyLiquidityParams, SwapParams} from "v4-core/src/types/PoolOperation.sol";
import {PoolId} from "v4-core/src/types/PoolId.sol";
import {StateLibrary} from "v4-core/src/libraries/StateLibrary.sol";
import {TickMath} from "v4-core/src/libraries/TickMath.sol";
import {LiquidityAmounts} from "v4-core/test/utils/LiquidityAmounts.sol";

interface IPositionManager {
    function modifyLiquidities(bytes calldata unlockData, uint256 deadline) external payable;
}

interface IAllowanceTransfer {
    function approve(address token, address spender, uint160 amount, uint48 expiration) external;
}

contract MineableToken is ERC20, ReentrancyGuard, IHooks {

    uint256 public constant MAX_SUPPLY = 21_000_000e18;
    uint256 public constant INITIAL_REWARD = 1_100e18;

    uint256 public constant HALVING_INTERVAL = 11_000;

    uint256 public constant MINT_FEE_BPS = 100;

    uint256 public constant READJUSTMENT_INTERVAL = 128;

    uint256 public constant MAXIMUM_TARGET = 2 ** 248;

    uint256 public constant MINIMUM_TARGET = 2 ** 16;

    uint256 public constant MAX_ADJUSTMENT_FACTOR = 4;

    uint256 public immutable targetMintTime;

    uint256 public constant INITIAL_SWAP_FEE_BPS = 400;

    uint256 public constant SWAP_FEE_DECAY_BPS = 150;

    uint256 public constant MIN_SWAP_FEE_BPS = 100;

    uint256 public constant POST_SALE_SWAP_FEE_BPS = 50;

    IPoolManager public immutable poolManager;

    address public immutable feeRecipient;

    uint256 public immutable MINT_PRICE;
    IPositionManager public immutable positionManager;
    address public immutable permit2;

    uint24 internal constant LP_FEE = 0;
    int24 internal constant TICK_SPACING = 60;
    int24 internal constant TICK_LOWER = -887_220;
    int24 internal constant TICK_UPPER = 887_220;

    uint8 internal constant ACTION_MINT_POSITION = 0x02;
    uint8 internal constant ACTION_SETTLE_PAIR = 0x0d;
    uint8 internal constant ACTION_SWEEP = 0x14;

    uint256 public polReserve;
    bool internal approvalsDone;

    uint256 public immutable seedThreshold;

    uint256 internal constant SEED_GAS_FLOOR = 800_000;

    uint160 public immutable initSqrtPriceX96;

    uint256 public miningTarget;
    bytes32 public challengeNumber;
    uint256 public epochCount;
    uint256 public tokensMinted;
    uint256 public lastRetargetTime;
    uint256 public lastMintBlock;

    event Mint(address indexed from, uint256 rewardAmount, uint256 epochCount, bytes32 newChallengeNumber);
    event DifficultyAdjusted(uint256 newMiningTarget, uint256 elapsedSeconds, uint256 expectedSeconds);
    event FeeCollected(address indexed sender, bool isBuy, uint256 ethAmount);
    event FeesClaimed(address indexed recipient, uint256 ethAmount);
    event LiquiditySeeded(uint256 ethAmount, uint256 tokenAmount, uint128 liquidity);

    error InvalidDigest();
    error SolutionAboveTarget();
    error MiningFinished();
    error BlockAlreadyMined();
    error InsufficientPayment();
    error PoolNotInitialized();
    error NothingToSeed();
    error InsufficientLiquidity();
    error InsufficientGasForSeed();
    error NotPoolManager();
    error WrongPool();
    error UnsupportedSwapMode();
    error InvalidAction();
    error NothingToClaim();
    error EthTransferFailed();

    constructor(
        string memory name_,
        string memory symbol_,
        uint256 initialMiningTarget,
        uint256 targetMintTime_,
        IPoolManager poolManager_,
        address feeRecipient_,
        IPositionManager positionManager_,
        address permit2_,
        uint256 mintPrice_,
        uint160 initSqrtPriceX96_,
        uint256 seedEveryNMints_
    ) ERC20(name_, symbol_) {
        require(targetMintTime_ > 0, "target time = 0");
        require(address(poolManager_) != address(0), "pool manager = 0");
        require(feeRecipient_ != address(0), "fee recipient = 0");
        require(address(positionManager_) != address(0), "position manager = 0");
        require(permit2_ != address(0), "permit2 = 0");
        require(initSqrtPriceX96_ > 0, "init price = 0");
        require(seedEveryNMints_ > 0, "seed interval = 0");

        miningTarget = _clampTarget(initialMiningTarget);
        targetMintTime = targetMintTime_;
        lastRetargetTime = block.timestamp;
        poolManager = poolManager_;
        feeRecipient = feeRecipient_;
        positionManager = positionManager_;
        permit2 = permit2_;
        MINT_PRICE = mintPrice_;
        seedThreshold = mintPrice_ * seedEveryNMints_;
        initSqrtPriceX96 = initSqrtPriceX96_;

        challengeNumber =
            keccak256(abi.encodePacked(_prevBlockhash(), block.chainid, address(this), block.timestamp));

        Hooks.validateHookPermissions(IHooks(address(this)), _permissions());
    }

    function _prevBlockhash() internal view returns (bytes32) {
        return block.number > 0 ? blockhash(block.number - 1) : bytes32(0);
    }

    function mint(uint256 nonce, bytes32 challengeDigest) external payable nonReentrant returns (bool) {
        bytes32 digest = keccak256(abi.encodePacked(challengeNumber, msg.sender, nonce));
        if (digest != challengeDigest) revert InvalidDigest();
        if (uint256(digest) > miningTarget) revert SolutionAboveTarget();
        if (block.number == lastMintBlock) revert BlockAlreadyMined();
        if (msg.value < MINT_PRICE) revert InsufficientPayment();

        uint256 reward = getMiningReward();
        if (reward == 0) revert MiningFinished();
        if (tokensMinted + reward > MAX_SUPPLY) {
            reward = MAX_SUPPLY - tokensMinted;
        }

        uint256 mintFee = (reward * MINT_FEE_BPS) / 10_000;
        if (tokensMinted + reward + mintFee > MAX_SUPPLY) {
            mintFee = MAX_SUPPLY - tokensMinted - reward;
        }

        polReserve += MINT_PRICE;
        tokensMinted += reward + mintFee;
        epochCount += 1;
        lastMintBlock = block.number;
        _mint(msg.sender, reward);
        if (mintFee > 0) {

            _mint(address(this), mintFee);
        }

        uint256 excess = msg.value - MINT_PRICE;
        if (excess > 0) {
            (bool ok,) = msg.sender.call{value: excess}("");
            if (!ok) revert EthTransferFailed();
        }

        if (polReserve >= seedThreshold) {
            if (gasleft() < SEED_GAS_FLOOR) revert InsufficientGasForSeed();
            try this.autoSeed() {} catch {}
        }

        if (epochCount % READJUSTMENT_INTERVAL == 0) {
            _adjustDifficulty();
        }

        challengeNumber = keccak256(abi.encodePacked(digest, _prevBlockhash(), epochCount));
        emit Mint(msg.sender, reward, epochCount, challengeNumber);
        return true;
    }

    function _adjustDifficulty() internal {
        uint256 expected = READJUSTMENT_INTERVAL * targetMintTime;
        uint256 elapsed = block.timestamp - lastRetargetTime;

        if (elapsed < expected / MAX_ADJUSTMENT_FACTOR) elapsed = expected / MAX_ADJUSTMENT_FACTOR;
        if (elapsed > expected * MAX_ADJUSTMENT_FACTOR) elapsed = expected * MAX_ADJUSTMENT_FACTOR;

        uint256 newTarget = _clampTarget(Math.mulDiv(miningTarget, elapsed, expected));
        miningTarget = newTarget;
        lastRetargetTime = block.timestamp;
        emit DifficultyAdjusted(newTarget, elapsed, expected);
    }

    function _clampTarget(uint256 target) internal pure returns (uint256) {
        if (target > MAXIMUM_TARGET) return MAXIMUM_TARGET;
        if (target < MINIMUM_TARGET) return MINIMUM_TARGET;
        return target;
    }

    function getMiningReward() public view returns (uint256) {
        uint256 era = epochCount / HALVING_INTERVAL;
        if (era > 63) return 0;
        uint256 reward = INITIAL_REWARD >> era;
        uint256 remaining = MAX_SUPPLY - tokensMinted;
        return reward < remaining ? reward : remaining;
    }

    function getMiningDifficulty() external view returns (uint256) {
        return MAXIMUM_TARGET / miningTarget;
    }

    function getChallengeNumber() external view returns (bytes32) {
        return challengeNumber;
    }

    function getMiningTarget() external view returns (uint256) {
        return miningTarget;
    }

    function checkMintSolution(uint256 nonce, address minter) external view returns (bool) {
        return uint256(keccak256(abi.encodePacked(challengeNumber, minter, nonce))) <= miningTarget;
    }

    function swapFeeBps() public view returns (uint256) {

        if (tokensMinted >= MAX_SUPPLY) return POST_SALE_SWAP_FEE_BPS;
        uint256 era = epochCount / HALVING_INTERVAL;
        uint256 decay = era * SWAP_FEE_DECAY_BPS;
        if (decay >= INITIAL_SWAP_FEE_BPS - MIN_SWAP_FEE_BPS) return MIN_SWAP_FEE_BPS;
        return INITIAL_SWAP_FEE_BPS - decay;
    }

    function claimFees() external nonReentrant {
        uint256 amount = address(this).balance - polReserve;
        if (amount == 0) revert NothingToClaim();
        (bool ok,) = feeRecipient.call{value: amount}("");
        if (!ok) revert EthTransferFailed();
        emit FeesClaimed(feeRecipient, amount);
    }

    receive() external payable {}

    function seedLiquidity() external nonReentrant {

        bool miningDone = tokensMinted >= MAX_SUPPLY;
        if (polReserve < seedThreshold && !miningDone) revert NothingToSeed();
        _seed();
    }

    function autoSeed() external {
        if (msg.sender != address(this)) revert InvalidAction();
        _seed();
    }

    function _seed() internal {
        uint256 eth = polReserve;
        uint256 tokens = balanceOf(address(this));

        PoolKey memory key = canonicalPoolKey();
        (uint160 sqrtPriceX96,,,) = StateLibrary.getSlot0(poolManager, key.toId());
        if (sqrtPriceX96 == 0) revert PoolNotInitialized();

        uint128 liquidity = LiquidityAmounts.getLiquidityForAmounts(
            sqrtPriceX96,
            TickMath.getSqrtPriceAtTick(TICK_LOWER),
            TickMath.getSqrtPriceAtTick(TICK_UPPER),
            eth,
            tokens
        );
        if (liquidity == 0) revert InsufficientLiquidity();

        if (!approvalsDone) {
            approvalsDone = true;
            _approve(address(this), permit2, type(uint256).max);
            IAllowanceTransfer(permit2).approve(
                address(this), address(positionManager), type(uint160).max, type(uint48).max
            );
        }

        bytes memory actions =
            abi.encodePacked(ACTION_MINT_POSITION, ACTION_SETTLE_PAIR, ACTION_SWEEP);
        bytes[] memory params = new bytes[](3);
        params[0] = abi.encode(key, TICK_LOWER, TICK_UPPER, liquidity, eth, tokens, address(this), bytes(""));
        params[1] = abi.encode(key.currency0, key.currency1);
        params[2] = abi.encode(key.currency0, address(this));

        uint256 balBefore = address(this).balance;
        positionManager.modifyLiquidities{value: eth}(abi.encode(actions, params), block.timestamp + 120);

        uint256 ethUsed = balBefore - address(this).balance;
        polReserve = eth - ethUsed;

        emit LiquiditySeeded(ethUsed, tokens, liquidity);
    }

    function canonicalPoolKey() public view returns (PoolKey memory) {
        return PoolKey({
            currency0: CurrencyLibrary.ADDRESS_ZERO,
            currency1: Currency.wrap(address(this)),
            fee: LP_FEE,
            tickSpacing: TICK_SPACING,
            hooks: IHooks(address(this))
        });
    }

    function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
        return this.onERC721Received.selector;
    }

    function _permissions() internal pure 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 sqrtPriceX96) external view returns (bytes4) {
        if (msg.sender != address(poolManager)) revert NotPoolManager();
        if (Currency.unwrap(key.currency0) != address(0)) revert WrongPool();
        if (Currency.unwrap(key.currency1) != address(this)) revert WrongPool();
        if (key.fee == LP_FEE && key.tickSpacing == TICK_SPACING && sqrtPriceX96 != initSqrtPriceX96) {
            revert WrongPool();
        }
        return IHooks.beforeInitialize.selector;
    }

    function beforeSwap(address sender, PoolKey calldata, SwapParams calldata params, bytes calldata)
        external
        nonReentrant
        returns (bytes4, BeforeSwapDelta, uint24)
    {
        if (msg.sender != address(poolManager)) revert NotPoolManager();

        bool isBuy = params.zeroForOne;
        bool isExactInput = params.amountSpecified < 0;

        if (!isBuy && !isExactInput) revert UnsupportedSwapMode();

        if (!isBuy || !isExactInput) {
            return (IHooks.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
        }

        uint256 ethIn = uint256(-params.amountSpecified);
        uint256 fee = (ethIn * swapFeeBps()) / 10_000;
        if (fee == 0) {
            return (IHooks.beforeSwap.selector, BeforeSwapDeltaLibrary.ZERO_DELTA, 0);
        }

        poolManager.take(CurrencyLibrary.ADDRESS_ZERO, address(this), fee);
        emit FeeCollected(sender, true, fee);

        return (IHooks.beforeSwap.selector, toBeforeSwapDelta(int128(int256(fee)), 0), 0);
    }

    function afterSwap(address sender, PoolKey calldata, SwapParams calldata params, BalanceDelta delta, bytes calldata)
        external
        returns (bytes4, int128)
    {
        if (msg.sender != address(poolManager)) revert NotPoolManager();

        bool isBuy = params.zeroForOne;
        bool isExactInput = params.amountSpecified < 0;

        bool ethIsUnspecified = (isBuy && !isExactInput) || (!isBuy && isExactInput);
        if (!ethIsUnspecified) {
            return (IHooks.afterSwap.selector, 0);
        }

        int128 ethDelta = delta.amount0();
        uint256 ethAmount = ethDelta < 0 ? uint256(int256(-ethDelta)) : uint256(int256(ethDelta));
        if (ethAmount == 0) {
            return (IHooks.afterSwap.selector, 0);
        }

        uint256 fee = (ethAmount * swapFeeBps()) / 10_000;
        if (fee == 0) {
            return (IHooks.afterSwap.selector, 0);
        }

        poolManager.take(CurrencyLibrary.ADDRESS_ZERO, address(this), fee);
        emit FeeCollected(sender, isBuy, fee);

        return (IHooks.afterSwap.selector, int128(int256(fee)));
    }

    function afterInitialize(address, PoolKey calldata, uint160, int24) external pure returns (bytes4) {
        revert InvalidAction();
    }

    function beforeAddLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
        external
        pure
        returns (bytes4)
    {
        revert InvalidAction();
    }

    function afterAddLiquidity(
        address,
        PoolKey calldata,
        ModifyLiquidityParams calldata,
        BalanceDelta,
        BalanceDelta,
        bytes calldata
    ) external pure returns (bytes4, BalanceDelta) {
        revert InvalidAction();
    }

    function beforeRemoveLiquidity(address, PoolKey calldata, ModifyLiquidityParams calldata, bytes calldata)
        external
        pure
        returns (bytes4)
    {
        revert InvalidAction();
    }

    function afterRemoveLiquidity(
        address,
        PoolKey calldata,
        ModifyLiquidityParams calldata,
        BalanceDelta,
        BalanceDelta,
        bytes calldata
    ) external pure returns (bytes4, BalanceDelta) {
        revert InvalidAction();
    }

    function beforeDonate(address, PoolKey calldata, uint256, uint256, bytes calldata)
        external
        pure
        returns (bytes4)
    {
        revert InvalidAction();
    }

    function afterDonate(address, PoolKey calldata, uint256, uint256, bytes calldata)
        external
        pure
        returns (bytes4)
    {
        revert InvalidAction();
    }
}
Chain explorer4032msChain node81ms