Abstract Testnet

Contract

0x9A0Ab7367d57dce66a28eE96bBABF7b6962d7d4e

Overview

ETH Balance

0 ETH

Multichain Info

N/A
Transaction Hash
Method
Block
From
To

There are no matching entries

9 Internal Transactions found.

Latest 9 internal transactions

Parent Transaction Hash Block From To
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
 Contract Creation0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
51929432025-01-26 20:51:374 days ago1737924697
0x9A0Ab736...6962d7d4e
0 ETH
49765162025-01-24 0:12:307 days ago1737677550
0x9A0Ab736...6962d7d4e
0 ETH
49765162025-01-24 0:12:307 days ago1737677550  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
g8keepLockerFactory

Compiler Version
v0.8.26+commit.8a97fa7a

ZkSolc Version
v1.5.7

Optimization Enabled:
Yes with Mode 3

Other Settings:
cancun EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 11 : g8keepLockerFactory.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {INonfungiblePositionManager} from "./interfaces/INonfungiblePositionManager.sol";
import {IG8keepLockerFactory} from "./interfaces/IG8keepLockerFactory.sol";
import {g8keepLiquidityLocker} from "./g8keepLiquidityLocker.sol";
import {Ownable} from "solady/auth/Ownable.sol";

/**
 * @title   g8keepLockerFactory
 * @notice  Factory contract for deploying liquidity locker contracts.
 */
contract g8keepLockerFactory is Ownable, IG8keepLockerFactory {
    /// @dev Emitted when a liquidity locker is deployed.
    event LockerDeployed(
        address indexed lockerAddress, address indexed owner, uint256 lpTokenId, uint256 durationSeconds
    );

    /// @dev Constant value for the max BPS value.
    uint16 private constant BPS = 10_000;

    /// @dev Address of the Uniswap V3 position manager.
    INonfungiblePositionManager public immutable UNISWAP_POSITION_MANAGER;
    /// @dev Address of the g8keep fee collector.
    address public feeCollector;
    /// @dev Amount of time, in seconds, that liquidity positions will be locked.
    uint64 public lockDuration = 75 * 365 days;
    /// @dev Amount of LP fees, in BPS, that will be allocated to g8keep.
    uint16 public lpFeesCut = 6_000; // 60%

    /// @dev Thrown when a supplied address that must be non-zero is zero.
    error ZeroAddress();
    /// @dev Thrown when a locker fails to deploy.
    error LockerFailedToDeploy();
    /// @dev Thrown when a setting is supplied that is invalid.
    error InvalidSettings();

    constructor(address _defaultOwner, address _feeCollector, INonfungiblePositionManager _uniswapPositionManager) {
        _initializeOwner(_defaultOwner);
        feeCollector = _feeCollector;
        UNISWAP_POSITION_MANAGER = _uniswapPositionManager;
    }

    /**
     * @notice  Deploys a new liquidity locker for a Uniswap V3 position.
     * 
     * @dev     Locker factory must have approval to transfer the LP token.
     *
     * @param lpTokenId    ID of the LP token to be locked.
     * @param beneficiary  Address of the wallet that will own the LP locker and receive fees.
     * @param feeWallet    Address of the g8keep fee wallet that will receive g8keep fees.
     *
     * @return lpLocker  Address of the deployed LP locker.
     */
    function deploy(uint256 lpTokenId, address beneficiary, address feeWallet) external returns (address lpLocker) {
        uint256 _lockDuration = lockDuration;
        lpLocker = address(
            new g8keepLiquidityLocker(
                UNISWAP_POSITION_MANAGER, lpTokenId, beneficiary, _lockDuration, lpFeesCut, feeWallet
            )
        );

        if (lpLocker == address(0)) {
            revert LockerFailedToDeploy();
        }

        UNISWAP_POSITION_MANAGER.transferFrom(msg.sender, lpLocker, lpTokenId);

        emit LockerDeployed(lpLocker, beneficiary, lpTokenId, _lockDuration);
    }

    /**
     * @notice  Admin function to update the LP locker settings.
     * 
     * @param _feeCollector  Address of the account that is allowed to initiate fee collection on behalf of g8keep.
     * @param _lockDuration  Time, in seconds, that LP positions will be locked.
     * @param _lpFeesCut     Fee rate, in BPS, that will be allocated to g8keep.
     */
    function setLockerSettings(address _feeCollector, uint64 _lockDuration, uint16 _lpFeesCut) external onlyOwner {
        if (_lpFeesCut > BPS) revert InvalidSettings();
        if (_feeCollector == address(0)) {
            revert ZeroAddress();
        }

        feeCollector = _feeCollector;
        lockDuration = _lockDuration;
        lpFeesCut = _lpFeesCut;
    }
}

File 2 of 11 : INonfungiblePositionManager.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./IPoolInitializer.sol";
import "./IPeripheryImmutableState.sol";

/// @title Non-fungible token for positions
/// @notice Wraps Uniswap V3 positions in a non-fungible token interface which allows for them to be transferred
/// and authorized.
interface INonfungiblePositionManager is IERC721, IPoolInitializer, IPeripheryImmutableState {
    /// @notice Emitted when liquidity is increased for a position NFT
    /// @dev Also emitted when a token is minted
    /// @param tokenId The ID of the token for which liquidity was increased
    /// @param liquidity The amount by which liquidity for the NFT position was increased
    /// @param amount0 The amount of token0 that was paid for the increase in liquidity
    /// @param amount1 The amount of token1 that was paid for the increase in liquidity
    event IncreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
    /// @notice Emitted when liquidity is decreased for a position NFT
    /// @param tokenId The ID of the token for which liquidity was decreased
    /// @param liquidity The amount by which liquidity for the NFT position was decreased
    /// @param amount0 The amount of token0 that was accounted for the decrease in liquidity
    /// @param amount1 The amount of token1 that was accounted for the decrease in liquidity
    event DecreaseLiquidity(uint256 indexed tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);
    /// @notice Emitted when tokens are collected for a position NFT
    /// @dev The amounts reported may not be exactly equivalent to the amounts transferred, due to rounding behavior
    /// @param tokenId The ID of the token for which underlying tokens were collected
    /// @param recipient The address of the account that received the collected tokens
    /// @param amount0 The amount of token0 owed to the position that was collected
    /// @param amount1 The amount of token1 owed to the position that was collected
    event Collect(uint256 indexed tokenId, address recipient, uint256 amount0, uint256 amount1);

    /// @notice Returns the position information associated with a given token ID.
    /// @dev Throws if the token ID is not valid.
    /// @param tokenId The ID of the token that represents the position
    /// @return nonce The nonce for permits
    /// @return operator The address that is approved for spending
    /// @return token0 The address of the token0 for a specific pool
    /// @return token1 The address of the token1 for a specific pool
    /// @return fee The fee associated with the pool
    /// @return tickLower The lower end of the tick range for the position
    /// @return tickUpper The higher end of the tick range for the position
    /// @return liquidity The liquidity of the position
    /// @return feeGrowthInside0LastX128 The fee growth of token0 as of the last action on the individual position
    /// @return feeGrowthInside1LastX128 The fee growth of token1 as of the last action on the individual position
    /// @return tokensOwed0 The uncollected amount of token0 owed to the position as of the last computation
    /// @return tokensOwed1 The uncollected amount of token1 owed to the position as of the last computation
    function positions(uint256 tokenId)
        external
        view
        returns (
            uint96 nonce,
            address operator,
            address token0,
            address token1,
            uint24 fee,
            int24 tickLower,
            int24 tickUpper,
            uint128 liquidity,
            uint256 feeGrowthInside0LastX128,
            uint256 feeGrowthInside1LastX128,
            uint128 tokensOwed0,
            uint128 tokensOwed1
        );

    struct MintParams {
        address token0;
        address token1;
        uint24 fee;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
        uint256 deadline;
    }

    /// @notice Creates a new position wrapped in a NFT
    /// @dev Call this when the pool does exist and is initialized. Note that if the pool is created but not initialized
    /// a method does not exist, i.e. the pool is assumed to be initialized.
    /// @param params The params necessary to mint a position, encoded as `MintParams` in calldata
    /// @return tokenId The ID of the token that represents the minted position
    /// @return liquidity The amount of liquidity for this position
    /// @return amount0 The amount of token0
    /// @return amount1 The amount of token1
    function mint(MintParams calldata params)
        external
        payable
        returns (uint256 tokenId, uint128 liquidity, uint256 amount0, uint256 amount1);

    struct IncreaseLiquidityParams {
        uint256 tokenId;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        uint256 deadline;
    }

    /// @notice Increases the amount of liquidity in a position, with tokens paid by the `msg.sender`
    /// @param params tokenId The ID of the token for which liquidity is being increased,
    /// amount0Desired The desired amount of token0 to be spent,
    /// amount1Desired The desired amount of token1 to be spent,
    /// amount0Min The minimum amount of token0 to spend, which serves as a slippage check,
    /// amount1Min The minimum amount of token1 to spend, which serves as a slippage check,
    /// deadline The time by which the transaction must be included to effect the change
    /// @return liquidity The new liquidity amount as a result of the increase
    /// @return amount0 The amount of token0 to acheive resulting liquidity
    /// @return amount1 The amount of token1 to acheive resulting liquidity
    function increaseLiquidity(IncreaseLiquidityParams calldata params)
        external
        payable
        returns (uint128 liquidity, uint256 amount0, uint256 amount1);

    struct DecreaseLiquidityParams {
        uint256 tokenId;
        uint128 liquidity;
        uint256 amount0Min;
        uint256 amount1Min;
        uint256 deadline;
    }

    /// @notice Decreases the amount of liquidity in a position and accounts it to the position
    /// @param params tokenId The ID of the token for which liquidity is being decreased,
    /// amount The amount by which liquidity will be decreased,
    /// amount0Min The minimum amount of token0 that should be accounted for the burned liquidity,
    /// amount1Min The minimum amount of token1 that should be accounted for the burned liquidity,
    /// deadline The time by which the transaction must be included to effect the change
    /// @return amount0 The amount of token0 accounted to the position's tokens owed
    /// @return amount1 The amount of token1 accounted to the position's tokens owed
    function decreaseLiquidity(DecreaseLiquidityParams calldata params)
        external
        payable
        returns (uint256 amount0, uint256 amount1);

    struct CollectParams {
        uint256 tokenId;
        address recipient;
        uint128 amount0Max;
        uint128 amount1Max;
    }

    /// @notice Collects up to a maximum amount of fees owed to a specific position to the recipient
    /// @param params tokenId The ID of the NFT for which tokens are being collected,
    /// recipient The account that should receive the tokens,
    /// amount0Max The maximum amount of token0 to collect,
    /// amount1Max The maximum amount of token1 to collect
    /// @return amount0 The amount of fees collected in token0
    /// @return amount1 The amount of fees collected in token1
    function collect(CollectParams calldata params) external payable returns (uint256 amount0, uint256 amount1);

    /// @notice Burns a token ID, which deletes it from the NFT contract. The token must have 0 liquidity and all tokens
    /// must be collected first.
    /// @param tokenId The ID of the token that is being burned
    function burn(uint256 tokenId) external payable;
}

File 3 of 11 : IG8keepLockerFactory.sol
//SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.26;

interface IG8keepLockerFactory {
    function deploy(uint256 lpTokenId, address beneficiary, address feeWallet) external returns (address lpLocker);
}

File 4 of 11 : g8keepLiquidityLocker.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import {Ownable} from "solady/auth/Ownable.sol";
import {SafeTransferLib} from "solady/utils/SafeTransferLib.sol";
import {INonfungiblePositionManager} from "./interfaces/INonfungiblePositionManager.sol";
import {g8keepLockerFactory} from "./g8keepLockerFactory.sol";

/**
 * @title   g8keepLiquidityLocker
 * @notice  Locks a liquidity position for a Uniswap V3 pool while allowing
 * @notice  fees to be collected and split between g8keep and the deployer.
 */
contract g8keepLiquidityLocker is Ownable {
    /// @dev Emitted when a liquidity token is locked.
    event LiquidityLocked(uint256 tokenId, uint256 duration);
    /// @dev Emitted when the liquidity token is released.
    event LiquidityReleased(uint256 tokenId);
    /// @dev Emitted when liquidity fees are collected.
    event ClaimedFees(
        address indexed claimer,
        address indexed token0,
        address indexed token1,
        uint256 amount0,
        uint256 amount1
    );

    /// @dev Constant value for the max BPS value.
    uint16 private constant BPS = 10_000;
    /// @dev Timestamp that vesting of the liquidity position ends.
    uint256 public immutable VESTING_END;
    /// @dev Address of the Uniswap V3 position manager.
    INonfungiblePositionManager immutable UNISWAP_POSITION_MANAGER;
    /// @dev g8keep fee percentage of liquidity fees in BPS.
    uint16 public immutable G8KEEP_FEE;
    /// @dev Token ID for the LP token that is locked.
    uint256 public immutable LP_TOKEN_ID;
    /// @dev Address of the locker factory that deployed the liquidity locker.
    g8keepLockerFactory public immutable LOCKER_FACTORY;
    /// @dev Address of the g8keep fee wallet that receives g8keep fees from liquidity fees.
    address public g8keepFeeWallet;

    /// @dev Thrown when attempting to withdraw the locked LP token before vesting has ended.
    error NotVested();
    /// @dev Thrown when a caller is not allowed for the function they are calling.
    error InvalidCaller();

    /**
     * @dev Creates the liquidity locker for the given LP token.
     */
    constructor(
        INonfungiblePositionManager _uniswapPositionManager,
        uint256 lpTokenId,
        address beneficiary,
        uint256 durationSeconds,
        uint16 fee,
        address feeWallet
    ) {
        _initializeOwner(beneficiary);

        UNISWAP_POSITION_MANAGER = _uniswapPositionManager;
        unchecked {
            if (block.timestamp + durationSeconds < block.timestamp) {
                VESTING_END = type(uint256).max;
            } else {
                VESTING_END = block.timestamp + durationSeconds;
            }
        }
        G8KEEP_FEE = fee;
        g8keepFeeWallet = feeWallet;
        LOCKER_FACTORY = g8keepLockerFactory(msg.sender);
        LP_TOKEN_ID = lpTokenId;

        emit LiquidityLocked(lpTokenId, durationSeconds);
    }

    /**
     * @notice  Collects fees and transfers the LP token to the owner.
     * 
     * @dev     Cannot be called before the vesting period expires.
     * @dev     Emits a `LiquidityReleased` event.
     */
    function release() external onlyOwner {
        if (block.timestamp < VESTING_END) {
            revert NotVested();
        }
        collectFees();

        UNISWAP_POSITION_MANAGER.transferFrom(address(this), msg.sender, LP_TOKEN_ID);
        emit LiquidityReleased(LP_TOKEN_ID);
    }

    /**
     * @notice  Withdraws an ERC721 token from the contract to the owner.
     * 
     * @dev     If the token address is the Uniswap position manager, the tokenId cannot be 
     * @dev     the locked LP token.
     *
     * @param _token    Address of the token to withdraw.
     * @param _tokenId  ID of the token to withdraw.
     */
    function withdrawNFT(address _token, uint256 _tokenId) external onlyOwner {
        if (_token == address(UNISWAP_POSITION_MANAGER) && _tokenId == LP_TOKEN_ID) {
            revert NotVested();
        }
        IERC721(_token).transferFrom(address(this), msg.sender, _tokenId);
    }

    /**
     * @notice  Withdraws an ERC20 token from the contract to the owner.
     *
     * @dev     The token address cannot be the Uniswap position manager.
     *
     * @param _token    Address of the token to withdraw.
     */
    function withdrawERC20(address _token) external onlyOwner {
        if (_token == address(UNISWAP_POSITION_MANAGER)) revert NotVested();
        SafeTransferLib.safeTransferAll(_token, msg.sender);
    }

    /**
     * @notice  Withdraws ETH that is in the contract to the owner.
     */
    function withdrawETH() external onlyOwner {
        SafeTransferLib.safeTransferAllETH(msg.sender);
    }

    /**
     * @notice  Updates the g8keep fee wallet address.
     * 
     * @dev     Caller must be the current fee wallet address.
     * 
     * @param _newFeeWallet  Address to set as the new fee wallet recipient.
     */
    function updateFeeWallet(address _newFeeWallet) external {
        if (msg.sender != g8keepFeeWallet) {
            revert InvalidCaller();
        }

        g8keepFeeWallet = _newFeeWallet;
    }

    /**
     * @notice  Collects fees from the locked LP token. Fees are split between the locker owner and g8keep.
     * 
     * @dev     Caller must be the locker owner, locker factory fee collector or locker factory owner.
     * @dev     Emits a `ClaimedFees` event for each recipient of fees.
     */
    function collectFees() public {
        address _owner = owner();
        address _g8keepFeeRecipient = g8keepFeeWallet;
        if (msg.sender != _owner) {
            if (msg.sender != LOCKER_FACTORY.feeCollector()) {
                if (msg.sender != LOCKER_FACTORY.owner()) {
                    revert InvalidCaller();
                }
            }
        }

        (,, address token0, address token1,,,,,,,,) = UNISWAP_POSITION_MANAGER.positions(LP_TOKEN_ID);

        if (G8KEEP_FEE == 0) {
            (uint256 amount0, uint256 amount1) = UNISWAP_POSITION_MANAGER.collect(
                INonfungiblePositionManager.CollectParams({
                    recipient: _owner,
                    amount0Max: type(uint128).max,
                    amount1Max: type(uint128).max,
                    tokenId: LP_TOKEN_ID
                })
            );

            emit ClaimedFees(_owner, token0, token1, amount0, amount1);
        } else {
            (uint256 amount0, uint256 amount1) = UNISWAP_POSITION_MANAGER.collect(
                INonfungiblePositionManager.CollectParams({
                    recipient: address(this),
                    amount0Max: type(uint128).max,
                    amount1Max: type(uint128).max,
                    tokenId: LP_TOKEN_ID
                })
            );


            uint256 protocolFee0 = (amount0 * G8KEEP_FEE) / BPS;
            uint256 protocolFee1 = (amount1 * G8KEEP_FEE) / BPS;

            uint256 recipientFee0 = amount0 - protocolFee0;
            uint256 recipientFee1 = amount1 - protocolFee1;

            SafeTransferLib.safeTransfer(token0, _owner, recipientFee0);
            SafeTransferLib.safeTransfer(token1, _owner, recipientFee1);

            SafeTransferLib.safeTransfer(token0, _g8keepFeeRecipient, protocolFee0);
            SafeTransferLib.safeTransfer(token1, _g8keepFeeRecipient, protocolFee1);

            emit ClaimedFees(_owner, token0, token1, recipientFee0, recipientFee1);
            emit ClaimedFees(_g8keepFeeRecipient, token0, token1, protocolFee0, protocolFee1);
        }
    }

    /**
     * @dev Returns the amount of time left on the liquidity vesting.
     */
    function vestingSchedule() external view returns (uint256) {
        unchecked {
            if (block.timestamp > VESTING_END) {
                return 0;
            } else {
                return VESTING_END - block.timestamp;
            }
        }
    }

    /**
     * @dev Allow contract to receive ETH.
     */
    receive() external payable {}
}

File 5 of 11 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

File 6 of 11 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC-721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC-721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC-721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 7 of 11 : IPoolInitializer.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.7.5;
pragma abicoder v2;

/// @title Creates and initializes V3 Pools
/// @notice Provides a method for creating and initializing a pool, if necessary, for bundling with other methods that
/// require the pool to exist.
interface IPoolInitializer {
    /// @notice Creates a new pool if it does not exist, then initializes if not initialized
    /// @dev This method can be bundled with others via IMulticall for the first action (e.g. mint) performed against a pool
    /// @param token0 The contract address of token0 of the pool
    /// @param token1 The contract address of token1 of the pool
    /// @param fee The fee amount of the v3 pool for the specified token pair
    /// @param sqrtPriceX96 The initial square root price of the pool as a Q64.96 value
    /// @return pool Returns the pool address based on the pair of tokens and fee, will return the newly created pool address if necessary
    function createAndInitializePoolIfNecessary(address token0, address token1, uint24 fee, uint160 sqrtPriceX96)
        external
        payable
        returns (address pool);
}

File 8 of 11 : IPeripheryImmutableState.sol
// SPDX-License-Identifier: GPL-2.0-or-later
pragma solidity >=0.5.0;

/// @title Immutable state
/// @notice Functions that return immutable state of the router
interface IPeripheryImmutableState {
    /// @return Returns the address of the Uniswap V3 factory
    function factory() external view returns (address);

    /// @return Returns the address of WETH9
    function WETH9() external view returns (address);
}

File 9 of 11 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-20 standard as defined in the ERC.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 value) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 value) external returns (bool);
}

File 10 of 11 : SafeTransferLib.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Safe ETH and ERC20 transfer library that gracefully handles missing return values.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SafeTransferLib.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SafeTransferLib.sol)
/// @author Permit2 operations from (https://github.com/Uniswap/permit2/blob/main/src/libraries/Permit2Lib.sol)
///
/// @dev Note:
/// - For ETH transfers, please use `forceSafeTransferETH` for DoS protection.
library SafeTransferLib {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ETH transfer has failed.
    error ETHTransferFailed();

    /// @dev The ERC20 `transferFrom` has failed.
    error TransferFromFailed();

    /// @dev The ERC20 `transfer` has failed.
    error TransferFailed();

    /// @dev The ERC20 `approve` has failed.
    error ApproveFailed();

    /// @dev The ERC20 `totalSupply` query has failed.
    error TotalSupplyQueryFailed();

    /// @dev The Permit2 operation has failed.
    error Permit2Failed();

    /// @dev The Permit2 amount must be less than `2**160 - 1`.
    error Permit2AmountOverflow();

    /// @dev The Permit2 approve operation has failed.
    error Permit2ApproveFailed();

    /// @dev The Permit2 lockdown operation has failed.
    error Permit2LockdownFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Suggested gas stipend for contract receiving ETH that disallows any storage writes.
    uint256 internal constant GAS_STIPEND_NO_STORAGE_WRITES = 2300;

    /// @dev Suggested gas stipend for contract receiving ETH to perform a few
    /// storage reads and writes, but low enough to prevent griefing.
    uint256 internal constant GAS_STIPEND_NO_GRIEF = 100000;

    /// @dev The unique EIP-712 domain domain separator for the DAI token contract.
    bytes32 internal constant DAI_DOMAIN_SEPARATOR =
        0xdbb8cf42e1ecb028be3f3dbc922e1d878b963f411dc388ced501601c60f7c6f7;

    /// @dev The address for the WETH9 contract on Ethereum mainnet.
    address internal constant WETH9 = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2;

    /// @dev The canonical Permit2 address.
    /// [Github](https://github.com/Uniswap/permit2)
    /// [Etherscan](https://etherscan.io/address/0x000000000022D473030F116dDEE9F6B43aC78BA3)
    address internal constant PERMIT2 = 0x000000000022D473030F116dDEE9F6B43aC78BA3;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ETH OPERATIONS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants.
    //
    // The regular variants:
    // - Forwards all remaining gas to the target.
    // - Reverts if the target reverts.
    // - Reverts if the current contract has insufficient balance.
    //
    // The force variants:
    // - Forwards with an optional gas stipend
    //   (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases).
    // - If the target reverts, or if the gas stipend is exhausted,
    //   creates a temporary contract to force send the ETH via `SELFDESTRUCT`.
    //   Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758.
    // - Reverts if the current contract has insufficient balance.
    //
    // The try variants:
    // - Forwards with a mandatory gas stipend.
    // - Instead of reverting, returns whether the transfer succeeded.

    /// @dev Sends `amount` (in wei) ETH to `to`.
    function safeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gas(), to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`.
    function safeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // Transfer all the ETH and check if it succeeded or not.
            if iszero(call(gas(), to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function forceSafeTransferAllETH(address to, uint256 gasStipend) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferETH(address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            if lt(selfbalance(), amount) {
                mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`.
                revert(0x1c, 0x04)
            }
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, amount, codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(amount, 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`.
    function forceSafeTransferAllETH(address to) internal {
        /// @solidity memory-safe-assembly
        assembly {
            // forgefmt: disable-next-item
            if iszero(call(GAS_STIPEND_NO_GRIEF, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)) {
                mstore(0x00, to) // Store the address in scratch space.
                mstore8(0x0b, 0x73) // Opcode `PUSH20`.
                mstore8(0x20, 0xff) // Opcode `SELFDESTRUCT`.
                if iszero(create(selfbalance(), 0x0b, 0x16)) { revert(codesize(), codesize()) } // For gas estimation.
            }
        }
    }

    /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`.
    function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, amount, codesize(), 0x00, codesize(), 0x00)
        }
    }

    /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`.
    function trySafeTransferAllETH(address to, uint256 gasStipend)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            success := call(gasStipend, to, selfbalance(), codesize(), 0x00, codesize(), 0x00)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC20 OPERATIONS                      */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for
    /// the current contract to manage.
    function safeTransferFrom(address token, address from, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function trySafeTransferFrom(address token, address from, address to, uint256 amount)
        internal
        returns (bool success)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                success := lt(or(iszero(extcodesize(token)), returndatasize()), success)
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends all of ERC20 `token` from `from` to `to`.
    /// Reverts upon failure.
    ///
    /// The `from` account must have their entire balance approved for the current contract to manage.
    function safeTransferAllFrom(address token, address from, address to)
        internal
        returns (uint256 amount)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x40, to) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20)
                )
            ) {
                mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`.
            amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x7939f424) // `TransferFromFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransfer(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sends all of ERC20 `token` from the current contract to `to`.
    /// Reverts upon failure.
    function safeTransferAll(address token, address to) internal returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`.
            mstore(0x20, address()) // Store the address of the current contract.
            // Read the balance, reverting upon failure.
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                    staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20)
                )
            ) {
                mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                revert(0x1c, 0x04)
            }
            mstore(0x14, to) // Store the `to` argument.
            amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it.
            mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`.
            // Perform the transfer, reverting upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x90b8ec18) // `TransferFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// Reverts upon failure.
    function safeApprove(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                    revert(0x1c, 0x04)
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract.
    /// If the initial attempt to approve fails, attempts to reset the approved amount to zero,
    /// then retries the approval again (some tokens, e.g. USDT, requires this).
    /// Reverts upon failure.
    function safeApproveWithRetry(address token, address to, uint256 amount) internal {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, to) // Store the `to` argument.
            mstore(0x34, amount) // Store the `amount` argument.
            mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
            // Perform the approval, retrying upon failure.
            let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
            if iszero(and(eq(mload(0x00), 1), success)) {
                if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                    mstore(0x34, 0) // Store 0 for the `amount`.
                    mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`.
                    pop(call(gas(), token, 0, 0x10, 0x44, codesize(), 0x00)) // Reset the approval.
                    mstore(0x34, amount) // Store back the original `amount`.
                    // Retry the approval, reverting upon failure.
                    success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20)
                    if iszero(and(eq(mload(0x00), 1), success)) {
                        // Check the `extcodesize` again just in case the token selfdestructs lol.
                        if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) {
                            mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`.
                            revert(0x1c, 0x04)
                        }
                    }
                }
            }
            mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten.
        }
    }

    /// @dev Returns the amount of ERC20 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Returns the total supply of the `token`.
    /// Reverts if the token does not exist or does not implement `totalSupply()`.
    function totalSupply(address token) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, 0x18160ddd) // `totalSupply()`.
            if iszero(
                and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20))
            ) {
                mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`.
                revert(0x1c, 0x04)
            }
            result := mload(0x00)
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to`.
    /// If the initial attempt fails, try to use Permit2 to transfer the token.
    /// Reverts upon failure.
    ///
    /// The `from` account must have at least `amount` approved for the current contract to manage.
    function safeTransferFrom2(address token, address from, address to, uint256 amount) internal {
        if (!trySafeTransferFrom(token, from, to, amount)) {
            permit2TransferFrom(token, from, to, amount);
        }
    }

    /// @dev Sends `amount` of ERC20 `token` from `from` to `to` via Permit2.
    /// Reverts upon failure.
    function permit2TransferFrom(address token, address from, address to, uint256 amount)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x74), shr(96, shl(96, token)))
            mstore(add(m, 0x54), amount)
            mstore(add(m, 0x34), to)
            mstore(add(m, 0x20), shl(96, from))
            // `transferFrom(address,address,uint160,address)`.
            mstore(m, 0x36c78516000000000000000000000000)
            let p := PERMIT2
            let exists := eq(chainid(), 1)
            if iszero(exists) { exists := iszero(iszero(extcodesize(p))) }
            if iszero(
                and(
                    call(gas(), p, 0, add(m, 0x10), 0x84, codesize(), 0x00),
                    lt(iszero(extcodesize(token)), exists) // Token has code and Permit2 exists.
                )
            ) {
                mstore(0x00, 0x7939f4248757f0fd) // `TransferFromFailed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(iszero(shr(160, amount))))), 0x04)
            }
        }
    }

    /// @dev Permit a user to spend a given amount of
    /// another user's tokens via native EIP-2612 permit if possible, falling
    /// back to Permit2 if native permit fails or is not implemented on the token.
    function permit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        bool success;
        /// @solidity memory-safe-assembly
        assembly {
            for {} shl(96, xor(token, WETH9)) {} {
                mstore(0x00, 0x3644e515) // `DOMAIN_SEPARATOR()`.
                if iszero(
                    and( // The arguments of `and` are evaluated from right to left.
                        lt(iszero(mload(0x00)), eq(returndatasize(), 0x20)), // Returns 1 non-zero word.
                        // Gas stipend to limit gas burn for tokens that don't refund gas when
                        // an non-existing function is called. 5K should be enough for a SLOAD.
                        staticcall(5000, token, 0x1c, 0x04, 0x00, 0x20)
                    )
                ) { break }
                // After here, we can be sure that token is a contract.
                let m := mload(0x40)
                mstore(add(m, 0x34), spender)
                mstore(add(m, 0x20), shl(96, owner))
                mstore(add(m, 0x74), deadline)
                if eq(mload(0x00), DAI_DOMAIN_SEPARATOR) {
                    mstore(0x14, owner)
                    mstore(0x00, 0x7ecebe00000000000000000000000000) // `nonces(address)`.
                    mstore(
                        add(m, 0x94),
                        lt(iszero(amount), staticcall(gas(), token, 0x10, 0x24, add(m, 0x54), 0x20))
                    )
                    mstore(m, 0x8fcbaf0c000000000000000000000000) // `IDAIPermit.permit`.
                    // `nonces` is already at `add(m, 0x54)`.
                    // `amount != 0` is already stored at `add(m, 0x94)`.
                    mstore(add(m, 0xb4), and(0xff, v))
                    mstore(add(m, 0xd4), r)
                    mstore(add(m, 0xf4), s)
                    success := call(gas(), token, 0, add(m, 0x10), 0x104, codesize(), 0x00)
                    break
                }
                mstore(m, 0xd505accf000000000000000000000000) // `IERC20Permit.permit`.
                mstore(add(m, 0x54), amount)
                mstore(add(m, 0x94), and(0xff, v))
                mstore(add(m, 0xb4), r)
                mstore(add(m, 0xd4), s)
                success := call(gas(), token, 0, add(m, 0x10), 0xe4, codesize(), 0x00)
                break
            }
        }
        if (!success) simplePermit2(token, owner, spender, amount, deadline, v, r, s);
    }

    /// @dev Simple permit on the Permit2 contract.
    function simplePermit2(
        address token,
        address owner,
        address spender,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0x927da105) // `allowance(address,address,address)`.
            {
                let addressMask := shr(96, not(0))
                mstore(add(m, 0x20), and(addressMask, owner))
                mstore(add(m, 0x40), and(addressMask, token))
                mstore(add(m, 0x60), and(addressMask, spender))
                mstore(add(m, 0xc0), and(addressMask, spender))
            }
            let p := mul(PERMIT2, iszero(shr(160, amount)))
            if iszero(
                and( // The arguments of `and` are evaluated from right to left.
                    gt(returndatasize(), 0x5f), // Returns 3 words: `amount`, `expiration`, `nonce`.
                    staticcall(gas(), p, add(m, 0x1c), 0x64, add(m, 0x60), 0x60)
                )
            ) {
                mstore(0x00, 0x6b836e6b8757f0fd) // `Permit2Failed()` or `Permit2AmountOverflow()`.
                revert(add(0x18, shl(2, iszero(p))), 0x04)
            }
            mstore(m, 0x2b67b570) // `Permit2.permit` (PermitSingle variant).
            // `owner` is already `add(m, 0x20)`.
            // `token` is already at `add(m, 0x40)`.
            mstore(add(m, 0x60), amount)
            mstore(add(m, 0x80), 0xffffffffffff) // `expiration = type(uint48).max`.
            // `nonce` is already at `add(m, 0xa0)`.
            // `spender` is already at `add(m, 0xc0)`.
            mstore(add(m, 0xe0), deadline)
            mstore(add(m, 0x100), 0x100) // `signature` offset.
            mstore(add(m, 0x120), 0x41) // `signature` length.
            mstore(add(m, 0x140), r)
            mstore(add(m, 0x160), s)
            mstore(add(m, 0x180), shl(248, v))
            if iszero( // Revert if token does not have code, or if the call fails.
            mul(extcodesize(token), call(gas(), p, 0, add(m, 0x1c), 0x184, codesize(), 0x00))) {
                mstore(0x00, 0x6b836e6b) // `Permit2Failed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Approves `spender` to spend `amount` of `token` for `address(this)`.
    function permit2Approve(address token, address spender, uint160 amount, uint48 expiration)
        internal
    {
        /// @solidity memory-safe-assembly
        assembly {
            let addressMask := shr(96, not(0))
            let m := mload(0x40)
            mstore(m, 0x87517c45) // `approve(address,address,uint160,uint48)`.
            mstore(add(m, 0x20), and(addressMask, token))
            mstore(add(m, 0x40), and(addressMask, spender))
            mstore(add(m, 0x60), and(addressMask, amount))
            mstore(add(m, 0x80), and(0xffffffffffff, expiration))
            if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
                mstore(0x00, 0x324f14ae) // `Permit2ApproveFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Revokes an approval for `token` and `spender` for `address(this)`.
    function permit2Lockdown(address token, address spender) internal {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(m, 0xcc53287f) // `Permit2.lockdown`.
            mstore(add(m, 0x20), 0x20) // Offset of the `approvals`.
            mstore(add(m, 0x40), 1) // `approvals.length`.
            mstore(add(m, 0x60), shr(96, shl(96, token)))
            mstore(add(m, 0x80), shr(96, shl(96, spender)))
            if iszero(call(gas(), PERMIT2, 0, add(m, 0x1c), 0xa0, codesize(), 0x00)) {
                mstore(0x00, 0x96b3de23) // `Permit2LockdownFailed()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 11 of 11 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

/**
 * @dev Interface of the ERC-165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[ERC].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[ERC section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "viaIR": false,
  "codegen": "yul",
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/",
    "solmate/=lib/solmate/src/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/"
  ],
  "evmVersion": "cancun",
  "outputSelection": {
    "*": {
      "*": [
        "abi",
        "metadata"
      ],
      "": [
        "ast"
      ]
    }
  },
  "optimizer": {
    "enabled": true,
    "mode": "3",
    "fallback_to_optimizing_for_size": false,
    "disable_system_request_memoization": true
  },
  "metadata": {},
  "libraries": {},
  "enableEraVMExtensions": false,
  "forceEVMLA": false
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"_defaultOwner","type":"address"},{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"contract INonfungiblePositionManager","name":"_uniswapPositionManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"InvalidSettings","type":"error"},{"inputs":[],"name":"LockerFailedToDeploy","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"lockerAddress","type":"address"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"durationSeconds","type":"uint256"}],"name":"LockerDeployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[],"name":"UNISWAP_POSITION_MANAGER","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"lpTokenId","type":"uint256"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"feeWallet","type":"address"}],"name":"deploy","outputs":[{"internalType":"address","name":"lpLocker","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"feeCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDuration","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lpFeesCut","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeCollector","type":"address"},{"internalType":"uint64","name":"_lockDuration","type":"uint64"},{"internalType":"uint16","name":"_lpFeesCut","type":"uint16"}],"name":"setLockerSettings","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]

0000000000000000000000004df78e3a20c706d10c31e8d25d0a14c3b730770a000000000000000000000000b20c44d202743cbcc393d67af242ceb3fd4177ad000000000000000000000000069f199763c045a294c7913e64ba80e5f362a5d7

Deployed Bytecode

0x000200000000000200090000000000020000006003100270000000b50330019700010000003103550000000100200190000000450000c13d0000008002000039000000400020043f000000040030008c000002160000413d000000000201043b000000e002200270000000c00020009c000000910000a13d000000c10020009c000000a70000a13d000000c20020009c000000cd0000213d000000c50020009c000000e20000613d000000c60020009c000002160000c13d000000240030008c000002160000413d0000000401100370000000000301043b000000b80030009c000002160000213d000000bb01000041000000000101041a0000000002000411000000000012004b000001be0000c13d000000d1010000410000000c0010043f000000000030043f0000000001000414000000b50010009c000000b501008041000000c001100210000000d5011001c70000801002000039000700000003001d02ce02c90000040f0000000100200190000002160000613d000000000101043b000500000001001d000000000101041a000600000001001d000000d60100004100000000001004430000000001000414000000b50010009c000000b501008041000000c001100210000000d7011001c70000800b0200003902ce02c90000040f0000000100200190000002180000613d000000000101043b000000060010006c000001e60000a13d000000d801000041000000000010043f000000d401000041000002d0000104300000000002000416000000000002004b000002160000c13d0000001f02300039000000b602200197000000a002200039000000400020043f0000001f0430018f000000b705300198000000a002500039000000560000613d000000a006000039000000000701034f000000007807043c0000000006860436000000000026004b000000520000c13d000000000004004b000000630000613d000000000151034f0000000304400210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000600030008c000002160000413d000000a00600043d000000b80060009c000002160000213d000000c00200043d000000b80020009c000002160000213d000000e00300043d000000b80030009c000002160000213d000000000100041a000000b901100197000000ba011001c7000000000010041b000000bb01000041000000000061041b0000000001000414000000b50010009c000000b501008041000000c001100210000000bc011001c7000700000002001d0000800d02000039000600000003001d0000000303000039000000bd04000041000000000500001902ce02c40000040f000000060300002900000001002001900000000702000029000002160000613d000000000100041a000000be01100197000000000121019f000000000010041b000000800030043f000001400000044300000160003004430000002001000039000001000010044300000001010000390000012000100443000000bf01000041000002cf0001042e000000ca0020009c000000b20000213d000000ce0020009c000000ff0000613d000000cf0020009c000001890000613d000000d00020009c000002160000c13d0000000001000416000000000001004b000002160000c13d0000000001000412000900000001001d000800000000003d000080050100003900000044030000390000000004000415000000090440008a0000000504400210000000e10200004102ce02a60000040f0000010d0000013d000000c70020009c000001080000613d000000c80020009c000001110000613d000000c90020009c000002160000c13d0000000001000416000000000001004b000002160000c13d000000000100041a0000010d0000013d000000cb0020009c000001600000613d000000cc0020009c000001b50000613d000000cd0020009c000002160000c13d000000bb01000041000000000501041a0000000001000411000000000051004b000001be0000c13d0000000001000414000000b50010009c000000b501008041000000c001100210000000bc011001c70000800d020000390000000303000039000000bd04000041000000000600001902ce02c40000040f0000000100200190000002160000613d000000bb01000041000000000001041b0000000001000019000002cf0001042e000000c30020009c000001780000613d000000c40020009c000002160000c13d000000240030008c000002160000413d0000000002000416000000000002004b000002160000c13d0000000401100370000000000101043b000000b80010009c000002160000213d000000d1020000410000000c0020043f000000000010043f02ce02990000040f000000000101041a000000800010043f000000d201000041000002cf0001042e000000640030008c000002160000413d0000000002000416000000000002004b000002160000c13d0000000402100370000000000202043b000000b80020009c000002160000213d0000002403100370000000000303043b000000d90030009c000002160000213d0000004401100370000000000101043b0000ffff0010008c000002160000213d000000bb04000041000000000404041a0000000005000411000000000045004b000001be0000c13d0000ffff0410018f000027110040008c000001ec0000413d000000df01000041000000000010043f000000de01000041000002d0000104300000000001000416000000000001004b000002160000c13d000000000100041a000000a001100270000000d901100197000000800010043f000000d201000041000002cf0001042e0000000001000416000000000001004b000002160000c13d000000bb01000041000000000101041a000000b801100197000000800010043f000000d201000041000002cf0001042e000000640030008c000002160000413d0000000002000416000000000002004b000002160000c13d0000000402100370000000000302043b0000002402100370000000000202043b000000b80020009c000002160000213d0000004401100370000000000101043b000000b80010009c000002160000213d000400000001001d000500000002001d000700000003001d000000000100041a000600000001001d000000e001000041000000a40010043f000000e10100004100000000001004430000000001000412000000040010044300000024000004430000000001000414000000b50010009c000000b501008041000000c001100210000000e2011001c7000080050200003902ce02c90000040f0000000100200190000002180000613d0000000502000029000000b8042001970000000402000029000000b8022001970000000605000029000000a003500270000000d903300197000000000101043b000000b801100197000500000001001d000001040010043f0000000701000029000001240010043f000400000004001d000001440040043f000300000003001d000001640030043f000000e0015002700000ffff0110018f000001840010043f000001a40020043f000000e3010000410000000002000414000000800010043f000000840000043f0000006001000039000000c40010043f000000c001000039000000e40010043f000000b50020009c000000b502008041000000c001200210000000e4011001c7000080060200003902ce02c40000040f0000000100200190000001c20000613d000000000101043b000000000001004b000001f20000c13d00000001010003670000000002000031000001c60000013d000000d1010000410000000c0010043f0000000001000411000000000010043f0000000001000414000000b50010009c000000b501008041000000c001100210000000d5011001c7000080100200003902ce02c90000040f0000000100200190000002160000613d000000000101043b000000000001041b0000000001000414000000b50010009c000000b501008041000000c001100210000000bc011001c70000800d020000390000000203000039000000f104000041000001af0000013d000000240030008c000002160000413d0000000401100370000000000101043b000000b80010009c000002160000213d000000bb02000041000000000202041a0000000003000411000000000023004b000001be0000c13d000000000001004b000001e90000c13d000000d301000041000000000010043f000000d401000041000002d000010430000000d1010000410000000c0010043f0000000001000411000000000010043f000000d60100004100000000001004430000000001000414000000b50010009c000000b501008041000000c001100210000000d7011001c70000800b0200003902ce02c90000040f0000000100200190000002180000613d000000000101043b000700000001001d0000000001000414000000b50010009c000000b501008041000000c001100210000000d5011001c7000080100200003902ce02c90000040f0000000100200190000002160000613d000000000101043b0000000702000029000000f20220009a000000000021041b0000000001000414000000b50010009c000000b501008041000000c001100210000000bc011001c70000800d020000390000000203000039000000f304000041000000000500041102ce02c40000040f0000000100200190000002160000613d0000000001000019000002cf0001042e0000000001000416000000000001004b000002160000c13d000000000100041a000000e0011002700000ffff0110018f000000800010043f000000d201000041000002cf0001042e000000f001000041000000000010043f000000d401000041000002d00001043000010000000103550000006002100270000000b50020019d000000b502200197000000f4052001980000001f0620018f000000400300043d0000000004530019000001d10000613d000000000701034f0000000008030019000000007907043c0000000008980436000000000048004b000001cd0000c13d000000000006004b000001de0000613d000000000151034f0000000305600210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000b50020009c000000b5020080410000006001200210000000b50030009c000000b5030080410000004002300210000000000112019f000002d0000104300000000501000029000000000001041b000000070100002902ce02820000040f0000000001000019000002cf0001042e000000000002004b000001f80000c13d000000dd01000041000000000010043f000000de01000041000002d000010430000000b801100198000002040000c13d000000ef01000041000000000010043f000000de01000041000002d000010430000000e001100210000000da01100197000000a003300210000000db03300197000000000113019f000000000300041a000000dc03300197000000000131019f000000000121019f000000000010041b0000000001000019000002cf0001042e000600000001001d000000e5010000410000000000100443000000050100002900000004001004430000000001000414000000b50010009c000000b501008041000000c001100210000000e6011001c7000080020200003902ce02c90000040f0000000100200190000002180000613d000000000101043b000000000001004b0000000702000029000002190000c13d0000000001000019000002d000010430000000000001042f000000400300043d00000044013000390000000000210435000000240130003900000006020000290000000000210435000000e7010000410000000001130436000100000001001d000200000003001d00000004013000390000000002000411000000000021043500000000010004140000000502000029000000040020008c0000023a0000613d0000000202000029000000b50020009c000000b5020080410000004002200210000000b50010009c000000b501008041000000c001100210000000000121019f000000e8011001c7000000050200002902ce02c40000040f0000006003100270000000b50030019d00010000000103550000000100200190000002630000613d0000000201000029000000e90010009c000002430000413d000000ed01000041000000000010043f0000004101000039000000040010043f000000ee01000041000002d0000104300000000202000029000000400020043f00000003010000290000000103000029000000000013043500000007010000290000000000120435000000b50020009c000000b50200804100000040012002100000000002000414000000b50020009c000000b502008041000000c002200210000000000112019f000000ea011001c70000800d020000390000000303000039000000eb040000410000000605000029000000040600002902ce02c40000040f0000000100200190000002160000613d000000400100043d00000006020000290000000000210435000000b50010009c000000b5010080410000004001100210000000ec011001c7000002cf0001042e000000b5033001970000001f0530018f000000b706300198000000400200043d00000000046200190000026f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000026b0000c13d000000000005004b0000027c0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000006001300210000000b50020009c000000b5020080410000004002200210000000000112019f000002d0000104300001000000000002000000bb02000041000000000502041a0000000002000414000000b806100197000000b50020009c000000b502008041000000c001200210000000bc011001c70000800d020000390000000303000039000000bd04000041000100000006001d02ce02c40000040f0000000100200190000002960000613d000000bb010000410000000102000029000000000021041b000000000001042d0000000001000019000002d000010430000000000001042f0000000001000414000000b50010009c000000b501008041000000c001100210000000d5011001c7000080100200003902ce02c90000040f0000000100200190000002a40000613d000000000101043b000000000001042d0000000001000019000002d00001043000000000050100190000000000200443000000050030008c000002b40000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b000002ac0000413d000000b50030009c000000b50300804100000060013002100000000002000414000000b50020009c000000b502008041000000c002200210000000000112019f000000f5011001c7000000000205001902ce02c90000040f0000000100200190000002c30000613d000000000101043b000000000001042d000000000001042f000002c7002104210000000102000039000000000001042d0000000002000019000000000001042d000002cc002104230000000102000039000000000001042d0000000002000019000000000001042d000002ce00000432000002cf0001042e000002d00001043000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffff00000000000000000000ffffffffffffffffffffffffffffffffffffffff00001770000000008cfa16800000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392702000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ffffffffffffffffffffffff00000000000000000000000000000000000000000000000200000000000000000000000000000080000001000000000000000000000000000000000000000000000000000000000000000000000000008da5cb5a00000000000000000000000000000000000000000000000000000000d850aa8a00000000000000000000000000000000000000000000000000000000f2fde38a00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000d850aa8b00000000000000000000000000000000000000000000000000000000f04e283e000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000009442fd6200000000000000000000000000000000000000000000000000000000c415b95c0000000000000000000000000000000000000000000000000000000054d1f13c0000000000000000000000000000000000000000000000000000000054d1f13d0000000000000000000000000000000000000000000000000000000057aa020100000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000000455444300000000000000000000000000000000000000000000000000000000256929620000000000000000000000000000000000000000000000000000000051f1889900000000000000000000000000000000000000000000000000000000389a75e10000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c000000000000000002000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000006f5e8818000000000000000000000000000000000000000000000000ffffffffffffffff0000ffff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff0000000000000000000000000000000000000000ffff000000000000000000000000000000000000000000000000000000000000d92e233d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000e591f33d0000000000000000000000000000000000000000000000000000000001000285cc6ce9b7fbd22ce0eb47b70aeb06f4a482881a1b7a2591741531c936310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000009c4d535bdea7cd8a978f128b93471df48c7dbab89d703809115bdc118c235bfd02000000000000000000000000000000000001440000008000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b83020000020000000000000000000000000000002400000000000000000000000023b872dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000000000001000000000000000002000000000000000000000000000000000000400000000000000000000000008c9faa2a823b28da2916270ab1de36db5fc6f3a130561852c8ac553416e64f6200000000000000000000000000000000000000200000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000002f713b29000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082b42900fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe00200000200000000000000000000000000000000000000000000000000000000f2afcbe99f4c61b9de7e81ffc8db19298aece8b207f6f6cc728bbd1bf06ab391

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000030000000000000000000000004df78e3a20c706d10c31e8d25d0a14c3b730770a000000000000000000000000b20c44d202743cbcc393d67af242ceb3fd4177ad000000000000000000000000069f199763c045a294c7913e64ba80e5f362a5d7

-----Decoded View---------------
Arg [0] : _defaultOwner (address): 0x0000000000000000000000000000000000000020
Arg [1] : _feeCollector (address): 0x0000000000000000000000000000000000000003
Arg [2] : _uniswapPositionManager (address): 0x4Df78e3A20c706D10C31e8D25D0a14c3B730770A

-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [2] : 0000000000000000000000004df78e3a20c706d10c31e8d25d0a14c3b730770a
Arg [3] : 000000000000000000000000b20c44d202743cbcc393d67af242ceb3fd4177ad
Arg [4] : 000000000000000000000000069f199763c045a294c7913e64ba80e5f362a5d7


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.