BIMOV4LiquidityLocker

0x0577db01d401c9735ceb25f2d0303442e7e9a3b1

Verification
Verified
0.8.24+commit.e11b9ed9
Type
Contract
19,358 bytes
ABI entries
85
41 read · 9 write
License
none

Contract information

Address
0x0577db01d401c9735ceb25f2d0303442e7e9a3b1
Chain
Robinhood Chain (4663)
Compiler
0.8.24+commit.e11b9ed9
Optimization
Enabled
Creation tx
0x4184a22d8a…e5e29a7ba3

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (41)

BATCH_BIMO()uint256
BATCH_ETH()uint256
BATCH_SIZE()uint256
BPS_DENOMINATOR()uint256
FULL_RANGE_TICK_LOWER()int24
FULL_RANGE_TICK_UPPER()int24
INITIAL_BIMO_PER_ETH()uint256
INITIAL_PRICE_BIMO_IS_TOKEN0()uint160
INITIAL_PRICE_BIMO_IS_TOKEN1()uint160
MAX_BUYBACK_WETH()uint256
MAX_EXECUTION_DEADLINE_DELAY()uint256
MAX_TWAP_TICK_DEVIATION()uint24
MIN_BUYBACK_WETH()uint256
PERMIT2_EXPIRATION()uint256
POST_INITIAL_LIQUIDITY_TWAP_DELAY()uint256
TWAP_WINDOW()uint32
bSingleSigner()address
bimo()address
coordinator()address
deployer()address
firstLiquidityAt()uint256
globalUnlockAt()uint256
initialSqrtPriceX96()uint160
launch()address
lpPermanentlyLocked()bool
officialHook()address
pendingBuybackWeth()uint256
permit2()address
poolKey()tuple
poolManager()address
positionManager()address
positionTokenId()uint256
tickLower()int24
tickUpper()int24
totalBimoBurned()uint256
totalBuybackBimoBurned()uint256
totalLpBimoAdded()uint256
totalLpEthAdded()uint256
totalResidualBimoBurned()uint256
totalWethBuyback()uint256
weth()address

Events (10)

BimoBurnedCoordinatorConfiguredFeesCollectedLiquidityAddedLpPermanentlyLockedPoolInitializedPositionCreatedPrincipalWithdrawnUnexpectedEthSweptWethBuybackBurned

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "bimo_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "weth_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "permit2_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "positionManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "poolManager_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "hook_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "launch_",
        "type": "address"
      },
      {
        "internalType": "address",
        "name": "bSingleSigner_",
        "type": "address"
      },
      {
        "internalType": "int24",
        "name": "tickLower_",
        "type": "int24"
      },
      {
        "internalType": "int24",
        "name": "tickUpper_",
        "type": "int24"
      },
      {
        "internalType": "uint160",
        "name": "initialSqrtPriceX96_",
        "type": "uint160"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "CoordinatorAlreadyConfigured",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "DeadlineExpired",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "DeadlineTooFar",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "DirectEthDisabled",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "used",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minimum",
        "type": "uint256"
      }
    ],
    "name": "InsufficientAssetUsed",
    "type": "error"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "received",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minimum",
        "type": "uint256"
      }
    ],
    "name": "InsufficientBuybackOutput",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidAddress",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidBatch",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidBuyback",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidConfiguration",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidPoolParameters",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidProtection",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "InvalidTicks",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LiquidityLocked",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "LiquidityPermanentlyLocked",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PositionMintNotConfirmed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PositionNotCreated",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "PriceOutsideTwap",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Reentrancy",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TokenCallFailed",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TwapObservationNotReady",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "Unauthorized",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "UnauthorizedBuybackCallback",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "BimoBurned",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "coordinator",
        "type": "address"
      }
    ],
    "name": "CoordinatorConfigured",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "FeesCollected",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "units",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "bimoUsed",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wethUsed",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "residualBimoBurned",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wethQueued",
        "type": "uint256"
      }
    ],
    "name": "LiquidityAdded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      }
    ],
    "name": "LpPermanentlyLocked",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [],
    "name": "PoolInitialized",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "unlockAt",
        "type": "uint256"
      }
    ],
    "name": "PositionCreated",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "uint256",
        "name": "tokenId",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint128",
        "name": "liquidity",
        "type": "uint128"
      },
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "PrincipalWithdrawn",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "UnexpectedEthSwept",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "wethAmount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "bimoAmount",
        "type": "uint256"
      }
    ],
    "name": "WethBuybackBurned",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "BATCH_BIMO",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "BATCH_ETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "BATCH_SIZE",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "BPS_DENOMINATOR",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "FULL_RANGE_TICK_LOWER",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "FULL_RANGE_TICK_UPPER",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_BIMO_PER_ETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_PRICE_BIMO_IS_TOKEN0",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "INITIAL_PRICE_BIMO_IS_TOKEN1",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_BUYBACK_WETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_EXECUTION_DEADLINE_DELAY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MAX_TWAP_TICK_DEVIATION",
    "outputs": [
      {
        "internalType": "uint24",
        "name": "",
        "type": "uint24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "MIN_BUYBACK_WETH",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "PERMIT2_EXPIRATION",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "POST_INITIAL_LIQUIDITY_TWAP_DELAY",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "TWAP_WINDOW",
    "outputs": [
      {
        "internalType": "uint32",
        "name": "",
        "type": "uint32"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "ethAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "bimoAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "units",
        "type": "uint256"
      },
      {
        "components": [
          {
            "internalType": "uint128",
            "name": "liquidity",
            "type": "uint128"
          },
          {
            "internalType": "uint128",
            "name": "amount0Max",
            "type": "uint128"
          },
          {
            "internalType": "uint128",
            "name": "amount1Max",
            "type": "uint128"
          },
          {
            "internalType": "uint128",
            "name": "amount0MinUsed",
            "type": "uint128"
          },
          {
            "internalType": "uint128",
            "name": "amount1MinUsed",
            "type": "uint128"
          },
          {
            "internalType": "uint256",
            "name": "deadline",
            "type": "uint256"
          }
        ],
        "internalType": "struct IBIMOV4LiquidityLocker.LiquidityProtection",
        "name": "protection",
        "type": "tuple"
      }
    ],
    "name": "addLiquidity",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "bSingleSigner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "bimo",
    "outputs": [
      {
        "internalType": "contract IBimoToken",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "expectedAmount",
        "type": "uint256"
      }
    ],
    "name": "burnLaunchBimo",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "wethAmount",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "minBimoOut",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "buybackAndBurn",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "burned",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "collectFees",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "coordinator_",
        "type": "address"
      }
    ],
    "name": "configureCoordinator",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "coordinator",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "deployer",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "firstLiquidityAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "globalUnlockAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "initialSqrtPriceX96",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "",
        "type": "uint160"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "launch",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lockLpForever",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lpPermanentlyLocked",
    "outputs": [
      {
        "internalType": "bool",
        "name": "",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "officialHook",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "pendingBuybackWeth",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "permit2",
    "outputs": [
      {
        "internalType": "contract IAllowanceTransfer",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "poolKey",
    "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": "poolManager",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionManager",
    "outputs": [
      {
        "internalType": "contract IPositionManager",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "positionTokenId",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "recipient",
        "type": "address"
      }
    ],
    "name": "sweepUnexpectedEth",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tickLower",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "tickUpper",
    "outputs": [
      {
        "internalType": "int24",
        "name": "",
        "type": "int24"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalBimoBurned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalBuybackBimoBurned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalLpBimoAdded",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalLpEthAdded",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalResidualBimoBurned",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "totalWethBuyback",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "bytes",
        "name": "data",
        "type": "bytes"
      }
    ],
    "name": "unlockCallback",
    "outputs": [
      {
        "internalType": "bytes",
        "name": "",
        "type": "bytes"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "weth",
    "outputs": [
      {
        "internalType": "contract IWETH9",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "uint128",
        "name": "liquidity",
        "type": "uint128"
      },
      {
        "internalType": "uint128",
        "name": "amount0Min",
        "type": "uint128"
      },
      {
        "internalType": "uint128",
        "name": "amount1Min",
        "type": "uint128"
      },
      {
        "internalType": "uint256",
        "name": "deadline",
        "type": "uint256"
      }
    ],
    "name": "withdrawPrincipal",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

import {IBimoToken} from "./interfaces/IBimoToken.sol";
import {
    BalanceDelta,
    Currency,
    IAllowanceTransfer,
    IHooks,
    IPoolManager,
    IPositionManager,
    IStateView,
    IWETH9,
    PoolKey,
    V4Actions
} from "./interfaces/IUniswapV4.sol";
import {
    IBIMOV4LiquidityLocker,
    IBIMOExecutionCoordinator,
    IHookInitialization,
    ILaunchBurner,
    IOfficialBurnHook
} from "./interfaces/IBIMOV1.sol";
import {SafeTransfer} from "./utils/SafeTransfer.sol";
import {BIMOConstants} from "./BIMOConstants.sol";

/// @notice Immutable holder of the sole official Uniswap V4 position NFT.
contract BIMOV4LiquidityLocker is IBIMOV4LiquidityLocker, ILaunchBurner {
    using SafeTransfer for address;

    uint256 public constant BATCH_SIZE = BIMOConstants.BATCH_SIZE;
    uint256 public constant BATCH_ETH = BIMOConstants.BATCH_ETH;
    uint256 public constant BATCH_BIMO = BIMOConstants.BATCH_BIMO;
    uint256 public constant BPS_DENOMINATOR = BIMOConstants.BPS_DENOMINATOR;
    uint32 public constant TWAP_WINDOW = BIMOConstants.TWAP_WINDOW;
    uint256 public constant POST_INITIAL_LIQUIDITY_TWAP_DELAY =
        BIMOConstants.POST_INITIAL_LIQUIDITY_TWAP_DELAY;
    uint24 public constant MAX_TWAP_TICK_DEVIATION = BIMOConstants.MAX_TWAP_TICK_DEVIATION;
    uint256 public constant PERMIT2_EXPIRATION = type(uint48).max;
    uint256 public constant MAX_EXECUTION_DEADLINE_DELAY = BIMOConstants.MAX_EXECUTION_DEADLINE_DELAY;
    uint256 public constant MIN_BUYBACK_WETH = BIMOConstants.MIN_BUYBACK_WETH;
    uint256 public constant MAX_BUYBACK_WETH = BATCH_ETH;
    uint256 public constant INITIAL_BIMO_PER_ETH = BIMOConstants.INITIAL_BIMO_PER_ETH;
    int24 public constant FULL_RANGE_TICK_LOWER = BIMOConstants.FULL_RANGE_TICK_LOWER;
    int24 public constant FULL_RANGE_TICK_UPPER = BIMOConstants.FULL_RANGE_TICK_UPPER;
    uint160 public constant INITIAL_PRICE_BIMO_IS_TOKEN0 = BIMOConstants.INITIAL_PRICE_BIMO_IS_TOKEN0;
    uint160 public constant INITIAL_PRICE_BIMO_IS_TOKEN1 = BIMOConstants.INITIAL_PRICE_BIMO_IS_TOKEN1;
    uint160 private constant MIN_SQRT_PRICE_LIMIT_X96 = 4_295_128_740;
    uint160 private constant MAX_SQRT_PRICE_LIMIT_X96 = 1461446703485210103287273052203988822378723970341;

    IBimoToken public immutable bimo;
    IWETH9 public immutable weth;
    IAllowanceTransfer public immutable permit2;
    IPositionManager public immutable positionManager;
    address public immutable poolManager;
    address public immutable launch;
    address public immutable officialHook;
    address public immutable bSingleSigner;
    PoolKey private _poolKey;
    int24 public immutable tickLower;
    int24 public immutable tickUpper;
    uint160 public immutable initialSqrtPriceX96;

    address public deployer;
    address public coordinator;
    uint256 public positionTokenId;
    uint256 public firstLiquidityAt;
    uint256 public globalUnlockAt;
    uint256 public totalBimoBurned;
    uint256 public totalLpEthAdded;
    uint256 public totalLpBimoAdded;
    uint256 public totalResidualBimoBurned;
    uint256 public pendingBuybackWeth;
    uint256 public totalWethBuyback;
    uint256 public totalBuybackBimoBurned;
    bool public lpPermanentlyLocked;
    uint256 private _entered;
    bool private _buybackActive;

    error Unauthorized();
    error Reentrancy();
    error InvalidAddress();
    error InvalidPoolParameters();
    error InvalidTicks();
    error InvalidBatch();
    error InvalidProtection();
    error DeadlineExpired();
    error DeadlineTooFar();
    error PositionMintNotConfirmed();
    error InsufficientAssetUsed(uint256 used, uint256 minimum);
    error UnauthorizedBuybackCallback();
    error InsufficientBuybackOutput(uint256 received, uint256 minimum);
    error InvalidBuyback();
    error LiquidityLocked();
    error LiquidityPermanentlyLocked();
    error PositionNotCreated();
    error DirectEthDisabled();
    error CoordinatorAlreadyConfigured();
    error InvalidConfiguration();
    error TwapObservationNotReady();
    error PriceOutsideTwap();

    event CoordinatorConfigured(address indexed coordinator);
    event PoolInitialized();
    event PositionCreated(uint256 indexed tokenId, uint256 unlockAt);
    event LiquidityAdded(
        uint256 indexed tokenId,
        uint256 indexed units,
        uint256 bimoUsed,
        uint256 wethUsed,
        uint256 residualBimoBurned,
        uint256 wethQueued
    );
    event FeesCollected(uint256 indexed tokenId, address indexed recipient);
    event PrincipalWithdrawn(uint256 indexed tokenId, uint128 liquidity, address indexed recipient);
    event LpPermanentlyLocked(uint256 indexed tokenId);
    event BimoBurned(uint256 amount);
    event WethBuybackBurned(uint256 wethAmount, uint256 bimoAmount);
    event UnexpectedEthSwept(address indexed recipient, uint256 amount);

    modifier onlyB() {
        if (msg.sender != bSingleSigner) revert Unauthorized();
        _;
    }

    modifier onlyLaunch() {
        if (msg.sender != launch) revert Unauthorized();
        _;
    }

    modifier onlyCoordinator() {
        if (msg.sender != coordinator) revert Unauthorized();
        _;
    }

    modifier nonReentrant() {
        if (_entered != 0) revert Reentrancy();
        _entered = 1;
        _;
        _entered = 0;
    }

    constructor(
        address bimo_,
        address weth_,
        address permit2_,
        address positionManager_,
        address poolManager_,
        address hook_,
        address launch_,
        address bSingleSigner_,
        int24 tickLower_,
        int24 tickUpper_,
        uint160 initialSqrtPriceX96_
    ) {
        if (
            bimo_ == address(0) || weth_ == address(0) || permit2_ == address(0)
                || positionManager_ == address(0) || poolManager_ == address(0) || hook_ == address(0)
                || launch_ == address(0) || bSingleSigner_ == address(0)
        ) revert InvalidAddress();
        if (
            bimo_ == weth_ || weth_.code.length == 0 || permit2_.code.length == 0
                || positionManager_.code.length == 0 || poolManager_.code.length == 0 || hook_.code.length == 0
        ) revert InvalidAddress();
        uint160 expectedInitialPrice =
            bimo_ < weth_ ? INITIAL_PRICE_BIMO_IS_TOKEN0 : INITIAL_PRICE_BIMO_IS_TOKEN1;
        if (
            tickLower_ != FULL_RANGE_TICK_LOWER || tickUpper_ != FULL_RANGE_TICK_UPPER
                || initialSqrtPriceX96_ != expectedInitialPrice
        ) revert InvalidTicks();
        if (
            IOfficialBurnHook(hook_).poolManager() != poolManager_ || IOfficialBurnHook(hook_).bimo() != bimo_
                || IOfficialBurnHook(hook_).expectedSqrtPriceX96() != initialSqrtPriceX96_
                || IOfficialBurnHook(hook_).currency0() != (bimo_ < weth_ ? bimo_ : weth_)
                || IOfficialBurnHook(hook_).currency1() != (bimo_ < weth_ ? weth_ : bimo_)
                || IOfficialBurnHook(hook_).stateView().code.length == 0
                || IStateView(IOfficialBurnHook(hook_).stateView()).poolManager() != poolManager_
        ) revert InvalidPoolParameters();
        bimo = IBimoToken(bimo_);
        weth = IWETH9(weth_);
        permit2 = IAllowanceTransfer(permit2_);
        positionManager = IPositionManager(positionManager_);
        poolManager = poolManager_;
        launch = launch_;
        officialHook = hook_;
        bSingleSigner = bSingleSigner_;
        tickLower = tickLower_;
        tickUpper = tickUpper_;
        initialSqrtPriceX96 = initialSqrtPriceX96_;

        (Currency currency0, Currency currency1) = bimo_ < weth_
            ? (Currency.wrap(bimo_), Currency.wrap(weth_))
            : (Currency.wrap(weth_), Currency.wrap(bimo_));
        _poolKey = PoolKey({
            currency0: currency0,
            currency1: currency1,
            fee: BIMOConstants.OFFICIAL_POOL_FEE,
            tickSpacing: BIMOConstants.OFFICIAL_POOL_TICK_SPACING,
            hooks: IHooks(hook_)
        });
        if (
            _poolKey.fee != BIMOConstants.OFFICIAL_POOL_FEE
                || _poolKey.tickSpacing != BIMOConstants.OFFICIAL_POOL_TICK_SPACING
        ) revert InvalidPoolParameters();
        deployer = msg.sender;
    }

    function poolKey() external view returns (PoolKey memory) {
        return _poolKey;
    }

    function configureCoordinator(address coordinator_) external {
        if (msg.sender != deployer) revert Unauthorized();
        if (coordinator != address(0)) revert CoordinatorAlreadyConfigured();
        if (coordinator_ == address(0) || coordinator_.code.length == 0) revert InvalidAddress();
        IBIMOExecutionCoordinator coordinatorContract = IBIMOExecutionCoordinator(coordinator_);
        if (coordinatorContract.launch() != launch || coordinatorContract.locker() != address(this)) {
            revert InvalidConfiguration();
        }
        coordinator = coordinator_;
        deployer = address(0);
        emit CoordinatorConfigured(coordinator_);
    }

    function addLiquidity(
        uint256 ethAmount,
        uint256 bimoAmount,
        uint256 units,
        LiquidityProtection calldata protection
    ) external onlyCoordinator nonReentrant {
        if (
            units == 0 || bimoAmount != units * BIMOConstants.LP_BIMO_PER_UNIT
                || ethAmount != units * BIMOConstants.LP_PRICE_PER_UNIT
        ) {
            revert InvalidBatch();
        }
        if (protection.liquidity == 0) revert InvalidProtection();
        _validateExecutionDeadline(protection.deadline);
        if (positionTokenId != 0) {
            if (block.timestamp < firstLiquidityAt + POST_INITIAL_LIQUIDITY_TWAP_DELAY) {
                revert TwapObservationNotReady();
            }
            if (
                !IOfficialBurnHook(address(_poolKey.hooks)).refreshAndCheckTwap(
                    TWAP_WINDOW, MAX_TWAP_TICK_DEVIATION
                )
            ) revert PriceOutsideTwap();
        }
        if (
            protection.amount0Max == 0 || protection.amount1Max == 0
                || protection.amount0MinUsed > protection.amount0Max
                || protection.amount1MinUsed > protection.amount1Max
        ) {
            revert InvalidProtection();
        }
        if (address(this).balance < ethAmount || bimo.balanceOf(address(this)) < bimoAmount) {
            revert InvalidBatch();
        }

        uint256 startingBimo = bimo.balanceOf(address(this));
        uint256 startingWeth = weth.balanceOf(address(this));
        weth.deposit{value: ethAmount}();
        _validateProtectionBounds(protection, ethAmount, bimoAmount);
        address(bimo).forceApprove(address(permit2), bimoAmount);
        address(weth).forceApprove(address(permit2), ethAmount);
        permit2.approve(
            address(bimo), address(positionManager), uint160(bimoAmount), uint48(PERMIT2_EXPIRATION)
        );
        permit2.approve(
            address(weth), address(positionManager), uint160(ethAmount), uint48(PERMIT2_EXPIRATION)
        );

        if (positionTokenId == 0) {
            if (!IHookInitialization(address(_poolKey.hooks)).poolInitialized()) {
                positionManager.initializePool(_poolKey, initialSqrtPriceX96);
                emit PoolInitialized();
            }
            uint256 expectedTokenId = positionManager.nextTokenId();
            positionManager.modifyLiquidities(
                _mintPayload(protection.liquidity, protection.amount0Max, protection.amount1Max),
                protection.deadline
            );
            if (positionManager.nextTokenId() <= expectedTokenId) revert PositionMintNotConfirmed();
            positionTokenId = expectedTokenId;
            firstLiquidityAt = block.timestamp;
            globalUnlockAt = firstLiquidityAt + BIMOConstants.LP_LOCK_DURATION;
            emit PositionCreated(expectedTokenId, globalUnlockAt);
        } else {
            positionManager.modifyLiquidities(
                _increasePayload(protection.liquidity, protection.amount0Max, protection.amount1Max),
                protection.deadline
            );
        }

        address(bimo).forceApprove(address(permit2), 0);
        address(weth).forceApprove(address(permit2), 0);
        permit2.approve(address(bimo), address(positionManager), 0, 0);
        permit2.approve(address(weth), address(positionManager), 0, 0);

        uint256 bimoAfterLiquidity = bimo.balanceOf(address(this));
        uint256 usedBimo = startingBimo - bimoAfterLiquidity;
        uint256 wethAfterLiquidity = weth.balanceOf(address(this));
        uint256 usedWeth = ethAmount - (wethAfterLiquidity - startingWeth);
        uint256 amount0Used = Currency.unwrap(_poolKey.currency0) == address(bimo) ? usedBimo : usedWeth;
        uint256 amount1Used = Currency.unwrap(_poolKey.currency1) == address(bimo) ? usedBimo : usedWeth;
        if (amount0Used < protection.amount0MinUsed) {
            revert InsufficientAssetUsed(amount0Used, protection.amount0MinUsed);
        }
        if (amount1Used < protection.amount1MinUsed) {
            revert InsufficientAssetUsed(amount1Used, protection.amount1MinUsed);
        }

        uint256 residualBimo = bimoAmount - usedBimo;
        uint256 wethQueued = ethAmount - usedWeth;
        _burnResidual(residualBimo);
        pendingBuybackWeth += wethQueued;
        totalLpEthAdded += usedWeth;
        totalLpBimoAdded += usedBimo;
        emit LiquidityAdded(positionTokenId, units, usedBimo, usedWeth, residualBimo, wethQueued);
    }

    function collectFees(uint256 deadline) external nonReentrant {
        if (msg.sender != coordinator && msg.sender != bSingleSigner) revert Unauthorized();
        if (positionTokenId == 0) revert PositionNotCreated();
        _validateExecutionDeadline(deadline);
        bytes memory actions =
            abi.encodePacked(uint8(V4Actions.DECREASE_LIQUIDITY), uint8(V4Actions.TAKE_PAIR));
        bytes[] memory params = new bytes[](2);
        params[0] = abi.encode(positionTokenId, uint256(0), uint128(0), uint128(0), bytes(""));
        params[1] = abi.encode(_poolKey.currency0, _poolKey.currency1, bSingleSigner);
        positionManager.modifyLiquidities(abi.encode(actions, params), deadline);
        emit FeesCollected(positionTokenId, bSingleSigner);
    }

    function buybackAndBurn(uint256 wethAmount, uint256 minBimoOut, uint256 deadline)
        external
        onlyCoordinator
        nonReentrant
        returns (uint256 burned)
    {
        if (
            wethAmount < MIN_BUYBACK_WETH || wethAmount > MAX_BUYBACK_WETH || wethAmount > pendingBuybackWeth
                || minBimoOut == 0
        ) revert InvalidBuyback();
        _validateExecutionDeadline(deadline);
        uint256 startingBimo = bimo.balanceOf(address(this));
        pendingBuybackWeth -= wethAmount;
        _buybackActive = true;
        IPoolManager(poolManager).unlock(abi.encode(wethAmount, minBimoOut));
        _buybackActive = false;
        uint256 bought = bimo.balanceOf(address(this)) - startingBimo;
        if (bought < minBimoOut) revert InsufficientBuybackOutput(bought, minBimoOut);
        burned = _burnBuyback(bought);
        totalWethBuyback += wethAmount;
        emit WethBuybackBurned(wethAmount, burned);
    }

    function withdrawPrincipal(uint128 liquidity, uint128 amount0Min, uint128 amount1Min, uint256 deadline)
        external
        onlyB
        nonReentrant
    {
        if (positionTokenId == 0) revert PositionNotCreated();
        if (block.timestamp < globalUnlockAt) revert LiquidityLocked();
        if (lpPermanentlyLocked) revert LiquidityPermanentlyLocked();
        if (liquidity == 0 || block.timestamp > deadline) revert InvalidProtection();
        bytes memory actions =
            abi.encodePacked(uint8(V4Actions.DECREASE_LIQUIDITY), uint8(V4Actions.TAKE_PAIR));
        bytes[] memory params = new bytes[](2);
        params[0] = abi.encode(positionTokenId, liquidity, amount0Min, amount1Min, bytes(""));
        params[1] = abi.encode(_poolKey.currency0, _poolKey.currency1, bSingleSigner);
        positionManager.modifyLiquidities(abi.encode(actions, params), deadline);
        emit PrincipalWithdrawn(positionTokenId, liquidity, bSingleSigner);
    }

    function lockLpForever() external onlyB {
        if (positionTokenId == 0) revert PositionNotCreated();
        if (block.timestamp < globalUnlockAt) revert LiquidityLocked();
        if (lpPermanentlyLocked) revert LiquidityPermanentlyLocked();
        lpPermanentlyLocked = true;
        emit LpPermanentlyLocked(positionTokenId);
    }

    function burnLaunchBimo(uint256 expectedAmount) external onlyLaunch nonReentrant returns (uint256) {
        uint256 amount = bimo.balanceOf(address(this));
        if (amount < expectedAmount) revert InvalidBatch();
        return _burn(expectedAmount);
    }

    function sweepUnexpectedEth(address recipient) external onlyB nonReentrant returns (uint256 amount) {
        if (recipient != bSingleSigner) revert InvalidAddress();
        amount = address(this).balance;
        if (amount == 0) return 0;
        (bool sent,) = recipient.call{value: amount}("");
        if (!sent) revert InvalidConfiguration();
        emit UnexpectedEthSwept(recipient, amount);
    }

    function unlockCallback(bytes calldata data) external returns (bytes memory) {
        if (msg.sender != poolManager || !_buybackActive) revert UnauthorizedBuybackCallback();
        (uint256 wethAmount, uint256 minimum) = abi.decode(data, (uint256, uint256));
        bool wethIsCurrency0 = Currency.unwrap(_poolKey.currency0) == address(weth);
        BalanceDelta delta = IPoolManager(poolManager).swap(
            _poolKey,
            IPoolManager.SwapParams({
                zeroForOne: wethIsCurrency0,
                amountSpecified: -int256(wethAmount),
                sqrtPriceLimitX96: wethIsCurrency0 ? MIN_SQRT_PRICE_LIMIT_X96 + 1 : MAX_SQRT_PRICE_LIMIT_X96 - 1
            }),
            bytes("")
        );
        int128 bimoDelta = Currency.unwrap(_poolKey.currency0) == address(bimo)
            ? int128(BalanceDelta.unwrap(delta) >> 128)
            : int128(BalanceDelta.unwrap(delta));
        if (bimoDelta <= 0) revert InsufficientBuybackOutput(0, minimum);
        uint256 bimoAmount = uint256(uint128(bimoDelta));
        if (bimoAmount < minimum) revert InsufficientBuybackOutput(bimoAmount, minimum);
        IPoolManager(poolManager).sync(Currency.wrap(address(weth)));
        address(weth).safeTransfer(poolManager, wethAmount);
        IPoolManager(poolManager).settle();
        IPoolManager(poolManager).take(Currency.wrap(address(bimo)), address(this), bimoAmount);
        return bytes("");
    }

    function _mintPayload(uint128 liquidity, uint128 amount0Max, uint128 amount1Max)
        private
        view
        returns (bytes memory)
    {
        bytes memory actions = abi.encodePacked(
            uint8(V4Actions.MINT_POSITION),
            uint8(V4Actions.SETTLE_PAIR),
            uint8(V4Actions.CLOSE_CURRENCY),
            uint8(V4Actions.CLOSE_CURRENCY)
        );
        bytes[] memory params = new bytes[](4);
        params[0] = abi.encode(
            _poolKey, tickLower, tickUpper, liquidity, amount0Max, amount1Max, address(this), bytes("")
        );
        params[1] = abi.encode(_poolKey.currency0, _poolKey.currency1);
        params[2] = abi.encode(_poolKey.currency0);
        params[3] = abi.encode(_poolKey.currency1);
        return abi.encode(actions, params);
    }

    function _increasePayload(uint128 liquidity, uint128 amount0Max, uint128 amount1Max)
        private
        view
        returns (bytes memory)
    {
        bytes memory actions = abi.encodePacked(
            uint8(V4Actions.INCREASE_LIQUIDITY),
            uint8(V4Actions.SETTLE_PAIR),
            uint8(V4Actions.CLOSE_CURRENCY),
            uint8(V4Actions.CLOSE_CURRENCY)
        );
        bytes[] memory params = new bytes[](4);
        params[0] = abi.encode(positionTokenId, liquidity, amount0Max, amount1Max, bytes(""));
        params[1] = abi.encode(_poolKey.currency0, _poolKey.currency1);
        params[2] = abi.encode(_poolKey.currency0);
        params[3] = abi.encode(_poolKey.currency1);
        return abi.encode(actions, params);
    }

    function _burn(uint256 amount) private returns (uint256) {
        if (amount != 0) {
            bimo.burn(amount);
            totalBimoBurned += amount;
            emit BimoBurned(amount);
        }
        return amount;
    }

    function _burnResidual(uint256 amount) private {
        if (amount != 0) {
            _burn(amount);
            totalResidualBimoBurned += amount;
        }
    }

    function _burnBuyback(uint256 amount) private returns (uint256) {
        if (amount != 0) {
            _burn(amount);
            totalBuybackBimoBurned += amount;
        }
        return amount;
    }

    function _validateProtectionBounds(
        LiquidityProtection calldata protection,
        uint256 ethAmount,
        uint256 bimoAmount
    ) private view {
        uint256 bimoMax = Currency.unwrap(_poolKey.currency0) == address(bimo)
            ? protection.amount0Max
            : protection.amount1Max;
        uint256 wethMax = Currency.unwrap(_poolKey.currency0) == address(weth)
            ? protection.amount0Max
            : protection.amount1Max;
        if (bimoMax > bimoAmount || wethMax > ethAmount) revert InvalidProtection();
    }

    function _validateExecutionDeadline(uint256 deadline) private view {
        if (block.timestamp > deadline) revert DeadlineExpired();
        if (deadline - block.timestamp > MAX_EXECUTION_DEADLINE_DELAY) revert DeadlineTooFar();
    }

    receive() external payable {
        if (msg.sender != launch && msg.sender != address(weth)) revert DirectEthDisabled();
    }
}
Chain explorer7385msChain node82ms