false
false
0

Contract Address Details

0x0CF951123B2d337eB52091bAbe61AfaDfff330b4

Contract Name
SOYLocalFarmV2
Creator
0xc7d98c–7f3521 at 0xc125f7–cb69b1
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
344 Transactions
Transfers
16,380 Transfers
Gas Used
56,444,521
Last Balance Update
16288866
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
SOYLocalFarmV2




Optimization enabled
true
Compiler version
v0.8.18+commit.87f61d96




Optimization runs
200
EVM Version
default




Verified at
2024-09-26T15:34:20.122627Z

Constructor Arguments

0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cee27d0627ce8a81df9b4d7eee0d753b8c2f613

Arg [0] (bool) : false
Arg [1] (address) : 0x1cee27d0627ce8a81df9b4d7eee0d753b8c2f613

              

Contract source code

// SPDX-License-Identifier: No License (None)
pragma solidity 0.8.18;


interface IERC223 {
    function balanceOf(address who) external view returns (uint);
    function transfer(address to, uint value) external;
    function transfer(address to, uint value, bytes memory data) external returns (bool success);
}

abstract contract IERC223Recipient {
    
 struct ERC223TransferInfo
    {
        address token_contract;
        address sender;
        uint256 value;
        bytes   data;
    }
    ERC223TransferInfo private tkn;
    
/**
 * @dev Standard ERC223 function that will handle incoming token transfers.
 *
 * @param _from  Token sender address.
 * @param _value Amount of tokens.
 * @param _data  Transaction metadata.
 */
    function tokenReceived(address _from, uint _value, bytes calldata _data) public virtual;
}


/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the `nonReentrant` modifier
 * available, which can be aplied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 */
contract ReentrancyGuard {
    /// @dev counter to allow mutex lock with only one SSTORE operation
    uint256 private _guardCounter;

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and make it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _guardCounter += 1;
        uint256 localCounter = _guardCounter;
        _;
        require(localCounter == _guardCounter, "ReentrancyGuard: reentrant call");
    }
}

abstract contract RewardsRecipient {
    address public globalFarm;

    function notifyRewardAmount(uint256 reward) external virtual;

    modifier onlyGlobalFarm() {
        require(msg.sender == globalFarm, "Caller is not global Farm contract");
        _;
    }
}


interface ISimplifiedGlobalFarm {
    function mintFarmingReward(address _localFarm) external;
    function getAllocationX1000(address _farm) external view returns (uint256);
    function getRewardPerSecond() external view returns (uint256);
    function rewardMintingAvailable(address _farm) external view returns (bool);
    function farmExists(address _farmAddress) external view returns (bool);
    function owner() external view returns (address);
}

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.0.0, only sets of type `address` (`AddressSet`) and `uint256`
 * (`UintSet`) are supported.
 */
library EnumerableSet {

    struct AddressSet {
        // Storage of set values
        address[] _values;

        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping (address => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        if (!contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) { // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
            // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.

            address lastvalue = set._values[lastIndex];

            // Move the last value to the index where the value to delete is
            set._values[toDeleteIndex] = lastvalue;
            // Update the index for the moved value
            set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns 1-based index of value in the set. O(1).
     */
    function indexOf(AddressSet storage set, address value) internal view returns (uint256) {
        return set._indexes[value];
    }


    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return set._values.length;
    }

   /**
    * @dev Returns the value stored at position `index` in the set. O(1).
    *
    * Note that there are no guarantees on the ordering of values inside the
    * array, and it may change when more values are added or removed.
    *
    * Requirements:
    *
    * - `index` must be strictly less than {length}.
    */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        require(set._values.length > index, "EnumerableSet: index out of bounds");
        return set._values[index];
    }
}

interface ICallistoNFT {
    function ownerOf(uint256 _tokenId) external view returns (address);
    function transfer(address _to, uint256 _tokenId, bytes calldata _data) external returns (bool);
    function silentTransfer(address _to, uint256 _tokenId) external returns (bool);
}

interface IReferralTracker {
    function userFee(address user) external view returns(uint256);   // fee percentage with 2 decimals for particular user 
}

interface ISoyFinancePair {
    function token0() external view returns (address);
    function token1() external view returns (address);
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);

    function mint(address to) external returns (uint liquidity);
    function burn(address to) external returns (uint amount0, uint amount1);
    function swap(uint amount0Out, uint amount1Out, address to, bytes calldata data) external;
}


contract SOYLocalFarmV2 is IERC223Recipient, ReentrancyGuard, RewardsRecipient
{
    using EnumerableSet for EnumerableSet.AddressSet;
    EnumerableSet.AddressSet boostNFTs; // NFT contracts provided bonuses
    IReferralTracker public referralTrackingContract;    // contract to track referrals and pay fee
    uint256 constant MAX_AMOUNT = 1e40; // Prevents accumulatedRewardPerShare from overflowing.
    address public constant BURN_ADDRESS = 0x000000000000000000000000000000000000dEaD;
    // SoyFinance factory contract = 0x9CC7C769eA3B37F1Af0Ad642A268b80dc80754c5 defined in the function pairFor()
    uint256 public insuranceFee;   // fee percentage with 2 decimals will be transferred to insurance fund
    uint256 public burnFee;    // fee percentage with 2 decimals will be burned
    uint256 public totalShares; // effective total shares included bonuses
    address public insuranceAddress;
    IERC223 public rewardsToken;
    address public lpToken;
    uint256 public lastRewardTimestamp;  // Last block number that SOY distribution occurs.
    uint256 public accumulatedRewardPerShare; // Accumulated SOY per share, times 1e18.
    bool public active;

    struct UserInfo {
        uint256 amount;     // How many LP tokens the user has provided.
        uint256 rewardPerSharePaid; // Accumulated SOY per share that was paid
        uint256 bonus;   // percent of bonus applied
        address nft;     // deposited NFT
        uint256 tokenId; // NFT tokenID
    }
    // Info of each user that stakes LP tokens.
    mapping(address => UserInfo) public userInfo;
    mapping(address NFT => uint256 boost) public boostPercentage;  // NFT contract address => boost %
    mapping(address pair => address token) public allowedTokensReceive; // allow to receive tokens from swapping pool
    
    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Withdraw(address indexed user, uint256 amount);
    event EmergencyWithdraw(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);
    event RewardReinvested(address indexed user, uint256 reward);
    event SetInsuranceWallet(address wallet);
    event SetReferralTracking(address refTrack);
    
    

    /* ========== CONSTRUCTOR ========== */

    constructor(
        bool _active,
        address _lpToken // LP token that will be staked in this Local Farm
    )
    {
        active = _active;
        lpToken = _lpToken;
        //test net
        //rewardsToken = IERC223(0x4c20231BCc5dB8D805DB9197C84c8BA8287CbA92);  // Soy token
        //globalFarm = 0x9F66541abc036503Ae074E1E28638b0Cb6165458;
        //insuranceAddress = 0x27d1a09fca4196ef8513aF068277AE96da083F49; // insurance wallet
        //referralTrackingContract = IReferralTracker(0xA3141cB11cfCd7dFEE9211b49627b4FdEa521fc4);
        // main net
        rewardsToken = IERC223(0x9FaE2529863bD691B4A7171bDfCf33C7ebB10a65);  // Soy token
        globalFarm = 0x64Fa36ACD0d13472FD786B03afC9C52aD5FCf023;
        insuranceAddress = 0x27d1a09fca4196ef8513aF068277AE96da083F49; // insurance wallet
        referralTrackingContract = IReferralTracker(0x0A17432e963AD18C280fb4bc6C00c4Ad186051C0);
        insuranceFee = 200; // 2%
        address token0 = ISoyFinancePair(_lpToken).token0();
        address token1 = ISoyFinancePair(_lpToken).token1();
        if (token0 != address(rewardsToken) && token1 != address(rewardsToken)) {
            address pair = pairFor(token0, address(rewardsToken));
            allowedTokensReceive[pair] = token0;
            pair = pairFor(token1, address(rewardsToken));
            allowedTokensReceive[pair] = token1;
        }
    }
    
    modifier onlyOwner() {
        require(owner() == msg.sender, "only owner");
        _;
    }
    
    modifier onlyActive {
        require(active, "The farm is not enabled by owner!");
        _;
    }
    
    function setActive(bool _status) external onlyOwner
    {
        active = _status;
    }
    
    function owner() public view returns(address) {
        return ISimplifiedGlobalFarm(globalFarm).owner();
    }

    /* ========== ERC223 transaction handlers ====== */
    
    // Analogue of deposit() function.
    function tokenReceived(address _from, uint256 _amount, bytes calldata ) public override nonReentrant onlyActive
    {
        if (_from == lpToken || allowedTokensReceive[_from] == msg.sender) return; // allow to receive tokens form pair contract for reinvestment

        require(msg.sender == address(lpToken), "Trying to deposit wrong token");
        uint256 userAmount = userInfo[_from].amount;
        require(userAmount + _amount <= MAX_AMOUNT, 'exceed the top');
        update();
        _payRewards(_from);

        if (_amount > 0) {
            uint256 shares = userAmount * (100 + userInfo[_from].bonus) / 100;
            uint256 newShares = (userAmount + _amount) * (100 + userInfo[_from].bonus) / 100;
            totalShares = totalShares + newShares - shares;
            userInfo[_from].amount += _amount;
        }
        
        emit Staked(_from, _amount);
    }
    
    
    function notifyRewardAmount(uint256 reward) external override
    {
        emit RewardAdded(reward);
    }
    
    function getRewardPerSecond() public view returns (uint256)
    {
        return ISimplifiedGlobalFarm(globalFarm).getRewardPerSecond();
    }
    
    function getAllocationX1000() public view returns (uint256)
    {
        return ISimplifiedGlobalFarm(globalFarm).getAllocationX1000(address(this));
    }
    
    /* ========== Farm Functions ====== */

    // View function to see pending Reward on frontend.
    function pendingReward(address _user) external view returns (uint256 pending) {
        UserInfo storage user = userInfo[_user];
        uint256 _accumulatedRewardPerShare = accumulatedRewardPerShare;
        if (block.timestamp > lastRewardTimestamp && totalShares != 0) {
            uint256 multiplier = block.timestamp - lastRewardTimestamp;
            uint256 _reward = multiplier * getRewardPerSecond() * getAllocationX1000() / 1000;
            _accumulatedRewardPerShare = accumulatedRewardPerShare + (_reward * 1e18 / totalShares);
        }
        uint256 shares = user.amount * (100 + user.bonus) / 100;
        pending = shares * (_accumulatedRewardPerShare - user.rewardPerSharePaid) / 1e18;

        // calculate fees
        uint256 refFee;
        if (address(referralTrackingContract) != address(0)) {
            refFee = referralTrackingContract.userFee(_user); // refFee is percentage with 2 decimals
            refFee = pending * refFee / 10000;  // refFee - amount of fee
        }
        uint256 bFee = pending * burnFee / 10000;  // burn fee amount
        uint256 iFee = pending * insuranceFee / 10000;  // insurance fee amount
        pending = pending - (refFee + iFee + bFee);
    }
    
    

    // Update reward variables of this Local Farm to be up-to-date.
    function update() public {
        ISimplifiedGlobalFarm(globalFarm).mintFarmingReward(address(this));
        if (block.timestamp <= lastRewardTimestamp) {
            return;
        }
       
        if (totalShares == 0) {
            lastRewardTimestamp = block.timestamp;
            return;
        }
        uint256 multiplier = block.timestamp - lastRewardTimestamp;
        
        // This silently calculates "assumed" reward!
        // This function does not take contract's actual balance into account
        // Global Farm and `reward_request` modifier are responsible for keeping this contract
        // stocked with funds to pay actual rewards.
        
        uint256 _reward = multiplier * getRewardPerSecond() * getAllocationX1000() / 1000;
        accumulatedRewardPerShare = accumulatedRewardPerShare + (_reward * 1e18 / totalShares);
        lastRewardTimestamp = block.timestamp;
    }
    

    // Withdraw tokens from STAKING.
    function withdraw(uint256 _amount) public nonReentrant {
        UserInfo storage user = userInfo[msg.sender];
        require(user.amount >= _amount, "withdraw: not good");
        
        update();
        _payRewards(msg.sender);
        if(_amount > 0) {
            uint256 shares = user.amount * (100 + user.bonus) / 100;
            user.amount = user.amount - _amount;
            uint256 newShares = user.amount * (100 + user.bonus) / 100;
            totalShares = totalShares + newShares - shares; // update total shares
            IERC223(lpToken).transfer(msg.sender, _amount);
        }

        emit Withdraw(msg.sender, _amount);
    }

    // Withdraw without caring about rewards. EMERGENCY ONLY.
    function emergencyWithdraw() public nonReentrant {
        UserInfo storage user = userInfo[msg.sender];
        IERC223(lpToken).transfer(msg.sender, user.amount);
        emit EmergencyWithdraw(msg.sender, user.amount);
        uint256 shares = user.amount * (100 + user.bonus) / 100;
        if (totalShares >= shares) totalShares -= shares;
        else totalShares = 0;
        user.amount = 0;
        user.rewardPerSharePaid = 0;
    }
    
    // Special function that allows owner to withdraw remaining unclaimed tokens of inactive farms
    function withdrawInactiveReward() public onlyOwner
    {
        require(!ISimplifiedGlobalFarm(globalFarm).farmExists(address(this)), "Farm must not be active");
        
        rewardsToken.transfer(msg.sender, rewardsToken.balanceOf(address(this)));
    }
    
    function rescueERC20(address token, address to) external onlyOwner {
        require(token != address(rewardsToken), "Reward token is not prone to ERC20 issues");
        require(token != address(lpToken), "LP token is not prone to ERC20 issues");
        
        
        uint256 value = IERC223(token).balanceOf(address(this));
        IERC223(token).transfer(to, value);
    }


    // on received boost NFT
    function onERC721Received(address, address _from, uint256 _tokenId, bytes calldata) external nonReentrant returns(bytes4) {
        require(boostNFTs.contains(msg.sender), "Not a boost NFT");
        UserInfo storage user = userInfo[_from];
        require(user.nft == address(0), "NFT already added");
        update();
        _payRewards(_from);
        user.nft = msg.sender;
        user.bonus = boostPercentage[msg.sender];
        user.tokenId = _tokenId;
        uint256 shares = user.amount * (100 + user.bonus) / 100;
        totalShares = totalShares + shares - user.amount; // update total shares
        return this.onERC721Received.selector;
    }

    // withdraw boost NFT
    function withdrawNFT() external nonReentrant {
        UserInfo storage user = userInfo[msg.sender];
        address nft = user.nft;
        require(nft != address(0), "No NFT");
        user.nft = address(0);
        update();
        _payRewards(msg.sender);
        // reduce shares by bonus
        uint256 shares = user.amount * (100 + user.bonus) / 100;
        totalShares = totalShares + user.amount - shares; // update total shares
        user.bonus = 0;

        ICallistoNFT(nft).silentTransfer(msg.sender, user.tokenId);
    }

    function _payRewards(address _user) internal {
        uint256 pending = _calculateReward(_user);
        if(pending > 0) rewardsToken.transfer(_user, pending);
        emit RewardPaid(_user, pending);
    }

    // calculate pending reward and pay fees
    function _calculateReward(address _user) internal returns(uint256 pending) {
        UserInfo storage user = userInfo[_user];
        uint256 shares = user.amount * (100 + user.bonus) / 100;
        pending = shares * (accumulatedRewardPerShare - user.rewardPerSharePaid) / 1e18;
        if(pending > 0) {
            uint256 refFee;
            if (address(referralTrackingContract) != address(0)) 
                refFee = referralTrackingContract.userFee(_user); // refFee is percentage with 2 decimals
            if (refFee != 0) {
                refFee = pending * refFee / 10000;  // refFee - amount of fee
                bytes memory data = abi.encode(_user);
                rewardsToken.transfer(address(referralTrackingContract), refFee, data);
            }
            uint256 bFee = pending * burnFee / 10000;  // burn fee amount
            if (bFee != 0) rewardsToken.transfer(BURN_ADDRESS, bFee);
            uint256 iFee = pending * insuranceFee / 10000;  // insurance fee amount
            if (iFee != 0) rewardsToken.transfer(insuranceAddress, iFee);
            pending = pending - (refFee + iFee + bFee);
        }
        user.rewardPerSharePaid = accumulatedRewardPerShare;
    }
    
    function setInsuranceWallet(address wallet) external onlyOwner {
        require(wallet != address(0));
        insuranceAddress = wallet;
        emit SetInsuranceWallet(wallet);
    }

    function setReferralTracking(address refTrack) external onlyOwner {
        require(refTrack != address(0));
        referralTrackingContract = IReferralTracker(refTrack);
        emit SetReferralTracking(refTrack);
    }

    // set fees percentage with 2 decimals (i.e. 100 = 1%)  
    function setFees(uint256 _burnFee, uint256 _insuranceFee) external onlyOwner {
        require(_burnFee < 10000 && _insuranceFee < 10000);
        burnFee = _burnFee;
        insuranceFee = _insuranceFee;
    }

    // set boost NFT contract and boost percentage (without decimals). If boost = 0, it will remove NFT contract
    function setBoostNFT(address[] memory contractNFT, uint256[] memory boost) external onlyOwner {
        require(contractNFT.length == boost.length, "wrong length");
        for (uint i=0; i<boost.length; i++) {
            require(contractNFT[i] != address(0), "Zero address");
            if (boost[i] == 0) {
                boostNFTs.remove(contractNFT[i]);
                boostPercentage[contractNFT[i]] = 0;
            } else {
                boostNFTs.add(contractNFT[i]);
                boostPercentage[contractNFT[i]] = boost[i];
            }
        }
    }

    function setGlobalFarm(address _globalFarm) external onlyOwner {
        require(_globalFarm != address(0));
        require(ISimplifiedGlobalFarm(_globalFarm).owner() == msg.sender, "New contract has another owner");
        globalFarm = _globalFarm;
    }

    // returns list of boost NFTs and its boost percentage
    function getBoostNFT() external view returns(address[] memory NFTs, uint256[] memory boosts) {
        uint len = boostNFTs.length();
        NFTs = new address[](len);
        boosts = new uint256[](len);
        for (uint i=0; i<len; i++) {
            NFTs[i] = boostNFTs.at(i);
            boosts[i] = boostPercentage[NFTs[i]];
        }
    }

    // babylonian method (https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Babylonian_method)
    function sqrt(uint y) internal pure returns (uint z) {
        if (y > 3) {
            z = y;
            uint x = y / 2 + 1;
            while (x < z) {
                z = x;
                x = (y / x + x) / 2;
            }
        } else if (y != 0) {
            z = 1;
        }
    }

    // calculate amounts base on available amount of tokenIn
    function calcAmountIn(uint256 availableAmount, uint256 reserveIn) internal pure returns (uint256 amountIn) {
        uint256 d = (1998*1998)*reserveIn*reserveIn + (4000*998)*reserveIn*availableAmount;
        amountIn = (sqrt(d) - 1998*reserveIn) / (2 * 998);
    }

    // calculate amounts In and Out for pairs A and B
    function calcAmounts(uint256 availableAmount, uint256 aI, uint256 aO, uint256 bI, uint256 bO, uint256 pA, uint256 pB) internal pure returns(uint256,uint256,uint256,uint256) {
        uint256 bO1 = bO*pA/pB;
        uint256 c = 998*availableAmount/1000;
        pA = aI + bI + c; // A
        pB = aO*(bI + c) + bO1*(aI + c); // -B
        //bI = aO*bO; // *c // C
        pB = pB /(2*pA);    // -P/2
        c = (aO*bO1) / pA * c;    // Q
        c = pB - sqrt(pB*pB - c); // amount out = -P/2 - Sqrt((P/2)^2 - Q)
       
        // get amounts
        aI = getAmountIn(c,aI,aO);  // amountIn for pair A
        aO = c;    // amountOut for pair A
        c = availableAmount - aI;
        bO = getAmountOut(c,bI,bO);    // amountOut for pair B
        bI = c;    // amountIn for pair B
        return(aI,aO,bI,bO);
    }

    function getAmountOut(uint256 amountIn, uint256 reserveIn, uint256 reserveOut) internal pure returns(uint256 amountOut) {
        uint256 amountInWithFee = amountIn * 998;
        uint256 numerator = amountInWithFee * reserveOut;
        uint256 denominator = (reserveIn * 1000) + amountInWithFee;
        amountOut = numerator / denominator;
    }

    // given an output amount of an asset and pair reserves, returns a required input amount of the other asset
    function getAmountIn(uint amountOut, uint reserveIn, uint reserveOut) internal pure returns (uint amountIn) {
        require(amountOut > 0, "INSUFFICIENT_OUTPUT_AMOUNT");
        uint numerator = reserveIn*amountOut*1000;
        uint denominator = (reserveOut-amountOut)*998;
        amountIn = (numerator / denominator)+1;
    }

    function getReserves(address tokenIn, address tokenOut) internal view returns(uint256 reserveIn, uint256 reserveOut, address pair) {
        pair = pairFor(tokenIn, tokenOut);
        (reserveIn, reserveOut,) = ISoyFinancePair(pair).getReserves();
        require(reserveIn > 0 && reserveOut > 0, "reinvestPools: pair error");
        if (tokenOut < tokenIn) 
            (reserveIn, reserveOut) = (reserveOut, reserveIn);
    }

    // calculates the CREATE2 address for a pair without making any external calls
    function pairFor(address tokenA, address tokenB) internal pure returns (address pair) {
        address factory = 0x9CC7C769eA3B37F1Af0Ad642A268b80dc80754c5;
        (address token0, address token1) = tokenA < tokenB ? (tokenA, tokenB) : (tokenB, tokenA);
        pair = address(uint160(uint256(keccak256(abi.encodePacked(
                hex'ff',
                factory,
                keccak256(abi.encodePacked(token0, token1)),
                hex'e410ea0a25ce340e309f2f0fe9d58d787bb87dd63d02333e8a9a747230f61758' // init code hash
            )))));
    }

    function reinvest() external returns(uint256 rewardReinvested) {
        update();
        uint256 liquidity;
        rewardReinvested = _calculateReward(msg.sender);
        if(rewardReinvested > 0) {
            address token0 = ISoyFinancePair(lpToken).token0();
            address token1 = ISoyFinancePair(lpToken).token1();
            if (token0 == address(rewardsToken)) {
                liquidity = reinvestSoyPool(rewardReinvested, token1);
            } else if (token1 == address(rewardsToken)) {
                liquidity = reinvestSoyPool(rewardReinvested, token0);
            } else {
                liquidity = reinvestPools(rewardReinvested, token0, token1);
            }
            emit RewardReinvested(msg.sender, rewardReinvested);
        }
        if (liquidity > 0) {
            UserInfo storage user = userInfo[msg.sender];
            uint256 userAmount = user.amount;
            uint256 shares = userAmount * (100 + user.bonus) / 100;
            uint256 newShares = (userAmount + liquidity) * (100 + user.bonus) / 100;
            totalShares = totalShares + newShares - shares;
            user.amount = userAmount + liquidity;
            emit Staked(msg.sender, liquidity);            
        }
    }

    function reinvestSoyPool(uint256 reinvestAmount, address tokenOut) internal returns(uint256 liquidity) {
        (uint256 reserveIn, uint256 reserveOut,) = ISoyFinancePair(lpToken).getReserves();
        if (tokenOut < address(rewardsToken)) {
            (reserveIn, reserveOut) = (reserveOut, reserveIn);
        }
        uint256 amountIn = calcAmountIn(reinvestAmount, reserveIn);
        uint256 amountOut = getAmountOut(amountIn, reserveIn, reserveOut);
        // swap Soy to pair token
        swap(address(lpToken), amountIn, amountOut, tokenOut);


        // add liquidity
        amountIn = reinvestAmount - amountIn;
        rewardsToken.transfer(address(lpToken), amountIn);
        IERC223(tokenOut).transfer(address(lpToken), amountOut);
        liquidity = ISoyFinancePair(lpToken).mint(address(this));
    }

    function reinvestPools(uint256 rewardReinvested, address token0, address token1) internal returns(uint256 liquidity) {
        (uint256 pA, uint256 pB, address pair) = getReserves(token0, token1);
        require (pair == address(lpToken), "wrong factory");
        (uint256 aI, uint256 aO, address pairA) = getReserves(address(rewardsToken), token0);
        (uint256 bI, uint256 bO, address pairB) = getReserves(address(rewardsToken), token1);

        // calculate amounts In and Out        
        (aI, aO, bI, bO) = calcAmounts(rewardReinvested, aI, aO, bI, bO, pA, pB);

        // swap Soy to required tokens
        swap(pairA, aI, aO, token0);
        swap(pairB, bI, bO, token1);

        // add liquidity
        IERC223(token0).transfer(address(lpToken), aO);
        IERC223(token1).transfer(address(lpToken), bO);
        liquidity = ISoyFinancePair(lpToken).mint(address(this));
    }

    // swap rewardsToken (SOY) to pair token (tokenOut)
    function swap(address pair, uint256 amountIn, uint256 amountOut, address tokenOut) internal {
        rewardsToken.transfer(pair, amountIn);
        (uint256 amount0Out, uint256 amount1Out) = address(rewardsToken) < tokenOut ? (uint256(0), amountOut) : (amountOut, uint256(0));
        ISoyFinancePair(pair).swap(amount0Out, amount1Out, address(this), new bytes(0));
    }

}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"bool","name":"_active","internalType":"bool"},{"type":"address","name":"_lpToken","internalType":"address"}]},{"type":"event","name":"EmergencyWithdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardAdded","inputs":[{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardPaid","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"RewardReinvested","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"SetInsuranceWallet","inputs":[{"type":"address","name":"wallet","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"SetReferralTracking","inputs":[{"type":"address","name":"refTrack","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Staked","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"Withdraw","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"BURN_ADDRESS","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"accumulatedRewardPerShare","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"active","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"token","internalType":"address"}],"name":"allowedTokensReceive","inputs":[{"type":"address","name":"pair","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"boost","internalType":"uint256"}],"name":"boostPercentage","inputs":[{"type":"address","name":"NFT","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"burnFee","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"emergencyWithdraw","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getAllocationX1000","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address[]","name":"NFTs","internalType":"address[]"},{"type":"uint256[]","name":"boosts","internalType":"uint256[]"}],"name":"getBoostNFT","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardPerSecond","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"globalFarm","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"insuranceAddress","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"insuranceFee","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastRewardTimestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"lpToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyRewardAmount","inputs":[{"type":"uint256","name":"reward","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bytes4","name":"","internalType":"bytes4"}],"name":"onERC721Received","inputs":[{"type":"address","name":"","internalType":"address"},{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_tokenId","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"pending","internalType":"uint256"}],"name":"pendingReward","inputs":[{"type":"address","name":"_user","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IReferralTracker"}],"name":"referralTrackingContract","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"uint256","name":"rewardReinvested","internalType":"uint256"}],"name":"reinvest","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"rescueERC20","inputs":[{"type":"address","name":"token","internalType":"address"},{"type":"address","name":"to","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC223"}],"name":"rewardsToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setActive","inputs":[{"type":"bool","name":"_status","internalType":"bool"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setBoostNFT","inputs":[{"type":"address[]","name":"contractNFT","internalType":"address[]"},{"type":"uint256[]","name":"boost","internalType":"uint256[]"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setFees","inputs":[{"type":"uint256","name":"_burnFee","internalType":"uint256"},{"type":"uint256","name":"_insuranceFee","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setGlobalFarm","inputs":[{"type":"address","name":"_globalFarm","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setInsuranceWallet","inputs":[{"type":"address","name":"wallet","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setReferralTracking","inputs":[{"type":"address","name":"refTrack","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_amount","internalType":"uint256"},{"type":"bytes","name":"","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalShares","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"update","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"rewardPerSharePaid","internalType":"uint256"},{"type":"uint256","name":"bonus","internalType":"uint256"},{"type":"address","name":"nft","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}],"name":"userInfo","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"_amount","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawInactiveReward","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdrawNFT","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x60806040523480156200001157600080fd5b5060405162003a4738038062003a478339810160408190526200003491620003a8565b6011805483151560ff19909116179055600e80546001600160a01b0383166001600160a01b03199182168117909255600d80548216739fae2529863bd691b4a7171bdfcf33c7ebb10a651790556005805482167364fa36acd0d13472fd786b03afc9c52ad5fcf023179055600c805482167327d1a09fca4196ef8513af068277ae96da083f4917905560088054909116730a17432e963ad18c280fb4bc6c00c4ad186051c017905560c860095560408051630dfe168160e01b8152905160009291630dfe16819160048281019260209291908290030181865afa15801562000120573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001469190620003e6565b90506000826001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa15801562000189573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190620001af9190620003e6565b600d549091506001600160a01b03838116911614801590620001df5750600d546001600160a01b03828116911614155b156200027057600d54600090620002019084906001600160a01b03166200027a565b6001600160a01b03818116600090815260146020526040902080546001600160a01b031916868316179055600d5491925062000240918491166200027a565b6001600160a01b03908116600090815260146020526040902080546001600160a01b031916918416919091179055505b505050506200040b565b6000739cc7c769ea3b37f1af0ad642a268b80dc80754c581806001600160a01b0380861690871610620002af578486620002b2565b85855b6040516001600160601b0319606084811b8216602084015283901b1660348201529193509150839060480160405160208183030381529060405280519060200120604051602001620003699291907fff00000000000000000000000000000000000000000000000000000000000000815260609290921b6001600160601b031916600183015260158201527fe410ea0a25ce340e309f2f0fe9d58d787bb87dd63d02333e8a9a747230f61758603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b80516001600160a01b0381168114620003a357600080fd5b919050565b60008060408385031215620003bc57600080fd5b82518015158114620003cd57600080fd5b9150620003dd602084016200038b565b90509250929050565b600060208284031215620003f957600080fd5b62000404826200038b565b9392505050565b61362c806200041b6000396000f3fe608060405234801561001057600080fd5b506004361061021c5760003560e01c80635fcbd28511610125578063d1af0c7d116100ad578063f40f0f521161007c578063f40f0f52146104dd578063f8077fae146104f0578063fccc2813146104f9578063fce589d814610502578063fdb5a03e1461050b57600080fd5b8063d1af0c7d146104a4578063da5b4ee7146104b7578063db2e21bc146104bf578063e8eed972146104c757600080fd5b80638da5cb5b116100f45780638da5cb5b1461046557806397c4fac71461046d578063a2e6204514610476578063acec338a1461047e578063d08e7b691461049157600080fd5b80635fcbd2851461042457806373af2516146104375780638943ec021461044a5780638cb7e27c1461045d57600080fd5b80633a98ef39116101a85780634f3a1ff8116101775780634f3a1ff8146103d057806352313461146103e35780635b158b3c146103f65780635d799f87146104095780635e38c9541461041c57600080fd5b80633a98ef391461036b5780633c6b16ab14610374578063400250dc146103875780634e48ad3a146103b057600080fd5b80631959a002116101ef5780631959a002146102975780631e29653c1461030e5780632401273c146103245780632e1a7d4d1461034f57806336d421951461036257600080fd5b806301bc71131461022157806302fb0c5e146102365780630b78f9c014610258578063150b7a021461026b575b600080fd5b61023461022f366004612f74565b610513565b005b6011546102439060ff1681565b60405190151581526020015b60405180910390f35b610234610266366004612f98565b6105b3565b61027e610279366004613003565b610608565b6040516001600160e01b0319909116815260200161024f565b6102dd6102a5366004612f74565b601260205260009081526040902080546001820154600283015460038401546004909401549293919290916001600160a01b03169085565b604080519586526020860194909452928401919091526001600160a01b03166060830152608082015260a00161024f565b610316610791565b60405190815260200161024f565b600c54610337906001600160a01b031681565b6040516001600160a01b03909116815260200161024f565b61023461035d366004613076565b610803565b61031660105481565b610316600b5481565b610234610382366004613076565b6109d2565b610337610395366004612f74565b6014602052600090815260409020546001600160a01b031681565b6103166103be366004612f74565b60136020526000908152604090205481565b600554610337906001600160a01b031681565b600854610337906001600160a01b031681565b610234610404366004612f74565b610a02565b61023461041736600461308f565b610b28565b610234610d06565b600e54610337906001600160a01b031681565b61023461044536600461319e565b610e86565b610234610458366004613260565b6110a5565b61023461137d565b61033761152c565b61031660095481565b61023461159a565b61023461048c3660046132ca565b611691565b61023461049f366004612f74565b6116d3565b600d54610337906001600160a01b031681565b610316611763565b6102346117ad565b6104cf6118fe565b60405161024f9291906132e7565b6103166104eb366004612f74565b611a54565b610316600f5481565b61033761dead81565b610316600a5481565b610316611c63565b3361051c61152c565b6001600160a01b03161461054b5760405162461bcd60e51b81526004016105429061336b565b60405180910390fd5b6001600160a01b03811661055e57600080fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527f4cc2fbf2911e773499430576cc26e11ebc7a7d9bca28a2456b2040b2e2a5e338906020015b60405180910390a150565b336105bc61152c565b6001600160a01b0316146105e25760405162461bcd60e51b81526004016105429061336b565b612710821080156105f4575061271081105b6105fd57600080fd5b600a91909155600955565b600060016004600082825461061d91906133a5565b9091555050600454610630600633611ed7565b61066e5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081848189bdbdcdd08139195608a1b6044820152606401610542565b6001600160a01b0380871660009081526012602052604090206003810154909116156106d05760405162461bcd60e51b815260206004820152601160248201527013919508185b1c9958591e481859191959607a1b6044820152606401610542565b6106d861159a565b6106e187611efb565b6003810180546001600160a01b03191633908117909155600090815260136020526040812054600283018190556004830188905560649061072290826133a5565b835461072e91906133b8565b61073891906133cf565b9050816000015481600b5461074d91906133a5565b61075791906133f1565b600b5550630a85bd0160e11b92505060045481146107875760405162461bcd60e51b815260040161054290613404565b5095945050505050565b60055460405163389bbbfd60e21b81523060048201526000916001600160a01b03169063e26eeff490602401602060405180830381865afa1580156107da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fe919061343b565b905090565b60016004600082825461081691906133a5565b909155505060045433600090815260126020526040902080548311156108735760405162461bcd60e51b81526020600482015260126024820152711dda5d1a191c985dce881b9bdd0819dbdbd960721b6044820152606401610542565b61087b61159a565b61088433611efb565b821561097757600060648260020154606461089f91906133a5565b83546108ab91906133b8565b6108b591906133cf565b82549091506108c59085906133f1565b825560028201546000906064906108dc90826133a5565b84546108e891906133b8565b6108f291906133cf565b90508181600b5461090391906133a5565b61090d91906133f1565b600b55600e5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906109429033908990600401613454565b600060405180830381600087803b15801561095c57600080fd5b505af1158015610970573d6000803e3d6000fd5b5050505050505b60405183815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a25060045481146109ce5760405162461bcd60e51b815260040161054290613404565b5050565b6040518181527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d906020016105a8565b33610a0b61152c565b6001600160a01b031614610a315760405162461bcd60e51b81526004016105429061336b565b6001600160a01b038116610a4457600080fd5b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab0919061346d565b6001600160a01b031614610b065760405162461bcd60e51b815260206004820152601e60248201527f4e657720636f6e74726163742068617320616e6f74686572206f776e657200006044820152606401610542565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b33610b3161152c565b6001600160a01b031614610b575760405162461bcd60e51b81526004016105429061336b565b600d546001600160a01b0390811690831603610bc75760405162461bcd60e51b815260206004820152602960248201527f52657761726420746f6b656e206973206e6f742070726f6e6520746f2045524360448201526832302069737375657360b81b6064820152608401610542565b600e546001600160a01b0390811690831603610c335760405162461bcd60e51b815260206004820152602560248201527f4c5020746f6b656e206973206e6f742070726f6e6520746f2045524332302069604482015264737375657360d81b6064820152608401610542565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9e919061343b565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb90610ccf9085908590600401613454565b600060405180830381600087803b158015610ce957600080fd5b505af1158015610cfd573d6000803e3d6000fd5b50505050505050565b600160046000828254610d1991906133a5565b909155505060045433600090815260126020526040902060038101546001600160a01b031680610d745760405162461bcd60e51b8152602060048201526006602482015265139bc813919560d21b6044820152606401610542565b6003820180546001600160a01b0319169055610d8e61159a565b610d9733611efb565b6000606483600201546064610dac91906133a5565b8454610db891906133b8565b610dc291906133cf565b9050808360000154600b54610dd791906133a5565b610de191906133f1565b600b5560006002840155600480840154604051633263830f60e21b81526001600160a01b0385169263c98e0c3c92610e1b92339201613454565b6020604051808303816000875af1158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e919061348a565b505050506004548114610e835760405162461bcd60e51b815260040161054290613404565b50565b33610e8f61152c565b6001600160a01b031614610eb55760405162461bcd60e51b81526004016105429061336b565b8051825114610ef55760405162461bcd60e51b815260206004820152600c60248201526b0eee4dedcce40d8cadccee8d60a31b6044820152606401610542565b60005b81518110156110a05760006001600160a01b0316838281518110610f1e57610f1e6134a7565b60200260200101516001600160a01b031603610f6b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606401610542565b818181518110610f7d57610f7d6134a7565b602002602001015160000361100357610fb9838281518110610fa157610fa16134a7565b60200260200101516006611fba90919063ffffffff16565b50600060136000858481518110610fd257610fd26134a7565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555061108e565b611030838281518110611018576110186134a7565b602002602001015160066120fc90919063ffffffff16565b50818181518110611043576110436134a7565b602002602001015160136000858481518110611061576110616134a7565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055505b80611098816134bd565b915050610ef8565b505050565b6001600460008282546110b891906133a5565b909155505060045460115460ff1661111c5760405162461bcd60e51b815260206004820152602160248201527f546865206661726d206973206e6f7420656e61626c6564206279206f776e65726044820152602160f81b6064820152608401610542565b600e546001600160a01b038681169116148061115157506001600160a01b038581166000908152601460205260409020541633145b61135557600e546001600160a01b031633146111af5760405162461bcd60e51b815260206004820152601d60248201527f547279696e6720746f206465706f7369742077726f6e6720746f6b656e0000006044820152606401610542565b6001600160a01b038516600090815260126020526040902054701d6329f1c35ca4bfabb9f56100000000006111e486836133a5565b11156112235760405162461bcd60e51b815260206004820152600e60248201526d06578636565642074686520746f760941b6044820152606401610542565b61122b61159a565b61123486611efb565b8415611310576001600160a01b03861660009081526012602052604081206002015460649061126390826133a5565b61126d90846133b8565b61127791906133cf565b6001600160a01b038816600090815260126020526040812060020154919250906064906112a490826133a5565b6112ae89866133a5565b6112b891906133b8565b6112c291906133cf565b90508181600b546112d391906133a5565b6112dd91906133f1565b600b556001600160a01b038816600090815260126020526040812080548992906113089084906133a5565b909155505050505b856001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8660405161134b91815260200190565b60405180910390a2505b60045481146113765760405162461bcd60e51b815260040161054290613404565b5050505050565b3361138661152c565b6001600160a01b0316146113ac5760405162461bcd60e51b81526004016105429061336b565b600554604051630d18304560e21b81523060048201526001600160a01b0390911690633460c11490602401602060405180830381865afa1580156113f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611418919061348a565b156114655760405162461bcd60e51b815260206004820152601760248201527f4661726d206d757374206e6f74206265206163746976650000000000000000006044820152606401610542565b600d546040516370a0823160e01b81523060048201526001600160a01b039091169063a9059cbb90339083906370a0823190602401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114db919061343b565b6040518363ffffffff1660e01b81526004016114f8929190613454565b600060405180830381600087803b15801561151257600080fd5b505af1158015611526573d6000803e3d6000fd5b50505050565b60055460408051638da5cb5b60e01b815290516000926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fe919061346d565b60055460405163032453f160e51b81523060048201526001600160a01b039091169063648a7e2090602401600060405180830381600087803b1580156115df57600080fd5b505af11580156115f3573d6000803e3d6000fd5b50505050600f54421161160257565b600b546000036116125742600f55565b6000600f544261162291906133f1565b905060006103e8611631610791565b611639611763565b61164390856133b8565b61164d91906133b8565b61165791906133cf565b600b5490915061166f82670de0b6b3a76400006133b8565b61167991906133cf565b60105461168691906133a5565b601055505042600f55565b3361169a61152c565b6001600160a01b0316146116c05760405162461bcd60e51b81526004016105429061336b565b6011805460ff1916911515919091179055565b336116dc61152c565b6001600160a01b0316146117025760405162461bcd60e51b81526004016105429061336b565b6001600160a01b03811661171557600080fd5b600c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f624b5eb8351863c55d945dc0de9319fcb2547eef7e762196fd564d95eb9d44c0906020016105a8565b6005546040805163da5b4ee760e01b815290516000926001600160a01b03169163da5b4ee79160048083019260209291908290030181865afa1580156107da573d6000803e3d6000fd5b6001600460008282546117c091906133a5565b9091555050600480543360008181526012602052604090819020600e548154925163a9059cbb60e01b8152949591946001600160a01b039091169363a9059cbb9361180f939192909101613454565b600060405180830381600087803b15801561182957600080fd5b505af115801561183d573d6000803e3d6000fd5b505082546040519081523392507f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd9695915060200160405180910390a2600060648260020154606461188d91906133a5565b835461189991906133b8565b6118a391906133cf565b905080600b54106118cb5780600b60008282546118c091906133f1565b909155506118d19050565b6000600b555b5060008082556001909101556004548114610e835760405162461bcd60e51b815260040161054290613404565b606080600061190c60065490565b90508067ffffffffffffffff811115611927576119276130c8565b604051908082528060200260200182016040528015611950578160200160208202803683370190505b5092508067ffffffffffffffff81111561196c5761196c6130c8565b604051908082528060200260200182016040528015611995578160200160208202803683370190505b50915060005b81811015611a4e576119ae60068261215f565b8482815181106119c0576119c06134a7565b60200260200101906001600160a01b031690816001600160a01b031681525050601360008583815181106119f6576119f66134a7565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054838281518110611a3157611a316134a7565b602090810291909101015280611a46816134bd565b91505061199b565b50509091565b6001600160a01b0381166000908152601260205260408120601054600f5442118015611a815750600b5415155b15611aff576000600f5442611a9691906133f1565b905060006103e8611aa5610791565b611aad611763565b611ab790856133b8565b611ac191906133b8565b611acb91906133cf565b600b54909150611ae382670de0b6b3a76400006133b8565b611aed91906133cf565b601054611afa91906133a5565b925050505b6000606483600201546064611b1491906133a5565b8454611b2091906133b8565b611b2a91906133cf565b9050670de0b6b3a7640000836001015483611b4591906133f1565b611b4f90836133b8565b611b5991906133cf565b6008549094506000906001600160a01b031615611bfa576008546040516356c5f34960e01b81526001600160a01b038881166004830152909116906356c5f34990602401602060405180830381865afa158015611bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bde919061343b565b9050612710611bed82876133b8565b611bf791906133cf565b90505b6000612710600a5487611c0d91906133b8565b611c1791906133cf565b9050600061271060095488611c2c91906133b8565b611c3691906133cf565b905081611c4382856133a5565b611c4d91906133a5565b611c5790886133f1565b98975050505050505050565b6000611c6d61159a565b6000611c78336121ee565b91508115611df957600e5460408051630dfe168160e01b815290516000926001600160a01b031691630dfe16819160048083019260209291908290030181865afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee919061346d565b90506000600e60009054906101000a90046001600160a01b03166001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d69919061346d565b600d549091506001600160a01b0390811690831603611d9357611d8c8482612501565b9250611dc1565b600d546001600160a01b0390811690821603611db357611d8c8483612501565b611dbe84838361272f565b92505b60405184815233907f7fc89d3ed4e23fda6ebcec646a642fe679e98dfc053a073434dfaf6ec6f4ed6f9060200160405180910390a250505b8015611ed3573360009081526012602052604081208054600282015491929091606490611e2690826133a5565b611e3090846133b8565b611e3a91906133cf565b90506000606484600201546064611e5191906133a5565b611e5b87866133a5565b611e6591906133b8565b611e6f91906133cf565b90508181600b54611e8091906133a5565b611e8a91906133f1565b600b55611e9785846133a5565b845560405185815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9060200160405180910390a2505050505b5090565b6001600160a01b038116600090815260018301602052604090205415155b92915050565b6000611f06826121ee565b90508015611f7357600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611f409085908590600401613454565b600060405180830381600087803b158015611f5a57600080fd5b505af1158015611f6e573d6000803e3d6000fd5b505050505b816001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048682604051611fae91815260200190565b60405180910390a25050565b6001600160a01b038116600090815260018301602052604081205480156120f2576000611fe86001836133f1565b8554909150600090611ffc906001906133f1565b90506000866000018281548110612015576120156134a7565b60009182526020909120015487546001600160a01b0390911691508190889085908110612044576120446134a7565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556120788360016133a5565b6001600160a01b038216600090815260018901602052604090205586548790806120a4576120a46134d6565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220919091559450611ef59350505050565b6000915050611ef5565b60006121088383611ed7565b61215757508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611ef5565b506000611ef5565b815460009082106121bd5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610542565b8260000182815481106121d2576121d26134a7565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b03811660009081526012602052604081206002810154829060649061221a90826133a5565b835461222691906133b8565b61223091906133cf565b9050670de0b6b3a7640000826001015460105461224d91906133f1565b61225790836133b8565b61226191906133cf565b925082156124f2576008546000906001600160a01b0316156122ee576008546040516356c5f34960e01b81526001600160a01b038781166004830152909116906356c5f34990602401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb919061343b565b90505b80156123b35761271061230182866133b8565b61230b91906133cf565b604080516001600160a01b03881660208201529192506000910160408051601f1981840301815290829052600d54600854635f22feb160e11b84529193506001600160a01b039081169263be45fd629261236d92169086908690600401613532565b6020604051808303816000875af115801561238c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b0919061348a565b50505b6000612710600a54866123c691906133b8565b6123d091906133cf565b9050801561243f57600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061240c9061dead908590600401613454565b600060405180830381600087803b15801561242657600080fd5b505af115801561243a573d6000803e3d6000fd5b505050505b60006127106009548761245291906133b8565b61245c91906133cf565b905080156124cd57600d54600c5460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb9261249a929116908590600401613454565b600060405180830381600087803b1580156124b457600080fd5b505af11580156124c8573d6000803e3d6000fd5b505050505b816124d882856133a5565b6124e291906133a5565b6124ec90876133f1565b95505050505b50601054600190910155919050565b6000806000600e60009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612559573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257d9190613579565b50600d546001600160701b039283169450911691506001600160a01b0390811690851610156125a857905b60006125b48684612967565b905060006125c38285856129da565b600e549091506125de906001600160a01b0316838389612a1e565b6125e882886133f1565b600d54600e5460405163a9059cbb60e01b81529294506001600160a01b039182169263a9059cbb926126209216908690600401613454565b600060405180830381600087803b15801561263a57600080fd5b505af115801561264e573d6000803e3d6000fd5b5050600e5460405163a9059cbb60e01b81526001600160a01b03808b16945063a9059cbb93506126849216908590600401613454565b600060405180830381600087803b15801561269e57600080fd5b505af11580156126b2573d6000803e3d6000fd5b5050600e546040516335313c2160e11b81523060048201526001600160a01b039091169250636a62784291506024016020604051808303816000875af1158015612700573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612724919061343b565b979650505050505050565b60008060008061273f8686612b26565b600e5492955090935091506001600160a01b038083169116146127945760405162461bcd60e51b815260206004820152600d60248201526c77726f6e6720666163746f727960981b6044820152606401610542565b600d54600090819081906127b1906001600160a01b03168a612b26565b600d549295509093509150600090819081906127d6906001600160a01b03168c612b26565b9250925092506127eb8d878786868e8e612c2a565b929850909650935091506128018487878f612a1e565b61280d8184848e612a1e565b600e5460405163a9059cbb60e01b81526001600160a01b038e81169263a9059cbb9261284192909116908990600401613454565b600060405180830381600087803b15801561285b57600080fd5b505af115801561286f573d6000803e3d6000fd5b505050508a6001600160a01b031663a9059cbb600e60009054906101000a90046001600160a01b0316846040518363ffffffff1660e01b81526004016128b6929190613454565b600060405180830381600087803b1580156128d057600080fd5b505af11580156128e4573d6000803e3d6000fd5b5050600e546040516335313c2160e11b81523060048201526001600160a01b039091169250636a62784291506024016020604051808303816000875af1158015612932573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612956919061343b565b9d9c50505050505050505050505050565b6000808361297884623ce9c06133b8565b61298291906133b8565b8361299081623ce9c46133b8565b61299a91906133b8565b6129a491906133a5565b90506107cc6129b5846107ce6133b8565b6129be83612d4b565b6129c891906133f1565b6129d291906133cf565b949350505050565b6000806129e9856103e66133b8565b905060006129f784836133b8565b9050600082612a08876103e86133b8565b612a1291906133a5565b905061272481836133cf565b600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90612a509087908790600401613454565b600060405180830381600087803b158015612a6a57600080fd5b505af1158015612a7e573d6000803e3d6000fd5b5050600d54600092508291506001600160a01b03808516911610612aa457836000612aa8565b6000845b6040805160008152602081019182905263022c0d9f60e01b90915291935091506001600160a01b0387169063022c0d9f90612aec90859085903090602481016135c9565b600060405180830381600087803b158015612b0657600080fd5b505af1158015612b1a573d6000803e3d6000fd5b50505050505050505050565b6000806000612b358585612dbb565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b999190613579565b506001600160701b0391821694501691508215801590612bb95750600082115b612c055760405162461bcd60e51b815260206004820152601960248201527f7265696e76657374506f6f6c733a2070616972206572726f72000000000000006044820152606401610542565b846001600160a01b0316846001600160a01b03161015612c23579091905b9250925092565b60008080808085612c3b888a6133b8565b612c4591906133cf565b905060006103e8612c588e6103e66133b8565b612c6291906133cf565b905080612c6f8b8e6133a5565b612c7991906133a5565b9750612c85818d6133a5565b612c8f90836133b8565b612c99828c6133a5565b612ca3908d6133b8565b612cad91906133a5565b9650612cba8860026133b8565b612cc490886133cf565b96508088612cd2848e6133b8565b612cdc91906133cf565b612ce691906133b8565b9050612d0581612cf689806133b8565b612d0091906133f1565b612d4b565b612d0f90886133f1565b9050612d1c818d8d612ebb565b9b50995089612d2b8c8e6133f1565b9050612d38818b8b6129da565b9b9d9a9c509a9998505050505050505050565b60006003821115612dac5750806000612d656002836133cf565b612d709060016133a5565b90505b81811015612da657905080600281612d8b81866133cf565b612d9591906133a5565b612d9f91906133cf565b9050612d73565b50919050565b8115612db6575060015b919050565b6000739cc7c769ea3b37f1af0ad642a268b80dc80754c581806001600160a01b0380861690871610612dee578486612df1565b85855b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b1660348201529193509150839060480160405160208183030381529060405280519060200120604051602001612e999291906001600160f81b0319815260609290921b6bffffffffffffffffffffffff1916600183015260158201527fe410ea0a25ce340e309f2f0fe9d58d787bb87dd63d02333e8a9a747230f61758603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b6000808411612f0c5760405162461bcd60e51b815260206004820152601a60248201527f494e53554646494349454e545f4f55545055545f414d4f554e540000000000006044820152606401610542565b6000612f1885856133b8565b612f24906103e86133b8565b90506000612f3286856133f1565b612f3e906103e66133b8565b9050612f4a81836133cf565b612f559060016133a5565b9695505050505050565b6001600160a01b0381168114610e8357600080fd5b600060208284031215612f8657600080fd5b8135612f9181612f5f565b9392505050565b60008060408385031215612fab57600080fd5b50508035926020909101359150565b60008083601f840112612fcc57600080fd5b50813567ffffffffffffffff811115612fe457600080fd5b602083019150836020828501011115612ffc57600080fd5b9250929050565b60008060008060006080868803121561301b57600080fd5b853561302681612f5f565b9450602086013561303681612f5f565b935060408601359250606086013567ffffffffffffffff81111561305957600080fd5b61306588828901612fba565b969995985093965092949392505050565b60006020828403121561308857600080fd5b5035919050565b600080604083850312156130a257600080fd5b82356130ad81612f5f565b915060208301356130bd81612f5f565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613107576131076130c8565b604052919050565b600067ffffffffffffffff821115613129576131296130c8565b5060051b60200190565b600082601f83011261314457600080fd5b813560206131596131548361310f565b6130de565b82815260059290921b8401810191818101908684111561317857600080fd5b8286015b84811015613193578035835291830191830161317c565b509695505050505050565b600080604083850312156131b157600080fd5b823567ffffffffffffffff808211156131c957600080fd5b818501915085601f8301126131dd57600080fd5b813560206131ed6131548361310f565b82815260059290921b8401810191818101908984111561320c57600080fd5b948201945b8386101561323357853561322481612f5f565b82529482019490820190613211565b9650508601359250508082111561324957600080fd5b5061325685828601613133565b9150509250929050565b6000806000806060858703121561327657600080fd5b843561328181612f5f565b935060208501359250604085013567ffffffffffffffff8111156132a457600080fd5b6132b087828801612fba565b95989497509550505050565b8015158114610e8357600080fd5b6000602082840312156132dc57600080fd5b8135612f91816132bc565b604080825283519082018190526000906020906060840190828701845b828110156133295781516001600160a01b031684529284019290840190600101613304565b5050508381038285015284518082528583019183019060005b8181101561335e57835183529284019291840191600101613342565b5090979650505050505050565b6020808252600a908201526937b7363c9037bbb732b960b11b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115611ef557611ef561338f565b8082028115828204841417611ef557611ef561338f565b6000826133ec57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115611ef557611ef561338f565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561344d57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561347f57600080fd5b8151612f9181612f5f565b60006020828403121561349c57600080fd5b8151612f91816132bc565b634e487b7160e01b600052603260045260246000fd5b6000600182016134cf576134cf61338f565b5060010190565b634e487b7160e01b600052603160045260246000fd5b6000815180845260005b81811015613512576020818501810151868301820152016134f6565b506000602082860101526020601f19601f83011685010191505092915050565b60018060a01b038416815282602082015260606040820152600061355960608301846134ec565b95945050505050565b80516001600160701b0381168114612db657600080fd5b60008060006060848603121561358e57600080fd5b61359784613562565b92506135a560208501613562565b9150604084015163ffffffff811681146135be57600080fd5b809150509250925092565b84815283602082015260018060a01b0383166040820152608060608201526000612f5560808301846134ec56fea2646970667358221220c576146de5bd9eddef1936e5eb619b08d3df4998fd9db0c3b381cab6e0f6235d64736f6c6343000812003300000000000000000000000000000000000000000000000000000000000000000000000000000000000000001cee27d0627ce8a81df9b4d7eee0d753b8c2f613

Deployed ByteCode

0x608060405234801561001057600080fd5b506004361061021c5760003560e01c80635fcbd28511610125578063d1af0c7d116100ad578063f40f0f521161007c578063f40f0f52146104dd578063f8077fae146104f0578063fccc2813146104f9578063fce589d814610502578063fdb5a03e1461050b57600080fd5b8063d1af0c7d146104a4578063da5b4ee7146104b7578063db2e21bc146104bf578063e8eed972146104c757600080fd5b80638da5cb5b116100f45780638da5cb5b1461046557806397c4fac71461046d578063a2e6204514610476578063acec338a1461047e578063d08e7b691461049157600080fd5b80635fcbd2851461042457806373af2516146104375780638943ec021461044a5780638cb7e27c1461045d57600080fd5b80633a98ef39116101a85780634f3a1ff8116101775780634f3a1ff8146103d057806352313461146103e35780635b158b3c146103f65780635d799f87146104095780635e38c9541461041c57600080fd5b80633a98ef391461036b5780633c6b16ab14610374578063400250dc146103875780634e48ad3a146103b057600080fd5b80631959a002116101ef5780631959a002146102975780631e29653c1461030e5780632401273c146103245780632e1a7d4d1461034f57806336d421951461036257600080fd5b806301bc71131461022157806302fb0c5e146102365780630b78f9c014610258578063150b7a021461026b575b600080fd5b61023461022f366004612f74565b610513565b005b6011546102439060ff1681565b60405190151581526020015b60405180910390f35b610234610266366004612f98565b6105b3565b61027e610279366004613003565b610608565b6040516001600160e01b0319909116815260200161024f565b6102dd6102a5366004612f74565b601260205260009081526040902080546001820154600283015460038401546004909401549293919290916001600160a01b03169085565b604080519586526020860194909452928401919091526001600160a01b03166060830152608082015260a00161024f565b610316610791565b60405190815260200161024f565b600c54610337906001600160a01b031681565b6040516001600160a01b03909116815260200161024f565b61023461035d366004613076565b610803565b61031660105481565b610316600b5481565b610234610382366004613076565b6109d2565b610337610395366004612f74565b6014602052600090815260409020546001600160a01b031681565b6103166103be366004612f74565b60136020526000908152604090205481565b600554610337906001600160a01b031681565b600854610337906001600160a01b031681565b610234610404366004612f74565b610a02565b61023461041736600461308f565b610b28565b610234610d06565b600e54610337906001600160a01b031681565b61023461044536600461319e565b610e86565b610234610458366004613260565b6110a5565b61023461137d565b61033761152c565b61031660095481565b61023461159a565b61023461048c3660046132ca565b611691565b61023461049f366004612f74565b6116d3565b600d54610337906001600160a01b031681565b610316611763565b6102346117ad565b6104cf6118fe565b60405161024f9291906132e7565b6103166104eb366004612f74565b611a54565b610316600f5481565b61033761dead81565b610316600a5481565b610316611c63565b3361051c61152c565b6001600160a01b03161461054b5760405162461bcd60e51b81526004016105429061336b565b60405180910390fd5b6001600160a01b03811661055e57600080fd5b600880546001600160a01b0319166001600160a01b0383169081179091556040519081527f4cc2fbf2911e773499430576cc26e11ebc7a7d9bca28a2456b2040b2e2a5e338906020015b60405180910390a150565b336105bc61152c565b6001600160a01b0316146105e25760405162461bcd60e51b81526004016105429061336b565b612710821080156105f4575061271081105b6105fd57600080fd5b600a91909155600955565b600060016004600082825461061d91906133a5565b9091555050600454610630600633611ed7565b61066e5760405162461bcd60e51b815260206004820152600f60248201526e139bdd081848189bdbdcdd08139195608a1b6044820152606401610542565b6001600160a01b0380871660009081526012602052604090206003810154909116156106d05760405162461bcd60e51b815260206004820152601160248201527013919508185b1c9958591e481859191959607a1b6044820152606401610542565b6106d861159a565b6106e187611efb565b6003810180546001600160a01b03191633908117909155600090815260136020526040812054600283018190556004830188905560649061072290826133a5565b835461072e91906133b8565b61073891906133cf565b9050816000015481600b5461074d91906133a5565b61075791906133f1565b600b5550630a85bd0160e11b92505060045481146107875760405162461bcd60e51b815260040161054290613404565b5095945050505050565b60055460405163389bbbfd60e21b81523060048201526000916001600160a01b03169063e26eeff490602401602060405180830381865afa1580156107da573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fe919061343b565b905090565b60016004600082825461081691906133a5565b909155505060045433600090815260126020526040902080548311156108735760405162461bcd60e51b81526020600482015260126024820152711dda5d1a191c985dce881b9bdd0819dbdbd960721b6044820152606401610542565b61087b61159a565b61088433611efb565b821561097757600060648260020154606461089f91906133a5565b83546108ab91906133b8565b6108b591906133cf565b82549091506108c59085906133f1565b825560028201546000906064906108dc90826133a5565b84546108e891906133b8565b6108f291906133cf565b90508181600b5461090391906133a5565b61090d91906133f1565b600b55600e5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906109429033908990600401613454565b600060405180830381600087803b15801561095c57600080fd5b505af1158015610970573d6000803e3d6000fd5b5050505050505b60405183815233907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a94243649060200160405180910390a25060045481146109ce5760405162461bcd60e51b815260040161054290613404565b5050565b6040518181527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d906020016105a8565b33610a0b61152c565b6001600160a01b031614610a315760405162461bcd60e51b81526004016105429061336b565b6001600160a01b038116610a4457600080fd5b336001600160a01b0316816001600160a01b0316638da5cb5b6040518163ffffffff1660e01b8152600401602060405180830381865afa158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab0919061346d565b6001600160a01b031614610b065760405162461bcd60e51b815260206004820152601e60248201527f4e657720636f6e74726163742068617320616e6f74686572206f776e657200006044820152606401610542565b600580546001600160a01b0319166001600160a01b0392909216919091179055565b33610b3161152c565b6001600160a01b031614610b575760405162461bcd60e51b81526004016105429061336b565b600d546001600160a01b0390811690831603610bc75760405162461bcd60e51b815260206004820152602960248201527f52657761726420746f6b656e206973206e6f742070726f6e6520746f2045524360448201526832302069737375657360b81b6064820152608401610542565b600e546001600160a01b0390811690831603610c335760405162461bcd60e51b815260206004820152602560248201527f4c5020746f6b656e206973206e6f742070726f6e6520746f2045524332302069604482015264737375657360d81b6064820152608401610542565b6040516370a0823160e01b81523060048201526000906001600160a01b038416906370a0823190602401602060405180830381865afa158015610c7a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c9e919061343b565b60405163a9059cbb60e01b81529091506001600160a01b0384169063a9059cbb90610ccf9085908590600401613454565b600060405180830381600087803b158015610ce957600080fd5b505af1158015610cfd573d6000803e3d6000fd5b50505050505050565b600160046000828254610d1991906133a5565b909155505060045433600090815260126020526040902060038101546001600160a01b031680610d745760405162461bcd60e51b8152602060048201526006602482015265139bc813919560d21b6044820152606401610542565b6003820180546001600160a01b0319169055610d8e61159a565b610d9733611efb565b6000606483600201546064610dac91906133a5565b8454610db891906133b8565b610dc291906133cf565b9050808360000154600b54610dd791906133a5565b610de191906133f1565b600b5560006002840155600480840154604051633263830f60e21b81526001600160a01b0385169263c98e0c3c92610e1b92339201613454565b6020604051808303816000875af1158015610e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e5e919061348a565b505050506004548114610e835760405162461bcd60e51b815260040161054290613404565b50565b33610e8f61152c565b6001600160a01b031614610eb55760405162461bcd60e51b81526004016105429061336b565b8051825114610ef55760405162461bcd60e51b815260206004820152600c60248201526b0eee4dedcce40d8cadccee8d60a31b6044820152606401610542565b60005b81518110156110a05760006001600160a01b0316838281518110610f1e57610f1e6134a7565b60200260200101516001600160a01b031603610f6b5760405162461bcd60e51b815260206004820152600c60248201526b5a65726f206164647265737360a01b6044820152606401610542565b818181518110610f7d57610f7d6134a7565b602002602001015160000361100357610fb9838281518110610fa157610fa16134a7565b60200260200101516006611fba90919063ffffffff16565b50600060136000858481518110610fd257610fd26134a7565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555061108e565b611030838281518110611018576110186134a7565b602002602001015160066120fc90919063ffffffff16565b50818181518110611043576110436134a7565b602002602001015160136000858481518110611061576110616134a7565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020819055505b80611098816134bd565b915050610ef8565b505050565b6001600460008282546110b891906133a5565b909155505060045460115460ff1661111c5760405162461bcd60e51b815260206004820152602160248201527f546865206661726d206973206e6f7420656e61626c6564206279206f776e65726044820152602160f81b6064820152608401610542565b600e546001600160a01b038681169116148061115157506001600160a01b038581166000908152601460205260409020541633145b61135557600e546001600160a01b031633146111af5760405162461bcd60e51b815260206004820152601d60248201527f547279696e6720746f206465706f7369742077726f6e6720746f6b656e0000006044820152606401610542565b6001600160a01b038516600090815260126020526040902054701d6329f1c35ca4bfabb9f56100000000006111e486836133a5565b11156112235760405162461bcd60e51b815260206004820152600e60248201526d06578636565642074686520746f760941b6044820152606401610542565b61122b61159a565b61123486611efb565b8415611310576001600160a01b03861660009081526012602052604081206002015460649061126390826133a5565b61126d90846133b8565b61127791906133cf565b6001600160a01b038816600090815260126020526040812060020154919250906064906112a490826133a5565b6112ae89866133a5565b6112b891906133b8565b6112c291906133cf565b90508181600b546112d391906133a5565b6112dd91906133f1565b600b556001600160a01b038816600090815260126020526040812080548992906113089084906133a5565b909155505050505b856001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8660405161134b91815260200190565b60405180910390a2505b60045481146113765760405162461bcd60e51b815260040161054290613404565b5050505050565b3361138661152c565b6001600160a01b0316146113ac5760405162461bcd60e51b81526004016105429061336b565b600554604051630d18304560e21b81523060048201526001600160a01b0390911690633460c11490602401602060405180830381865afa1580156113f4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611418919061348a565b156114655760405162461bcd60e51b815260206004820152601760248201527f4661726d206d757374206e6f74206265206163746976650000000000000000006044820152606401610542565b600d546040516370a0823160e01b81523060048201526001600160a01b039091169063a9059cbb90339083906370a0823190602401602060405180830381865afa1580156114b7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114db919061343b565b6040518363ffffffff1660e01b81526004016114f8929190613454565b600060405180830381600087803b15801561151257600080fd5b505af1158015611526573d6000803e3d6000fd5b50505050565b60055460408051638da5cb5b60e01b815290516000926001600160a01b031691638da5cb5b9160048083019260209291908290030181865afa158015611576573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107fe919061346d565b60055460405163032453f160e51b81523060048201526001600160a01b039091169063648a7e2090602401600060405180830381600087803b1580156115df57600080fd5b505af11580156115f3573d6000803e3d6000fd5b50505050600f54421161160257565b600b546000036116125742600f55565b6000600f544261162291906133f1565b905060006103e8611631610791565b611639611763565b61164390856133b8565b61164d91906133b8565b61165791906133cf565b600b5490915061166f82670de0b6b3a76400006133b8565b61167991906133cf565b60105461168691906133a5565b601055505042600f55565b3361169a61152c565b6001600160a01b0316146116c05760405162461bcd60e51b81526004016105429061336b565b6011805460ff1916911515919091179055565b336116dc61152c565b6001600160a01b0316146117025760405162461bcd60e51b81526004016105429061336b565b6001600160a01b03811661171557600080fd5b600c80546001600160a01b0319166001600160a01b0383169081179091556040519081527f624b5eb8351863c55d945dc0de9319fcb2547eef7e762196fd564d95eb9d44c0906020016105a8565b6005546040805163da5b4ee760e01b815290516000926001600160a01b03169163da5b4ee79160048083019260209291908290030181865afa1580156107da573d6000803e3d6000fd5b6001600460008282546117c091906133a5565b9091555050600480543360008181526012602052604090819020600e548154925163a9059cbb60e01b8152949591946001600160a01b039091169363a9059cbb9361180f939192909101613454565b600060405180830381600087803b15801561182957600080fd5b505af115801561183d573d6000803e3d6000fd5b505082546040519081523392507f5fafa99d0643513820be26656b45130b01e1c03062e1266bf36f88cbd3bd9695915060200160405180910390a2600060648260020154606461188d91906133a5565b835461189991906133b8565b6118a391906133cf565b905080600b54106118cb5780600b60008282546118c091906133f1565b909155506118d19050565b6000600b555b5060008082556001909101556004548114610e835760405162461bcd60e51b815260040161054290613404565b606080600061190c60065490565b90508067ffffffffffffffff811115611927576119276130c8565b604051908082528060200260200182016040528015611950578160200160208202803683370190505b5092508067ffffffffffffffff81111561196c5761196c6130c8565b604051908082528060200260200182016040528015611995578160200160208202803683370190505b50915060005b81811015611a4e576119ae60068261215f565b8482815181106119c0576119c06134a7565b60200260200101906001600160a01b031690816001600160a01b031681525050601360008583815181106119f6576119f66134a7565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054838281518110611a3157611a316134a7565b602090810291909101015280611a46816134bd565b91505061199b565b50509091565b6001600160a01b0381166000908152601260205260408120601054600f5442118015611a815750600b5415155b15611aff576000600f5442611a9691906133f1565b905060006103e8611aa5610791565b611aad611763565b611ab790856133b8565b611ac191906133b8565b611acb91906133cf565b600b54909150611ae382670de0b6b3a76400006133b8565b611aed91906133cf565b601054611afa91906133a5565b925050505b6000606483600201546064611b1491906133a5565b8454611b2091906133b8565b611b2a91906133cf565b9050670de0b6b3a7640000836001015483611b4591906133f1565b611b4f90836133b8565b611b5991906133cf565b6008549094506000906001600160a01b031615611bfa576008546040516356c5f34960e01b81526001600160a01b038881166004830152909116906356c5f34990602401602060405180830381865afa158015611bba573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bde919061343b565b9050612710611bed82876133b8565b611bf791906133cf565b90505b6000612710600a5487611c0d91906133b8565b611c1791906133cf565b9050600061271060095488611c2c91906133b8565b611c3691906133cf565b905081611c4382856133a5565b611c4d91906133a5565b611c5790886133f1565b98975050505050505050565b6000611c6d61159a565b6000611c78336121ee565b91508115611df957600e5460408051630dfe168160e01b815290516000926001600160a01b031691630dfe16819160048083019260209291908290030181865afa158015611cca573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611cee919061346d565b90506000600e60009054906101000a90046001600160a01b03166001600160a01b031663d21220a76040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d45573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d69919061346d565b600d549091506001600160a01b0390811690831603611d9357611d8c8482612501565b9250611dc1565b600d546001600160a01b0390811690821603611db357611d8c8483612501565b611dbe84838361272f565b92505b60405184815233907f7fc89d3ed4e23fda6ebcec646a642fe679e98dfc053a073434dfaf6ec6f4ed6f9060200160405180910390a250505b8015611ed3573360009081526012602052604081208054600282015491929091606490611e2690826133a5565b611e3090846133b8565b611e3a91906133cf565b90506000606484600201546064611e5191906133a5565b611e5b87866133a5565b611e6591906133b8565b611e6f91906133cf565b90508181600b54611e8091906133a5565b611e8a91906133f1565b600b55611e9785846133a5565b845560405185815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d9060200160405180910390a2505050505b5090565b6001600160a01b038116600090815260018301602052604090205415155b92915050565b6000611f06826121ee565b90508015611f7357600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90611f409085908590600401613454565b600060405180830381600087803b158015611f5a57600080fd5b505af1158015611f6e573d6000803e3d6000fd5b505050505b816001600160a01b03167fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e048682604051611fae91815260200190565b60405180910390a25050565b6001600160a01b038116600090815260018301602052604081205480156120f2576000611fe86001836133f1565b8554909150600090611ffc906001906133f1565b90506000866000018281548110612015576120156134a7565b60009182526020909120015487546001600160a01b0390911691508190889085908110612044576120446134a7565b600091825260209091200180546001600160a01b0319166001600160a01b03929092169190911790556120788360016133a5565b6001600160a01b038216600090815260018901602052604090205586548790806120a4576120a46134d6565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b0388168252600189810190915260408220919091559450611ef59350505050565b6000915050611ef5565b60006121088383611ed7565b61215757508154600180820184556000848152602080822090930180546001600160a01b0319166001600160a01b03861690811790915585549082528286019093526040902091909155611ef5565b506000611ef5565b815460009082106121bd5760405162461bcd60e51b815260206004820152602260248201527f456e756d657261626c655365743a20696e646578206f7574206f6620626f756e604482015261647360f01b6064820152608401610542565b8260000182815481106121d2576121d26134a7565b6000918252602090912001546001600160a01b03169392505050565b6001600160a01b03811660009081526012602052604081206002810154829060649061221a90826133a5565b835461222691906133b8565b61223091906133cf565b9050670de0b6b3a7640000826001015460105461224d91906133f1565b61225790836133b8565b61226191906133cf565b925082156124f2576008546000906001600160a01b0316156122ee576008546040516356c5f34960e01b81526001600160a01b038781166004830152909116906356c5f34990602401602060405180830381865afa1580156122c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122eb919061343b565b90505b80156123b35761271061230182866133b8565b61230b91906133cf565b604080516001600160a01b03881660208201529192506000910160408051601f1981840301815290829052600d54600854635f22feb160e11b84529193506001600160a01b039081169263be45fd629261236d92169086908690600401613532565b6020604051808303816000875af115801561238c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123b0919061348a565b50505b6000612710600a54866123c691906133b8565b6123d091906133cf565b9050801561243f57600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb9061240c9061dead908590600401613454565b600060405180830381600087803b15801561242657600080fd5b505af115801561243a573d6000803e3d6000fd5b505050505b60006127106009548761245291906133b8565b61245c91906133cf565b905080156124cd57600d54600c5460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb9261249a929116908590600401613454565b600060405180830381600087803b1580156124b457600080fd5b505af11580156124c8573d6000803e3d6000fd5b505050505b816124d882856133a5565b6124e291906133a5565b6124ec90876133f1565b95505050505b50601054600190910155919050565b6000806000600e60009054906101000a90046001600160a01b03166001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612559573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061257d9190613579565b50600d546001600160701b039283169450911691506001600160a01b0390811690851610156125a857905b60006125b48684612967565b905060006125c38285856129da565b600e549091506125de906001600160a01b0316838389612a1e565b6125e882886133f1565b600d54600e5460405163a9059cbb60e01b81529294506001600160a01b039182169263a9059cbb926126209216908690600401613454565b600060405180830381600087803b15801561263a57600080fd5b505af115801561264e573d6000803e3d6000fd5b5050600e5460405163a9059cbb60e01b81526001600160a01b03808b16945063a9059cbb93506126849216908590600401613454565b600060405180830381600087803b15801561269e57600080fd5b505af11580156126b2573d6000803e3d6000fd5b5050600e546040516335313c2160e11b81523060048201526001600160a01b039091169250636a62784291506024016020604051808303816000875af1158015612700573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612724919061343b565b979650505050505050565b60008060008061273f8686612b26565b600e5492955090935091506001600160a01b038083169116146127945760405162461bcd60e51b815260206004820152600d60248201526c77726f6e6720666163746f727960981b6044820152606401610542565b600d54600090819081906127b1906001600160a01b03168a612b26565b600d549295509093509150600090819081906127d6906001600160a01b03168c612b26565b9250925092506127eb8d878786868e8e612c2a565b929850909650935091506128018487878f612a1e565b61280d8184848e612a1e565b600e5460405163a9059cbb60e01b81526001600160a01b038e81169263a9059cbb9261284192909116908990600401613454565b600060405180830381600087803b15801561285b57600080fd5b505af115801561286f573d6000803e3d6000fd5b505050508a6001600160a01b031663a9059cbb600e60009054906101000a90046001600160a01b0316846040518363ffffffff1660e01b81526004016128b6929190613454565b600060405180830381600087803b1580156128d057600080fd5b505af11580156128e4573d6000803e3d6000fd5b5050600e546040516335313c2160e11b81523060048201526001600160a01b039091169250636a62784291506024016020604051808303816000875af1158015612932573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612956919061343b565b9d9c50505050505050505050505050565b6000808361297884623ce9c06133b8565b61298291906133b8565b8361299081623ce9c46133b8565b61299a91906133b8565b6129a491906133a5565b90506107cc6129b5846107ce6133b8565b6129be83612d4b565b6129c891906133f1565b6129d291906133cf565b949350505050565b6000806129e9856103e66133b8565b905060006129f784836133b8565b9050600082612a08876103e86133b8565b612a1291906133a5565b905061272481836133cf565b600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb90612a509087908790600401613454565b600060405180830381600087803b158015612a6a57600080fd5b505af1158015612a7e573d6000803e3d6000fd5b5050600d54600092508291506001600160a01b03808516911610612aa457836000612aa8565b6000845b6040805160008152602081019182905263022c0d9f60e01b90915291935091506001600160a01b0387169063022c0d9f90612aec90859085903090602481016135c9565b600060405180830381600087803b158015612b0657600080fd5b505af1158015612b1a573d6000803e3d6000fd5b50505050505050505050565b6000806000612b358585612dbb565b9050806001600160a01b0316630902f1ac6040518163ffffffff1660e01b8152600401606060405180830381865afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b999190613579565b506001600160701b0391821694501691508215801590612bb95750600082115b612c055760405162461bcd60e51b815260206004820152601960248201527f7265696e76657374506f6f6c733a2070616972206572726f72000000000000006044820152606401610542565b846001600160a01b0316846001600160a01b03161015612c23579091905b9250925092565b60008080808085612c3b888a6133b8565b612c4591906133cf565b905060006103e8612c588e6103e66133b8565b612c6291906133cf565b905080612c6f8b8e6133a5565b612c7991906133a5565b9750612c85818d6133a5565b612c8f90836133b8565b612c99828c6133a5565b612ca3908d6133b8565b612cad91906133a5565b9650612cba8860026133b8565b612cc490886133cf565b96508088612cd2848e6133b8565b612cdc91906133cf565b612ce691906133b8565b9050612d0581612cf689806133b8565b612d0091906133f1565b612d4b565b612d0f90886133f1565b9050612d1c818d8d612ebb565b9b50995089612d2b8c8e6133f1565b9050612d38818b8b6129da565b9b9d9a9c509a9998505050505050505050565b60006003821115612dac5750806000612d656002836133cf565b612d709060016133a5565b90505b81811015612da657905080600281612d8b81866133cf565b612d9591906133a5565b612d9f91906133cf565b9050612d73565b50919050565b8115612db6575060015b919050565b6000739cc7c769ea3b37f1af0ad642a268b80dc80754c581806001600160a01b0380861690871610612dee578486612df1565b85855b6040516bffffffffffffffffffffffff19606084811b8216602084015283901b1660348201529193509150839060480160405160208183030381529060405280519060200120604051602001612e999291906001600160f81b0319815260609290921b6bffffffffffffffffffffffff1916600183015260158201527fe410ea0a25ce340e309f2f0fe9d58d787bb87dd63d02333e8a9a747230f61758603582015260550190565b60408051601f1981840301815291905280516020909101209695505050505050565b6000808411612f0c5760405162461bcd60e51b815260206004820152601a60248201527f494e53554646494349454e545f4f55545055545f414d4f554e540000000000006044820152606401610542565b6000612f1885856133b8565b612f24906103e86133b8565b90506000612f3286856133f1565b612f3e906103e66133b8565b9050612f4a81836133cf565b612f559060016133a5565b9695505050505050565b6001600160a01b0381168114610e8357600080fd5b600060208284031215612f8657600080fd5b8135612f9181612f5f565b9392505050565b60008060408385031215612fab57600080fd5b50508035926020909101359150565b60008083601f840112612fcc57600080fd5b50813567ffffffffffffffff811115612fe457600080fd5b602083019150836020828501011115612ffc57600080fd5b9250929050565b60008060008060006080868803121561301b57600080fd5b853561302681612f5f565b9450602086013561303681612f5f565b935060408601359250606086013567ffffffffffffffff81111561305957600080fd5b61306588828901612fba565b969995985093965092949392505050565b60006020828403121561308857600080fd5b5035919050565b600080604083850312156130a257600080fd5b82356130ad81612f5f565b915060208301356130bd81612f5f565b809150509250929050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff81118282101715613107576131076130c8565b604052919050565b600067ffffffffffffffff821115613129576131296130c8565b5060051b60200190565b600082601f83011261314457600080fd5b813560206131596131548361310f565b6130de565b82815260059290921b8401810191818101908684111561317857600080fd5b8286015b84811015613193578035835291830191830161317c565b509695505050505050565b600080604083850312156131b157600080fd5b823567ffffffffffffffff808211156131c957600080fd5b818501915085601f8301126131dd57600080fd5b813560206131ed6131548361310f565b82815260059290921b8401810191818101908984111561320c57600080fd5b948201945b8386101561323357853561322481612f5f565b82529482019490820190613211565b9650508601359250508082111561324957600080fd5b5061325685828601613133565b9150509250929050565b6000806000806060858703121561327657600080fd5b843561328181612f5f565b935060208501359250604085013567ffffffffffffffff8111156132a457600080fd5b6132b087828801612fba565b95989497509550505050565b8015158114610e8357600080fd5b6000602082840312156132dc57600080fd5b8135612f91816132bc565b604080825283519082018190526000906020906060840190828701845b828110156133295781516001600160a01b031684529284019290840190600101613304565b5050508381038285015284518082528583019183019060005b8181101561335e57835183529284019291840191600101613342565b5090979650505050505050565b6020808252600a908201526937b7363c9037bbb732b960b11b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b80820180821115611ef557611ef561338f565b8082028115828204841417611ef557611ef561338f565b6000826133ec57634e487b7160e01b600052601260045260246000fd5b500490565b81810381811115611ef557611ef561338f565b6020808252601f908201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604082015260600190565b60006020828403121561344d57600080fd5b5051919050565b6001600160a01b03929092168252602082015260400190565b60006020828403121561347f57600080fd5b8151612f9181612f5f565b60006020828403121561349c57600080fd5b8151612f91816132bc565b634e487b7160e01b600052603260045260246000fd5b6000600182016134cf576134cf61338f565b5060010190565b634e487b7160e01b600052603160045260246000fd5b6000815180845260005b81811015613512576020818501810151868301820152016134f6565b506000602082860101526020601f19601f83011685010191505092915050565b60018060a01b038416815282602082015260606040820152600061355960608301846134ec565b95945050505050565b80516001600160701b0381168114612db657600080fd5b60008060006060848603121561358e57600080fd5b61359784613562565b92506135a560208501613562565b9150604084015163ffffffff811681146135be57600080fd5b809150509250925092565b84815283602082015260018060a01b0383166040820152608060608201526000612f5560808301846134ec56fea2646970667358221220c576146de5bd9eddef1936e5eb619b08d3df4998fd9db0c3b381cab6e0f6235d64736f6c63430008120033