false
false
0
Contract Address Details
contract

0xeF335b44D958ae1ea58aCd69Ef59a2545475B9aF

Sponsored: ERAM, a pioneering Central Bank Blockchain. The First Banking Regulatory Blockchain, Licensed by the Central Bank.

ERAM, Central Bank Digital Currency (CBDC) (STABLE COIN)

Overview

ERAM Balance

0 ERAM

ERAM Value

$0.00

Token Holdings

Fetching tokens...

More Info

Private Name Tags

Last Balance Update

Blocks Validated

Sponsored

Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
FarmBooster




Optimization enabled
true
Compiler version
v0.8.10+commit.fc410830




Optimization runs
999999
EVM Version
default




Verified at
2024-07-20T03:42:30.754906Z

Constructor Arguments

0x00000000000000000000000054ba4075ceb2e31ed20e0cc442ea8ca0f3479ccf000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000c35000000000000000000000000000000000000000000000000000000000000186a0

Arg [0] (address) : 0x54ba4075ceb2e31ed20e0cc442ea8ca0f3479ccf
Arg [1] (address) : 0xab387712bead1e4c031977f69230245e3af79a8f
Arg [2] (address) : 0x3a4408e9cfa913e4563ad21101d5e6b11f26ae7a
Arg [3] (uint256) : 3
Arg [4] (uint256) : 50000
Arg [5] (uint256) : 100000

              

contracts/FarmBooster.sol

Sol2uml
new
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import './interfaces/ICakePool.sol';
import './interfaces/IMasterChefV3.sol';
import './libraries/IterateMapping.sol';
import './interfaces/IPancakeV3Pool.sol';

contract FarmBooster is Ownable {
    using IterableMapping for ItMap;

    /// @notice Cake token.
    address public immutable CAKE;
    /// @notice Cake pool.
    address public immutable CAKE_POOL;
    /// @notice MasterChef V3 contract.
    IMasterChefV3 public immutable MASTER_CHEF_V3;

    /// @notice Initialize the totalLockedAmount.
    bool initialization;

    /// @notice Cake Pool total locked cake amount.
    uint256 public totalLockedAmount;

    /// @notice The latest total locked cake amount In CakePool
    uint256 latestTotalLockedAmountInCakePool;

    struct UserLockedInfo {
        bool init;
        uint256 lockedAmount;
    }

    /// @notice Record user lockedAmount in cake pool
    mapping(address => UserLockedInfo) public userLockedInfos;

    /// @notice Maximum allowed boosted position numbers
    uint256 public MAX_BOOST_POSITION;
    /// @notice limit max boost
    uint256 public cA;
    /// @notice include 1e4
    uint256 public constant MIN_CA = 1e4;
    /// @notice include 1e5
    uint256 public constant MAX_CA = 1e5;
    /// @notice cA precision
    uint256 public constant CA_PRECISION = 1e5;
    /// @notice controls difficulties
    uint256 public cB;
    /// @notice not include 0
    uint256 public constant MIN_CB = 0;
    /// @notice include 50
    uint256 public constant MAX_CB = 1e8;
    /// @notice cB precision
    uint256 public constant CB_PRECISION = 1e4;
    /// @notice MCV3 basic boost factor, none boosted user"s boost factor
    uint256 public constant BOOST_PRECISION = 100 * 1e10;
    /// @notice MCV3 Hard limit for maxmium boost factor
    uint256 public constant MAX_BOOST_PRECISION = 200 * 1e10;
    /// @notice Average boost ratio precision
    uint256 public constant BOOST_RATIO_PRECISION = 1e5;
    /// @notice Cake pool BOOST_WEIGHT precision
    uint256 public constant BOOST_WEIGHT_PRECISION = 100 * 1e10; // 100%

    /// @notice Override global cB for special pool pid.
    mapping(uint256 => uint256) public cBOverride;

    /// @notice The whitelist of pools allowed for farm boosting.
    mapping(uint256 => bool) public whiteList;

    /// @notice Record whether the farm booster has been turned on, in order to save gas.
    mapping(uint256 => bool) public everBoosted;

    /// @notice Info of each pool user.
    mapping(address => ItMap) public userInfo;

    event UpdateMaxBoostPosition(uint256 max);
    event UpdateCA(uint256 oldCA, uint256 newCA);
    event UpdateCB(uint256 oldCB, uint256 newCB);
    event UpdateCBOverride(uint256 pid, uint256 oldCB, uint256 newCB);
    event UpdateBoostFarms(uint256 pid, bool status);
    event AdjustTotalLockedAmount(bool down, uint256 amount);
    event ActiveFarmPool(address indexed user, uint256 indexed pid, uint256 indexed tokenId);
    event DeactiveFarmPool(address indexed user, uint256 indexed pid, uint256 indexed tokenId);
    event UpdatePoolBoostMultiplier(
        address indexed user,
        uint256 indexed pid,
        uint256 indexed tokenId,
        uint256 oldMultiplier,
        uint256 newMultiplier
    );
    event UpdateCakePool(
        address indexed user,
        uint256 lockedAmount,
        uint256 lockedDuration,
        uint256 totalLockedAmount,
        uint256 maxLockDuration
    );

    /// @param _cake CAKE token contract address.
    /// @param _cakePool Cake Pool contract address.
    /// @param _v3 MasterChefV3 contract address.
    /// @param _max Maximum allowed boosted farm quantity.
    /// @param _cA Limit max boost.
    /// @param _cB Controls difficulties.
    constructor(address _cake, address _cakePool, IMasterChefV3 _v3, uint256 _max, uint256 _cA, uint256 _cB) {
        require(_max > 0 && _cA >= MIN_CA && _cA <= MAX_CA && _cB > MIN_CB && _cB <= MAX_CB, 'Invalid parameter');
        CAKE = _cake;
        CAKE_POOL = _cakePool;
        MASTER_CHEF_V3 = _v3;
        MAX_BOOST_POSITION = _max;
        cA = _cA;
        cB = _cB;
    }

    /// @notice Checks if the msg.sender is the cake pool.
    modifier onlyCakePool() {
        require(msg.sender == CAKE_POOL, 'Not cake pool');
        _;
    }

    /// @notice Checks if the msg.sender is the MasterChef V3.
    modifier onlyMasterChefV3() {
        require(msg.sender == address(MASTER_CHEF_V3), 'Not MasterChef V3');
        _;
    }

    /// @notice Adjust the totalLockedAmount caused by inaccurate calculations.
    /// @param _down Down or up.
    /// @param _amount The amount need to be adjusted.
    function adjustTotalLockedAmount(bool _down, uint256 _amount) external onlyOwner {
        if (_down) {
            totalLockedAmount -= _amount;
        } else {
            totalLockedAmount += _amount;
        }
        emit AdjustTotalLockedAmount(_down, _amount);
    }

    /// @notice set maximum allowed boosted position numbers.
    /// @param _max MAX_BOOST_POSITION.
    function setMaxBoostPosition(uint256 _max) external onlyOwner {
        require(_max > 0, 'Can not be zero');
        MAX_BOOST_POSITION = _max;
        emit UpdateMaxBoostPosition(_max);
    }

    /// @notice Only allow whitelisted pids for farm boosting.
    /// @param _pid pool id(Masterchef V3 pool).
    /// @param _status farm pool allowed boosted or not.
    function setBoosterFarms(uint256 _pid, bool _status) external onlyOwner {
        if (_status && !everBoosted[_pid]) everBoosted[_pid] = true;
        whiteList[_pid] = _status;
        emit UpdateBoostFarms(_pid, _status);
    }

    /// @notice Limit max boost.
    /// @param _cA Max boost.
    function setCA(uint256 _cA) external onlyOwner {
        require(_cA >= MIN_CA && _cA <= MAX_CA, 'Invalid cA');
        uint256 temp = cA;
        cA = _cA;
        emit UpdateCA(temp, cA);
    }

    /// @notice Controls difficulties.
    /// @param _cB Difficulties.
    function setCB(uint256 _cB) external onlyOwner {
        require(_cB > MIN_CB && _cB <= MAX_CB, 'Invalid cB');
        uint256 temp = cB;
        cB = _cB;
        emit UpdateCB(temp, cB);
    }

    /// @notice Set cBOverride.
    /// @param _pid Pool pid.
    /// @param _cB Difficulties.
    function setCBOverride(uint256 _pid, uint256 _cB) external onlyOwner {
        // Can set cBOverride[pid] 0 when need to remove override value.
        require(_cB <= MAX_CB, 'Invalid cB');
        uint256 temp = cB;
        cBOverride[_pid] = _cB;
        emit UpdateCBOverride(_pid, temp, cB);
    }

    /// @notice Calculate totalLockedAmount and update UserLockedInfo.
    /// @dev This is to fix the totalLockedAmount issue in cake pool.
    /// @param _user User address.
    function updateTotalLockedAmount(address _user) internal {
        uint256 totalLockedAmountInCakePool = ICakePool(CAKE_POOL).totalLockedAmount();
        if (!initialization) {
            // Record the totalLockedAmount as the initial value after setting farm booster contract in cake pool.
            initialization = true;
            totalLockedAmount = totalLockedAmountInCakePool;
            latestTotalLockedAmountInCakePool = totalLockedAmountInCakePool;
        }
        (, , , , , , , , uint256 userLockedAmount) = ICakePool(CAKE_POOL).userInfo(_user);
        UserLockedInfo storage lockedInfo = userLockedInfos[_user];
        if (!lockedInfo.init) {
            lockedInfo.init = true;
            lockedInfo.lockedAmount = userLockedAmount;

            // Deposit cake into cake pool.
            if (totalLockedAmountInCakePool >= latestTotalLockedAmountInCakePool) {
                totalLockedAmount += totalLockedAmountInCakePool - latestTotalLockedAmountInCakePool;
            } else {
                // Withdraw cake from cake pool.
                totalLockedAmount -= latestTotalLockedAmountInCakePool - totalLockedAmountInCakePool;
            }
        } else {
            totalLockedAmount = totalLockedAmount - lockedInfo.lockedAmount + userLockedAmount;
            lockedInfo.lockedAmount = userLockedAmount;
        }
        latestTotalLockedAmountInCakePool = totalLockedAmountInCakePool;
    }

    /// @notice Update UserLockedInfo.
    /// @dev This will update the userLockedAmount for the users who had already locked cake in cake pool.
    /// @param _user User address.
    function updateUserLockedAmount(address _user) internal {
        UserLockedInfo storage lockedInfo = userLockedInfos[_user];
        if (initialization && !lockedInfo.init) {
            (, , , , , , , , uint256 userLockedAmount) = ICakePool(CAKE_POOL).userInfo(_user);
            lockedInfo.init = true;
            lockedInfo.lockedAmount = userLockedAmount;
        }
    }

    /// @notice Cakepool operation(deposit/withdraw) automatically call this function.
    /// @param _user User address.
    /// @param _lockedAmount User locked amount in cake pool.
    /// @param _lockedDuration User locked duration in cake pool.
    /// @param _totalLockedAmount Total locked cake amount in cake pool.
    /// @param _maxLockDuration Maximum locked duration in cake pool.
    function onCakePoolUpdate(
        address _user,
        uint256 _lockedAmount,
        uint256 _lockedDuration,
        uint256 _totalLockedAmount,
        uint256 _maxLockDuration
    ) external onlyCakePool {
        updateTotalLockedAmount(_user);
        ItMap storage itmap = userInfo[_user];
        uint256 length = itmap.keys.length;
        if (length > 0) {
            uint256 avgDuration = avgLockDuration();
            for (uint256 i = 0; i < length; i++) {
                uint256 tokenId = itmap.keys[i];
                (uint128 liquidity, address user, uint256 pid, ) = getUserPositionInfo(tokenId);
                if (_user == user) _updateBoostMultiplier(itmap, user, pid, tokenId, avgDuration, liquidity);
            }
        }
        emit UpdateCakePool(_user, _lockedAmount, _lockedDuration, _totalLockedAmount, _maxLockDuration);
    }

    /// @notice Update user boost multiplier, only for MasterChef V3.
    /// @param _tokenId Token Id of position NFT.
    function updatePositionBoostMultiplier(uint256 _tokenId) external onlyMasterChefV3 returns (uint256 _multiplier) {
        (uint128 liquidity, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);
        // Set default multiplier
        _multiplier = BOOST_PRECISION;
        // In order to save gas, no need to check the farms which have never beed boosted.
        if (everBoosted[pid]) {
            ItMap storage itmap = userInfo[user];
            uint256 prevMultiplier = itmap.data[_tokenId];
            if (prevMultiplier == 0) return BOOST_PRECISION;
            if (!whiteList[pid]) {
                if (itmap.contains(_tokenId)) {
                    itmap.remove(_tokenId);
                    emit DeactiveFarmPool(user, pid, _tokenId);
                }
            } else {
                _multiplier = _boostCalculate(user, pid, avgLockDuration(), uint256(liquidity));
                itmap.insert(_tokenId, _multiplier);
            }
            emit UpdatePoolBoostMultiplier(user, pid, _tokenId, prevMultiplier, _multiplier);
        }
    }

    /// @notice Remove user boost multiplier when user withdraw or butn in MasterChef V3.
    /// @param _user User address.
    /// @param _tokenId Token Id of position NFT.
    /// @param _pid Id of MasterChef V3 farm pool.
    function removeBoostMultiplier(address _user, uint256 _tokenId, uint256 _pid) external onlyMasterChefV3 {
        // In order to save gas, no need to check the farms which have never beed boosted.
        if (everBoosted[_pid]) {
            ItMap storage itmap = userInfo[_user];
            if (itmap.contains(_tokenId)) {
                itmap.remove(_tokenId);
                emit DeactiveFarmPool(_user, _pid, _tokenId);
            }
        }
    }

    /// @notice Active user farm pool.
    /// @param _tokenId Token Id of position NFT.
    function activate(uint256 _tokenId) external {
        (uint128 liquidity, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);
        require(whiteList[pid], 'Not boosted farm pool');
        require(user == msg.sender, 'Not owner');
        ItMap storage itmap = userInfo[user];
        require(!itmap.contains(_tokenId), 'Already boosted');
        require(itmap.keys.length < MAX_BOOST_POSITION, 'Boosted positions reach to MAX');
        updateUserLockedAmount(user);

        _updateBoostMultiplier(itmap, user, pid, _tokenId, avgLockDuration(), uint256(liquidity));

        emit ActiveFarmPool(user, pid, _tokenId);
    }

    /// @notice Deactive user farm pool.
    /// @param _tokenId Token Id of position NFT.
    function deactive(uint256 _tokenId) external {
        ItMap storage itmap = userInfo[msg.sender];
        require(itmap.contains(_tokenId), 'None boost user');

        if (itmap.data[_tokenId] > BOOST_PRECISION) {
            MASTER_CHEF_V3.updateBoostMultiplier(_tokenId, BOOST_PRECISION);
        }
        itmap.remove(_tokenId);

        (, , uint256 pid, ) = getUserPositionInfo(_tokenId);
        emit DeactiveFarmPool(msg.sender, pid, _tokenId);
    }

    /// @param _user user address.
    /// @param _pid pool id.
    /// @param _tokenId token id.
    /// @param _duration cake pool average locked duration.
    /// @param _liquidity position liquidity.
    function _updateBoostMultiplier(
        ItMap storage itmap,
        address _user,
        uint256 _pid,
        uint256 _tokenId,
        uint256 _duration,
        uint256 _liquidity
    ) internal {
        // Used to be boost farm pool and current is not, remove from mapping
        if (!whiteList[_pid]) {
            if (itmap.data[_tokenId] > BOOST_PRECISION) {
                // reset to BOOST_PRECISION
                MASTER_CHEF_V3.updateBoostMultiplier(_tokenId, BOOST_PRECISION);
            }
            itmap.remove(_tokenId);
            emit DeactiveFarmPool(_user, _pid, _tokenId);
            return;
        }

        (, , , uint256 prevMultiplier) = getUserPositionInfo(_tokenId);
        uint256 multiplier = _boostCalculate(_user, _pid, _duration, _liquidity);

        if (multiplier < BOOST_PRECISION) {
            multiplier = BOOST_PRECISION;
        } else if (multiplier > MAX_BOOST_PRECISION) {
            multiplier = MAX_BOOST_PRECISION;
        }

        // Update multiplier to MCV3
        if (multiplier != prevMultiplier) {
            MASTER_CHEF_V3.updateBoostMultiplier(_tokenId, multiplier);
        }
        itmap.insert(_tokenId, multiplier);

        emit UpdatePoolBoostMultiplier(_user, _pid, _tokenId, prevMultiplier, multiplier);
    }

    /// @notice Whether position boosted specific farm pool.
    /// @param _tokenId Token Id of position NFT.
    function isBoostedPool(uint256 _tokenId) external view returns (bool, uint256) {
        (, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);
        return (userInfo[user].contains(_tokenId), pid);
    }

    /// @notice Actived position list.
    /// @param _user user address.
    function activedPositions(address _user) external view returns (uint256[] memory positions) {
        ItMap storage itmap = userInfo[_user];
        if (itmap.keys.length == 0) return positions;

        positions = new uint256[](itmap.keys.length);
        // solidity for-loop not support multiple variables initializae by "," separate.
        for (uint256 index = 0; index < itmap.keys.length; index++) {
            positions[index] = itmap.keys[index];
        }
    }

    function getUserPositionInfo(
        uint256 _tokenId
    ) internal view returns (uint128 liquidity, address user, uint256 pid, uint256 boostMultiplier) {
        (liquidity, , , , , , user, pid, boostMultiplier) = MASTER_CHEF_V3.userPositionInfos(_tokenId);
    }

    /// @notice Anyone can call this function, if you find some guys effectived multiplier is not fair
    /// for other users, just call "updateLiquidity" function in MasterChef V3.
    /// @param _tokenId Token Id of position NFT.
    /// @dev If return value not in range [BOOST_PRECISION, MAX_BOOST_PRECISION]
    /// the actual effectived multiplier will be the close to side boundry value.
    function getUserMultiplier(uint256 _tokenId) external view returns (uint256) {
        (uint128 liquidity, address user, uint256 pid, ) = getUserPositionInfo(_tokenId);
        if (!whiteList[pid]) {
            return BOOST_PRECISION;
        } else {
            return _boostCalculate(user, pid, avgLockDuration(), uint256(liquidity));
        }
    }

    /// @notice Cake pool average locked duration calculator.
    function avgLockDuration() public view returns (uint256) {
        uint256 totalStakedAmount = IERC20(CAKE).balanceOf(CAKE_POOL);

        uint256 pricePerFullShare = ICakePool(CAKE_POOL).getPricePerFullShare();

        uint256 flexibleShares;
        if (totalStakedAmount > totalLockedAmount && pricePerFullShare > 0)
            flexibleShares = ((totalStakedAmount - totalLockedAmount) * 1e18) / pricePerFullShare;
        if (flexibleShares == 0) return 0;

        uint256 originalShares = (totalLockedAmount * 1e18) / pricePerFullShare;
        if (originalShares == 0) return 0;

        uint256 boostedRatio = ((ICakePool(CAKE_POOL).totalShares() - flexibleShares) * BOOST_RATIO_PRECISION) /
            originalShares;
        if (boostedRatio <= BOOST_RATIO_PRECISION) return 0;

        uint256 boostWeight = ICakePool(CAKE_POOL).BOOST_WEIGHT();
        uint256 maxLockDuration = ICakePool(CAKE_POOL).MAX_LOCK_DURATION() * BOOST_RATIO_PRECISION;

        uint256 duration = ((boostedRatio - BOOST_RATIO_PRECISION) * 365 * BOOST_WEIGHT_PRECISION) / boostWeight;
        return duration <= maxLockDuration ? duration : maxLockDuration;
    }

    /// @notice Get the total liquidity.
    /// @dev Will use the smaller value between MasterChefV3 pool totalLiquidity and V3 pool liquidity.
    /// @param _pid pool id(MasterchefV3 pool).
    function _getTotalLiquidity(uint256 _pid) internal view returns (uint256) {
        (, address v3Pool, , , , uint256 totalLiquidity, ) = MASTER_CHEF_V3.poolInfo(_pid);
        uint256 v3PoolLiquidity = IPancakeV3Pool(v3Pool).liquidity();
        if (totalLiquidity > v3PoolLiquidity) {
            totalLiquidity = v3PoolLiquidity;
        }
        return totalLiquidity;
    }

    /// @param _user user address.
    /// @param _pid pool id(MasterchefV3 pool).
    /// @param _duration cake pool average locked duration.
    /// @param _liquidity position liquidity.
    function _boostCalculate(
        address _user,
        uint256 _pid,
        uint256 _duration,
        uint256 _liquidity
    ) internal view returns (uint256) {
        if (_duration == 0) return BOOST_PRECISION;

        uint256 dB = (cA * _liquidity) / CA_PRECISION;
        // dB == 0 means _liquidity close to 0
        if (_liquidity == 0 || dB == 0) return BOOST_PRECISION;

        (, , , , uint256 lockStartTime, uint256 lockEndTime, , , uint256 userLockedAmount) = ICakePool(CAKE_POOL)
            .userInfo(_user);
        if (userLockedAmount == 0 || block.timestamp >= lockEndTime) return BOOST_PRECISION;

        uint256 totalLiquidity = _getTotalLiquidity(_pid);

        uint256 userLockedDuration = (lockEndTime - lockStartTime) / (3600 * 24); // days

        // will use cBOverride[pid] If cBOverride[pid] is greater than 0 , or will use global cB.
        uint256 realCB = cBOverride[_pid] > 0 ? cBOverride[_pid] : cB;

        uint256 aB = (((totalLiquidity * userLockedAmount * userLockedDuration) *
            BOOST_RATIO_PRECISION *
            CB_PRECISION) / realCB) / (totalLockedAmount * _duration);

        // should "*" BOOST_PRECISION
        return ((_liquidity < (dB + aB) ? _liquidity : (dB + aB)) * BOOST_PRECISION) / dB;
    }
}
        

contracts/interfaces/IPancakeV3Pool.sol

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

interface IPancakeV3Pool {
    /// @notice The currently in range liquidity available to the pool
    /// @dev This value has no relationship to the total liquidity across all ticks
    function liquidity() external view returns (uint128);
}
          

@openzeppelin/contracts/utils/Context.sol

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

pragma solidity ^0.8.0;

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

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

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

contracts/interfaces/ICakePool.sol

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

interface ICakePool {
    function userInfo(
        address _user
    ) external view returns (uint256, uint256, uint256, uint256, uint256, uint256, uint256, bool, uint256);

    function getPricePerFullShare() external view returns (uint256);

    function totalLockedAmount() external view returns (uint256);

    function totalShares() external view returns (uint256);

    function BOOST_WEIGHT() external view returns (uint256);

    function MAX_LOCK_DURATION() external view returns (uint256);
}
          

@openzeppelin/contracts/access/Ownable.sol

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

@openzeppelin/contracts/token/ERC20/IERC20.sol

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

contracts/interfaces/IMasterChefV3.sol

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

interface IMasterChefV3 {
    function userPositionInfos(
        uint256 _tokenId
    ) external view returns (uint128, uint128, int24, int24, uint256, uint256, address, uint256, uint256);

    function poolInfo(
        uint256 _pid
    ) external view returns (uint256, address, address, address, uint24, uint256, uint256);

    function getBoostMultiplier(address _user, uint256 _pid) external view returns (uint256);

    function updateBoostMultiplier(uint256 _tokenId, uint256 _newMultiplier) external;
}
          

contracts/libraries/IterateMapping.sol

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

struct ItMap {
    // pid => boost
    mapping(uint256 => uint256) data;
    // pid => index
    mapping(uint256 => uint256) indexs;
    // array of pid
    uint256[] keys;
    // never use it, just for keep compile success.
    uint256 size;
}

library IterableMapping {
    function insert(ItMap storage self, uint256 key, uint256 value) internal {
        uint256 keyIndex = self.indexs[key];
        self.data[key] = value;
        if (keyIndex > 0) return;
        else {
            self.indexs[key] = self.keys.length + 1;
            self.keys.push(key);
            return;
        }
    }

    function remove(ItMap storage self, uint256 key) internal {
        uint256 index = self.indexs[key];
        if (index == 0) return;
        uint256 lastKey = self.keys[self.keys.length - 1];
        if (key != lastKey) {
            self.keys[index - 1] = lastKey;
            self.indexs[lastKey] = index;
        }
        delete self.data[key];
        delete self.indexs[key];
        self.keys.pop();
    }

    function contains(ItMap storage self, uint256 key) internal view returns (bool) {
        return self.indexs[key] > 0;
    }
}
          

Compiler Settings

{"outputSelection":{"*":{"*":["abi","evm.bytecode","evm.deployedBytecode","evm.methodIdentifiers","metadata","storageLayout"],"":["ast"]}},"optimizer":{"runs":999999,"enabled":true},"libraries":{}}
              

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_cake","internalType":"address"},{"type":"address","name":"_cakePool","internalType":"address"},{"type":"address","name":"_v3","internalType":"contract IMasterChefV3"},{"type":"uint256","name":"_max","internalType":"uint256"},{"type":"uint256","name":"_cA","internalType":"uint256"},{"type":"uint256","name":"_cB","internalType":"uint256"}]},{"type":"event","name":"ActiveFarmPool","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"AdjustTotalLockedAmount","inputs":[{"type":"bool","name":"down","internalType":"bool","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DeactiveFarmPool","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true}],"anonymous":false},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"event","name":"UpdateBoostFarms","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":false},{"type":"bool","name":"status","internalType":"bool","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateCA","inputs":[{"type":"uint256","name":"oldCA","internalType":"uint256","indexed":false},{"type":"uint256","name":"newCA","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateCB","inputs":[{"type":"uint256","name":"oldCB","internalType":"uint256","indexed":false},{"type":"uint256","name":"newCB","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateCBOverride","inputs":[{"type":"uint256","name":"pid","internalType":"uint256","indexed":false},{"type":"uint256","name":"oldCB","internalType":"uint256","indexed":false},{"type":"uint256","name":"newCB","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateCakePool","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"lockedAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"lockedDuration","internalType":"uint256","indexed":false},{"type":"uint256","name":"totalLockedAmount","internalType":"uint256","indexed":false},{"type":"uint256","name":"maxLockDuration","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdateMaxBoostPosition","inputs":[{"type":"uint256","name":"max","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"UpdatePoolBoostMultiplier","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"pid","internalType":"uint256","indexed":true},{"type":"uint256","name":"tokenId","internalType":"uint256","indexed":true},{"type":"uint256","name":"oldMultiplier","internalType":"uint256","indexed":false},{"type":"uint256","name":"newMultiplier","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BOOST_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BOOST_RATIO_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BOOST_WEIGHT_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"CAKE","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"CAKE_POOL","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"CA_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"CB_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IMasterChefV3"}],"name":"MASTER_CHEF_V3","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_BOOST_POSITION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_BOOST_PRECISION","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_CA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MAX_CB","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_CA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"MIN_CB","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"activate","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256[]","name":"positions","internalType":"uint256[]"}],"name":"activedPositions","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"adjustTotalLockedAmount","inputs":[{"type":"bool","name":"_down","internalType":"bool"},{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"avgLockDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cA","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cB","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"cBOverride","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"deactive","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"everBoosted","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getUserMultiplier","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"},{"type":"uint256","name":"","internalType":"uint256"}],"name":"isBoostedPool","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"onCakePoolUpdate","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"uint256","name":"_lockedAmount","internalType":"uint256"},{"type":"uint256","name":"_lockedDuration","internalType":"uint256"},{"type":"uint256","name":"_totalLockedAmount","internalType":"uint256"},{"type":"uint256","name":"_maxLockDuration","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"removeBoostMultiplier","inputs":[{"type":"address","name":"_user","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"uint256","name":"_pid","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBoosterFarms","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"bool","name":"_status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCA","inputs":[{"type":"uint256","name":"_cA","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCB","inputs":[{"type":"uint256","name":"_cB","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setCBOverride","inputs":[{"type":"uint256","name":"_pid","internalType":"uint256"},{"type":"uint256","name":"_cB","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setMaxBoostPosition","inputs":[{"type":"uint256","name":"_max","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalLockedAmount","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"_multiplier","internalType":"uint256"}],"name":"updatePositionBoostMultiplier","inputs":[{"type":"uint256","name":"_tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"size","internalType":"uint256"}],"name":"userInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"init","internalType":"bool"},{"type":"uint256","name":"lockedAmount","internalType":"uint256"}],"name":"userLockedInfos","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"whiteList","inputs":[{"type":"uint256","name":"","internalType":"uint256"}]}]
              

Contract Creation Code

0x60e06040523480156200001157600080fd5b5060405162002fc538038062002fc583398101604081905262000034916200015e565b6200003f33620000f5565b6000831180156200005257506127108210155b8015620000625750620186a08211155b80156200006f5750600081115b80156200008057506305f5e1008111155b620000c55760405162461bcd60e51b815260206004820152601160248201527024b73b30b634b2103830b930b6b2ba32b960791b604482015260640160405180910390fd5b6001600160a01b0395861660805293851660a0529190931660c052600492909255600591909155600655620001ce565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6001600160a01b03811681146200015b57600080fd5b50565b60008060008060008060c087890312156200017857600080fd5b8651620001858162000145565b6020880151909650620001988162000145565b6040880151909550620001ab8162000145565b80945050606087015192506080870151915060a087015190509295509295509295565b60805160a05160c051612d496200027c600039600081816103f1015281816106f401528181610ce10152818161157501528181611bc6015281816121c30152818161231601526126a30152600081816105a6015281816108ba0152818161095801528181610a7b01528181610b4201528181610bd90152818161176a01528181611d94015281816120ae015281816123fd015261254101526000818161036701526108e70152612d496000f3fe608060405234801561001057600080fd5b50600436106102c85760003560e01c8063715018a61161017b578063ae69d198116100d8578063cdf7b7171161008c578063e874fdaf11610071578063e874fdaf146105db578063f2fde38b146105ee578063fe19a9041461060157600080fd5b8063cdf7b717146105a1578063e0c5f195146105c857600080fd5b8063c459a9c2116100bd578063c459a9c21461058e578063c61a66e014610566578063cc6db2da1461056f57600080fd5b8063ae69d1981461056f578063b260c42a1461057b57600080fd5b80638abe30031161012f5780639c1ebe63116101145780639c1ebe63146105555780639cc1d7be1461055e578063a817715b1461056657600080fd5b80638abe3003146103455780638da5cb5b1461053757600080fd5b8063810577141161016057806381057714146104ee578063852b7c88146104f75780638a8a6ee01461052457600080fd5b8063715018a6146104d35780637c78dca4146104db57600080fd5b80634ffcbb39116102295780635dd574db116101dd57806369074d64116101c257806369074d641461048957806369b02128146104b35780636cbb37dd146104c057600080fd5b80635dd574db1461044657806363613da91461046957600080fd5b806352fb65311161020e57806352fb6531146103ec5780635c475d42146104135780635c5aaa491461034557600080fd5b80634ffcbb39146103ce578063506328fc146103d957600080fd5b80632707a8111161028057806344e7bf061161026557806344e7bf061461034f5780634ca6ef28146103625780634e986628146103ae57600080fd5b80632707a8111461033d5780632d015aff1461034557600080fd5b80631959a002116102b15780631959a002146102fe5780631e728ac91461032157806325f148731461032a57600080fd5b806305a9f274146102cd5780630dcebf65146102e9575b600080fd5b6102d660015481565b6040519081526020015b60405180910390f35b6102fc6102f73660046127df565b610614565b005b6102d661030c36600461281a565b600a6020526000908152604090206003015481565b6102d660045481565b6102fc6103383660046127df565b6107b5565b6102d661087d565b6102d6620186a081565b6102d661035d3660046127df565b610cc7565b6103897f000000000000000000000000000000000000000000000000000000000000000081565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e0565b6102d66103bc3660046127df565b60076020526000908152604090205481565b6102d66305f5e10081565b6102d66103e73660046127df565b610f01565b6103897f000000000000000000000000000000000000000000000000000000000000000081565b6104366104213660046127df565b60086020526000908152604090205460ff1681565b60405190151581526020016102e0565b6104366104543660046127df565b60096020526000908152604090205460ff1681565b61047c61047736600461281a565b610f6c565b6040516102e0919061283e565b61049c6104973660046127df565b611052565b6040805192151583526020830191909152016102e0565b6102d66501d1a94a200081565b6102fc6104ce3660046127df565b6110a6565b6102fc611167565b6102fc6104e9366004612890565b61117b565b6102d660065481565b61049c61050536600461281a565b6003602052600090815260409020805460019091015460ff9091169082565b6102fc6105323660046128bc565b6111f6565b60005473ffffffffffffffffffffffffffffffffffffffff16610389565b6102d660055481565b6102d6600081565b6102d661271081565b6102d664e8d4a5100081565b6102fc6105893660046127df565b6112c7565b6102fc61059c3660046128ec565b61155d565b6103897f000000000000000000000000000000000000000000000000000000000000000081565b6102fc6105d63660046127df565b6116a5565b6102fc6105e9366004612921565b611752565b6102fc6105fc36600461281a565b611951565b6102fc61060f366004612965565b611a08565b336000908152600a60209081526040808320848452600181019092529091205461069f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f6e6520626f6f73742075736572000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526020829052604090205464e8d4a510001015610766576040517f69746a1d0000000000000000000000000000000000000000000000000000000081526004810183905264e8d4a5100060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561074d57600080fd5b505af1158015610761573d6000803e3d6000fd5b505050505b6107708183611adb565b600061077b83611bbe565b5060405190935085925083915033907f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee590600090a4505050565b6107bd611c76565b6000811180156107d157506305f5e1008111155b610837576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206342000000000000000000000000000000000000000000006044820152606401610696565b600680549082905560408051828152602081018490527fff6a4b972407d470846bd3a5979c60d68807653244cc8d096c4174a76486e71c91015b60405180910390a15050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000008116600483015260009182917f000000000000000000000000000000000000000000000000000000000000000016906370a0823190602401602060405180830381865afa15801561092e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109529190612987565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166377c7b8fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e59190612987565b90506000600154831180156109fa5750600082115b15610a2d578160015484610a0e91906129cf565b610a2090670de0b6b3a76400006129e6565b610a2a9190612a23565b90505b80610a3c576000935050505090565b600082600154670de0b6b3a7640000610a5591906129e6565b610a5f9190612a23565b905080610a7157600094505050505090565b600081620186a0847f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b089190612987565b610b1291906129cf565b610b1c91906129e6565b610b269190612a23565b9050620186a08111610b3e5760009550505050505090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663bc75f4b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcf9190612987565b90506000620186a07f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16634f1bfc9e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c669190612987565b610c7091906129e6565b905060008264e8d4a51000610c88620186a0876129cf565b610c949061016d6129e6565b610c9e91906129e6565b610ca89190612a23565b905081811115610cb85781610cba565b805b9850505050505050505090565b60003373ffffffffffffffffffffffffffffffffffffffff7f00000000000000000000000000000000000000000000000000000000000000001614610d68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f74204d6173746572436865662056330000000000000000000000000000006044820152606401610696565b6000806000610d7685611bbe565b5060008181526009602052604090205464e8d4a510009750929550909350915060ff1615610ef85773ffffffffffffffffffffffffffffffffffffffff82166000908152600a60209081526040808320888452918290529091205480610de7575064e8d4a510009695505050505050565b60008381526008602052604090205460ff16610e6857600087815260018301602052604090205415610e6357610e1d8288611adb565b86838573ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a45b610e9a565b610e8d8484610e7561087d565b886fffffffffffffffffffffffffffffffff16611cf7565b9550610e9a828888611f31565b86838573ffffffffffffffffffffffffffffffffffffffff167f1e0e5eda2403f0a5efd54ab2b1ed4a66a026877e4255695d414a66acb88419e8848a604051610eed929190918252602082015260400190565b60405180910390a450505b5050505b919050565b600080600080610f1085611bbe565b50600081815260086020526040902054929550909350915060ff16610f3e575064e8d4a51000949350505050565b610f638282610f4b61087d565b866fffffffffffffffffffffffffffffffff16611cf7565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a60205260409020600281015460609190610fa45750919050565b600281015467ffffffffffffffff811115610fc157610fc1612a5e565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b50915060005b600282015481101561104b5781600201818154811061101157611011612a8d565b906000526020600020015483828151811061102e5761102e612a8d565b60209081029190910101528061104381612abc565b915050610ff0565b5050919050565b60008060008061106185611bbe565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600a60209081526040808320998352600190990190529690962054151596945050505050565b6110ae611c76565b61271081101580156110c35750620186a08111155b611129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206341000000000000000000000000000000000000000000006044820152606401610696565b600580549082905560408051828152602081018490527f948053d58d4dfed61c0843c01f010e1a4446c65f03d475567102cc64dfe0ecd49101610871565b61116f611c76565b6111796000611f9c565b565b611183611c76565b81156111a657806001600082825461119b91906129cf565b909155506111be9050565b80600160008282546111b89190612af5565b90915550505b604080518315158152602081018390527f17280d1b63dd2c0e7804a31929a7f5bd757e7180eb78e3f51fc60c81614ee9e19101610871565b6111fe611c76565b80801561121a575060008281526009602052604090205460ff16155b1561125757600082815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008281526008602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168415159081179091558251858152918201527fbeef892af000af61e107ef5e9c764acbccd54157fd6c219d241750fb3eca31029101610871565b60008060006112d584611bbe565b50600081815260086020526040902054929550909350915060ff16611356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420626f6f73746564206661726d20706f6f6c00000000000000000000006044820152606401610696565b73ffffffffffffffffffffffffffffffffffffffff821633146113d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610696565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600a60209081526040808320878452600181019092529091205415611472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920626f6f7374656400000000000000000000000000000000006044820152606401610696565b6004546002820154106114e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6f7374656420706f736974696f6e7320726561636820746f204d415800006044820152606401610696565b6114ea83612011565b611511818484886114f961087d565b896fffffffffffffffffffffffffffffffff16612158565b84828473ffffffffffffffffffffffffffffffffffffffff167f9f6398294ee15ad134ab621e36ed4c7385c08a62072b3a197ea358b776062f4160405160405180910390a45050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146115fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f74204d6173746572436865662056330000000000000000000000000000006044820152606401610696565b60008181526009602052604090205460ff16156116a05773ffffffffffffffffffffffffffffffffffffffff83166000908152600a6020908152604080832085845260018101909252909120541561169e576116588184611adb565b82828573ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a45b505b505050565b6116ad611c76565b60008111611717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f43616e206e6f74206265207a65726f00000000000000000000000000000000006044820152606401610696565b60048190556040518181527f2c058e16ebb012296bb27ec12aadec210755e31adf3d342ca8fccde0dbd899a39060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000000000000000000000000000000000000000000016146117f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f742063616b6520706f6f6c000000000000000000000000000000000000006044820152606401610696565b6117fa856123f9565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600a60205260409020600281015480156118e857600061183461087d565b905060005b828110156118e557600084600201828154811061185857611858612a8d565b90600052602060002001549050600080600061187384611bbe565b509250925092508173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff1614156118ce576118ce888383878a886fffffffffffffffffffffffffffffffff16612158565b5050505080806118dd90612abc565b915050611839565b50505b60408051878152602081018790529081018590526060810184905273ffffffffffffffffffffffffffffffffffffffff8816907f4f25e09d2aa19c6510101d1f39a2f36e12ac77e34d234c68920ba710f6d6f1b19060800160405180910390a250505050505050565b611959611c76565b73ffffffffffffffffffffffffffffffffffffffff81166119fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610696565b611a0581611f9c565b50565b611a10611c76565b6305f5e100811115611a7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206342000000000000000000000000000000000000000000006044820152606401610696565b600680546000848152600760209081526040918290208590559254815186815293840183905290830152907fa6a879d52f70ee909a019d4e93c2b17407cfe6a072da32219ad04ab25e15de429060600160405180910390a1505050565b600081815260018301602052604090205480611af657505050565b60028301805460009190611b0c906001906129cf565b81548110611b1c57611b1c612a8d565b90600052602060002001549050808314611b73578060028501611b406001856129cf565b81548110611b5057611b50612a8d565b600091825260208083209091019290925582815260018601909152604090208290555b6000838152602085815260408083208390556001870190915281205560028401805480611ba257611ba2612b0d565b6001900381819060005260206000200160009055905550505050565b6000806000807f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16633b1acf74866040518263ffffffff1660e01b8152600401611c1f91815260200190565b61012060405180830381865afa158015611c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c619190612b6e565b979d919c509a50959850949650505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611179576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610696565b600082611d0a575064e8d4a51000611f29565b6000620186a083600554611d1e91906129e6565b611d289190612a23565b9050821580611d35575080155b15611d485764e8d4a51000915050611f29565b6040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152600091829182917f000000000000000000000000000000000000000000000000000000000000000090911690631959a0029060240161012060405180830381865afa158015611dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e029190612bfe565b9850505096509650505050508060001480611e1d5750814210155b15611e335764e8d4a51000945050505050611f29565b6000611e3e8961269c565b9050600062015180611e5086866129cf565b611e5a9190612a23565b60008b81526007602052604081205491925090611e7957600654611e89565b60008b8152600760205260409020545b905060008a600154611e9b91906129e6565b82612710620186a086611eae8a8a6129e6565b611eb891906129e6565b611ec291906129e6565b611ecc91906129e6565b611ed69190612a23565b611ee09190612a23565b90508764e8d4a51000611ef38383612af5565b8c10611f0857611f03838b612af5565b611f0a565b8b5b611f1491906129e6565b611f1e9190612a23565b985050505050505050505b949350505050565b6000828152600184016020908152604080832054918690529091208290558015611f5b5750505050565b6002840154611f6b906001612af5565b6000848152600180870160209081526040832093909355600290960180549687018155815220909301919091555050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260408120905474010000000000000000000000000000000000000000900460ff1680156120615750805460ff16155b15612154576040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690631959a0029060240161012060405180830381865afa1580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190612bfe565b8a547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178c558b01555050505050505050505b5050565b60008481526008602052604090205460ff166122895760008381526020879052604090205464e8d4a510001015612235576040517f69746a1d0000000000000000000000000000000000000000000000000000000081526004810184905264e8d4a5100060248201527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561221c57600080fd5b505af1158015612230573d6000803e3d6000fd5b505050505b61223f8684611adb565b82848673ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a46123f1565b600061229484611bbe565b935050505060006122a787878686611cf7565b905064e8d4a510008110156122c2575064e8d4a510006122d9565b6501d1a94a20008111156122d957506501d1a94a20005b818114612388576040517f69746a1d00000000000000000000000000000000000000000000000000000000815260048101869052602481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561236f57600080fd5b505af1158015612383573d6000803e3d6000fd5b505050505b612393888683611f31565b84868873ffffffffffffffffffffffffffffffffffffffff167f1e0e5eda2403f0a5efd54ab2b1ed4a66a026877e4255695d414a66acb88419e885856040516123e6929190918252602082015260400190565b60405180910390a450505b505050505050565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff166305a9f2746040518163ffffffff1660e01b8152600401602060405180830381865afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248a9190612987565b60005490915074010000000000000000000000000000000000000000900460ff166124f957600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055600181905560028190555b6040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f000000000000000000000000000000000000000000000000000000000000000090911690631959a0029060240161012060405180830381865afa15801561258b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125af9190612bfe565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526003602052604090208054919a50985060ff16965061266c955050505050505780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558101829055600254831061264d5760025461263190846129cf565b600160008282546126429190612af5565b909155506126949050565b8260025461265b91906129cf565b6001600082825461264291906129cf565b81816001015460015461267f91906129cf565b6126899190612af5565b600190815581018290555b505060025550565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16631526fe27856040518263ffffffff1660e01b81526004016126fc91815260200190565b60e060405180830381865afa158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190612c72565b50955050505092505060008273ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b79190612cf8565b6fffffffffffffffffffffffffffffffff169050808211156127d7578091505b509392505050565b6000602082840312156127f157600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114611a0557600080fd5b60006020828403121561282c57600080fd5b8135612837816127f8565b9392505050565b6020808252825182820181905260009190848201906040850190845b818110156128765783518352928401929184019160010161285a565b50909695505050505050565b8015158114611a0557600080fd5b600080604083850312156128a357600080fd5b82356128ae81612882565b946020939093013593505050565b600080604083850312156128cf57600080fd5b8235915060208301356128e181612882565b809150509250929050565b60008060006060848603121561290157600080fd5b833561290c816127f8565b95602085013595506040909401359392505050565b600080600080600060a0868803121561293957600080fd5b8535612944816127f8565b97602087013597506040870135966060810135965060800135945092505050565b6000806040838503121561297857600080fd5b50508035926020909101359150565b60006020828403121561299957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156129e1576129e16129a0565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612a1e57612a1e6129a0565b500290565b600082612a59577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415612aee57612aee6129a0565b5060010190565b60008219821115612b0857612b086129a0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b80516fffffffffffffffffffffffffffffffff81168114610efc57600080fd5b8051600281900b8114610efc57600080fd5b60008060008060008060008060006101208a8c031215612b8d57600080fd5b612b968a612b3c565b9850612ba460208b01612b3c565b9750612bb260408b01612b5c565b9650612bc060608b01612b5c565b955060808a0151945060a08a0151935060c08a0151612bde816127f8565b8093505060e08a015191506101008a015190509295985092959850929598565b60008060008060008060008060006101208a8c031215612c1d57600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a0151612c5981612882565b809250506101008a015190509295985092959850929598565b600080600080600080600060e0888a031215612c8d57600080fd5b875196506020880151612c9f816127f8565b6040890151909650612cb0816127f8565b6060890151909550612cc1816127f8565b608089015190945062ffffff81168114612cda57600080fd5b8093505060a0880151915060c0880151905092959891949750929550565b600060208284031215612d0a57600080fd5b61283782612b3c56fea2646970667358221220f18f92aacb13690568ed2144cdf67d3a45924f3f0a5f470c7ada15458c118d7e64736f6c634300080a003300000000000000000000000054ba4075ceb2e31ed20e0cc442ea8ca0f3479ccf000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a0000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000c35000000000000000000000000000000000000000000000000000000000000186a0

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106102c85760003560e01c8063715018a61161017b578063ae69d198116100d8578063cdf7b7171161008c578063e874fdaf11610071578063e874fdaf146105db578063f2fde38b146105ee578063fe19a9041461060157600080fd5b8063cdf7b717146105a1578063e0c5f195146105c857600080fd5b8063c459a9c2116100bd578063c459a9c21461058e578063c61a66e014610566578063cc6db2da1461056f57600080fd5b8063ae69d1981461056f578063b260c42a1461057b57600080fd5b80638abe30031161012f5780639c1ebe63116101145780639c1ebe63146105555780639cc1d7be1461055e578063a817715b1461056657600080fd5b80638abe3003146103455780638da5cb5b1461053757600080fd5b8063810577141161016057806381057714146104ee578063852b7c88146104f75780638a8a6ee01461052457600080fd5b8063715018a6146104d35780637c78dca4146104db57600080fd5b80634ffcbb39116102295780635dd574db116101dd57806369074d64116101c257806369074d641461048957806369b02128146104b35780636cbb37dd146104c057600080fd5b80635dd574db1461044657806363613da91461046957600080fd5b806352fb65311161020e57806352fb6531146103ec5780635c475d42146104135780635c5aaa491461034557600080fd5b80634ffcbb39146103ce578063506328fc146103d957600080fd5b80632707a8111161028057806344e7bf061161026557806344e7bf061461034f5780634ca6ef28146103625780634e986628146103ae57600080fd5b80632707a8111461033d5780632d015aff1461034557600080fd5b80631959a002116102b15780631959a002146102fe5780631e728ac91461032157806325f148731461032a57600080fd5b806305a9f274146102cd5780630dcebf65146102e9575b600080fd5b6102d660015481565b6040519081526020015b60405180910390f35b6102fc6102f73660046127df565b610614565b005b6102d661030c36600461281a565b600a6020526000908152604090206003015481565b6102d660045481565b6102fc6103383660046127df565b6107b5565b6102d661087d565b6102d6620186a081565b6102d661035d3660046127df565b610cc7565b6103897f00000000000000000000000054ba4075ceb2e31ed20e0cc442ea8ca0f3479ccf81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016102e0565b6102d66103bc3660046127df565b60076020526000908152604090205481565b6102d66305f5e10081565b6102d66103e73660046127df565b610f01565b6103897f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a81565b6104366104213660046127df565b60086020526000908152604090205460ff1681565b60405190151581526020016102e0565b6104366104543660046127df565b60096020526000908152604090205460ff1681565b61047c61047736600461281a565b610f6c565b6040516102e0919061283e565b61049c6104973660046127df565b611052565b6040805192151583526020830191909152016102e0565b6102d66501d1a94a200081565b6102fc6104ce3660046127df565b6110a6565b6102fc611167565b6102fc6104e9366004612890565b61117b565b6102d660065481565b61049c61050536600461281a565b6003602052600090815260409020805460019091015460ff9091169082565b6102fc6105323660046128bc565b6111f6565b60005473ffffffffffffffffffffffffffffffffffffffff16610389565b6102d660055481565b6102d6600081565b6102d661271081565b6102d664e8d4a5100081565b6102fc6105893660046127df565b6112c7565b6102fc61059c3660046128ec565b61155d565b6103897f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f81565b6102fc6105d63660046127df565b6116a5565b6102fc6105e9366004612921565b611752565b6102fc6105fc36600461281a565b611951565b6102fc61060f366004612965565b611a08565b336000908152600a60209081526040808320848452600181019092529091205461069f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f4e6f6e6520626f6f73742075736572000000000000000000000000000000000060448201526064015b60405180910390fd5b60008281526020829052604090205464e8d4a510001015610766576040517f69746a1d0000000000000000000000000000000000000000000000000000000081526004810183905264e8d4a5100060248201527f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a73ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561074d57600080fd5b505af1158015610761573d6000803e3d6000fd5b505050505b6107708183611adb565b600061077b83611bbe565b5060405190935085925083915033907f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee590600090a4505050565b6107bd611c76565b6000811180156107d157506305f5e1008111155b610837576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206342000000000000000000000000000000000000000000006044820152606401610696565b600680549082905560408051828152602081018490527fff6a4b972407d470846bd3a5979c60d68807653244cc8d096c4174a76486e71c91015b60405180910390a15050565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f8116600483015260009182917f00000000000000000000000054ba4075ceb2e31ed20e0cc442ea8ca0f3479ccf16906370a0823190602401602060405180830381865afa15801561092e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109529190612987565b905060007f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f73ffffffffffffffffffffffffffffffffffffffff166377c7b8fc6040518163ffffffff1660e01b8152600401602060405180830381865afa1580156109c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e59190612987565b90506000600154831180156109fa5750600082115b15610a2d578160015484610a0e91906129cf565b610a2090670de0b6b3a76400006129e6565b610a2a9190612a23565b90505b80610a3c576000935050505090565b600082600154670de0b6b3a7640000610a5591906129e6565b610a5f9190612a23565b905080610a7157600094505050505090565b600081620186a0847f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f73ffffffffffffffffffffffffffffffffffffffff16633a98ef396040518163ffffffff1660e01b8152600401602060405180830381865afa158015610ae4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b089190612987565b610b1291906129cf565b610b1c91906129e6565b610b269190612a23565b9050620186a08111610b3e5760009550505050505090565b60007f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f73ffffffffffffffffffffffffffffffffffffffff1663bc75f4b86040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bab573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610bcf9190612987565b90506000620186a07f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f73ffffffffffffffffffffffffffffffffffffffff16634f1bfc9e6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c42573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c669190612987565b610c7091906129e6565b905060008264e8d4a51000610c88620186a0876129cf565b610c949061016d6129e6565b610c9e91906129e6565b610ca89190612a23565b905081811115610cb85781610cba565b805b9850505050505050505090565b60003373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a1614610d68576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f74204d6173746572436865662056330000000000000000000000000000006044820152606401610696565b6000806000610d7685611bbe565b5060008181526009602052604090205464e8d4a510009750929550909350915060ff1615610ef85773ffffffffffffffffffffffffffffffffffffffff82166000908152600a60209081526040808320888452918290529091205480610de7575064e8d4a510009695505050505050565b60008381526008602052604090205460ff16610e6857600087815260018301602052604090205415610e6357610e1d8288611adb565b86838573ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a45b610e9a565b610e8d8484610e7561087d565b886fffffffffffffffffffffffffffffffff16611cf7565b9550610e9a828888611f31565b86838573ffffffffffffffffffffffffffffffffffffffff167f1e0e5eda2403f0a5efd54ab2b1ed4a66a026877e4255695d414a66acb88419e8848a604051610eed929190918252602082015260400190565b60405180910390a450505b5050505b919050565b600080600080610f1085611bbe565b50600081815260086020526040902054929550909350915060ff16610f3e575064e8d4a51000949350505050565b610f638282610f4b61087d565b866fffffffffffffffffffffffffffffffff16611cf7565b95945050505050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600a60205260409020600281015460609190610fa45750919050565b600281015467ffffffffffffffff811115610fc157610fc1612a5e565b604051908082528060200260200182016040528015610fea578160200160208202803683370190505b50915060005b600282015481101561104b5781600201818154811061101157611011612a8d565b906000526020600020015483828151811061102e5761102e612a8d565b60209081029190910101528061104381612abc565b915050610ff0565b5050919050565b60008060008061106185611bbe565b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600a60209081526040808320998352600190990190529690962054151596945050505050565b6110ae611c76565b61271081101580156110c35750620186a08111155b611129576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206341000000000000000000000000000000000000000000006044820152606401610696565b600580549082905560408051828152602081018490527f948053d58d4dfed61c0843c01f010e1a4446c65f03d475567102cc64dfe0ecd49101610871565b61116f611c76565b6111796000611f9c565b565b611183611c76565b81156111a657806001600082825461119b91906129cf565b909155506111be9050565b80600160008282546111b89190612af5565b90915550505b604080518315158152602081018390527f17280d1b63dd2c0e7804a31929a7f5bd757e7180eb78e3f51fc60c81614ee9e19101610871565b6111fe611c76565b80801561121a575060008281526009602052604090205460ff16155b1561125757600082815260096020526040902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660011790555b60008281526008602090815260409182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00168415159081179091558251858152918201527fbeef892af000af61e107ef5e9c764acbccd54157fd6c219d241750fb3eca31029101610871565b60008060006112d584611bbe565b50600081815260086020526040902054929550909350915060ff16611356576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f7420626f6f73746564206661726d20706f6f6c00000000000000000000006044820152606401610696565b73ffffffffffffffffffffffffffffffffffffffff821633146113d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600960248201527f4e6f74206f776e657200000000000000000000000000000000000000000000006044820152606401610696565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600a60209081526040808320878452600181019092529091205415611472576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f416c726561647920626f6f7374656400000000000000000000000000000000006044820152606401610696565b6004546002820154106114e1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f426f6f7374656420706f736974696f6e7320726561636820746f204d415800006044820152606401610696565b6114ea83612011565b611511818484886114f961087d565b896fffffffffffffffffffffffffffffffff16612158565b84828473ffffffffffffffffffffffffffffffffffffffff167f9f6398294ee15ad134ab621e36ed4c7385c08a62072b3a197ea358b776062f4160405160405180910390a45050505050565b3373ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a16146115fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f4e6f74204d6173746572436865662056330000000000000000000000000000006044820152606401610696565b60008181526009602052604090205460ff16156116a05773ffffffffffffffffffffffffffffffffffffffff83166000908152600a6020908152604080832085845260018101909252909120541561169e576116588184611adb565b82828573ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a45b505b505050565b6116ad611c76565b60008111611717576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f43616e206e6f74206265207a65726f00000000000000000000000000000000006044820152606401610696565b60048190556040518181527f2c058e16ebb012296bb27ec12aadec210755e31adf3d342ca8fccde0dbd899a39060200160405180910390a150565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f16146117f1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f4e6f742063616b6520706f6f6c000000000000000000000000000000000000006044820152606401610696565b6117fa856123f9565b73ffffffffffffffffffffffffffffffffffffffff85166000908152600a60205260409020600281015480156118e857600061183461087d565b905060005b828110156118e557600084600201828154811061185857611858612a8d565b90600052602060002001549050600080600061187384611bbe565b509250925092508173ffffffffffffffffffffffffffffffffffffffff168d73ffffffffffffffffffffffffffffffffffffffff1614156118ce576118ce888383878a886fffffffffffffffffffffffffffffffff16612158565b5050505080806118dd90612abc565b915050611839565b50505b60408051878152602081018790529081018590526060810184905273ffffffffffffffffffffffffffffffffffffffff8816907f4f25e09d2aa19c6510101d1f39a2f36e12ac77e34d234c68920ba710f6d6f1b19060800160405180910390a250505050505050565b611959611c76565b73ffffffffffffffffffffffffffffffffffffffff81166119fc576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610696565b611a0581611f9c565b50565b611a10611c76565b6305f5e100811115611a7e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600a60248201527f496e76616c6964206342000000000000000000000000000000000000000000006044820152606401610696565b600680546000848152600760209081526040918290208590559254815186815293840183905290830152907fa6a879d52f70ee909a019d4e93c2b17407cfe6a072da32219ad04ab25e15de429060600160405180910390a1505050565b600081815260018301602052604090205480611af657505050565b60028301805460009190611b0c906001906129cf565b81548110611b1c57611b1c612a8d565b90600052602060002001549050808314611b73578060028501611b406001856129cf565b81548110611b5057611b50612a8d565b600091825260208083209091019290925582815260018601909152604090208290555b6000838152602085815260408083208390556001870190915281205560028401805480611ba257611ba2612b0d565b6001900381819060005260206000200160009055905550505050565b6000806000807f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a73ffffffffffffffffffffffffffffffffffffffff16633b1acf74866040518263ffffffff1660e01b8152600401611c1f91815260200190565b61012060405180830381865afa158015611c3d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c619190612b6e565b979d919c509a50959850949650505050505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611179576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610696565b600082611d0a575064e8d4a51000611f29565b6000620186a083600554611d1e91906129e6565b611d289190612a23565b9050821580611d35575080155b15611d485764e8d4a51000915050611f29565b6040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8781166004830152600091829182917f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f90911690631959a0029060240161012060405180830381865afa158015611dde573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e029190612bfe565b9850505096509650505050508060001480611e1d5750814210155b15611e335764e8d4a51000945050505050611f29565b6000611e3e8961269c565b9050600062015180611e5086866129cf565b611e5a9190612a23565b60008b81526007602052604081205491925090611e7957600654611e89565b60008b8152600760205260409020545b905060008a600154611e9b91906129e6565b82612710620186a086611eae8a8a6129e6565b611eb891906129e6565b611ec291906129e6565b611ecc91906129e6565b611ed69190612a23565b611ee09190612a23565b90508764e8d4a51000611ef38383612af5565b8c10611f0857611f03838b612af5565b611f0a565b8b5b611f1491906129e6565b611f1e9190612a23565b985050505050505050505b949350505050565b6000828152600184016020908152604080832054918690529091208290558015611f5b5750505050565b6002840154611f6b906001612af5565b6000848152600180870160209081526040832093909355600290960180549687018155815220909301919091555050565b6000805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600360205260408120905474010000000000000000000000000000000000000000900460ff1680156120615750805460ff16155b15612154576040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f90911690631959a0029060240161012060405180830381865afa1580156120f8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061211c9190612bfe565b8a547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081178c558b01555050505050505050505b5050565b60008481526008602052604090205460ff166122895760008381526020879052604090205464e8d4a510001015612235576040517f69746a1d0000000000000000000000000000000000000000000000000000000081526004810184905264e8d4a5100060248201527f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a73ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561221c57600080fd5b505af1158015612230573d6000803e3d6000fd5b505050505b61223f8684611adb565b82848673ffffffffffffffffffffffffffffffffffffffff167f16b057de3e4eecea219e9a906a9d13247edc6d41056cfb9c1d28f71fa02f8ee560405160405180910390a46123f1565b600061229484611bbe565b935050505060006122a787878686611cf7565b905064e8d4a510008110156122c2575064e8d4a510006122d9565b6501d1a94a20008111156122d957506501d1a94a20005b818114612388576040517f69746a1d00000000000000000000000000000000000000000000000000000000815260048101869052602481018290527f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a73ffffffffffffffffffffffffffffffffffffffff16906369746a1d90604401600060405180830381600087803b15801561236f57600080fd5b505af1158015612383573d6000803e3d6000fd5b505050505b612393888683611f31565b84868873ffffffffffffffffffffffffffffffffffffffff167f1e0e5eda2403f0a5efd54ab2b1ed4a66a026877e4255695d414a66acb88419e885856040516123e6929190918252602082015260400190565b60405180910390a450505b505050505050565b60007f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f73ffffffffffffffffffffffffffffffffffffffff166305a9f2746040518163ffffffff1660e01b8152600401602060405180830381865afa158015612466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061248a9190612987565b60005490915074010000000000000000000000000000000000000000900460ff166124f957600080547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1674010000000000000000000000000000000000000000179055600181905560028190555b6040517f1959a00200000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526000917f000000000000000000000000ab387712bead1e4c031977f69230245e3af79a8f90911690631959a0029060240161012060405180830381865afa15801561258b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125af9190612bfe565b73ffffffffffffffffffffffffffffffffffffffff8c1660009081526003602052604090208054919a50985060ff16965061266c955050505050505780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811782558101829055600254831061264d5760025461263190846129cf565b600160008282546126429190612af5565b909155506126949050565b8260025461265b91906129cf565b6001600082825461264291906129cf565b81816001015460015461267f91906129cf565b6126899190612af5565b600190815581018290555b505060025550565b60008060007f0000000000000000000000003a4408e9cfa913e4563ad21101d5e6b11f26ae7a73ffffffffffffffffffffffffffffffffffffffff16631526fe27856040518263ffffffff1660e01b81526004016126fc91815260200190565b60e060405180830381865afa158015612719573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061273d9190612c72565b50955050505092505060008273ffffffffffffffffffffffffffffffffffffffff16631a6865026040518163ffffffff1660e01b8152600401602060405180830381865afa158015612793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127b79190612cf8565b6fffffffffffffffffffffffffffffffff169050808211156127d7578091505b509392505050565b6000602082840312156127f157600080fd5b5035919050565b73ffffffffffffffffffffffffffffffffffffffff81168114611a0557600080fd5b60006020828403121561282c57600080fd5b8135612837816127f8565b9392505050565b6020808252825182820181905260009190848201906040850190845b818110156128765783518352928401929184019160010161285a565b50909695505050505050565b8015158114611a0557600080fd5b600080604083850312156128a357600080fd5b82356128ae81612882565b946020939093013593505050565b600080604083850312156128cf57600080fd5b8235915060208301356128e181612882565b809150509250929050565b60008060006060848603121561290157600080fd5b833561290c816127f8565b95602085013595506040909401359392505050565b600080600080600060a0868803121561293957600080fd5b8535612944816127f8565b97602087013597506040870135966060810135965060800135945092505050565b6000806040838503121561297857600080fd5b50508035926020909101359150565b60006020828403121561299957600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000828210156129e1576129e16129a0565b500390565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0483118215151615612a1e57612a1e6129a0565b500290565b600082612a59577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff821415612aee57612aee6129a0565b5060010190565b60008219821115612b0857612b086129a0565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b80516fffffffffffffffffffffffffffffffff81168114610efc57600080fd5b8051600281900b8114610efc57600080fd5b60008060008060008060008060006101208a8c031215612b8d57600080fd5b612b968a612b3c565b9850612ba460208b01612b3c565b9750612bb260408b01612b5c565b9650612bc060608b01612b5c565b955060808a0151945060a08a0151935060c08a0151612bde816127f8565b8093505060e08a015191506101008a015190509295985092959850929598565b60008060008060008060008060006101208a8c031215612c1d57600080fd5b8951985060208a0151975060408a0151965060608a0151955060808a0151945060a08a0151935060c08a0151925060e08a0151612c5981612882565b809250506101008a015190509295985092959850929598565b600080600080600080600060e0888a031215612c8d57600080fd5b875196506020880151612c9f816127f8565b6040890151909650612cb0816127f8565b6060890151909550612cc1816127f8565b608089015190945062ffffff81168114612cda57600080fd5b8093505060a0880151915060c0880151905092959891949750929550565b600060208284031215612d0a57600080fd5b61283782612b3c56fea2646970667358221220f18f92aacb13690568ed2144cdf67d3a45924f3f0a5f470c7ada15458c118d7e64736f6c634300080a0033