ETH Price: $2,008.78 (-2.73%)

Contract

0x9eF52D8953d184840F2c69096B7b3A7dA7093685
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Stake_66380860221332782025-03-26 19:49:1136 mins ago1743018551IN
0x9eF52D89...dA7093685
0 ETH0.000178680.67369074
Stake_66380860221332222025-03-26 19:37:5947 mins ago1743017879IN
0x9eF52D89...dA7093685
0 ETH0.000185830.62533521
Claim_41202704221318182025-03-26 14:56:115 hrs ago1743000971IN
0x9eF52D89...dA7093685
0 ETH0.000761772.81063849
Stake_66380860221311832025-03-26 12:49:117 hrs ago1742993351IN
0x9eF52D89...dA7093685
0 ETH0.000308481.03934788
Claim_41202704221309392025-03-26 12:00:118 hrs ago1742990411IN
0x9eF52D89...dA7093685
0 ETH0.000290981.07065224
Claim_41202704221268012025-03-25 22:10:1122 hrs ago1742940611IN
0x9eF52D89...dA7093685
0 ETH0.000269530.93305102
Request Claim_81...221262892025-03-25 20:26:4723 hrs ago1742934407IN
0x9eF52D89...dA7093685
0 ETH0.000575851.82372374
Flash Withdraw W...221262782025-03-25 20:24:3524 hrs ago1742934275IN
0x9eF52D89...dA7093685
0 ETH0.000321572.04021793
Request Claim_81...221261342025-03-25 19:55:3524 hrs ago1742932535IN
0x9eF52D89...dA7093685
0 ETH0.000313240.99162003
Flash Withdraw W...221244732025-03-25 14:20:1130 hrs ago1742912411IN
0x9eF52D89...dA7093685
0 ETH0.000072110.5
Flash Withdraw W...221244702025-03-25 14:19:3530 hrs ago1742912375IN
0x9eF52D89...dA7093685
0 ETH0.000072110.5
Stake_66380860221243042025-03-25 13:46:1130 hrs ago1742910371IN
0x9eF52D89...dA7093685
0 ETH0.000293090.97059446
Claim_41202704221215372025-03-25 4:29:1139 hrs ago1742876951IN
0x9eF52D89...dA7093685
0 ETH0.000360621.24834975
Claim_41202704221206682025-03-25 1:34:2342 hrs ago1742866463IN
0x9eF52D89...dA7093685
0 ETH0.000189620.69772812
Claim_41202704221182432025-03-24 17:25:232 days ago1742837123IN
0x9eF52D89...dA7093685
0 ETH0.000410961.4226059
Request Claim_81...221152132025-03-24 7:17:112 days ago1742800631IN
0x9eF52D89...dA7093685
0 ETH0.000268440.87387491
Request Claim_81...221135442025-03-24 1:41:592 days ago1742780519IN
0x9eF52D89...dA7093685
0 ETH0.000391821.24090916
Claim_41202704221095822025-03-23 12:26:113 days ago1742732771IN
0x9eF52D89...dA7093685
0 ETH0.000259020.89664552
Claim_41202704221078442025-03-23 6:37:113 days ago1742711831IN
0x9eF52D89...dA7093685
0 ETH0.000238250.87905479
Stake_66380860221041832025-03-22 18:22:354 days ago1742667755IN
0x9eF52D89...dA7093685
0 ETH0.000154340.49167953
Request Claim_81...221012972025-03-22 8:42:114 days ago1742632931IN
0x9eF52D89...dA7093685
0 ETH0.000295030.91496194
Stake_66380860221010462025-03-22 7:51:474 days ago1742629907IN
0x9eF52D89...dA7093685
0 ETH0.000281790.93317283
Claim_41202704221005032025-03-22 6:02:354 days ago1742623355IN
0x9eF52D89...dA7093685
0 ETH0.00027090.93777629
Stake_66380860221003202025-03-22 5:25:354 days ago1742621135IN
0x9eF52D89...dA7093685
0 ETH0.000278570.88639285
Claim_41202704220990262025-03-22 1:06:234 days ago1742605583IN
0x9eF52D89...dA7093685
0 ETH0.000576262
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Vault

Compiler Version
v0.8.28+commit.7893614a

Optimization Enabled:
Yes with 20 runs

Other Settings:
paris EvmVersion
File 1 of 18 : Vault.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol";
import {AccessControl} from "@openzeppelin/contracts/access/AccessControl.sol";
import "./IzkToken.sol";
import "./IWithdrawVault.sol";
import "./IVault.sol";
import "./utils.sol";

contract Vault is Pausable, AccessControl, IVault {
    using SafeERC20 for IERC20;
    using SafeERC20 for IzkToken;

    mapping(address => uint256) private tvl;

    // Supported tokens list
    mapping(address => bool) public supportedTokens;

    //zkTokens list
    mapping(address => IzkToken) public supportedTokenToZkToken;
    mapping(address => address) public zkTokenToSupportedToken;

    uint256 public lastClaimQueueID = 10_000;
    mapping(uint256 => ClaimItem) private claimQueue;

    // Main information
    mapping(address => mapping(address => AssetsInfo)) private userAssetsInfo;

    // Reward rate
    struct RewardRateState {
        address token;
        uint256 rewardRate;
        uint256 updatedTime;
    }
    mapping(address => RewardRateState[]) private rewardRateState;

    // Role
    bytes32 private constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
    bytes32 private constant BOT_ROLE = keccak256("BOT_ROLE");

    // Misc
    address private ceffu;
    uint256 private penaltyRate = 50; // 0.5%
    mapping(address => uint256) public minStakeAmount;
    mapping(address => uint256) public maxStakeAmount;
    uint256 public WAITING_TIME;
    uint256 private constant BASE = 10_000;

    mapping(address => uint256) public totalStakeAmountByToken;
    mapping(address => uint256) private _lastRewardUpdatedTime;
    mapping(address => uint256) public totalRewardsAmountByToken;

    uint256 private initialTime;
    IWithdrawVault private withdrawVault;
    address private airdropAddr;

    bool flashNotEnable;
    bool cancelNotEnable = true;

    constructor(
        address[] memory _tokens,
        address[] memory _zkTokens,
        uint256[] memory _newRewardRate,
        uint256[] memory _minStakeAmount,
        uint256[] memory _maxStakeAmount,
        address _admin,
        address _bot,
        address _ceffu,
        uint256 _waitingTime,
        address payable withdrawVaultAddress,
        address _airdropAddr
    ) {
        Utils.CheckIsZeroAddress(_ceffu);
        Utils.CheckIsZeroAddress(_admin);
        Utils.CheckIsZeroAddress(_bot);
        airdropAddr = _airdropAddr;

        uint256 len = _tokens.length;
        require(Utils.MustGreaterThanZero(len));
        require(
            len == _newRewardRate.length &&
            len == _minStakeAmount.length &&
            len == _maxStakeAmount.length && 
            len == _zkTokens.length
        );

        // Grant role
        _grantRole(DEFAULT_ADMIN_ROLE, _admin);
        _grantRole(PAUSER_ROLE, _admin);
        _grantRole(BOT_ROLE, _bot);

        ceffu = _ceffu;
        emit UpdateCeffu(address(0), _ceffu);

        WAITING_TIME = _waitingTime;
        emit UpdateWaitingTime(0, _waitingTime);

        initialTime = block.timestamp;

        // Set the supported tokens and reward rate
        for (uint256 i = 0; i < len; i++) {
            require(_minStakeAmount[i] < _maxStakeAmount[i]);

            // supported tokens
            address token = _tokens[i];
            minStakeAmount[token] = _minStakeAmount[i];
            maxStakeAmount[token] = _maxStakeAmount[i];
            supportedTokens[token] = true;
            emit AddSupportedToken(token, _minStakeAmount[i], _maxStakeAmount[i]);

            IzkToken tokenTemp = IzkToken(_zkTokens[i]);
            supportedTokenToZkToken[token] = tokenTemp;
            zkTokenToSupportedToken[address(tokenTemp)] = token;
            emit ZkTokenCreated(address(tokenTemp));

            // reward rate
            RewardRateState memory rewardRateItem = RewardRateState({
                token: token,
                rewardRate: _newRewardRate[i],
                updatedTime: block.timestamp
            });
            rewardRateState[token].push(rewardRateItem);
            emit UpdateRewardRate(token, 0, _newRewardRate[i]);

            _lastRewardUpdatedTime[token] = block.timestamp;
        
        }

        withdrawVault = IWithdrawVault(withdrawVaultAddress);

        _pause();
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                           Controller                                              ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////


    modifier OnlyFlashEnable{
        require(!flashNotEnable, "flash withdraw not enable");
    _;
    }
    modifier OnlyCancelEnable{
        require(!cancelNotEnable, "cancel claim not enable");
    _;
    }

    event FlashStatusChanged(bool indexed oldStatus, bool indexed newStatus);
    event CancelStatusChanged(bool indexed oldStatus, bool indexed newStatus);

    function setFlashEnable(bool _enable) external onlyRole(DEFAULT_ADMIN_ROLE){
        require(_enable != flashNotEnable, "nothing changed");
        bool oldStatus = flashNotEnable;
        flashNotEnable = _enable;
        emit FlashStatusChanged(oldStatus, _enable);
    }
    function setCancelEnable(bool _enable) external onlyRole(DEFAULT_ADMIN_ROLE){
        require(_enable != cancelNotEnable, "nothing changed");
        bool oldStatus = cancelNotEnable;
        cancelNotEnable = _enable;

        emit CancelStatusChanged(oldStatus, _enable);
    }

    modifier onlySupportedToken(address _token) {
        require(supportedTokens[_token], "Unsupported");
        _;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                             write                                                 ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    // function signature: 000000ed, the less function matching, the more gas saved
    function stake_66380860(address _token,  uint256 _stakedAmount) external onlySupportedToken(_token) whenNotPaused {
        AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
        uint256 currentStakedAmount = assetsInfo.stakedAmount;

        require(Utils.Add(currentStakedAmount, _stakedAmount) >= minStakeAmount[_token]);
        require(Utils.Add(currentStakedAmount, _stakedAmount) <= maxStakeAmount[_token]);

        IERC20(_token).safeTransferFrom(msg.sender, address(this), _stakedAmount);

        _updateRewardState(msg.sender, _token);
        uint256 exchangeRate = _getExchangeRate(_token);

        totalStakeAmountByToken[_token] += _stakedAmount;
        uint256 mintAmount = _stakedAmount * 1e18 / exchangeRate;
        supportedTokenToZkToken[_token].mint(msg.sender, mintAmount);

        // update status
        assetsInfo.stakeHistory.push(
            StakeItem({
                stakeTimestamp: block.timestamp,
                amount: _stakedAmount,
                token: _token,
                user: msg.sender
            })
        );
        unchecked {
            assetsInfo.stakedAmount += _stakedAmount;
            tvl[_token] += _stakedAmount;
        }

        emit Stake(msg.sender, _token, _stakedAmount);
    }

    // function signature: 0000004e, the less function matching, the more gas saved
    function requestClaim_8135334(
        address _token, 
        uint256 _amount
    ) external onlySupportedToken(_token) whenNotPaused returns(uint256 _returnID) {
        _updateRewardState(msg.sender, _token);
        uint256 exchangeRate = _getExchangeRate(_token);

        AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
        uint256 currentStakedAmount = assetsInfo.stakedAmount;
        uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;

        require(
            Utils.MustGreaterThanZero(_amount) && 
            (_amount <= Utils.Add(currentStakedAmount, currentAccumulatedRewardAmount) || _amount == type(uint256).max), 
            "Invalid amount"
        );

        ClaimItem storage queueItem = claimQueue[lastClaimQueueID];

        // Withdraw from reward first; if insufficient, continue withdrawing from principal
        uint256 totalAmount = _amount;
        (totalAmount, , ) = _handleWithdraw(_amount, assetsInfo, queueItem, false);

        require(totalAmount > 0, "No assets to withdraw");

        // update status
        assetsInfo.pendingClaimQueueIDs.push(lastClaimQueueID);

        totalStakeAmountByToken[_token] -= queueItem.principalAmount;
        totalRewardsAmountByToken[_token] -= queueItem.rewardAmount;

        uint256 sharesToBurn = totalAmount * 1e18 / exchangeRate;
        uint256 zkBalance = supportedTokenToZkToken[_token].balanceOf(msg.sender);
        
        if(sharesToBurn > zkBalance || assetsInfo.stakedAmount == 0) sharesToBurn = zkBalance;

        supportedTokenToZkToken[_token].burn(msg.sender, sharesToBurn);

        // update queue
        queueItem.token = _token;
        queueItem.user = msg.sender;
        queueItem.totalAmount = totalAmount;
        queueItem.requestTime = block.timestamp;
        queueItem.claimTime = Utils.Add(block.timestamp, WAITING_TIME);

        unchecked {
            _returnID = lastClaimQueueID;
            ++lastClaimQueueID;
        }

        emit RequestClaim(msg.sender, _token, totalAmount, _returnID);
    }

    function cancelClaim(uint256 _queueId, address _token) external whenNotPaused OnlyCancelEnable{
        ClaimItem memory claimItem = claimQueue[_queueId];
        delete claimQueue[_queueId];

        address token = claimItem.token;
        AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][token];
        uint256[] memory pendingClaimQueueIDs = userAssetsInfo[msg.sender][token].pendingClaimQueueIDs;
        
        require(Utils.MustGreaterThanZero(claimItem.totalAmount));
        require(claimItem.user == msg.sender);
        require(!claimItem.isDone, "claimed");
        require(token == _token, "wrong token");

        for(uint256 i = 0; i < pendingClaimQueueIDs.length; i++) {
            if(pendingClaimQueueIDs[i] == _queueId) {
                assetsInfo.pendingClaimQueueIDs[i] = pendingClaimQueueIDs[pendingClaimQueueIDs.length-1];
                assetsInfo.pendingClaimQueueIDs.pop();
                break;
            }
        }

        uint256 principal = claimItem.principalAmount;
        uint256 reward = claimItem.rewardAmount;

        assetsInfo.stakedAmount += principal;
        assetsInfo.accumulatedReward += reward;
        assetsInfo.lastRewardUpdateTime = block.timestamp;

        _updateRewardState(msg.sender, _token);
        uint256 exchangeRate = _getExchangeRate(_token);
        uint256 amountToMint = (principal + reward) * 1e18 / exchangeRate;

        totalStakeAmountByToken[_token] += principal;
        totalRewardsAmountByToken[_token] += reward;

        supportedTokenToZkToken[_token].mint(msg.sender, amountToMint);

        emit CancelClaim(msg.sender, _token, principal + reward, _queueId);
    }

    // function signature: 000000e5, the less function matching, the more gas saved
    function claim_41202704(uint256 _queueID, address _token) external whenNotPaused{
        ClaimItem memory claimItem = claimQueue[_queueID];
        address token = claimItem.token;
        AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][token];
        uint256[] memory pendingClaimQueueIDs = userAssetsInfo[msg.sender][token].pendingClaimQueueIDs;
        
        require(Utils.MustGreaterThanZero(claimItem.totalAmount));
        require(block.timestamp >= claimItem.claimTime);
        require(claimItem.user == msg.sender);
        require(!claimItem.isDone, "claimed");
        require(token == _token, "wrong token");

        // update status
        claimQueue[_queueID].isDone = true;
        for(uint256 i = 0; i < pendingClaimQueueIDs.length; i++) {
            if(pendingClaimQueueIDs[i] == _queueID) {
                assetsInfo.pendingClaimQueueIDs[i] = pendingClaimQueueIDs[pendingClaimQueueIDs.length-1];
                assetsInfo.pendingClaimQueueIDs.pop();
                break;
            }
        }
        tvl[token] -= claimItem.principalAmount;

        assetsInfo.claimHistory.push(
            ClaimItem({
                isDone: true,
                token: token,
                user: msg.sender,
                totalAmount: claimItem.totalAmount,
                principalAmount: claimItem.principalAmount,
                rewardAmount: claimItem.rewardAmount,
                requestTime: claimItem.requestTime,
                claimTime: block.timestamp
            })
        );
        withdrawVault.transfer(token, msg.sender, claimItem.totalAmount);

        emit ClaimAssets(msg.sender, token, claimItem.totalAmount, _queueID);
    }

    function flashWithdrawWithPenalty(
        address _token,
        uint256 _amount
    ) external onlySupportedToken(_token) whenNotPaused OnlyFlashEnable{
        AssetsInfo storage assetsInfo = userAssetsInfo[msg.sender][_token];
        _updateRewardState(msg.sender, _token);
        uint256 exchangeRate = _getExchangeRate(_token);

        uint256 currentStakedAmount = assetsInfo.stakedAmount;
        uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;

        require(
            Utils.MustGreaterThanZero(_amount) && 
            (_amount <= Utils.Add(currentStakedAmount, currentAccumulatedRewardAmount) || _amount == type(uint256).max)
        );

        uint256 totalAmount = _amount;
        uint256 principalAmount;
        uint256 rewardAmount;
        (totalAmount, principalAmount, rewardAmount) = _handleWithdraw(_amount, assetsInfo, claimQueue[lastClaimQueueID], true);

        require(totalAmount > 0, "no assets to withdraw");
    
        totalStakeAmountByToken[_token] -= principalAmount;
        totalRewardsAmountByToken[_token] -= rewardAmount;

        uint256 sharesToBurn = (totalAmount * 1e18) / exchangeRate;
        uint256 zkBalance = supportedTokenToZkToken[_token].balanceOf(msg.sender);

        if(sharesToBurn > zkBalance || assetsInfo.stakedAmount == 0) sharesToBurn = zkBalance;

        supportedTokenToZkToken[_token].burn(msg.sender, sharesToBurn);

        uint256 amountToSent = totalAmount * (BASE - penaltyRate) / BASE;
        uint256 fee = totalAmount - amountToSent;

        require(getContractBalance(_token) >= amountToSent, "not enough balance");

        IERC20(_token).safeTransfer(msg.sender, amountToSent);

        tvl[_token] -= principalAmount;

        assetsInfo.claimHistory.push(
            ClaimItem({
                isDone: true,
                token: _token,
                user: msg.sender,
                totalAmount: totalAmount,
                principalAmount: principalAmount,
                rewardAmount: rewardAmount,
                requestTime: block.timestamp,
                claimTime: block.timestamp
            })
        );

        emit FlashWithdraw(msg.sender, _token, totalAmount, fee);
    }

    function _handleWithdraw(
        uint256 _amount,
        AssetsInfo storage assetsInfo,
        ClaimItem storage queueItem,
        bool isFlash
    ) internal returns(uint256, uint256, uint256){
        uint256 totalAmount = _amount;
        uint256 principalAmount;
        uint256 rewardAmount;
        uint256 currentAccumulatedRewardAmount = assetsInfo.accumulatedReward;
        if(_amount == type(uint256).max){
            totalAmount = Utils.Add(currentAccumulatedRewardAmount, assetsInfo.stakedAmount);
            rewardAmount = currentAccumulatedRewardAmount;

            assetsInfo.accumulatedReward = 0;

            principalAmount = assetsInfo.stakedAmount;
            assetsInfo.stakedAmount = 0;
        }else if(currentAccumulatedRewardAmount >= _amount) {
            assetsInfo.accumulatedReward -= _amount;
            rewardAmount = _amount;
        } else {
            rewardAmount = currentAccumulatedRewardAmount;
            assetsInfo.accumulatedReward = 0;

            uint256 difference = _amount - currentAccumulatedRewardAmount;
            assetsInfo.stakedAmount -= difference;
            principalAmount = difference;
        }
        if(!isFlash) {
            queueItem.rewardAmount = rewardAmount;
            queueItem.principalAmount = principalAmount;

        }
        return(totalAmount, principalAmount, rewardAmount);
    }

    function _updateRewardState(address _user, address _token) internal {
        AssetsInfo storage assetsInfo = userAssetsInfo[_user][_token];
        uint256 newAccumulatedReward = 0;
        uint256 newAccumulatedRewardForAll;
        if(assetsInfo.lastRewardUpdateTime != 0) { // not the first time to stake
            newAccumulatedReward = _getClaimableRewards(_user, _token);
        }
        
        newAccumulatedRewardForAll = _getClaimableRewards(address(this), _token);

        assetsInfo.accumulatedReward = newAccumulatedReward;
        assetsInfo.lastRewardUpdateTime = block.timestamp;

        _lastRewardUpdatedTime[_token] = block.timestamp;
        totalRewardsAmountByToken[_token] = newAccumulatedRewardForAll;
    }

    function _getExchangeRate(address _token) internal view returns(uint256 exchangeRate){
        uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
        if (totalSupplyZKToken == 0) {
            exchangeRate = 1e18;
        } else {
            exchangeRate = ((totalStakeAmountByToken[_token] + totalRewardsAmountByToken[_token]) * 1e18) / totalSupplyZKToken;
        }
    }

    function convertToShares(uint256 tokenAmount, address _token) public view returns(uint256 shares) {
        uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
        uint256 totalStaked = totalStakeAmountByToken[_token];
        uint256 totalRewards = _getClaimableRewards(address(this), _token);

        uint256 exchangeRate = totalSupplyZKToken == 0 ? 
        1e18 : (totalStaked + totalRewards) * 1e18 / totalSupplyZKToken;
        shares = (tokenAmount * 1e18) / exchangeRate;
    }

    function convertToAssets(uint256 shares, address _token) public view returns(uint256 tokenAmount) {
        uint256 totalSupplyZKToken = supportedTokenToZkToken[_token].totalSupply();
        uint256 totalStaked = totalStakeAmountByToken[_token];
        uint256 totalRewards = _getClaimableRewards(address(this), _token);

        uint256 exchangeRate = totalSupplyZKToken == 0 ? 
        1e18 : (totalStaked + totalRewards) * 1e18 / totalSupplyZKToken;

        tokenAmount = (shares * exchangeRate) / 1e18;
    }

    function transferOrTransferFrom(address token, address from, address to, uint256 amount) public returns (bool) {
        require(from != to, "from can not be same as the to");
        require(amount > 0, "amount must be greater than 0");

        uint256 tokenBefore = getZKTokenAmount(from, token);
        require(tokenBefore >= amount, "balance");
        if(msg.sender != from){
            require(supportedTokenToZkToken[token].allowance(from, msg.sender) >= amount, "allowance");
            supportedTokenToZkToken[token].updateAllowance(from, msg.sender, amount);
            supportedTokenToZkToken[token].transferFrom(from, to, amount);
        }else{
            supportedTokenToZkToken[token].transferFrom(msg.sender, to, amount);
        }

        _assetsInfoUpdate(token, from, to, amount, tokenBefore);

        return true;
    }

    // airdrop
    function sendLpTokens(address token, address to, uint256 amount, bool flag) external {
        require(msg.sender == airdropAddr);
        supportedTokenToZkToken[token].transferFrom(airdropAddr, to, amount);
        
        AssetsInfo storage assetsInfo = userAssetsInfo[to][token];
        if(flag == true){
            assetsInfo.lastRewardUpdateTime = initialTime;
        }else{
            _updateRewardState(to, token);
        }

        assetsInfo.stakedAmount += amount;

        totalStakeAmountByToken[token] += amount;
        tvl[token] += amount;
    }

    function _assetsInfoUpdate(address token, address from, address to, uint256 amount, uint256 tokenBefore) internal{
        _updateRewardState(from, token);
        _updateRewardState(to, token);
        AssetsInfo storage assetsInfoFrom = userAssetsInfo[from][token];
        uint256 stakedAmount = assetsInfoFrom.stakedAmount;
        uint256 accumulatedReward = assetsInfoFrom.accumulatedReward;

        AssetsInfo storage assetsInfoTo = userAssetsInfo[to][token];

        uint256 percent = amount * 1e18 / tokenBefore;
        uint256 deltaStaked = (stakedAmount * percent / 1e18);
        uint256 deltaReward = (accumulatedReward * percent / 1e18);

        assetsInfoTo.stakedAmount += deltaStaked;
        assetsInfoFrom.stakedAmount -= deltaStaked;
        assetsInfoTo.accumulatedReward += deltaReward;
        assetsInfoFrom.accumulatedReward -= deltaReward;
        assetsInfoTo.lastRewardUpdateTime = block.timestamp ;
    }

    function transferToCeffu(
        address _token,
        uint256 _amount
    ) external onlySupportedToken(_token) onlyRole(BOT_ROLE) {
        require(Utils.MustGreaterThanZero(_amount), "must > 0");
        require(_amount <= IERC20(_token).balanceOf(address(this)), "Not enough balance");

        IERC20(_token).safeTransfer(ceffu, _amount);

        emit CeffuReceive(_token, ceffu, _amount);
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                          emergency                                                ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function emergencyWithdraw(address _token, address _receiver) external onlyRole(DEFAULT_ADMIN_ROLE) {
        // `_token` could be not supported, so that we could sweep the tokens which are sent to this contract accidentally
        Utils.CheckIsZeroAddress(_token);
        Utils.CheckIsZeroAddress(_receiver);

        IERC20(_token).safeTransfer(_receiver, IERC20(_token).balanceOf(address(this)));
        emit EmergencyWithdrawal(_token, _receiver);
    }

    function pause() external onlyRole(PAUSER_ROLE) {
        _pause();
    }

    function unpause() external onlyRole(PAUSER_ROLE) {
        _unpause();
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                        configuration                                              ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function addSupportedToken(
        address _token,
        uint256 _minAmount,
        uint256 _maxAmount,
        address _zkToken
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        Utils.CheckIsZeroAddress(_token);
        require(!supportedTokens[_token], "Supported");

        // update the supported tokens
        supportedTokens[_token] = true;
        setStakeLimit(_token, _minAmount, _maxAmount);
        emit AddSupportedToken(_token, _minAmount, _maxAmount);

        IzkToken tokenTemp = IzkToken(_zkToken);
        supportedTokenToZkToken[_token] = tokenTemp;
        zkTokenToSupportedToken[address(tokenTemp)] = _token;
        emit ZkTokenCreated(address(tokenTemp));
    }

    function setRewardRate(
        address _token, 
        uint256 _newRewardRate
    ) external onlySupportedToken(_token) onlyRole(DEFAULT_ADMIN_ROLE) {
        require(_newRewardRate < BASE, "Invalid rate");

        RewardRateState[] memory rewardRateArray = rewardRateState[_token];
        uint256 currentRewardRate = rewardRateArray[rewardRateArray.length - 1].rewardRate;
        require(currentRewardRate != _newRewardRate && Utils.MustGreaterThanZero(_newRewardRate), "Invalid new rate");

        // add the new reward rate to the array
        RewardRateState memory rewardRateItem = RewardRateState({
            updatedTime: block.timestamp,
            token: _token,
            rewardRate: _newRewardRate
        });
        rewardRateState[_token].push(rewardRateItem);

        emit UpdateRewardRate(_token, currentRewardRate, _newRewardRate);
    }

    function setAirdropAddr(address newAirdropAddr) external onlyRole(DEFAULT_ADMIN_ROLE) {
        //allow equal address(0), when we want to disable airdrop
        airdropAddr = newAirdropAddr;
    }

    function setPenaltyRate(uint256 newRate) external onlyRole(DEFAULT_ADMIN_ROLE) {
        require(newRate <= BASE && newRate != penaltyRate, "Invalid");

        emit UpdatePenaltyRate(penaltyRate, newRate);
        penaltyRate = newRate;
    }


    function setCeffu(address _newCeffu) external onlyRole(DEFAULT_ADMIN_ROLE) {
        Utils.CheckIsZeroAddress(_newCeffu);
        require(_newCeffu != ceffu);

        emit UpdateCeffu(ceffu, _newCeffu);
        ceffu = _newCeffu;
    }

    function setStakeLimit(
        address _token,
        uint256 _minAmount,
        uint256 _maxAmount
    ) public onlyRole(DEFAULT_ADMIN_ROLE) onlySupportedToken(_token) {
        require(Utils.MustGreaterThanZero(_minAmount) && _minAmount < _maxAmount);

        emit UpdateStakeLimit(_token, minStakeAmount[_token], maxStakeAmount[_token], _minAmount, _maxAmount);
        minStakeAmount[_token] = _minAmount;
        maxStakeAmount[_token] = _maxAmount;
    }

    function setWaitingTime(uint256 _newWaitingTime) external onlyRole(DEFAULT_ADMIN_ROLE){
        require(_newWaitingTime != WAITING_TIME, "Invalid");

        emit UpdateWaitingTime(WAITING_TIME, _newWaitingTime);
        WAITING_TIME = _newWaitingTime;        
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                          view / pure                                              ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function calculateReward(
        uint256 _stakedAmount, 
        uint256 _rewardRate, 
        uint256 _elapsedTime
    ) internal pure returns (uint256 result) {
        // (stakedAmount * rewardRate * elapsedTime) / (ONE_YEAR * 10000)
        // Parameter descriptions:
        // - stakedAmount: The amount staked by the user
        // - rewardRate: The annual reward rate (e.g., 700 means 7%)
        // - elapsedTime: The time interval over which the reward is calculated, in seconds
        // - ONE_YEAR: The total number of seconds in one year (365.25 days)
        assembly {
            // uint256 ONE_YEAR = uint256(365.25 * 24 * 60 * 60); // 365.25 days per year: 31557600
            let ONE_YEAR := 31557600

            // Calculate numerator = stakedAmount * rewardRate * elapsedTime
            let numerator := mul(_stakedAmount, _rewardRate)
            numerator := mul(numerator, _elapsedTime)

            // Calculate denominator = ONE_YEAR * 10000
            let denominator := mul(ONE_YEAR, BASE)

            // Perform the division result = numerator / denominator
            result := div(numerator, denominator)
        }
    }

    function _getClaimableRewards(address _user, address _token) internal view returns (uint256) {
        uint256 currentStakedAmount;
        uint256 lastRewardUpdate;
        uint256 currentRewardAmount;

        if(_user != address(this)){
            AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
            currentStakedAmount = assetsInfo.stakedAmount;
            lastRewardUpdate = assetsInfo.lastRewardUpdateTime;
            currentRewardAmount = assetsInfo.accumulatedReward;
        } else {
            currentStakedAmount = totalStakeAmountByToken[_token];
            lastRewardUpdate = _lastRewardUpdatedTime[_token];
            currentRewardAmount = totalRewardsAmountByToken[_token];
        }

        RewardRateState[] memory rewardRateArray = rewardRateState[_token];
        uint256 rewardRateLength = rewardRateArray.length;
        RewardRateState memory currentRewardRateState = rewardRateArray[rewardRateLength - 1];

        if(lastRewardUpdate == 0) return 0;

        // 1. Retrieve the last deposit time `begin`
        // 2. Retrieve the current deposit time `end`
        // 3. Check whether the reward rate changed between time `begin` and time `end`
        // 4. Determine if the reward rate has changed since the last deposit:
        //    - If no changes occurred, directly calculate and add the reward.
        //    - If changes occurred, divide the deposit time into segments based on different rates 
        //      and accumulate the rewards accordingly.
        if(currentRewardRateState.updatedTime <= lastRewardUpdate){
            /*
                   begin                   end
                    |~~~~~~ position ~~~~~~~|
                |--------- reward rate 1 --------------|--------- upcoming reward rate 2 --------------|
            */

            uint256 elapsedTime = block.timestamp - lastRewardUpdate;
            uint256 reward = calculateReward(
                currentStakedAmount,
                currentRewardRateState.rewardRate,
                elapsedTime
            );

            return currentRewardAmount + reward;
        } else {
            /*
                   begin                                                       end
                    |~~~~~~~~~~~~~~~~~~~~~~ position ~~~~~~~~~~~~~~~~~~~~~~~~~~~|
                |--------- reward rate 1 --------------|-- reward rate 2 --|-------- reward rate 3 --------|
            */

            // a. based on the reward rate at the time of the last stake, find the corresponding index in the rate array
            uint256 beginIndex = 0;
            for (uint256 i = 0; i < rewardRateLength; i++) {
                if (lastRewardUpdate < rewardRateArray[i].updatedTime) {
                    beginIndex = i;
                    break;
                }
            }

            // b. iterate to the latest-1 reward rate
            uint256 tempLastRewardUpdateTime = lastRewardUpdate;
            for (uint256 i = beginIndex; i < rewardRateLength; i++) {
                if(i == 0) continue;

                uint256 tempElapsedTime = rewardRateArray[i].updatedTime - tempLastRewardUpdateTime;
                uint256 tempReward = calculateReward(
                    currentStakedAmount,
                    rewardRateArray[i - 1].rewardRate,
                    tempElapsedTime
                );
                tempLastRewardUpdateTime = rewardRateArray[i].updatedTime;
                unchecked{
                    currentRewardAmount += tempReward;
                }
            }

            // c. the reward generated by the latest reward rate
            uint256 elapsedTime = block.timestamp - currentRewardRateState.updatedTime;
            uint256 reward = calculateReward(
                currentStakedAmount,
                currentRewardRateState.rewardRate,
                elapsedTime
            );

            return currentRewardAmount + reward;
        }
    }

    // principal + rewards
    function getClaimableAssets(address _user, address _token) external view returns (uint256) {
        AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
        
        return Utils.Add(assetsInfo.stakedAmount, _getClaimableRewards(_user, _token));
    }

    // current rewards
    function getClaimableRewards(address _user, address _token) external view returns (uint256) {
        return _getClaimableRewards(_user, _token);
    }

    // history rewards + current rewards
    function getTotalRewards(address _user, address _token) external view returns (uint256) {
        uint256 historyRewards = 0;
        uint256 currentRewards = _getClaimableRewards(_user, _token);

        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
        for(uint256 i = 0; i < stakeInfo.claimHistory.length; i++) {
            historyRewards += stakeInfo.claimHistory[i].rewardAmount;
        }

        return Utils.Add(historyRewards, currentRewards);
    }

    // Calculate the total withdrawable amount for a user at a future time, 
    // based on the user's current staked amount and the current reward rate.
    function getClaimableRewardsWithTargetTime(
        address _user,
        address _token,
        uint256 _targetTime
    ) external view returns (uint256) {
        require(_targetTime > block.timestamp, "Invalid time");

        AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
        RewardRateState[] memory rewardRateArray = rewardRateState[_token];
        RewardRateState memory currentRewardRateState = rewardRateArray[rewardRateArray.length - 1];

        uint256 newAccumulatedReward = 0;
        if(assetsInfo.lastRewardUpdateTime != 0) { // not the first time to stake
            newAccumulatedReward = _getClaimableRewards(_user, _token);
        }

        uint256 elapsedTime = _targetTime - block.timestamp;
        uint256 reward = calculateReward(
            assetsInfo.stakedAmount,
            currentRewardRateState.rewardRate,
            elapsedTime
        );

        return Utils.Add(newAccumulatedReward, reward);
    }

    function getStakedAmount(address _user, address _token) public view onlySupportedToken(_token) returns (uint256) {
        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
        return stakeInfo.stakedAmount;
    }

    function getZKTokenAmount(address _user, address _token) public view onlySupportedToken(_token) returns (uint256) {
        return supportedTokenToZkToken[_token].balanceOf(_user);
    }

    function getContractBalance(address _token) public view returns (uint256) {
        Utils.CheckIsZeroAddress(_token);
        return IERC20(_token).balanceOf(address(this));
    }

    function getStakeHistory(
        address _user,
        address _token,
        uint256 _index
    ) external view onlySupportedToken(_token) returns (StakeItem memory) {
        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
        require(_index < stakeInfo.stakeHistory.length, "index");

        return stakeInfo.stakeHistory[_index];
    }

    function getClaimHistory(
        address _user,
        address _token,
        uint256 _index
    ) external view onlySupportedToken(_token) returns (ClaimItem memory) {
        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
        require(_index < stakeInfo.claimHistory.length, "index");

        return stakeInfo.claimHistory[_index];
    }

    function getStakeHistoryLength(address _user, address _token) external view returns(uint256) {
        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];

        return stakeInfo.stakeHistory.length;
    }
    function getClaimHistoryLength(address _user, address _token) public view returns(uint256) {
        AssetsInfo memory stakeInfo = userAssetsInfo[_user][_token];
        
        return stakeInfo.claimHistory.length;
    }

    // Check the current withdrawal request in progress for a specific user
    function getClaimQueueIDs(address _user, address _token) external view returns (uint256[] memory) {
        AssetsInfo memory assetsInfo = userAssetsInfo[_user][_token];
        return assetsInfo.pendingClaimQueueIDs;
    }

    // Measure the reward rate as a percentage, and return the numerator and denominator
    function getCurrentRewardRate(address _token) external view returns (uint256, uint256) {
        RewardRateState[] memory rewardRateStateArray = rewardRateState[_token];
        RewardRateState memory currentRewardRateState = rewardRateStateArray[rewardRateStateArray.length - 1];

        return (currentRewardRateState.rewardRate, BASE);
    }

    function getClaimQueueInfo(uint256 _index) external view returns(ClaimItem memory) {
        return claimQueue[_index];
    }

    function getTVL(address _token) external view returns(uint256){
        return tvl[_token];
    }

    receive() external payable {
        revert();
    }
}

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

pragma solidity ^0.8.20;

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

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

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

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

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

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

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

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

File 3 of 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";
import {IERC1363} from "../../../interfaces/IERC1363.sol";
import {Address} from "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC-20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    /**
     * @dev An operation with an ERC-20 token failed.
     */
    error SafeERC20FailedOperation(address token);

    /**
     * @dev Indicates a failed `decreaseAllowance` request.
     */
    error SafeERC20FailedDecreaseAllowance(address spender, uint256 currentAllowance, uint256 requestedDecrease);

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transfer, (to, value)));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeCall(token.transferFrom, (from, to, value)));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        forceApprove(token, spender, oldAllowance + value);
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `requestedDecrease`. If `token` returns no
     * value, non-reverting calls are assumed to be successful.
     *
     * IMPORTANT: If the token implements ERC-7674 (ERC-20 with temporary allowance), and if the "client"
     * smart contract uses ERC-7674 to set temporary allowances, then the "client" smart contract should avoid using
     * this function. Performing a {safeIncreaseAllowance} or {safeDecreaseAllowance} operation on a token contract
     * that has a non-zero temporary allowance (for that particular owner-spender) will result in unexpected behavior.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 requestedDecrease) internal {
        unchecked {
            uint256 currentAllowance = token.allowance(address(this), spender);
            if (currentAllowance < requestedDecrease) {
                revert SafeERC20FailedDecreaseAllowance(spender, currentAllowance, requestedDecrease);
            }
            forceApprove(token, spender, currentAllowance - requestedDecrease);
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     *
     * NOTE: If the token implements ERC-7674, this function will not modify any temporary allowance. This function
     * only sets the "standard" allowance. Any temporary allowance will remain active, in addition to the value being
     * set here.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeCall(token.approve, (spender, value));

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeCall(token.approve, (spender, 0)));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Performs an {ERC1363} transferAndCall, with a fallback to the simple {ERC20} transfer if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            safeTransfer(token, to, value);
        } else if (!token.transferAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} transferFromAndCall, with a fallback to the simple {ERC20} transferFrom if the target
     * has no code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * Reverts if the returned value is other than `true`.
     */
    function transferFromAndCallRelaxed(
        IERC1363 token,
        address from,
        address to,
        uint256 value,
        bytes memory data
    ) internal {
        if (to.code.length == 0) {
            safeTransferFrom(token, from, to, value);
        } else if (!token.transferFromAndCall(from, to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Performs an {ERC1363} approveAndCall, with a fallback to the simple {ERC20} approve if the target has no
     * code. This can be used to implement an {ERC721}-like safe transfer that rely on {ERC1363} checks when
     * targeting contracts.
     *
     * NOTE: When the recipient address (`to`) has no code (i.e. is an EOA), this function behaves as {forceApprove}.
     * Opposedly, when the recipient address (`to`) has code, this function only attempts to call {ERC1363-approveAndCall}
     * once without retrying, and relies on the returned value to be true.
     *
     * Reverts if the returned value is other than `true`.
     */
    function approveAndCallRelaxed(IERC1363 token, address to, uint256 value, bytes memory data) internal {
        if (to.code.length == 0) {
            forceApprove(token, to, value);
        } else if (!token.approveAndCall(to, value, data)) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturnBool} that reverts if call fails to meet the requirements.
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            let success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            // bubble errors
            if iszero(success) {
                let ptr := mload(0x40)
                returndatacopy(ptr, 0, returndatasize())
                revert(ptr, returndatasize())
            }
            returnSize := returndatasize()
            returnValue := mload(0)
        }

        if (returnSize == 0 ? address(token).code.length == 0 : returnValue != 1) {
            revert SafeERC20FailedOperation(address(token));
        }
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silently catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        bool success;
        uint256 returnSize;
        uint256 returnValue;
        assembly ("memory-safe") {
            success := call(gas(), token, 0, add(data, 0x20), mload(data), 0, 0x20)
            returnSize := returndatasize()
            returnValue := mload(0)
        }
        return success && (returnSize == 0 ? address(token).code.length > 0 : returnValue == 1);
    }
}

File 4 of 18 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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 {
    bool private _paused;

    /**
     * @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);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @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 {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @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());
    }
}

File 5 of 18 : AccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/AccessControl.sol)

pragma solidity ^0.8.20;

import {IAccessControl} from "./IAccessControl.sol";
import {Context} from "../utils/Context.sol";
import {ERC165} from "../utils/introspection/ERC165.sol";

/**
 * @dev Contract module that allows children to implement role-based access
 * control mechanisms. This is a lightweight version that doesn't allow enumerating role
 * members except through off-chain means by accessing the contract event logs. Some
 * applications may benefit from on-chain enumerability, for those cases see
 * {AccessControlEnumerable}.
 *
 * Roles are referred to by their `bytes32` identifier. These should be exposed
 * in the external API and be unique. The best way to achieve this is by
 * using `public constant` hash digests:
 *
 * ```solidity
 * bytes32 public constant MY_ROLE = keccak256("MY_ROLE");
 * ```
 *
 * Roles can be used to represent a set of permissions. To restrict access to a
 * function call, use {hasRole}:
 *
 * ```solidity
 * function foo() public {
 *     require(hasRole(MY_ROLE, msg.sender));
 *     ...
 * }
 * ```
 *
 * Roles can be granted and revoked dynamically via the {grantRole} and
 * {revokeRole} functions. Each role has an associated admin role, and only
 * accounts that have a role's admin role can call {grantRole} and {revokeRole}.
 *
 * By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means
 * that only accounts with this role will be able to grant or revoke other
 * roles. More complex role relationships can be created by using
 * {_setRoleAdmin}.
 *
 * WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to
 * grant and revoke this role. Extra precautions should be taken to secure
 * accounts that have been granted it. We recommend using {AccessControlDefaultAdminRules}
 * to enforce additional security measures for this role.
 */
abstract contract AccessControl is Context, IAccessControl, ERC165 {
    struct RoleData {
        mapping(address account => bool) hasRole;
        bytes32 adminRole;
    }

    mapping(bytes32 role => RoleData) private _roles;

    bytes32 public constant DEFAULT_ADMIN_ROLE = 0x00;

    /**
     * @dev Modifier that checks that an account has a specific role. Reverts
     * with an {AccessControlUnauthorizedAccount} error including the required role.
     */
    modifier onlyRole(bytes32 role) {
        _checkRole(role);
        _;
    }

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IAccessControl).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) public view virtual returns (bool) {
        return _roles[role].hasRole[account];
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `_msgSender()`
     * is missing `role`. Overriding this function changes the behavior of the {onlyRole} modifier.
     */
    function _checkRole(bytes32 role) internal view virtual {
        _checkRole(role, _msgSender());
    }

    /**
     * @dev Reverts with an {AccessControlUnauthorizedAccount} error if `account`
     * is missing `role`.
     */
    function _checkRole(bytes32 role, address account) internal view virtual {
        if (!hasRole(role, account)) {
            revert AccessControlUnauthorizedAccount(account, role);
        }
    }

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) public view virtual returns (bytes32) {
        return _roles[role].adminRole;
    }

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleGranted} event.
     */
    function grantRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _grantRole(role, account);
    }

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     *
     * May emit a {RoleRevoked} event.
     */
    function revokeRole(bytes32 role, address account) public virtual onlyRole(getRoleAdmin(role)) {
        _revokeRole(role, account);
    }

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been revoked `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     *
     * May emit a {RoleRevoked} event.
     */
    function renounceRole(bytes32 role, address callerConfirmation) public virtual {
        if (callerConfirmation != _msgSender()) {
            revert AccessControlBadConfirmation();
        }

        _revokeRole(role, callerConfirmation);
    }

    /**
     * @dev Sets `adminRole` as ``role``'s admin role.
     *
     * Emits a {RoleAdminChanged} event.
     */
    function _setRoleAdmin(bytes32 role, bytes32 adminRole) internal virtual {
        bytes32 previousAdminRole = getRoleAdmin(role);
        _roles[role].adminRole = adminRole;
        emit RoleAdminChanged(role, previousAdminRole, adminRole);
    }

    /**
     * @dev Attempts to grant `role` to `account` and returns a boolean indicating if `role` was granted.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleGranted} event.
     */
    function _grantRole(bytes32 role, address account) internal virtual returns (bool) {
        if (!hasRole(role, account)) {
            _roles[role].hasRole[account] = true;
            emit RoleGranted(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Attempts to revoke `role` to `account` and returns a boolean indicating if `role` was revoked.
     *
     * Internal function without access restriction.
     *
     * May emit a {RoleRevoked} event.
     */
    function _revokeRole(bytes32 role, address account) internal virtual returns (bool) {
        if (hasRole(role, account)) {
            _roles[role].hasRole[account] = false;
            emit RoleRevoked(role, account, _msgSender());
            return true;
        } else {
            return false;
        }
    }
}

File 6 of 18 : IzkToken.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

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

interface IzkToken is IERC20 {
    function mint(address to, uint256 amount) external;
    function burn(address from, uint256 amount) external;
    function setMinter(address minter, address vault) external;
    function updateAllowance(address from, address to, uint256 amount) external;
}

File 7 of 18 : IWithdrawVault.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

interface IWithdrawVault {
    function transfer(address, address, uint256) external;
    function addSupportedToken(address) external;
    function setVault(address) external;
    function getSupportedTokens() external view returns (address[] memory);
    function getBalance(address) external view returns (uint256);
    function emergencyWithdraw(address, address, uint) external;
    function transferToCeffu(address token, uint amount)external;
}

File 8 of 18 : IVault.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

// Main information: stake and claim
struct AssetsInfo {
    uint256 stakedAmount;
    uint256 accumulatedReward;
    uint256 lastRewardUpdateTime;
    uint256[] pendingClaimQueueIDs;
    StakeItem[] stakeHistory;
    ClaimItem[] claimHistory;
}
struct StakeItem {
    address token;
    address user;
    uint256 amount;
    uint256 stakeTimestamp;
}
struct ClaimItem {
    bool isDone;
    address token;
    address user;
    uint256 totalAmount;
    uint256 principalAmount;
    uint256 rewardAmount;
    uint256 requestTime;
    uint256 claimTime;
}

interface IVault {
    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                             events                                                ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    event Stake(address indexed _user, address indexed _token, uint256 indexed _amount);
    event RequestClaim(address _user, address indexed _token, uint256 indexed _amount, uint256 indexed _id);
    event ClaimAssets(address indexed _user, address indexed _token, uint256 indexed _amount, uint256 _id);
    event UpdateRewardRate(address _token, uint256 _oldRewardRate, uint256 _newRewardRate);
    event UpdateCeffu(address _oldCeffu, address _newCeffu);
    event UpdateStakeLimit(address indexed _token, uint256 _oldMinAmount, uint256 _oldMaxAmount, uint256 _newMinAmount, uint256 _newMaxAmount);
    event CeffuReceive(address indexed _token, address _ceffu, uint256 indexed _amount);
    event AddSupportedToken(address indexed _token, uint256 _minAmount, uint256 _maxAmount);
    event EmergencyWithdrawal(address indexed _token, address indexed _receiver);
    event UpdateWaitingTime(uint256 _oldWaitingTime, uint256 _newWaitingTIme);
    event ZkTokenCreated(address indexed _token);
    event FlashWithdraw(address indexed _user, address indexed _token, uint256 indexed _amount, uint _fee);
    event UpdatePenaltyRate(uint indexed oldRate, uint indexed newRate);
    event CancelClaim(address indexed user, address indexed _token, uint256 indexed _amount, uint256 _id);

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                             write                                                 ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function stake_66380860(address _token, uint256 _stakedAmount) external;
    function requestClaim_8135334(address _token, uint256 _amount) external returns(uint256);
    function cancelClaim(uint _queueId, address _token) external;
    function claim_41202704(uint256 _queueID, address token) external;
    function flashWithdrawWithPenalty(address _token, uint256 _amount) external;

    function sendLpTokens(address token, address to, uint amount, bool flag) external;
    function transferToCeffu(address _token, uint256 _amount) external;
    function emergencyWithdraw(address _token, address _receiver) external;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                        configuration                                              ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function addSupportedToken(address _token, uint256 _minAmount, uint256 _maxAmount, address _zkToken) external;
    function setRewardRate(address _token, uint256 _newRewardRate) external;
    function setPenaltyRate(uint256 _newRate) external;
    function setAirdropAddr(address newAirdropAddr) external;
    function setStakeLimit(address _token, uint256 _minAmount, uint256 _maxAmount) external;
    function setCeffu(address _newCeffu) external;
    function setWaitingTime(uint256 _newWaitingTIme) external;
    function pause() external;
    function unpause() external;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////
    ///                                          view / pure                                              ///
    /////////////////////////////////////////////////////////////////////////////////////////////////////////

    function convertToShares(uint tokenAmount, address _token) external view returns (uint256);
    function convertToAssets(uint shares, address _token) external view returns (uint256);
    function getClaimableRewardsWithTargetTime(address _user, address _token, uint256 _targetTime) external view returns (uint256);
    function getClaimableAssets(address _user, address _token) external view returns (uint256);
    function getClaimableRewards(address _user, address _token) external view returns (uint256);
    function getTotalRewards(address _user, address _token) external view returns (uint256);
    function getStakedAmount(address _user, address _token) external view returns (uint256);
    function getContractBalance(address _token) external view returns (uint256);
    function getStakeHistory(address _user, address _token, uint256 _index) external view returns (StakeItem memory);
    function getClaimHistory(address _user, address _token, uint256 _index) external view returns (ClaimItem memory);
    function getStakeHistoryLength(address _user, address _token) external view returns(uint256);
    function getClaimHistoryLength(address _user, address _token) external view returns(uint256);
    function getCurrentRewardRate(address _token) external view returns(uint256, uint256);
    function getClaimQueueInfo(uint256 _index) external view returns(ClaimItem memory);
    function getClaimQueueIDs(address _user, address _token) external view returns(uint256[] memory);
    function getTVL(address _token) external view returns(uint256);
    function getZKTokenAmount(address _user, address _token) external view returns(uint256);
    function lastClaimQueueID() external view returns(uint256);
}

File 9 of 18 : utils.sol
// SPDX-License-Identifier: MIT
pragma solidity =0.8.28;

library Utils {
    // Use this when we are certain that an overflow will not occur
    function Add(uint _a, uint _b) public pure returns (uint256) {
        assembly {
            mstore(0x0, add(_a, _b))
            return(0x0, 32)
        }
    }

    function CheckIsZeroAddress(address _address) public pure returns (bool) {
        assembly {
            if iszero(_address) {
                mstore(0x00, 0x20)
                mstore(0x20, 0x0c)
                mstore(0x40, 0x5a65726f20416464726573730000000000000000000000000000000000000000) // load hex of "Zero Address" to memory
                revert(0x00, 0x60)
            }
        }
        return true;
    }

    function MustGreaterThanZero(uint256 _value) internal pure returns (bool result) {
        assembly {
            // The 'iszero' opcode returns 1 if the input is zero, and 0 otherwise.
            // So, 'iszero(iszero(_value))' returns 1 if value > 0, and 0 if value == 0.
            result := iszero(iszero(_value))
        }
    }

}

File 10 of 18 : IERC1363.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (interfaces/IERC1363.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC165} from "./IERC165.sol";

/**
 * @title IERC1363
 * @dev Interface of the ERC-1363 standard as defined in the https://eips.ethereum.org/EIPS/eip-1363[ERC-1363].
 *
 * Defines an extension interface for ERC-20 tokens that supports executing code on a recipient contract
 * after `transfer` or `transferFrom`, or code on a spender contract after `approve`, in a single transaction.
 */
interface IERC1363 is IERC20, IERC165 {
    /*
     * Note: the ERC-165 identifier for this interface is 0xb0202a11.
     * 0xb0202a11 ===
     *   bytes4(keccak256('transferAndCall(address,uint256)')) ^
     *   bytes4(keccak256('transferAndCall(address,uint256,bytes)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256)')) ^
     *   bytes4(keccak256('transferFromAndCall(address,address,uint256,bytes)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256)')) ^
     *   bytes4(keccak256('approveAndCall(address,uint256,bytes)'))
     */

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from the caller's account to `to`
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferAndCall(address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the allowance mechanism
     * and then calls {IERC1363Receiver-onTransferReceived} on `to`.
     * @param from The address which you want to send tokens from.
     * @param to The address which you want to transfer to.
     * @param value The amount of tokens to be transferred.
     * @param data Additional data with no specified format, sent in call to `to`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function transferFromAndCall(address from, address to, uint256 value, bytes calldata data) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value) external returns (bool);

    /**
     * @dev Sets a `value` amount of tokens as the allowance of `spender` over the
     * caller's tokens and then calls {IERC1363Spender-onApprovalReceived} on `spender`.
     * @param spender The address which will spend the funds.
     * @param value The amount of tokens to be spent.
     * @param data Additional data with no specified format, sent in call to `spender`.
     * @return A boolean value indicating whether the operation succeeded unless throwing.
     */
    function approveAndCall(address spender, uint256 value, bytes calldata data) external returns (bool);
}

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

pragma solidity ^0.8.20;

import {Errors} from "./Errors.sol";

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev There's no code at `target` (it is not a contract).
     */
    error AddressEmptyCode(address target);

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.8.20/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        if (address(this).balance < amount) {
            revert Errors.InsufficientBalance(address(this).balance, amount);
        }

        (bool success, ) = recipient.call{value: amount}("");
        if (!success) {
            revert Errors.FailedCall();
        }
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason or custom error, it is bubbled
     * up by this function (like regular Solidity function calls). However, if
     * the call reverted with no returned reason, this function reverts with a
     * {Errors.FailedCall} error.
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     */
    function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
        if (address(this).balance < value) {
            revert Errors.InsufficientBalance(address(this).balance, value);
        }
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and reverts if the target
     * was not a contract or bubbling up the revert reason (falling back to {Errors.FailedCall}) in case
     * of an unsuccessful call.
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata
    ) internal view returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            // only check if target is a contract if the call was successful and the return data is empty
            // otherwise we already know that it was a contract
            if (returndata.length == 0 && target.code.length == 0) {
                revert AddressEmptyCode(target);
            }
            return returndata;
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and reverts if it wasn't, either by bubbling the
     * revert reason or with a default {Errors.FailedCall} error.
     */
    function verifyCallResult(bool success, bytes memory returndata) internal pure returns (bytes memory) {
        if (!success) {
            _revert(returndata);
        } else {
            return returndata;
        }
    }

    /**
     * @dev Reverts with returndata if present. Otherwise reverts with {Errors.FailedCall}.
     */
    function _revert(bytes memory returndata) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            assembly ("memory-safe") {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert Errors.FailedCall();
        }
    }
}

File 12 of 18 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }
}

File 13 of 18 : IAccessControl.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (access/IAccessControl.sol)

pragma solidity ^0.8.20;

/**
 * @dev External interface of AccessControl declared to support ERC-165 detection.
 */
interface IAccessControl {
    /**
     * @dev The `account` is missing a role.
     */
    error AccessControlUnauthorizedAccount(address account, bytes32 neededRole);

    /**
     * @dev The caller of a function is not the expected one.
     *
     * NOTE: Don't confuse with {AccessControlUnauthorizedAccount}.
     */
    error AccessControlBadConfirmation();

    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call. This account bears the admin role (for the granted role).
     * Expected in cases where the role was granted using the internal {AccessControl-_grantRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `callerConfirmation`.
     */
    function renounceRole(bytes32 role, address callerConfirmation) external;
}

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

pragma solidity ^0.8.20;

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

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC-165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

File 15 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../token/ERC20/IERC20.sol";

File 16 of 18 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/IERC165.sol)

pragma solidity ^0.8.20;

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

File 17 of 18 : Errors.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.1.0) (utils/Errors.sol)

pragma solidity ^0.8.20;

/**
 * @dev Collection of common custom errors used in multiple contracts
 *
 * IMPORTANT: Backwards compatibility is not guaranteed in future versions of the library.
 * It is recommended to avoid relying on the error API for critical functionality.
 *
 * _Available since v5.1._
 */
library Errors {
    /**
     * @dev The ETH balance of the account is not enough to perform the operation.
     */
    error InsufficientBalance(uint256 balance, uint256 needed);

    /**
     * @dev A call to an address target failed. The target may have reverted.
     */
    error FailedCall();

    /**
     * @dev The deployment failed.
     */
    error FailedDeployment();

    /**
     * @dev A necessary precompile is missing.
     */
    error MissingPrecompile(address);
}

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

pragma solidity ^0.8.20;

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

Settings
{
  "remappings": [
    "forge-std/=lib/forge-std/src/",
    "@openzeppelin/=lib/openzeppelin-contracts/",
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "halmos-cheatcodes/=lib/openzeppelin-contracts/lib/halmos-cheatcodes/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 20
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {
    "src/utils.sol": {
      "Utils": "0x8724d1B62DDf87D830811C9DCB2E1a6494C9c117"
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address[]","name":"_tokens","type":"address[]"},{"internalType":"address[]","name":"_zkTokens","type":"address[]"},{"internalType":"uint256[]","name":"_newRewardRate","type":"uint256[]"},{"internalType":"uint256[]","name":"_minStakeAmount","type":"uint256[]"},{"internalType":"uint256[]","name":"_maxStakeAmount","type":"uint256[]"},{"internalType":"address","name":"_admin","type":"address"},{"internalType":"address","name":"_bot","type":"address"},{"internalType":"address","name":"_ceffu","type":"address"},{"internalType":"uint256","name":"_waitingTime","type":"uint256"},{"internalType":"address payable","name":"withdrawVaultAddress","type":"address"},{"internalType":"address","name":"_airdropAddr","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccessControlBadConfirmation","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"bytes32","name":"neededRole","type":"bytes32"}],"name":"AccessControlUnauthorizedAccount","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"SafeERC20FailedOperation","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_minAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_maxAmount","type":"uint256"}],"name":"AddSupportedToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"CancelClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"CancelStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"address","name":"_ceffu","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"CeffuReceive","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"ClaimAssets","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"address","name":"_receiver","type":"address"}],"name":"EmergencyWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bool","name":"oldStatus","type":"bool"},{"indexed":true,"internalType":"bool","name":"newStatus","type":"bool"}],"name":"FlashStatusChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_fee","type":"uint256"}],"name":"FlashWithdraw","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":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"_id","type":"uint256"}],"name":"RequestClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"previousAdminRole","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"newAdminRole","type":"bytes32"}],"name":"RoleAdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"sender","type":"address"}],"name":"RoleRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":true,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Stake","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_oldCeffu","type":"address"},{"indexed":false,"internalType":"address","name":"_newCeffu","type":"address"}],"name":"UpdateCeffu","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"oldRate","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"UpdatePenaltyRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_oldRewardRate","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newRewardRate","type":"uint256"}],"name":"UpdateRewardRate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"uint256","name":"_oldMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_oldMaxAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newMinAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newMaxAmount","type":"uint256"}],"name":"UpdateStakeLimit","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_oldWaitingTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_newWaitingTIme","type":"uint256"}],"name":"UpdateWaitingTime","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_token","type":"address"}],"name":"ZkTokenCreated","type":"event"},{"inputs":[],"name":"DEFAULT_ADMIN_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WAITING_TIME","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_minAmount","type":"uint256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"},{"internalType":"address","name":"_zkToken","type":"address"}],"name":"addSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueId","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"cancelClaim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_queueID","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"claim_41202704","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"shares","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"convertToAssets","outputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"internalType":"address","name":"_token","type":"address"}],"name":"convertToShares","outputs":[{"internalType":"uint256","name":"shares","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"address","name":"_receiver","type":"address"}],"name":"emergencyWithdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"flashWithdrawWithPenalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getClaimHistory","outputs":[{"components":[{"internalType":"bool","name":"isDone","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"principalAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"requestTime","type":"uint256"},{"internalType":"uint256","name":"claimTime","type":"uint256"}],"internalType":"struct ClaimItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimQueueIDs","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getClaimQueueInfo","outputs":[{"components":[{"internalType":"bool","name":"isDone","type":"bool"},{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"totalAmount","type":"uint256"},{"internalType":"uint256","name":"principalAmount","type":"uint256"},{"internalType":"uint256","name":"rewardAmount","type":"uint256"},{"internalType":"uint256","name":"requestTime","type":"uint256"},{"internalType":"uint256","name":"claimTime","type":"uint256"}],"internalType":"struct ClaimItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimableAssets","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getClaimableRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_targetTime","type":"uint256"}],"name":"getClaimableRewardsWithTargetTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getContractBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getCurrentRewardRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"getRoleAdmin","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"getStakeHistory","outputs":[{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"stakeTimestamp","type":"uint256"}],"internalType":"struct StakeItem","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getStakeHistoryLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getStakedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getTVL","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getTotalRewards","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_user","type":"address"},{"internalType":"address","name":"_token","type":"address"}],"name":"getZKTokenAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lastClaimQueueID","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"maxStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"minStakeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"callerConfirmation","type":"address"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"requestClaim_8135334","outputs":[{"internalType":"uint256","name":"_returnID","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bool","name":"flag","type":"bool"}],"name":"sendLpTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newAirdropAddr","type":"address"}],"name":"setAirdropAddr","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enable","type":"bool"}],"name":"setCancelEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newCeffu","type":"address"}],"name":"setCeffu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_enable","type":"bool"}],"name":"setFlashEnable","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newRate","type":"uint256"}],"name":"setPenaltyRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_newRewardRate","type":"uint256"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_minAmount","type":"uint256"},{"internalType":"uint256","name":"_maxAmount","type":"uint256"}],"name":"setStakeLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newWaitingTime","type":"uint256"}],"name":"setWaitingTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_stakedAmount","type":"uint256"}],"name":"stake_66380860","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokenToZkToken","outputs":[{"internalType":"contract IzkToken","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalRewardsAmountByToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalStakeAmountByToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferOrTransferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToCeffu","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"zkTokenToSupportedToken","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

608080604052346105c457615900803803809161001c8285610658565b83398101610160828203126105c45781516001600160401b0381116105c457816100479184016106a6565b60208301519091906001600160401b0381116105c457816100699185016106a6565b60408401519092906001600160401b0381116105c4578261008b91860161070b565b60608501519093906001600160401b0381116105c457836100ad91870161070b565b608086015190936001600160401b0382116105c4576100cd91870161070b565b926100da60a08701610692565b936100e760c08801610692565b6100f360e08901610692565b6101008901516101208a01516001600160a01b0381169a908b90036105c45761014061011f9101610692565b6000805460ff191690556127106006556032600b556014805460ff60a81b1916600160a81b17905560405163092d4e2760e21b81526001600160a01b039093166004840181905292738724d1b62ddf87d830811c9dcb2e1a6494c9c11790602081602481855af480156106145761063b575b5060405163092d4e2760e21b81526001600160a01b038b16600482015290602082602481845af490811561061457602492602092610620575b5060405163092d4e2760e21b81526001600160a01b038816600482015292839182905af48015610614576105e7575b50601480546001600160a01b0319166001600160a01b039290921691909117905586519788156105c45789518914806105dd575b806105d3575b806105c9575b156105c457604080936102a17fe4200d45d2a3d89971b73afef9feb38c84ba9c3a34c7a5d971392dbd399692299661029b856102957f2181541ed844bb663fa1c189300cc64ee66517f8346ea79c074cf61c782f0ed397610794565b50610810565b506108a8565b50600a80546001600160a01b031916821790558151600081526020810191909152a180600e55815190600082526020820152a14260125560005b85811061035457601380546001600160a01b0319168917905560005460ff81166103435760019060ff1916176000557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a1604051614f3f90816109418239f35b63d93c066560e01b60005260046000fd5b61035e8184610780565b516103698284610780565b5111156105c4576001600160a01b036103828287610780565b51169061038f8185610780565b5182600052600c6020526040600020556103a98184610780565b5182600052600d6020526040600020558160005260036020526040600020600160ff19825416179055817fd9fe4a232fa59fb866233bcdccaf84797cdd30506e8fc261699d4daaff18e4cd60406104008488610780565b5161040b8588610780565b5182519182526020820152a26001600160a01b036104298287610780565b5116826000526004602052604060002060018060a01b03821660018060a01b0319825416179055806000526005602052604060002060018060a01b03841660018060a01b03198254161790557fb2d8bbd38e8da68edecef6590f2c4977823a30e753091a7822bf5229ebd71977600080a26104a48189610780565b51604051909290606081016001600160401b038111828210176105ae576040528181526020810193845260408101428152826000526009602052604060002090815495680100000000000000008710156105ae5760018701808455871015610598576001966002936000526003602060002091020193878060a01b0390888060a01b0390511616878060a01b03198554161784555186840155519101557f37709c0c7a143f7f128833da302459d5478d74b7775d223b5f77553310a221de606061056e848c610780565b5160405190848252600060208301526040820152a1600052601060205242604060002055016102db565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052604160045260246000fd5b600080fd5b5086518914610239565b5084518914610233565b508551891461022d565b6106089060203d60201161060d575b6106008183610658565b810190610768565b6101f9565b503d6105f6565b6040513d6000823e3d90fd5b61063690833d851161060d576106008183610658565b6101ca565b6106539060203d60201161060d576106008183610658565b610191565b601f909101601f19168101906001600160401b038211908210176105ae57604052565b6001600160401b0381116105ae5760051b60200190565b51906001600160a01b03821682036105c457565b9080601f830112156105c45781516106bd8161067b565b926106cb6040519485610658565b81845260208085019260051b8201019283116105c457602001905b8282106106f35750505090565b6020809161070084610692565b8152019101906106e6565b9080601f830112156105c45781516107228161067b565b926107306040519485610658565b81845260208085019260051b8201019283116105c457602001905b8282106107585750505090565b815181526020918201910161074b565b908160209103126105c4575180151581036105c45790565b80518210156105985760209160051b010190565b6001600160a01b03811660009081526000805160206158a0833981519152602052604090205460ff1661080a576001600160a01b031660008181526000805160206158a083398151915260205260408120805460ff191660011790553391906000805160206158808339815191528180a4600190565b50600090565b6001600160a01b03811660009081526000805160206158e0833981519152602052604090205460ff1661080a576001600160a01b031660008181526000805160206158e083398151915260205260408120805460ff191660011790553391907f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a906000805160206158808339815191529080a4600190565b6001600160a01b03811660009081526000805160206158c0833981519152602052604090205460ff1661080a576001600160a01b031660008181526000805160206158c083398151915260205260408120805460ff191660011790553391907f6d5c9827c1f410bbb61d3b2a0a34b6b30492d9a1fd38588edca7ec4562ab9c9b906000805160206158808339815191529080a460019056fe60806040526004361015610013575b600080fd5b6000803560e01c80604e14613af4578060ed1461379b57806301ffc9a71461374457806304d3a96d146132245780630db14e95146130925780630e155c9514612faf5780630f40517a14612f765780631a9be40a14612d81578063209302ca14612d545780632169678314612a7a578063248a9ca314612a5b578063251d6ec314612a225780632d4abd2d146128b35780632f2ff15d1461288157806332cf58c41461267f578063361032911461255857806336568abe1461251357806339de62a6146124975780633a33a4f8146122ec5780633f4ba83a14612286578063429f30501461202357806343ab265f14611fff57806346891db714611e1757806348d832cb14611d3c5780634d2b144414611d1e5780634f8fe1f114611ca25780635c975abb14611c805780636382d9ad14611b0557806366fd9d651461170757806368c4ac26146116c85780636c0a188e146116aa5780637c395b131461150e578063812a71d5146112a15780638456cb59146112485780638d34a9ed146110fb57806391d14854146110af578063920c28f31461106e57806394af69aa14610e1757806395d322b014610dde5780639ed9e48314610c6f578063a1bab44714610c03578063a217fddf14610be7578063abd4292214610ba3578063b883d89c14610b5e578063cb0b8fe514610b25578063cfb66ab114610ae4578063d295fa9a146109a0578063d547741f14610965578063da57c7d71461077e578063e30227ea1461069e578063e315d80414610665578063ebc73e6514610604578063f56f4f0f146105cf5763f7192ba81461026a57600080fd5b346105cc5760403660031901126105cc5760043561028661402a565b9061028f61476d565b60ff60145460a81c1661058d5780835260076020526102b0604084206143ae565b818452600760205283600660408220828155826001820155826002820155826003820155826004820155826005820155015560018060a01b03602082015116903385526008602052604080862060009060018060a01b03851682526020522033865260086020526040862060018060a01b03841660005260205261033a600360406000200161434a565b94606083015115610589576040830151336001600160a01b03909116036105895761036683511561455f565b6001600160a01b0381169361037c908514614595565b865b865181101561057a5785610392828961444b565b51146103a05760010161037e565b909192939495805190600019820191821161056657916103f26103ca6103f793610435969561444b565b516103d96003880193846141cc565b90919082549060031b91821b91600019901b1916179055565b6145cf565b60a060808501519401519261040d858254614290565b81556001810161041e858254614290565b9055600242910155610430813361478a565b614811565b61043f8284614290565b670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561055257869161046b91614230565b848252600f60205260408220610482858254614290565b905584825260116020526040822061049b848254614290565b9055848252600460205260408220546001600160a01b0316803b1561054e576040516340c10f1960e01b815291839183918290849082906104e0903360048401614250565b03925af180156105435761052a575b50506104fa91614290565b916040519081527f16a8ebcbce0c773c9fc99b0335c37c4f8128bb11da6e765f86f0aa66c6735b1860203392a480f35b81610534916141ab565b61053f5784386104ef565b8480fd5b6040513d84823e3d90fd5b8280fd5b634e487b7160e01b87526011600452602487fd5b634e487b7160e01b89526011600452602489fd5b506104359192939495506103f7565b8680fd5b60405162461bcd60e51b815260206004820152601760248201527663616e63656c20636c61696d206e6f7420656e61626c6560481b6044820152606490fd5b80fd5b50346105cc5760403660031901126105cc5760206105fc6105ee614014565b6105f661402a565b90614a2f565b604051908152f35b50346105cc5760203660031901126105cc5760043561062161492d565b7fe4200d45d2a3d89971b73afef9feb38c84ba9c3a34c7a5d971392dbd399692296040600e5461065381851415614737565b8151908152836020820152a1600e5580f35b50346105cc5760203660031901126105cc576020906040906001600160a01b0361068d614014565b168152601183522054604051908152f35b50346105cc5760203660031901126105cc576001600160a01b036106c0614014565b16815260096020526040812080546106d781614397565b916106e560405193846141ab565b81835283526020808420849184015b838310610740578585805191600019830192831161072c576040602061071a858561444b565b51015181519081526127106020820152f35b634e487b7160e01b81526011600452602490fd5b6003602060019260405161075381614190565b848060a01b0386541681528486015483820152600286015460408201528152019201920191906106f4565b50346105cc57604061078f36614040565b9291846060845161079f81614128565b8281528260208201528286820152015260018060a01b038216855260036020526107ce60ff84872054166140ee565b6001600160a01b03908116855260086020908152838620929091166000908152919052206040516107fe81614175565b8154815260018201546020820152600282015460408201526108226003830161434a565b60608201526004820191825461083781614397565b9361084560405195866141ab565b81855286526020808720879186015b8383106109105750505050600590608083019384520190815461087681614397565b9261088460405194856141ab565b81845286526020808720969084015b8282106108f25760806108ba88888860a08901526108b48151518310614703565b5161444b565b5160606040519160018060a01b03815116835260018060a01b0360208201511660208401526040810151604084015201516060820152f35b600760206001926109028b6143ae565b815201980191019096610893565b6004602060019260409b989b5161092681614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190979497610854565b50346105cc5760403660031901126105cc5761099c60043561098561402a565b906109976109928261450d565b6149f2565b614e28565b5080f35b50346105cc5760403660031901126105cc5760043560046109bf61402a565b6001600160a01b03818116808652602084815260408088205490516318160ddd60e01b81529592939192869290918391165afa928315610ad9578593610aa5575b508452600f602052610a1760408520549130614a2f565b82610a5757505050670de0b6b3a7640000915b670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561072c5760206105fc8484614230565b610a6091614290565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610a915790610a8b91614230565b91610a2a565b634e487b7160e01b84526011600452602484fd5b9092506020813d602011610ad1575b81610ac1602093836141ab565b8101031261000e57519138610a00565b3d9150610ab4565b6040513d87823e3d90fd5b50346105cc5760203660031901126105cc576020906001600160a01b03610b09614014565b16815260048252604060018060a01b0391205416604051908152f35b50346105cc5760203660031901126105cc576020906040906001600160a01b03610b4d614014565b168152600f83522054604051908152f35b50346105cc5760203660031901126105cc57610b78614014565b610b8061492d565b601480546001600160a01b0319166001600160a01b039290921691909117905580f35b50346105cc5760203660031901126105cc57610bd76040610be392610bc66146c6565b5060043581526007602052206143ae565b60405191829182614089565b0390f35b50346105cc57806003193601126105cc57602090604051908152f35b50346105cc5760203660031901126105cc57600435610c2061492d565b61271081111580610c63575b610c3590614737565b80600b547f2841fef93624d9d474e38055eb5f9d3a6a8c9fdf078b6790af293d5d31225e108480a3600b5580f35b50600b54811415610c2c565b50346105cc5760403660031901126105cc576040610c8b614014565b610c9361402a565b6001600160a01b0391821684526008602090815283852091909216600090815291522060405191610cc383614175565b815483526001820154602084015260028201546040840152610ce76003830161434a565b606084015260048201918254610cfc81614397565b93610d0a60405195866141ab565b81855283526020808420849186015b838310610d8f575050505060808401928352600501805490610d3a82614397565b92610d4860405194856141ab565b82845290815260208082209084015b838310610d71576020868660a08a01525151604051908152f35b60076020600192610d81856143ae565b815201920192019190610d57565b60046020600192604051610da281614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190610d19565b50346105cc5760203660031901126105cc576020906040906001600160a01b03610e06614014565b168152600c83522054604051908152f35b50346105cc5760803660031901126105cc57610e31614014565b6064356001600160a01b0381169190604435906024359084900361053f57610e5761492d565b60405163092d4e2760e21b81526001600160a01b039093166004840181905292602081602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4801561106357611036575b50828552600360205260ff60408620541661100557828552600360205260408520805460ff19166001179055610ed361492d565b8285526003602052610eeb60ff6040872054166140ee565b80151580610ffc575b1561053f5760407fd9fe4a232fa59fb866233bcdccaf84797cdd30506e8fc261699d4daaff18e4cd918493848852600c602052847fe4b65af790442ef39b02e91f9b1e0caf05cb7e3607b3525b51b8d26dc27383826080858b2054838c52600d602052868c2054875191825260208201528587820152846060820152a2848852600c6020528183892055848852600d602052808389205582519182526020820152a280835260046020908152604080852080546001600160a01b03199081166001600160a01b0387161790915584865260059092528420805490911690911790557fb2d8bbd38e8da68edecef6590f2c4977823a30e753091a7822bf5229ebd719778280a280f35b50818110610ef4565b60405162461bcd60e51b815260206004820152600960248201526814dd5c1c1bdc9d195960ba1b6044820152606490fd5b6110579060203d60201161105c575b61104f81836141ab565b810190614419565b610e9f565b503d611045565b6040513d88823e3d90fd5b50346105cc5760203660031901126105cc576020906001600160a01b03611093614014565b16815260058252604060018060a01b0391205416604051908152f35b50346105cc5760403660031901126105cc5760406110cb61402a565b9160043581526001602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346105cc5760803660031901126105cc57611115614014565b61111d61402a565b90604435916064359081151580920361053f576014546001600160a01b031692338490036112445761118960208660018060a01b03841696878a5260048352858a60018060a01b0360408220541692604051968795869485936323b872dd60e01b85526004850161460e565b03925af180156112395761121c575b506001600160a01b03821686526008602090815260408088206000878152925290209260010361120e57505060125460028201555b6111d8838254614290565b9055808352600f602052604083206111f1838254614290565b90558252600260205261120960408320918254614290565b905580f35b6112179161478a565b6111cd565b6112349060203d60201161105c5761104f81836141ab565b611198565b6040513d89823e3d90fd5b8580fd5b50346105cc57806003193601126105cc57611261614980565b61126961476d565b600160ff198254161781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346105cc5760403660031901126105cc576112bb614014565b6001600160a01b031680825260036020526040822054602435906112e19060ff166140ee565b6112e961492d565b6127108110156114da57818352600960205260408320805461130a81614397565b9161131860405193846141ab565b81835285526020808620869184015b83831061149c575050505080519060001982019182116114885760209161134d9161444b565b510151818114158061147f575b156114475760405161136b81614190565b838152602081018381526040820190428252858752600960205260408720805490600160401b821015611433576001820180825582101561141f57885260208089209451600390920290940180546001600160a01b0319166001600160a01b03929092169190911781559051600182015590516002919091015560408051948552908401919091528201527f37709c0c7a143f7f128833da302459d5478d74b7775d223b5f77553310a221de90606090a180f35b634e487b7160e01b89526032600452602489fd5b634e487b7160e01b89526041600452602489fd5b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964206e6577207261746560801b6044820152606490fd5b5081151561135a565b634e487b7160e01b85526011600452602485fd5b600360206001926040516114af81614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190611327565b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964207261746560a01b6044820152606490fd5b50346105cc5760409061152036614040565b939161152a6146c6565b506001600160a01b038216845260036020528284205461154c9060ff166140ee565b6001600160a01b03908116845260086020908152838520929091166000908152919052206040519061157d82614175565b8054825260018101546020830152600281015460408301526115a16003820161434a565b60608301526004810180546115b581614397565b916115c360405193846141ab565b81835285526020808620869184015b83831061165b575050505060808301526005018054906115f182614397565b936115ff60405195866141ab565b82855290815260208082209085015b83831061163d57610be361163088886108b460a08a0191808352518310614703565b5160405191829182614089565b6007602060019261164d856143ae565b81520192019201919061160e565b6004602060019260405161166e81614128565b848060a01b038654168152848060a01b0385870154168382015260028601546040820152600386015460608201528152019201920191906115d2565b50346105cc57806003193601126105cc576020600654604051908152f35b50346105cc5760203660031901126105cc5760209060ff906040906001600160a01b036116f3614014565b168152600384522054166040519015158152f35b50346105cc5760803660031901126105cc57611721614014565b61172961402a565b6044356001600160a01b038116919082810361053f57606435906001600160a01b03831690848214611ac0578215611a7b57611765868561445f565b93838510611a4c57338314611a0b5760018060a01b038716808952600460205260018060a01b0360408a20541660206040518092636eb1769f60e11b825281806117b3338960048401614431565b03915afa8015611a005786918b916119cb575b501061199a578089526004602052604089205489906001600160a01b0316803b1561199657816040518092630f75ba2160e41b825281838161180d8d338c6004850161460e565b03925af180156105435761197d575b5052600460205260018060a01b0360408920541691602060405180946323b872dd60e01b8252818c816118548b888a6004850161460e565b03925af1928315611972578880936118759261187a96611953575b5061478a565b61478a565b85526008602052604080862060009060018060a01b03871682526020522091825491604060018501968754968952600860205281892060009160018060a01b031682526020522096670de0b6b3a76400008202918204670de0b6b3a76400000361072c5750611910611940959493670de0b6b3a7640000611909611902611926968396614230565b809361421d565b049561421d565b049261191d818854614290565b875582546141fa565b905560018401611937828254614290565b905582546141fa565b9055600242910155602060405160018152f35b61196b9060203d60201161105c5761104f81836141ab565b503861186f565b6040513d8b823e3d90fd5b81611987916141ab565b61199257883861181c565b8880fd5b5080fd5b60405162461bcd60e51b8152602060048201526009602482015268616c6c6f77616e636560b81b6044820152606490fd5b9150506020813d6020116119f8575b816119e7602093836141ab565b8101031261000e57859051386117c6565b3d91506119da565b6040513d8c823e3d90fd5b60018060a01b0387168852600460205260018060a01b0360408920541691602060405180946323b872dd60e01b8252818c816118548b88336004850161460e565b60405162461bcd60e51b815260206004820152600760248201526662616c616e636560c81b6044820152606490fd5b60405162461bcd60e51b815260206004820152601d60248201527f616d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b60405162461bcd60e51b815260206004820152601e60248201527f66726f6d2063616e206e6f742062652073616d652061732074686520746f00006044820152606490fd5b50346105cc5760403660031901126105cc57611b1f614014565b611b2761402a565b90611b3061492d565b60405163092d4e2760e21b81526001600160a01b0390911660048201819052738724d1b62ddf87d830811c9dcb2e1a6494c9c117929091602081602481875af48015610ad957611c63575b5060405163092d4e2760e21b81526001600160a01b0382166004820181905293602090829060249082905af48015610ad957611c46575b506040516370a0823160e01b815230600482015290602082602481865afa908115610ad9578591611c10575b611be99250836148f3565b7ff5b6d8b404f034718f55a370884db03c4e27e9652e2636d4adcd0540d7c4203f8380a380f35b90506020823d602011611c3e575b81611c2b602093836141ab565b8101031261000e57611be9915190611bde565b3d9150611c1e565b611c5e9060203d60201161105c5761104f81836141ab565b611bb2565b611c7b9060203d60201161105c5761104f81836141ab565b611b7b565b50346105cc57806003193601126105cc5760ff60209154166040519015158152f35b50346105cc5760203660031901126105cc57611cbc61407a565b611cc461492d565b6014549060ff8260a81c16151590151591611ce182841415614521565b60ff60a81b191660a883901b60ff60a81b16176014557f84e3667aff0d15c7464eb61e79d9db356389b19a3a5024099a09272a7bf11ce98380a380f35b50346105cc57806003193601126105cc576020600e54604051908152f35b50346105cc5760603660031901126105cc57611d56614014565b60243560443591611d6561492d565b6001600160a01b031680845260036020526040842054909190611d8a9060ff166140ee565b80151580611e0e575b15611e0a57818452600c602052817fe4b65af790442ef39b02e91f9b1e0caf05cb7e3607b3525b51b8d26dc273838260806040872054838852600d60205260408820546040519182526020820152846040820152866060820152a2818452600c60205260408420558252600d602052604082205580f35b8380fd5b50828110611d93565b50346105cc5760403660031901126105cc57611e31614014565b6001600160a01b0316808252600360205260408220546024359190611e589060ff166140ee565b7f6d5c9827c1f410bbb61d3b2a0a34b6b30492d9a1fd38588edca7ec4562ab9c9b8352600160209081526040808520336000908152925290205460ff1615611fc8578115611f98576040516370a0823160e01b8152306004820152602081602481855afa908115611f8d578491611f5b575b508211611f2157600a54611ee99083906001600160a01b0316836148f3565b7f4df7f50f630ac07eef038205b5b9c0c910ce8498aa925abbfcb0e1e674058aa9602060018060a01b03600a5416604051908152a380f35b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b90506020813d602011611f85575b81611f76602093836141ab565b8101031261000e575138611eca565b3d9150611f69565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152600860248201526706d757374203e20360c41b6044820152606490fd5b63e2517d3f60e01b8352336004527f6d5c9827c1f410bbb61d3b2a0a34b6b30492d9a1fd38588edca7ec4562ab9c9b602452604483fd5b50346105cc5760203660031901126105cc5760206105fc61201e614014565b614630565b50346105cc5760403660031901126105cc5760043561204061402a565b9061204961476d565b808352600760205261205d604084206143ae565b60208181015133808752600880845260408089206001600160a01b039094166000818152948652818520938a529185528089208285529094529290912090949192906120ab9060030161434a565b9460608201928351156122825760e08301514210612282576040830151336001600160a01b0390911603612282576120f8906120e884511561455f565b6001600160a01b03168514614595565b848752600760205260408720805460ff19166001179055865b86518110156122715785612125828961444b565b511461213357600101612111565b9091929394958051906000198201918211610566576005926103f26121606121dc97969461216f9461444b565b516103d96003860193846141cc565b60808301928351878a52600260205261218d60408b209182546141fa565b9055855193519060c060a082015191015191604051956121ac87614159565b600187528960208801523360408801526060870152608086015260a085015260c08401524260e08401520161429d565b601354815185916001600160a01b0316803b1561054e576040516317d5759960e31b8152918391839182908490829061221a90338c6004850161460e565b03925af180156105435761225c575b505051916040519081527fdddf48d4d866b99b4e98ab4756d69715555f0445680fe5941715d094c362c0fd60203392a480f35b81612266916141ab565b611e0a578338612229565b506121dc929394955060059061216f565b8780fd5b50346105cc57806003193601126105cc5761229f614980565b805460ff8116156122dd5760ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b50346105cc5760403660031901126105cc576040612308614014565b61231061402a565b6001600160a01b0391821684526008602090815283852091909216600090815291522060405161233f81614175565b8154815260018201546020820152600282015460408201526123636003830161434a565b916060820192835260048101805461237a81614397565b9161238860405193846141ab565b81835286526020808720879184015b8383106124485750505050906005916080840152019081546123b881614397565b926123c660405194856141ab565b81845285526020808620869185015b83831061242a575050505060a001525190604051918291602083016020845282518091526020604085019301915b818110612411575050500390f35b8251845285945060209384019390920191600101612403565b6007602060019261243a856143ae565b8152019201920191906123d5565b6004602060019260405161245b81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612397565b50346105cc5760203660031901126105cc576124b161407a565b6124b961492d565b6014549060ff8260a01c161515901515916124d682841415614521565b60ff60a01b191660a083901b60ff60a01b16176014557f99859612a8514731da8547a1b97ab4654097e36c13fe2c98960ecd00f770747b8380a380f35b50346105cc5760403660031901126105cc5761252d61402a565b336001600160a01b038216036125495761099c90600435614e28565b63334bd91960e11b8252600482fd5b50346105cc5760403660031901126105cc5760049061257561402a565b6001600160a01b03818116808452602085815260408086205490516318160ddd60e01b81529692939192879290918391165afa938415612674578394612640575b508252600f6020526125cd60408320549130614a2f565b836125f757505050506020670de0b6b3a76400006125ee815b60043561421d565b04604051908152f35b61260091614290565b90670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561072c57506125ee61263b602093670de0b6b3a764000093614230565b6125e6565b9093506020813d60201161266c575b8161265c602093836141ab565b8101031261000e575192386125b6565b3d915061264f565b6040513d85823e3d90fd5b50346105cc5760403660031901126105cc57612699614014565b6126a161402a565b9160018060a01b03821681526008602052604080822060009060018060a01b03861682526020522092604051936126d785614175565b8054855260018101546020860152600281015460408601526126fb6003820161434a565b606086015260048101805461270f81614397565b9161271d60405193846141ab565b81835285526020808620869184015b83831061283257505050509060059160808701520193845461274d81614397565b9061275b60405192836141ab565b80825260208201968552602085209685905b8282106128145750505060a082015251926127889190614a2f565b60405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d5575b602090604051908152f35b506020813d602011612800575b816127ef602093836141ab565b8101031261000e57602090516127ca565b3d91506127e2565b604051903d90823e3d90fd5b600760206001926128248c6143ae565b81520199019101909761276d565b6004602060019260405161284581614128565b848060a01b038654168152848060a01b03858701541683820152600286015460408201526003860154606082015281520192019201919061272c565b50346105cc5760403660031901126105cc5761099c6004356128a161402a565b906128ae6109928261450d565b614d99565b50346105cc5760403660031901126105cc5760406128cf614014565b6128d761402a565b6001600160a01b03918216845260086020908152838520919092166000908152915220604051909161290882614175565b82548252600183015460208301526002830154604083015261292c6003840161434a565b60608301526004830192835461294181614397565b9061294f60405192836141ab565b80825260208201958452602084209584905b8282106129d357505050608084015260050180549061297f82614397565b9261298d60405194856141ab565b82845290815260208082209084015b8383106129b5576020858060a089015251604051908152f35b600760206001926129c5856143ae565b81520192019201919061299c565b600460206001926040516129e681614128565b848060a01b038c54168152848060a01b03858d0154168382015260028c0154604082015260038c01546060820152815201980191019096612961565b50346105cc5760203660031901126105cc576020906040906001600160a01b03612a4a614014565b168152600d83522054604051908152f35b50346105cc5760203660031901126105cc5760206105fc60043561450d565b50346105cc57612a8936614040565b929042841115612d205760018060a01b03831682526008602052604080832060009060018060a01b0384168252602052209260405191612ac883614175565b845483526001850154602084015260028501549460408401958652612aef6003820161434a565b6060850152600481018054612b0381614397565b91612b1160405193846141ab565b81835287526020808820889184015b838310612cd1575050505060808501526005018054612b3e81614397565b91612b4c60405193846141ab565b81835286526020808720879184015b838310612cb3575050505060a08401526001600160a01b03811684526009602052604084208054612b8b81614397565b91612b9960405193846141ab565b81835286526020808720879184015b838310612c7557505050508051906000198201918211612c615790612bcc9161444b565b5191849551612c41575b50506020612bed644979cb9e0094959642906141fa565b925191015102020460405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d557602090604051908152f35b644979cb9e00949550612c59602092612bed92614a2f565b959450612bd6565b634e487b7160e01b86526011600452602486fd5b60036020600192604051612c8881614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190612ba8565b60076020600192612cc3856143ae565b815201920192019190612b5b565b60046020600192604051612ce481614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612b20565b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b6044820152606490fd5b50346105cc5760403660031901126105cc5760206105fc612d73614014565b612d7b61402a565b9061445f565b50346105cc5760403660031901126105cc57612d9b614014565b90612da461402a565b9160408293612db38184614a2f565b6001600160a01b0393841685526008602090815283862092909416600090815291909352206040519290612de684614175565b805484526001810154602085015260028101546040850152612e0a6003820161434a565b6060850152600481018054612e1e81614397565b91612e2c60405193846141ab565b81835284526020808520859184015b838310612f27575050505090600591608086015201928354612e5c81614397565b94612e6a60405196876141ab565b81865283526020808420849187015b838310612f09575050505060a00192835280935b83518051861015612ebb5760019160a0612eaa88612eb39461444b565b51015190614290565b940193612e8d565b509160405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d557602090604051908152f35b60076020600192612f19856143ae565b815201920192019190612e79565b60046020600192604051612f3a81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612e3b565b50346105cc5760203660031901126105cc576020906040906001600160a01b03612f9e614014565b168152600283522054604051908152f35b50346105cc5760203660031901126105cc57612fc9614014565b612fd161492d565b60405163092d4e2760e21b81526001600160a01b038216600482018190529190602081602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af48015611f8d57613075575b50600a54906001600160a01b0382169083821461053f577f2181541ed844bb663fa1c189300cc64ee66517f8346ea79c074cf61c782f0ed39161306160405192839283614431565b0390a16001600160a01b03191617600a5580f35b61308d9060203d60201161105c5761104f81836141ab565b613019565b50346105cc5760403660031901126105cc5760406130ae614014565b6130b661402a565b6001600160a01b03811684526003602052828420549091906130da9060ff166140ee565b60018060a01b03168352600860205281832060009160018060a01b03168252602052209060405161310a81614175565b82548152600183015460208201526002830154604082015261312e6003840161434a565b60608201526004830192835461314381614397565b9061315160405192836141ab565b80825260208201958552602085209585905b8282106131d557505050608083015260050180549061318182614397565b9361318f60405195866141ab565b82855290815260208082209085015b8383106131b7576020858760a082015251604051908152f35b600760206001926131c7856143ae565b81520192019201919061319e565b600460206001926040516131e881614128565b848060a01b038c54168152848060a01b03858d0154168382015260028c0154604082015260038c01546060820152815201980191019096613163565b50346105cc5760403660031901126105cc5761323e614014565b6001600160a01b0381168083526003602052604083205460243592906132669060ff166140ee565b61326e61476d565b60ff60145460a01c1661370357338452600860205260408085206000908482526020522061329c823361478a565b6132a582614811565b81549160018101928354908715159182613662575b50501561058957600654875260076020528254958781600019810361361d5750505086815460405190637afbe4f160e01b82528860048301526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156105435782916135e8575b509693558054918782555b86156135ab57858852600f6020526040882061334b8482546141fa565b90558588526011602052604088206133648582546141fa565b9055670de0b6b3a76400008702878104670de0b6b3a76400000361056657889161338d91614230565b86825260046020526024602060018060a01b03604085205416604051928380926370a0823160e01b82523360048301525afa908115612674578391613576575b50808211801561356d575b613565575b50868252600460205260408220546001600160a01b0316803b1561054e57604051632770a7eb60e21b81529183918391829084908290613421903360048401614250565b03925af1801561054357613550575b5050600b5461271003612710811161353c5761344f612710918861421d565b04908161346561345f828a6141fa565b96614630565b10613502576134d39361347b60059333896148f3565b8689526002602052604089206134928582546141fa565b9055604051936134a185614159565b60018552876020860152336040860152886060860152608085015260a08401524260c08401524260e08401520161429d565b6040519081527febb065a01aeb84b2b8d3adb2f31a9b004b8ddaba2a4f702240f6f569e49855be60203392a480f35b60405162461bcd60e51b81526020600482015260126024820152716e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b634e487b7160e01b88526011600452602488fd5b8161355a916141ab565b610589578638613430565b9050386133dd565b508354156133d8565b9250506020823d6020116135a3575b81613592602093836141ab565b8101031261000e57889151386133cd565b3d9150613585565b60405162461bcd60e51b81526020600482015260156024820152746e6f2061737365747320746f20776974686472617760581b6044820152606490fd5b9150506020813d602011613615575b81613604602093836141ab565b8101031261000e5787905138613323565b3d91506135f7565b91979394909382811061363e57506136368282546141fa565b90559261332e565b9094935061364f91898296556141fa565b61365a8183546141fa565b82559161332e565b604051637afbe4f160e01b8152600481019290925260248201529050602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156136f85788916136c6575b5086118015906136bb575b38806132ba565b5060001986146136b4565b90506020813d6020116136f0575b816136e1602093836141ab565b8101031261000e5751386136a9565b3d91506136d4565b6040513d8a823e3d90fd5b60405162461bcd60e51b8152602060048201526019602482015278666c617368207769746864726177206e6f7420656e61626c6560381b6044820152606490fd5b50346105cc5760203660031901126105cc5760043563ffffffff60e01b811680910361199657602090637965db0b60e01b811490811561378a575b506040519015158152f35b6301ffc9a760e01b1490508261377f565b50346105cc5760403660031901126105cc576137b5614014565b6001600160a01b0381168083526003602052604083205460243592906137dd9060ff166140ee565b6137e561476d565b3384526008602052604080852060009084825260205220908154738724d1b62ddf87d830811c9dcb2e1a6494c9c11790604051637afbe4f160e01b8152816004820152866024820152602081604481865af49081156136f8578891613ac2575b50858852600c60205260408820541161058957602090604460405180948193637afbe4f160e01b835260048301528960248301525af4908115611063578691613a90575b50838652600d60205260408620541061053f576138e4906138da6040516323b872dd60e01b60208201526138d4816138c68930336024850161460e565b03601f1981018352826141ab565b85614eae565b610430813361478a565b828552600f602052604085206138fb858254614290565b9055670de0b6b3a76400008402848104670de0b6b3a76400001485151715612c6157859161392891614230565b838252600460205260408220546001600160a01b0316803b1561054e576040516340c10f1960e01b8152918391839182908490829061396b903360048401614250565b03925af1801561054357613a7b575b50506040516004820161398c82614128565b8382526020820133815260408301908682526060840192428452805490600160401b821015613a675760018201808255821015613a535789526020808a209551600292831b90960180546001600160a01b039788166001600160a01b03199182161782559351600182018054919098169416939093179095559151818301559151600390920191909155825485019092558285525260408320805483019055337f99039fcf0a98f484616c5196ee8b2ecfa971babf0b519848289ea4db381f85f78480a480f35b634e487b7160e01b8a52603260045260248afd5b634e487b7160e01b8a52604160045260248afd5b81613a85916141ab565b611e0a57833861397a565b90506020813d602011613aba575b81613aab602093836141ab565b8101031261000e575138613889565b3d9150613a9e565b90506020813d602011613aec575b81613add602093836141ab565b8101031261000e575138613845565b3d9150613ad0565b50346105cc5760403660031901126105cc57613b0e614014565b6001600160a01b038116808352600360205260408320546024359290613b369060ff166140ee565b613b3e61476d565b613b48813361478a565b613b5181614811565b903385526008602052604085208386526020526040852080549260018201938454908715159182613f7e575b505015613f485760065487526007602052604087209386888254986000198114600014613f065750505087835460405190637afbe4f160e01b82528960048301526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4908115610543578291613ed4575b5097915582548884555b60048601918255600386019081558715613e975760065460038501805490600160401b821015613e8357816103d9916001613c3695940181556141cc565b54868952600f602052613c4e60408a209182546141fa565b9055548588526011602052613c68604089209182546141fa565b9055670de0b6b3a76400008602868104670de0b6b3a76400000361353c57613c94889392602492614230565b918684526004602052602060018060a01b03604086205416604051938480926370a0823160e01b82523360048301525afa918215611f8d578492613e4f575b50818311908115613e45575b50613e3d575b50848252600460205260408220546001600160a01b031690813b1561054e578291613d2791604051948580948193632770a7eb60e21b83523360048401614250565b03925af1801561106357613e27575b50613d41908261426b565b6001810180546001600160a01b03191633179055600281018390554260058201819055600e54604051637afbe4f160e01b815260048101929092526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49485156128085794613df2575b509260066020940155600654918291600183016006557f558f1f0a2c456722ef2cc50e288df74e32ca2e201a9218272de7eb91065150a985604051338152a4604051908152f35b93506020843d602011613e1f575b81613e0d602093836141ab565b8101031261000e579251926006613dab565b3d9150613e00565b94613e3681613d4193976141ab565b9490613d36565b905038613ce5565b9050541538613cdf565b9091506020813d602011613e7b575b81613e6b602093836141ab565b81010312611e0a57519038613cd3565b3d9150613e5e565b634e487b7160e01b8c52604160045260248cfd5b60405162461bcd60e51b81526020600482015260156024820152744e6f2061737365747320746f20776974686472617760581b6044820152606490fd5b90506020813d602011613efe575b81613eef602093836141ab565b81010312611996575138613bee565b3d9150613ee2565b9198909290828110613f265750613f1e8282546141fa565b905590613bf8565b909250613f36918a8294556141fa565b613f418185546141fa565b8455613bf8565b60405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606490fd5b604051637afbe4f160e01b8152600481019290925260248201529050602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156136f8578891613fe2575b508611801590613fd7575b3880613b7d565b506000198614613fd0565b90506020813d60201161400c575b81613ffd602093836141ab565b81010312612282575138613fc5565b3d9150613ff0565b600435906001600160a01b038216820361000e57565b602435906001600160a01b038216820361000e57565b606090600319011261000e576004356001600160a01b038116810361000e57906024356001600160a01b038116810361000e579060443590565b60043590811515820361000e57565b91909160e08061010083019480511515845260018060a01b03602082015116602085015260018060a01b036040820151166040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b156140f557565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b608081019081106001600160401b0382111761414357604052565b634e487b7160e01b600052604160045260246000fd5b61010081019081106001600160401b0382111761414357604052565b60c081019081106001600160401b0382111761414357604052565b606081019081106001600160401b0382111761414357604052565b90601f801991011681019081106001600160401b0382111761414357604052565b80548210156141e45760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b9190820391821161420757565b634e487b7160e01b600052601160045260246000fd5b8181029291811591840414171561420757565b811561423a570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b039091168152602081019190915260400190565b8054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b9190820180921161420757565b805490600160401b82101561414357600182018082558210156141e45760069160e09160005260076020600020910201928051151560ff801986541691161784556142f460018060a01b036020830151168561426b565b60408101516001850180546001600160a01b0319166001600160a01b0392909216919091179055606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b906040519182815491828252602082019060005260206000209260005b81811061437e57505061437c925003836141ab565b565b8454835260019485019487945060209093019201614367565b6001600160401b0381116141435760051b60200190565b906040516143bb81614159565b825460ff81161515825260081c6001600160a01b03908116602083015260018401541660408201526002830154606082015260038301546080820152600483015460a0820152600583015460c08201526006929092015460e0830152565b9081602091031261000e5751801515810361000e5790565b6001600160a01b0391821681529116602082015260400190565b80518210156141e45760209160051b010190565b6001600160a01b039091166000818152600360205260409020546144859060ff166140ee565b6000526004602052602060018060a01b0360406000205416916024604051809481936370a0823160e01b835260018060a01b031660048301525afa908115614501576000916144d2575090565b90506020813d6020116144f9575b816144ed602093836141ab565b8101031261000e575190565b3d91506144e0565b6040513d6000823e3d90fd5b600052600160205260016040600020015490565b1561452857565b60405162461bcd60e51b815260206004820152600f60248201526e1b9bdd1a1a5b99c818da185b99d959608a1b6044820152606490fd5b1561456657565b60405162461bcd60e51b815260206004820152600760248201526618db185a5b595960ca1b6044820152606490fd5b1561459c57565b60405162461bcd60e51b815260206004820152600b60248201526a3bb937b733903a37b5b2b760a91b6044820152606490fd5b805480156145f85760001901906145e682826141cc565b8154906000199060031b1b1916905555565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b03918216815291166020820152604081019190915260600190565b60405163092d4e2760e21b81526001600160a01b0390911660048201819052602082602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4908115614501576024926020926146ab575b506040516370a0823160e01b815230600482015292839182905afa908115614501576000916144d2575090565b6146c190833d851161105c5761104f81836141ab565b61467e565b604051906146d382614159565b600060e0838281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b1561470a57565b60405162461bcd60e51b81526020600482015260056024820152640d2dcc8caf60db1b6044820152606490fd5b1561473e57565b60405162461bcd60e51b8152602060048201526007602482015266125b9d985b1a5960ca1b6044820152606490fd5b60ff6000541661477957565b63d93c066560e01b60005260046000fd5b9060018060a01b0382166000526008602052604060002060018060a01b03821660005260205260406000209160008260028501928354614800575b506147d260019130614a2f565b94015542905560018060a01b0316806000526010602052426040600020556000526011602052604060002055565b61480a9250614a2f565b82386147c5565b6001600160a01b039081166000818152600460208181526040928390205492516318160ddd60e01b81529490928592918391165afa918215614501576000926148bf575b5081614869575050670de0b6b3a764000090565b8061489191600052600f60205260406000205490600052601160205260406000205490614290565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715614207576148bc91614230565b90565b90916020823d6020116148eb575b816148da602093836141ab565b810103126105cc5750519038614855565b3d91506148cd565b61492861437c939261491a60405194859263a9059cbb60e01b602085015260248401614250565b03601f1981018452836141ab565b614eae565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff161561496657565b63e2517d3f60e01b60005233600452600060245260446000fd5b3360009081527fb9cbbae02fe941283ec0eefd7b121e3bc7f89fae077b27bdd75a7fd4cf1543a8602052604090205460ff16156149b957565b63e2517d3f60e01b600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b600081815260016020908152604080832033845290915290205460ff1615614a175750565b63e2517d3f60e01b6000523360045260245260446000fd5b9091906001600160a01b03166000308214614d5b5750600052600860205260408060002060009060018060a01b03851682526020522091604051614a7281614175565b835481526001840154906020810191825260028501549460408201958652614a9c6003820161434a565b6060830152600481018054614ab081614397565b91614abe60405193846141ab565b818352602083019060005260206000206000915b838310614d0c575050505060808301526005018054614af081614397565b91614afe60405193846141ab565b818352602083019060005260206000206000915b838310614cee575050505060a08201525193519051915b60018060a01b031660005260096020526040600020908154614b4a81614397565b92614b5860405194856141ab565b818452602084019060005260206000206000915b838310614cb05750505050815191600019830183811161420757614b90908261444b565b51928215614ca55760408401918383511115600014614bd057505050906148bc93946020614bc4644979cb9e0094426141fa565b92015102020490614290565b60009392939260005b838110614c77575b505b828410614c075750505050906148bc93946020614bc4644979cb9e009451426141fa565b839691929315614c6d57614c29906040614c21898661444b565b5101516141fa565b6000198701878111614207576001916020614c4a644979cb9e00938761444b565b5101518b0202046040614c5d898661444b565b5101519201965b01929190614be3565b9095600190614c64565b6040614c86828596979561444b565b5101518210614c9b5760010193929193614bd9565b9392915038614be1565b506000955050505050565b60036020600192604051614cc381614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190614b6c565b60076020600192614cfe856143ae565b815201920192019190614b12565b60046020600192604051614d1f81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190614ad2565b929050604060018060a01b03821693848152600f60205220549280600052601060205260406000205490600052601160205260406000205491614b29565b60008181526001602090815260408083206001600160a01b038616845290915290205460ff16614e215760008181526001602081815260408084206001600160a01b0396909616808552959091528220805460ff19169091179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b60008181526001602090815260408083206001600160a01b038616845290915290205460ff1615614e215760008181526001602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b906000602091828151910182855af115614501576000513d614f0057506001600160a01b0381163b155b614edf5750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415614ed856fea26469706673582212207e4762669c715cdbd5a4a68f8422d6b23a0e6fabf252bf8692575e8a66c8482f64736f6c634300081c00332f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0da6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb4923b5fec2089556a6c5b151e34068bfe081a4d2aa094faa466b56d44dbb75c738b9cbbae02fe941283ec0eefd7b121e3bc7f89fae077b27bdd75a7fd4cf1543a8000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000006740a2b31bc55782e46c2a9d7a32a38905e118c5000000000000000000000000934c775d3004689ea5738fe80f34378f589f190d000000000000000000000000d038213a84a86348d000929c115528ae9ddc11580000000000000000000000000000000000000000000000000000000000127500000000000000000000000000c4a718735f0783e81fdcaa999773199c2d1498d4000000000000000000000000cb60b1d1f6399e2177ef60df7ae9312940a5e5430000000000000000000000000000000000000000000000000000000000000002000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000020000000000000000000000007336c89ff7af86131d336d504e677db0eb338a160000000000000000000000001ee6e93134aee641bdbe470df2417af476bb917f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

Deployed Bytecode

0x60806040526004361015610013575b600080fd5b6000803560e01c80604e14613af4578060ed1461379b57806301ffc9a71461374457806304d3a96d146132245780630db14e95146130925780630e155c9514612faf5780630f40517a14612f765780631a9be40a14612d81578063209302ca14612d545780632169678314612a7a578063248a9ca314612a5b578063251d6ec314612a225780632d4abd2d146128b35780632f2ff15d1461288157806332cf58c41461267f578063361032911461255857806336568abe1461251357806339de62a6146124975780633a33a4f8146122ec5780633f4ba83a14612286578063429f30501461202357806343ab265f14611fff57806346891db714611e1757806348d832cb14611d3c5780634d2b144414611d1e5780634f8fe1f114611ca25780635c975abb14611c805780636382d9ad14611b0557806366fd9d651461170757806368c4ac26146116c85780636c0a188e146116aa5780637c395b131461150e578063812a71d5146112a15780638456cb59146112485780638d34a9ed146110fb57806391d14854146110af578063920c28f31461106e57806394af69aa14610e1757806395d322b014610dde5780639ed9e48314610c6f578063a1bab44714610c03578063a217fddf14610be7578063abd4292214610ba3578063b883d89c14610b5e578063cb0b8fe514610b25578063cfb66ab114610ae4578063d295fa9a146109a0578063d547741f14610965578063da57c7d71461077e578063e30227ea1461069e578063e315d80414610665578063ebc73e6514610604578063f56f4f0f146105cf5763f7192ba81461026a57600080fd5b346105cc5760403660031901126105cc5760043561028661402a565b9061028f61476d565b60ff60145460a81c1661058d5780835260076020526102b0604084206143ae565b818452600760205283600660408220828155826001820155826002820155826003820155826004820155826005820155015560018060a01b03602082015116903385526008602052604080862060009060018060a01b03851682526020522033865260086020526040862060018060a01b03841660005260205261033a600360406000200161434a565b94606083015115610589576040830151336001600160a01b03909116036105895761036683511561455f565b6001600160a01b0381169361037c908514614595565b865b865181101561057a5785610392828961444b565b51146103a05760010161037e565b909192939495805190600019820191821161056657916103f26103ca6103f793610435969561444b565b516103d96003880193846141cc565b90919082549060031b91821b91600019901b1916179055565b6145cf565b60a060808501519401519261040d858254614290565b81556001810161041e858254614290565b9055600242910155610430813361478a565b614811565b61043f8284614290565b670de0b6b3a7640000810290808204670de0b6b3a7640000149015171561055257869161046b91614230565b848252600f60205260408220610482858254614290565b905584825260116020526040822061049b848254614290565b9055848252600460205260408220546001600160a01b0316803b1561054e576040516340c10f1960e01b815291839183918290849082906104e0903360048401614250565b03925af180156105435761052a575b50506104fa91614290565b916040519081527f16a8ebcbce0c773c9fc99b0335c37c4f8128bb11da6e765f86f0aa66c6735b1860203392a480f35b81610534916141ab565b61053f5784386104ef565b8480fd5b6040513d84823e3d90fd5b8280fd5b634e487b7160e01b87526011600452602487fd5b634e487b7160e01b89526011600452602489fd5b506104359192939495506103f7565b8680fd5b60405162461bcd60e51b815260206004820152601760248201527663616e63656c20636c61696d206e6f7420656e61626c6560481b6044820152606490fd5b80fd5b50346105cc5760403660031901126105cc5760206105fc6105ee614014565b6105f661402a565b90614a2f565b604051908152f35b50346105cc5760203660031901126105cc5760043561062161492d565b7fe4200d45d2a3d89971b73afef9feb38c84ba9c3a34c7a5d971392dbd399692296040600e5461065381851415614737565b8151908152836020820152a1600e5580f35b50346105cc5760203660031901126105cc576020906040906001600160a01b0361068d614014565b168152601183522054604051908152f35b50346105cc5760203660031901126105cc576001600160a01b036106c0614014565b16815260096020526040812080546106d781614397565b916106e560405193846141ab565b81835283526020808420849184015b838310610740578585805191600019830192831161072c576040602061071a858561444b565b51015181519081526127106020820152f35b634e487b7160e01b81526011600452602490fd5b6003602060019260405161075381614190565b848060a01b0386541681528486015483820152600286015460408201528152019201920191906106f4565b50346105cc57604061078f36614040565b9291846060845161079f81614128565b8281528260208201528286820152015260018060a01b038216855260036020526107ce60ff84872054166140ee565b6001600160a01b03908116855260086020908152838620929091166000908152919052206040516107fe81614175565b8154815260018201546020820152600282015460408201526108226003830161434a565b60608201526004820191825461083781614397565b9361084560405195866141ab565b81855286526020808720879186015b8383106109105750505050600590608083019384520190815461087681614397565b9261088460405194856141ab565b81845286526020808720969084015b8282106108f25760806108ba88888860a08901526108b48151518310614703565b5161444b565b5160606040519160018060a01b03815116835260018060a01b0360208201511660208401526040810151604084015201516060820152f35b600760206001926109028b6143ae565b815201980191019096610893565b6004602060019260409b989b5161092681614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190979497610854565b50346105cc5760403660031901126105cc5761099c60043561098561402a565b906109976109928261450d565b6149f2565b614e28565b5080f35b50346105cc5760403660031901126105cc5760043560046109bf61402a565b6001600160a01b03818116808652602084815260408088205490516318160ddd60e01b81529592939192869290918391165afa928315610ad9578593610aa5575b508452600f602052610a1760408520549130614a2f565b82610a5757505050670de0b6b3a7640000915b670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561072c5760206105fc8484614230565b610a6091614290565b670de0b6b3a7640000810290808204670de0b6b3a76400001490151715610a915790610a8b91614230565b91610a2a565b634e487b7160e01b84526011600452602484fd5b9092506020813d602011610ad1575b81610ac1602093836141ab565b8101031261000e57519138610a00565b3d9150610ab4565b6040513d87823e3d90fd5b50346105cc5760203660031901126105cc576020906001600160a01b03610b09614014565b16815260048252604060018060a01b0391205416604051908152f35b50346105cc5760203660031901126105cc576020906040906001600160a01b03610b4d614014565b168152600f83522054604051908152f35b50346105cc5760203660031901126105cc57610b78614014565b610b8061492d565b601480546001600160a01b0319166001600160a01b039290921691909117905580f35b50346105cc5760203660031901126105cc57610bd76040610be392610bc66146c6565b5060043581526007602052206143ae565b60405191829182614089565b0390f35b50346105cc57806003193601126105cc57602090604051908152f35b50346105cc5760203660031901126105cc57600435610c2061492d565b61271081111580610c63575b610c3590614737565b80600b547f2841fef93624d9d474e38055eb5f9d3a6a8c9fdf078b6790af293d5d31225e108480a3600b5580f35b50600b54811415610c2c565b50346105cc5760403660031901126105cc576040610c8b614014565b610c9361402a565b6001600160a01b0391821684526008602090815283852091909216600090815291522060405191610cc383614175565b815483526001820154602084015260028201546040840152610ce76003830161434a565b606084015260048201918254610cfc81614397565b93610d0a60405195866141ab565b81855283526020808420849186015b838310610d8f575050505060808401928352600501805490610d3a82614397565b92610d4860405194856141ab565b82845290815260208082209084015b838310610d71576020868660a08a01525151604051908152f35b60076020600192610d81856143ae565b815201920192019190610d57565b60046020600192604051610da281614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190610d19565b50346105cc5760203660031901126105cc576020906040906001600160a01b03610e06614014565b168152600c83522054604051908152f35b50346105cc5760803660031901126105cc57610e31614014565b6064356001600160a01b0381169190604435906024359084900361053f57610e5761492d565b60405163092d4e2760e21b81526001600160a01b039093166004840181905292602081602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4801561106357611036575b50828552600360205260ff60408620541661100557828552600360205260408520805460ff19166001179055610ed361492d565b8285526003602052610eeb60ff6040872054166140ee565b80151580610ffc575b1561053f5760407fd9fe4a232fa59fb866233bcdccaf84797cdd30506e8fc261699d4daaff18e4cd918493848852600c602052847fe4b65af790442ef39b02e91f9b1e0caf05cb7e3607b3525b51b8d26dc27383826080858b2054838c52600d602052868c2054875191825260208201528587820152846060820152a2848852600c6020528183892055848852600d602052808389205582519182526020820152a280835260046020908152604080852080546001600160a01b03199081166001600160a01b0387161790915584865260059092528420805490911690911790557fb2d8bbd38e8da68edecef6590f2c4977823a30e753091a7822bf5229ebd719778280a280f35b50818110610ef4565b60405162461bcd60e51b815260206004820152600960248201526814dd5c1c1bdc9d195960ba1b6044820152606490fd5b6110579060203d60201161105c575b61104f81836141ab565b810190614419565b610e9f565b503d611045565b6040513d88823e3d90fd5b50346105cc5760203660031901126105cc576020906001600160a01b03611093614014565b16815260058252604060018060a01b0391205416604051908152f35b50346105cc5760403660031901126105cc5760406110cb61402a565b9160043581526001602052209060018060a01b0316600052602052602060ff604060002054166040519015158152f35b50346105cc5760803660031901126105cc57611115614014565b61111d61402a565b90604435916064359081151580920361053f576014546001600160a01b031692338490036112445761118960208660018060a01b03841696878a5260048352858a60018060a01b0360408220541692604051968795869485936323b872dd60e01b85526004850161460e565b03925af180156112395761121c575b506001600160a01b03821686526008602090815260408088206000878152925290209260010361120e57505060125460028201555b6111d8838254614290565b9055808352600f602052604083206111f1838254614290565b90558252600260205261120960408320918254614290565b905580f35b6112179161478a565b6111cd565b6112349060203d60201161105c5761104f81836141ab565b611198565b6040513d89823e3d90fd5b8580fd5b50346105cc57806003193601126105cc57611261614980565b61126961476d565b600160ff198254161781557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586020604051338152a180f35b50346105cc5760403660031901126105cc576112bb614014565b6001600160a01b031680825260036020526040822054602435906112e19060ff166140ee565b6112e961492d565b6127108110156114da57818352600960205260408320805461130a81614397565b9161131860405193846141ab565b81835285526020808620869184015b83831061149c575050505080519060001982019182116114885760209161134d9161444b565b510151818114158061147f575b156114475760405161136b81614190565b838152602081018381526040820190428252858752600960205260408720805490600160401b821015611433576001820180825582101561141f57885260208089209451600390920290940180546001600160a01b0319166001600160a01b03929092169190911781559051600182015590516002919091015560408051948552908401919091528201527f37709c0c7a143f7f128833da302459d5478d74b7775d223b5f77553310a221de90606090a180f35b634e487b7160e01b89526032600452602489fd5b634e487b7160e01b89526041600452602489fd5b60405162461bcd60e51b815260206004820152601060248201526f496e76616c6964206e6577207261746560801b6044820152606490fd5b5081151561135a565b634e487b7160e01b85526011600452602485fd5b600360206001926040516114af81614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190611327565b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c6964207261746560a01b6044820152606490fd5b50346105cc5760409061152036614040565b939161152a6146c6565b506001600160a01b038216845260036020528284205461154c9060ff166140ee565b6001600160a01b03908116845260086020908152838520929091166000908152919052206040519061157d82614175565b8054825260018101546020830152600281015460408301526115a16003820161434a565b60608301526004810180546115b581614397565b916115c360405193846141ab565b81835285526020808620869184015b83831061165b575050505060808301526005018054906115f182614397565b936115ff60405195866141ab565b82855290815260208082209085015b83831061163d57610be361163088886108b460a08a0191808352518310614703565b5160405191829182614089565b6007602060019261164d856143ae565b81520192019201919061160e565b6004602060019260405161166e81614128565b848060a01b038654168152848060a01b0385870154168382015260028601546040820152600386015460608201528152019201920191906115d2565b50346105cc57806003193601126105cc576020600654604051908152f35b50346105cc5760203660031901126105cc5760209060ff906040906001600160a01b036116f3614014565b168152600384522054166040519015158152f35b50346105cc5760803660031901126105cc57611721614014565b61172961402a565b6044356001600160a01b038116919082810361053f57606435906001600160a01b03831690848214611ac0578215611a7b57611765868561445f565b93838510611a4c57338314611a0b5760018060a01b038716808952600460205260018060a01b0360408a20541660206040518092636eb1769f60e11b825281806117b3338960048401614431565b03915afa8015611a005786918b916119cb575b501061199a578089526004602052604089205489906001600160a01b0316803b1561199657816040518092630f75ba2160e41b825281838161180d8d338c6004850161460e565b03925af180156105435761197d575b5052600460205260018060a01b0360408920541691602060405180946323b872dd60e01b8252818c816118548b888a6004850161460e565b03925af1928315611972578880936118759261187a96611953575b5061478a565b61478a565b85526008602052604080862060009060018060a01b03871682526020522091825491604060018501968754968952600860205281892060009160018060a01b031682526020522096670de0b6b3a76400008202918204670de0b6b3a76400000361072c5750611910611940959493670de0b6b3a7640000611909611902611926968396614230565b809361421d565b049561421d565b049261191d818854614290565b875582546141fa565b905560018401611937828254614290565b905582546141fa565b9055600242910155602060405160018152f35b61196b9060203d60201161105c5761104f81836141ab565b503861186f565b6040513d8b823e3d90fd5b81611987916141ab565b61199257883861181c565b8880fd5b5080fd5b60405162461bcd60e51b8152602060048201526009602482015268616c6c6f77616e636560b81b6044820152606490fd5b9150506020813d6020116119f8575b816119e7602093836141ab565b8101031261000e57859051386117c6565b3d91506119da565b6040513d8c823e3d90fd5b60018060a01b0387168852600460205260018060a01b0360408920541691602060405180946323b872dd60e01b8252818c816118548b88336004850161460e565b60405162461bcd60e51b815260206004820152600760248201526662616c616e636560c81b6044820152606490fd5b60405162461bcd60e51b815260206004820152601d60248201527f616d6f756e74206d7573742062652067726561746572207468616e20300000006044820152606490fd5b60405162461bcd60e51b815260206004820152601e60248201527f66726f6d2063616e206e6f742062652073616d652061732074686520746f00006044820152606490fd5b50346105cc5760403660031901126105cc57611b1f614014565b611b2761402a565b90611b3061492d565b60405163092d4e2760e21b81526001600160a01b0390911660048201819052738724d1b62ddf87d830811c9dcb2e1a6494c9c117929091602081602481875af48015610ad957611c63575b5060405163092d4e2760e21b81526001600160a01b0382166004820181905293602090829060249082905af48015610ad957611c46575b506040516370a0823160e01b815230600482015290602082602481865afa908115610ad9578591611c10575b611be99250836148f3565b7ff5b6d8b404f034718f55a370884db03c4e27e9652e2636d4adcd0540d7c4203f8380a380f35b90506020823d602011611c3e575b81611c2b602093836141ab565b8101031261000e57611be9915190611bde565b3d9150611c1e565b611c5e9060203d60201161105c5761104f81836141ab565b611bb2565b611c7b9060203d60201161105c5761104f81836141ab565b611b7b565b50346105cc57806003193601126105cc5760ff60209154166040519015158152f35b50346105cc5760203660031901126105cc57611cbc61407a565b611cc461492d565b6014549060ff8260a81c16151590151591611ce182841415614521565b60ff60a81b191660a883901b60ff60a81b16176014557f84e3667aff0d15c7464eb61e79d9db356389b19a3a5024099a09272a7bf11ce98380a380f35b50346105cc57806003193601126105cc576020600e54604051908152f35b50346105cc5760603660031901126105cc57611d56614014565b60243560443591611d6561492d565b6001600160a01b031680845260036020526040842054909190611d8a9060ff166140ee565b80151580611e0e575b15611e0a57818452600c602052817fe4b65af790442ef39b02e91f9b1e0caf05cb7e3607b3525b51b8d26dc273838260806040872054838852600d60205260408820546040519182526020820152846040820152866060820152a2818452600c60205260408420558252600d602052604082205580f35b8380fd5b50828110611d93565b50346105cc5760403660031901126105cc57611e31614014565b6001600160a01b0316808252600360205260408220546024359190611e589060ff166140ee565b7f6d5c9827c1f410bbb61d3b2a0a34b6b30492d9a1fd38588edca7ec4562ab9c9b8352600160209081526040808520336000908152925290205460ff1615611fc8578115611f98576040516370a0823160e01b8152306004820152602081602481855afa908115611f8d578491611f5b575b508211611f2157600a54611ee99083906001600160a01b0316836148f3565b7f4df7f50f630ac07eef038205b5b9c0c910ce8498aa925abbfcb0e1e674058aa9602060018060a01b03600a5416604051908152a380f35b60405162461bcd60e51b81526020600482015260126024820152714e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b90506020813d602011611f85575b81611f76602093836141ab565b8101031261000e575138611eca565b3d9150611f69565b6040513d86823e3d90fd5b60405162461bcd60e51b815260206004820152600860248201526706d757374203e20360c41b6044820152606490fd5b63e2517d3f60e01b8352336004527f6d5c9827c1f410bbb61d3b2a0a34b6b30492d9a1fd38588edca7ec4562ab9c9b602452604483fd5b50346105cc5760203660031901126105cc5760206105fc61201e614014565b614630565b50346105cc5760403660031901126105cc5760043561204061402a565b9061204961476d565b808352600760205261205d604084206143ae565b60208181015133808752600880845260408089206001600160a01b039094166000818152948652818520938a529185528089208285529094529290912090949192906120ab9060030161434a565b9460608201928351156122825760e08301514210612282576040830151336001600160a01b0390911603612282576120f8906120e884511561455f565b6001600160a01b03168514614595565b848752600760205260408720805460ff19166001179055865b86518110156122715785612125828961444b565b511461213357600101612111565b9091929394958051906000198201918211610566576005926103f26121606121dc97969461216f9461444b565b516103d96003860193846141cc565b60808301928351878a52600260205261218d60408b209182546141fa565b9055855193519060c060a082015191015191604051956121ac87614159565b600187528960208801523360408801526060870152608086015260a085015260c08401524260e08401520161429d565b601354815185916001600160a01b0316803b1561054e576040516317d5759960e31b8152918391839182908490829061221a90338c6004850161460e565b03925af180156105435761225c575b505051916040519081527fdddf48d4d866b99b4e98ab4756d69715555f0445680fe5941715d094c362c0fd60203392a480f35b81612266916141ab565b611e0a578338612229565b506121dc929394955060059061216f565b8780fd5b50346105cc57806003193601126105cc5761229f614980565b805460ff8116156122dd5760ff191681557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa6020604051338152a180f35b638dfc202b60e01b8252600482fd5b50346105cc5760403660031901126105cc576040612308614014565b61231061402a565b6001600160a01b0391821684526008602090815283852091909216600090815291522060405161233f81614175565b8154815260018201546020820152600282015460408201526123636003830161434a565b916060820192835260048101805461237a81614397565b9161238860405193846141ab565b81835286526020808720879184015b8383106124485750505050906005916080840152019081546123b881614397565b926123c660405194856141ab565b81845285526020808620869185015b83831061242a575050505060a001525190604051918291602083016020845282518091526020604085019301915b818110612411575050500390f35b8251845285945060209384019390920191600101612403565b6007602060019261243a856143ae565b8152019201920191906123d5565b6004602060019260405161245b81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612397565b50346105cc5760203660031901126105cc576124b161407a565b6124b961492d565b6014549060ff8260a01c161515901515916124d682841415614521565b60ff60a01b191660a083901b60ff60a01b16176014557f99859612a8514731da8547a1b97ab4654097e36c13fe2c98960ecd00f770747b8380a380f35b50346105cc5760403660031901126105cc5761252d61402a565b336001600160a01b038216036125495761099c90600435614e28565b63334bd91960e11b8252600482fd5b50346105cc5760403660031901126105cc5760049061257561402a565b6001600160a01b03818116808452602085815260408086205490516318160ddd60e01b81529692939192879290918391165afa938415612674578394612640575b508252600f6020526125cd60408320549130614a2f565b836125f757505050506020670de0b6b3a76400006125ee815b60043561421d565b04604051908152f35b61260091614290565b90670de0b6b3a7640000820291808304670de0b6b3a7640000149015171561072c57506125ee61263b602093670de0b6b3a764000093614230565b6125e6565b9093506020813d60201161266c575b8161265c602093836141ab565b8101031261000e575192386125b6565b3d915061264f565b6040513d85823e3d90fd5b50346105cc5760403660031901126105cc57612699614014565b6126a161402a565b9160018060a01b03821681526008602052604080822060009060018060a01b03861682526020522092604051936126d785614175565b8054855260018101546020860152600281015460408601526126fb6003820161434a565b606086015260048101805461270f81614397565b9161271d60405193846141ab565b81835285526020808620869184015b83831061283257505050509060059160808701520193845461274d81614397565b9061275b60405192836141ab565b80825260208201968552602085209685905b8282106128145750505060a082015251926127889190614a2f565b60405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d5575b602090604051908152f35b506020813d602011612800575b816127ef602093836141ab565b8101031261000e57602090516127ca565b3d91506127e2565b604051903d90823e3d90fd5b600760206001926128248c6143ae565b81520199019101909761276d565b6004602060019260405161284581614128565b848060a01b038654168152848060a01b03858701541683820152600286015460408201526003860154606082015281520192019201919061272c565b50346105cc5760403660031901126105cc5761099c6004356128a161402a565b906128ae6109928261450d565b614d99565b50346105cc5760403660031901126105cc5760406128cf614014565b6128d761402a565b6001600160a01b03918216845260086020908152838520919092166000908152915220604051909161290882614175565b82548252600183015460208301526002830154604083015261292c6003840161434a565b60608301526004830192835461294181614397565b9061294f60405192836141ab565b80825260208201958452602084209584905b8282106129d357505050608084015260050180549061297f82614397565b9261298d60405194856141ab565b82845290815260208082209084015b8383106129b5576020858060a089015251604051908152f35b600760206001926129c5856143ae565b81520192019201919061299c565b600460206001926040516129e681614128565b848060a01b038c54168152848060a01b03858d0154168382015260028c0154604082015260038c01546060820152815201980191019096612961565b50346105cc5760203660031901126105cc576020906040906001600160a01b03612a4a614014565b168152600d83522054604051908152f35b50346105cc5760203660031901126105cc5760206105fc60043561450d565b50346105cc57612a8936614040565b929042841115612d205760018060a01b03831682526008602052604080832060009060018060a01b0384168252602052209260405191612ac883614175565b845483526001850154602084015260028501549460408401958652612aef6003820161434a565b6060850152600481018054612b0381614397565b91612b1160405193846141ab565b81835287526020808820889184015b838310612cd1575050505060808501526005018054612b3e81614397565b91612b4c60405193846141ab565b81835286526020808720879184015b838310612cb3575050505060a08401526001600160a01b03811684526009602052604084208054612b8b81614397565b91612b9960405193846141ab565b81835286526020808720879184015b838310612c7557505050508051906000198201918211612c615790612bcc9161444b565b5191849551612c41575b50506020612bed644979cb9e0094959642906141fa565b925191015102020460405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d557602090604051908152f35b644979cb9e00949550612c59602092612bed92614a2f565b959450612bd6565b634e487b7160e01b86526011600452602486fd5b60036020600192604051612c8881614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190612ba8565b60076020600192612cc3856143ae565b815201920192019190612b5b565b60046020600192604051612ce481614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612b20565b60405162461bcd60e51b815260206004820152600c60248201526b496e76616c69642074696d6560a01b6044820152606490fd5b50346105cc5760403660031901126105cc5760206105fc612d73614014565b612d7b61402a565b9061445f565b50346105cc5760403660031901126105cc57612d9b614014565b90612da461402a565b9160408293612db38184614a2f565b6001600160a01b0393841685526008602090815283862092909416600090815291909352206040519290612de684614175565b805484526001810154602085015260028101546040850152612e0a6003820161434a565b6060850152600481018054612e1e81614397565b91612e2c60405193846141ab565b81835284526020808520859184015b838310612f27575050505090600591608086015201928354612e5c81614397565b94612e6a60405196876141ab565b81865283526020808420849187015b838310612f09575050505060a00192835280935b83518051861015612ebb5760019160a0612eaa88612eb39461444b565b51015190614290565b940193612e8d565b509160405192637afbe4f160e01b845260048401526024830152602082604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af490811561280857906127d557602090604051908152f35b60076020600192612f19856143ae565b815201920192019190612e79565b60046020600192604051612f3a81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190612e3b565b50346105cc5760203660031901126105cc576020906040906001600160a01b03612f9e614014565b168152600283522054604051908152f35b50346105cc5760203660031901126105cc57612fc9614014565b612fd161492d565b60405163092d4e2760e21b81526001600160a01b038216600482018190529190602081602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af48015611f8d57613075575b50600a54906001600160a01b0382169083821461053f577f2181541ed844bb663fa1c189300cc64ee66517f8346ea79c074cf61c782f0ed39161306160405192839283614431565b0390a16001600160a01b03191617600a5580f35b61308d9060203d60201161105c5761104f81836141ab565b613019565b50346105cc5760403660031901126105cc5760406130ae614014565b6130b661402a565b6001600160a01b03811684526003602052828420549091906130da9060ff166140ee565b60018060a01b03168352600860205281832060009160018060a01b03168252602052209060405161310a81614175565b82548152600183015460208201526002830154604082015261312e6003840161434a565b60608201526004830192835461314381614397565b9061315160405192836141ab565b80825260208201958552602085209585905b8282106131d557505050608083015260050180549061318182614397565b9361318f60405195866141ab565b82855290815260208082209085015b8383106131b7576020858760a082015251604051908152f35b600760206001926131c7856143ae565b81520192019201919061319e565b600460206001926040516131e881614128565b848060a01b038c54168152848060a01b03858d0154168382015260028c0154604082015260038c01546060820152815201980191019096613163565b50346105cc5760403660031901126105cc5761323e614014565b6001600160a01b0381168083526003602052604083205460243592906132669060ff166140ee565b61326e61476d565b60ff60145460a01c1661370357338452600860205260408085206000908482526020522061329c823361478a565b6132a582614811565b81549160018101928354908715159182613662575b50501561058957600654875260076020528254958781600019810361361d5750505086815460405190637afbe4f160e01b82528860048301526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156105435782916135e8575b509693558054918782555b86156135ab57858852600f6020526040882061334b8482546141fa565b90558588526011602052604088206133648582546141fa565b9055670de0b6b3a76400008702878104670de0b6b3a76400000361056657889161338d91614230565b86825260046020526024602060018060a01b03604085205416604051928380926370a0823160e01b82523360048301525afa908115612674578391613576575b50808211801561356d575b613565575b50868252600460205260408220546001600160a01b0316803b1561054e57604051632770a7eb60e21b81529183918391829084908290613421903360048401614250565b03925af1801561054357613550575b5050600b5461271003612710811161353c5761344f612710918861421d565b04908161346561345f828a6141fa565b96614630565b10613502576134d39361347b60059333896148f3565b8689526002602052604089206134928582546141fa565b9055604051936134a185614159565b60018552876020860152336040860152886060860152608085015260a08401524260c08401524260e08401520161429d565b6040519081527febb065a01aeb84b2b8d3adb2f31a9b004b8ddaba2a4f702240f6f569e49855be60203392a480f35b60405162461bcd60e51b81526020600482015260126024820152716e6f7420656e6f7567682062616c616e636560701b6044820152606490fd5b634e487b7160e01b88526011600452602488fd5b8161355a916141ab565b610589578638613430565b9050386133dd565b508354156133d8565b9250506020823d6020116135a3575b81613592602093836141ab565b8101031261000e57889151386133cd565b3d9150613585565b60405162461bcd60e51b81526020600482015260156024820152746e6f2061737365747320746f20776974686472617760581b6044820152606490fd5b9150506020813d602011613615575b81613604602093836141ab565b8101031261000e5787905138613323565b3d91506135f7565b91979394909382811061363e57506136368282546141fa565b90559261332e565b9094935061364f91898296556141fa565b61365a8183546141fa565b82559161332e565b604051637afbe4f160e01b8152600481019290925260248201529050602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156136f85788916136c6575b5086118015906136bb575b38806132ba565b5060001986146136b4565b90506020813d6020116136f0575b816136e1602093836141ab565b8101031261000e5751386136a9565b3d91506136d4565b6040513d8a823e3d90fd5b60405162461bcd60e51b8152602060048201526019602482015278666c617368207769746864726177206e6f7420656e61626c6560381b6044820152606490fd5b50346105cc5760203660031901126105cc5760043563ffffffff60e01b811680910361199657602090637965db0b60e01b811490811561378a575b506040519015158152f35b6301ffc9a760e01b1490508261377f565b50346105cc5760403660031901126105cc576137b5614014565b6001600160a01b0381168083526003602052604083205460243592906137dd9060ff166140ee565b6137e561476d565b3384526008602052604080852060009084825260205220908154738724d1b62ddf87d830811c9dcb2e1a6494c9c11790604051637afbe4f160e01b8152816004820152866024820152602081604481865af49081156136f8578891613ac2575b50858852600c60205260408820541161058957602090604460405180948193637afbe4f160e01b835260048301528960248301525af4908115611063578691613a90575b50838652600d60205260408620541061053f576138e4906138da6040516323b872dd60e01b60208201526138d4816138c68930336024850161460e565b03601f1981018352826141ab565b85614eae565b610430813361478a565b828552600f602052604085206138fb858254614290565b9055670de0b6b3a76400008402848104670de0b6b3a76400001485151715612c6157859161392891614230565b838252600460205260408220546001600160a01b0316803b1561054e576040516340c10f1960e01b8152918391839182908490829061396b903360048401614250565b03925af1801561054357613a7b575b50506040516004820161398c82614128565b8382526020820133815260408301908682526060840192428452805490600160401b821015613a675760018201808255821015613a535789526020808a209551600292831b90960180546001600160a01b039788166001600160a01b03199182161782559351600182018054919098169416939093179095559151818301559151600390920191909155825485019092558285525260408320805483019055337f99039fcf0a98f484616c5196ee8b2ecfa971babf0b519848289ea4db381f85f78480a480f35b634e487b7160e01b8a52603260045260248afd5b634e487b7160e01b8a52604160045260248afd5b81613a85916141ab565b611e0a57833861397a565b90506020813d602011613aba575b81613aab602093836141ab565b8101031261000e575138613889565b3d9150613a9e565b90506020813d602011613aec575b81613add602093836141ab565b8101031261000e575138613845565b3d9150613ad0565b50346105cc5760403660031901126105cc57613b0e614014565b6001600160a01b038116808352600360205260408320546024359290613b369060ff166140ee565b613b3e61476d565b613b48813361478a565b613b5181614811565b903385526008602052604085208386526020526040852080549260018201938454908715159182613f7e575b505015613f485760065487526007602052604087209386888254986000198114600014613f065750505087835460405190637afbe4f160e01b82528960048301526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4908115610543578291613ed4575b5097915582548884555b60048601918255600386019081558715613e975760065460038501805490600160401b821015613e8357816103d9916001613c3695940181556141cc565b54868952600f602052613c4e60408a209182546141fa565b9055548588526011602052613c68604089209182546141fa565b9055670de0b6b3a76400008602868104670de0b6b3a76400000361353c57613c94889392602492614230565b918684526004602052602060018060a01b03604086205416604051938480926370a0823160e01b82523360048301525afa918215611f8d578492613e4f575b50818311908115613e45575b50613e3d575b50848252600460205260408220546001600160a01b031690813b1561054e578291613d2791604051948580948193632770a7eb60e21b83523360048401614250565b03925af1801561106357613e27575b50613d41908261426b565b6001810180546001600160a01b03191633179055600281018390554260058201819055600e54604051637afbe4f160e01b815260048101929092526024820152602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49485156128085794613df2575b509260066020940155600654918291600183016006557f558f1f0a2c456722ef2cc50e288df74e32ca2e201a9218272de7eb91065150a985604051338152a4604051908152f35b93506020843d602011613e1f575b81613e0d602093836141ab565b8101031261000e579251926006613dab565b3d9150613e00565b94613e3681613d4193976141ab565b9490613d36565b905038613ce5565b9050541538613cdf565b9091506020813d602011613e7b575b81613e6b602093836141ab565b81010312611e0a57519038613cd3565b3d9150613e5e565b634e487b7160e01b8c52604160045260248cfd5b60405162461bcd60e51b81526020600482015260156024820152744e6f2061737365747320746f20776974686472617760581b6044820152606490fd5b90506020813d602011613efe575b81613eef602093836141ab565b81010312611996575138613bee565b3d9150613ee2565b9198909290828110613f265750613f1e8282546141fa565b905590613bf8565b909250613f36918a8294556141fa565b613f418185546141fa565b8455613bf8565b60405162461bcd60e51b815260206004820152600e60248201526d125b9d985b1a5908185b5bdd5b9d60921b6044820152606490fd5b604051637afbe4f160e01b8152600481019290925260248201529050602081604481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af49081156136f8578891613fe2575b508611801590613fd7575b3880613b7d565b506000198614613fd0565b90506020813d60201161400c575b81613ffd602093836141ab565b81010312612282575138613fc5565b3d9150613ff0565b600435906001600160a01b038216820361000e57565b602435906001600160a01b038216820361000e57565b606090600319011261000e576004356001600160a01b038116810361000e57906024356001600160a01b038116810361000e579060443590565b60043590811515820361000e57565b91909160e08061010083019480511515845260018060a01b03602082015116602085015260018060a01b036040820151166040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b156140f557565b60405162461bcd60e51b815260206004820152600b60248201526a155b9cdd5c1c1bdc9d195960aa1b6044820152606490fd5b608081019081106001600160401b0382111761414357604052565b634e487b7160e01b600052604160045260246000fd5b61010081019081106001600160401b0382111761414357604052565b60c081019081106001600160401b0382111761414357604052565b606081019081106001600160401b0382111761414357604052565b90601f801991011681019081106001600160401b0382111761414357604052565b80548210156141e45760005260206000200190600090565b634e487b7160e01b600052603260045260246000fd5b9190820391821161420757565b634e487b7160e01b600052601160045260246000fd5b8181029291811591840414171561420757565b811561423a570490565b634e487b7160e01b600052601260045260246000fd5b6001600160a01b039091168152602081019190915260400190565b8054610100600160a81b03191660089290921b610100600160a81b0316919091179055565b9190820180921161420757565b805490600160401b82101561414357600182018082558210156141e45760069160e09160005260076020600020910201928051151560ff801986541691161784556142f460018060a01b036020830151168561426b565b60408101516001850180546001600160a01b0319166001600160a01b0392909216919091179055606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b906040519182815491828252602082019060005260206000209260005b81811061437e57505061437c925003836141ab565b565b8454835260019485019487945060209093019201614367565b6001600160401b0381116141435760051b60200190565b906040516143bb81614159565b825460ff81161515825260081c6001600160a01b03908116602083015260018401541660408201526002830154606082015260038301546080820152600483015460a0820152600583015460c08201526006929092015460e0830152565b9081602091031261000e5751801515810361000e5790565b6001600160a01b0391821681529116602082015260400190565b80518210156141e45760209160051b010190565b6001600160a01b039091166000818152600360205260409020546144859060ff166140ee565b6000526004602052602060018060a01b0360406000205416916024604051809481936370a0823160e01b835260018060a01b031660048301525afa908115614501576000916144d2575090565b90506020813d6020116144f9575b816144ed602093836141ab565b8101031261000e575190565b3d91506144e0565b6040513d6000823e3d90fd5b600052600160205260016040600020015490565b1561452857565b60405162461bcd60e51b815260206004820152600f60248201526e1b9bdd1a1a5b99c818da185b99d959608a1b6044820152606490fd5b1561456657565b60405162461bcd60e51b815260206004820152600760248201526618db185a5b595960ca1b6044820152606490fd5b1561459c57565b60405162461bcd60e51b815260206004820152600b60248201526a3bb937b733903a37b5b2b760a91b6044820152606490fd5b805480156145f85760001901906145e682826141cc565b8154906000199060031b1b1916905555565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b03918216815291166020820152604081019190915260600190565b60405163092d4e2760e21b81526001600160a01b0390911660048201819052602082602481738724d1b62ddf87d830811c9dcb2e1a6494c9c1175af4908115614501576024926020926146ab575b506040516370a0823160e01b815230600482015292839182905afa908115614501576000916144d2575090565b6146c190833d851161105c5761104f81836141ab565b61467e565b604051906146d382614159565b600060e0838281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b1561470a57565b60405162461bcd60e51b81526020600482015260056024820152640d2dcc8caf60db1b6044820152606490fd5b1561473e57565b60405162461bcd60e51b8152602060048201526007602482015266125b9d985b1a5960ca1b6044820152606490fd5b60ff6000541661477957565b63d93c066560e01b60005260046000fd5b9060018060a01b0382166000526008602052604060002060018060a01b03821660005260205260406000209160008260028501928354614800575b506147d260019130614a2f565b94015542905560018060a01b0316806000526010602052426040600020556000526011602052604060002055565b61480a9250614a2f565b82386147c5565b6001600160a01b039081166000818152600460208181526040928390205492516318160ddd60e01b81529490928592918391165afa918215614501576000926148bf575b5081614869575050670de0b6b3a764000090565b8061489191600052600f60205260406000205490600052601160205260406000205490614290565b90670de0b6b3a7640000820291808304670de0b6b3a76400001490151715614207576148bc91614230565b90565b90916020823d6020116148eb575b816148da602093836141ab565b810103126105cc5750519038614855565b3d91506148cd565b61492861437c939261491a60405194859263a9059cbb60e01b602085015260248401614250565b03601f1981018452836141ab565b614eae565b3360009081527fa6eef7e35abe7026729641147f7915573c7e97b47efa546f5f6e3230263bcb49602052604090205460ff161561496657565b63e2517d3f60e01b60005233600452600060245260446000fd5b3360009081527fb9cbbae02fe941283ec0eefd7b121e3bc7f89fae077b27bdd75a7fd4cf1543a8602052604090205460ff16156149b957565b63e2517d3f60e01b600052336004527f65d7a28e3265b37a6474929f336521b332c1681b933f6cb9f3376673440d862a60245260446000fd5b600081815260016020908152604080832033845290915290205460ff1615614a175750565b63e2517d3f60e01b6000523360045260245260446000fd5b9091906001600160a01b03166000308214614d5b5750600052600860205260408060002060009060018060a01b03851682526020522091604051614a7281614175565b835481526001840154906020810191825260028501549460408201958652614a9c6003820161434a565b6060830152600481018054614ab081614397565b91614abe60405193846141ab565b818352602083019060005260206000206000915b838310614d0c575050505060808301526005018054614af081614397565b91614afe60405193846141ab565b818352602083019060005260206000206000915b838310614cee575050505060a08201525193519051915b60018060a01b031660005260096020526040600020908154614b4a81614397565b92614b5860405194856141ab565b818452602084019060005260206000206000915b838310614cb05750505050815191600019830183811161420757614b90908261444b565b51928215614ca55760408401918383511115600014614bd057505050906148bc93946020614bc4644979cb9e0094426141fa565b92015102020490614290565b60009392939260005b838110614c77575b505b828410614c075750505050906148bc93946020614bc4644979cb9e009451426141fa565b839691929315614c6d57614c29906040614c21898661444b565b5101516141fa565b6000198701878111614207576001916020614c4a644979cb9e00938761444b565b5101518b0202046040614c5d898661444b565b5101519201965b01929190614be3565b9095600190614c64565b6040614c86828596979561444b565b5101518210614c9b5760010193929193614bd9565b9392915038614be1565b506000955050505050565b60036020600192604051614cc381614190565b848060a01b038654168152848601548382015260028601546040820152815201920192019190614b6c565b60076020600192614cfe856143ae565b815201920192019190614b12565b60046020600192604051614d1f81614128565b848060a01b038654168152848060a01b038587015416838201526002860154604082015260038601546060820152815201920192019190614ad2565b929050604060018060a01b03821693848152600f60205220549280600052601060205260406000205490600052601160205260406000205491614b29565b60008181526001602090815260408083206001600160a01b038616845290915290205460ff16614e215760008181526001602081815260408084206001600160a01b0396909616808552959091528220805460ff19169091179055339291907f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d9080a4600190565b5050600090565b60008181526001602090815260408083206001600160a01b038616845290915290205460ff1615614e215760008181526001602090815260408083206001600160a01b0395909516808452949091528120805460ff19169055339291907ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9080a4600190565b906000602091828151910182855af115614501576000513d614f0057506001600160a01b0381163b155b614edf5750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415614ed856fea26469706673582212207e4762669c715cdbd5a4a68f8422d6b23a0e6fabf252bf8692575e8a66c8482f64736f6c634300081c0033

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

000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e00000000000000000000000006740a2b31bc55782e46c2a9d7a32a38905e118c5000000000000000000000000934c775d3004689ea5738fe80f34378f589f190d000000000000000000000000d038213a84a86348d000929c115528ae9ddc11580000000000000000000000000000000000000000000000000000000000127500000000000000000000000000c4a718735f0783e81fdcaa999773199c2d1498d4000000000000000000000000cb60b1d1f6399e2177ef60df7ae9312940a5e5430000000000000000000000000000000000000000000000000000000000000002000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4800000000000000000000000000000000000000000000000000000000000000020000000000000000000000007336c89ff7af86131d336d504e677db0eb338a160000000000000000000000001ee6e93134aee641bdbe470df2417af476bb917f000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000002bc00000000000000000000000000000000000000000000000000000000000002bc0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000098968000000000000000000000000000000000000000000000000000000000009896800000000000000000000000000000000000000000000000000000000000000002ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

-----Decoded View---------------
Arg [0] : _tokens (address[]): 0xdAC17F958D2ee523a2206206994597C13D831ec7,0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _zkTokens (address[]): 0x7336C89fF7AF86131D336d504E677Db0eb338a16,0x1EE6e93134aee641BDBe470Df2417aF476bb917f
Arg [2] : _newRewardRate (uint256[]): 700,700
Arg [3] : _minStakeAmount (uint256[]): 10000000,10000000
Arg [4] : _maxStakeAmount (uint256[]): 115792089237316195423570985008687907853269984665640564039457584007913129639935,115792089237316195423570985008687907853269984665640564039457584007913129639935
Arg [5] : _admin (address): 0x6740a2b31BC55782e46C2a9D7A32A38905E118C5
Arg [6] : _bot (address): 0x934C775d3004689EA5738FE80F34378f589F190D
Arg [7] : _ceffu (address): 0xD038213A84a86348d000929C115528AE9DdC1158
Arg [8] : _waitingTime (uint256): 1209600
Arg [9] : withdrawVaultAddress (address): 0xc4A718735F0783E81FdcAA999773199C2D1498d4
Arg [10] : _airdropAddr (address): 0xcB60b1d1F6399e2177eF60df7aE9312940a5E543

-----Encoded View---------------
26 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000160
Arg [1] : 00000000000000000000000000000000000000000000000000000000000001c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000220
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [4] : 00000000000000000000000000000000000000000000000000000000000002e0
Arg [5] : 0000000000000000000000006740a2b31bc55782e46c2a9d7a32a38905e118c5
Arg [6] : 000000000000000000000000934c775d3004689ea5738fe80f34378f589f190d
Arg [7] : 000000000000000000000000d038213a84a86348d000929c115528ae9ddc1158
Arg [8] : 0000000000000000000000000000000000000000000000000000000000127500
Arg [9] : 000000000000000000000000c4a718735f0783e81fdcaa999773199c2d1498d4
Arg [10] : 000000000000000000000000cb60b1d1f6399e2177ef60df7ae9312940a5e543
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [12] : 000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7
Arg [13] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [14] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [15] : 0000000000000000000000007336c89ff7af86131d336d504e677db0eb338a16
Arg [16] : 0000000000000000000000001ee6e93134aee641bdbe470df2417af476bb917f
Arg [17] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [18] : 00000000000000000000000000000000000000000000000000000000000002bc
Arg [19] : 00000000000000000000000000000000000000000000000000000000000002bc
Arg [20] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [21] : 0000000000000000000000000000000000000000000000000000000000989680
Arg [22] : 0000000000000000000000000000000000000000000000000000000000989680
Arg [23] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [24] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Arg [25] : ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ 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.