Address Details
contract

0x572564B0efEC39Dd325138187F5DD4e75B17251E

Contract Name
StakingRewards
Creator
0x9ee360–7a65d2 at 0x326c20–38c74d
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
14,703 Transactions
Transfers
15,287 Transfers
Gas Used
1,175,014,932
Last Balance Update
12840156
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
StakingRewards




Optimization enabled
true
Compiler version
v0.8.3+commit.8d00100c




Optimization runs
999999
EVM Version
istanbul




Verified at
2021-05-02T20:52:29.209587Z

Contract source code

// SPDX-License-Identifier: MIT
// solhint-disable not-rely-on-time

pragma solidity ^0.8.3;

import "../../openzeppelin-solidity/contracts/Math.sol";
import "../../openzeppelin-solidity/contracts/SafeMath.sol";
import "../../openzeppelin-solidity/contracts/SafeERC20.sol";
import "../../openzeppelin-solidity/contracts/ReentrancyGuard.sol";

// Inheritance
import "./interfaces/IStakingRewards.sol";
import "./RewardsDistributionRecipient.sol";


// https://docs.synthetix.io/contracts/source/contracts/stakingrewards
// XXX: removed Pausable
contract StakingRewards is IStakingRewards, RewardsDistributionRecipient, ReentrancyGuard {
    using SafeMath for uint256;
    using SafeERC20 for IERC20;

    /* ========== STATE VARIABLES ========== */

    IERC20 public rewardsToken;
    IERC20 public stakingToken;
    uint256 public periodFinish = 0;
    uint256 public rewardRate = 0;
    uint256 public rewardsDuration = 7 days;
    uint256 public lastUpdateTime;
    uint256 public rewardPerTokenStored;

    mapping(address => uint256) public userRewardPerTokenPaid;
    mapping(address => uint256) public rewards;

    uint256 private _totalSupply;
    mapping(address => uint256) private _balances;

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

    constructor(
        address _owner,
        address _rewardsDistribution,
        address _rewardsToken,
        address _stakingToken
    ) Owned(_owner) {
        rewardsToken = IERC20(_rewardsToken);
        stakingToken = IERC20(_stakingToken);
        rewardsDistribution = _rewardsDistribution;
    }

    /* ========== VIEWS ========== */

    function totalSupply() external view override returns (uint256) {
        return _totalSupply;
    }

    function balanceOf(address account) external view override returns (uint256) {
        return _balances[account];
    }

    function lastTimeRewardApplicable() public view override returns (uint256) {
        return Math.min(block.timestamp, periodFinish);
    }

    function rewardPerToken() public view override returns (uint256) {
        if (_totalSupply == 0) {
            return rewardPerTokenStored;
        }
        return
            rewardPerTokenStored.add(
                lastTimeRewardApplicable().sub(lastUpdateTime).mul(rewardRate).mul(1e18).div(_totalSupply)
            );
    }

    function earned(address account) public view override returns (uint256) {
        return _balances[account].mul(rewardPerToken().sub(userRewardPerTokenPaid[account])).div(1e18).add(rewards[account]);
    }

    function getRewardForDuration() external view override returns (uint256) {
        return rewardRate.mul(rewardsDuration);
    }

    /* ========== MUTATIVE FUNCTIONS ========== */

    // XXX: removed notPaused
    function stake(uint256 amount) external override nonReentrant updateReward(msg.sender) {
        require(amount > 0, "Cannot stake 0");
        _totalSupply = _totalSupply.add(amount);
        _balances[msg.sender] = _balances[msg.sender].add(amount);
        stakingToken.safeTransferFrom(msg.sender, address(this), amount);
        emit Staked(msg.sender, amount);
    }

    function withdraw(uint256 amount) public override nonReentrant updateReward(msg.sender) {
        require(amount > 0, "Cannot withdraw 0");
        _totalSupply = _totalSupply.sub(amount);
        _balances[msg.sender] = _balances[msg.sender].sub(amount);
        stakingToken.safeTransfer(msg.sender, amount);
        emit Withdrawn(msg.sender, amount);
    }

    function getReward() public override nonReentrant updateReward(msg.sender) {
        uint256 reward = rewards[msg.sender];
        if (reward > 0) {
            rewards[msg.sender] = 0;
            rewardsToken.safeTransfer(msg.sender, reward);
            emit RewardPaid(msg.sender, reward);
        }
    }

    function exit() external override {
        withdraw(_balances[msg.sender]);
        getReward();
    }

    /* ========== RESTRICTED FUNCTIONS ========== */

    function notifyRewardAmount(uint256 reward) external override onlyRewardsDistribution updateReward(address(0)) {
        if (block.timestamp >= periodFinish) {
            rewardRate = reward.div(rewardsDuration);
        } else {
            uint256 remaining = periodFinish.sub(block.timestamp);
            uint256 leftover = remaining.mul(rewardRate);
            rewardRate = reward.add(leftover).div(rewardsDuration);
        }

        // Ensure the provided reward amount is not more than the balance in the contract.
        // This keeps the reward rate in the right range, preventing overflows due to
        // very high values of rewardRate in the earned and rewardsPerToken functions;
        // Reward + leftover must be less than 2^256 / 10^18 to avoid overflow.
        uint balance = rewardsToken.balanceOf(address(this));
        require(rewardRate <= balance.div(rewardsDuration), "Provided reward too high");

        lastUpdateTime = block.timestamp;
        periodFinish = block.timestamp.add(rewardsDuration);
        emit RewardAdded(reward);
    }

    // End rewards emission earlier
    function updatePeriodFinish(uint timestamp) external onlyOwner updateReward(address(0)) {
        periodFinish = timestamp;
    }

    // Added to support recovering LP Rewards from other systems such as BAL to be distributed to holders
    function recoverERC20(address tokenAddress, uint256 tokenAmount) external onlyOwner {
        require(tokenAddress != address(stakingToken), "Cannot withdraw the staking token");
        IERC20(tokenAddress).safeTransfer(owner, tokenAmount);
        emit Recovered(tokenAddress, tokenAmount);
    }

    function setRewardsDuration(uint256 _rewardsDuration) external onlyOwner {
        require(
            block.timestamp > periodFinish,
            "Previous rewards period must be complete before changing the duration for the new period"
        );
        rewardsDuration = _rewardsDuration;
        emit RewardsDurationUpdated(rewardsDuration);
    }

    /* ========== MODIFIERS ========== */

    modifier updateReward(address account) {
        rewardPerTokenStored = rewardPerToken();
        lastUpdateTime = lastTimeRewardApplicable();
        if (account != address(0)) {
            rewards[account] = earned(account);
            userRewardPerTokenPaid[account] = rewardPerTokenStored;
        }
        _;
    }

    /* ========== EVENTS ========== */

    event RewardAdded(uint256 reward);
    event Staked(address indexed user, uint256 amount);
    event Withdrawn(address indexed user, uint256 amount);
    event RewardPaid(address indexed user, uint256 reward);
    event RewardsDurationUpdated(uint256 newDuration);
    event Recovered(address token, uint256 amount);
}
        

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_owner","internalType":"address"},{"type":"address","name":"_rewardsDistribution","internalType":"address"},{"type":"address","name":"_rewardsToken","internalType":"address"},{"type":"address","name":"_stakingToken","internalType":"address"}]},{"type":"event","name":"OwnerChanged","inputs":[{"type":"address","name":"oldOwner","internalType":"address","indexed":false},{"type":"address","name":"newOwner","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"OwnerNominated","inputs":[{"type":"address","name":"newOwner","internalType":"address","indexed":false}],"anonymous":false},{"type":"event","name":"Recovered","inputs":[{"type":"address","name":"token","internalType":"address","indexed":false},{"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":"RewardsDurationUpdated","inputs":[{"type":"uint256","name":"newDuration","internalType":"uint256","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":"Withdrawn","inputs":[{"type":"address","name":"user","internalType":"address","indexed":true},{"type":"uint256","name":"amount","internalType":"uint256","indexed":false}],"anonymous":false},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"acceptOwnership","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"balanceOf","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"earned","inputs":[{"type":"address","name":"account","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"exit","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"getReward","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"getRewardForDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastTimeRewardApplicable","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"lastUpdateTime","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"nominateNewOwner","inputs":[{"type":"address","name":"_owner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"nominatedOwner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"notifyRewardAmount","inputs":[{"type":"uint256","name":"reward","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"periodFinish","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"recoverERC20","inputs":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenAmount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardPerTokenStored","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardRate","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewards","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"rewardsDistribution","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"rewardsDuration","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"rewardsToken","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardsDistribution","inputs":[{"type":"address","name":"_rewardsDistribution","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"setRewardsDuration","inputs":[{"type":"uint256","name":"_rewardsDuration","internalType":"uint256"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"stake","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"contract IERC20"}],"name":"stakingToken","inputs":[]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"totalSupply","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"updatePeriodFinish","inputs":[{"type":"uint256","name":"timestamp","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"uint256","name":"","internalType":"uint256"}],"name":"userRewardPerTokenPaid","inputs":[{"type":"address","name":"","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"withdraw","inputs":[{"type":"uint256","name":"amount","internalType":"uint256"}]}]
            

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106101ce5760003560e01c806372f702f311610104578063a694fc3a116100a2578063d1af0c7d11610071578063d1af0c7d146103f9578063df136d6514610419578063e9fad8ee14610422578063ebe2b12b1461042a576101ce565b8063a694fc3a146103c2578063c8f33c91146103d5578063cc1a378f146103de578063cd3daf9d146103f1576101ce565b806380faa57d116100de57806380faa57d146103675780638980f11f1461036f5780638b876347146103825780638da5cb5b146103a2576101ce565b806372f702f31461033657806379ba5097146103565780637b0a47ee1461035e576101ce565b8063386a9525116101715780633fc6df6e1161014b5780633fc6df6e1461028857806353a47bb7146102cd578063556f6e6b146102ed57806370a0823114610300576101ce565b8063386a9525146102645780633c6b16ab1461026d5780633d18b91214610280576101ce565b806318160ddd116101ad57806318160ddd1461022e57806319762143146102365780631c1f78eb146102495780632e1a7d4d14610251576101ce565b80628cc262146101d35780630700037d146101f95780631627540c14610219575b600080fd5b6101e66101e13660046117c0565b610433565b6040519081526020015b60405180910390f35b6101e66102073660046117c0565b600c6020526000908152604090205481565b61022c6102273660046117c0565b6104cd565b005b6101e661054f565b61022c6102443660046117c0565b610556565b6101e66105a5565b61022c61025f366004611823565b6105c3565b6101e660085481565b61022c61027b366004611823565b6107bb565b61022c610ab1565b6002546102a89073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101f0565b6001546102a89073ffffffffffffffffffffffffffffffffffffffff1681565b61022c6102fb366004611823565b610c1f565b6101e661030e3660046117c0565b73ffffffffffffffffffffffffffffffffffffffff166000908152600e602052604090205490565b6005546102a89073ffffffffffffffffffffffffffffffffffffffff1681565b61022c610ca3565b6101e660075481565b6101e6610dee565b61022c61037d3660046117da565b610dfc565b6101e66103903660046117c0565b600b6020526000908152604090205481565b6000546102a89073ffffffffffffffffffffffffffffffffffffffff1681565b61022c6103d0366004611823565b610f29565b6101e660095481565b61022c6103ec366004611823565b611110565b6101e6611204565b6004546102a89073ffffffffffffffffffffffffffffffffffffffff1681565b6101e6600a5481565b61022c611252565b6101e660065481565b73ffffffffffffffffffffffffffffffffffffffff81166000908152600c6020908152604080832054600b9092528220546104c591906104bf90670de0b6b3a7640000906104b99061048d90610487611204565b90611275565b73ffffffffffffffffffffffffffffffffffffffff88166000908152600e602052604090205490611288565b90611294565b906112a0565b90505b919050565b6104d56112ac565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081179091556040519081527f906a1c6bd7e3091ea86693dd029a831c19049ce77f1dce2ce0bab1cacbabce22906020015b60405180910390a150565b600d545b90565b61055e6112ac565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60006105be60085460075461128890919063ffffffff16565b905090565b60026003541415610635576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c0060448201526064015b60405180910390fd5b600260035533610643611204565b600a5561064e610dee565b60095573ffffffffffffffffffffffffffffffffffffffff8116156106af5761067681610433565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020908152604080832093909355600a54600b909152919020555b60008211610719576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601160248201527f43616e6e6f742077697468647261772030000000000000000000000000000000604482015260640161062c565b600d546107269083611275565b600d55336000908152600e60205260409020546107439083611275565b336000818152600e602052604090209190915560055461077c9173ffffffffffffffffffffffffffffffffffffffff9091169084611353565b60405182815233907f7084f5476618d8e60b11ef0d7d3f06914655adb8793e28ff7f018d4c76d505d5906020015b60405180910390a250506001600355565b60025473ffffffffffffffffffffffffffffffffffffffff163314610862576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f43616c6c6572206973206e6f742052657761726473446973747269627574696f60448201527f6e20636f6e747261637400000000000000000000000000000000000000000000606482015260840161062c565b600061086c611204565b600a55610877610dee565b60095573ffffffffffffffffffffffffffffffffffffffff8116156108d85761089f81610433565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020908152604080832093909355600a54600b909152919020555b60065442106108f7576008546108ef908390611294565b60075561093a565b6006546000906109079042611275565b905060006109206007548361128890919063ffffffff16565b600854909150610934906104b986846112a0565b60075550505b600480546040517f70a08231000000000000000000000000000000000000000000000000000000008152309281019290925260009173ffffffffffffffffffffffffffffffffffffffff909116906370a082319060240160206040518083038186803b1580156109a957600080fd5b505afa1580156109bd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109e1919061183b565b90506109f86008548261129490919063ffffffff16565b6007541115610a63576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601860248201527f50726f76696465642072657761726420746f6f20686967680000000000000000604482015260640161062c565b426009819055600854610a7691906112a0565b6006556040518381527fde88a922e0d3b88b24e9623efeb464919c6bf9f66857a65e2bfcf2ce87a9433d9060200160405180910390a1505050565b60026003541415610b1e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161062c565b600260035533610b2c611204565b600a55610b37610dee565b60095573ffffffffffffffffffffffffffffffffffffffff811615610b9857610b5f81610433565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020908152604080832093909355600a54600b909152919020555b336000908152600c60205260409020548015610c1657336000818152600c6020526040812055600454610be49173ffffffffffffffffffffffffffffffffffffffff9091169083611353565b60405181815233907fe2403640ba68fed3a2f88b7557551d1993f84b99bb10ff833f0cf8db0c5e0486906020016107aa565b50506001600355565b610c276112ac565b6000610c31611204565b600a55610c3c610dee565b60095573ffffffffffffffffffffffffffffffffffffffff811615610c9d57610c6481610433565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020908152604080832093909355600a54600b909152919020555b50600655565b60015473ffffffffffffffffffffffffffffffffffffffff163314610d4a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603560248201527f596f75206d757374206265206e6f6d696e61746564206265666f726520796f7560448201527f2063616e20616363657074206f776e6572736869700000000000000000000000606482015260840161062c565b6000546001546040805173ffffffffffffffffffffffffffffffffffffffff93841681529290911660208301527fb532073b38c83145e3e5135377a08bf9aab55bc0fd7c1179cd4fb995d2a5159c910160405180910390a160018054600080547fffffffffffffffffffffffff000000000000000000000000000000000000000090811673ffffffffffffffffffffffffffffffffffffffff841617909155169055565b60006105be4260065461142c565b610e046112ac565b60055473ffffffffffffffffffffffffffffffffffffffff83811691161415610eaf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f43616e6e6f7420776974686472617720746865207374616b696e6720746f6b6560448201527f6e00000000000000000000000000000000000000000000000000000000000000606482015260840161062c565b600054610ed69073ffffffffffffffffffffffffffffffffffffffff848116911683611353565b6040805173ffffffffffffffffffffffffffffffffffffffff84168152602081018390527f8c1256b8896378cd5044f80c202f9772b9d77dc85c8a6eb51967210b09bfaa28910160405180910390a15050565b60026003541415610f96576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c00604482015260640161062c565b600260035533610fa4611204565b600a55610faf610dee565b60095573ffffffffffffffffffffffffffffffffffffffff81161561101057610fd781610433565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600c6020908152604080832093909355600a54600b909152919020555b6000821161107a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f43616e6e6f74207374616b652030000000000000000000000000000000000000604482015260640161062c565b600d5461108790836112a0565b600d55336000908152600e60205260409020546110a490836112a0565b336000818152600e60205260409020919091556005546110de9173ffffffffffffffffffffffffffffffffffffffff909116903085611442565b60405182815233907f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d906020016107aa565b6111186112ac565b60065442116111cf576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152605860248201527f50726576696f7573207265776172647320706572696f64206d7573742062652060448201527f636f6d706c657465206265666f7265206368616e67696e67207468652064757260648201527f6174696f6e20666f7220746865206e657720706572696f640000000000000000608482015260a40161062c565b60088190556040518181527ffb46ca5a5e06d4540d6387b930a7c978bce0db5f449ec6b3f5d07c6e1d44f2d390602001610544565b6000600d546000141561121a5750600a54610553565b6105be611249600d546104b9670de0b6b3a7640000611243600754611243600954610487610dee565b90611288565b600a54906112a0565b336000908152600e602052604090205461126b906105c3565b611273610ab1565b565b6000611281828461194e565b9392505050565b60006112818284611911565b600061128182846118d8565b600061128182846118c0565b60005473ffffffffffffffffffffffffffffffffffffffff163314611273576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602f60248201527f4f6e6c792074686520636f6e7472616374206f776e6572206d6179207065726660448201527f6f726d207468697320616374696f6e0000000000000000000000000000000000606482015260840161062c565b60405173ffffffffffffffffffffffffffffffffffffffff83166024820152604481018290526114279084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526114a6565b505050565b600081831061143b5781611281565b5090919050565b60405173ffffffffffffffffffffffffffffffffffffffff808516602483015283166044820152606481018290526114a09085907f23b872dd00000000000000000000000000000000000000000000000000000000906084016113a5565b50505050565b6000611508826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166115b29092919063ffffffff16565b80519091501561142757808060200190518101906115269190611803565b611427576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161062c565b60606115c184846000856115c9565b949350505050565b60608247101561165b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161062c565b843b6116c3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161062c565b6000808673ffffffffffffffffffffffffffffffffffffffff1685876040516116ec9190611853565b60006040518083038185875af1925050503d8060008114611729576040519150601f19603f3d011682016040523d82523d6000602084013e61172e565b606091505b509150915061173e828286611749565b979650505050505050565b60608315611758575081611281565b8251156117685782518084602001fd5b816040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161062c919061186f565b803573ffffffffffffffffffffffffffffffffffffffff811681146104c857600080fd5b6000602082840312156117d1578081fd5b6112818261179c565b600080604083850312156117ec578081fd5b6117f58361179c565b946020939093013593505050565b600060208284031215611814578081fd5b81518015158114611281578182fd5b600060208284031215611834578081fd5b5035919050565b60006020828403121561184c578081fd5b5051919050565b60008251611865818460208701611965565b9190910192915050565b600060208252825180602084015261188e816040850160208701611965565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b600082198211156118d3576118d3611991565b500190565b60008261190c577f4e487b710000000000000000000000000000000000000000000000000000000081526012600452602481fd5b500490565b6000817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff048311821515161561194957611949611991565b500290565b60008282101561196057611960611991565b500390565b60005b83811015611980578181015183820152602001611968565b838111156114a05750506000910152565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fdfea26469706673582212204741156476b1119a35758ba68769b1a7738761c3a0698f422dff39246b0a32a164736f6c63430008030033