false
false
0

Contract Address Details

0xeB4511C90F9387De8F8945ABD8C803d5cB275509

Contract Name
SoyStaking
Creator
0xc7d98c–7f3521 at 0xb7a41b–7ef598
Balance
0 CLO
Tokens
Fetching tokens...
Transactions
Fetching transactions...
Transfers
Fetching transfers...
Gas Used
Fetching gas used...
Last Balance Update
16284917
Warning! Contract bytecode has been changed and doesn't match the verified one. Therefore, interaction with this smart contract may be risky.
Contract name:
SoyStaking




Optimization enabled
true
Compiler version
v0.6.12+commit.27d51765




Optimization runs
200
EVM Version
default




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

Contract source code

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

/**
 * @title SafeMath
 * @dev Math operations with safety checks that throw on error
 */
library SafeMath {
  function mul(uint a, uint b) internal pure returns (uint) {
    if (a == 0) {
      return 0;
    }
    uint c = a * b;
    require(c / a == b);
    return c;
  }

  function div(uint a, uint b) internal pure returns (uint) {
    // assert(b > 0); // Solidity automatically throws when dividing by 0
    uint c = a / b;
    // assert(a == b * c + a % b); // There is no case in which this doesn't hold
    return c;
  }

  function sub(uint a, uint b) internal pure returns (uint) {
    require(b <= a);
    return a - b;
  }

  function add(uint a, uint b) internal pure returns (uint) {
    uint c = a + b;
    require(c >= a);
    return c;
  }
}

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);
}

interface IERC223 {
    /**
     * @dev Returns the balance of the `who` address.
     */
    function balanceOf(address who) external view returns (uint);
        
    /**
     * @dev Transfers `value` tokens from `msg.sender` to `to` address
     * and returns `true` on success.
     */
    function transfer(address to, uint value) external returns (bool success);
        
    /**
     * @dev Transfers `value` tokens from `msg.sender` to `to` address with `data` parameter
     * and returns `true` on success.
     */
    function transfer(address to, uint value, bytes memory data) external returns (bool success);
     
     /**
     * @dev Event that is fired on successful transfer.
     */
    event Transfer(address indexed from, address indexed to, uint value);
    
     /**
     * @dev Additional event that is fired on successful transfer and logs transfer metadata,
     *      this event is implemented to keep Transfer event compatible with ERC20.
     */
    event TransferData(bytes data);
}

contract SoyStaking {
    
    // NOTE: The contract only works for intervals of time > round_interval

    using SafeMath for uint;

    event StartStaking(address addr, uint value, uint amount, uint time, uint end_time);
    event WithdrawStake(address staker, uint amount);
    event Claim(address staker, uint reward);
    event DonationDeposited(address _address, uint value);

    struct Staker
    {
        uint amount;
        uint time;              // Staking start time or last claim rewards
        uint multiplier;        // Rewards multiplier = 0.40 + (0.05 * rounds). [0.45..1] (max rounds 12)
        uint end_time;          // Time when staking ends and user may withdraw. After this time user will not receive rewards.
    }


    uint public LastBlock = block.number;
    uint public Timestamp = now;    //timestamp of the last interaction with the contract.

    uint public TotalStakingWeight; //total weight = sum (each_staking_amount * each_staking_time).
    uint public TotalStakingAmount; //currently frozen amount for Staking.
    uint public StakingRewardPool;  //available amount for paying rewards.
    uint public staking_threshold = 0 ether;

    uint public constant round_interval   = 27 days;     // 1 month.
    uint public constant max_delay        = 365 days;    // 1 year after staking ends.
    uint public constant BlockStartStaking = 7600000;

    uint constant NOMINATOR = 10**18;           // Nominator / denominator used for float point numbers

    address public constant SOY = 0x9FaE2529863bD691B4A7171bDfCf33C7ebB10a65;
    address public constant globalFarm = 0x64Fa36ACD0d13472FD786B03afC9C52aD5FCf023;
    uint public stake_until = 1662033600; // 1 September 2022 12:00:00 GMT (all staking should be finished until this time)
    address public admin;   // admin address who can set stake_until

    //========== TESTNET VALUES ===========
    //uint public constant round_interval   = 1 hours; 
    //uint public constant max_delay        = 2 days;
    //uint public constant BlockStartStaking = 0;
    
    //https://github.com/SoyFinance/smart-contracts/tree/main/Farming#testsoy223-token
    //address public constant SOY = 0xC8227f810FB2F4FacBf9D3CAbca21e47f51d87a3;

    // https://github.com/SoyFinance/smart-contracts/tree/main/Farming#test-global-farm-contract-3-minutes
    //address public constant globalFarm = 0xE8B2Fee5D18ec30f5625a5f7F1f06E5df17E1774;
    //========== END TEST VALUES ==========
    
    mapping(address => Staker) public staker;


    constructor() public {
        admin = msg.sender;
    }

    function setStakeUntil(uint newDate) external {
        require(admin == msg.sender, "Only admin");
        stake_until = newDate;
    }

    // ERC223 token transfer callback
    // bytes _data = abi.encode(address receiver, uint256 toChainId)
    function tokenReceived(address _from, uint _value, bytes calldata _data) external {
        require(msg.sender == SOY, "Only SOY");
        if (_from == globalFarm || _from == admin) return; // if globalFarm or admin transfer tokens, they will be added to reward pool

        // No donations accepted to fallback!
        // Consider value deposit is an attempt to become staker.
        // May not accept deposit from other contracts due GAS limit.
        // by default stake for 1 round
        uint rounds;
        if (_data.length >= 32) {
            rounds = abi.decode(_data, (uint256));  // _data should contain ABI encoded UINT =  number of rounds
        }
        if (rounds == 0) rounds = 1;
        start_staking(_from, _value, rounds);
    }

    function notifyRewardAmount(uint256 reward) external {}

    function reward_request() internal
    {
        if(ISimplifiedGlobalFarm(globalFarm).rewardMintingAvailable(address(this)))
        {
            ISimplifiedGlobalFarm(globalFarm).mintFarmingReward(address(this));
        }
    }

    // update TotalStakingAmount value.
    function new_block(uint amount) internal
    {
        if (block.number > LastBlock)   //run once per block.
        {
            reward_request();
            uint _LastBlock = LastBlock;
            LastBlock = block.number;

            StakingRewardPool = IERC223(SOY).balanceOf(address(this)).sub(TotalStakingAmount + amount);   //fix rewards pool for this block.
            // amount here for case new_block() is calling from start_staking(), and amount will be added to CurrentBlockDeposits.

            //The consensus protocol enforces block timestamps are always at least +1 from their parent, so a node cannot "lie into the past". 
            if (now > Timestamp) //But with this condition I feel safer :) May be removed.
            {
                uint _blocks = block.number - _LastBlock;
                uint _seconds = now - Timestamp;
                if (_seconds > _blocks * 25) //if time goes far in the future, then use new time as 25 second * blocks.
                {
                    _seconds = _blocks * 25;
                }
                TotalStakingWeight += _seconds.mul(TotalStakingAmount);
                Timestamp += _seconds;
            }
        }
    }

    function start_staking(address user, uint amount, uint rounds) internal staking_available
    {
        assert(amount >= staking_threshold);
        require(rounds > 0);
        new_block(amount); //run once per block.
        // to reduce gas cost we will use local variable instead of global
        uint _Timestamp = Timestamp;
        uint staker_amount = staker[user].amount;
        uint r = rounds;
        if (r > 6) r = 6;
        uint multiplier = (40 + (10 * r)) * NOMINATOR / 100;  // staker multiplier = 0.40 + (0.05 * rounds). [0.45..1]
        uint end_time = _Timestamp.add(round_interval.mul(rounds));
        require(end_time <= stake_until, "Too long staking time");  // do not allow stake longer than "stake_until"
        // claim reward if available.
        if (staker_amount > 0)
        {
            if (_Timestamp >= staker[user].time + round_interval)
            { 
                _claim(payable(user)); 
            }
            uint staker_end_time = staker[user].end_time;
            if (staker_end_time > end_time) {
                end_time = staker_end_time;     // Staking end time is the bigger from previous and new one.
                r = (end_time.sub(_Timestamp)).div(round_interval);  // update number of rounds
                if (r > 12) r = 12;
                multiplier = (40 + (5 * r)) * NOMINATOR / 100;  // staker multiplier = 0.40 + (0.05 * rounds). [0.45..1]
            }
            // if there is active staking with bigger multiplier
            if (staker[user].multiplier > multiplier && staker_end_time > _Timestamp) {
                // recalculate multiplier = (staker.multiplier * staker.amount + new.multiplier * new.amount) / ( staker.amount + new.amount)
                multiplier = ((staker[user].multiplier.mul(staker_amount)).add(multiplier.mul(amount))) / (staker_amount.add(amount));
                if (multiplier > NOMINATOR) multiplier = NOMINATOR; // multiplier can't be more then 1
            }
            TotalStakingWeight = TotalStakingWeight.sub((_Timestamp.sub(staker[user].time)).mul(staker_amount)); // remove from Weight
        }

        TotalStakingAmount = TotalStakingAmount.add(amount);
        staker[user].time = _Timestamp;
        staker[user].amount = staker_amount.add(amount);
        staker[user].multiplier = multiplier;
        staker[user].end_time = end_time;

        emit StartStaking(
            user,
            amount,
            staker[user].amount,
            _Timestamp,
            end_time
        );
    }

    function withdraw_stake() external {
        _withdraw_stake(msg.sender);
    }

    function withdraw_stake(address payable user) external {
        _withdraw_stake(user);
    }

    function _withdraw_stake(address payable user) internal
    {
        new_block(0); //run once per block.
        require(Timestamp >= staker[user].end_time); //reject withdrawal before end time.

        uint _amount = staker[user].amount;
        require(_amount != 0);
        // claim reward if available.
        _claim(user); 
        TotalStakingAmount = TotalStakingAmount.sub(_amount);
        TotalStakingWeight = TotalStakingWeight.sub((Timestamp.sub(staker[user].time)).mul(staker[user].amount)); // remove from Weight.
        
        staker[user].amount = 0;
        IERC223(SOY).transfer(user, _amount);
        emit WithdrawStake(user, _amount);
    }

    //claim rewards
    function claim() external only_staker
    {
        _claim(msg.sender);
    }


    function _claim(address payable user) internal
    {
        new_block(0); //run once per block
        // to reduce gas cost we will use local variable instead of global
        uint _Timestamp = Timestamp;
        if (_Timestamp > staker[user].end_time) _Timestamp = staker[user].end_time; // rewards calculates until staking ends
        uint _StakingInterval = _Timestamp.sub(staker[user].time);  //time interval of deposit.
        if (_StakingInterval >= round_interval)
        {
            uint _CompleteRoundsInterval = (_StakingInterval / round_interval).mul(round_interval); //only complete rounds.
            uint _StakerWeight = _CompleteRoundsInterval.mul(staker[user].amount); //Weight of completed rounds.
            uint _reward = StakingRewardPool.mul(_StakerWeight).div(TotalStakingWeight);  //StakingRewardPool * _StakerWeight/TotalStakingWeight
            _reward = _reward.mul(staker[user].multiplier) / NOMINATOR;   // reduce rewards if staked on less then 12 rounds.
            StakingRewardPool = StakingRewardPool.sub(_reward);
            TotalStakingWeight = TotalStakingWeight.sub(_StakerWeight); // remove paid Weight.

            staker[user].time = staker[user].time.add(_CompleteRoundsInterval); // reset to paid time, staking continue without a loss of incomplete rounds.
	    
            IERC223(SOY).transfer(user, _reward);
            emit Claim(user, _reward);
        }
    }

    //This function may be used for info only. This can show estimated user reward at current time.
    function stake_reward(address _addr) external view returns (uint _reward)
    {
        //require(staker[_addr].amount > 0);

        uint _blocks = block.number - LastBlock;
        uint _seconds = now - Timestamp;
        if (_seconds > _blocks * 25) //if time goes far in the future, then use new time as 25 second * blocks.
        {
            _seconds = _blocks * 25;
        }
        uint _Timestamp = Timestamp + _seconds;
        if (_Timestamp > staker[_addr].end_time) _Timestamp = staker[_addr].end_time; // rewards calculates until staking ends
        uint _TotalStakingWeight = TotalStakingWeight + _seconds.mul(TotalStakingAmount);
        uint _StakingInterval = _Timestamp.sub(staker[_addr].time); //time interval of deposit.
	
        //uint _StakerWeight = _StakingInterval.mul(staker[_addr].amount); //Staker weight.
        uint _CompleteRoundsInterval = (_StakingInterval / round_interval).mul(round_interval); //only complete rounds.
        uint _StakerWeight = _CompleteRoundsInterval.mul(staker[_addr].amount); //Weight of completed rounds.
        uint _StakingRewardPool = IERC223(SOY).balanceOf(address(this)).sub(TotalStakingAmount);
        _reward = _StakingRewardPool.mul(_StakerWeight).div(_TotalStakingWeight);  //StakingRewardPool * _StakerWeight/TotalStakingWeight
        _reward = _reward.mul(staker[_addr].multiplier) / NOMINATOR;   // reduce rewards if staked on less then 12 rounds.
    }

    modifier only_staker
    {
        require(staker[msg.sender].amount > 0);
        _;
    }

    modifier staking_available
    {
        require(block.number >= BlockStartStaking);
        _;
    }

    //return deposit to inactive staker after 1 year when staking ends.
    function report_abuse(address payable _addr) public only_staker
    {
        require(staker[_addr].amount > 0);
        new_block(0); //run once per block.
        require(Timestamp > staker[_addr].end_time.add(max_delay));
        
        uint _amount = staker[_addr].amount;
        
        TotalStakingAmount = TotalStakingAmount.sub(_amount);
        TotalStakingWeight = TotalStakingWeight.sub((Timestamp.sub(staker[_addr].time)).mul(_amount)); // remove from Weight.

        staker[_addr].amount = 0;
        IERC223(SOY).transfer(_addr, _amount);
    }
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[]},{"type":"event","name":"Claim","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":false},{"type":"uint256","name":"reward","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"DonationDeposited","inputs":[{"type":"address","name":"_address","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"StartStaking","inputs":[{"type":"address","name":"addr","internalType":"address","indexed":false},{"type":"uint256","name":"value","internalType":"uint256","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false},{"type":"uint256","name":"time","internalType":"uint256","indexed":false},{"type":"uint256","name":"end_time","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"event","name":"WithdrawStake","inputs":[{"type":"address","name":"staker","internalType":"address","indexed":false},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"BlockStartStaking","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"LastBlock","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"SOY","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"StakingRewardPool","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"Timestamp","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TotalStakingAmount","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"TotalStakingWeight","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"admin","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"claim","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"globalFarm","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"max_delay","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyRewardAmount","inputs":[{"type":"uint256","name":"reward","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"report_abuse","inputs":[{"type":"address","name":"_addr","internalType":"address payable"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"round_interval","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setStakeUntil","inputs":[{"type":"uint256","name":"newDate","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"_reward","internalType":"uint256"}],"name":"stake_reward","inputs":[{"type":"address","name":"_addr","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"stake_until","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"uint256","name":"time","internalType":"uint256"},{"type":"uint256","name":"multiplier","internalType":"uint256"},{"type":"uint256","name":"end_time","internalType":"uint256"}],"name":"staker","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"staking_threshold","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"tokenReceived","inputs":[{"type":"address","name":"_from","internalType":"address"},{"type":"uint256","name":"_value","internalType":"uint256"},{"type":"bytes","name":"_data","internalType":"bytes"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw_stake","inputs":[{"type":"address","name":"user","internalType":"address payable"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw_stake","inputs":[]}]
              

Contract Creation Code

Verify & Publish
0x6080604052436000554260015560006005556363109ec060065534801561002557600080fd5b50600780546001600160a01b03191633179055611209806100476000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c8063aaee69d9116100b8578063cd9488551161007c578063cd94885514610327578063e2d405681461032f578063e6369e4114610337578063edbbc33b1461033f578063f851a44014610347578063f88400711461034f57610142565b8063aaee69d9146102c3578063b3fefcf5146102e9578063b43e92fa146102f1578063be9e2c9a146102f9578063bf92b4ef1461030157610142565b80635499eae61161010a5780635499eae6146101b45780635c854aa9146101bc5780637157c113146101c457806378be0ad4146101cc57806382e4eda4146101f25780638943ec021461023e57610142565b806314657ef0146101475780631e37de4c146101615780633c6b16ab146101695780634e71d92d146101885780634f3a1ff814610190575b600080fd5b61014f61036c565b60408051918252519081900360200190f35b61014f610372565b6101866004803603602081101561017f57600080fd5b5035610378565b005b61018661037b565b61019861039f565b604080516001600160a01b039092168252519081900360200190f35b61014f6103b7565b61014f6103bd565b61014f6103c3565b610186600480360360208110156101e257600080fd5b50356001600160a01b03166103ca565b6102186004803603602081101561020857600080fd5b50356001600160a01b03166103d3565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6101866004803603606081101561025457600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561028457600080fd5b82018360208201111561029657600080fd5b803590602001918460018302840111640100000000831117156102b857600080fd5b5090925090506103fa565b610186600480360360208110156102d957600080fd5b50356001600160a01b03166104ca565b61014f610653565b61014f610659565b61019861065f565b61014f6004803603602081101561031757600080fd5b50356001600160a01b0316610677565b610186610861565b61014f61086a565b61014f610872565b61014f610878565b61019861087f565b6101866004803603602081101561036557600080fd5b503561088e565b60025481565b60045481565b50565b3360009081526008602052604090205461039457600080fd5b61039d336108df565b565b7364fa36acd0d13472fd786b03afc9c52ad5fcf02381565b60065481565b60055481565b6223988081565b61037881610b37565b60086020526000908152604090208054600182015460028301546003909301549192909184565b33739fae2529863bd691b4a7171bdfcf33c7ebb10a651461044d576040805162461bcd60e51b81526020600482015260086024820152674f6e6c7920534f5960c01b604482015290519081900360640190fd5b6001600160a01b0384167364fa36acd0d13472fd786b03afc9c52ad5fcf023148061048557506007546001600160a01b038581169116145b1561048f576104c4565b6000602082106104ae57828260208110156104a957600080fd5b503590505b806104b7575060015b6104c2858583610cc6565b505b50505050565b336000908152600860205260409020546104e357600080fd5b6001600160a01b03811660009081526008602052604090205461050557600080fd5b61050f6000610fbb565b6001600160a01b038116600090815260086020526040902060030154610539906301e1338061107f565b6001541161054657600080fd5b6001600160a01b03811660009081526008602052604090205460035461056c908261109a565b6003556001600160a01b038216600090815260086020526040902060019081015490546105b2916105a99184916105a3919061109a565b906110af565b6002549061109a565b6002556001600160a01b0382166000818152600860209081526040808320839055805163a9059cbb60e01b815260048101949094526024840185905251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb9360448083019493928390030190829087803b15801561062957600080fd5b505af115801561063d573d6000803e3d6000fd5b505050506040513d60208110156104c457600080fd5b60035481565b60005481565b739fae2529863bd691b4a7171bdfcf33c7ebb10a6581565b600080546001544391909103904203601982028111156106975750601981025b6001546001600160a01b038516600090815260086020526040902060030154908201908111156106df57506001600160a01b0384166000908152600860205260409020600301545b60006106f6600354846110af90919063ffffffff16565b6002546001600160a01b0388166000908152600860205260408120600101549290910192509061072790849061109a565b9050600061073c6223988080845b04906110af565b6001600160a01b038916600090815260086020526040812054919250906107649083906110af565b90506000610801600354739fae2529863bd691b4a7171bdfcf33c7ebb10a656001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156107cf57600080fd5b505afa1580156107e3573d6000803e3d6000fd5b505050506040513d60208110156107f957600080fd5b50519061109a565b90506108178561081183856110af565b906110d6565b6001600160a01b038b16600090815260086020526040902060020154909950670de0b6b3a76400009061084b908b906110af565b8161085257fe5b049a9950505050505050505050565b61039d33610b37565b6301e1338081565b60015481565b6273f78081565b6007546001600160a01b031681565b6007546001600160a01b031633146108da576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9030b236b4b760b11b604482015290519081900360640190fd5b600655565b6108e96000610fbb565b6001546001600160a01b03821660009081526008602052604090206003015481111561092d57506001600160a01b0381166000908152600860205260409020600301545b6001600160a01b03821660009081526008602052604081206001015461095490839061109a565b9050622398808110610b32576000610970622398808084610735565b6001600160a01b038516600090815260086020526040812054919250906109989083906110af565b905060006109b7600254610811846004546110af90919063ffffffff16565b6001600160a01b038716600090815260086020526040902060020154909150670de0b6b3a7640000906109eb9083906110af565b816109f257fe5b049050610a0a8160045461109a90919063ffffffff16565b600455600254610a1a908361109a565b6002556001600160a01b038616600090815260086020526040902060010154610a43908461107f565b6001600160a01b038716600081815260086020908152604080832060010194909455835163a9059cbb60e01b81526004810193909352602483018590529251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb93604480820194929392918390030190829087803b158015610abe57600080fd5b505af1158015610ad2573d6000803e3d6000fd5b505050506040513d6020811015610ae857600080fd5b5050604080516001600160a01b03881681526020810183905281517f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4929181900390910190a15050505b505050565b610b416000610fbb565b6001600160a01b0381166000908152600860205260409020600301546001541015610b6b57600080fd5b6001600160a01b03811660009081526008602052604090205480610b8e57600080fd5b610b97826108df565b600354610ba4908261109a565b6003556001600160a01b038216600090815260086020526040902080546001918201549154610bdb926105a992916105a39161109a565b6002556001600160a01b0382166000818152600860209081526040808320839055805163a9059cbb60e01b815260048101949094526024840185905251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb9360448083019493928390030190829087803b158015610c5257600080fd5b505af1158015610c66573d6000803e3d6000fd5b505050506040513d6020811015610c7c57600080fd5b5050604080516001600160a01b03841681526020810183905281517f141ef67c4a6d3ec2adfb2f66d33c2b11de5b4f34344757554d430570b18a92ec929181900390910190a15050565b6273f780431015610cd657600080fd5b600554821015610ce257fe5b60008111610cef57600080fd5b610cf882610fbb565b6001546001600160a01b038416600090815260086020526040902054826006811115610d22575060065b6064670de0b6b3a7640000600a830260280102046000610d4f610d4862239880886110af565b869061107f565b9050600654811115610da0576040805162461bcd60e51b8152602060048201526015602482015274546f6f206c6f6e67207374616b696e672074696d6560581b604482015290519081900360640190fd5b8315610f02576001600160a01b03881660009081526008602052604090206001015462239880018510610dd657610dd6886108df565b6001600160a01b03881660009081526008602052604090206003015481811115610e3557905080610e0e62239880610811838961109a565b9350600c841115610e1e57600c93505b606460286005860201670de0b6b3a7640000020492505b6001600160a01b03891660009081526008602052604090206002015483108015610e5e57508581115b15610ecc57610e6d858961107f565b610ea6610e7a858b6110af565b6001600160a01b038c16600090815260086020526040902060020154610ea090896110af565b9061107f565b81610ead57fe5b049250670de0b6b3a7640000831115610ecc57670de0b6b3a764000092505b6001600160a01b038916600090815260086020526040902060010154610efd906105a99087906105a3908a9061109a565b600255505b600354610f0f908861107f565b6003556001600160a01b0388166000908152600860205260409020600101859055610f3a848861107f565b6001600160a01b03891660008181526008602090815260409182902084815560028101879055600301859055815192835282018a905281810192909252606081018790526080810183905290517f59314c5dd1994b45a3987ac7bace43129e2616c39c4ce9a995c6cc5e4adc5cb49181900360a00190a15050505050505050565b60005443111561037857610fcd6110eb565b6000805443909155600354604080516370a0823160e01b8152306004820152905161103192850191739fae2529863bd691b4a7171bdfcf33c7ebb10a65916370a0823191602480820192602092909190829003018186803b1580156107cf57600080fd5b60045560015442111561107b5760015443829003904203601982028111156110595750601981025b6003546110679082906110af565b600280549091019055600180549091019055505b5050565b60008282018381101561109157600080fd5b90505b92915050565b6000828211156110a957600080fd5b50900390565b6000826110be57506000611094565b828202828482816110cb57fe5b041461109157600080fd5b6000808284816110e257fe5b04949350505050565b6040805163445c92c560e01b815230600482015290517364fa36acd0d13472fd786b03afc9c52ad5fcf0239163445c92c5916024808301926020929190829003018186803b15801561113c57600080fd5b505afa158015611150573d6000803e3d6000fd5b505050506040513d602081101561116657600080fd5b50511561039d576040805163032453f160e51b815230600482015290517364fa36acd0d13472fd786b03afc9c52ad5fcf0239163648a7e2091602480830192600092919082900301818387803b1580156111bf57600080fd5b505af11580156104c4573d6000803e3d6000fdfea2646970667358221220abb7a91ba61042161509e9d29db3c6b81d3287416e8ad32f421aeea5a8b6787064736f6c634300060c0033

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101425760003560e01c8063aaee69d9116100b8578063cd9488551161007c578063cd94885514610327578063e2d405681461032f578063e6369e4114610337578063edbbc33b1461033f578063f851a44014610347578063f88400711461034f57610142565b8063aaee69d9146102c3578063b3fefcf5146102e9578063b43e92fa146102f1578063be9e2c9a146102f9578063bf92b4ef1461030157610142565b80635499eae61161010a5780635499eae6146101b45780635c854aa9146101bc5780637157c113146101c457806378be0ad4146101cc57806382e4eda4146101f25780638943ec021461023e57610142565b806314657ef0146101475780631e37de4c146101615780633c6b16ab146101695780634e71d92d146101885780634f3a1ff814610190575b600080fd5b61014f61036c565b60408051918252519081900360200190f35b61014f610372565b6101866004803603602081101561017f57600080fd5b5035610378565b005b61018661037b565b61019861039f565b604080516001600160a01b039092168252519081900360200190f35b61014f6103b7565b61014f6103bd565b61014f6103c3565b610186600480360360208110156101e257600080fd5b50356001600160a01b03166103ca565b6102186004803603602081101561020857600080fd5b50356001600160a01b03166103d3565b604080519485526020850193909352838301919091526060830152519081900360800190f35b6101866004803603606081101561025457600080fd5b6001600160a01b038235169160208101359181019060608101604082013564010000000081111561028457600080fd5b82018360208201111561029657600080fd5b803590602001918460018302840111640100000000831117156102b857600080fd5b5090925090506103fa565b610186600480360360208110156102d957600080fd5b50356001600160a01b03166104ca565b61014f610653565b61014f610659565b61019861065f565b61014f6004803603602081101561031757600080fd5b50356001600160a01b0316610677565b610186610861565b61014f61086a565b61014f610872565b61014f610878565b61019861087f565b6101866004803603602081101561036557600080fd5b503561088e565b60025481565b60045481565b50565b3360009081526008602052604090205461039457600080fd5b61039d336108df565b565b7364fa36acd0d13472fd786b03afc9c52ad5fcf02381565b60065481565b60055481565b6223988081565b61037881610b37565b60086020526000908152604090208054600182015460028301546003909301549192909184565b33739fae2529863bd691b4a7171bdfcf33c7ebb10a651461044d576040805162461bcd60e51b81526020600482015260086024820152674f6e6c7920534f5960c01b604482015290519081900360640190fd5b6001600160a01b0384167364fa36acd0d13472fd786b03afc9c52ad5fcf023148061048557506007546001600160a01b038581169116145b1561048f576104c4565b6000602082106104ae57828260208110156104a957600080fd5b503590505b806104b7575060015b6104c2858583610cc6565b505b50505050565b336000908152600860205260409020546104e357600080fd5b6001600160a01b03811660009081526008602052604090205461050557600080fd5b61050f6000610fbb565b6001600160a01b038116600090815260086020526040902060030154610539906301e1338061107f565b6001541161054657600080fd5b6001600160a01b03811660009081526008602052604090205460035461056c908261109a565b6003556001600160a01b038216600090815260086020526040902060019081015490546105b2916105a99184916105a3919061109a565b906110af565b6002549061109a565b6002556001600160a01b0382166000818152600860209081526040808320839055805163a9059cbb60e01b815260048101949094526024840185905251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb9360448083019493928390030190829087803b15801561062957600080fd5b505af115801561063d573d6000803e3d6000fd5b505050506040513d60208110156104c457600080fd5b60035481565b60005481565b739fae2529863bd691b4a7171bdfcf33c7ebb10a6581565b600080546001544391909103904203601982028111156106975750601981025b6001546001600160a01b038516600090815260086020526040902060030154908201908111156106df57506001600160a01b0384166000908152600860205260409020600301545b60006106f6600354846110af90919063ffffffff16565b6002546001600160a01b0388166000908152600860205260408120600101549290910192509061072790849061109a565b9050600061073c6223988080845b04906110af565b6001600160a01b038916600090815260086020526040812054919250906107649083906110af565b90506000610801600354739fae2529863bd691b4a7171bdfcf33c7ebb10a656001600160a01b03166370a08231306040518263ffffffff1660e01b815260040180826001600160a01b0316815260200191505060206040518083038186803b1580156107cf57600080fd5b505afa1580156107e3573d6000803e3d6000fd5b505050506040513d60208110156107f957600080fd5b50519061109a565b90506108178561081183856110af565b906110d6565b6001600160a01b038b16600090815260086020526040902060020154909950670de0b6b3a76400009061084b908b906110af565b8161085257fe5b049a9950505050505050505050565b61039d33610b37565b6301e1338081565b60015481565b6273f78081565b6007546001600160a01b031681565b6007546001600160a01b031633146108da576040805162461bcd60e51b815260206004820152600a60248201526927b7363c9030b236b4b760b11b604482015290519081900360640190fd5b600655565b6108e96000610fbb565b6001546001600160a01b03821660009081526008602052604090206003015481111561092d57506001600160a01b0381166000908152600860205260409020600301545b6001600160a01b03821660009081526008602052604081206001015461095490839061109a565b9050622398808110610b32576000610970622398808084610735565b6001600160a01b038516600090815260086020526040812054919250906109989083906110af565b905060006109b7600254610811846004546110af90919063ffffffff16565b6001600160a01b038716600090815260086020526040902060020154909150670de0b6b3a7640000906109eb9083906110af565b816109f257fe5b049050610a0a8160045461109a90919063ffffffff16565b600455600254610a1a908361109a565b6002556001600160a01b038616600090815260086020526040902060010154610a43908461107f565b6001600160a01b038716600081815260086020908152604080832060010194909455835163a9059cbb60e01b81526004810193909352602483018590529251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb93604480820194929392918390030190829087803b158015610abe57600080fd5b505af1158015610ad2573d6000803e3d6000fd5b505050506040513d6020811015610ae857600080fd5b5050604080516001600160a01b03881681526020810183905281517f47cee97cb7acd717b3c0aa1435d004cd5b3c8c57d70dbceb4e4458bbd60e39d4929181900390910190a15050505b505050565b610b416000610fbb565b6001600160a01b0381166000908152600860205260409020600301546001541015610b6b57600080fd5b6001600160a01b03811660009081526008602052604090205480610b8e57600080fd5b610b97826108df565b600354610ba4908261109a565b6003556001600160a01b038216600090815260086020526040902080546001918201549154610bdb926105a992916105a39161109a565b6002556001600160a01b0382166000818152600860209081526040808320839055805163a9059cbb60e01b815260048101949094526024840185905251739fae2529863bd691b4a7171bdfcf33c7ebb10a659363a9059cbb9360448083019493928390030190829087803b158015610c5257600080fd5b505af1158015610c66573d6000803e3d6000fd5b505050506040513d6020811015610c7c57600080fd5b5050604080516001600160a01b03841681526020810183905281517f141ef67c4a6d3ec2adfb2f66d33c2b11de5b4f34344757554d430570b18a92ec929181900390910190a15050565b6273f780431015610cd657600080fd5b600554821015610ce257fe5b60008111610cef57600080fd5b610cf882610fbb565b6001546001600160a01b038416600090815260086020526040902054826006811115610d22575060065b6064670de0b6b3a7640000600a830260280102046000610d4f610d4862239880886110af565b869061107f565b9050600654811115610da0576040805162461bcd60e51b8152602060048201526015602482015274546f6f206c6f6e67207374616b696e672074696d6560581b604482015290519081900360640190fd5b8315610f02576001600160a01b03881660009081526008602052604090206001015462239880018510610dd657610dd6886108df565b6001600160a01b03881660009081526008602052604090206003015481811115610e3557905080610e0e62239880610811838961109a565b9350600c841115610e1e57600c93505b606460286005860201670de0b6b3a7640000020492505b6001600160a01b03891660009081526008602052604090206002015483108015610e5e57508581115b15610ecc57610e6d858961107f565b610ea6610e7a858b6110af565b6001600160a01b038c16600090815260086020526040902060020154610ea090896110af565b9061107f565b81610ead57fe5b049250670de0b6b3a7640000831115610ecc57670de0b6b3a764000092505b6001600160a01b038916600090815260086020526040902060010154610efd906105a99087906105a3908a9061109a565b600255505b600354610f0f908861107f565b6003556001600160a01b0388166000908152600860205260409020600101859055610f3a848861107f565b6001600160a01b03891660008181526008602090815260409182902084815560028101879055600301859055815192835282018a905281810192909252606081018790526080810183905290517f59314c5dd1994b45a3987ac7bace43129e2616c39c4ce9a995c6cc5e4adc5cb49181900360a00190a15050505050505050565b60005443111561037857610fcd6110eb565b6000805443909155600354604080516370a0823160e01b8152306004820152905161103192850191739fae2529863bd691b4a7171bdfcf33c7ebb10a65916370a0823191602480820192602092909190829003018186803b1580156107cf57600080fd5b60045560015442111561107b5760015443829003904203601982028111156110595750601981025b6003546110679082906110af565b600280549091019055600180549091019055505b5050565b60008282018381101561109157600080fd5b90505b92915050565b6000828211156110a957600080fd5b50900390565b6000826110be57506000611094565b828202828482816110cb57fe5b041461109157600080fd5b6000808284816110e257fe5b04949350505050565b6040805163445c92c560e01b815230600482015290517364fa36acd0d13472fd786b03afc9c52ad5fcf0239163445c92c5916024808301926020929190829003018186803b15801561113c57600080fd5b505afa158015611150573d6000803e3d6000fd5b505050506040513d602081101561116657600080fd5b50511561039d576040805163032453f160e51b815230600482015290517364fa36acd0d13472fd786b03afc9c52ad5fcf0239163648a7e2091602480830192600092919082900301818387803b1580156111bf57600080fd5b505af11580156104c4573d6000803e3d6000fdfea2646970667358221220abb7a91ba61042161509e9d29db3c6b81d3287416e8ad32f421aeea5a8b6787064736f6c634300060c0033