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
- Creator
- 0xBD556B6244…EE291dF893
- 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