ETH Price: $1,973.76 (-2.75%)
 

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Retrieve ETH234707892025-09-29 19:38:47154 days ago1759174727IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000114861.91887245
Deploy Token233447392025-09-12 4:58:11172 days ago1757653091IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.001557810.24579469
Deploy Token233378082025-09-11 5:43:11173 days ago1757569391IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.001624170.25626223
Deploy Token233376462025-09-11 5:10:23173 days ago1757567423IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.001339930.21139143
Deploy Token229281092025-07-16 0:16:35230 days ago1752624995IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.014224972.24456717
Deploy Token229279832025-07-15 23:51:11230 days ago1752623471IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.012829652.02387972
Deploy Token228359842025-07-03 3:22:23243 days ago1751512943IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.002556940.40341636
Predict Token Ad...228093942025-06-29 10:09:47247 days ago1751191787IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000014230.37255108
Predict Token Ad...227600872025-06-22 12:49:47254 days ago1750596587IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.00003941.03131133
Predict Token Ad...226691982025-06-09 19:47:35266 days ago1749498455IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000097682.50856277
Deploy Token226272092025-06-03 22:48:47272 days ago1748990927IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.007137671.12608477
Retrieve ETH226259332025-06-03 18:31:35272 days ago1748975495IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000148524.58825774
Deploy Token226257522025-06-03 17:55:23273 days ago1748973323IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.026448824.17295455
Deploy Token226195942025-06-02 21:14:35273 days ago1748898875IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.028669494.52344134
Retrieve ETH226193232025-06-02 20:20:11273 days ago1748895611IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000165045.09869855
Deploy Token225980482025-05-30 20:51:11276 days ago1748638271IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.011524631.81829602
Deploy Token225976122025-05-30 19:23:35276 days ago1748633015IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.01132461.78679037
Retrieve ETH225621442025-05-25 20:13:59281 days ago1748204039IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000034231.05704886
Deploy Token225618672025-05-25 19:17:59281 days ago1748200679IN
0x2DE4bA2b...22D8Bdaa6
0.01 ETH0.005498250.86834981
Collect Fees225521782025-05-24 10:42:59283 days ago1748083379IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000259080.70398974
Retrieve ETH225521552025-05-24 10:38:23283 days ago1748083103IN
0x2DE4bA2b...22D8Bdaa6
0 ETH0.000042021.29823326
Deploy Token225519732025-05-24 10:01:47283 days ago1748080907IN
0x2DE4bA2b...22D8Bdaa6
0.0102 ETH0.003466450.54307356

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Transfer234707892025-09-29 19:38:47154 days ago1759174727
0x2DE4bA2b...22D8Bdaa6
0.0686 ETH
0x60806040233447392025-09-12 4:58:11172 days ago1757653091
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer233447392025-09-12 4:58:11172 days ago1757653091
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040233378082025-09-11 5:43:11173 days ago1757569391
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer233378082025-09-11 5:43:11173 days ago1757569391
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040233376462025-09-11 5:10:23173 days ago1757567423
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer233376462025-09-11 5:10:23173 days ago1757567423
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040229281092025-07-16 0:16:35230 days ago1752624995
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer229281092025-07-16 0:16:35230 days ago1752624995
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040229279832025-07-15 23:51:11230 days ago1752623471
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer229279832025-07-15 23:51:11230 days ago1752623471
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040228359842025-07-03 3:22:23243 days ago1751512943
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer228359842025-07-03 3:22:23243 days ago1751512943
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040226272092025-06-03 22:48:47272 days ago1748990927
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer226272092025-06-03 22:48:47272 days ago1748990927
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
Transfer226259332025-06-03 18:31:35272 days ago1748975495
0x2DE4bA2b...22D8Bdaa6
0.0196 ETH
0x60806040226257522025-06-03 17:55:23273 days ago1748973323
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer226257522025-06-03 17:55:23273 days ago1748973323
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040226195942025-06-02 21:14:35273 days ago1748898875
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer226195942025-06-02 21:14:35273 days ago1748898875
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
Transfer226193232025-06-02 20:20:11273 days ago1748895611
0x2DE4bA2b...22D8Bdaa6
0.0196 ETH
0x60806040225980482025-05-30 20:51:11276 days ago1748638271
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer225980482025-05-30 20:51:11276 days ago1748638271
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
0x60806040225976122025-05-30 19:23:35276 days ago1748633015
0x2DE4bA2b...22D8Bdaa6
 Contract Creation0 ETH
Transfer225976122025-05-30 19:23:35276 days ago1748633015
0x2DE4bA2b...22D8Bdaa6
0.0002 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
KOAToLockerV5

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {Pausable} from "@openzeppelin/contracts/security/Pausable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "./NFTAutoLockerV5.sol";
import "./libraries/TickMath.sol";
import {Token} from "./token.sol";
import "./Interface.sol";

// GoPlus Locker Interface
interface IUniV3LPLocker {
    struct FeeStruct {
        string name;
        uint256 lpFee;
        uint256 collectFee;
        uint256 lockFee;
        address lockFeeToken;
    }
    
    function lock(
        address nftManager_,
        uint256 nftId_,
        address owner_,
        address collector_,
        uint256 endTime_,
        string memory feeName_
    ) external payable returns (uint256 lockId);
    
    function getFee(string memory name_) external view returns (FeeStruct memory);
    function isSupportedFeeName(string memory name_) external view returns(bool);
}

/**
 * @title KING OF APES
 * @dev BBB
 *
 * _  _______ _   _  _____    ____  ______            _____  ______  _____ 
 *| |/ /_   _| \ | |/ ____|  / __ \|  ____|     /\   |  __ \|  ____|/ ____|
 *| ' /  | | |  \| | |  __  | |  | | |__       /  \  | |__) | |__  | (___  
 *|  <   | | | . ` | | |_ | | |  | |  __|     / /\ \ |  ___/|  __|  \___ \ 
 *| . \ _| |_| |\  | |__| | | |__| | |       / ____ \| |    | |____ ____) |
 *|_|\_\_____|_| \_|\_____|  \____/|_|      /_/    \_\_|    |______|_____/ 
 *                                                                        
 *
 */

contract KOAToLockerV5 is Ownable, Pausable {
    // Deployment parameters struct to avoid stack too deep
    struct DeploymentParams {
        string name;
        string symbol;
        uint256 supply;
        int24 initialTick;
        uint24 fee;
        address feeRecipient;
        address recipient;
        uint256 recipientAmount;
    }
    
    // NFTAutoLockerV5 contract address
    address payable public nftLocker;
    
    // GoPlus Locker contract address
    address public goPlusLocker;
    
    // State variables that were in KOAToWallet
    address public taxCollector;
    address public weth;
    IUniswapV3Factory public uniswapV3Factory;
    INonfungiblePositionManager public positionManager;
    address public swapRouter;
    
    // Define the required recipient address (where fees go)
    address public constant REQUIRED_RECIPIENT = 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926;
    
    // Fee constants
    uint256 public constant MINIMUM_DEPLOYMENT_FEE = 0.01 ether; // 0.01 ETH minimum
    uint256 public constant PROTOCOL_FEE = 0.0002 ether; // 0.0002 ETH protocol fee
    
    // Debug events
    event DebugStep(string step);
    event DebugValues(string name, uint256 value);
    event DebugAddress(string name, address addr);
    event DebugIntValues(string name, int256 value);
    event SaltGeneration(uint256 attempts, bytes32 salt);
    
    // Retrieve function events
    event ETHRetrieved(address recipient, uint256 amount);
    event ERC20Retrieved(address tokenAddress, address recipient, uint256 amount);
    
    // Fee events
    event DeploymentFeeCollected(uint256 totalFee, uint256 protocolFee, uint256 remainingForSwap);
    event ProtocolFeeTransferred(address recipient, uint256 amount);
    
    // Pause events
    event ContractPaused(address indexed by);
    event ContractUnpaused(address indexed by);
    
    // Event for token deployment with locker
    event TokenCreatedWithLocker(
        address tokenAddress,
        uint256 lpNftId,
        address deployer,
        string name,
        string symbol,
        uint256 supply,
        address recipient,
        uint256 recipientAmount,
        address lockerAddress,
        address feeRecipient
    );
    
    // GoPlus locking events
    event NFTLockedInGoPlus(uint256 nftId, uint256 goPlusLockId, uint256 endTime);
    event GoPlusLockerUpdated(address oldLocker, address newLocker);
    
    /**
     * @dev Constructor that includes all necessary parameters
     * @param taxCollector_ Address that receives the tax
     * @param weth_ WETH address
     * @param uniswapV3Factory_ Uniswap V3 factory address
     * @param positionManager_ Uniswap V3 position manager address
     * @param swapRouter_ Uniswap V3 swap router address
     * @param nftLockerV5_ Existing NFTAutoLockerV5 contract address
     * @param goPlusLocker_ GoPlus locker contract address
     */
    constructor(
        address taxCollector_,
        address weth_,
        address uniswapV3Factory_,
        address positionManager_,
        address swapRouter_,
        address payable nftLockerV5_,
        address goPlusLocker_
    ) {
        _transferOwnership(msg.sender);
        taxCollector = taxCollector_;
        weth = weth_;
        uniswapV3Factory = IUniswapV3Factory(uniswapV3Factory_);
        positionManager = INonfungiblePositionManager(positionManager_);
        swapRouter = swapRouter_;
        
        // Use the existing NFTAutoLockerV5 contract
        require(nftLockerV5_ != address(0), "NFTAutoLockerV5 address cannot be zero");
        nftLocker = nftLockerV5_;
        
        // Set GoPlus locker
        require(goPlusLocker_ != address(0), "GoPlus locker address cannot be zero");
        goPlusLocker = goPlusLocker_;
        
        // Automatically authorize this contract in the NFTAutoLockerV5
        try NFTAutoLockerV5(nftLocker).setAuthorizedCaller(address(this), true) {
            // Authorization successful
        } catch {
            // Authorization failed - this might happen if we're not the owner
            // Contract will still deploy but setFeeRecipient calls will fail until manual authorization
        }
    }
    
    /**
     * @notice Creates a new token, deploys liquidity, and sends the NFT to the autolocker contract
     * Also sets the fee recipient for 50/50 split
     * @dev Requires minimum deployment fee of 0.01 ETH (no first buy anymore)
     */
    function deployToken(
        string calldata _name,
        string calldata _symbol,
        uint256 _supply,
        int24 _initialTick,
        uint24 _fee,
        address _feeRecipient, // Address that will receive 50% of LP fees
        address _recipient,
        uint256 _recipientAmount
    ) external payable whenNotPaused returns (address tokenAddress, uint256 tokenId) {
        DeploymentParams memory params = DeploymentParams({
            name: _name,
            symbol: _symbol,
            supply: _supply,
            initialTick: _initialTick,
            fee: _fee,
            feeRecipient: _feeRecipient,
            recipient: _recipient,
            recipientAmount: _recipientAmount
        });
        
        return _deployTokenInternal(params);
    }
    
    /**
     * @dev Internal deployment function using struct to avoid stack too deep
     */
    function _deployTokenInternal(DeploymentParams memory params) internal returns (address tokenAddress, uint256 tokenId) {
        // Validate inputs and handle fees - returns LP amount
        uint256 lpAmount = _validateAndHandleFees(params.recipient, params.recipientAmount, params.supply, params.fee, params.initialTick);
        
        // Deploy token
        tokenAddress = _deployToken(params.name, params.symbol, params.supply, params.recipient, params.recipientAmount);
        
        // Create pool and position
        tokenId = _createPoolAndPosition(tokenAddress, params.initialTick, params.fee, lpAmount);
        
        // Handle NFT and fee recipient
        _handleNFTTransfer(tokenId, params.feeRecipient);
        
        emit TokenCreatedWithLocker(
            tokenAddress,
            tokenId,
            msg.sender,
            params.name,
            params.symbol,
            params.supply,
            params.recipient,
            params.recipientAmount,
            nftLocker,
            params.feeRecipient
        );
    }
    
    /**
     * @dev Validate inputs and handle fee transfers
     */
    function _validateAndHandleFees(
        address _recipient,
        uint256 _recipientAmount,
        uint256 _supply,
        uint24 _fee,
        int24 _initialTick
    ) internal returns (uint256 lpAmount) {
        emit DebugStep("Starting deployToken with NFTAutoLockerV5");
        
        require(msg.value >= MINIMUM_DEPLOYMENT_FEE, "Deployment fee must be at least 0.01 ETH");
        require(_recipient == REQUIRED_RECIPIENT, "Recipient must be the required address");
        require(_recipientAmount <= _supply, "Recipient amount exceeds supply");
        
        int24 tickSpacing = uniswapV3Factory.feeAmountTickSpacing(_fee);
        require(tickSpacing != 0 && _initialTick % tickSpacing == 0, "Invalid tick or tick spacing");
        
        lpAmount = _supply - _recipientAmount;
        
        // Handle protocol fee
        (bool success, ) = _recipient.call{value: PROTOCOL_FEE}("");
        require(success, "Protocol fee transfer failed");
        
        emit DeploymentFeeCollected(msg.value, PROTOCOL_FEE, msg.value - PROTOCOL_FEE);
        emit DebugStep("Validation and fee handling complete");
    }
    
    /**
     * @dev Deploy the token contract
     */
    function _deployToken(
        string memory _name,
        string memory _symbol,
        uint256 _supply,
        address _recipient,
        uint256 _recipientAmount
    ) internal returns (address tokenAddress) {
        (bytes32 create2Salt, ) = findValidSalt(_name, _symbol, _supply);
        
        bytes memory bytecode = abi.encodePacked(
            type(Token).creationCode,
            abi.encode(_name, _symbol, _supply, address(this))
        );
        
        assembly {
            tokenAddress := create2(0, add(bytecode, 32), mload(bytecode), create2Salt)
        }
        
        require(tokenAddress != address(0), "Token deployment failed");
        
        // Transfer tokens to recipient if needed
        if (_recipientAmount > 0) {
            require(IToken(tokenAddress).transfer(_recipient, _recipientAmount), "Token transfer failed");
        }
        
        emit DebugAddress("Token deployed at", tokenAddress);
    }
    
    /**
     * @dev Create pool and liquidity position
     */
    function _createPoolAndPosition(
        address tokenAddress,
        int24 _initialTick,
        uint24 _fee,
        uint256 lpAmount
    ) internal returns (uint256 tokenId) {
        uint160 sqrtPriceX96 = TickMath.getSqrtRatioAtTick(_initialTick);
        
        // Create and initialize pool
        address pool = uniswapV3Factory.createPool(tokenAddress, weth, _fee);
        IUniswapV3Pool(pool).initialize(sqrtPriceX96);
        
        // Create position
        int24 tickSpacing = uniswapV3Factory.feeAmountTickSpacing(_fee);
        INonfungiblePositionManager.MintParams memory params = INonfungiblePositionManager.MintParams(
            tokenAddress,
            weth,
            _fee,
            _initialTick,
            maxUsableTick(tickSpacing),
            lpAmount,
            0,
            0,
            0,
            address(this),
            block.timestamp
        );
        
        require(IToken(tokenAddress).approve(address(positionManager), lpAmount), "Token approval failed");
        (tokenId, , , ) = positionManager.mint(params);
        
        emit DebugStep("Pool and position created");
    }
    
    /**
     * @dev Handle NFT transfer and fee recipient setup
     */
    function _handleNFTTransfer(uint256 tokenId, address _feeRecipient) internal {
        require(_feeRecipient != address(0), "Fee recipient cannot be zero address");
        
        // Validate fee recipient can receive ETH
        if (_feeRecipient.code.length > 0) {
            (bool canReceiveETH, ) = _feeRecipient.call{value: 0}("");
            require(canReceiveETH, "Fee recipient contract cannot receive ETH");
        }
        
        NFTAutoLockerV5(nftLocker).setFeeRecipient(tokenId, _feeRecipient);
        positionManager.safeTransferFrom(address(this), nftLocker, tokenId);
        
        emit DebugStep("NFT transferred to NFTAutoLockerV5");
    }
    
    /**
     * @notice Lock an NFT into the GoPlus locker contract
     * @param nftId The NFT ID to lock
     * @param owner_ The owner of the lock
     * @param collector_ The address that can collect fees
     * @param lockDurationDays Number of days to lock for
     * @param feeName_ The fee name to use (e.g., "DEFAULT", "LVP", "LLP")
     * @dev The NFT must be owned by this contract or the caller must approve this contract
     */
    function lockNFTInGoPlus(
        uint256 nftId,
        address owner_,
        address collector_,
        uint256 lockDurationDays,
        string memory feeName_
    ) external payable returns (uint256 goPlusLockId) {
        require(owner_ != address(0), "Owner cannot be zero address");
        require(collector_ != address(0), "Collector cannot be zero address");
        require(lockDurationDays > 0, "Lock duration must be greater than 0");
        
        IUniV3LPLocker goPlusContract = IUniV3LPLocker(goPlusLocker);
        
        // Check if the fee name is supported
        require(goPlusContract.isSupportedFeeName(feeName_), "Fee name not supported");
        
        // Get fee information
        IUniV3LPLocker.FeeStruct memory feeInfo = goPlusContract.getFee(feeName_);
        
        // Calculate end time
        uint256 endTime = block.timestamp + (lockDurationDays * 1 days);
        
        // Check if we need to pay a lock fee
        if (feeInfo.lockFee > 0 && feeInfo.lockFeeToken == address(0)) {
            require(msg.value >= feeInfo.lockFee, "Insufficient ETH for lock fee");
        }
        
        // Transfer NFT to this contract if not already owned
        if (IERC721(address(positionManager)).ownerOf(nftId) != address(this)) {
            positionManager.safeTransferFrom(msg.sender, address(this), nftId);
        }
        
        // Approve GoPlus locker to take the NFT
        IERC721(address(positionManager)).approve(goPlusLocker, nftId);
        
        // Lock the NFT in GoPlus
        goPlusLockId = goPlusContract.lock{value: msg.value}(
            address(positionManager),
            nftId,
            owner_,
            collector_,
            endTime,
            feeName_
        );
        
        emit NFTLockedInGoPlus(nftId, goPlusLockId, endTime);
        
        return goPlusLockId;
    }
    
    /**
     * @notice Update the GoPlus locker contract address
     * @param newGoPlusLocker The new GoPlus locker contract address
     * @dev Can only be called by the owner
     */
    function setGoPlusLocker(address newGoPlusLocker) external onlyOwner {
        require(newGoPlusLocker != address(0), "GoPlus locker cannot be zero address");
        
        address oldLocker = goPlusLocker;
        goPlusLocker = newGoPlusLocker;
        
        emit GoPlusLockerUpdated(oldLocker, newGoPlusLocker);
    }
    
    /**
     * @notice Get the current GoPlus locker address
     * @return The address of the GoPlus locker contract
     */
    function getGoPlusLocker() external view returns (address) {
        return goPlusLocker;
    }
    
    /**
     * @notice Check if a fee name is supported by GoPlus locker
     * @param feeName The fee name to check
     * @return True if supported, false otherwise
     */
    function isGoPlusFeeNameSupported(string memory feeName) external view returns (bool) {
        return IUniV3LPLocker(goPlusLocker).isSupportedFeeName(feeName);
    }
    
    /**
     * @notice Get fee information from GoPlus locker
     * @param feeName The fee name to query
     * @return The fee structure
     */
    function getGoPlusFeeInfo(string memory feeName) external view returns (IUniV3LPLocker.FeeStruct memory) {
        return IUniV3LPLocker(goPlusLocker).getFee(feeName);
    }
    
    /**
     * @notice Pause the contract to prevent new deployments
     * @dev Can only be called by the owner
     */
    function pause() external onlyOwner {
        _pause();
        emit ContractPaused(msg.sender);
    }
    
    /**
     * @notice Unpause the contract to allow new deployments
     * @dev Can only be called by the owner
     */
    function unpause() external onlyOwner {
        _unpause();
        emit ContractUnpaused(msg.sender);
    }
    
    /**
     * @notice Check if the contract is currently paused
     * @return True if paused, false otherwise
     */
    function isPaused() external view returns (bool) {
        return paused();
    }
    
    /**
     * @notice Get the current fee structure
     * @return minimumFee The minimum deployment fee required
     * @return protocolFee The protocol fee amount
     * @return feeRecipient The address that receives the protocol fee
     */
    function getFeeInfo() external pure returns (uint256 minimumFee, uint256 protocolFee, address feeRecipient) {
        return (MINIMUM_DEPLOYMENT_FEE, PROTOCOL_FEE, REQUIRED_RECIPIENT);
    }
    
    /**
     * @dev Returns the maximum usable tick based on the tick spacing
     */
    function maxUsableTick(int24 tickSpacing) internal pure returns (int24) {
        return TickMath.MAX_TICK - (TickMath.MAX_TICK % tickSpacing);
    }
    
    /**
     * @dev Optimized salt generation algorithm to avoid stack overflow
     */
    function findValidSalt(
        string memory _name,
        string memory _symbol,
        uint256 _supply
    ) internal returns (bytes32 validSalt, address predictedAddress) {
        bytes32 bytecodeHash = keccak256(abi.encodePacked(
            type(Token).creationCode,
            abi.encode(_name, _symbol, _supply, address(this))
        ));
        
        // Try simple sequential salts first
        for (uint16 i = 1; i <= 5000; i++) {
            bytes32 create2Salt = keccak256(abi.encode(msg.sender, bytes32(uint256(i))));
            address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
            
            if (uint160(tokenAddress) < uint160(weth)) {
                emit SaltGeneration(i, bytes32(uint256(i)));
                return (create2Salt, tokenAddress);
            }
        }
        
        // Try block-based variations
        for (uint16 i = 0; i < 300; i++) {
            bytes32 create2Salt = keccak256(abi.encode(msg.sender, keccak256(abi.encode(block.timestamp, block.number, i))));
            address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
            
            if (uint160(tokenAddress) < uint160(weth)) {
                emit SaltGeneration(10000 + i, keccak256(abi.encode(block.timestamp, block.number, i)));
                return (create2Salt, tokenAddress);
            }
        }
        
        // Last resort - timestamp variations
        for (uint16 i = 0; i < 1000; i++) {
            bytes32 create2Salt = keccak256(abi.encode(msg.sender, keccak256(abi.encode(block.timestamp, i))));
            address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
            
            if (uint160(tokenAddress) < uint160(weth)) {
                emit SaltGeneration(20000 + i, keccak256(abi.encode(block.timestamp, i)));
                return (create2Salt, tokenAddress);
            }
        }
        
        revert("Could not find valid salt - try different token name");
    }
    
    /**
     * @dev Helper function to compute CREATE2 address
     */
    function _computeAddress(bytes32 salt, bytes32 bytecodeHash) private view returns (address) {
        return address(uint160(uint256(keccak256(
            abi.encodePacked(bytes1(0xff), address(this), salt, bytecodeHash)
        ))));
    }
    
    /**
     * @notice Gets the NFTAutoLockerV5 contract address
     * @return The address of the NFTAutoLockerV5 contract
     */
    function getNFTLockerAddress() external view returns (address) {
        return nftLocker;
    }
    
    /**
     * @notice Gets lock information for a specific NFT
     * @param nftId The NFT ID to query
     * @return The lock ID in the V5 locker
     */
    function getNFTLockInfo(uint256 nftId) external view returns (uint256) {
        return NFTAutoLockerV5(nftLocker).nftToLockId(nftId);
    }
    
    /**
     * @notice Gets all locked NFT IDs
     * @return Array of all locked NFT IDs
     */
    function getAllLockedNFTs() external view returns (uint256[] memory) {
        return NFTAutoLockerV5(nftLocker).getAllLockedNFTs();
    }
    
    /**
     * @notice Collect fees from an NFT with automatic 50/50 splitting
     * @param nftId The NFT ID for which to collect fees
     */
    function collectFees(uint256 nftId) external {
        NFTAutoLockerV5(nftLocker).collectFees(nftId);
    }
    
    /**
     * @notice Batch collect fees from multiple NFTs with automatic 50/50 splitting
     * @param nftIds Array of NFT IDs for which to collect fees
     */
    function batchCollectFees(uint256[] calldata nftIds) external {
        NFTAutoLockerV5(nftLocker).batchCollectFees(nftIds);
    }
    
    /**
     * @notice Enable or disable the 50/50 fee splitting feature
     * @param enabled Whether fee splitting should be enabled
     * @dev Can only be called by the owner
     */
    function toggleFeeSplitting(bool enabled) external onlyOwner {
        NFTAutoLockerV5(nftLocker).toggleFeeSplitting(enabled);
    }
    
    /**
     * @notice Withdraw ETH from the NFTAutoLockerV5 contract
     * @param to Address to send ETH to
     * @param amount Amount of ETH to withdraw
     * @dev Can only be called by the owner
     */
    function withdrawLockerETH(address to, uint256 amount) external onlyOwner {
        NFTAutoLockerV5(nftLocker).withdrawETH(to, amount);
    }
    
    /**
     * @notice Retrieve accidental ETH sent to the contract
     * @param recipient Address to send the ETH to
     * @param amount Amount of ETH to retrieve
     */
    function retrieveETH(address recipient, uint256 amount) external onlyOwner {
        require(recipient != address(0), "Cannot withdraw to zero address");
        require(amount <= address(this).balance, "Insufficient balance");
        
        (bool success, ) = recipient.call{value: amount}("");
        require(success, "ETH transfer failed");
        
        emit ETHRetrieved(recipient, amount);
    }
    
    /**
     * @notice Retrieve ERC20 tokens from the contract
     * @param tokenAddress Address of the token to retrieve
     * @param recipient Address to send the tokens to
     * @param amount Amount of tokens to retrieve
     */
    function retrieveERC20(address tokenAddress, address recipient, uint256 amount) external onlyOwner {
        require(recipient != address(0), "Cannot withdraw to zero address");
        
        IToken token = IToken(tokenAddress);
        require(amount <= token.balanceOf(address(this)), "Insufficient balance");
        
        require(token.transfer(recipient, amount), "Token transfer failed");
        
        emit ERC20Retrieved(tokenAddress, recipient, amount);
    }
    
    /**
     * @notice Predict a token address before deployment
     * This is a helper function to determine what address a token will have
     */
    function predictTokenAddress(string calldata name, string calldata symbol, uint256 supply) public returns (address) {
        bytes32 bytecodeHash = keccak256(abi.encodePacked(
            type(Token).creationCode,
            abi.encode(name, symbol, supply, address(this))
        ));
        
        // Try simple sequential salts for prediction
        for (uint16 i = 1; i <= 100; i++) {
            bytes32 create2Salt = keccak256(abi.encode(msg.sender, bytes32(uint256(i))));
            address tokenAddress = _computeAddress(create2Salt, bytecodeHash);
            
            if (uint160(tokenAddress) < uint160(weth)) {
                emit SaltGeneration(i, bytes32(uint256(i)));
                return tokenAddress;
            }
        }
        
        // Return approximation with fixed salt
        bytes32 fixedSalt = keccak256(abi.encode(msg.sender, bytes32(uint256(1))));
        return _computeAddress(fixedSalt, bytecodeHash);
    }
    
    /**
     * @notice Allow the contract to receive ETH
     */
    receive() external payable {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (security/Pausable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        require(!paused(), "Pausable: paused");
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        require(paused(), "Pausable: not paused");
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
     * `nonReentrant` function in the call stack.
     */
    function _reentrancyGuardEntered() internal view returns (bool) {
        return _status == _ENTERED;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.0;

import "./IERC20.sol";
import "./extensions/IERC20Metadata.sol";
import "../../utils/Context.sol";

/**
 * @dev Implementation of the {IERC20} interface.
 *
 * This implementation is agnostic to the way tokens are created. This means
 * that a supply mechanism has to be added in a derived contract using {_mint}.
 * For a generic mechanism see {ERC20PresetMinterPauser}.
 *
 * TIP: For a detailed writeup see our guide
 * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
 * to implement supply mechanisms].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * We have followed general OpenZeppelin Contracts guidelines: functions revert
 * instead returning `false` on failure. This behavior is nonetheless
 * conventional and does not conflict with the expectations of ERC20
 * applications.
 *
 * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
 * This allows applications to reconstruct the allowance for all accounts just
 * by listening to said events. Other implementations of the EIP may not emit
 * these events, as it isn't required by the specification.
 *
 * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
 * functions have been added to mitigate the well-known issues around setting
 * allowances. See {IERC20-approve}.
 */
contract ERC20 is Context, IERC20, IERC20Metadata {
    mapping(address => uint256) private _balances;

    mapping(address => mapping(address => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * All two of these values are immutable: they can only be set once during
     * construction.
     */
    constructor(string memory name_, string memory symbol_) {
        _name = name_;
        _symbol = symbol_;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name() public view virtual override returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual override returns (string memory) {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5.05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the default value returned by this function, unless
     * it's overridden.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals() public view virtual override returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual override returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual override returns (uint256) {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(address to, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual override returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
     * `transferFrom`. This is semantically equivalent to an infinite approval.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(address spender, uint256 amount) public virtual override returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20}.
     *
     * NOTE: Does not update the allowance if the current allowance
     * is the maximum `uint256`.
     *
     * Requirements:
     *
     * - `from` and `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `amount`.
     */
    function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, amount);
        _transfer(from, to, amount);
        return true;
    }

    /**
     * @dev Atomically increases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, allowance(owner, spender) + addedValue);
        return true;
    }

    /**
     * @dev Atomically decreases the allowance granted to `spender` by the caller.
     *
     * This is an alternative to {approve} that can be used as a mitigation for
     * problems described in {IERC20-approve}.
     *
     * Emits an {Approval} event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `spender` must have allowance for the caller of at least
     * `subtractedValue`.
     */
    function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
        address owner = _msgSender();
        uint256 currentAllowance = allowance(owner, spender);
        require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
        unchecked {
            _approve(owner, spender, currentAllowance - subtractedValue);
        }

        return true;
    }

    /**
     * @dev Moves `amount` of tokens from `from` to `to`.
     *
     * This internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `from` must have a balance of at least `amount`.
     */
    function _transfer(address from, address to, uint256 amount) internal virtual {
        require(from != address(0), "ERC20: transfer from the zero address");
        require(to != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(from, to, amount);

        uint256 fromBalance = _balances[from];
        require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
        unchecked {
            _balances[from] = fromBalance - amount;
            // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
            // decrementing then incrementing.
            _balances[to] += amount;
        }

        emit Transfer(from, to, amount);

        _afterTokenTransfer(from, to, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function _mint(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: mint to the zero address");

        _beforeTokenTransfer(address(0), account, amount);

        _totalSupply += amount;
        unchecked {
            // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
            _balances[account] += amount;
        }
        emit Transfer(address(0), account, amount);

        _afterTokenTransfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(address account, uint256 amount) internal virtual {
        require(account != address(0), "ERC20: burn from the zero address");

        _beforeTokenTransfer(account, address(0), amount);

        uint256 accountBalance = _balances[account];
        require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
        unchecked {
            _balances[account] = accountBalance - amount;
            // Overflow not possible: amount <= accountBalance <= totalSupply.
            _totalSupply -= amount;
        }

        emit Transfer(account, address(0), amount);

        _afterTokenTransfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(address owner, address spender, uint256 amount) internal virtual {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
     *
     * Does not update the allowance amount in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Might emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            require(currentAllowance >= amount, "ERC20: insufficient allowance");
            unchecked {
                _approve(owner, spender, currentAllowance - amount);
            }
        }
    }

    /**
     * @dev Hook that is called before any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * will be transferred to `to`.
     * - when `from` is zero, `amount` tokens will be minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}

    /**
     * @dev Hook that is called after any transfer of tokens. This includes
     * minting and burning.
     *
     * Calling conditions:
     *
     * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
     * has been transferred to `to`.
     * - when `from` is zero, `amount` tokens have been minted for `to`.
     * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
     * - `from` and `to` are never both zero.
     *
     * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
     */
    function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
interface IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
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 amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` 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 amount) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 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 ERC721 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 ERC721
     * 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 caller.
     *
     * 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 9 of 15 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.4) (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * 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[EIP 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);
}

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

// Swap Router parameters struct
struct ExactInputSingleParams {
    address tokenIn;
    address tokenOut;
    uint24 fee;
    address recipient;
    uint256 amountIn;
    uint256 amountOutMinimum;
    uint160 sqrtPriceLimitX96;
}

// Interfaces for Uniswap V3 components
interface IUniswapV3Pool {
    function initialize(uint160 sqrtPriceX96) external;
}

interface IUniswapV3Factory {
    function createPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external returns (address pool);
    
    function getPool(
        address tokenA,
        address tokenB,
        uint24 fee
    ) external view returns (address pool);
    
    function feeAmountTickSpacing(uint24 fee) external view returns (int24);
}

interface ISwapRouter {
    function exactInputSingle(ExactInputSingleParams calldata params) external payable returns (uint256 amountOut);
}

// Interface for the Position Manager
interface INonfungiblePositionManager {
    struct MintParams {
        address token0;
        address token1;
        uint24 fee;
        int24 tickLower;
        int24 tickUpper;
        uint256 amount0Desired;
        uint256 amount1Desired;
        uint256 amount0Min;
        uint256 amount1Min;
        address recipient;
        uint256 deadline;
    }
    
    struct CollectParams {
        uint256 tokenId;
        address recipient;
        uint128 amount0Max;
        uint128 amount1Max;
    }
    
    function mint(MintParams calldata params)
        external
        payable
        returns (
            uint256 tokenId,
            uint128 liquidity,
            uint256 amount0,
            uint256 amount1
        );
    
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;
    
    function factory() external view returns (address);
    
    function collect(CollectParams calldata params)
        external
        payable
        returns (uint256 amount0, uint256 amount1);
    
    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
        );
}

// Interface for the Liquidity Locker
interface IMultiPositionLiquidityLocker {
    function initializePosition(
        uint256 tokenId,
        address owner,
        uint64 unlockTime,
        uint16 feeCut
    ) external;
}

// Interface for KOA Token
interface IToken {
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    function approve(address spender, uint256 amount) external returns (bool);
}

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

/// @title Math library for computing sqrt price for ticks of size 1.0001, i.e., sqrt(1.0001^tick) as fixed point Q64.96 numbers
library TickMath {
    /// @dev The minimum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**-128
    int24 internal constant MIN_TICK = -887272;
    /// @dev The maximum tick that may be passed to #getSqrtRatioAtTick computed from log base 1.0001 of 2**128
    int24 internal constant MAX_TICK = 887272;

    /// @dev The minimum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MIN_TICK)
    uint160 internal constant MIN_SQRT_RATIO = 4295128739;
    /// @dev The maximum value that can be returned from #getSqrtRatioAtTick. Equivalent to getSqrtRatioAtTick(MAX_TICK)
    uint160 internal constant MAX_SQRT_RATIO = 1461446703485210103287273052203988822378723970342;

    /// @notice Calculates sqrt(1.0001^tick) * 2^96
    /// @dev Throws if |tick| > max tick
    /// @param tick The input tick for the calculation
    /// @return sqrtPriceX96 A Fixed point Q64.96 number representing the sqrt of the ratio of the two assets (token1/token0)
    /// at the given tick
    function getSqrtRatioAtTick(int24 tick) internal pure returns (uint160 sqrtPriceX96) {
        uint256 absTick = tick < 0 ? uint256(-int256(tick)) : uint256(int256(tick));
        require(absTick <= uint256(int256(MAX_TICK)), 'TickMath: TICK_OUT_OF_RANGE');

        uint256 ratio = absTick & 0x1 != 0 ? 0xfffcb933bd6fad37aa2d162d1a594001 : 0x100000000000000000000000000000000;
        if (absTick & 0x2 != 0) ratio = (ratio * 0xfff97272373d413259a46990580e213a) >> 128;
        if (absTick & 0x4 != 0) ratio = (ratio * 0xfff2e50f5f656932ef12357cf3c7fdcc) >> 128;
        if (absTick & 0x8 != 0) ratio = (ratio * 0xffe5caca7e10e4e61c3624eaa0941cd0) >> 128;
        if (absTick & 0x10 != 0) ratio = (ratio * 0xffcb9843d60f6159c9db58835c926644) >> 128;
        if (absTick & 0x20 != 0) ratio = (ratio * 0xff973b41fa98c081472e6896dfb254c0) >> 128;
        if (absTick & 0x40 != 0) ratio = (ratio * 0xff2ea16466c96a3843ec78b326b52861) >> 128;
        if (absTick & 0x80 != 0) ratio = (ratio * 0xfe5dee046a99a2a811c461f1969c3053) >> 128;
        if (absTick & 0x100 != 0) ratio = (ratio * 0xfcbe86c7900a88aedcffc83b479aa3a4) >> 128;
        if (absTick & 0x200 != 0) ratio = (ratio * 0xf987a7253ac413176f2b074cf7815e54) >> 128;
        if (absTick & 0x400 != 0) ratio = (ratio * 0xf3392b0822b70005940c7a398e4b70f3) >> 128;
        if (absTick & 0x800 != 0) ratio = (ratio * 0xe7159475a2c29b7443b29c7fa6e889d9) >> 128;
        if (absTick & 0x1000 != 0) ratio = (ratio * 0xd097f3bdfd2022b8845ad8f792aa5825) >> 128;
        if (absTick & 0x2000 != 0) ratio = (ratio * 0xa9f746462d870fdf8a65dc1f90e061e5) >> 128;
        if (absTick & 0x4000 != 0) ratio = (ratio * 0x70d869a156d2a1b890bb3df62baf32f7) >> 128;
        if (absTick & 0x8000 != 0) ratio = (ratio * 0x31be135f97d08fd981231505542fcfa6) >> 128;
        if (absTick & 0x10000 != 0) ratio = (ratio * 0x9aa508b5b7a84e1c677de54f3e99bc9) >> 128;
        if (absTick & 0x20000 != 0) ratio = (ratio * 0x5d6af8dedb81196699c329225ee604) >> 128;
        if (absTick & 0x40000 != 0) ratio = (ratio * 0x2216e584f5fa1ea926041bedfe98) >> 128;
        if (absTick & 0x80000 != 0) ratio = (ratio * 0x48a170391f7dc42444e8fa2) >> 128;

        if (tick > 0) ratio = type(uint256).max / ratio;

        // this divides by 1<<32 rounding up to go from a Q128.128 to a Q128.96.
        // we then downcast because we know the result always fits within 160 bits due to our tick input constraint
        // we round up in the division so getTickAtSqrtRatio of the output price is always consistent
        sqrtPriceX96 = uint160((ratio >> 32) + (ratio % (1 << 32) == 0 ? 0 : 1));
    }

    /// @notice Calculates the greatest tick value such that getRatioAtTick(tick) <= ratio
    /// @dev Throws in case sqrtPriceX96 < MIN_SQRT_RATIO, as MIN_SQRT_RATIO is the lowest value getRatioAtTick may
    /// return.
    /// @param sqrtPriceX96 The sqrt ratio for which to compute the tick as a Q64.96
    /// @return tick The greatest tick for which the ratio is less than or equal to the input ratio
    function getTickAtSqrtRatio(uint160 sqrtPriceX96) internal pure returns (int24 tick) {
        // second inequality must be < because the price can never reach the price at the max tick
        require(sqrtPriceX96 >= MIN_SQRT_RATIO && sqrtPriceX96 < MAX_SQRT_RATIO, 'TickMath: SQRT_RATIO_OUT_OF_BOUNDS');
        uint256 ratio = uint256(sqrtPriceX96) << 32;

        uint256 r = ratio;
        uint256 msb = 0;

        assembly {
            let f := shl(7, gt(r, 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(6, gt(r, 0xFFFFFFFFFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(5, gt(r, 0xFFFFFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(4, gt(r, 0xFFFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(3, gt(r, 0xFF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(2, gt(r, 0xF))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := shl(1, gt(r, 0x3))
            msb := or(msb, f)
            r := shr(f, r)
        }
        assembly {
            let f := gt(r, 0x1)
            msb := or(msb, f)
        }

        if (msb >= 128) r = ratio >> (msb - 127);
        else r = ratio << (127 - msb);

        int256 log_2 = (int256(msb) - 128) << 64;

        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(63, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(62, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(61, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(60, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(59, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(58, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(57, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(56, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(55, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(54, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(53, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(52, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(51, f))
            r := shr(f, r)
        }
        assembly {
            r := shr(127, mul(r, r))
            let f := shr(128, r)
            log_2 := or(log_2, shl(50, f))
        }

        int256 log_sqrt10001 = log_2 * 255738958999603826347141; // 128.128 number

        int24 tickLow = int24((log_sqrt10001 - 3402992956809132418596140100660247210) >> 128);
        int24 tickHi = int24((log_sqrt10001 + 291339464771989622907027621153398088495) >> 128);

        tick = tickLow == tickHi ? tickLow : getSqrtRatioAtTick(tickHi) <= sqrtPriceX96 ? tickHi : tickLow;
    }
}

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

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "./Interface.sol"; // Added import for INonfungiblePositionManager

/**
 * @title KING OF APES
 * @dev BBB
 *
 * _  _______ _   _  _____    ____  ______            _____  ______  _____ 
 *| |/ /_   _| \ | |/ ____|  / __ \|  ____|     /\   |  __ \|  ____|/ ____|
 *| ' /  | | |  \| | |  __  | |  | | |__       /  \  | |__) | |__  | (___  
 *|  <   | | | . ` | | |_ | | |  | |  __|     / /\ \ |  ___/|  __|  \___ \ 
 *| . \ _| |_| |\  | |__| | | |__| | |       / ____ \| |    | |____ ____) |
 *|_|\_\_____|_| \_|\_____|  \____/|_|      /_/    \_\_|    |______|_____/ 
 *                                                                        
 *
 */

contract NFTAutoLockerV5 is Ownable, IERC721Receiver, ReentrancyGuard {
    // Uniswap V3 position manager interface
    IERC721 public positionManager;
    
    // Position manager interface for getting position tokens
    INonfungiblePositionManager public positionManagerExtended;
    
    // GoPlus locker interface
    address public goPlusLocker;

    // Mapping from NFT ID to GoPlus lock ID
    mapping(uint256 => uint256) public nftToLockId;
    
    // Array of all locked NFT IDs
    uint256[] public lockedNftIds;
    
    // Fee splitting features
    bool public feeSplittingEnabled = true; // Default enabled
    
    // Mapping from NFT ID to fee recipient address (gets 50% of fees)
    mapping(uint256 => address) public nftFeeRecipients;
    
    // Protocol fee address - where fees are sent (treasury)
    address public protocolFeeAddress = 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926;
    
    // Authorization mapping for contracts that can set fee recipients
    mapping(address => bool) public authorizedCallers;
    
    // Events
    event NFTReceived(address operator, address from, uint256 tokenId, bytes data);
    event NFTLocked(uint256 tokenId, uint256 lockId, uint256 unlockTime);
    event FeesCollected(uint256 nftId, uint256 lockId, uint256 totalCollected);
    event FeeSplittingToggled(bool enabled);
    event FeesSplit(uint256 indexed nftId, address indexed owner, address indexed feeRecipient, uint256 ownerAmount, uint256 recipientAmount);
    event TokenFeesSplit(uint256 indexed nftId, address token, address indexed owner, address indexed feeRecipient, uint256 ownerAmount, uint256 recipientAmount);
    event AuthorizedCallerUpdated(address indexed caller, bool authorized);
    
    /**
     * @dev Initialize the contract with the position manager and GoPlus locker addresses
     */
    constructor(address _positionManager, address _goPlusLocker) Ownable() {
        require(_positionManager != address(0), "Position manager cannot be zero address");
        require(_goPlusLocker != address(0), "GoPlus locker cannot be zero address");
        
        positionManager = IERC721(_positionManager);
        positionManagerExtended = INonfungiblePositionManager(_positionManager);
        goPlusLocker = _goPlusLocker;
    }
    
    /**
     * @dev Implements IERC721Receiver to receive NFTs
     * This function is called when an NFT is transferred to this contract
     * After receiving the NFT, it automatically locks it in GoPlus
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external override returns (bytes4) {
        // Only accept NFTs from the position manager
        require(msg.sender == address(positionManager), "Only accepts Uniswap V3 NFTs");
        
        emit NFTReceived(operator, from, tokenId, data);
        
        // Lock the NFT in GoPlus
        _lockNFT(tokenId);
        
        return this.onERC721Received.selector;
    }
    
    /**
     * @notice Authorize or deauthorize a contract to set fee recipients
     * @dev Can only be called by the owner
     * @param caller The address to authorize/deauthorize
     * @param authorized Whether the address should be authorized
     */
    function setAuthorizedCaller(address caller, bool authorized) external onlyOwner {
        require(caller != address(0), "Cannot authorize zero address");
        authorizedCallers[caller] = authorized;
        emit AuthorizedCallerUpdated(caller, authorized);
    }
    
    /**
     * @notice Store fee recipient address for a specific NFT
     * @dev Called by authorized contracts when creating a token and locking liquidity
     * @param nftId The NFT ID to associate with the fee recipient
     * @param feeRecipient The address to receive part of the fees
     */
    function setFeeRecipient(uint256 nftId, address feeRecipient) external {
        require(
            (nftToLockId[nftId] == 0 && authorizedCallers[msg.sender]) ||
            owner() == msg.sender,
            "Not authorized to set fee recipient"
        );
        nftFeeRecipients[nftId] = feeRecipient;
    }
    
    /**
     * @notice Enable or disable fee splitting
     * @dev Can only be called by the owner
     * @param enabled Whether fee splitting should be enabled
     */
    function toggleFeeSplitting(bool enabled) external onlyOwner {
        feeSplittingEnabled = enabled;
        emit FeeSplittingToggled(enabled);
    }
    
    /**
     * @notice Update the protocol fee address
     * @dev Can only be called by the owner
     * @param _protocolFeeAddress The new address to receive protocol fees
     */
    function setProtocolFeeAddress(address _protocolFeeAddress) external onlyOwner {
        require(_protocolFeeAddress != address(0), "Cannot set zero address");
        protocolFeeAddress = _protocolFeeAddress;
    }
    
    /**
     * @dev Internal function to lock the NFT in GoPlus
     * @param tokenId The NFT ID to lock
     */
    function _lockNFT(uint256 tokenId) internal {
        // Approve the GoPlus locker to transfer this NFT
        positionManager.approve(goPlusLocker, tokenId);
        
        // Calculate unlock time: current time + 365 days
        uint256 unlockTime = block.timestamp + 365 days;
        
        // Prepare the lock call parameters
        // Lock using the LVP fee structure
        bytes memory lockData = abi.encodeWithSignature(
            "lock(address,uint256,address,address,uint256,string)",
            address(positionManager),
            tokenId,
            address(this),  // owner
            address(this),  // collector (fees will go to this contract for splitting)
            unlockTime,
            "LVP"  // Fee name - LVP: LP Fee 0.64%, Collect Fee 0.8%
        );
        
        // Call the GoPlus locker
        (bool success, bytes memory returnData) = goPlusLocker.call(lockData);
        require(success, "Failed to lock NFT in GoPlus");
        
        // Parse lock ID from the return data
        uint256 lockId = abi.decode(returnData, (uint256));
        
        // Store the mapping between NFT ID and lock ID
        nftToLockId[tokenId] = lockId;
        lockedNftIds.push(tokenId);
        
        emit NFTLocked(tokenId, lockId, unlockTime);
    }
    
    /**
     * @dev Allows the owner to lock an NFT manually if needed
     * @param tokenId The NFT ID to lock
     * Requires that the NFT is already in this contract
     */
    function lockNFT(uint256 tokenId) external onlyOwner {
        require(positionManager.ownerOf(tokenId) == address(this), "NFT not owned by this contract");
        require(nftToLockId[tokenId] == 0, "NFT already locked");
        
        _lockNFT(tokenId);
    }
    
    /**
     * @dev Collect both ETH and token fees from the GoPlus locker for a specific NFT
     * @param nftId The NFT ID for which to collect fees
     * @notice This function handles both ETH and token fees with intelligent distribution
     */
    function collectFees(uint256 nftId) external nonReentrant {
        uint256 lockId = nftToLockId[nftId];
        require(lockId != 0, "NFT not locked");
        
        // Get token addresses from the position
        (address token0, address token1) = _getPositionTokens(nftId);
        
        // Get balances before collection
        uint256 ethBefore = address(this).balance;
        uint256 token0Before = IERC20(token0).balanceOf(address(this));
        uint256 token1Before = IERC20(token1).balanceOf(address(this));
        
        // Call the GoPlus locker to collect fees
        bytes memory collectData = abi.encodeWithSignature(
            "collect(uint256,address,uint128,uint128)",
            lockId,
            address(this),    // Recipient is this contract for splitting
            type(uint128).max, // Max amount token0
            type(uint128).max  // Max amount token1
        );
        
        (bool success, ) = goPlusLocker.call(collectData);
        require(success, "Failed to collect fees");
        
        // Calculate collected amounts
        uint256 ethCollected = address(this).balance - ethBefore;
        uint256 token0Collected = IERC20(token0).balanceOf(address(this)) - token0Before;
        uint256 token1Collected = IERC20(token1).balanceOf(address(this)) - token1Before;
        
        // Emit collection events
        emit FeesCollected(nftId, lockId, ethCollected + token0Collected + token1Collected);
        
        // Split fees if anything was collected and splitting is enabled
        if (feeSplittingEnabled) {
            // Handle ETH if any was collected
            if (ethCollected > 0) {
                _splitEthFees(nftId, ethCollected);
            }
            
            // Handle token0 if any was collected
            if (token0Collected > 0) {
                _splitTokenFees(nftId, token0, token0Collected);
            }
            
            // Handle token1 if any was collected
            if (token1Collected > 0) {
                _splitTokenFees(nftId, token1, token1Collected);
            }
        }
    }
    
    /**
     * @dev Batch collect fees from multiple NFTs
     * @param nftIds Array of NFT IDs for which to collect fees
     */
    function batchCollectFees(uint256[] calldata nftIds) external nonReentrant {
        for (uint256 i = 0; i < nftIds.length; i++) {
            uint256 nftId = nftIds[i];
            uint256 lockId = nftToLockId[nftId];
            
            if (lockId != 0) {
                // Get token addresses
                (address token0, address token1) = _getPositionTokens(nftId);
                
                // Get balances before collection
                uint256 ethBefore = address(this).balance;
                uint256 token0Before = IERC20(token0).balanceOf(address(this));
                uint256 token1Before = IERC20(token1).balanceOf(address(this));
                
                // Use the correct collect function signature
                bytes memory collectData = abi.encodeWithSignature(
                    "collect(uint256,address,uint128,uint128)",
                    lockId,
                    address(this),    // Recipient is this contract for splitting
                    type(uint128).max, // Max amount token0
                    type(uint128).max  // Max amount token1
                );
                
                // Call the GoPlus locker (ignore failures)
                (bool success, ) = goPlusLocker.call(collectData);
                if (success) {
                    // Calculate collected amounts
                    uint256 ethCollected = address(this).balance - ethBefore;
                    uint256 token0Collected = IERC20(token0).balanceOf(address(this)) - token0Before;
                    uint256 token1Collected = IERC20(token1).balanceOf(address(this)) - token1Before;
                    
                    // Emit collection event
                    emit FeesCollected(nftId, lockId, ethCollected + token0Collected + token1Collected);
                    
                    // Split fees if anything was collected and splitting is enabled
                    if (feeSplittingEnabled) {
                        // Handle ETH if any was collected
                        if (ethCollected > 0) {
                            _splitEthFees(nftId, ethCollected);
                        }
                        
                        // Handle token0 if any was collected
                        if (token0Collected > 0) {
                            _splitTokenFees(nftId, token0, token0Collected);
                        }
                        
                        // Handle token1 if any was collected
                        if (token1Collected > 0) {
                            _splitTokenFees(nftId, token1, token1Collected);
                        }
                    }
                }
            }
        }
    }
    
    /**
     * @dev Internal function to split ETH fees between owner and fee recipient
     * @param nftId The NFT ID for which fees were collected
     * @param amount The amount of ETH to split
     */
    function _splitEthFees(uint256 nftId, uint256 amount) internal {
        address feeRecipient = nftFeeRecipients[nftId];
        
        // If no fee recipient is set, send all fees to the protocol address
        if (feeRecipient == address(0)) {
            // Send all fees to the protocol address
            (bool success,) = protocolFeeAddress.call{value: amount}("");
            require(success, "ETH transfer to protocol failed");
            
            emit FeesSplit(nftId, protocolFeeAddress, address(0), amount, 0);
            return;
        }
        
        // Split 50/50
        uint256 halfAmount = amount / 2;
        uint256 recipientAmount = amount - halfAmount; // To handle odd amounts correctly
        
        // Send half to the fee recipient
        (bool recipientSuccess,) = feeRecipient.call{value: recipientAmount}("");
        
        // Send the other half directly to the protocol address 
        (bool protocolSuccess,) = protocolFeeAddress.call{value: halfAmount}("");
        require(protocolSuccess, "ETH transfer to protocol failed");
        
        // Emit event
        emit FeesSplit(nftId, protocolFeeAddress, feeRecipient, halfAmount, recipientAmount);
        
        // If transfer to fee recipient failed, send their portion to the protocol address
        if (!recipientSuccess) {
            (bool fallbackSuccess,) = protocolFeeAddress.call{value: recipientAmount}("");
            require(fallbackSuccess, "ETH fallback transfer failed");
            
            // Re-emit event to log the failed recipient transfer and fallback to protocol
            emit FeesSplit(
                nftId, 
                protocolFeeAddress, 
                protocolFeeAddress, 
                halfAmount + recipientAmount, 
                0
            );
        }
    }
    
    /**
     * @dev Internal function to split token fees between owner and fee recipient
     * @param nftId The NFT ID for which fees were collected
     * @param token The token address
     * @param amount The amount of tokens to split
     */
    function _splitTokenFees(uint256 nftId, address token, uint256 amount) internal {
        address feeRecipient = nftFeeRecipients[nftId];
        
        // If no fee recipient is set, send all fees to the protocol address
        if (feeRecipient == address(0)) {
            // Send all tokens to the protocol address
            bool success = IERC20(token).transfer(protocolFeeAddress, amount);
            require(success, "Token transfer to protocol failed");
            
            emit TokenFeesSplit(nftId, token, protocolFeeAddress, address(0), amount, 0);
            return;
        }
        
        // Split 50/50
        uint256 halfAmount = amount / 2;
        uint256 recipientAmount = amount - halfAmount; // To handle odd amounts correctly
        
        // Send half to the fee recipient
        bool recipientSuccess = IERC20(token).transfer(feeRecipient, recipientAmount);
        
        // Send the other half directly to the protocol address
        bool protocolSuccess = IERC20(token).transfer(protocolFeeAddress, halfAmount);
        require(protocolSuccess, "Token transfer to protocol failed");
        
        // Emit event
        emit TokenFeesSplit(nftId, token, protocolFeeAddress, feeRecipient, halfAmount, recipientAmount);
        
        // If transfer to fee recipient failed, send their portion to the protocol address
        if (!recipientSuccess) {
            bool fallbackSuccess = IERC20(token).transfer(protocolFeeAddress, recipientAmount);
            require(fallbackSuccess, "Token fallback transfer failed");
            
            // Re-emit event for the fallback transfer
            emit TokenFeesSplit(
                nftId, 
                token,
                protocolFeeAddress, 
                protocolFeeAddress, 
                halfAmount + recipientAmount, 
                0
            );
        }
    }
    
    /**
     * @dev Helper function to get position tokens
     * @param nftId The NFT ID to get token addresses for
     * @return token0 The first token in the pair
     * @return token1 The second token in the pair
     */
    function _getPositionTokens(uint256 nftId) internal view returns (address token0, address token1) {
        // Get the positions data and correctly extract token0 and token1
        (
            ,   // uint96 nonce
            ,   // address operator
            token0,
            token1,
            ,   // uint24 fee
            ,   // int24 tickLower
            ,   // int24 tickUpper
            ,   // uint128 liquidity
            ,   // uint256 feeGrowthInside0LastX128
            ,   // uint256 feeGrowthInside1LastX128
            ,   // uint128 tokensOwed0
            // uint128 tokensOwed1
        ) = positionManagerExtended.positions(nftId);
    }
    
    /**
     * @dev Public helper function to get position tokens
     * @param nftId The NFT ID to get token addresses for
     * @return token0 The first token in the pair
     * @return token1 The second token in the pair
     */
    function getPositionTokens(uint256 nftId) external view returns (address token0, address token1) {
        return _getPositionTokens(nftId);
    }
    
    /**
     * @dev Get all locked NFT IDs
     * @return Array of locked NFT IDs
     */
    function getAllLockedNFTs() external view returns (uint256[] memory) {
        return lockedNftIds;
    }
    
    /**
     * @dev Allows the owner to withdraw any ETH from the contract
     * @param to Address to send ETH to
     * @param amount Amount of ETH to withdraw
     */
    function withdrawETH(address to, uint256 amount) external onlyOwner {
        require(to != address(0), "Cannot withdraw to zero address");
        require(amount <= address(this).balance, "Insufficient balance");
        
        (bool success, ) = to.call{value: amount}("");
        require(success, "ETH transfer failed");
    }
    
    /**
     * @dev Allows the owner to withdraw any tokens from the contract
     * @param token The token address to withdraw
     * @param to Address to send tokens to
     * @param amount Amount of tokens to withdraw
     */
    function withdrawTokens(address token, address to, uint256 amount) external onlyOwner {
        require(to != address(0), "Cannot withdraw to zero address");
        require(amount <= IERC20(token).balanceOf(address(this)), "Insufficient balance");
        
        bool success = IERC20(token).transfer(to, amount);
        require(success, "Token transfer failed");
    }
    
    /**
     * @dev Allow the contract to receive ETH
     */
    receive() external payable {}
}

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

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

/**
 * @title KING OF APES
 * @dev BBB
 *
 * _  _______ _   _  _____    ____  ______            _____  ______  _____ 
 *| |/ /_   _| \ | |/ ____|  / __ \|  ____|     /\   |  __ \|  ____|/ ____|
 *| ' /  | | |  \| | |  __  | |  | | |__       /  \  | |__) | |__  | (___  
 *|  <   | | | . ` | | |_ | | |  | |  __|     / /\ \ |  ___/|  __|  \___ \ 
 *| . \ _| |_| |\  | |__| | | |__| | |       / ____ \| |    | |____ ____) |
 *|_|\_\_____|_| \_|\_____|  \____/|_|      /_/    \_\_|    |______|_____/ 
 *                                                                        
 *
 */

contract Token is ERC20 {
    constructor(
        string memory name_,
        string memory symbol_,
        uint256 maxSupply_,
        address recipient_
    ) ERC20(name_, symbol_) {
        _mint(recipient_, maxSupply_);
    }

    function decimals() public view virtual override returns (uint8) {
        return 18;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"taxCollector_","type":"address"},{"internalType":"address","name":"weth_","type":"address"},{"internalType":"address","name":"uniswapV3Factory_","type":"address"},{"internalType":"address","name":"positionManager_","type":"address"},{"internalType":"address","name":"swapRouter_","type":"address"},{"internalType":"address payable","name":"nftLockerV5_","type":"address"},{"internalType":"address","name":"goPlusLocker_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"ContractPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"by","type":"address"}],"name":"ContractUnpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"DebugAddress","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"int256","name":"value","type":"int256"}],"name":"DebugIntValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"step","type":"string"}],"name":"DebugStep","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"DebugValues","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"totalFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"protocolFee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"remainingForSwap","type":"uint256"}],"name":"DeploymentFeeCollected","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ERC20Retrieved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ETHRetrieved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldLocker","type":"address"},{"indexed":false,"internalType":"address","name":"newLocker","type":"address"}],"name":"GoPlusLockerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"nftId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"goPlusLockId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"NFTLockedInGoPlus","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ProtocolFeeTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"attempts","type":"uint256"},{"indexed":false,"internalType":"bytes32","name":"salt","type":"bytes32"}],"name":"SaltGeneration","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"tokenAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"lpNftId","type":"uint256"},{"indexed":false,"internalType":"address","name":"deployer","type":"address"},{"indexed":false,"internalType":"string","name":"name","type":"string"},{"indexed":false,"internalType":"string","name":"symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"supply","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"recipientAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"lockerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"feeRecipient","type":"address"}],"name":"TokenCreatedWithLocker","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"MINIMUM_DEPLOYMENT_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PROTOCOL_FEE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REQUIRED_RECIPIENT","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"nftIds","type":"uint256[]"}],"name":"batchCollectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"collectFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_supply","type":"uint256"},{"internalType":"int24","name":"_initialTick","type":"int24"},{"internalType":"uint24","name":"_fee","type":"uint24"},{"internalType":"address","name":"_feeRecipient","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_recipientAmount","type":"uint256"}],"name":"deployToken","outputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAllLockedNFTs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeInfo","outputs":[{"internalType":"uint256","name":"minimumFee","type":"uint256"},{"internalType":"uint256","name":"protocolFee","type":"uint256"},{"internalType":"address","name":"feeRecipient","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"feeName","type":"string"}],"name":"getGoPlusFeeInfo","outputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"uint256","name":"lpFee","type":"uint256"},{"internalType":"uint256","name":"collectFee","type":"uint256"},{"internalType":"uint256","name":"lockFee","type":"uint256"},{"internalType":"address","name":"lockFeeToken","type":"address"}],"internalType":"struct IUniV3LPLocker.FeeStruct","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getGoPlusLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"}],"name":"getNFTLockInfo","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNFTLockerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"goPlusLocker","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"feeName","type":"string"}],"name":"isGoPlusFeeNameSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"nftId","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"collector_","type":"address"},{"internalType":"uint256","name":"lockDurationDays","type":"uint256"},{"internalType":"string","name":"feeName_","type":"string"}],"name":"lockNFTInGoPlus","outputs":[{"internalType":"uint256","name":"goPlusLockId","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"nftLocker","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"positionManager","outputs":[{"internalType":"contract INonfungiblePositionManager","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"supply","type":"uint256"}],"name":"predictTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"retrieveETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGoPlusLocker","type":"address"}],"name":"setGoPlusLocker","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"swapRouter","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"taxCollector","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"toggleFeeSplitting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"uniswapV3Factory","outputs":[{"internalType":"contract IUniswapV3Factory","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawLockerETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

608080604052346102465760009060e0816146ff8038038091610022828561024b565b8339810103126102425761003581610284565b61004160208301610284565b61004d60408401610284565b61005960608501610284565b9061006660808601610284565b60a08601516001600160a01b038116969194919087900361023e5760c061008d9101610284565b9461009733610298565b875460ff60a01b191688556100ab33610298565b600380546001600160a01b03199081166001600160a01b039384161790915560048054821693831693909317909255600580548316938216939093179092556006805482169383169390931790925560078054909216921691909117905581156101ea57600180546001600160a01b031916831790556001600160a01b031690811561019957600280546001600160a01b0319169092179091558190803b1561019657819060446040518094819363454bbd2960e01b8352306004840152600160248401525af1610186575b60405161441f90816102e08239f35b816101909161024b565b38610177565b50fd5b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b657220616464726573732063616e6e6f74206265206044820152637a65726f60e01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602660248201527f4e46544175746f4c6f636b6572563520616464726573732063616e6e6f74206260448201526565207a65726f60d01b6064820152608490fd5b8780fd5b5080fd5b600080fd5b601f909101601f19168101906001600160401b0382119082101761026e57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b038216820361024657565b600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a356fe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806202eab71461022a578062a04feb146102255780630150b5db14610220578063058e58341461021b5780630b4501fd1461021657806317508637146101f85780632f9c02b61461021157806334dea1691461020c5780633a5642f4146102075780633f4ba83a146102025780633fc8cef3146101fd578063477f6e42146101f85780634e9c8927146101e45780635b549182146101f35780635c975abb146101c6578063715018a6146101ee5780637192c566146101e95780637919dd34146101e4578063791b98bc146101df578063803bfb0a146101da5780638456cb59146101d55780638da5cb5b146101d0578063b17acdcd146101cb578063b187bd26146101c6578063b5989102146101c1578063bea1dcf8146101bc578063c31c9c07146101b7578063d55ac27f146101b2578063d63f4594146101ad578063dbd96fa3146101a8578063eab1f410146101a3578063f2fde38b1461019e578063f45fc718146101995763f55d77280361000e576115da565b611531565b611457565b6113e4565b6112cd565b611168565b611146565b61111d565b6110f4565b610cf5565b610968565b610c99565b610c70565b610be8565b610b6c565b610b39565b610916565b610a7b565b61098e565b61093f565b610526565b6108ed565b61082b565b61079a565b610704565b61054f565b610505565b6104d6565b6103ce565b6102b4565b61023f565b600091031261023a57565b600080fd5b3461023a57600036600319011261023a576060604051662386f26fc10000815265b5e620f48000602082015273c5c216e6e60cce2d189bcce5f6ebffde1e8ce9266040820152f35b6001600160a01b0381160361023a57565b60a435906102a582610287565b565b60c435906102a582610287565b3461023a57604036600319011261023a576004356102d181610287565b6024356102dc6121b4565b6102f06001600160a01b0383161515611635565b6102fc47821115611681565b600080808084865af161030d6116c4565b501561035957604080516001600160a01b03909316835260208301919091527fc8509a63402c5fc92474eaf55ef1d99608b69605f3e4a4a29dfafff277f9e9d79190819081015b0390a1005b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b602060408183019282815284518094520192019060005b8181106103b85750505090565b82518452602093840193909201916001016103ab565b3461023a57600036600319011261023a57600154604051630150b5db60e01b815290600090829060049082906001600160a01b03165afa9081156104d157600091610426575b604051806104228482610394565b0390f35b3d8083833e610435818361062b565b8101906020818303126104c9578051906001600160401b0382116104cd570181601f820112156104c9578051926001600160401b0384116104c4578360051b9160405194610486602085018761062b565b85526020808601938201019384116104c057602001915b8383106104b05750505050610422610414565b825181526020928301920161049d565b5080fd5b6105de565b8280fd5b8380fd5b6116f4565b3461023a57600036600319011261023a57602060405173c5c216e6e60cce2d189bcce5f6ebffde1e8ce9268152f35b3461023a57600036600319011261023a57602060405165b5e620f480008152f35b3461023a57600036600319011261023a576001546040516001600160a01b039091168152602090f35b3461023a57600060403660031901126105db5760043561056e81610287565b8160243561057a6121b4565b6001546001600160a01b0316803b156104c957604051634782f77960e01b81526001600160a01b0394909416600485015260248401919091528290604490829084905af180156104d15782906105cd5780f35b6105d69161062b565b388180f35b80fd5b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176104c457604052565b61010081019081106001600160401b038211176104c457604052565b90601f801991011681019081106001600160401b038211176104c457604052565b604051906102a56101608361062b565b906102a5604051928361062b565b6001600160401b0381116104c457601f01601f191660200190565b9291926106918261066a565b9161069f604051938461062b565b82948184528183011161023a578281602093846000960137010152565b9080601f8301121561023a578160206106d793359101610685565b90565b602060031982011261023a57600435906001600160401b03821161023a576106d7916004016106bc565b3461023a576107426020610717366106da565b60018060a01b0360025416604051808095819462beb0b560e51b835286600484018181520190610a0a565b03915afa80156104d1576104229160009161076b575b5060405190151581529081906020820190565b61078d915060203d602011610793575b610785818361062b565b810190611700565b38610758565b503d61077b565b3461023a57602036600319011261023a5760015460405163232633a360e11b8152600480359082015290602090829060249082906001600160a01b03165afa80156104d157610422916000916107fc575b506040519081529081906020820190565b61081e915060203d602011610824575b610816818361062b565b810190611726565b386107eb565b503d61080c565b3461023a57600036600319011261023a576108446121b4565b60005460ff8160a01c16156108b15760ff60a01b19166000556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a1337f5b65b0c1363b3003db9bcc5e1fd8805a6d6bf5bf6dc9d3431ee4494cd7d11766600080a2005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b3461023a57600036600319011261023a576004546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576002546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576005546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a57602060ff60005460a01c166040519015158152f35b3461023a57600036600319011261023a576109a76121b4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b60005b8381106109fa5750506000910152565b81810151838201526020016109ea565b90602091610a23815180928185528580860191016109e7565b601f01601f1916010190565b6020815260a0610a4a835182602085015260c0840190610a0a565b926020810151604084015260408101516060840152606081015160808401526080600180841b039101511691015290565b3461023a57610af36000610a8e366106da565b816080604051610a9d816105f4565b606081528260208201528260408201528260608201520152610ad8610acc610acc60025460018060a01b031690565b6001600160a01b031690565b6040518080958194631da3ddcd60e31b835260048301611715565b03915afa80156104d15761042291600091610b16575b5060405191829182610a2f565b610b3391503d806000833e610b2b818361062b565b810190611740565b38610b09565b3461023a57600036600319011261023a576006546040516001600160a01b039091168152602090f35b8015150361023a57565b3461023a57602036600319011261023a57600435610b8981610b62565b610b916121b4565b6001546001600160a01b031690813b1561023a5760009160248392604051948593849263401dfd8560e11b8452151560048401525af180156104d157610bd357005b80610be260006100199361062b565b8061022f565b3461023a57600036600319011261023a57610c016121b4565b610c0961224e565b6000805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a1337f81990fd9a5c552b8e3677917d8a03c07678f0d2cb68f88b634aca2022e9bd19f600080a2005b3461023a57600036600319011261023a576000546040516001600160a01b039091168152602090f35b3461023a57600060203660031901126105db576001548190600435906001600160a01b0316803b15610cf15760248392604051948593849263b17acdcd60e01b845260048401525af180156104d15782906105cd5780f35b5050fd5b60a036600319011261023a57600435602435610d1081610287565b60443591610d1d83610287565b606435916084356001600160401b03811161023a57610d409036906004016106bc565b90610d556001600160a01b03821615156117fd565b610d696001600160a01b0386161515611849565b610d74841515611894565b600254610d8b90610acc906001600160a01b031681565b60405162beb0b560e51b815260208180610da88760048301611715565b0381855afa80156104d157610dc5916000916110d5575b506118ec565b604051631da3ddcd60e31b81529460008680610de48760048301611715565b0381855afa9586156104d1576000966110b0575b50610e05610e0b91611947565b42611d34565b946060810151908115159081611092575b50611080575b50600654610e38906001600160a01b0316610acc565b610e4a6001600160a01b038216610acc565b6040516331a9108f60e11b81526004810187905290602090829060249082905afa9081156104d157600091611051575b50306001600160a01b0390911603610ffb575b50600654610ea790610acc9081906001600160a01b031681565b6002546001600160a01b03169390803b1561023a5760405163095ea7b360e01b81526001600160a01b03959095166004860152602485018690526000908590604490829084905af19081156104d1576020948692610fe6575b50600654610f3990610f1a906001600160a01b0316610acc565b91886040519a8b97889687966387d8de3d60e01b885260048801611da2565b039134905af19182156104d15761042293600093610f9f575b5060408051928352602083018490528201527f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9080606081015b0390a16040519081529081906020820190565b610f8c935091610fde7f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9360203d60201161082457610816818361062b565b935091610f52565b80610be26000610ff59361062b565b38610f00565b803b1561023a57604051632142170760e11b815233600482015230602482015260448101869052906000908290606490829084905af180156104d15715610e8d5780610be2600061104b9361062b565b38610e8d565b611073915060203d602011611079575b61106b818361062b565b810190611d8d565b38610e7a565b503d611061565b61108c90341015611d41565b38610e22565b608001516110a991506001600160a01b0316610acc565b1538610e1c565b610e0b9196506110cd610e05913d806000833e610b2b818361062b565b969150610df8565b6110ee915060203d60201161079357610785818361062b565b38610dbf565b3461023a57600036600319011261023a576003546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576007546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576020604051662386f26fc100008152f35b3461023a57606036600319011261023a5760043561118581610287565b60243561119181610287565b6044359161119d6121b4565b6111b16001600160a01b0383161515611635565b6040516370a0823160e01b81523060048201526001600160a01b0382169390602081602481885afa80156104d1576111f4916000916112ae575b50821115611681565b60405163a9059cbb60e01b81526001600160a01b03841660048201526024810182905293602090859060449082906000905af19081156104d157611265610354927ffe8481f63faf91d08f7565991454ae923fc935d8fcb9a3c8334dcb54c7ade0369660009161128f575b50611de3565b604080516001600160a01b0394851681529490931660208501529183019190915281906060820190565b6112a8915060203d60201161079357610785818361062b565b3861125f565b6112c7915060203d60201161082457610816818361062b565b386111eb565b3461023a57602036600319011261023a576004356112ea81610287565b6112f26121b4565b6001600160a01b0381161561136657600280546001600160a01b038381166001600160a01b03198316179092557f8977e98559e29c9185e31021f81f42c435d8fdf093856040aac30d90543a5682929116604080516001600160a01b03928316815292909116602083015281908101610354565b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b65722063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b9181601f8401121561023a578235916001600160401b03831161023a576020838186019501011161023a57565b3461023a57606036600319011261023a576004356001600160401b03811161023a576114149036906004016113b7565b90602435906001600160401b03821161023a5760209261143b6114459336906004016113b7565b9160443593611eb4565b6040516001600160a01b039091168152f35b3461023a57602036600319011261023a5760043561147481610287565b61147c6121b4565b6001600160a01b038116156114d257600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b8060020b0361023a57565b61010036600319011261023a576004356001600160401b03811161023a5761155d9036906004016113b7565b906024356001600160401b03811161023a5761157d9036906004016113b7565b929060443560643561158e81611526565b6084359162ffffff8316830361023a576115bd966115aa610298565b946115b36102a7565b9660e43598611fec565b604080516001600160a01b03939093168352602083019190915290f35b3461023a57602036600319011261023a576004356001600160401b03811161023a573660238201121561023a5780600401356001600160401b03811161023a573660248260051b8401011161023a5760246100199201612139565b1561163c57565b60405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f7420776974686472617720746f207a65726f2061646472657373006044820152606490fd5b1561168857565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b3d156116ef573d906116d58261066a565b916116e3604051938461062b565b82523d6000602084013e565b606090565b6040513d6000823e3d90fd5b9081602091031261023a57516106d781610b62565b9060206106d7928181520190610a0a565b9081602091031261023a575190565b51906102a582610287565b60208183031261023a578051906001600160401b03821161023a570160a08183031261023a5760405191611773836105f4565b81516001600160401b03811161023a5782019181601f8401121561023a5782519161179d8361066a565b906117ab604051928361062b565b8382526020848601011161023a576117cf6080936117f595602080850191016109e7565b845260208101516020850152604081015160408501526060810151606085015201611735565b608082015290565b1561180457565b60405162461bcd60e51b815260206004820152601c60248201527f4f776e65722063616e6e6f74206265207a65726f2061646472657373000000006044820152606490fd5b1561185057565b606460405162461bcd60e51b815260206004820152602060248201527f436f6c6c6563746f722063616e6e6f74206265207a65726f20616464726573736044820152fd5b1561189b57565b60405162461bcd60e51b8152602060048201526024808201527f4c6f636b206475726174696f6e206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b156118f357565b60405162461bcd60e51b8152602060048201526016602482015275119959481b985b59481b9bdd081cdd5c1c1bdc9d195960521b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b906201518082029180830462015180149015171561196157565b611931565b906ffff97272373d413259a46990580e213a8202918083046ffff97272373d413259a46990580e213a149015171561196157565b906ffff2e50f5f656932ef12357cf3c7fdcc8202918083046ffff2e50f5f656932ef12357cf3c7fdcc149015171561196157565b906fffe5caca7e10e4e61c3624eaa0941cd08202918083046fffe5caca7e10e4e61c3624eaa0941cd0149015171561196157565b906fffcb9843d60f6159c9db58835c9266448202918083046fffcb9843d60f6159c9db58835c926644149015171561196157565b906fff973b41fa98c081472e6896dfb254c08202918083046fff973b41fa98c081472e6896dfb254c0149015171561196157565b906fff2ea16466c96a3843ec78b326b528618202918083046fff2ea16466c96a3843ec78b326b52861149015171561196157565b906ffe5dee046a99a2a811c461f1969c30538202918083046ffe5dee046a99a2a811c461f1969c3053149015171561196157565b906ffcbe86c7900a88aedcffc83b479aa3a48202918083046ffcbe86c7900a88aedcffc83b479aa3a4149015171561196157565b906ff987a7253ac413176f2b074cf7815e548202918083046ff987a7253ac413176f2b074cf7815e54149015171561196157565b906ff3392b0822b70005940c7a398e4b70f38202918083046ff3392b0822b70005940c7a398e4b70f3149015171561196157565b906fe7159475a2c29b7443b29c7fa6e889d98202918083046fe7159475a2c29b7443b29c7fa6e889d9149015171561196157565b906fd097f3bdfd2022b8845ad8f792aa58258202918083046fd097f3bdfd2022b8845ad8f792aa5825149015171561196157565b906fa9f746462d870fdf8a65dc1f90e061e58202918083046fa9f746462d870fdf8a65dc1f90e061e5149015171561196157565b906f70d869a156d2a1b890bb3df62baf32f78202918083046f70d869a156d2a1b890bb3df62baf32f7149015171561196157565b906f31be135f97d08fd981231505542fcfa68202918083046f31be135f97d08fd981231505542fcfa6149015171561196157565b906f09aa508b5b7a84e1c677de54f3e99bc98202918083046f09aa508b5b7a84e1c677de54f3e99bc9149015171561196157565b906e5d6af8dedb81196699c329225ee6048202918083046e5d6af8dedb81196699c329225ee604149015171561196157565b906d2216e584f5fa1ea926041bedfe988202918083046d2216e584f5fa1ea926041bedfe98149015171561196157565b906b048a170391f7dc42444e8fa28202918083046b048a170391f7dc42444e8fa2149015171561196157565b9190820180921161196157565b15611d4857565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e742045544820666f72206c6f636b206665650000006044820152606490fd5b9081602091031261023a57516106d781610287565b6001600160a01b0391821681526020810192909252918216604082015291166060820152608081019190915260c060a082018190526106d792910190610a0a565b15611dea57565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b908060209392818452848401376000828201840152601f01601f1916010190565b949695929093611e66606095611e7494608089526080890191611e27565b918683036020880152611e27565b60408401959095526001600160a01b0316910152565b90611e9d602092828151948592016109e7565b0190565b61ffff1661ffff81146119615760010190565b611f1a9291611ef2611f0092611ef29697610d3c98611ed560208b0161065c565b99808b5261366e60208c0139604051968795309460208801611e48565b03601f19810183528261062b565b604051928391611f14602084018097611e8a565b90611e8a565b519020600454600190611f3790610acc906001600160a01b031681565b905b61ffff811660648111611fc257604080513360208201908152918101839052611f73918691611f6b8160608101611ef2565b51902061220c565b906001600160a01b0382168411611f94575050611f8f90611ea1565b611f39565b6040805161ffff94909416845260208401919091529093506000805160206143ca833981519152925090a190565b50506040805133602082019081526001928201929092526106d7939250611f6b8160608101611ef2565b999895949796929099611ffd61224e565b6040519a61200a8c61060f565b369061201592610685565b8a52369061202292610685565b602089019081526040890183815260029790970b60608a0181815262ffffff9590951660808b018181526001600160a01b0394851660a08d019081529890941660c08c0181815260e08d01898152979a90999098949796909594612087949392612514565b89518551875189516001600160a01b0316908751926120a5946127d5565b975160020b915162ffffff166120bb928961297d565b81519098906001600160a01b03166120d3908a612e42565b519251935194516001600160a01b031691516001546001600160a01b031691516001600160a01b0316926040519687963396612111978d8c8b612295565b037fe066edb1db52f98a38d68a78bc2ca9bab37ef397ba8fd5929a2b4ecb672ab4c091a19190565b6001546001600160a01b031691823b1561023a57604051631eabaee560e31b81526020600482015260248101829052926001600160fb1b03821161023a578360006044828296819660051b80918484013781010301925af180156104d15761219e5750565b806121ab6000809361062b565b80031261023a57565b6000546001600160a01b031633036121c857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60405191602083019160ff60f81b83523060601b6021850152603584015260558301526055825261223e60758361062b565b905190206001600160a01b031690565b60ff60005460a01c1661225d57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b98959a9996936122e6936101209996936122d89360018060a01b03168c5260208c015260018060a01b031660408b015261014060608b01526101408a0190610a0a565b9088820360808a0152610a0a565b60a08701989098526001600160a01b0390811660c087015260e086019190915290811661010085015216910152565b1561231c57565b60405162461bcd60e51b815260206004820152602860248201527f4465706c6f796d656e7420666565206d757374206265206174206c65617374206044820152670605c6062408aa8960c31b6064820152608490fd5b1561237957565b60405162461bcd60e51b815260206004820152602660248201527f526563697069656e74206d75737420626520746865207265717569726564206160448201526564647265737360d01b6064820152608490fd5b156123d457565b60405162461bcd60e51b815260206004820152601f60248201527f526563697069656e7420616d6f756e74206578636565647320737570706c79006044820152606490fd5b9081602091031261023a57516106d781611526565b634e487b7160e01b600052601260045260246000fd5b9060020b9081156124565760020b0790565b61242e565b1561246257565b60405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964207469636b206f72207469636b2073706163696e67000000006044820152606490fd5b65b5e620f47fff1981019190821161196157565b9190820391821161196157565b156124cf57565b60405162461bcd60e51b815260206004820152601c60248201527f50726f746f636f6c20666565207472616e73666572206661696c6564000000006044820152606490fd5b949392916020612605936000805160206143aa8339815191526040518061257f8160809060208152602960208201527f5374617274696e67206465706c6f79546f6b656e2077697468204e46544175746040820152686f4c6f636b6572563560b81b60608201520190565b0390a1612595662386f26fc10000341015612315565b6125bd6001600160a01b03891673c5c216e6e60cce2d189bcce5f6ebffde1e8ce92614612372565b6125c9838511156123cd565b6005546125de906001600160a01b0316610acc565b60405180809781946322afcccb60e01b83526004830191909162ffffff6020820193169052565b03915afa9283156104d15765b5e620f4800061264d6000959486959461264861265e99889788978891612730575b508060020b15159182612713575b505061245b565b6124bb565b975af16126586116c4565b506124c8565b7f1fe20b63cae31fc9f78c0bef12d650e5d82cbb98b7c1d17096830cfff47c6bf86126af61268b346124a7565b6040805134815265b5e620f480006020820152908101919091529081906060820190565b0390a16000805160206143aa8339815191526040518061270e8160809060208152602460208201527f56616c69646174696f6e20616e64206665652068616e646c696e6720636f6d706040820152636c65746560e01b60608201520190565b0390a1565b61272892509061272291612444565b60020b90565b153880612641565b612752915060203d602011612758575b61274a818361062b565b810190612419565b38612633565b503d612740565b9294939060609261277b611e7492608087526080870190610a0a565b908582036020870152610a0a565b1561279057565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e206465706c6f796d656e74206661696c65640000000000000000006044820152606490fd5b9091612822611ef29196959496611f006127f0828787612ff6565b5095611ef2610d3c966128056020890161065c565b9780895261366e60208a013960405194859330926020860161275f565b51906000f5926001600160a01b0384169161283e831515612789565b806128ac575b50506040805181815260119181019190915270151bdad95b8819195c1b1bde595908185d607a1b60608201526001600160a01b03841660208201527fb3f7d6c63a62ab0e6ae5263ef1deb9c5a64f4689288c380db949c116314a55409150806080810161270e565b60405163a9059cbb60e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000905af180156104d1576128f69160009161128f5750611de3565b388080612844565b1561290557565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b919082608091031261023a5781519160208101516fffffffffffffffffffffffffffffffff8116810361023a57916060604083015192015190565b926129878261335d565b6005546129f59060209086906129a5906001600160a01b0316610acc565b6004546001600160a01b031660405163a167129560e01b81526001600160a01b03808c166004830152909116602482015262ffffff90921660448301529092839190829060009082906064820190565b03925af19081156104d157600091612d6d575b506001600160a01b0316803b1561023a5760405163f637731d60e01b81526001600160a01b039290921660048301526000908290602490829084905af180156104d157612d58575b50600554612a66906001600160a01b0316610acc565b6040516322afcccb60e01b815262ffffff851660048201529290602090849060249082905afa9283156104d157612b90946020948793612b1893600092612d33575b50612b04612b0e9293612af8612ace612ac860045460018060a01b031690565b96613642565b95612ae9612ada61064c565b6001600160a01b03909e168e52565b6001600160a01b03168c8b0152565b62ffffff1660408b0152565b60020b6060890152565b60020b6080870152565b60a08501829052600060c0860181905260e086018190526101008601523061012086015242610140860152600654612b58906001600160a01b0316610acc565b60405163095ea7b360e01b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03926001600160a01b03165af180156104d157600092612bbd612c7e926080948691612d14575b506128fe565b600654612bd2906001600160a01b0316610acc565b60408051634418b22b60e11b815283516001600160a01b0390811660048301526020850151811660248301529184015162ffffff1660448201526060840151600290810b60648301526080850151900b608482015260a084015160a482015260c084015160c482015260e084015160e482015261010084015161010482015261012084015190911661012482015261014090920151610144830152909384928391908290610164820190565b03925af19081156104d157600091612ce2575b50906000805160206143aa8339815191526040518061270e8160609060208152601960208201527f506f6f6c20616e6420706f736974696f6e20637265617465640000000000000060408201520190565b612d04915060803d608011612d0d575b612cfc818361062b565b810190612942565b50505038612c91565b503d612cf2565b612d2d915060203d60201161079357610785818361062b565b38612bb7565b612b0e9250612d51612b0491893d8b116127585761274a818361062b565b9250612aa8565b80610be26000612d679361062b565b38612a50565b612d86915060203d6020116110795761106b818361062b565b38612a08565b15612d9357565b60405162461bcd60e51b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b15612deb57565b60405162461bcd60e51b815260206004820152602960248201527f46656520726563697069656e7420636f6e74726163742063616e6e6f742072656044820152680c6cad2ecca408aa8960bb1b6064820152608490fd5b90612e576001600160a01b0382161515612d8c565b803b612faf575b600154612e7590610acc906001600160a01b031681565b803b1561023a57604051633dc4139960e11b8152600481018490526001600160a01b039290921660248301526000908290604490829084905af180156104d157612f9a575b50600654612ed0906001600160a01b0316610acc565b6001549091906001600160a01b031690823b1561023a57604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820152906000908290606490829084905af180156104d157612f85575b506000805160206143aa8339815191526040518061270e8160809060208152602260208201527f4e4654207472616e7366657272656420746f204e46544175746f4c6f636b6572604082015261563560f01b60608201520190565b80610be26000612f949361062b565b38612f2a565b80610be26000612fa99361062b565b38612eba565b612fc9600080808080865af1612fc36116c4565b50612de4565b612e5e565b61ffff16612710019061ffff821161196157565b61ffff16614e20019061ffff821161196157565b9161301590611f00611ef293611ef2610d3c966128056020890161065c565b5190206004546001929061303390610acc906001600160a01b031681565b925b61ffff811661138881116130c8576040805133602082019081529181018390526130628160608101611ef2565b51902061306f858261220c565b916001600160a01b03831687116130915750505061308c90611ea1565b613035565b6040805161ffff909516855260208501919091529195509293506000805160206143ca8339815191529190819081015b0390a19190565b505091909160005b61012c61ffff82161061322b575060005b6103e861ffff8216106131505760405162461bcd60e51b815260206004820152603460248201527f436f756c64206e6f742066696e642076616c69642073616c74202d2074727920604482015273646966666572656e7420746f6b656e206e616d6560601b6064820152608490fd5b60408051426020820190815261ffff8416928201929092526131758160608101611ef2565b51902060408051336020820190815291810192909252906131998160608101611ef2565b5190206131a6858261220c565b906001600160a01b03821685116131c557505060010161ffff166130e1565b9293509350806131e36000805160206143ca83398151915292612fe2565b9060405161320b81611ef26020820194428690929161ffff6020916040840195845216910152565b5190206040805161ffff90931683526020830191909152819081016130c1565b604080514260208201908152439282019290925261ffff831660608201526132568160808101611ef2565b519020604080513360208201908152918101929092529061327a8160608101611ef2565b519020613287858261220c565b906001600160a01b03821685116132a657505060010161ffff166130d0565b9293509350806132c46000805160206143ca83398151915292612fce565b9060405161320b81611ef2602082019443428791604091949361ffff9160608501968552602085015216910152565b600160ff1b81146119615760000390565b1561330b57565b60405162461bcd60e51b815260206004820152601b60248201527f5469636b4d6174683a205449434b5f4f55545f4f465f52414e474500000000006044820152606490fd5b8015612456576000190490565b610acc6106d79160020b6000811260001461363c5761337b816132f3565b905b61338c620d89e8831115613304565b600182161561362a576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116613617575b60048116613604575b600881166135f1575b601081166135de575b602081166135cb575b604081166135b8575b608081166135a5575b6101008116613592575b610200811661357f575b610400811661356c575b6108008116613559575b6110008116613546575b6120008116613533575b6140008116613520575b618000811661350d575b6201000081166134fa575b6202000081166134e7575b6204000081166134ce575b62080000166134b1575b6000126134a3575b61348a6134808260201c90565b9163ffffffff1690565b61349a5760ff60005b1690611d34565b60ff6001613493565b6134ac90613350565b613473565b906134c66134c0600092611d08565b60801c90565b91905061346b565b916134df6134c06208000092611cd8565b929050613461565b916134c06134f491611ca6565b91613456565b916134c061350791611c72565b9161344b565b916134c061351a91611c3e565b91613440565b916134c061352d91611c0a565b91613436565b916134c061354091611bd6565b9161342c565b916134c061355391611ba2565b91613422565b916134c061356691611b6e565b91613418565b916134c061357991611b3a565b9161340e565b916134c061358c91611b06565b91613404565b916134c061359f91611ad2565b916133fa565b916134c06135b291611a9e565b916133f0565b916134c06135c591611a6a565b916133e7565b916134c06135d891611a36565b916133de565b916134c06135eb91611a02565b916133d5565b916134c06135fe916119ce565b916133cc565b916134c06136119161199a565b916133c3565b916134c061362491611966565b916133ba565b6001600160881b03600160801b6133af565b8061337d565b60020b801561245657620d89e80760020b620d89e803627fffff8113627fffff19821217611961579056fe6080604052346103fa57610d3c80380380610019816103ff565b9283398101906080818303126103fa5780516001600160401b0381116103fa5782610045918301610424565b602082015190926001600160401b0382116103fa57610065918301610424565b604082015160609092015190916001600160a01b038216918290036103fa5783516001600160401b03811161030357600354600181811c911680156103f0575b60208210146102e357601f811161038b575b50602094601f821160011461032457948192939495600092610319575b50508160011b916000199060031b1c1916176003555b82516001600160401b03811161030357600454600181811c911680156102f9575b60208210146102e357601f811161027e575b506020601f8211600114610217578192939460009261020c575b50508160011b916000199060031b1c1916176004555b81156101c757600254908082018092116101b15760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160009360025584845283825260408420818154019055604051908152a36040516108ac90816104908239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b015190503880610137565b601f198216906004600052806000209160005b8181106102665750958360019596971061024d575b505050811b0160045561014d565b015160001960f88460031b161c1916905538808061023f565b9192602060018192868b01518155019401920161022a565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106102d9575b601f0160051c01905b8181106102cd575061011d565b600081556001016102c0565b90915081906102b7565b634e487b7160e01b600052602260045260246000fd5b90607f169061010b565b634e487b7160e01b600052604160045260246000fd5b0151905038806100d4565b601f198216956003600052806000209160005b8881106103735750836001959697981061035a575b505050811b016003556100ea565b015160001960f88460031b161c1916905538808061034c565b91926020600181928685015181550194019201610337565b60036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106103e6575b601f0160051c01905b8181106103da57506100b7565b600081556001016103cd565b90915081906103c4565b90607f16906100a5565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761030357604052565b81601f820112156103fa578051906001600160401b03821161030357610453601f8301601f19166020016103ff565b92828452602083830101116103fa5760005b82811061047a57505060206000918301015290565b8060208092840101518282870101520161046556fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde03146104a757508063095ea7b31461048157806318160ddd1461046357806323b872dd146103a5578063313ce56714610389578063395093511461032157806370a08231146102e757806395d89b41146101c6578063a457c2d71461011f578063a9059cbb146100ee5763dd62ed3e1461009857600080fd5b346100e95760403660031901126100e9576100b16105c3565b6100b96105d9565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b600080fd5b346100e95760403660031901126100e95761011461010a6105c3565b60243590336106f7565b602060405160018152f35b346100e95760403660031901126100e9576101386105c3565b60243590336000526001602052604060002060018060a01b0382166000526020526040600020549180831061017357610114920390336105ef565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346100e95760003660031901126100e95760405160006004548060011c906001811680156102dd575b6020831081146102c9578285529081156102ad5750600114610256575b50819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b0390f35b634e487b7160e01b600052604160045260246000fd5b905060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6000905b8282106102975750602091508201018261020c565b6001816020925483858801015201910190610282565b90506020925060ff191682840152151560051b8201018261020c565b634e487b7160e01b84526022600452602484fd5b91607f16916101ef565b346100e95760203660031901126100e9576001600160a01b036103086105c3565b1660005260006020526020604060002054604051908152f35b346100e95760403660031901126100e95761033a6105c3565b336000526001602052604060002060018060a01b03821660005260205260406000205460243581018091116103735761011491336105ef565b634e487b7160e01b600052601160045260246000fd5b346100e95760003660031901126100e957602060405160128152f35b346100e95760603660031901126100e9576103be6105c3565b6103c66105d9565b6001600160a01b0382166000908152600160208181526040808420338552909152909120549260443592918401610402575b61011493506106f7565b82841061041e5761041983610114950333836105ef565b6103f8565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346100e95760003660031901126100e9576020600254604051908152f35b346100e95760403660031901126100e95761011461049d6105c3565b60243590336105ef565b346100e95760003660031901126100e95760006003548060011c90600181168015610570575b6020831081146102c9578285529081156102ad57506001146105195750819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b905060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b6000905b82821061055a5750602091508201018261020c565b6001816020925483858801015201910190610545565b91607f16916104cd565b91909160208152825180602083015260005b8181106105ad575060409293506000838284010152601f8019910116010190565b806020809287010151604082860101520161058c565b600435906001600160a01b03821682036100e957565b602435906001600160a01b03821682036100e957565b6001600160a01b03169081156106a6576001600160a01b03169182156106565760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b0316908115610823576001600160a01b03169182156107d25781600052600060205260406000205481811061077e57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209285600052600084520360406000205584600052600082526040600020818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fdfea264697066735822122074ff4234c658f74e187510519776b8ea4e39b5c6743b1caeebf48be4c2f0270464736f6c634300081a003394ebca8d29d278a0288a52a710c11e928307b6f2e15fbaf4508cc4ceb3d21f8b2d85e5bc21a27644fa43503d10d34b03fef575277be4ae9f6da8f6f484ab0652a2646970667358221220fc89f062f0f16d35043a568f1cacb772d61a3999b149b553636a8c30706af53264736f6c634300081a0033000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b000000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806202eab71461022a578062a04feb146102255780630150b5db14610220578063058e58341461021b5780630b4501fd1461021657806317508637146101f85780632f9c02b61461021157806334dea1691461020c5780633a5642f4146102075780633f4ba83a146102025780633fc8cef3146101fd578063477f6e42146101f85780634e9c8927146101e45780635b549182146101f35780635c975abb146101c6578063715018a6146101ee5780637192c566146101e95780637919dd34146101e4578063791b98bc146101df578063803bfb0a146101da5780638456cb59146101d55780638da5cb5b146101d0578063b17acdcd146101cb578063b187bd26146101c6578063b5989102146101c1578063bea1dcf8146101bc578063c31c9c07146101b7578063d55ac27f146101b2578063d63f4594146101ad578063dbd96fa3146101a8578063eab1f410146101a3578063f2fde38b1461019e578063f45fc718146101995763f55d77280361000e576115da565b611531565b611457565b6113e4565b6112cd565b611168565b611146565b61111d565b6110f4565b610cf5565b610968565b610c99565b610c70565b610be8565b610b6c565b610b39565b610916565b610a7b565b61098e565b61093f565b610526565b6108ed565b61082b565b61079a565b610704565b61054f565b610505565b6104d6565b6103ce565b6102b4565b61023f565b600091031261023a57565b600080fd5b3461023a57600036600319011261023a576060604051662386f26fc10000815265b5e620f48000602082015273c5c216e6e60cce2d189bcce5f6ebffde1e8ce9266040820152f35b6001600160a01b0381160361023a57565b60a435906102a582610287565b565b60c435906102a582610287565b3461023a57604036600319011261023a576004356102d181610287565b6024356102dc6121b4565b6102f06001600160a01b0383161515611635565b6102fc47821115611681565b600080808084865af161030d6116c4565b501561035957604080516001600160a01b03909316835260208301919091527fc8509a63402c5fc92474eaf55ef1d99608b69605f3e4a4a29dfafff277f9e9d79190819081015b0390a1005b60405162461bcd60e51b8152602060048201526013602482015272115512081d1c985b9cd9995c8819985a5b1959606a1b6044820152606490fd5b602060408183019282815284518094520192019060005b8181106103b85750505090565b82518452602093840193909201916001016103ab565b3461023a57600036600319011261023a57600154604051630150b5db60e01b815290600090829060049082906001600160a01b03165afa9081156104d157600091610426575b604051806104228482610394565b0390f35b3d8083833e610435818361062b565b8101906020818303126104c9578051906001600160401b0382116104cd570181601f820112156104c9578051926001600160401b0384116104c4578360051b9160405194610486602085018761062b565b85526020808601938201019384116104c057602001915b8383106104b05750505050610422610414565b825181526020928301920161049d565b5080fd5b6105de565b8280fd5b8380fd5b6116f4565b3461023a57600036600319011261023a57602060405173c5c216e6e60cce2d189bcce5f6ebffde1e8ce9268152f35b3461023a57600036600319011261023a57602060405165b5e620f480008152f35b3461023a57600036600319011261023a576001546040516001600160a01b039091168152602090f35b3461023a57600060403660031901126105db5760043561056e81610287565b8160243561057a6121b4565b6001546001600160a01b0316803b156104c957604051634782f77960e01b81526001600160a01b0394909416600485015260248401919091528290604490829084905af180156104d15782906105cd5780f35b6105d69161062b565b388180f35b80fd5b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b038211176104c457604052565b61010081019081106001600160401b038211176104c457604052565b90601f801991011681019081106001600160401b038211176104c457604052565b604051906102a56101608361062b565b906102a5604051928361062b565b6001600160401b0381116104c457601f01601f191660200190565b9291926106918261066a565b9161069f604051938461062b565b82948184528183011161023a578281602093846000960137010152565b9080601f8301121561023a578160206106d793359101610685565b90565b602060031982011261023a57600435906001600160401b03821161023a576106d7916004016106bc565b3461023a576107426020610717366106da565b60018060a01b0360025416604051808095819462beb0b560e51b835286600484018181520190610a0a565b03915afa80156104d1576104229160009161076b575b5060405190151581529081906020820190565b61078d915060203d602011610793575b610785818361062b565b810190611700565b38610758565b503d61077b565b3461023a57602036600319011261023a5760015460405163232633a360e11b8152600480359082015290602090829060249082906001600160a01b03165afa80156104d157610422916000916107fc575b506040519081529081906020820190565b61081e915060203d602011610824575b610816818361062b565b810190611726565b386107eb565b503d61080c565b3461023a57600036600319011261023a576108446121b4565b60005460ff8160a01c16156108b15760ff60a01b19166000556040513381527f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa90602090a1337f5b65b0c1363b3003db9bcc5e1fd8805a6d6bf5bf6dc9d3431ee4494cd7d11766600080a2005b60405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b6044820152606490fd5b3461023a57600036600319011261023a576004546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576002546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576005546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a57602060ff60005460a01c166040519015158152f35b3461023a57600036600319011261023a576109a76121b4565b600080546001600160a01b0319811682556001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b60005b8381106109fa5750506000910152565b81810151838201526020016109ea565b90602091610a23815180928185528580860191016109e7565b601f01601f1916010190565b6020815260a0610a4a835182602085015260c0840190610a0a565b926020810151604084015260408101516060840152606081015160808401526080600180841b039101511691015290565b3461023a57610af36000610a8e366106da565b816080604051610a9d816105f4565b606081528260208201528260408201528260608201520152610ad8610acc610acc60025460018060a01b031690565b6001600160a01b031690565b6040518080958194631da3ddcd60e31b835260048301611715565b03915afa80156104d15761042291600091610b16575b5060405191829182610a2f565b610b3391503d806000833e610b2b818361062b565b810190611740565b38610b09565b3461023a57600036600319011261023a576006546040516001600160a01b039091168152602090f35b8015150361023a57565b3461023a57602036600319011261023a57600435610b8981610b62565b610b916121b4565b6001546001600160a01b031690813b1561023a5760009160248392604051948593849263401dfd8560e11b8452151560048401525af180156104d157610bd357005b80610be260006100199361062b565b8061022f565b3461023a57600036600319011261023a57610c016121b4565b610c0961224e565b6000805460ff60a01b1916600160a01b1790556040513381527f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a25890602090a1337f81990fd9a5c552b8e3677917d8a03c07678f0d2cb68f88b634aca2022e9bd19f600080a2005b3461023a57600036600319011261023a576000546040516001600160a01b039091168152602090f35b3461023a57600060203660031901126105db576001548190600435906001600160a01b0316803b15610cf15760248392604051948593849263b17acdcd60e01b845260048401525af180156104d15782906105cd5780f35b5050fd5b60a036600319011261023a57600435602435610d1081610287565b60443591610d1d83610287565b606435916084356001600160401b03811161023a57610d409036906004016106bc565b90610d556001600160a01b03821615156117fd565b610d696001600160a01b0386161515611849565b610d74841515611894565b600254610d8b90610acc906001600160a01b031681565b60405162beb0b560e51b815260208180610da88760048301611715565b0381855afa80156104d157610dc5916000916110d5575b506118ec565b604051631da3ddcd60e31b81529460008680610de48760048301611715565b0381855afa9586156104d1576000966110b0575b50610e05610e0b91611947565b42611d34565b946060810151908115159081611092575b50611080575b50600654610e38906001600160a01b0316610acc565b610e4a6001600160a01b038216610acc565b6040516331a9108f60e11b81526004810187905290602090829060249082905afa9081156104d157600091611051575b50306001600160a01b0390911603610ffb575b50600654610ea790610acc9081906001600160a01b031681565b6002546001600160a01b03169390803b1561023a5760405163095ea7b360e01b81526001600160a01b03959095166004860152602485018690526000908590604490829084905af19081156104d1576020948692610fe6575b50600654610f3990610f1a906001600160a01b0316610acc565b91886040519a8b97889687966387d8de3d60e01b885260048801611da2565b039134905af19182156104d15761042293600093610f9f575b5060408051928352602083018490528201527f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9080606081015b0390a16040519081529081906020820190565b610f8c935091610fde7f551698bdc559ecd28afa921d1e208573aaa3115abf7710efcb3dc7bda5e017fb9360203d60201161082457610816818361062b565b935091610f52565b80610be26000610ff59361062b565b38610f00565b803b1561023a57604051632142170760e11b815233600482015230602482015260448101869052906000908290606490829084905af180156104d15715610e8d5780610be2600061104b9361062b565b38610e8d565b611073915060203d602011611079575b61106b818361062b565b810190611d8d565b38610e7a565b503d611061565b61108c90341015611d41565b38610e22565b608001516110a991506001600160a01b0316610acc565b1538610e1c565b610e0b9196506110cd610e05913d806000833e610b2b818361062b565b969150610df8565b6110ee915060203d60201161079357610785818361062b565b38610dbf565b3461023a57600036600319011261023a576003546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576007546040516001600160a01b039091168152602090f35b3461023a57600036600319011261023a576020604051662386f26fc100008152f35b3461023a57606036600319011261023a5760043561118581610287565b60243561119181610287565b6044359161119d6121b4565b6111b16001600160a01b0383161515611635565b6040516370a0823160e01b81523060048201526001600160a01b0382169390602081602481885afa80156104d1576111f4916000916112ae575b50821115611681565b60405163a9059cbb60e01b81526001600160a01b03841660048201526024810182905293602090859060449082906000905af19081156104d157611265610354927ffe8481f63faf91d08f7565991454ae923fc935d8fcb9a3c8334dcb54c7ade0369660009161128f575b50611de3565b604080516001600160a01b0394851681529490931660208501529183019190915281906060820190565b6112a8915060203d60201161079357610785818361062b565b3861125f565b6112c7915060203d60201161082457610816818361062b565b386111eb565b3461023a57602036600319011261023a576004356112ea81610287565b6112f26121b4565b6001600160a01b0381161561136657600280546001600160a01b038381166001600160a01b03198316179092557f8977e98559e29c9185e31021f81f42c435d8fdf093856040aac30d90543a5682929116604080516001600160a01b03928316815292909116602083015281908101610354565b60405162461bcd60e51b8152602060048201526024808201527f476f506c7573206c6f636b65722063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b9181601f8401121561023a578235916001600160401b03831161023a576020838186019501011161023a57565b3461023a57606036600319011261023a576004356001600160401b03811161023a576114149036906004016113b7565b90602435906001600160401b03821161023a5760209261143b6114459336906004016113b7565b9160443593611eb4565b6040516001600160a01b039091168152f35b3461023a57602036600319011261023a5760043561147481610287565b61147c6121b4565b6001600160a01b038116156114d257600080546001600160a01b039283166001600160a01b03198216811783559216907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09080a3005b60405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b6064820152608490fd5b8060020b0361023a57565b61010036600319011261023a576004356001600160401b03811161023a5761155d9036906004016113b7565b906024356001600160401b03811161023a5761157d9036906004016113b7565b929060443560643561158e81611526565b6084359162ffffff8316830361023a576115bd966115aa610298565b946115b36102a7565b9660e43598611fec565b604080516001600160a01b03939093168352602083019190915290f35b3461023a57602036600319011261023a576004356001600160401b03811161023a573660238201121561023a5780600401356001600160401b03811161023a573660248260051b8401011161023a5760246100199201612139565b1561163c57565b60405162461bcd60e51b815260206004820152601f60248201527f43616e6e6f7420776974686472617720746f207a65726f2061646472657373006044820152606490fd5b1561168857565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b3d156116ef573d906116d58261066a565b916116e3604051938461062b565b82523d6000602084013e565b606090565b6040513d6000823e3d90fd5b9081602091031261023a57516106d781610b62565b9060206106d7928181520190610a0a565b9081602091031261023a575190565b51906102a582610287565b60208183031261023a578051906001600160401b03821161023a570160a08183031261023a5760405191611773836105f4565b81516001600160401b03811161023a5782019181601f8401121561023a5782519161179d8361066a565b906117ab604051928361062b565b8382526020848601011161023a576117cf6080936117f595602080850191016109e7565b845260208101516020850152604081015160408501526060810151606085015201611735565b608082015290565b1561180457565b60405162461bcd60e51b815260206004820152601c60248201527f4f776e65722063616e6e6f74206265207a65726f2061646472657373000000006044820152606490fd5b1561185057565b606460405162461bcd60e51b815260206004820152602060248201527f436f6c6c6563746f722063616e6e6f74206265207a65726f20616464726573736044820152fd5b1561189b57565b60405162461bcd60e51b8152602060048201526024808201527f4c6f636b206475726174696f6e206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b156118f357565b60405162461bcd60e51b8152602060048201526016602482015275119959481b985b59481b9bdd081cdd5c1c1bdc9d195960521b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b906201518082029180830462015180149015171561196157565b611931565b906ffff97272373d413259a46990580e213a8202918083046ffff97272373d413259a46990580e213a149015171561196157565b906ffff2e50f5f656932ef12357cf3c7fdcc8202918083046ffff2e50f5f656932ef12357cf3c7fdcc149015171561196157565b906fffe5caca7e10e4e61c3624eaa0941cd08202918083046fffe5caca7e10e4e61c3624eaa0941cd0149015171561196157565b906fffcb9843d60f6159c9db58835c9266448202918083046fffcb9843d60f6159c9db58835c926644149015171561196157565b906fff973b41fa98c081472e6896dfb254c08202918083046fff973b41fa98c081472e6896dfb254c0149015171561196157565b906fff2ea16466c96a3843ec78b326b528618202918083046fff2ea16466c96a3843ec78b326b52861149015171561196157565b906ffe5dee046a99a2a811c461f1969c30538202918083046ffe5dee046a99a2a811c461f1969c3053149015171561196157565b906ffcbe86c7900a88aedcffc83b479aa3a48202918083046ffcbe86c7900a88aedcffc83b479aa3a4149015171561196157565b906ff987a7253ac413176f2b074cf7815e548202918083046ff987a7253ac413176f2b074cf7815e54149015171561196157565b906ff3392b0822b70005940c7a398e4b70f38202918083046ff3392b0822b70005940c7a398e4b70f3149015171561196157565b906fe7159475a2c29b7443b29c7fa6e889d98202918083046fe7159475a2c29b7443b29c7fa6e889d9149015171561196157565b906fd097f3bdfd2022b8845ad8f792aa58258202918083046fd097f3bdfd2022b8845ad8f792aa5825149015171561196157565b906fa9f746462d870fdf8a65dc1f90e061e58202918083046fa9f746462d870fdf8a65dc1f90e061e5149015171561196157565b906f70d869a156d2a1b890bb3df62baf32f78202918083046f70d869a156d2a1b890bb3df62baf32f7149015171561196157565b906f31be135f97d08fd981231505542fcfa68202918083046f31be135f97d08fd981231505542fcfa6149015171561196157565b906f09aa508b5b7a84e1c677de54f3e99bc98202918083046f09aa508b5b7a84e1c677de54f3e99bc9149015171561196157565b906e5d6af8dedb81196699c329225ee6048202918083046e5d6af8dedb81196699c329225ee604149015171561196157565b906d2216e584f5fa1ea926041bedfe988202918083046d2216e584f5fa1ea926041bedfe98149015171561196157565b906b048a170391f7dc42444e8fa28202918083046b048a170391f7dc42444e8fa2149015171561196157565b9190820180921161196157565b15611d4857565b60405162461bcd60e51b815260206004820152601d60248201527f496e73756666696369656e742045544820666f72206c6f636b206665650000006044820152606490fd5b9081602091031261023a57516106d781610287565b6001600160a01b0391821681526020810192909252918216604082015291166060820152608081019190915260c060a082018190526106d792910190610a0a565b15611dea57565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b881d1c985b9cd9995c8819985a5b1959605a1b6044820152606490fd5b908060209392818452848401376000828201840152601f01601f1916010190565b949695929093611e66606095611e7494608089526080890191611e27565b918683036020880152611e27565b60408401959095526001600160a01b0316910152565b90611e9d602092828151948592016109e7565b0190565b61ffff1661ffff81146119615760010190565b611f1a9291611ef2611f0092611ef29697610d3c98611ed560208b0161065c565b99808b5261366e60208c0139604051968795309460208801611e48565b03601f19810183528261062b565b604051928391611f14602084018097611e8a565b90611e8a565b519020600454600190611f3790610acc906001600160a01b031681565b905b61ffff811660648111611fc257604080513360208201908152918101839052611f73918691611f6b8160608101611ef2565b51902061220c565b906001600160a01b0382168411611f94575050611f8f90611ea1565b611f39565b6040805161ffff94909416845260208401919091529093506000805160206143ca833981519152925090a190565b50506040805133602082019081526001928201929092526106d7939250611f6b8160608101611ef2565b999895949796929099611ffd61224e565b6040519a61200a8c61060f565b369061201592610685565b8a52369061202292610685565b602089019081526040890183815260029790970b60608a0181815262ffffff9590951660808b018181526001600160a01b0394851660a08d019081529890941660c08c0181815260e08d01898152979a90999098949796909594612087949392612514565b89518551875189516001600160a01b0316908751926120a5946127d5565b975160020b915162ffffff166120bb928961297d565b81519098906001600160a01b03166120d3908a612e42565b519251935194516001600160a01b031691516001546001600160a01b031691516001600160a01b0316926040519687963396612111978d8c8b612295565b037fe066edb1db52f98a38d68a78bc2ca9bab37ef397ba8fd5929a2b4ecb672ab4c091a19190565b6001546001600160a01b031691823b1561023a57604051631eabaee560e31b81526020600482015260248101829052926001600160fb1b03821161023a578360006044828296819660051b80918484013781010301925af180156104d15761219e5750565b806121ab6000809361062b565b80031261023a57565b6000546001600160a01b031633036121c857565b606460405162461bcd60e51b815260206004820152602060248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152fd5b60405191602083019160ff60f81b83523060601b6021850152603584015260558301526055825261223e60758361062b565b905190206001600160a01b031690565b60ff60005460a01c1661225d57565b60405162461bcd60e51b815260206004820152601060248201526f14185d5cd8589b194e881c185d5cd95960821b6044820152606490fd5b98959a9996936122e6936101209996936122d89360018060a01b03168c5260208c015260018060a01b031660408b015261014060608b01526101408a0190610a0a565b9088820360808a0152610a0a565b60a08701989098526001600160a01b0390811660c087015260e086019190915290811661010085015216910152565b1561231c57565b60405162461bcd60e51b815260206004820152602860248201527f4465706c6f796d656e7420666565206d757374206265206174206c65617374206044820152670605c6062408aa8960c31b6064820152608490fd5b1561237957565b60405162461bcd60e51b815260206004820152602660248201527f526563697069656e74206d75737420626520746865207265717569726564206160448201526564647265737360d01b6064820152608490fd5b156123d457565b60405162461bcd60e51b815260206004820152601f60248201527f526563697069656e7420616d6f756e74206578636565647320737570706c79006044820152606490fd5b9081602091031261023a57516106d781611526565b634e487b7160e01b600052601260045260246000fd5b9060020b9081156124565760020b0790565b61242e565b1561246257565b60405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964207469636b206f72207469636b2073706163696e67000000006044820152606490fd5b65b5e620f47fff1981019190821161196157565b9190820391821161196157565b156124cf57565b60405162461bcd60e51b815260206004820152601c60248201527f50726f746f636f6c20666565207472616e73666572206661696c6564000000006044820152606490fd5b949392916020612605936000805160206143aa8339815191526040518061257f8160809060208152602960208201527f5374617274696e67206465706c6f79546f6b656e2077697468204e46544175746040820152686f4c6f636b6572563560b81b60608201520190565b0390a1612595662386f26fc10000341015612315565b6125bd6001600160a01b03891673c5c216e6e60cce2d189bcce5f6ebffde1e8ce92614612372565b6125c9838511156123cd565b6005546125de906001600160a01b0316610acc565b60405180809781946322afcccb60e01b83526004830191909162ffffff6020820193169052565b03915afa9283156104d15765b5e620f4800061264d6000959486959461264861265e99889788978891612730575b508060020b15159182612713575b505061245b565b6124bb565b975af16126586116c4565b506124c8565b7f1fe20b63cae31fc9f78c0bef12d650e5d82cbb98b7c1d17096830cfff47c6bf86126af61268b346124a7565b6040805134815265b5e620f480006020820152908101919091529081906060820190565b0390a16000805160206143aa8339815191526040518061270e8160809060208152602460208201527f56616c69646174696f6e20616e64206665652068616e646c696e6720636f6d706040820152636c65746560e01b60608201520190565b0390a1565b61272892509061272291612444565b60020b90565b153880612641565b612752915060203d602011612758575b61274a818361062b565b810190612419565b38612633565b503d612740565b9294939060609261277b611e7492608087526080870190610a0a565b908582036020870152610a0a565b1561279057565b60405162461bcd60e51b815260206004820152601760248201527f546f6b656e206465706c6f796d656e74206661696c65640000000000000000006044820152606490fd5b9091612822611ef29196959496611f006127f0828787612ff6565b5095611ef2610d3c966128056020890161065c565b9780895261366e60208a013960405194859330926020860161275f565b51906000f5926001600160a01b0384169161283e831515612789565b806128ac575b50506040805181815260119181019190915270151bdad95b8819195c1b1bde595908185d607a1b60608201526001600160a01b03841660208201527fb3f7d6c63a62ab0e6ae5263ef1deb9c5a64f4689288c380db949c116314a55409150806080810161270e565b60405163a9059cbb60e01b81526001600160a01b03929092166004830152602482015290602090829060449082906000905af180156104d1576128f69160009161128f5750611de3565b388080612844565b1561290557565b60405162461bcd60e51b8152602060048201526015602482015274151bdad95b88185c1c1c9bdd985b0819985a5b1959605a1b6044820152606490fd5b919082608091031261023a5781519160208101516fffffffffffffffffffffffffffffffff8116810361023a57916060604083015192015190565b926129878261335d565b6005546129f59060209086906129a5906001600160a01b0316610acc565b6004546001600160a01b031660405163a167129560e01b81526001600160a01b03808c166004830152909116602482015262ffffff90921660448301529092839190829060009082906064820190565b03925af19081156104d157600091612d6d575b506001600160a01b0316803b1561023a5760405163f637731d60e01b81526001600160a01b039290921660048301526000908290602490829084905af180156104d157612d58575b50600554612a66906001600160a01b0316610acc565b6040516322afcccb60e01b815262ffffff851660048201529290602090849060249082905afa9283156104d157612b90946020948793612b1893600092612d33575b50612b04612b0e9293612af8612ace612ac860045460018060a01b031690565b96613642565b95612ae9612ada61064c565b6001600160a01b03909e168e52565b6001600160a01b03168c8b0152565b62ffffff1660408b0152565b60020b6060890152565b60020b6080870152565b60a08501829052600060c0860181905260e086018190526101008601523061012086015242610140860152600654612b58906001600160a01b0316610acc565b60405163095ea7b360e01b81526001600160a01b03909116600482015260248101929092529092839190829060009082906044820190565b03926001600160a01b03165af180156104d157600092612bbd612c7e926080948691612d14575b506128fe565b600654612bd2906001600160a01b0316610acc565b60408051634418b22b60e11b815283516001600160a01b0390811660048301526020850151811660248301529184015162ffffff1660448201526060840151600290810b60648301526080850151900b608482015260a084015160a482015260c084015160c482015260e084015160e482015261010084015161010482015261012084015190911661012482015261014090920151610144830152909384928391908290610164820190565b03925af19081156104d157600091612ce2575b50906000805160206143aa8339815191526040518061270e8160609060208152601960208201527f506f6f6c20616e6420706f736974696f6e20637265617465640000000000000060408201520190565b612d04915060803d608011612d0d575b612cfc818361062b565b810190612942565b50505038612c91565b503d612cf2565b612d2d915060203d60201161079357610785818361062b565b38612bb7565b612b0e9250612d51612b0491893d8b116127585761274a818361062b565b9250612aa8565b80610be26000612d679361062b565b38612a50565b612d86915060203d6020116110795761106b818361062b565b38612a08565b15612d9357565b60405162461bcd60e51b8152602060048201526024808201527f46656520726563697069656e742063616e6e6f74206265207a65726f206164646044820152637265737360e01b6064820152608490fd5b15612deb57565b60405162461bcd60e51b815260206004820152602960248201527f46656520726563697069656e7420636f6e74726163742063616e6e6f742072656044820152680c6cad2ecca408aa8960bb1b6064820152608490fd5b90612e576001600160a01b0382161515612d8c565b803b612faf575b600154612e7590610acc906001600160a01b031681565b803b1561023a57604051633dc4139960e11b8152600481018490526001600160a01b039290921660248301526000908290604490829084905af180156104d157612f9a575b50600654612ed0906001600160a01b0316610acc565b6001549091906001600160a01b031690823b1561023a57604051632142170760e11b81523060048201526001600160a01b039290921660248301526044820152906000908290606490829084905af180156104d157612f85575b506000805160206143aa8339815191526040518061270e8160809060208152602260208201527f4e4654207472616e7366657272656420746f204e46544175746f4c6f636b6572604082015261563560f01b60608201520190565b80610be26000612f949361062b565b38612f2a565b80610be26000612fa99361062b565b38612eba565b612fc9600080808080865af1612fc36116c4565b50612de4565b612e5e565b61ffff16612710019061ffff821161196157565b61ffff16614e20019061ffff821161196157565b9161301590611f00611ef293611ef2610d3c966128056020890161065c565b5190206004546001929061303390610acc906001600160a01b031681565b925b61ffff811661138881116130c8576040805133602082019081529181018390526130628160608101611ef2565b51902061306f858261220c565b916001600160a01b03831687116130915750505061308c90611ea1565b613035565b6040805161ffff909516855260208501919091529195509293506000805160206143ca8339815191529190819081015b0390a19190565b505091909160005b61012c61ffff82161061322b575060005b6103e861ffff8216106131505760405162461bcd60e51b815260206004820152603460248201527f436f756c64206e6f742066696e642076616c69642073616c74202d2074727920604482015273646966666572656e7420746f6b656e206e616d6560601b6064820152608490fd5b60408051426020820190815261ffff8416928201929092526131758160608101611ef2565b51902060408051336020820190815291810192909252906131998160608101611ef2565b5190206131a6858261220c565b906001600160a01b03821685116131c557505060010161ffff166130e1565b9293509350806131e36000805160206143ca83398151915292612fe2565b9060405161320b81611ef26020820194428690929161ffff6020916040840195845216910152565b5190206040805161ffff90931683526020830191909152819081016130c1565b604080514260208201908152439282019290925261ffff831660608201526132568160808101611ef2565b519020604080513360208201908152918101929092529061327a8160608101611ef2565b519020613287858261220c565b906001600160a01b03821685116132a657505060010161ffff166130d0565b9293509350806132c46000805160206143ca83398151915292612fce565b9060405161320b81611ef2602082019443428791604091949361ffff9160608501968552602085015216910152565b600160ff1b81146119615760000390565b1561330b57565b60405162461bcd60e51b815260206004820152601b60248201527f5469636b4d6174683a205449434b5f4f55545f4f465f52414e474500000000006044820152606490fd5b8015612456576000190490565b610acc6106d79160020b6000811260001461363c5761337b816132f3565b905b61338c620d89e8831115613304565b600182161561362a576001600160881b036ffffcb933bd6fad37aa2d162d1a5940015b169160028116613617575b60048116613604575b600881166135f1575b601081166135de575b602081166135cb575b604081166135b8575b608081166135a5575b6101008116613592575b610200811661357f575b610400811661356c575b6108008116613559575b6110008116613546575b6120008116613533575b6140008116613520575b618000811661350d575b6201000081166134fa575b6202000081166134e7575b6204000081166134ce575b62080000166134b1575b6000126134a3575b61348a6134808260201c90565b9163ffffffff1690565b61349a5760ff60005b1690611d34565b60ff6001613493565b6134ac90613350565b613473565b906134c66134c0600092611d08565b60801c90565b91905061346b565b916134df6134c06208000092611cd8565b929050613461565b916134c06134f491611ca6565b91613456565b916134c061350791611c72565b9161344b565b916134c061351a91611c3e565b91613440565b916134c061352d91611c0a565b91613436565b916134c061354091611bd6565b9161342c565b916134c061355391611ba2565b91613422565b916134c061356691611b6e565b91613418565b916134c061357991611b3a565b9161340e565b916134c061358c91611b06565b91613404565b916134c061359f91611ad2565b916133fa565b916134c06135b291611a9e565b916133f0565b916134c06135c591611a6a565b916133e7565b916134c06135d891611a36565b916133de565b916134c06135eb91611a02565b916133d5565b916134c06135fe916119ce565b916133cc565b916134c06136119161199a565b916133c3565b916134c061362491611966565b916133ba565b6001600160881b03600160801b6133af565b8061337d565b60020b801561245657620d89e80760020b620d89e803627fffff8113627fffff19821217611961579056fe6080604052346103fa57610d3c80380380610019816103ff565b9283398101906080818303126103fa5780516001600160401b0381116103fa5782610045918301610424565b602082015190926001600160401b0382116103fa57610065918301610424565b604082015160609092015190916001600160a01b038216918290036103fa5783516001600160401b03811161030357600354600181811c911680156103f0575b60208210146102e357601f811161038b575b50602094601f821160011461032457948192939495600092610319575b50508160011b916000199060031b1c1916176003555b82516001600160401b03811161030357600454600181811c911680156102f9575b60208210146102e357601f811161027e575b506020601f8211600114610217578192939460009261020c575b50508160011b916000199060031b1c1916176004555b81156101c757600254908082018092116101b15760207fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9160009360025584845283825260408420818154019055604051908152a36040516108ac90816104908239f35b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606490fd5b015190503880610137565b601f198216906004600052806000209160005b8181106102665750958360019596971061024d575b505050811b0160045561014d565b015160001960f88460031b161c1916905538808061023f565b9192602060018192868b01518155019401920161022a565b60046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b601f830160051c810191602084106102d9575b601f0160051c01905b8181106102cd575061011d565b600081556001016102c0565b90915081906102b7565b634e487b7160e01b600052602260045260246000fd5b90607f169061010b565b634e487b7160e01b600052604160045260246000fd5b0151905038806100d4565b601f198216956003600052806000209160005b8881106103735750836001959697981061035a575b505050811b016003556100ea565b015160001960f88460031b161c1916905538808061034c565b91926020600181928685015181550194019201610337565b60036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b601f830160051c810191602084106103e6575b601f0160051c01905b8181106103da57506100b7565b600081556001016103cd565b90915081906103c4565b90607f16906100a5565b600080fd5b6040519190601f01601f191682016001600160401b0381118382101761030357604052565b81601f820112156103fa578051906001600160401b03821161030357610453601f8301601f19166020016103ff565b92828452602083830101116103fa5760005b82811061047a57505060206000918301015290565b8060208092840101518282870101520161046556fe608080604052600436101561001357600080fd5b60003560e01c90816306fdde03146104a757508063095ea7b31461048157806318160ddd1461046357806323b872dd146103a5578063313ce56714610389578063395093511461032157806370a08231146102e757806395d89b41146101c6578063a457c2d71461011f578063a9059cbb146100ee5763dd62ed3e1461009857600080fd5b346100e95760403660031901126100e9576100b16105c3565b6100b96105d9565b6001600160a01b039182166000908152600160209081526040808320949093168252928352819020549051908152f35b600080fd5b346100e95760403660031901126100e95761011461010a6105c3565b60243590336106f7565b602060405160018152f35b346100e95760403660031901126100e9576101386105c3565b60243590336000526001602052604060002060018060a01b0382166000526020526040600020549180831061017357610114920390336105ef565b60405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f77604482015264207a65726f60d81b6064820152608490fd5b346100e95760003660031901126100e95760405160006004548060011c906001811680156102dd575b6020831081146102c9578285529081156102ad5750600114610256575b50819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b0390f35b634e487b7160e01b600052604160045260246000fd5b905060046000527f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b6000905b8282106102975750602091508201018261020c565b6001816020925483858801015201910190610282565b90506020925060ff191682840152151560051b8201018261020c565b634e487b7160e01b84526022600452602484fd5b91607f16916101ef565b346100e95760203660031901126100e9576001600160a01b036103086105c3565b1660005260006020526020604060002054604051908152f35b346100e95760403660031901126100e95761033a6105c3565b336000526001602052604060002060018060a01b03821660005260205260406000205460243581018091116103735761011491336105ef565b634e487b7160e01b600052601160045260246000fd5b346100e95760003660031901126100e957602060405160128152f35b346100e95760603660031901126100e9576103be6105c3565b6103c66105d9565b6001600160a01b0382166000908152600160208181526040808420338552909152909120549260443592918401610402575b61011493506106f7565b82841061041e5761041983610114950333836105ef565b6103f8565b60405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606490fd5b346100e95760003660031901126100e9576020600254604051908152f35b346100e95760403660031901126100e95761011461049d6105c3565b60243590336105ef565b346100e95760003660031901126100e95760006003548060011c90600181168015610570575b6020831081146102c9578285529081156102ad57506001146105195750819003601f01601f191681019067ffffffffffffffff8211818310176102405761023c8291826040528261057a565b905060036000527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b6000905b82821061055a5750602091508201018261020c565b6001816020925483858801015201910190610545565b91607f16916104cd565b91909160208152825180602083015260005b8181106105ad575060409293506000838284010152601f8019910116010190565b806020809287010151604082860101520161058c565b600435906001600160a01b03821682036100e957565b602435906001600160a01b03821682036100e957565b6001600160a01b03169081156106a6576001600160a01b03169182156106565760207f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925918360005260018252604060002085600052825280604060002055604051908152a3565b60405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608490fd5b60405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608490fd5b6001600160a01b0316908115610823576001600160a01b03169182156107d25781600052600060205260406000205481811061077e57817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9260209285600052600084520360406000205584600052600082526040600020818154019055604051908152a3565b60405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e7420657863656564732062604482015265616c616e636560d01b6064820152608490fd5b60405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608490fd5b60405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f206164604482015264647265737360d81b6064820152608490fdfea264697066735822122074ff4234c658f74e187510519776b8ea4e39b5c6743b1caeebf48be4c2f0270464736f6c634300081a003394ebca8d29d278a0288a52a710c11e928307b6f2e15fbaf4508cc4ceb3d21f8b2d85e5bc21a27644fa43503d10d34b03fef575277be4ae9f6da8f6f484ab0652a2646970667358221220fc89f062f0f16d35043a568f1cacb772d61a3999b149b553636a8c30706af53264736f6c634300081a0033

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

000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88000000000000000000000000e592427a0aece92de3edee1f18e0157c058615640000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b000000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52

-----Decoded View---------------
Arg [0] : taxCollector_ (address): 0xc5C216E6E60ccE2d189Bcce5f6ebFFDE1e8ce926
Arg [1] : weth_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [2] : uniswapV3Factory_ (address): 0x1F98431c8aD98523631AE4a59f267346ea31F984
Arg [3] : positionManager_ (address): 0xC36442b4a4522E871399CD717aBDD847Ab11FE88
Arg [4] : swapRouter_ (address): 0xE592427A0AEce92De3Edee1F18E0157C05861564
Arg [5] : nftLockerV5_ (address): 0x0fa69466d99880fb6dB58775343BD214f58c98b0
Arg [6] : goPlusLocker_ (address): 0x25c9C4B56E820e0DEA438b145284F02D9Ca9Bd52

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 000000000000000000000000c5c216e6e60cce2d189bcce5f6ebffde1e8ce926
Arg [1] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [2] : 0000000000000000000000001f98431c8ad98523631ae4a59f267346ea31f984
Arg [3] : 000000000000000000000000c36442b4a4522e871399cd717abdd847ab11fe88
Arg [4] : 000000000000000000000000e592427a0aece92de3edee1f18e0157c05861564
Arg [5] : 0000000000000000000000000fa69466d99880fb6db58775343bd214f58c98b0
Arg [6] : 00000000000000000000000025c9c4b56e820e0dea438b145284f02d9ca9bd52


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.