ETH Price: $2,480.59 (-0.58%)

Contract

0x4B67B3289fFfCA4f40C0687F44931c75C473c79E
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

Please try again later

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
StakingAccrualERC20

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 16 : StakingAccrualERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;
pragma experimental ABIEncoderV2;

import {Adminable} from "../lib/Adminable.sol";
import {Initializable} from "../lib/Initializable.sol";
import {Address} from "../lib/Address.sol";
import {SafeERC20} from "../lib/SafeERC20.sol";
import {SafeMath} from "../lib/SafeMath.sol";
import {CreditScoreVerifiable} from "../lib/CreditScoreVerifiable.sol";

import {ISablier} from "../global/ISablier.sol";
import {BaseERC20} from "../token/BaseERC20.sol";
import {IPermittableERC20} from "../token/IPermittableERC20.sol";
import {SapphireTypes} from "../debt/sapphire/SapphireTypes.sol";
import {ISapphireCreditScore} from "../debt/sapphire/ISapphireCreditScore.sol";

/**
 * @notice An ERC20 that allows users to deposit a given token, where their
 *         balance is expressed in forms of shares. This will expose users to the
 *         increase and decrease of the balance of the token on the contract.
 *
 *         To withdraw their balance, users must first express their withdrawal
 *         intent, which will trigger a cooldown after which they will be able
 *         to reclaim their share.
 */
contract StakingAccrualERC20 is BaseERC20, CreditScoreVerifiable, Adminable, Initializable {

    /* ========== Libraries ========== */

    using Address for address;
    using SafeERC20 for IPermittableERC20;
    using SafeMath for uint256;

    /* ========== Variables ========== */

    uint256 constant BASE = 1e18;

    uint256 public exitCooldownDuration;

    IPermittableERC20 public stakingToken;

    ISablier public sablierContract;
    uint256 public sablierStreamId;

    /**
     * @notice Cooldown duration to be elapsed for users to exit
     */

    mapping (address => uint256) public cooldowns;

    /* ========== Events ========== */

    event ExitCooldownDurationSet(uint256 _duration);

    event TokensRecovered(uint256 _amount);

    event Staked(address indexed _user, uint256 _amount);

    event ExitCooldownStarted(address indexed _user, uint256 _cooldownEndTimestamp);

    event Exited(address indexed _user, uint256 _amount);

    event SablierContractSet(address _sablierContract);

    event SablierStreamIdSet(uint256 _newStreamId);

    event FundsWithdrawnFromSablier(uint256 _streamId, uint256 _amount);

    event CreditScoreContractSet(address _creditScoreContract);

    /* ========== Constructor (ignore) ========== */

    constructor ()
        public
        BaseERC20("", "", 18)
    {}

    /* ========== Restricted Functions ========== */

    function init(
        string calldata __name,
        string calldata __symbol,
        uint8 __decimals,
        address _stakingToken,
        uint256 _exitCooldownDuration,
        address _creditScoreContract,
        address _sablierContract
    )
        external
        onlyAdmin
        initializer
    {
        _name = __name;
        _symbol = __symbol;
        _decimals = __decimals;
        exitCooldownDuration = _exitCooldownDuration;

        require (
            _stakingToken.isContract(),
            "StakingAccrualERC20: staking token is not a contract"
        );

        require (
            _creditScoreContract.isContract(),
            "StakingAccrualERC20: the credit score contract is invalid"
        );

        require (
            _sablierContract.isContract(),
            "StakingAccrualERC20: the sablier contract is invalid"
        );

        DOMAIN_SEPARATOR = _initDomainSeparator(
            __name,
            "1"
        );

        stakingToken = IPermittableERC20(_stakingToken);
        creditScoreContract = ISapphireCreditScore(_creditScoreContract);
        sablierContract = ISablier(_sablierContract);
    }

    /**
     * @notice Sets the exit cooldown duration
     */
    function setExitCooldownDuration(
        uint256 _duration
    )
        external
        onlyAdmin
    {
        require(
            exitCooldownDuration != _duration,
            "StakingAccrualERC20: the same cooldown is already set"
        );

        exitCooldownDuration = _duration;

        emit ExitCooldownDurationSet(exitCooldownDuration);
    }

    /**
     * @notice Recovers tokens from the totalShares

     */
    function recoverTokens(
        uint256 _amount
    )
        external
        onlyAdmin
    {
        uint256 contractBalance = stakingToken.balanceOf(address(this));

        require (
            _amount <= contractBalance,
            "StakingAccrualERC20: cannot recover more than the balance"
        );

        emit TokensRecovered(_amount);

        stakingToken.safeTransfer(
            getAdmin(),
            _amount
        );
    }

    function setCreditScoreContract(
        address _creditScoreAddress
    )
        external
        onlyAdmin
    {
        require(
            address(creditScoreContract) != _creditScoreAddress,
            "StakingAccrualERC20: the same credit score address is already set"
        );

        require(
            _creditScoreAddress.isContract(),
            "StakingAccrualERC20: the given address is not a contract"
        );

        creditScoreContract = ISapphireCreditScore(_creditScoreAddress);

        emit CreditScoreContractSet(_creditScoreAddress);
    }

    /**
     * @notice Sets the Sablier contract address
     */
    function setSablierContract(
        address _sablierContract
    )
        external
        onlyAdmin
    {
        require (
            _sablierContract.isContract(),
            "StakingAccrualERC20: address is not a contract"
        );

        sablierContract = ISablier(_sablierContract);

        emit SablierContractSet(_sablierContract);
    }

    /**
     * @notice Sets the Sablier stream ID
     */
    function setSablierStreamId(
        uint256 _sablierStreamId
    )
        external
        onlyAdmin
    {
        require (
            sablierStreamId != _sablierStreamId,
            "StakingAccrualERC20: the same stream ID is already set"
        );

        (, address recipient,,,,,,) = sablierContract.getStream(_sablierStreamId);

        require (
            recipient == address(this),
            "StakingAccrualERC20: incorrect stream ID"
        );

        sablierStreamId = _sablierStreamId;

        emit SablierStreamIdSet(sablierStreamId);
    }

    /* ========== Mutative Functions ========== */

    function stake(
        uint256 _amount,
        SapphireTypes.ScoreProof memory _scoreProof
    )
        public
        checkScoreProof(_scoreProof, true)
    {
        claimStreamFunds();

        uint256 cooldownTimestamp = cooldowns[msg.sender];

        require (
            cooldownTimestamp == 0,
            "StakingAccrualERC20: cannot stake during cooldown period"
        );

        // Gets the amount of the staking token locked in the contract
        uint256 totalStakingToken = stakingToken.balanceOf(address(this));
        // Gets the amount of the staked token in existence
        uint256 totalShares = totalSupply();
        // If no the staked token exists, mint it 1:1 to the amount put in
        if (totalShares == 0 || totalStakingToken == 0) {
            _mint(msg.sender, totalStakingToken.add(_amount));
        }
        // Calculate and mint the amount of stToken the Token is worth. The ratio will change overtime, as stToken is burned/minted and Token deposited + gained from fees / withdrawn.
        else {
            uint256 what = _amount.mul(totalShares).div(totalStakingToken);
            _mint(msg.sender, what);
        }
        // Lock the staking token in the contract
        stakingToken.safeTransferFrom(msg.sender, address(this), _amount);

        emit Staked(msg.sender, _amount);
    }

    function stakeWithPermit(
        uint256 _amount,
        uint256 _deadline,
        uint8 _v,
        bytes32 _r,
        bytes32 _s,
        SapphireTypes.ScoreProof memory _scoreProof
    )
        public
    {
        stakingToken.permit(
            msg.sender,
            address(this),
            _amount,
            _deadline,
            _v,
            _r,
            _s
        );
        stake(_amount, _scoreProof);
    }

    /**
     * @notice Starts the exit cooldown. After this call the user won't be able to
     *         stake until they exit.
     */
    function startExitCooldown()
        public
    {
        require (
            balanceOf(msg.sender) > 0,
            "StakingAccrualERC20: user has 0 balance"
        );

        require (
            cooldowns[msg.sender] == 0,
            "StakingAccrualERC20: exit cooldown already started"
        );

        cooldowns[msg.sender] = currentTimestamp().add(exitCooldownDuration);

        emit ExitCooldownStarted(msg.sender, cooldowns[msg.sender]);
    }

    /**
     * @notice Returns the staked tokens proportionally, as long as
     *         the caller's cooldown time has elapsed. Exiting resets
     *         the cooldown so the user can start staking again.
     */
    function exit()
        external
    {
        claimStreamFunds();

        uint256 cooldownTimestamp = cooldowns[msg.sender];
         // Gets the amount of stakedToken in existence
        uint256 totalShares = totalSupply();
        // Amount of shares to exit
        uint256 _share = balanceOf(msg.sender);

        require(
            _share > 0,
            "StakingAccrualERC20: user has 0 balance"
        );

        require(
            currentTimestamp() >= cooldownTimestamp,
            "StakingAccrualERC20: exit cooldown not elapsed"
        );
        require(
            cooldownTimestamp != 0,
            "StakingAccrualERC20: exit cooldown was not initiated"
        );

        // Calculates the amount of staking token the staked token is worth
        uint256 what = _share.mul(stakingToken.balanceOf(address(this))).div(totalShares);
        _burn(msg.sender, _share);
        cooldowns[msg.sender] = 0;
        emit Exited(msg.sender, what);
        stakingToken.safeTransfer(msg.sender, what);
    }

    /**
     * @notice Withdraws from the sablier stream if possible
     */
    function claimStreamFunds()
        public
    {
        if (address(sablierContract) == address(0) || sablierStreamId == 0) {
            return;
        }

        uint256 availableBalance = sablierContract.balanceOf(sablierStreamId, address(this));

        if (availableBalance == 0) {
            return;
        }

        sablierContract.withdrawFromStream(sablierStreamId, availableBalance);

        emit FundsWithdrawnFromSablier(sablierStreamId, availableBalance);
    }

    /* ========== View Functions ========== */

    function getExchangeRate() public view returns (uint256) {
        if (totalSupply() == 0) {
            return 0;
        }
        return stakingToken.balanceOf(address(this)).mul(1e18).div(totalSupply());
    }

    function toStakingToken(uint256 stTokenAmount) public view returns (uint256) {
        if (totalSupply() == 0) {
            return 0;
        }
        return stTokenAmount.mul(stakingToken.balanceOf(address(this))).div(totalSupply());
    }

    function toStakedToken(uint256 token) public view returns (uint256) {
        uint256 stakingBalance = stakingToken.balanceOf(address(this));
        if (stakingBalance == 0) {
            return 0;
        }
        return token.mul(totalSupply()).div(stakingBalance);
    }

    function currentTimestamp()
        public
        view
        returns (uint256)
    {
        return block.timestamp;
    }
}

File 2 of 16 : Adminable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

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

/**
 * @title Adminable
 * @author dYdX
 *
 * @dev EIP-1967 Proxy Admin contract.
 */
contract Adminable {
    /**
     * @dev Storage slot with the admin of the contract.
     *  This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1.
     */
    bytes32 internal constant ADMIN_SLOT =
    0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
    * @dev Modifier to check whether the `msg.sender` is the admin.
    *  If it is, it will run the function. Otherwise, it will revert.
    */
    modifier onlyAdmin() {
        require(
            msg.sender == getAdmin(),
            "Adminable: caller is not admin"
        );
        _;
    }

    /**
     * @return The EIP-1967 proxy admin
     */
    function getAdmin()
        public
        view
        returns (address)
    {
        return address(uint160(uint256(Storage.load(ADMIN_SLOT))));
    }
}

File 3 of 16 : Initializable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;

/**
 * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
 * behind a proxy. Since a proxied contract can't have a constructor, it's common to move constructor logic to an
 * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
 * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
 *
 * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
 * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
 *
 * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
 * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
 *
 * Taken from OpenZeppelin
 */
contract Initializable {
    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

    /**
     * @dev Indicates that the contract is in the process of being initialized.
     */
    bool private _initializing;

    /**
     * @dev Modifier to protect an initializer function from being invoked twice.
     */
    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

File 4 of 16 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;

/**
 * @dev Collection of functions related to the address type.
 *      Take from OpenZeppelin at
 *      https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/Address.sol
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        // solium-disable-next-line security/no-inline-assembly
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

File 5 of 16 : SafeERC20.sol
// SPDX-License-Identifier: GPL-3.0-or-later

pragma solidity ^0.5.16;

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

// helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
library SafeERC20 {
    function safeApprove(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('approve(address,uint256)')));
        /* solium-disable-next-line */
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(0x095ea7b3, to, value)
        );

        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: APPROVE_FAILED"
        );
    }

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transfer(address,uint256)')));
        /* solium-disable-next-line */
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(0xa9059cbb, to, value)
        );

        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: TRANSFER_FAILED"
        );
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
        /* solium-disable-next-line */
        (bool success, bytes memory data) = address(token).call(
            abi.encodeWithSelector(
                0x23b872dd,
                from,
                to,
                value
            )
        );

        require(
            success && (data.length == 0 || abi.decode(data, (bool))),
            "SafeERC20: TRANSFER_FROM_FAILED"
        );
    }
}

File 6 of 16 : SafeMath.sol
pragma solidity ^0.5.16;

library SafeMath {
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        if (a == 0) {
            return 0;
        }

        uint256 c = a * b;
        require(c / a == b, "SafeMath: multiplication overflow");

        return c;
    }

    function div(uint256 a, uint256 b) internal pure returns (uint256) {

        require(b > 0, "SafeMath: division by zero");
        uint256 c = a / b;

        return c;
    }

    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        require(b <= a, "SafeMath: subtraction overflow");
        uint256 c = a - b;

        return c;
    }

    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, "SafeMath: addition overflow");

        return c;
    }
}

File 7 of 16 : CreditScoreVerifiable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

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

import {ISapphireCreditScore} from "../debt/sapphire/ISapphireCreditScore.sol";
import {SapphireTypes} from "../debt/sapphire/SapphireTypes.sol";

/**
 * @dev Provides the ability of verifying users' credit scores
 */
contract CreditScoreVerifiable {

    using Address for address;

    ISapphireCreditScore public creditScoreContract;

    /**
     * @dev Verifies that the proof is passed if the score is required, and
     *      validates it.
     */
    modifier checkScoreProof(
        SapphireTypes.ScoreProof memory _scoreProof,
        bool _isScoreRequired
    ) {
        if (_scoreProof.account != address(0)) {
            require (
                msg.sender == _scoreProof.account,
                "CreditScoreVerifiable: proof does not belong to the caller"
            );
        }

        bool isProofPassed = _scoreProof.merkleProof.length > 0;

        if (_isScoreRequired) {
            require(
                isProofPassed,
                "CreditScoreVerifiable: proof is required but it is not passed"
            );
        }

        if (isProofPassed) {
            creditScoreContract.verifyAndUpdate(_scoreProof);
        }
        _;
    }
}

File 8 of 16 : ISablier.sol
pragma solidity ^0.5.16;

/**
 * @title ISablier
 * @author Sablier
 */
interface ISablier {
    /**
     * @notice Emits when a stream is successfully created.
     */
    event CreateStream(
        uint256 indexed streamId,
        address indexed sender,
        address indexed recipient,
        uint256 deposit,
        address tokenAddress,
        uint256 startTime,
        uint256 stopTime
    );

    /**
     * @notice Emits when the recipient of a stream withdraws a portion or all their pro rata share of the stream.
     */
    event WithdrawFromStream(uint256 indexed streamId, address indexed recipient, uint256 amount);

    /**
     * @notice Emits when a stream is successfully cancelled and tokens are transferred back on a pro rata basis.
     */
    event CancelStream(
        uint256 indexed streamId,
        address indexed sender,
        address indexed recipient,
        uint256 senderBalance,
        uint256 recipientBalance
    );

    function balanceOf(uint256 streamId, address who) external view returns (uint256 balance);

    function getStream(uint256 streamId)
        external
        view
        returns (
            address sender,
            address recipient,
            uint256 deposit,
            address token,
            uint256 startTime,
            uint256 stopTime,
            uint256 remainingBalance,
            uint256 ratePerSecond
        );

    function createStream(
        address recipient,
        uint256 deposit,
        address tokenAddress,
        uint256 startTime,
        uint256 stopTime
    )
        external
        returns (uint256 streamId);

    function withdrawFromStream(uint256 streamId, uint256 funds) external returns (bool);

    function cancelStream(uint256 streamId) external returns (bool);
}

File 9 of 16 : BaseERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.16;

import {SafeMath} from "../lib/SafeMath.sol";

import {IERC20Metadata} from "./IERC20Metadata.sol";
import {Permittable} from "./Permittable.sol";

/**
 * @title ERC20 Token
 *
 * Basic ERC20 Implementation
 */
contract BaseERC20 is IERC20Metadata, Permittable {

    using SafeMath for uint256;

    mapping (address => uint256) private _balances;

    mapping (address => mapping (address => uint256)) internal _allowances;

    uint8   internal _decimals;
    uint256 private _totalSupply;

    string  internal _name;
    string  internal _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
     * a default value of 18.
     *
     * All three of these values are immutable: they can only be set once during
     * construction.
     */
    constructor (
        string memory name,
        string memory symbol,
        uint8         decimals
    )
        public
        Permittable(name, "1")
    {
        _name = name;
        _symbol = symbol;
        _decimals = decimals;
    }

    /**
     * @dev Returns the name of the token.
     */
    function name()
        public
        view
        returns (string memory)
    {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol()
        public
        view
        returns (string memory)
    {
        return _symbol;
    }

    /**
     * @dev Returns the number of decimals used to get its user representation.
     * For example, if `decimals` equals `2`, a balance of `505` tokens should
     * be displayed to a user as `5,05` (`505 / 10 ** 2`).
     *
     * Tokens usually opt for a value of 18, imitating the relationship between
     * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
     * called.
     *
     * NOTE: This information is only used for _display_ purposes: it in
     * no way affects any of the arithmetic of the contract, including
     * {IERC20-balanceOf} and {IERC20-transfer}.
     */
    function decimals()
        public
        view
        returns (uint8)
    {
        return _decimals;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply()
        public
        view
        returns (uint256)
    {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(
        address account
    )
        public
        view
        returns (uint256)
    {
        return _balances[account];
    }

    /**
     * @dev See {IERC20-transfer}.
     *
     * Requirements:
     *
     * - `recipient` cannot be the zero address.
     * - the caller must have a balance of at least `amount`.
     */
    function transfer(
        address recipient,
        uint256 amount
    )
        public
        returns (bool)
    {
        _transfer(msg.sender, recipient, amount);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(
        address owner,
        address spender
    )
        public
        view
        returns (uint256)
    {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     */
    function approve(
        address spender,
        uint256 amount
    )
        public
        returns (bool)
    {
        _approve(msg.sender, spender, amount);
        return true;
    }

    /**
     * @dev See {IERC20-transferFrom}.
     *
     * Emits an {Approval} event indicating the updated allowance. This is not
     * required by the EIP. See the note at the beginning of {ERC20};
     *
     * Requirements:
     * - `sender` and `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     * - the caller must have allowance for ``sender``'s tokens of at least
     * `amount`.
     */
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    )
        public
        returns (bool)
    {
        _transfer(sender, recipient, amount);
        _approve(
            sender,
            msg.sender,
            _allowances[sender][msg.sender].sub(amount)
        );

        return true;
    }

    /**
    * @dev Approve by signature.
    *
    * Adapted from Uniswap's UniswapV2ERC20 and MakerDAO's Dai contracts:
    * https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol
    * https://github.com/makerdao/dss/blob/master/src/dai.sol
    */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        public
    {
        _permit(
            owner,
            spender,
            value,
            deadline,
            v,
            r,
            s
        );
        _approve(owner, spender, value);
    }

    /**
     * @dev Moves tokens `amount` from `sender` to `recipient`.
     *
     * This is internal function is equivalent to {transfer}, and can be used to
     * e.g. implement automatic token fees, slashing mechanisms, etc.
     *
     * Emits a {Transfer} event.
     *
     * Requirements:
     *
     * - `sender` cannot be the zero address.
     * - `recipient` cannot be the zero address.
     * - `sender` must have a balance of at least `amount`.
     */
    function _transfer(
        address sender,
        address recipient,
        uint256 amount
    )
        internal
    {
        require(
            sender != address(0),
            "ERC20: transfer from the zero address"
        );

        require(
            recipient != address(0),
            "ERC20: transfer to the zero address"
        );

        _balances[sender] = _balances[sender].sub(amount);

        _balances[recipient] = _balances[recipient].add(amount);
        emit Transfer(sender, recipient, amount);
    }

    /** @dev Creates `amount` tokens and assigns them to `account`, increasing
     * the total supply.
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * Requirements
     *
     * - `to` cannot be the zero address.
     */
    function _mint(
        address account,
        uint256 amount
    )
        internal
    {
        require(account != address(0), "ERC20: mint to the zero address");

        _totalSupply = _totalSupply.add(amount);
        _balances[account] = _balances[account].add(amount);
        emit Transfer(address(0), account, amount);
    }

    /**
     * @dev Destroys `amount` tokens from `account`, reducing the
     * total supply.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * Requirements
     *
     * - `account` cannot be the zero address.
     * - `account` must have at least `amount` tokens.
     */
    function _burn(
        address account,
        uint256 amount
    )
        internal
    {
        require(account != address(0), "ERC20: burn from the zero address");

        _balances[account] = _balances[account].sub(amount);
        _totalSupply = _totalSupply.sub(amount);
        emit Transfer(account, address(0), amount);
    }

    /**
     * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
     *
     * This internal function is equivalent to `approve`, and can be used to
     * e.g. set automatic allowances for certain subsystems, etc.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `owner` cannot be the zero address.
     * - `spender` cannot be the zero address.
     */
    function _approve(
        address owner,
        address spender,
        uint256 amount
    )
        internal
    {
        require(owner != address(0), "ERC20: approve from the zero address");
        require(spender != address(0), "ERC20: approve to the zero address");

        _allowances[owner][spender] = amount;
        emit Approval(owner, spender, amount);
    }
}

File 10 of 16 : IPermittableERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.5.16;

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

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
contract IPermittableERC20 is IERC20 {

    /**
     * @notice Approve token with signature
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        external;
}

File 11 of 16 : SapphireTypes.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;
pragma experimental ABIEncoderV2;

library SapphireTypes {

    struct ScoreProof {
        address account;
        uint256 score;
        bytes32[] merkleProof;
    }

    struct CreditScore {
        uint256 score;
        uint256 lastUpdated;
    }

    struct Vault {
        uint256 collateralAmount;
        uint256 borrowedAmount;
    }

    enum Operation {
        Deposit,
        Withdraw,
        Borrow,
        Repay,
        Liquidate
    }

    struct Action {
        uint256 amount;
        Operation operation;
        address userToLiquidate;
    }

}

File 12 of 16 : ISapphireCreditScore.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;
pragma experimental ABIEncoderV2;

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

interface ISapphireCreditScore {
    function updateMerkleRoot(bytes32 newRoot) external;

    function setMerkleRootUpdater(address merkleRootUpdater) external;

    function verifyAndUpdate(SapphireTypes.ScoreProof calldata proof) external returns (uint256, uint16);

    function getLastScore(address user) external view returns (uint256, uint16, uint256);

    function setMerkleRootDelay(uint256 delay) external;

    function setPause(bool status) external;
}

File 13 of 16 : Storage.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

library Storage {

    /**
     * @dev Performs an SLOAD and returns the data in the slot.
     */
    function load(
        bytes32 slot
    )
        internal
        view
        returns (bytes32)
    {
        bytes32 result;
        /* solium-disable-next-line security/no-inline-assembly */
        assembly {
            result := sload(slot)
        }
        return result;
    }

    /**
     * @dev Performs an SSTORE to save the value to the slot.
     */
    function store(
        bytes32 slot,
        bytes32 value
    )
        internal
    {
        /* solium-disable-next-line security/no-inline-assembly */
        assembly {
            sstore(slot, value)
        }
    }
}

File 14 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.5.16;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(
        address indexed from,
        address indexed to,
        uint256 value
    );

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

File 15 of 16 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;

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

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 *
 * _Available since v4.1._
 */
contract IERC20Metadata is IERC20 {
    /**
     * @dev Returns the name of the token.
     */
    function name() external view returns (string memory);

    /**
     * @dev Returns the symbol of the token.
     */
    function symbol() external view returns (string memory);

    /**
     * @dev Returns the decimals places of the token.
     */
    function decimals() external view returns (uint8);
}

File 16 of 16 : Permittable.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.5.16;

contract Permittable {

    /* ============ Variables ============ */

    bytes32 public DOMAIN_SEPARATOR;

    mapping (address => uint256) public nonces;

    /* ============ Constants ============ */

    // keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    /* solium-disable-next-line */
    bytes32 public constant PERMIT_TYPEHASH = 0x6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9;

    /* ============ Constructor ============ */

    constructor(
        string memory name,
        string memory version
    )
        public
    {
        DOMAIN_SEPARATOR = _initDomainSeparator(name, version);
    }

    /**
     * @dev Initializes EIP712 DOMAIN_SEPARATOR based on the current contract and chain ID.
     */
    function _initDomainSeparator(
        string memory name,
        string memory version
    )
        internal
        view
        returns (bytes32)
    {
        uint256 chainID;
        /* solium-disable-next-line */
        assembly {
            chainID := chainid()
        }

        return keccak256(
            abi.encode(
                keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                chainID,
                address(this)
            )
        );
    }

    /**
    * @dev Approve by signature.
    *      Caution: If an owner signs a permit with no deadline, the corresponding spender
    *      can call permit at any time in the future to mess with the nonce, invalidating
    *      signatures to other spenders, possibly making their transactions fail.
    *
    * Adapted from Uniswap's UniswapV2ERC20 and MakerDAO's Dai contracts:
    * https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol
    * https://github.com/makerdao/dss/blob/master/src/dai.sol
    */
    function _permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    )
        internal
    {
        require(
            deadline == 0 || deadline >= block.timestamp,
            "Permittable: Permit expired"
        );

        require(
            spender != address(0),
            "Permittable: spender cannot be 0x0"
        );

        bytes32 digest = keccak256(
            abi.encodePacked(
                "\x19\x01",
                DOMAIN_SEPARATOR,
                keccak256(
                    abi.encode(
                    PERMIT_TYPEHASH,
                    owner,
                    spender,
                    value,
                    nonces[owner]++,
                    deadline
                )
            )
        ));

        address recoveredAddress = ecrecover(
            digest,
            v,
            r,
            s
        );

        require(
            recoveredAddress != address(0) && owner == recoveredAddress,
            "Permittable: Signature invalid"
        );

    }

}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_creditScoreContract","type":"address"}],"name":"CreditScoreContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"ExitCooldownDurationSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_cooldownEndTimestamp","type":"uint256"}],"name":"ExitCooldownStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Exited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_streamId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"FundsWithdrawnFromSablier","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_sablierContract","type":"address"}],"name":"SablierContractSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_newStreamId","type":"uint256"}],"name":"SablierStreamIdSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_user","type":"address"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"Staked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"TokensRecovered","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":true,"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"claimStreamFunds","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"cooldowns","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"creditScoreContract","outputs":[{"internalType":"contract ISapphireCreditScore","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"currentTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"exit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"exitCooldownDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"getExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"__name","type":"string"},{"internalType":"string","name":"__symbol","type":"string"},{"internalType":"uint8","name":"__decimals","type":"uint8"},{"internalType":"address","name":"_stakingToken","type":"address"},{"internalType":"uint256","name":"_exitCooldownDuration","type":"uint256"},{"internalType":"address","name":"_creditScoreContract","type":"address"},{"internalType":"address","name":"_sablierContract","type":"address"}],"name":"init","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"recoverTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"sablierContract","outputs":[{"internalType":"contract ISablier","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"sablierStreamId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_creditScoreAddress","type":"address"}],"name":"setCreditScoreContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setExitCooldownDuration","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_sablierContract","type":"address"}],"name":"setSablierContract","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_sablierStreamId","type":"uint256"}],"name":"setSablierStreamId","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct SapphireTypes.ScoreProof","name":"_scoreProof","type":"tuple"}],"name":"stake","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_deadline","type":"uint256"},{"internalType":"uint8","name":"_v","type":"uint8"},{"internalType":"bytes32","name":"_r","type":"bytes32"},{"internalType":"bytes32","name":"_s","type":"bytes32"},{"components":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"score","type":"uint256"},{"internalType":"bytes32[]","name":"merkleProof","type":"bytes32[]"}],"internalType":"struct SapphireTypes.ScoreProof","name":"_scoreProof","type":"tuple"}],"name":"stakeWithPermit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"stakingToken","outputs":[{"internalType":"contract IPermittableERC20","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"startExitCooldown","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"token","type":"uint256"}],"name":"toStakedToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"uint256","name":"stTokenAmount","type":"uint256"}],"name":"toStakingToken","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]

60806040523480156200001157600080fd5b506040518060200160405280600081525060405180602001604052806000815250601282604051806040016040528060018152602001603160f81b815250620000618282620000af60201b60201c565b600055505082516200007b90600690602086019062000111565b5081516200009190600790602085019062000111565b506004805460ff191660ff9290921691909117905550620002ce9050565b6040516000904690620000c2906200024e565b6040518091039020848051906020012084805190602001208330604051602001620000f295949392919062000261565b6040516020818303038152906040528051906020012091505092915050565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106200015457805160ff191683800117855562000184565b8280016001018555821562000184579182015b828111156200018457825182559160200191906001019062000167565b506200019292915062000196565b5090565b620001b391905b808211156200019257600081556001016200019d565b90565b620001c181620002bc565b82525050565b620001c181620001b3565b6000620001e1605283620002b7565b7f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320602082015271766572696679696e67436f6e74726163742960701b604082015260520192915050565b60006200025b82620001d2565b92915050565b60a08101620002718288620001c7565b620002806020830187620001c7565b6200028f6040830186620001c7565b6200029e6060830185620001c7565b620002ad6080830184620001b6565b9695505050505050565b919050565b60006001600160a01b0382166200025b565b61368380620002de6000396000f3fe608060405234801561001057600080fd5b50600436106102115760003560e01c806371dc479511610125578063d505accf116100ad578063e1f7c2c91161007c578063e1f7c2c91461040f578063e6aa216c14610422578063e9fad8ee1461042a578063f8356c8114610432578063fe686b481461044557610211565b8063d505accf146103c3578063dcc42a96146103d6578063dd62ed3e146103e9578063df45d0b3146103fc57610211565b8063a6a14292116100f4578063a6a142921461036f578063a762498714610382578063a9059cbb14610395578063bcdb699f146103a8578063c7d595fa146103b057610211565b806371dc47951461034457806372f702f31461034c5780637ecebe001461035457806395d89b411461036757610211565b806330599fc5116101a8578063605c8cc611610177578063605c8cc6146102f9578063639cdcce146103015780636aca3e97146103095780636e9960c31461031c57806370a082311461033157610211565b806330599fc5146102bf57806330adf81f146102d4578063313ce567146102dc5780633644e515146102f157610211565b806318160ddd116101e457806318160ddd1461028957806318272fc5146102915780631e2ff94f146102a457806323b872dd146102ac57610211565b806301320fe21461021657806303a42b6f1461023f57806306fdde0314610254578063095ea7b314610269575b600080fd5b610229610224366004612040565b61044d565b60405161023691906131c9565b60405180910390f35b61024761045f565b60405161023691906132b2565b61025c61046e565b60405161023691906132c0565b61027c610277366004612239565b610505565b60405161023691906131bb565b61022961051c565b61022961029f36600461235a565b610522565b6102296105e6565b61027c6102ba3660046120a0565b6105ea565b6102d26102cd36600461235a565b610642565b005b610229610785565b6102e46107a9565b604051610236919061352b565b6102296107b2565b6102d26107b8565b610247610931565b6102d2610317366004612040565b610940565b6103246109f1565b6040516102369190613102565b61022961033f366004612040565b610a21565b610229610a3c565b610247610a42565b610229610362366004612040565b610a51565b61025c610a63565b6102d261037d36600461240e565b610ac4565b6102d2610390366004612287565b610b44565b61027c6103a3366004612239565b610d61565b610229610d6e565b6102d26103be36600461235a565b610d74565b6102d26103d136600461219d565b610e03565b6102d26103e436600461235a565b610e26565b6102296103f7366004612066565b610f7d565b61022961040a36600461235a565b610fa8565b6102d261041d366004612040565b61105a565b610229611139565b6102d26111f4565b6102d2610440366004612396565b61133e565b6102d26115b1565b600d6020526000908152604090205481565b6008546001600160a01b031681565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104fa5780601f106104cf576101008083540402835291602001916104fa565b820191906000526020600020905b8154815290600101906020018083116104dd57829003601f168201915b505050505090505b90565b600061051233848461166d565b5060015b92915050565b60055490565b600061052c61051c565b610538575060006105e1565b6105de61054361051c565b600a546040516370a0823160e01b81526105d2916001600160a01b0316906370a0823190610575903090600401613102565b60206040518083038186803b15801561058d57600080fd5b505afa1580156105a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105c59190810190612378565b859063ffffffff61172116565b9063ffffffff61175b16565b90505b919050565b4290565b60006105f7848484611790565b6001600160a01b038416600090815260036020908152604080832033808552925290912054610637918691610632908663ffffffff61188c16565b61166d565b5060015b9392505050565b61064a6109f1565b6001600160a01b0316336001600160a01b0316146106835760405162461bcd60e51b815260040161067a906133a1565b60405180910390fd5b600a546040516370a0823160e01b81526000916001600160a01b0316906370a08231906106b4903090600401613102565b60206040518083038186803b1580156106cc57600080fd5b505afa1580156106e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107049190810190612378565b9050808211156107265760405162461bcd60e51b815260040161067a906134b1565b7fbe842a2fe0dcb4d753f6d8de0884c9fe5e49f6c1e9d4c1b61d2a0c8fe16506318260405161075591906131c9565b60405180910390a16107816107686109f1565b600a546001600160a01b0316908463ffffffff6118b416565b5050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60045460ff1690565b60005481565b600b546001600160a01b031615806107d05750600c54155b156107da5761092f565b600b54600c54604051631b2b776160e11b81526000926001600160a01b031691633656eec29161080f91903090600401613502565b60206040518083038186803b15801561082757600080fd5b505afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085f9190810190612378565b90508061086c575061092f565b600b54600c54604051631ea6cb1b60e21b81526001600160a01b0390921691637a9b2c6c9161089f91859060040161351d565b602060405180830381600087803b1580156108b957600080fd5b505af11580156108cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108f19190810190612269565b507fe6643f7201409bc3c3a5fd11c50564bb2e4e13479cb71fbb48e8079486106d31600c548260405161092592919061351d565b60405180910390a1505b565b600b546001600160a01b031681565b6109486109f1565b6001600160a01b0316336001600160a01b0316146109785760405162461bcd60e51b815260040161067a906133a1565b61098a816001600160a01b03166119a2565b6109a65760405162461bcd60e51b815260040161067a90613441565b600b80546001600160a01b0319166001600160a01b0383161790556040517f84a373b9623d96e07e5945bf517d7f63701b00ec16467c73ad6b1f28870f986c90610925908390613102565b6000610a1c7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61036119a8565b905090565b6001600160a01b031660009081526002602052604090205490565b600c5481565b600a546001600160a01b031681565b60016020526000908152604090205481565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104fa5780601f106104cf576101008083540402835291602001916104fa565b600a5460405163d505accf60e01b81526001600160a01b039091169063d505accf90610b0090339030908b908b908b908b908b90600401613110565b600060405180830381600087803b158015610b1a57600080fd5b505af1158015610b2e573d6000803e3d6000fd5b50505050610b3c868261133e565b505050505050565b610b4c6109f1565b6001600160a01b0316336001600160a01b031614610b7c5760405162461bcd60e51b815260040161067a906133a1565b600854600160a81b900460ff1680610b9e5750600854600160a01b900460ff16155b610bba5760405162461bcd60e51b815260040161067a906133d1565b600854600160a81b900460ff16158015610bf1576008805460ff60a01b1960ff60a81b19909116600160a81b1716600160a01b1790555b610bfd60068b8b611e20565b50610c0a60078989611e20565b506004805460ff191660ff88161790556009849055610c316001600160a01b0386166119a2565b610c4d5760405162461bcd60e51b815260040161067a906132e1565b610c5f836001600160a01b03166119a2565b610c7b5760405162461bcd60e51b815260040161067a90613341565b610c8d826001600160a01b03166119a2565b610ca95760405162461bcd60e51b815260040161067a906133b1565b610d018a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506119ac9050565b600055600a80546001600160a01b038088166001600160a01b03199283161790925560088054868416908316179055600b8054928516929091169190911790558015610d55576008805460ff60a81b191690555b50505050505050505050565b6000610512338484611790565b60095481565b610d7c6109f1565b6001600160a01b0316336001600160a01b031614610dac5760405162461bcd60e51b815260040161067a906133a1565b806009541415610dce5760405162461bcd60e51b815260040161067a90613421565b60098190556040517fba0e1ced950ddef70ab40c6fd5e010571d362990d7e276e25a78ce54e9706c3c906109259083906131c9565b610e1287878787878787611a0a565b610e1d87878761166d565b50505050505050565b610e2e6109f1565b6001600160a01b0316336001600160a01b031614610e5e5760405162461bcd60e51b815260040161067a906133a1565b80600c541415610e805760405162461bcd60e51b815260040161067a90613451565b600b5460405163894e9a0d60e01b81526000916001600160a01b03169063894e9a0d90610eb19085906004016131c9565b6101006040518083038186803b158015610eca57600080fd5b505afa158015610ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f0291908101906120ed565b505050505050915050306001600160a01b0316816001600160a01b031614610f3c5760405162461bcd60e51b815260040161067a906134a1565b600c8290556040517ff7c865e734a76f428766e3240c17d5131a683c20e4885977402727570df0e1bb90610f719084906131c9565b60405180910390a15050565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b600a546040516370a0823160e01b815260009182916001600160a01b03909116906370a0823190610fdd903090600401613102565b60206040518083038186803b158015610ff557600080fd5b505afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061102d9190810190612378565b90508061103e5760009150506105e1565b61063b816105d261104d61051c565b869063ffffffff61172116565b6110626109f1565b6001600160a01b0316336001600160a01b0316146110925760405162461bcd60e51b815260040161067a906133a1565b6008546001600160a01b03828116911614156110c05760405162461bcd60e51b815260040161067a906132f1565b6110d2816001600160a01b03166119a2565b6110ee5760405162461bcd60e51b815260040161067a90613431565b600880546001600160a01b0319166001600160a01b0383161790556040517ff5280746e16d30bc414b77f117a4fa3a918ce04d0d6789e62ddbb13a1bb03e3090610925908390613102565b600061114361051c565b61114f57506000610502565b610a1c61115a61051c565b600a546040516370a0823160e01b81526105d291670de0b6b3a7640000916001600160a01b03909116906370a0823190611198903090600401613102565b60206040518083038186803b1580156111b057600080fd5b505afa1580156111c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111e89190810190612378565b9063ffffffff61172116565b6111fc6107b8565b336000908152600d60205260408120549061121561051c565b9050600061122233610a21565b9050600081116112445760405162461bcd60e51b815260040161067a90613491565b8261124d6105e6565b101561126b5760405162461bcd60e51b815260040161067a90613351565b826112885760405162461bcd60e51b815260040161067a906134d1565b600a546040516370a0823160e01b81526000916112c59185916105d2916001600160a01b03909116906370a0823190610575903090600401613102565b90506112d13383611b96565b336000818152600d602052604080822091909155517f920bb94eb3842a728db98228c375ff6b00c5bc5a54fac6736155517a0a20a61a906113139084906131c9565b60405180910390a2600a54611338906001600160a01b0316338363ffffffff6118b416565b50505050565b805181906001906001600160a01b03161561137c5781516001600160a01b0316331461137c5760405162461bcd60e51b815260040161067a90613401565b604082015151151581156113a757806113a75760405162461bcd60e51b815260040161067a906134c1565b801561143157600854604051631f33cd1960e21b81526001600160a01b0390911690637ccf3464906113dd9086906004016134f1565b6040805180830381600087803b1580156113f657600080fd5b505af115801561140a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061142e91908101906123de565b50505b6114396107b8565b336000908152600d602052604090205480156114675760405162461bcd60e51b815260040161067a90613371565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611498903090600401613102565b60206040518083038186803b1580156114b057600080fd5b505afa1580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114e89190810190612378565b905060006114f461051c565b9050801580611501575081155b156115245761151f3361151a848b63ffffffff611c5e16565b611c83565b611548565b600061153a836105d28b8563ffffffff61172116565b90506115463382611c83565b505b600a54611566906001600160a01b031633308b63ffffffff611d3716565b336001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8960405161159f91906131c9565b60405180910390a25050505050505050565b60006115bc33610a21565b116115d95760405162461bcd60e51b815260040161067a90613491565b336000908152600d6020526040902054156116065760405162461bcd60e51b815260040161067a90613301565b6116206009546116146105e6565b9063ffffffff611c5e16565b336000818152600d6020526040908190208390555190917f48a37de01454fea7daf610b49703424ca91f1fc6392f1a4fc90f36676f568d389161166391906131c9565b60405180910390a2565b6001600160a01b0383166116935760405162461bcd60e51b815260040161067a90613481565b6001600160a01b0382166116b95760405162461bcd60e51b815260040161067a90613321565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906117149085906131c9565b60405180910390a3505050565b60008261173057506000610516565b8282028284828161173d57fe5b041461063b5760405162461bcd60e51b815260040161067a90613411565b600080821161177c5760405162461bcd60e51b815260040161067a90613391565b600082848161178757fe5b04949350505050565b6001600160a01b0383166117b65760405162461bcd60e51b815260040161067a90613471565b6001600160a01b0382166117dc5760405162461bcd60e51b815260040161067a906132d1565b6001600160a01b038316600090815260026020526040902054611805908263ffffffff61188c16565b6001600160a01b03808516600090815260026020526040808220939093559084168152205461183a908263ffffffff611c5e16565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906117149085906131c9565b6000828211156118ae5760405162461bcd60e51b815260040161067a90613381565b50900390565b60006060846001600160a01b031663a9059cbb85856040516024016118da9291906131a0565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161191391906130ba565b6000604051808303816000865af19150503d8060008114611950576040519150601f19603f3d011682016040523d82523d6000602084013e611955565b606091505b509150915081801561197f57508051158061197f57508080602001905161197f9190810190612269565b61199b5760405162461bcd60e51b815260040161067a90613311565b5050505050565b3b151590565b5490565b60405160009046906119bd906130f7565b60405180910390208480519060200120848051906020012083306040516020016119eb959493929190613231565b6040516020818303038152906040528051906020012091505092915050565b831580611a175750428410155b611a335760405162461bcd60e51b815260040161067a906133f1565b6001600160a01b038616611a595760405162461bcd60e51b815260040161067a906133c1565b600080546001600160a01b03891682526001602081815260408085208054938401905551611ab3927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d9290918d91016131d7565b60405160208183030381529060405280519060200120604051602001611ada9291906130c6565b604051602081830303815290604052805190602001209050600060018286868660405160008152602001604052604051611b17949392919061327d565b6020604051602081039080840390855afa158015611b39573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611b6f5750806001600160a01b0316896001600160a01b0316145b611b8b5760405162461bcd60e51b815260040161067a90613361565b505050505050505050565b6001600160a01b038216611bbc5760405162461bcd60e51b815260040161067a90613461565b6001600160a01b038216600090815260026020526040902054611be5908263ffffffff61188c16565b6001600160a01b038316600090815260026020526040902055600554611c11908263ffffffff61188c16565b6005556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c529085906131c9565b60405180910390a35050565b60008282018381101561063b5760405162461bcd60e51b815260040161067a90613331565b6001600160a01b038216611ca95760405162461bcd60e51b815260040161067a906134e1565b600554611cbc908263ffffffff611c5e16565b6005556001600160a01b038216600090815260026020526040902054611ce8908263ffffffff611c5e16565b6001600160a01b0383166000818152600260205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c529085906131c9565b60006060856001600160a01b03166323b872dd868686604051602401611d5f93929190613178565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611d9891906130ba565b6000604051808303816000865af19150503d8060008114611dd5576040519150601f19603f3d011682016040523d82523d6000602084013e611dda565b606091505b5091509150818015611e04575080511580611e04575080806020019051611e049190810190612269565b610b3c5760405162461bcd60e51b815260040161067a906133e1565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611e615782800160ff19823516178555611e8e565b82800160010185558215611e8e579182015b82811115611e8e578235825591602001919060010190611e73565b50611e9a929150611e9e565b5090565b61050291905b80821115611e9a5760008155600101611ea4565b803561051681613605565b805161051681613605565b600082601f830112611edf57600080fd5b8135611ef2611eed82613560565b613539565b91508181835260208401935060208101905083856020840282011115611f1757600080fd5b60005b83811015611f435781611f2d8882611f58565b8452506020928301929190910190600101611f1a565b5050505092915050565b80516105168161361c565b803561051681613625565b60008083601f840112611f7557600080fd5b50813567ffffffffffffffff811115611f8d57600080fd5b602083019150836001820283011115611fa557600080fd5b9250929050565b600060608284031215611fbe57600080fd5b611fc86060613539565b90506000611fd68484611eb8565b8252506020611fe784848301611f58565b602083015250604082013567ffffffffffffffff81111561200757600080fd5b61201384828501611ece565b60408301525092915050565b80516105168161362e565b805161051681613625565b803561051681613637565b60006020828403121561205257600080fd5b600061205e8484611eb8565b949350505050565b6000806040838503121561207957600080fd5b60006120858585611eb8565b925050602061209685828601611eb8565b9150509250929050565b6000806000606084860312156120b557600080fd5b60006120c18686611eb8565b93505060206120d286828701611eb8565b92505060406120e386828701611f58565b9150509250925092565b600080600080600080600080610100898b03121561210a57600080fd5b60006121168b8b611ec3565b98505060206121278b828c01611ec3565b97505060406121388b828c0161202a565b96505060606121498b828c01611ec3565b955050608061215a8b828c0161202a565b94505060a061216b8b828c0161202a565b93505060c061217c8b828c0161202a565b92505060e061218d8b828c0161202a565b9150509295985092959890939650565b600080600080600080600060e0888a0312156121b857600080fd5b60006121c48a8a611eb8565b97505060206121d58a828b01611eb8565b96505060406121e68a828b01611f58565b95505060606121f78a828b01611f58565b94505060806122088a828b01612035565b93505060a06122198a828b01611f58565b92505060c061222a8a828b01611f58565b91505092959891949750929550565b6000806040838503121561224c57600080fd5b60006122588585611eb8565b925050602061209685828601611f58565b60006020828403121561227b57600080fd5b600061205e8484611f4d565b600080600080600080600080600060e08a8c0312156122a557600080fd5b893567ffffffffffffffff8111156122bc57600080fd5b6122c88c828d01611f63565b995099505060208a013567ffffffffffffffff8111156122e757600080fd5b6122f38c828d01611f63565b975097505060406123068c828d01612035565b95505060606123178c828d01611eb8565b94505060806123288c828d01611f58565b93505060a06123398c828d01611eb8565b92505060c061234a8c828d01611eb8565b9150509295985092959850929598565b60006020828403121561236c57600080fd5b600061205e8484611f58565b60006020828403121561238a57600080fd5b600061205e848461202a565b600080604083850312156123a957600080fd5b60006123b58585611f58565b925050602083013567ffffffffffffffff8111156123d257600080fd5b61209685828601611fac565b600080604083850312156123f157600080fd5b60006123fd858561202a565b92505060206120968582860161201f565b60008060008060008060c0878903121561242757600080fd5b60006124338989611f58565b965050602061244489828a01611f58565b955050604061245589828a01612035565b945050606061246689828a01611f58565b935050608061247789828a01611f58565b92505060a087013567ffffffffffffffff81111561249457600080fd5b6124a089828a01611fac565b9150509295509295509295565b60006124b9838361253b565b505060200190565b6124ca816135bd565b82525050565b6124ca81613594565b60006124e482613587565b6124ee818561358b565b93506124f983613581565b8060005b8381101561252757815161251188826124ad565b975061251c83613581565b9250506001016124fd565b509495945050505050565b6124ca8161359f565b6124ca81610502565b6124ca61255082610502565b610502565b600061256082613587565b61256a81856105e1565b935061257a8185602086016135cf565b9290920192915050565b6124ca816135c4565b600061259882613587565b6125a2818561358b565b93506125b28185602086016135cf565b6125bb816135fb565b9093019392505050565b60006125d260238361358b565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647281526265737360e81b602082015260400192915050565b600061261760348361358b565b7f5374616b696e674163637275616c45524332303a207374616b696e6720746f6b815273195b881a5cc81b9bdd08184818dbdb9d1c9858dd60621b602082015260400192915050565b600061266d60418361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d6520637281527f656469742073636f7265206164647265737320697320616c72656164792073656020820152601d60fa1b604082015260600192915050565b60006126d660328361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f8152711ddb88185b1c9958591e481cdd185c9d195960721b602082015260400192915050565b600061272a601a8361358b565b7f5361666545524332303a205452414e534645525f4641494c4544000000000000815260200192915050565b600061276360228361358b565b7f45524332303a20617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b60006127a76002836105e1565b61190160f01b815260020192915050565b60006127c5601b8361358b565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006127fe60398361358b565b7f5374616b696e674163637275616c45524332303a20746865206372656469742081527f73636f726520636f6e747261637420697320696e76616c696400000000000000602082015260400192915050565b600061285d602e8361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f81526d1ddb881b9bdd08195b185c1cd95960921b602082015260400192915050565b60006128ad601e8361358b565b7f5065726d69747461626c653a205369676e617475726520696e76616c69640000815260200192915050565b60006128e660388361358b565b7f5374616b696e674163637275616c45524332303a2063616e6e6f74207374616b81527f6520647572696e6720636f6f6c646f776e20706572696f640000000000000000602082015260400192915050565b6000612945601e8361358b565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b600061297e601a8361358b565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b60006129b7601e8361358b565b7f41646d696e61626c653a2063616c6c6572206973206e6f742061646d696e0000815260200192915050565b60006129f060348361358b565b7f5374616b696e674163637275616c45524332303a20746865207361626c6965728152730818dbdb9d1c9858dd081a5cc81a5b9d985b1a5960621b602082015260400192915050565b6000612a4660228361358b565b7f5065726d69747461626c653a207370656e6465722063616e6e6f742062652030815261078360f41b602082015260400192915050565b6000612a8a602e8361358b565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656181526d191e481a5b9a5d1a585b1a5e995960921b602082015260400192915050565b6000612ada601f8361358b565b7f5361666545524332303a205452414e534645525f46524f4d5f4641494c454400815260200192915050565b6000612b13601b8361358b565b7f5065726d69747461626c653a205065726d697420657870697265640000000000815260200192915050565b6000612b4c6052836105e1565b7f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320602082015271766572696679696e67436f6e74726163742960701b604082015260520192915050565b6000612bc6603a8361358b565b7f43726564697453636f726556657269666961626c653a2070726f6f6620646f6581527f73206e6f742062656c6f6e6720746f207468652063616c6c6572000000000000602082015260400192915050565b6000612c2560218361358b565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612c6860358361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d6520636f8152741bdb191bdddb881a5cc8185b1c9958591e481cd95d605a1b602082015260400192915050565b6000612cbf60388361358b565b7f5374616b696e674163637275616c45524332303a2074686520676976656e206181527f646472657373206973206e6f74206120636f6e74726163740000000000000000602082015260400192915050565b6000612d1e602e8361358b565b7f5374616b696e674163637275616c45524332303a20616464726573732069732081526d1b9bdd08184818dbdb9d1c9858dd60921b602082015260400192915050565b6000612d6e60368361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d652073748152751c99585b481251081a5cc8185b1c9958591e481cd95d60521b602082015260400192915050565b6000612dc660218361358b565b7f45524332303a206275726e2066726f6d20746865207a65726f206164647265738152607360f81b602082015260400192915050565b6000612e0960258361358b565b7f45524332303a207472616e736665722066726f6d20746865207a65726f206164815264647265737360d81b602082015260400192915050565b6000612e5060248361358b565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015260400192915050565b6000612e9660278361358b565b7f5374616b696e674163637275616c45524332303a20757365722068617320302081526662616c616e636560c81b602082015260400192915050565b6000612edf60288361358b565b7f5374616b696e674163637275616c45524332303a20696e636f727265637420738152671d1c99585b48125160c21b602082015260400192915050565b6000612f2960398361358b565b7f5374616b696e674163637275616c45524332303a2063616e6e6f74207265636f81527f766572206d6f7265207468616e207468652062616c616e636500000000000000602082015260400192915050565b6000612f88603d8361358b565b7f43726564697453636f726556657269666961626c653a2070726f6f662069732081527f726571756972656420627574206974206973206e6f7420706173736564000000602082015260400192915050565b6000612fe760348361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f8152731ddb881dd85cc81b9bdd081a5b9a5d1a585d195960621b602082015260400192915050565b600061303d601f8361358b565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300815260200192915050565b8051600090606084019061307d85826124d0565b506020830151613090602086018261253b565b50604083015184820360408601526130a882826124d9565b95945050505050565b6124ca816135b7565b600061063b8284612555565b60006130d18261279a565b91506130dd8285612544565b6020820191506130ed8284612544565b5060200192915050565b600061051682612b3f565b6020810161051682846124d0565b60e0810161311e828a6124c1565b61312b60208301896124d0565b613138604083018861253b565b613145606083018761253b565b61315260808301866130b1565b61315f60a083018561253b565b61316c60c083018461253b565b98975050505050505050565b6060810161318682866124d0565b61319360208301856124d0565b61205e604083018461253b565b604081016131ae82856124d0565b61063b602083018461253b565b602081016105168284612532565b60208101610516828461253b565b60c081016131e5828961253b565b6131f260208301886124d0565b6131ff60408301876124d0565b61320c606083018661253b565b613219608083018561253b565b61322660a083018461253b565b979650505050505050565b60a0810161323f828861253b565b61324c602083018761253b565b613259604083018661253b565b613266606083018561253b565b61327360808301846124d0565b9695505050505050565b6080810161328b828761253b565b61329860208301866130b1565b6132a5604083018561253b565b6130a8606083018461253b565b602081016105168284612584565b6020808252810161063b818461258d565b602080825281016105de816125c5565b602080825281016105de8161260a565b602080825281016105de81612660565b602080825281016105de816126c9565b602080825281016105de8161271d565b602080825281016105de81612756565b602080825281016105de816127b8565b602080825281016105de816127f1565b602080825281016105de81612850565b602080825281016105de816128a0565b602080825281016105de816128d9565b602080825281016105de81612938565b602080825281016105de81612971565b602080825281016105de816129aa565b602080825281016105de816129e3565b602080825281016105de81612a39565b602080825281016105de81612a7d565b602080825281016105de81612acd565b602080825281016105de81612b06565b602080825281016105de81612bb9565b602080825281016105de81612c18565b602080825281016105de81612c5b565b602080825281016105de81612cb2565b602080825281016105de81612d11565b602080825281016105de81612d61565b602080825281016105de81612db9565b602080825281016105de81612dfc565b602080825281016105de81612e43565b602080825281016105de81612e89565b602080825281016105de81612ed2565b602080825281016105de81612f1c565b602080825281016105de81612f7b565b602080825281016105de81612fda565b602080825281016105de81613030565b6020808252810161063b8184613069565b60408101613510828561253b565b61063b60208301846124d0565b604081016131ae828561253b565b6020810161051682846130b1565b60405181810167ffffffffffffffff8111828210171561355857600080fd5b604052919050565b600067ffffffffffffffff82111561357757600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b60006105de826135ab565b151590565b61ffff1690565b6001600160a01b031690565b60ff1690565b60006105de825b60006105de82613594565b60005b838110156135ea5781810151838201526020016135d2565b838111156113385750506000910152565b601f01601f191690565b61360e81613594565b811461361957600080fd5b50565b61360e8161359f565b61360e81610502565b61360e816135a4565b61360e816135b756fea365627a7a72315820db9700a594ad31ff1ac3e3785e6e46ee9279003485a0366d15c021c012a0b2ad6c6578706572696d656e74616cf564736f6c63430005100040

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102115760003560e01c806371dc479511610125578063d505accf116100ad578063e1f7c2c91161007c578063e1f7c2c91461040f578063e6aa216c14610422578063e9fad8ee1461042a578063f8356c8114610432578063fe686b481461044557610211565b8063d505accf146103c3578063dcc42a96146103d6578063dd62ed3e146103e9578063df45d0b3146103fc57610211565b8063a6a14292116100f4578063a6a142921461036f578063a762498714610382578063a9059cbb14610395578063bcdb699f146103a8578063c7d595fa146103b057610211565b806371dc47951461034457806372f702f31461034c5780637ecebe001461035457806395d89b411461036757610211565b806330599fc5116101a8578063605c8cc611610177578063605c8cc6146102f9578063639cdcce146103015780636aca3e97146103095780636e9960c31461031c57806370a082311461033157610211565b806330599fc5146102bf57806330adf81f146102d4578063313ce567146102dc5780633644e515146102f157610211565b806318160ddd116101e457806318160ddd1461028957806318272fc5146102915780631e2ff94f146102a457806323b872dd146102ac57610211565b806301320fe21461021657806303a42b6f1461023f57806306fdde0314610254578063095ea7b314610269575b600080fd5b610229610224366004612040565b61044d565b60405161023691906131c9565b60405180910390f35b61024761045f565b60405161023691906132b2565b61025c61046e565b60405161023691906132c0565b61027c610277366004612239565b610505565b60405161023691906131bb565b61022961051c565b61022961029f36600461235a565b610522565b6102296105e6565b61027c6102ba3660046120a0565b6105ea565b6102d26102cd36600461235a565b610642565b005b610229610785565b6102e46107a9565b604051610236919061352b565b6102296107b2565b6102d26107b8565b610247610931565b6102d2610317366004612040565b610940565b6103246109f1565b6040516102369190613102565b61022961033f366004612040565b610a21565b610229610a3c565b610247610a42565b610229610362366004612040565b610a51565b61025c610a63565b6102d261037d36600461240e565b610ac4565b6102d2610390366004612287565b610b44565b61027c6103a3366004612239565b610d61565b610229610d6e565b6102d26103be36600461235a565b610d74565b6102d26103d136600461219d565b610e03565b6102d26103e436600461235a565b610e26565b6102296103f7366004612066565b610f7d565b61022961040a36600461235a565b610fa8565b6102d261041d366004612040565b61105a565b610229611139565b6102d26111f4565b6102d2610440366004612396565b61133e565b6102d26115b1565b600d6020526000908152604090205481565b6008546001600160a01b031681565b60068054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104fa5780601f106104cf576101008083540402835291602001916104fa565b820191906000526020600020905b8154815290600101906020018083116104dd57829003601f168201915b505050505090505b90565b600061051233848461166d565b5060015b92915050565b60055490565b600061052c61051c565b610538575060006105e1565b6105de61054361051c565b600a546040516370a0823160e01b81526105d2916001600160a01b0316906370a0823190610575903090600401613102565b60206040518083038186803b15801561058d57600080fd5b505afa1580156105a1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506105c59190810190612378565b859063ffffffff61172116565b9063ffffffff61175b16565b90505b919050565b4290565b60006105f7848484611790565b6001600160a01b038416600090815260036020908152604080832033808552925290912054610637918691610632908663ffffffff61188c16565b61166d565b5060015b9392505050565b61064a6109f1565b6001600160a01b0316336001600160a01b0316146106835760405162461bcd60e51b815260040161067a906133a1565b60405180910390fd5b600a546040516370a0823160e01b81526000916001600160a01b0316906370a08231906106b4903090600401613102565b60206040518083038186803b1580156106cc57600080fd5b505afa1580156106e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506107049190810190612378565b9050808211156107265760405162461bcd60e51b815260040161067a906134b1565b7fbe842a2fe0dcb4d753f6d8de0884c9fe5e49f6c1e9d4c1b61d2a0c8fe16506318260405161075591906131c9565b60405180910390a16107816107686109f1565b600a546001600160a01b0316908463ffffffff6118b416565b5050565b7f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b60045460ff1690565b60005481565b600b546001600160a01b031615806107d05750600c54155b156107da5761092f565b600b54600c54604051631b2b776160e11b81526000926001600160a01b031691633656eec29161080f91903090600401613502565b60206040518083038186803b15801561082757600080fd5b505afa15801561083b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061085f9190810190612378565b90508061086c575061092f565b600b54600c54604051631ea6cb1b60e21b81526001600160a01b0390921691637a9b2c6c9161089f91859060040161351d565b602060405180830381600087803b1580156108b957600080fd5b505af11580156108cd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506108f19190810190612269565b507fe6643f7201409bc3c3a5fd11c50564bb2e4e13479cb71fbb48e8079486106d31600c548260405161092592919061351d565b60405180910390a1505b565b600b546001600160a01b031681565b6109486109f1565b6001600160a01b0316336001600160a01b0316146109785760405162461bcd60e51b815260040161067a906133a1565b61098a816001600160a01b03166119a2565b6109a65760405162461bcd60e51b815260040161067a90613441565b600b80546001600160a01b0319166001600160a01b0383161790556040517f84a373b9623d96e07e5945bf517d7f63701b00ec16467c73ad6b1f28870f986c90610925908390613102565b6000610a1c7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61036119a8565b905090565b6001600160a01b031660009081526002602052604090205490565b600c5481565b600a546001600160a01b031681565b60016020526000908152604090205481565b60078054604080516020601f60026000196101006001881615020190951694909404938401819004810282018101909252828152606093909290918301828280156104fa5780601f106104cf576101008083540402835291602001916104fa565b600a5460405163d505accf60e01b81526001600160a01b039091169063d505accf90610b0090339030908b908b908b908b908b90600401613110565b600060405180830381600087803b158015610b1a57600080fd5b505af1158015610b2e573d6000803e3d6000fd5b50505050610b3c868261133e565b505050505050565b610b4c6109f1565b6001600160a01b0316336001600160a01b031614610b7c5760405162461bcd60e51b815260040161067a906133a1565b600854600160a81b900460ff1680610b9e5750600854600160a01b900460ff16155b610bba5760405162461bcd60e51b815260040161067a906133d1565b600854600160a81b900460ff16158015610bf1576008805460ff60a01b1960ff60a81b19909116600160a81b1716600160a01b1790555b610bfd60068b8b611e20565b50610c0a60078989611e20565b506004805460ff191660ff88161790556009849055610c316001600160a01b0386166119a2565b610c4d5760405162461bcd60e51b815260040161067a906132e1565b610c5f836001600160a01b03166119a2565b610c7b5760405162461bcd60e51b815260040161067a90613341565b610c8d826001600160a01b03166119a2565b610ca95760405162461bcd60e51b815260040161067a906133b1565b610d018a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250506040805180820190915260018152603160f81b602082015291506119ac9050565b600055600a80546001600160a01b038088166001600160a01b03199283161790925560088054868416908316179055600b8054928516929091169190911790558015610d55576008805460ff60a81b191690555b50505050505050505050565b6000610512338484611790565b60095481565b610d7c6109f1565b6001600160a01b0316336001600160a01b031614610dac5760405162461bcd60e51b815260040161067a906133a1565b806009541415610dce5760405162461bcd60e51b815260040161067a90613421565b60098190556040517fba0e1ced950ddef70ab40c6fd5e010571d362990d7e276e25a78ce54e9706c3c906109259083906131c9565b610e1287878787878787611a0a565b610e1d87878761166d565b50505050505050565b610e2e6109f1565b6001600160a01b0316336001600160a01b031614610e5e5760405162461bcd60e51b815260040161067a906133a1565b80600c541415610e805760405162461bcd60e51b815260040161067a90613451565b600b5460405163894e9a0d60e01b81526000916001600160a01b03169063894e9a0d90610eb19085906004016131c9565b6101006040518083038186803b158015610eca57600080fd5b505afa158015610ede573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f0291908101906120ed565b505050505050915050306001600160a01b0316816001600160a01b031614610f3c5760405162461bcd60e51b815260040161067a906134a1565b600c8290556040517ff7c865e734a76f428766e3240c17d5131a683c20e4885977402727570df0e1bb90610f719084906131c9565b60405180910390a15050565b6001600160a01b03918216600090815260036020908152604080832093909416825291909152205490565b600a546040516370a0823160e01b815260009182916001600160a01b03909116906370a0823190610fdd903090600401613102565b60206040518083038186803b158015610ff557600080fd5b505afa158015611009573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061102d9190810190612378565b90508061103e5760009150506105e1565b61063b816105d261104d61051c565b869063ffffffff61172116565b6110626109f1565b6001600160a01b0316336001600160a01b0316146110925760405162461bcd60e51b815260040161067a906133a1565b6008546001600160a01b03828116911614156110c05760405162461bcd60e51b815260040161067a906132f1565b6110d2816001600160a01b03166119a2565b6110ee5760405162461bcd60e51b815260040161067a90613431565b600880546001600160a01b0319166001600160a01b0383161790556040517ff5280746e16d30bc414b77f117a4fa3a918ce04d0d6789e62ddbb13a1bb03e3090610925908390613102565b600061114361051c565b61114f57506000610502565b610a1c61115a61051c565b600a546040516370a0823160e01b81526105d291670de0b6b3a7640000916001600160a01b03909116906370a0823190611198903090600401613102565b60206040518083038186803b1580156111b057600080fd5b505afa1580156111c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506111e89190810190612378565b9063ffffffff61172116565b6111fc6107b8565b336000908152600d60205260408120549061121561051c565b9050600061122233610a21565b9050600081116112445760405162461bcd60e51b815260040161067a90613491565b8261124d6105e6565b101561126b5760405162461bcd60e51b815260040161067a90613351565b826112885760405162461bcd60e51b815260040161067a906134d1565b600a546040516370a0823160e01b81526000916112c59185916105d2916001600160a01b03909116906370a0823190610575903090600401613102565b90506112d13383611b96565b336000818152600d602052604080822091909155517f920bb94eb3842a728db98228c375ff6b00c5bc5a54fac6736155517a0a20a61a906113139084906131c9565b60405180910390a2600a54611338906001600160a01b0316338363ffffffff6118b416565b50505050565b805181906001906001600160a01b03161561137c5781516001600160a01b0316331461137c5760405162461bcd60e51b815260040161067a90613401565b604082015151151581156113a757806113a75760405162461bcd60e51b815260040161067a906134c1565b801561143157600854604051631f33cd1960e21b81526001600160a01b0390911690637ccf3464906113dd9086906004016134f1565b6040805180830381600087803b1580156113f657600080fd5b505af115801561140a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061142e91908101906123de565b50505b6114396107b8565b336000908152600d602052604090205480156114675760405162461bcd60e51b815260040161067a90613371565b600a546040516370a0823160e01b81526000916001600160a01b0316906370a0823190611498903090600401613102565b60206040518083038186803b1580156114b057600080fd5b505afa1580156114c4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506114e89190810190612378565b905060006114f461051c565b9050801580611501575081155b156115245761151f3361151a848b63ffffffff611c5e16565b611c83565b611548565b600061153a836105d28b8563ffffffff61172116565b90506115463382611c83565b505b600a54611566906001600160a01b031633308b63ffffffff611d3716565b336001600160a01b03167f9e71bc8eea02a63969f509818f2dafb9254532904319f9dbda79b67bd34a5f3d8960405161159f91906131c9565b60405180910390a25050505050505050565b60006115bc33610a21565b116115d95760405162461bcd60e51b815260040161067a90613491565b336000908152600d6020526040902054156116065760405162461bcd60e51b815260040161067a90613301565b6116206009546116146105e6565b9063ffffffff611c5e16565b336000818152600d6020526040908190208390555190917f48a37de01454fea7daf610b49703424ca91f1fc6392f1a4fc90f36676f568d389161166391906131c9565b60405180910390a2565b6001600160a01b0383166116935760405162461bcd60e51b815260040161067a90613481565b6001600160a01b0382166116b95760405162461bcd60e51b815260040161067a90613321565b6001600160a01b0380841660008181526003602090815260408083209487168084529490915290819020849055517f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925906117149085906131c9565b60405180910390a3505050565b60008261173057506000610516565b8282028284828161173d57fe5b041461063b5760405162461bcd60e51b815260040161067a90613411565b600080821161177c5760405162461bcd60e51b815260040161067a90613391565b600082848161178757fe5b04949350505050565b6001600160a01b0383166117b65760405162461bcd60e51b815260040161067a90613471565b6001600160a01b0382166117dc5760405162461bcd60e51b815260040161067a906132d1565b6001600160a01b038316600090815260026020526040902054611805908263ffffffff61188c16565b6001600160a01b03808516600090815260026020526040808220939093559084168152205461183a908263ffffffff611c5e16565b6001600160a01b0380841660008181526002602052604090819020939093559151908516907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906117149085906131c9565b6000828211156118ae5760405162461bcd60e51b815260040161067a90613381565b50900390565b60006060846001600160a01b031663a9059cbb85856040516024016118da9291906131a0565b6040516020818303038152906040529060e01b6020820180516001600160e01b03838183161783525050505060405161191391906130ba565b6000604051808303816000865af19150503d8060008114611950576040519150601f19603f3d011682016040523d82523d6000602084013e611955565b606091505b509150915081801561197f57508051158061197f57508080602001905161197f9190810190612269565b61199b5760405162461bcd60e51b815260040161067a90613311565b5050505050565b3b151590565b5490565b60405160009046906119bd906130f7565b60405180910390208480519060200120848051906020012083306040516020016119eb959493929190613231565b6040516020818303038152906040528051906020012091505092915050565b831580611a175750428410155b611a335760405162461bcd60e51b815260040161067a906133f1565b6001600160a01b038616611a595760405162461bcd60e51b815260040161067a906133c1565b600080546001600160a01b03891682526001602081815260408085208054938401905551611ab3927f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c9928d928d928d9290918d91016131d7565b60405160208183030381529060405280519060200120604051602001611ada9291906130c6565b604051602081830303815290604052805190602001209050600060018286868660405160008152602001604052604051611b17949392919061327d565b6020604051602081039080840390855afa158015611b39573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b03811615801590611b6f5750806001600160a01b0316896001600160a01b0316145b611b8b5760405162461bcd60e51b815260040161067a90613361565b505050505050505050565b6001600160a01b038216611bbc5760405162461bcd60e51b815260040161067a90613461565b6001600160a01b038216600090815260026020526040902054611be5908263ffffffff61188c16565b6001600160a01b038316600090815260026020526040902055600554611c11908263ffffffff61188c16565b6005556040516000906001600160a01b038416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c529085906131c9565b60405180910390a35050565b60008282018381101561063b5760405162461bcd60e51b815260040161067a90613331565b6001600160a01b038216611ca95760405162461bcd60e51b815260040161067a906134e1565b600554611cbc908263ffffffff611c5e16565b6005556001600160a01b038216600090815260026020526040902054611ce8908263ffffffff611c5e16565b6001600160a01b0383166000818152600260205260408082209390935591519091907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611c529085906131c9565b60006060856001600160a01b03166323b872dd868686604051602401611d5f93929190613178565b6040516020818303038152906040529060e01b6020820180516001600160e01b038381831617835250505050604051611d9891906130ba565b6000604051808303816000865af19150503d8060008114611dd5576040519150601f19603f3d011682016040523d82523d6000602084013e611dda565b606091505b5091509150818015611e04575080511580611e04575080806020019051611e049190810190612269565b610b3c5760405162461bcd60e51b815260040161067a906133e1565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f10611e615782800160ff19823516178555611e8e565b82800160010185558215611e8e579182015b82811115611e8e578235825591602001919060010190611e73565b50611e9a929150611e9e565b5090565b61050291905b80821115611e9a5760008155600101611ea4565b803561051681613605565b805161051681613605565b600082601f830112611edf57600080fd5b8135611ef2611eed82613560565b613539565b91508181835260208401935060208101905083856020840282011115611f1757600080fd5b60005b83811015611f435781611f2d8882611f58565b8452506020928301929190910190600101611f1a565b5050505092915050565b80516105168161361c565b803561051681613625565b60008083601f840112611f7557600080fd5b50813567ffffffffffffffff811115611f8d57600080fd5b602083019150836001820283011115611fa557600080fd5b9250929050565b600060608284031215611fbe57600080fd5b611fc86060613539565b90506000611fd68484611eb8565b8252506020611fe784848301611f58565b602083015250604082013567ffffffffffffffff81111561200757600080fd5b61201384828501611ece565b60408301525092915050565b80516105168161362e565b805161051681613625565b803561051681613637565b60006020828403121561205257600080fd5b600061205e8484611eb8565b949350505050565b6000806040838503121561207957600080fd5b60006120858585611eb8565b925050602061209685828601611eb8565b9150509250929050565b6000806000606084860312156120b557600080fd5b60006120c18686611eb8565b93505060206120d286828701611eb8565b92505060406120e386828701611f58565b9150509250925092565b600080600080600080600080610100898b03121561210a57600080fd5b60006121168b8b611ec3565b98505060206121278b828c01611ec3565b97505060406121388b828c0161202a565b96505060606121498b828c01611ec3565b955050608061215a8b828c0161202a565b94505060a061216b8b828c0161202a565b93505060c061217c8b828c0161202a565b92505060e061218d8b828c0161202a565b9150509295985092959890939650565b600080600080600080600060e0888a0312156121b857600080fd5b60006121c48a8a611eb8565b97505060206121d58a828b01611eb8565b96505060406121e68a828b01611f58565b95505060606121f78a828b01611f58565b94505060806122088a828b01612035565b93505060a06122198a828b01611f58565b92505060c061222a8a828b01611f58565b91505092959891949750929550565b6000806040838503121561224c57600080fd5b60006122588585611eb8565b925050602061209685828601611f58565b60006020828403121561227b57600080fd5b600061205e8484611f4d565b600080600080600080600080600060e08a8c0312156122a557600080fd5b893567ffffffffffffffff8111156122bc57600080fd5b6122c88c828d01611f63565b995099505060208a013567ffffffffffffffff8111156122e757600080fd5b6122f38c828d01611f63565b975097505060406123068c828d01612035565b95505060606123178c828d01611eb8565b94505060806123288c828d01611f58565b93505060a06123398c828d01611eb8565b92505060c061234a8c828d01611eb8565b9150509295985092959850929598565b60006020828403121561236c57600080fd5b600061205e8484611f58565b60006020828403121561238a57600080fd5b600061205e848461202a565b600080604083850312156123a957600080fd5b60006123b58585611f58565b925050602083013567ffffffffffffffff8111156123d257600080fd5b61209685828601611fac565b600080604083850312156123f157600080fd5b60006123fd858561202a565b92505060206120968582860161201f565b60008060008060008060c0878903121561242757600080fd5b60006124338989611f58565b965050602061244489828a01611f58565b955050604061245589828a01612035565b945050606061246689828a01611f58565b935050608061247789828a01611f58565b92505060a087013567ffffffffffffffff81111561249457600080fd5b6124a089828a01611fac565b9150509295509295509295565b60006124b9838361253b565b505060200190565b6124ca816135bd565b82525050565b6124ca81613594565b60006124e482613587565b6124ee818561358b565b93506124f983613581565b8060005b8381101561252757815161251188826124ad565b975061251c83613581565b9250506001016124fd565b509495945050505050565b6124ca8161359f565b6124ca81610502565b6124ca61255082610502565b610502565b600061256082613587565b61256a81856105e1565b935061257a8185602086016135cf565b9290920192915050565b6124ca816135c4565b600061259882613587565b6125a2818561358b565b93506125b28185602086016135cf565b6125bb816135fb565b9093019392505050565b60006125d260238361358b565b7f45524332303a207472616e7366657220746f20746865207a65726f206164647281526265737360e81b602082015260400192915050565b600061261760348361358b565b7f5374616b696e674163637275616c45524332303a207374616b696e6720746f6b815273195b881a5cc81b9bdd08184818dbdb9d1c9858dd60621b602082015260400192915050565b600061266d60418361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d6520637281527f656469742073636f7265206164647265737320697320616c72656164792073656020820152601d60fa1b604082015260600192915050565b60006126d660328361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f8152711ddb88185b1c9958591e481cdd185c9d195960721b602082015260400192915050565b600061272a601a8361358b565b7f5361666545524332303a205452414e534645525f4641494c4544000000000000815260200192915050565b600061276360228361358b565b7f45524332303a20617070726f766520746f20746865207a65726f206164647265815261737360f01b602082015260400192915050565b60006127a76002836105e1565b61190160f01b815260020192915050565b60006127c5601b8361358b565b7f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815260200192915050565b60006127fe60398361358b565b7f5374616b696e674163637275616c45524332303a20746865206372656469742081527f73636f726520636f6e747261637420697320696e76616c696400000000000000602082015260400192915050565b600061285d602e8361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f81526d1ddb881b9bdd08195b185c1cd95960921b602082015260400192915050565b60006128ad601e8361358b565b7f5065726d69747461626c653a205369676e617475726520696e76616c69640000815260200192915050565b60006128e660388361358b565b7f5374616b696e674163637275616c45524332303a2063616e6e6f74207374616b81527f6520647572696e6720636f6f6c646f776e20706572696f640000000000000000602082015260400192915050565b6000612945601e8361358b565b7f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815260200192915050565b600061297e601a8361358b565b7f536166654d6174683a206469766973696f6e206279207a65726f000000000000815260200192915050565b60006129b7601e8361358b565b7f41646d696e61626c653a2063616c6c6572206973206e6f742061646d696e0000815260200192915050565b60006129f060348361358b565b7f5374616b696e674163637275616c45524332303a20746865207361626c6965728152730818dbdb9d1c9858dd081a5cc81a5b9d985b1a5960621b602082015260400192915050565b6000612a4660228361358b565b7f5065726d69747461626c653a207370656e6465722063616e6e6f742062652030815261078360f41b602082015260400192915050565b6000612a8a602e8361358b565b7f496e697469616c697a61626c653a20636f6e747261637420697320616c72656181526d191e481a5b9a5d1a585b1a5e995960921b602082015260400192915050565b6000612ada601f8361358b565b7f5361666545524332303a205452414e534645525f46524f4d5f4641494c454400815260200192915050565b6000612b13601b8361358b565b7f5065726d69747461626c653a205065726d697420657870697265640000000000815260200192915050565b6000612b4c6052836105e1565b7f454950373132446f6d61696e28737472696e67206e616d652c737472696e672081527f76657273696f6e2c75696e7432353620636861696e49642c6164647265737320602082015271766572696679696e67436f6e74726163742960701b604082015260520192915050565b6000612bc6603a8361358b565b7f43726564697453636f726556657269666961626c653a2070726f6f6620646f6581527f73206e6f742062656c6f6e6720746f207468652063616c6c6572000000000000602082015260400192915050565b6000612c2560218361358b565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000612c6860358361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d6520636f8152741bdb191bdddb881a5cc8185b1c9958591e481cd95d605a1b602082015260400192915050565b6000612cbf60388361358b565b7f5374616b696e674163637275616c45524332303a2074686520676976656e206181527f646472657373206973206e6f74206120636f6e74726163740000000000000000602082015260400192915050565b6000612d1e602e8361358b565b7f5374616b696e674163637275616c45524332303a20616464726573732069732081526d1b9bdd08184818dbdb9d1c9858dd60921b602082015260400192915050565b6000612d6e60368361358b565b7f5374616b696e674163637275616c45524332303a207468652073616d652073748152751c99585b481251081a5cc8185b1c9958591e481cd95d60521b602082015260400192915050565b6000612dc660218361358b565b7f45524332303a206275726e2066726f6d20746865207a65726f206164647265738152607360f81b602082015260400192915050565b6000612e0960258361358b565b7f45524332303a207472616e736665722066726f6d20746865207a65726f206164815264647265737360d81b602082015260400192915050565b6000612e5060248361358b565b7f45524332303a20617070726f76652066726f6d20746865207a65726f206164648152637265737360e01b602082015260400192915050565b6000612e9660278361358b565b7f5374616b696e674163637275616c45524332303a20757365722068617320302081526662616c616e636560c81b602082015260400192915050565b6000612edf60288361358b565b7f5374616b696e674163637275616c45524332303a20696e636f727265637420738152671d1c99585b48125160c21b602082015260400192915050565b6000612f2960398361358b565b7f5374616b696e674163637275616c45524332303a2063616e6e6f74207265636f81527f766572206d6f7265207468616e207468652062616c616e636500000000000000602082015260400192915050565b6000612f88603d8361358b565b7f43726564697453636f726556657269666961626c653a2070726f6f662069732081527f726571756972656420627574206974206973206e6f7420706173736564000000602082015260400192915050565b6000612fe760348361358b565b7f5374616b696e674163637275616c45524332303a206578697420636f6f6c646f8152731ddb881dd85cc81b9bdd081a5b9a5d1a585d195960621b602082015260400192915050565b600061303d601f8361358b565b7f45524332303a206d696e7420746f20746865207a65726f206164647265737300815260200192915050565b8051600090606084019061307d85826124d0565b506020830151613090602086018261253b565b50604083015184820360408601526130a882826124d9565b95945050505050565b6124ca816135b7565b600061063b8284612555565b60006130d18261279a565b91506130dd8285612544565b6020820191506130ed8284612544565b5060200192915050565b600061051682612b3f565b6020810161051682846124d0565b60e0810161311e828a6124c1565b61312b60208301896124d0565b613138604083018861253b565b613145606083018761253b565b61315260808301866130b1565b61315f60a083018561253b565b61316c60c083018461253b565b98975050505050505050565b6060810161318682866124d0565b61319360208301856124d0565b61205e604083018461253b565b604081016131ae82856124d0565b61063b602083018461253b565b602081016105168284612532565b60208101610516828461253b565b60c081016131e5828961253b565b6131f260208301886124d0565b6131ff60408301876124d0565b61320c606083018661253b565b613219608083018561253b565b61322660a083018461253b565b979650505050505050565b60a0810161323f828861253b565b61324c602083018761253b565b613259604083018661253b565b613266606083018561253b565b61327360808301846124d0565b9695505050505050565b6080810161328b828761253b565b61329860208301866130b1565b6132a5604083018561253b565b6130a8606083018461253b565b602081016105168284612584565b6020808252810161063b818461258d565b602080825281016105de816125c5565b602080825281016105de8161260a565b602080825281016105de81612660565b602080825281016105de816126c9565b602080825281016105de8161271d565b602080825281016105de81612756565b602080825281016105de816127b8565b602080825281016105de816127f1565b602080825281016105de81612850565b602080825281016105de816128a0565b602080825281016105de816128d9565b602080825281016105de81612938565b602080825281016105de81612971565b602080825281016105de816129aa565b602080825281016105de816129e3565b602080825281016105de81612a39565b602080825281016105de81612a7d565b602080825281016105de81612acd565b602080825281016105de81612b06565b602080825281016105de81612bb9565b602080825281016105de81612c18565b602080825281016105de81612c5b565b602080825281016105de81612cb2565b602080825281016105de81612d11565b602080825281016105de81612d61565b602080825281016105de81612db9565b602080825281016105de81612dfc565b602080825281016105de81612e43565b602080825281016105de81612e89565b602080825281016105de81612ed2565b602080825281016105de81612f1c565b602080825281016105de81612f7b565b602080825281016105de81612fda565b602080825281016105de81613030565b6020808252810161063b8184613069565b60408101613510828561253b565b61063b60208301846124d0565b604081016131ae828561253b565b6020810161051682846130b1565b60405181810167ffffffffffffffff8111828210171561355857600080fd5b604052919050565b600067ffffffffffffffff82111561357757600080fd5b5060209081020190565b60200190565b5190565b90815260200190565b60006105de826135ab565b151590565b61ffff1690565b6001600160a01b031690565b60ff1690565b60006105de825b60006105de82613594565b60005b838110156135ea5781810151838201526020016135d2565b838111156113385750506000910152565b601f01601f191690565b61360e81613594565b811461361957600080fd5b50565b61360e8161359f565b61360e81610502565b61360e816135a4565b61360e816135b756fea365627a7a72315820db9700a594ad31ff1ac3e3785e6e46ee9279003485a0366d15c021c012a0b2ad6c6578706572696d656e74616cf564736f6c63430005100040

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.