ETH Price: $1,662.50 (+4.17%)
Gas: 18 Gwei
 
Transaction Hash
Method
Block
From
To
Value
0x87491d47050efa706671759ec9153312ac35a518070eb71f5d03cbaabbec7924Permit And Stake(pending)2023-09-24 2:06:504 days 15 hrs ago1695521210IN
0xf4d06d...9711F899
0 ETH(Pending)(Pending)
0x0de38a7c849dd0665a340cbb6c8a4e22a56f3c07a19f2c23b5b2795dd3e808a6Permit And Stake(pending)2023-09-17 3:33:2711 days 14 hrs ago1694921607IN
0xf4d06d...9711F899
0 ETH(Pending)(Pending)
Permit And Stake182093082023-09-25 0:43:473 days 17 hrs ago1695602627IN
0xf4d06d...9711F899
0 ETH0.001801917.15735577
Unstake182092762023-09-25 0:37:233 days 17 hrs ago1695602243IN
0xf4d06d...9711F899
0 ETH0.001174997.56084259
Permit And Stake182014682023-09-23 22:22:594 days 19 hrs ago1695507779IN
0xf4d06d...9711F899
0 ETH0.001924017.50042141
Unstake182014612023-09-23 22:21:354 days 19 hrs ago1695507695IN
0xf4d06d...9711F899
0 ETH0.001370727.2058206
Unstake181761852023-09-20 9:23:478 days 8 hrs ago1695201827IN
0xf4d06d...9711F899
0 ETH0.001205457.74844969
Unstake181432962023-09-15 18:10:1112 days 23 hrs ago1694801411IN
0xf4d06d...9711F899
0 ETH0.0055174529.0050251
Unstake181143182023-09-11 16:31:4717 days 1 hr ago1694449907IN
0xf4d06d...9711F899
0 ETH0.0047081134
Permit And Stake180962212023-09-09 3:40:4719 days 14 hrs ago1694230847IN
0xf4d06d...9711F899
0 ETH0.0029939310.94012944
Permit And Stake180691882023-09-05 8:49:2323 days 8 hrs ago1693903763IN
0xf4d06d...9711F899
0 ETH0.0028219911
Unstake180640532023-09-04 15:36:4724 days 2 hrs ago1693841807IN
0xf4d06d...9711F899
0 ETH0.0039077428.22007085
Permit And Stake180513582023-09-02 20:59:1125 days 20 hrs ago1693688351IN
0xf4d06d...9711F899
0 ETH0.002553210.14153921
Unstake180513002023-09-02 20:47:1125 days 21 hrs ago1693687631IN
0xf4d06d...9711F899
0 ETH0.0016329310.4961877
Unstake180496552023-09-02 15:14:3526 days 2 hrs ago1693667675IN
0xf4d06d...9711F899
0 ETH0.0023380915.02996168
Permit And Stake180466122023-09-02 4:59:5926 days 12 hrs ago1693630799IN
0xf4d06d...9711F899
0 ETH0.0022060311.03019693
Permit And Stake180388362023-09-01 2:51:1127 days 14 hrs ago1693536671IN
0xf4d06d...9711F899
0 ETH0.0031285712.1950502
Permit And Stake180388332023-09-01 2:50:2327 days 14 hrs ago1693536623IN
0xf4d06d...9711F899
0 ETH0.002486711.30320783
Unstake180388032023-09-01 2:44:2327 days 15 hrs ago1693536263IN
0xf4d06d...9711F899
0 ETH0.00156711.33007414
Unstake180264322023-08-30 9:09:3529 days 8 hrs ago1693386575IN
0xf4d06d...9711F899
0 ETH0.0025487316.38280392
Unstake180206512023-08-29 13:44:4730 days 4 hrs ago1693316687IN
0xf4d06d...9711F899
0 ETH0.0040574728.35553809
Unstake180206482023-08-29 13:44:1130 days 4 hrs ago1693316651IN
0xf4d06d...9711F899
0 ETH0.0039442827.56219567
Permit And Stake180206442023-08-29 13:43:2330 days 4 hrs ago1693316603IN
0xf4d06d...9711F899
0 ETH0.0064795827.05992816
Unstake180181992023-08-29 5:28:3530 days 12 hrs ago1693286915IN
0xf4d06d...9711F899
0 ETH0.0035366717.05770954
Unstake179915122023-08-25 11:48:4734 days 5 hrs ago1692964127IN
0xf4d06d...9711F899
0 ETH0.0020881215.07958086
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Staking

Compiler Version
v0.8.4+commit.c7e474f2

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion
File 1 of 8 : Staking.sol
// SPDX-License-Identifier: UNLICENSED
// solhint-disable-next-line compiler-fixed, compiler-gt-0_8
pragma solidity ^0.8.0;

import "./actions/StakingMsgProcessor.sol";
import "./interfaces/IActionMsgReceiver.sol";
import "./interfaces/IErc20Min.sol";
import "./interfaces/IStakingTypes.sol";
import "./interfaces/IVotingPower.sol";
import "./utils/ImmutableOwnable.sol";
import "./utils/Utils.sol";

/**
 * @title Staking
 * @notice It lets users stake $ZKP token for governance voting and rewards.
 * @dev At request of smart contracts and off-chain requesters, it computes
 * user "voting power" on the basis of tokens users stake.
 * It acts as the "ActionOracle" for the "RewardMaster": if stake terms presume
 * rewarding, it sends "messages" on stakes made and stakes claimed to the
 * "RewardMaster" contract which rewards stakers.
 * It supports multiple types of stakes (terms), which the owner may add or
 * remove without contract code upgrades.
 */
contract Staking is
    ImmutableOwnable,
    Utils,
    StakingMsgProcessor,
    IStakingTypes,
    IVotingPower
{
    // solhint-disable var-name-mixedcase
    /// @notice Staking token
    IErc20Min public immutable TOKEN;

    /// @dev Block the contract deployed in
    uint256 public immutable START_BLOCK;

    /// @notice RewardMaster contract instance
    IActionMsgReceiver public immutable REWARD_MASTER;

    // solhint-enable var-name-mixedcase

    // Scale for min/max limits
    uint256 private constant SCALE = 1e18;

    /// @notice Total token amount staked
    /// @dev Staking token is deemed to have max total supply of 1e27
    uint96 public totalStaked = 0;

    /// @dev Mapping from stake type to terms
    mapping(bytes4 => Terms) public terms;

    /// @dev Mapping from the staker address to stakes of the staker
    mapping(address => Stake[]) public stakes;

    // Special address to store global state
    address private constant GLOBAL_ACCOUNT = address(0);

    /// @dev Voting power integrants for each account
    // special case: GLOBAL_ACCOUNT for total voting power
    mapping(address => Power) public power;

    /// @dev Snapshots of each account
    // special case: GLOBAL_ACCOUNT for global snapshots
    mapping(address => Snapshot[]) private snapshots;

    /// @dev Emitted on a new stake made
    event StakeCreated(
        address indexed account,
        uint256 indexed stakeID,
        uint256 amount,
        bytes4 stakeType,
        uint256 lockedTill
    );

    /// @dev Emitted on a stake claimed (i.e. "unstaked")
    event StakeClaimed(address indexed account, uint256 indexed stakeID);

    /// @dev Voting power delegated
    event Delegation(
        address indexed owner,
        address indexed from,
        address indexed to,
        uint256 stakeID,
        uint256 amount
    );

    /// @dev New terms (for the given stake type) added
    event TermsAdded(bytes4 stakeType);

    /// @dev Terms (for the given stake type) are disabled
    event TermsDisabled(bytes4 stakeType);

    /// @dev Call to REWARD_MASTER reverted
    event RewardMasterRevert(address staker, uint256 stakeID);

    /**
     * @notice Sets staking token, owner and
     * @param stakingToken - Address of the {ZKPToken} contract
     * @param rewardMaster - Address of the {RewardMaster} contract
     * @param owner - Address of the owner account
     */
    constructor(
        address stakingToken,
        address rewardMaster,
        address owner
    ) ImmutableOwnable(owner) {
        require(
            stakingToken != address(0) && rewardMaster != address(0),
            "Staking:C1"
        );
        TOKEN = IErc20Min(stakingToken);
        REWARD_MASTER = IActionMsgReceiver(rewardMaster);
        START_BLOCK = blockNow();
    }

    /**
     * @notice Stakes tokens
     * @dev This contract should be approve()'d for amount
     * @param amount - Amount to stake
     * @param stakeType - Type of the stake
     * @param data - Arbitrary data for "RewardMaster" (zero, if inapplicable)
     * @return stake ID
     */
    function stake(
        uint256 amount,
        bytes4 stakeType,
        bytes calldata data
    ) public returns (uint256) {
        return _createStake(msg.sender, amount, stakeType, data);
    }

    /**
     * @notice Approves this contract to transfer `amount` tokens from the `msg.sender`
     * and stakes these tokens. Only the owner of tokens (i.e. the staker) may call.
     * @dev This contract does not need to be approve()'d in advance - see EIP-2612
     * @param owner - The owner of tokens being staked (i.e. the `msg.sender`)
     * @param amount - Amount to stake
     * @param v - "v" param of the signature from `owner` for "permit"
     * @param r - "r" param of the signature from `owner` for "permit"
     * @param s - "s" param of the signature from `owner` for "permit"
     * @param stakeType - Type of the stake
     * @param data - Arbitrary data for "RewardMaster" (zero, if inapplicable)
     * @return stake ID
     */
    function permitAndStake(
        address owner,
        uint256 amount,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s,
        bytes4 stakeType,
        bytes calldata data
    ) external returns (uint256) {
        require(owner == msg.sender, "Staking: owner must be msg.sender");
        TOKEN.permit(owner, address(this), amount, deadline, v, r, s);
        return _createStake(owner, amount, stakeType, data);
    }

    /**
     * @notice Claims staked token
     * @param stakeID - ID of the stake to claim
     * @param data - Arbitrary data for "RewardMaster" (zero, if inapplicable)
     * @param _isForced - Do not revert if "RewardMaster" fails
     */
    function unstake(
        uint256 stakeID,
        bytes calldata data,
        bool _isForced
    ) external stakeExist(msg.sender, stakeID) {
        Stake memory _stake = stakes[msg.sender][stakeID];

        require(_stake.claimedAt == 0, "Staking: Stake claimed");
        require(_stake.lockedTill < safe32TimeNow(), "Staking: Stake locked");

        if (_stake.delegatee != address(0)) {
            _undelegatePower(_stake.delegatee, msg.sender, _stake.amount);
        }
        _removePower(msg.sender, _stake.amount);

        stakes[msg.sender][stakeID].claimedAt = safe32TimeNow();

        totalStaked = safe96(uint256(totalStaked) - uint256(_stake.amount));

        emit StakeClaimed(msg.sender, stakeID);

        // known contract - reentrancy guard and `safeTransfer` unneeded
        require(
            TOKEN.transfer(msg.sender, _stake.amount),
            "Staking: transfer failed"
        );

        Terms memory _terms = terms[_stake.stakeType];
        if (_terms.isRewarded) {
            _sendUnstakedMsg(msg.sender, _stake, data, _isForced);
        }
    }

    /**
     * @notice Updates vote delegation
     * @param stakeID - ID of the stake to delegate votes uber
     * @param to - address to delegate to
     */
    function delegate(uint256 stakeID, address to)
        public
        stakeExist(msg.sender, stakeID)
    {
        require(
            to != GLOBAL_ACCOUNT,
            "Staking: Can't delegate to GLOBAL_ACCOUNT"
        );

        Stake memory s = stakes[msg.sender][stakeID];
        require(s.claimedAt == 0, "Staking: Stake claimed");
        require(s.delegatee != to, "Staking: Already delegated");

        if (s.delegatee == address(0)) {
            _delegatePower(msg.sender, to, s.amount);
        } else {
            if (to == msg.sender) {
                _undelegatePower(s.delegatee, msg.sender, s.amount);
            } else {
                _reDelegatePower(s.delegatee, to, s.amount);
            }
        }

        emit Delegation(msg.sender, s.delegatee, to, stakeID, s.amount);

        stakes[msg.sender][stakeID].delegatee = to;
    }

    /**
     * @notice Delegates voting power of stake back to self
     * @param stakeID - ID of the stake to delegate votes back to self
     */
    function undelegate(uint256 stakeID) external {
        delegate(stakeID, msg.sender);
    }

    /// @notice Returns number of stakes of given _account
    function stakesNum(address _account) external view returns (uint256) {
        return stakes[_account].length;
    }

    /// @notice Returns stakes of given account
    function accountStakes(address _account)
        external
        view
        returns (Stake[] memory)
    {
        Stake[] memory _stakes = stakes[_account];
        return _stakes;
    }

    /// @inheritdoc IVotingPower
    function totalVotingPower() external view override returns (uint256) {
        Power memory _power = power[GLOBAL_ACCOUNT];
        return _power.own + _power.delegated;
    }

    /// @inheritdoc IVotingPower
    function totalPower() external view override returns (Power memory) {
        return power[GLOBAL_ACCOUNT];
    }

    /// @inheritdoc IVotingPower
    function latestGlobalsSnapshotBlock()
        public
        view
        override
        returns (uint256)
    {
        return latestSnapshotBlock(GLOBAL_ACCOUNT);
    }

    /// @inheritdoc IVotingPower
    function latestSnapshotBlock(address _account)
        public
        view
        override
        returns (uint256)
    {
        if (snapshots[_account].length == 0) return 0;

        return snapshots[_account][snapshots[_account].length - 1].beforeBlock;
    }

    /// @inheritdoc IVotingPower
    function globalsSnapshotLength() external view override returns (uint256) {
        return snapshots[GLOBAL_ACCOUNT].length;
    }

    /// @inheritdoc IVotingPower
    function snapshotLength(address _account)
        external
        view
        override
        returns (uint256)
    {
        return snapshots[_account].length;
    }

    /// @inheritdoc IVotingPower
    function globalsSnapshot(uint256 _index)
        external
        view
        override
        returns (Snapshot memory)
    {
        return snapshots[GLOBAL_ACCOUNT][_index];
    }

    /// @inheritdoc IVotingPower
    function snapshot(address _account, uint256 _index)
        external
        view
        override
        returns (Snapshot memory)
    {
        return snapshots[_account][_index];
    }

    /// @inheritdoc IVotingPower
    function globalSnapshotAt(uint256 blockNum, uint256 hint)
        external
        view
        override
        returns (Snapshot memory)
    {
        return _snapshotAt(GLOBAL_ACCOUNT, blockNum, hint);
    }

    /// @inheritdoc IVotingPower
    function snapshotAt(
        address _account,
        uint256 blockNum,
        uint256 hint
    ) external view override returns (Snapshot memory) {
        return _snapshotAt(_account, blockNum, hint);
    }

    /// Only for the owner functions

    /// @notice Adds a new stake type with given terms
    /// @dev May be only called by the {OWNER}
    function addTerms(bytes4 stakeType, Terms memory _terms)
        external
        onlyOwner
        nonZeroStakeType(stakeType)
    {
        Terms memory existingTerms = terms[stakeType];
        require(!_isDefinedTerms(existingTerms), "Staking:E1");
        require(_terms.isEnabled, "Staking:E2");

        uint256 _now = timeNow();

        if (_terms.allowedTill != 0) {
            require(_terms.allowedTill > _now, "Staking:E3");
            require(_terms.allowedTill > _terms.allowedSince, "Staking:E4");
        }

        if (_terms.maxAmountScaled != 0) {
            require(
                _terms.maxAmountScaled > _terms.minAmountScaled,
                "Staking:E5"
            );
        }

        // only one of three "lock time" parameters must be non-zero
        if (_terms.lockedTill != 0) {
            require(
                _terms.exactLockPeriod == 0 && _terms.minLockPeriod == 0,
                "Staking:E6"
            );
            require(
                _terms.lockedTill > _now &&
                    _terms.lockedTill >= _terms.allowedTill,
                "Staking:E7"
            );
        } else {
            require(
                // one of two params must be non-zero
                (_terms.exactLockPeriod == 0) != (_terms.minLockPeriod == 0),
                "Staking:E8"
            );
        }

        terms[stakeType] = _terms;
        emit TermsAdded(stakeType);
    }

    function disableTerms(bytes4 stakeType)
        external
        onlyOwner
        nonZeroStakeType(stakeType)
    {
        Terms memory _terms = terms[stakeType];
        require(_isDefinedTerms(terms[stakeType]), "Staking:E9");
        require(_terms.isEnabled, "Staking:EA");

        terms[stakeType].isEnabled = false;
        emit TermsDisabled(stakeType);
    }

    /// Internal and private functions follow

    function _createStake(
        address staker,
        uint256 amount,
        bytes4 stakeType,
        bytes calldata data
    ) internal nonZeroStakeType(stakeType) returns (uint256) {
        Terms memory _terms = terms[stakeType];
        require(_terms.isEnabled, "Staking: Terms unknown or disabled");

        require(amount > 0, "Staking: Amount not set");
        uint256 _totalStake = amount + uint256(totalStaked);
        require(_totalStake < 2**96, "Staking: Too big amount");

        require(
            _terms.minAmountScaled == 0 ||
                amount >= SCALE * _terms.minAmountScaled,
            "Staking: Too small amount"
        );
        require(
            _terms.maxAmountScaled == 0 ||
                amount <= SCALE * _terms.maxAmountScaled,
            "Staking: Too large amount"
        );

        uint32 _now = safe32TimeNow();
        require(
            _terms.allowedSince == 0 || _now >= _terms.allowedSince,
            "Staking: Not yet allowed"
        );
        require(
            _terms.allowedTill == 0 || _terms.allowedTill > _now,
            "Staking: Not allowed anymore"
        );

        // known contract - reentrancy guard and `safeTransferFrom` unneeded
        require(
            TOKEN.transferFrom(staker, address(this), amount),
            "Staking: transferFrom failed"
        );

        uint256 stakeID = stakes[staker].length;

        uint32 lockedTill = _terms.lockedTill;
        if (lockedTill == 0) {
            uint256 period = _terms.exactLockPeriod == 0
                ? _terms.minLockPeriod
                : _terms.exactLockPeriod;
            lockedTill = safe32(period + _now);
        }

        Stake memory _stake = Stake(
            uint32(stakeID), // overflow risk ignored
            stakeType,
            _now, // stakedAt
            lockedTill,
            0, // claimedAt
            uint96(amount),
            address(0) // no delegatee
        );
        stakes[staker].push(_stake);

        totalStaked = uint96(_totalStake);
        _addPower(staker, amount);

        emit StakeCreated(staker, stakeID, amount, stakeType, lockedTill);

        if (_terms.isRewarded) {
            _sendStakedMsg(staker, _stake, data);
        }
        return stakeID;
    }

    function _addPower(address to, uint256 amount) private {
        _takeSnapshot(GLOBAL_ACCOUNT);
        _takeSnapshot(to);
        power[GLOBAL_ACCOUNT].own += uint96(amount);
        power[to].own += uint96(amount);
    }

    function _removePower(address from, uint256 amount) private {
        _takeSnapshot(GLOBAL_ACCOUNT);
        _takeSnapshot(from);
        power[GLOBAL_ACCOUNT].own -= uint96(amount);
        power[from].own -= uint96(amount);
    }

    function _delegatePower(
        address from,
        address to,
        uint256 amount
    ) private {
        _takeSnapshot(GLOBAL_ACCOUNT);
        _takeSnapshot(to);
        _takeSnapshot(from);
        power[GLOBAL_ACCOUNT].own -= uint96(amount);
        power[from].own -= uint96(amount);
        power[GLOBAL_ACCOUNT].delegated += uint96(amount);
        power[to].delegated += uint96(amount);
    }

    function _reDelegatePower(
        address from,
        address to,
        uint256 amount
    ) private {
        _takeSnapshot(to);
        _takeSnapshot(from);
        power[from].delegated -= uint96(amount);
        power[to].delegated += uint96(amount);
    }

    function _undelegatePower(
        address from,
        address to,
        uint256 amount
    ) private {
        power[GLOBAL_ACCOUNT].delegated -= uint96(amount);
        power[from].delegated -= uint96(amount);
        power[GLOBAL_ACCOUNT].own += uint96(amount);
        power[to].own += uint96(amount);
    }

    function _takeSnapshot(address _account) internal {
        uint32 curBlockNum = safe32BlockNow();
        if (latestSnapshotBlock(_account) < curBlockNum) {
            // make new snapshot as the latest one taken before current block
            snapshots[_account].push(
                Snapshot(
                    curBlockNum,
                    power[_account].own,
                    power[_account].delegated
                )
            );
        }
    }

    function _snapshotAt(
        address _account,
        uint256 blockNum,
        uint256 hint
    ) internal view returns (Snapshot memory) {
        _sanitizeBlockNum(blockNum);

        Snapshot[] storage snapshotsInfo = snapshots[_account];

        if (
            // hint is correct?
            hint <= snapshotsInfo.length &&
            (hint == 0 || snapshotsInfo[hint - 1].beforeBlock < blockNum) &&
            (hint == snapshotsInfo.length ||
                snapshotsInfo[hint].beforeBlock >= blockNum)
        ) {
            // yes, return the hinted snapshot
            if (hint < snapshotsInfo.length) {
                return snapshotsInfo[hint];
            } else {
                return
                    Snapshot(
                        uint32(blockNum),
                        power[_account].own,
                        power[_account].delegated
                    );
            }
        }
        // no, fall back to binary search
        else return _snapshotAt(_account, blockNum);
    }

    function _snapshotAt(address _account, uint256 blockNum)
        internal
        view
        returns (Snapshot memory)
    {
        _sanitizeBlockNum(blockNum);

        // https://en.wikipedia.org/wiki/Binary_search_algorithm
        Snapshot[] storage snapshotsInfo = snapshots[_account];
        uint256 index;
        uint256 low = 0;
        uint256 high = snapshotsInfo.length;

        while (low < high) {
            uint256 mid = (low + high) / 2;

            if (snapshotsInfo[mid].beforeBlock > blockNum) {
                high = mid;
            } else {
                low = mid + 1;
            }
        }

        // `low` is the exclusive upper bound. Find the inclusive upper bounds and set to index
        if (low > 0 && snapshotsInfo[low - 1].beforeBlock == blockNum) {
            return snapshotsInfo[low - 1];
        } else {
            index = low;
        }

        // If index is equal to snapshot array length, then no update made after the requested blockNum.
        // This means the latest value is the right one.
        if (index == snapshotsInfo.length) {
            return
                Snapshot(
                    uint32(blockNum),
                    uint96(power[_account].own),
                    uint96(power[_account].delegated)
                );
        } else {
            return snapshotsInfo[index];
        }
    }

    function _sanitizeBlockNum(uint256 blockNum) private view {
        require(blockNum <= safe32BlockNow(), "Staking: Too big block number");
    }

    function _isDefinedTerms(Terms memory _terms) internal pure returns (bool) {
        return
            (_terms.minLockPeriod != 0) ||
            (_terms.exactLockPeriod != 0) ||
            (_terms.lockedTill != 0);
    }

    function _sendStakedMsg(
        address staker,
        Stake memory _stake,
        bytes calldata data
    ) internal {
        bytes4 action = _encodeStakeActionType(_stake.stakeType);
        bytes memory message = _packStakingActionMsg(staker, _stake, data);
        // known contract - reentrancy guard unneeded
        // solhint-disable-next-line no-empty-blocks
        try REWARD_MASTER.onAction(action, message) {} catch {
            revert("Staking: onStake msg failed");
        }
    }

    function _sendUnstakedMsg(
        address staker,
        Stake memory _stake,
        bytes calldata data,
        bool _isForced
    ) internal {
        bytes4 action = _encodeUnstakeActionType(_stake.stakeType);
        bytes memory message = _packStakingActionMsg(staker, _stake, data);
        // known contract - reentrancy guard unneeded
        // solhint-disable-next-line no-empty-blocks
        try REWARD_MASTER.onAction(action, message) {} catch {
            emit RewardMasterRevert(staker, _stake.id);
            // REWARD_MASTER must be unable to revert forced calls
            require(_isForced, "Staking: REWARD_MASTER reverts");
        }
    }

    modifier stakeExist(address staker, uint256 stakeID) {
        require(
            stakes[staker].length > stakeID,
            "Staking: Stake doesn't exist"
        );
        _;
    }

    modifier nonZeroStakeType(bytes4 stakeType) {
        require(stakeType != bytes4(0), "Staking: Invalid stake type 0");
        _;
    }
}

File 2 of 8 : StakingMsgProcessor.sol
// SPDX-License-Identifier: UNLICENSED
// solhint-disable-next-line compiler-fixed, compiler-gt-0_8
pragma solidity ^0.8.0;

import "../interfaces/IStakingTypes.sol";

abstract contract StakingMsgProcessor {
    bytes4 internal constant STAKE_ACTION = bytes4(keccak256("stake"));
    bytes4 internal constant UNSTAKE_ACTION = bytes4(keccak256("unstake"));

    function _encodeStakeActionType(bytes4 stakeType)
        internal
        pure
        returns (bytes4)
    {
        return bytes4(keccak256(abi.encodePacked(STAKE_ACTION, stakeType)));
    }

    function _encodeUnstakeActionType(bytes4 stakeType)
        internal
        pure
        returns (bytes4)
    {
        return bytes4(keccak256(abi.encodePacked(UNSTAKE_ACTION, stakeType)));
    }

    function _packStakingActionMsg(
        address staker,
        IStakingTypes.Stake memory stake,
        bytes calldata data
    ) internal pure returns (bytes memory) {
        return
            abi.encodePacked(
                staker, // address
                stake.amount, // uint96
                stake.id, // uint32
                stake.stakedAt, // uint32
                stake.lockedTill, // uint32
                stake.claimedAt, // uint32
                data // bytes
            );
    }

    // For efficiency we use "packed" (rather than "ABI") encoding.
    // It results in shorter data, but requires custom unpack function.
    function _unpackStakingActionMsg(bytes memory message)
        internal
        pure
        returns (
            address staker,
            uint96 amount,
            uint32 id,
            uint32 stakedAt,
            uint32 lockedTill,
            uint32 claimedAt,
            bytes memory data
        )
    {
        // staker, amount, id and 3 timestamps occupy exactly 48 bytes
        // (`data` may be of zero length)
        require(message.length >= 48, "SMP: unexpected msg length");

        uint256 stakerAndAmount;
        uint256 idAndStamps;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            // the 1st word (32 bytes) contains the `message.length`
            // we need the (entire) 2nd word ..
            stakerAndAmount := mload(add(message, 0x20))
            // .. and (16 bytes of) the 3rd word
            idAndStamps := mload(add(message, 0x40))
        }

        staker = address(uint160(stakerAndAmount >> 96));
        amount = uint96(stakerAndAmount & 0xFFFFFFFFFFFFFFFFFFFFFFFF);

        id = uint32((idAndStamps >> 224) & 0xFFFFFFFF);
        stakedAt = uint32((idAndStamps >> 192) & 0xFFFFFFFF);
        lockedTill = uint32((idAndStamps >> 160) & 0xFFFFFFFF);
        claimedAt = uint32((idAndStamps >> 128) & 0xFFFFFFFF);

        uint256 dataLength = message.length - 48;
        data = new bytes(dataLength);
        for (uint256 i = 0; i < dataLength; i++) {
            data[i] = message[i + 48];
        }
    }
}

File 3 of 8 : IActionMsgReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IActionMsgReceiver {
    function onAction(bytes4 action, bytes memory message) external;
}

File 4 of 8 : IErc20Min.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IErc20Min {
    /// @dev ERC-20 `balanceOf`
    function balanceOf(address account) external view returns (uint256);

    /// @dev ERC-20 `transfer`
    function transfer(address recipient, uint256 amount)
        external
        returns (bool);

    /// @dev ERC-20 `transferFrom`
    function transferFrom(
        address sender,
        address recipient,
        uint256 amount
    ) external returns (bool);

    /// @dev EIP-2612 `permit`
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;
}

File 5 of 8 : IStakingTypes.sol
// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-fixed, compiler-gt-0_8
pragma solidity ^0.8.0;

interface IStakingTypes {
    // Stake type terms
    struct Terms {
        // if stakes of this kind allowed
        bool isEnabled;
        // if messages on stakes to be sent to the {RewardMaster}
        bool isRewarded;
        // limit on the minimum amount staked, no limit if zero
        uint32 minAmountScaled;
        // limit on the maximum amount staked, no limit if zero
        uint32 maxAmountScaled;
        // Stakes not accepted before this time, has no effect if zero
        uint32 allowedSince;
        // Stakes not accepted after this time, has no effect if zero
        uint32 allowedTill;
        // One (at least) of the following three params must be non-zero
        // if non-zero, overrides both `exactLockPeriod` and `minLockPeriod`
        uint32 lockedTill;
        // ignored if non-zero `lockedTill` defined, overrides `minLockPeriod`
        uint32 exactLockPeriod;
        // has effect only if both `lockedTill` and `exactLockPeriod` are zero
        uint32 minLockPeriod;
    }

    struct Stake {
        // index in the `Stake[]` array of `stakes`
        uint32 id;
        // defines Terms
        bytes4 stakeType;
        // time this stake was created at
        uint32 stakedAt;
        // time this stake can be claimed at
        uint32 lockedTill;
        // time this stake was claimed at (unclaimed if 0)
        uint32 claimedAt;
        // amount of tokens on this stake (assumed to be less 1e27)
        uint96 amount;
        // address stake voting power is delegated to
        address delegatee;
    }
}

File 6 of 8 : IVotingPower.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @title IStaking
interface IVotingPower {
    struct Snapshot {
        uint32 beforeBlock;
        uint96 ownPower;
        uint96 delegatedPower;
    }

    /// @dev Voting power integrants
    struct Power {
        uint96 own; // voting power that remains after delegating to others
        uint96 delegated; // voting power delegated by others
    }

    /// @notice Returns total voting power staked
    /// @dev "own" and "delegated" voting power summed up
    function totalVotingPower() external view returns (uint256);

    /// @notice Returns total "own" and total "delegated" voting power separately
    /// @dev Useful, if "own" and "delegated" voting power treated differently
    function totalPower() external view returns (Power memory);

    /// @notice Returns global snapshot for given block
    /// @param blockNum - block number to get state at
    /// @param hint - off-chain computed index of the required snapshot
    function globalSnapshotAt(uint256 blockNum, uint256 hint)
        external
        view
        returns (Snapshot memory);

    /// @notice Returns snapshot on given block for given account
    /// @param _account - account to get snapshot for
    /// @param blockNum - block number to get state at
    /// @param hint - off-chain computed index of the required snapshot
    function snapshotAt(
        address _account,
        uint256 blockNum,
        uint256 hint
    ) external view returns (Snapshot memory);

    /// @dev Returns block number of the latest global snapshot
    function latestGlobalsSnapshotBlock() external view returns (uint256);

    /// @dev Returns block number of the given account latest snapshot
    function latestSnapshotBlock(address _account)
        external
        view
        returns (uint256);

    /// @dev Returns number of global snapshots
    function globalsSnapshotLength() external view returns (uint256);

    /// @dev Returns number of snapshots for given account
    function snapshotLength(address _account) external view returns (uint256);

    /// @dev Returns global snapshot at given index
    function globalsSnapshot(uint256 _index)
        external
        view
        returns (Snapshot memory);

    /// @dev Returns snapshot at given index for given account
    function snapshot(address _account, uint256 _index)
        external
        view
        returns (Snapshot memory);
}

File 7 of 8 : ImmutableOwnable.sol
// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-fixed, compiler-gt-0_8
pragma solidity ^0.8.0;

/// @title Staking
abstract contract ImmutableOwnable {
    /// @notice The owner who has privileged rights
    // solhint-disable-next-line var-name-mixedcase
    address public immutable OWNER;

    /// @dev Throws if called by any account other than the {OWNER}.
    modifier onlyOwner() {
        require(OWNER == msg.sender, "ImmOwn: unauthorized");
        _;
    }

    constructor(address _owner) {
        require(_owner != address(0), "ImmOwn: zero owner address");
        OWNER = _owner;
    }
}

File 8 of 8 : Utils.sol
// SPDX-License-Identifier: MIT
// solhint-disable-next-line compiler-fixed, compiler-gt-0_8
pragma solidity ^0.8.0;

abstract contract Utils {
    function safe32(uint256 n) internal pure returns (uint32) {
        require(n < 2**32, "UNSAFE32");
        return uint32(n);
    }

    function safe96(uint256 n) internal pure returns (uint96) {
        require(n < 2**96, "UNSAFE96");
        return uint96(n);
    }

    function safe128(uint256 n) internal pure returns (uint128) {
        require(n < 2**128, "UNSAFE128");
        return uint128(n);
    }

    function safe160(uint256 n) internal pure returns (uint160) {
        require(n < 2**160, "UNSAFE160");
        return uint160(n);
    }

    function safe32TimeNow() internal view returns (uint32) {
        return safe32(timeNow());
    }

    function safe32BlockNow() internal view returns (uint32) {
        return safe32(blockNow());
    }

    /// @dev Returns the current block timestamp (added to ease testing)
    function timeNow() internal view virtual returns (uint256) {
        return block.timestamp;
    }

    /// @dev Returns the current block number (added to ease testing)
    function blockNow() internal view virtual returns (uint256) {
        return block.number;
    }
}

Settings
{
  "metadata": {
    "bytecodeHash": "none",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address","name":"stakingToken","type":"address"},{"internalType":"address","name":"rewardMaster","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Delegation","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"staker","type":"address"},{"indexed":false,"internalType":"uint256","name":"stakeID","type":"uint256"}],"name":"RewardMasterRevert","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"stakeID","type":"uint256"}],"name":"StakeClaimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"stakeID","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"indexed":false,"internalType":"uint256","name":"lockedTill","type":"uint256"}],"name":"StakeCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"stakeType","type":"bytes4"}],"name":"TermsAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes4","name":"stakeType","type":"bytes4"}],"name":"TermsDisabled","type":"event"},{"inputs":[],"name":"OWNER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"REWARD_MASTER","outputs":[{"internalType":"contract IActionMsgReceiver","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"START_BLOCK","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN","outputs":[{"internalType":"contract IErc20Min","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"accountStakes","outputs":[{"components":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"internalType":"uint32","name":"stakedAt","type":"uint32"},{"internalType":"uint32","name":"lockedTill","type":"uint32"},{"internalType":"uint32","name":"claimedAt","type":"uint32"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"delegatee","type":"address"}],"internalType":"struct IStakingTypes.Stake[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"components":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isRewarded","type":"bool"},{"internalType":"uint32","name":"minAmountScaled","type":"uint32"},{"internalType":"uint32","name":"maxAmountScaled","type":"uint32"},{"internalType":"uint32","name":"allowedSince","type":"uint32"},{"internalType":"uint32","name":"allowedTill","type":"uint32"},{"internalType":"uint32","name":"lockedTill","type":"uint32"},{"internalType":"uint32","name":"exactLockPeriod","type":"uint32"},{"internalType":"uint32","name":"minLockPeriod","type":"uint32"}],"internalType":"struct IStakingTypes.Terms","name":"_terms","type":"tuple"}],"name":"addTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeID","type":"uint256"},{"internalType":"address","name":"to","type":"address"}],"name":"delegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"stakeType","type":"bytes4"}],"name":"disableTerms","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"name":"globalSnapshotAt","outputs":[{"components":[{"internalType":"uint32","name":"beforeBlock","type":"uint32"},{"internalType":"uint96","name":"ownPower","type":"uint96"},{"internalType":"uint96","name":"delegatedPower","type":"uint96"}],"internalType":"struct IVotingPower.Snapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"globalsSnapshot","outputs":[{"components":[{"internalType":"uint32","name":"beforeBlock","type":"uint32"},{"internalType":"uint96","name":"ownPower","type":"uint96"},{"internalType":"uint96","name":"delegatedPower","type":"uint96"}],"internalType":"struct IVotingPower.Snapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"globalsSnapshotLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"latestGlobalsSnapshotBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"latestSnapshotBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"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"},{"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"permitAndStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"power","outputs":[{"internalType":"uint96","name":"own","type":"uint96"},{"internalType":"uint96","name":"delegated","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"_index","type":"uint256"}],"name":"snapshot","outputs":[{"components":[{"internalType":"uint32","name":"beforeBlock","type":"uint32"},{"internalType":"uint96","name":"ownPower","type":"uint96"},{"internalType":"uint96","name":"delegatedPower","type":"uint96"}],"internalType":"struct IVotingPower.Snapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"uint256","name":"blockNum","type":"uint256"},{"internalType":"uint256","name":"hint","type":"uint256"}],"name":"snapshotAt","outputs":[{"components":[{"internalType":"uint32","name":"beforeBlock","type":"uint32"},{"internalType":"uint96","name":"ownPower","type":"uint96"},{"internalType":"uint96","name":"delegatedPower","type":"uint96"}],"internalType":"struct IVotingPower.Snapshot","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"snapshotLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"stake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"stakes","outputs":[{"internalType":"uint32","name":"id","type":"uint32"},{"internalType":"bytes4","name":"stakeType","type":"bytes4"},{"internalType":"uint32","name":"stakedAt","type":"uint32"},{"internalType":"uint32","name":"lockedTill","type":"uint32"},{"internalType":"uint32","name":"claimedAt","type":"uint32"},{"internalType":"uint96","name":"amount","type":"uint96"},{"internalType":"address","name":"delegatee","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"stakesNum","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"name":"terms","outputs":[{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isRewarded","type":"bool"},{"internalType":"uint32","name":"minAmountScaled","type":"uint32"},{"internalType":"uint32","name":"maxAmountScaled","type":"uint32"},{"internalType":"uint32","name":"allowedSince","type":"uint32"},{"internalType":"uint32","name":"allowedTill","type":"uint32"},{"internalType":"uint32","name":"lockedTill","type":"uint32"},{"internalType":"uint32","name":"exactLockPeriod","type":"uint32"},{"internalType":"uint32","name":"minLockPeriod","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalPower","outputs":[{"components":[{"internalType":"uint96","name":"own","type":"uint96"},{"internalType":"uint96","name":"delegated","type":"uint96"}],"internalType":"struct IVotingPower.Power","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalStaked","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVotingPower","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeID","type":"uint256"}],"name":"undelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakeID","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bool","name":"_isForced","type":"bool"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]

610100604052600080546001600160601b03191690553480156200002257600080fd5b5060405162003e6538038062003e6583398101604081905262000045916200015a565b806001600160a01b038116620000a25760405162461bcd60e51b815260206004820152601a60248201527f496d6d4f776e3a207a65726f206f776e6572206164647265737300000000000060448201526064015b60405180910390fd5b60601b6001600160601b0319166080526001600160a01b03831615801590620000d357506001600160a01b03821615155b6200010e5760405162461bcd60e51b815260206004820152600a6024820152695374616b696e673a433160b01b604482015260640162000099565b6001600160601b0319606084811b821660a05283901b1660e052620001304390565b60c05250620001a3915050565b80516001600160a01b03811681146200015557600080fd5b919050565b6000806000606084860312156200016f578283fd5b6200017a846200013d565b92506200018a602085016200013d565b91506200019a604085016200013d565b90509250925092565b60805160601c60a05160601c60c05160e05160601c613c4e62000217600039600081816103cc01528181612e8b01526131b80152600061032b0152600081816104dc01528181610c98015281816118de015261275c01526000818161028701528181610db50152611b1a0152613c4e6000f3fe608060405234801561001057600080fd5b50600436106101b95760003560e01c8063584b62a1116100f957806382bfefc811610097578063ce24b29311610071578063ce24b293146105e1578063db3ad22c146105f4578063f9b7ab161461066e578063fc114a811461068157600080fd5b806382bfefc8146104d7578063a281edf6146104fe578063a55743001461051157600080fd5b80636fa5734a116100d35780636fa5734a1461047e578063729aedad146104865780637f67833414610499578063817b1cd2146104ac57600080fd5b8063584b62a1146103ee578063671b3793146104635780636c68c0e11461046b57600080fd5b806323574e40116101665780633aaf59e4116101405780633aaf59e41461034d578063503371a5146103605780635391dff5146103b4578063576eadd2146103c757600080fd5b806323574e40146102ea57806332f0c5341461031357806339b3e8261461032657600080fd5b806309fe7dd81161019757806309fe7dd814610236578063117803e3146102825780631ea06bba146102c157600080fd5b806305517146146101be578063074bc01d146101e757806308bbb82414610221575b600080fd5b6101d16101cc366004613641565b610694565b6040516101de9190613a13565b60405180910390f35b6000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec545b6040519081526020016101de565b61023461022f366004613886565b610787565b005b61024961024436600461386e565b610b33565b60408051825163ffffffff1681526020808401516001600160601b039081169183019190915292820151909216908201526060016101de565b6102a97f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020016101de565b6102136102cf366004613641565b6001600160a01b031660009081526004602052604090205490565b6102136102f8366004613641565b6001600160a01b031660009081526002602052604090205490565b6102136103213660046136b6565b610bea565b6102137f000000000000000000000000000000000000000000000000000000000000000081565b61024961035b36600461365b565b610d0f565b61039461036e366004613641565b6003602052600090815260409020546001600160601b0380821691600160601b90041682565b604080516001600160601b039384168152929091166020830152016101de565b6102346103c2366004613790565b610db3565b6102a97f000000000000000000000000000000000000000000000000000000000000000081565b6104016103fc36600461365b565b611441565b6040805163ffffffff98891681526001600160e01b031990971660208801529487169486019490945291851660608501529390931660808301526001600160601b0390921660a08201526001600160a01b0390911660c082015260e0016101de565b6102136114ce565b61023461047936600461386e565b61153d565b61021361154a565b610249610494366004613684565b61155b565b6102346104a7366004613909565b61158d565b6000546104bf906001600160601b031681565b6040516001600160601b0390911681526020016101de565b6102a97f000000000000000000000000000000000000000000000000000000000000000081565b61021361050c3660046138b1565b611a7f565b61058c61051f366004613776565b60016020526000908152604090205460ff8082169161010081049091169063ffffffff62010000820481169166010000000000008104821691600160501b8204811691600160701b8104821691600160901b8204811691600160b01b8104821691600160d01b9091041689565b604080519915158a5297151560208a015263ffffffff9687169789019790975293851660608801529184166080870152831660a0860152821660c0850152811660e084015216610100820152610120016101de565b6102136105ef366004613641565b611a97565b60408051808201825260008082526020918201819052805260038152815180830183527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff546001600160601b03808216808452600160601b90920481169284019283528451918252915190911691810191909152016101de565b61023461067c366004613776565b611b18565b61024961068f366004613966565b611fce565b6001600160a01b0381166000908152600260209081526040808320805482518185028101850190935280835260609493849084015b8282101561077b5760008481526020908190206040805160e0808201835260028702909301805463ffffffff8082168452640100000000820490951b6001600160e01b03191683870152680100000000000000008104851693830193909352600160601b830484166060830152600160801b83049093166080820152600160a01b9091046001600160601b031660a08201526001918201546001600160a01b031660c0820152835290920191016106c9565b50929695505050505050565b33600081815260026020526040902054839081106107ec5760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a205374616b6520646f65736e27742065786973740000000060448201526064015b60405180910390fd5b6001600160a01b0383166108685760405162461bcd60e51b815260206004820152602960248201527f5374616b696e673a2043616e27742064656c656761746520746f20474c4f424160448201527f4c5f4143434f554e54000000000000000000000000000000000000000000000060648201526084016107e3565b33600090815260026020526040812080548690811061089757634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160e08082018352600294909402909201805463ffffffff8082168552640100000000820490951b6001600160e01b03191695840195909552680100000000000000008504841691830191909152600160601b840483166060830152600160801b840490921660808201819052600160a01b9093046001600160601b031660a08201526001909101546001600160a01b031660c082015291501561098b5760405162461bcd60e51b815260206004820152601660248201527f5374616b696e673a205374616b6520636c61696d65640000000000000000000060448201526064016107e3565b836001600160a01b03168160c001516001600160a01b031614156109f15760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e673a20416c72656164792064656c65676174656400000000000060448201526064016107e3565b60c08101516001600160a01b0316610a2057610a1b33858360a001516001600160601b0316611ff7565b610a69565b6001600160a01b038416331415610a4d57610a1b8160c00151338360a001516001600160601b0316612187565b610a698160c00151858360a001516001600160601b03166122d2565b60c081015160a0820151604080518881526001600160601b0390921660208301526001600160a01b0380881693169133917f35139ff50199d80fb2041281ddf20e81c33e5506d58d42848aed916b7dfc9902910160405180910390a4336000908152600260205260409020805485919087908110610af757634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050505050565b60408051606081018252600080825260208201819052918101919091526000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec805483908110610b9a57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015292915050565b60006001600160a01b038a163314610c4e5760405162461bcd60e51b815260206004820152602160248201527f5374616b696e673a206f776e6572206d757374206265206d73672e73656e64656044820152603960f91b60648201526084016107e3565b60405163d505accf60e01b81526001600160a01b038b81166004830152306024830152604482018b9052606482018a905260ff8916608483015260a4820188905260c482018790527f0000000000000000000000000000000000000000000000000000000000000000169063d505accf9060e401600060405180830381600087803b158015610cdc57600080fd5b505af1158015610cf0573d6000803e3d6000fd5b50505050610d018a8a86868661231f565b9a9950505050505050505050565b60408051606081018252600080825260208083018290528284018290526001600160a01b03861682526004905291909120805483908110610d6057634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015290505b92915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314610e2b5760405162461bcd60e51b815260206004820152601460248201527f496d6d4f776e3a20756e617574686f72697a656400000000000000000000000060448201526064016107e3565b816001600160e01b03198116610e835760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b6001600160e01b03198316600090815260016020908152604091829020825161012081018452905460ff8082161515835261010080830490911615159383019390935263ffffffff6201000082048116948301949094526601000000000000810484166060830152600160501b810484166080830152600160701b8104841660a0830152600160901b8104841660c0830152600160b01b8104841660e0830152600160d01b900490921690820152610f3a81612b26565b15610f875760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45310000000000000000000000000000000000000000000060448201526064016107e3565b8251610fd55760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45320000000000000000000000000000000000000000000060448201526064016107e3565b60a0830151429063ffffffff16156110a357808460a0015163ffffffff16116110405760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45330000000000000000000000000000000000000000000060448201526064016107e3565b836080015163ffffffff168460a0015163ffffffff16116110a35760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45340000000000000000000000000000000000000000000060448201526064016107e3565b606084015163ffffffff161561111657836040015163ffffffff16846060015163ffffffff16116111165760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45350000000000000000000000000000000000000000000060448201526064016107e3565b60c084015163ffffffff16156112115760e084015163ffffffff16158015611147575061010084015163ffffffff16155b6111935760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45360000000000000000000000000000000000000000000060448201526064016107e3565b808460c0015163ffffffff161180156111c057508360a0015163ffffffff168460c0015163ffffffff1610155b61120c5760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45370000000000000000000000000000000000000000000060448201526064016107e3565b611276565b61010084015160e085015163ffffffff9081161591161514156112765760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45380000000000000000000000000000000000000000000060448201526064016107e3565b8360016000876001600160e01b0319166001600160e01b031916815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600e6101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160126101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160166101000a81548163ffffffff021916908363ffffffff16021790555061010082015181600001601a6101000a81548163ffffffff021916908363ffffffff1602179055509050507f5b115698ff2b7b4225a2027f36fbf8ed56c057120b7286510f6a4792b124c3da8560405161143291906001600160e01b031991909116815260200190565b60405180910390a15050505050565b6002602052816000526040600020818154811061145d57600080fd5b60009182526020909120600290910201805460019091015463ffffffff8083169450640100000000830460e01b9350680100000000000000008304811692600160601b8104821692600160801b820490921691600160a01b9091046001600160601b0316906001600160a01b031687565b600080805260036020908152604080518082019091527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff546001600160601b03808216808452600160601b90920416928201839052909161152e91613b74565b6001600160601b031691505090565b6115478133610787565b50565b60006115566000611a97565b905090565b6040805160608101825260008082526020820181905291810191909152611583848484612b62565b90505b9392505050565b33600081815260026020526040902054859081106115ed5760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a205374616b6520646f65736e27742065786973740000000060448201526064016107e3565b33600090815260026020526040812080548890811061161c57634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160e08082018352600294909402909201805463ffffffff8082168552640100000000820490951b6001600160e01b03191695840195909552680100000000000000008504841691830191909152600160601b840483166060830152600160801b840490921660808201819052600160a01b9093046001600160601b031660a08201526001909101546001600160a01b031660c08201529150156117105760405162461bcd60e51b815260206004820152601660248201527f5374616b696e673a205374616b6520636c61696d65640000000000000000000060448201526064016107e3565b611718612d24565b63ffffffff16816060015163ffffffff16106117765760405162461bcd60e51b815260206004820152601560248201527f5374616b696e673a205374616b65206c6f636b6564000000000000000000000060448201526064016107e3565b60c08101516001600160a01b0316156117a5576117a58160c00151338360a001516001600160601b0316612187565b6117bc338260a001516001600160601b0316612d2f565b6117c4612d24565b3360009081526002602052604090208054899081106117f357634e487b7160e01b600052603260045260246000fd5b600091825260208220600290910201805463ffffffff93909316600160801b027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9093169290921790915560a082015190546118649161185f916001600160601b039182169116613bde565b612df9565b600080546bffffffffffffffffffffffff19166001600160601b0392909216919091178155604051889133917f2aeea59856f5616c244717fd488ead1d1b5fd33608d9583a4607b4c4ba3631e49190a360a081015160405163a9059cbb60e01b81523360048201526001600160601b0390911660248201527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063a9059cbb90604401602060405180830381600087803b15801561192a57600080fd5b505af115801561193e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611962919061375a565b6119ae5760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a207472616e73666572206661696c6564000000000000000060448201526064016107e3565b6020808201516001600160e01b031916600090815260018252604090819020815161012081018352905460ff808216151583526101008083049091161580159584019590955263ffffffff6201000083048116948401949094526601000000000000820484166060840152600160501b820484166080840152600160701b8204841660a0840152600160901b8204841660c0840152600160b01b8204841660e0840152600160d01b9091049092169181019190915290611a7557611a753383898989612e52565b5050505050505050565b6000611a8e338686868661231f565b95945050505050565b6001600160a01b038116600090815260046020526040812054611abc57506000919050565b6001600160a01b03821660009081526004602052604090208054611ae290600190613bde565b81548110611b0057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1692915050565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163314611b905760405162461bcd60e51b815260206004820152601460248201527f496d6d4f776e3a20756e617574686f72697a656400000000000000000000000060448201526064016107e3565b806001600160e01b03198116611be85760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b600060016000846001600160e01b0319166001600160e01b0319168152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600e9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160129054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160169054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509050611eda60016000856001600160e01b0319166001600160e01b0319168152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600e9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160129054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160169054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff1681525050612b26565b611f265760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45390000000000000000000000000000000000000000000060448201526064016107e3565b8051611f745760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45410000000000000000000000000000000000000000000060448201526064016107e3565b6001600160e01b03198316600081815260016020908152604091829020805460ff1916905590519182527f8a38309c2f745d8049207b437f03ddd33259692a1e387c7ab67dceb1cf1b29bf910160405180910390a1505050565b604080516060810182526000808252602082018190529181019190915261158660008484612b62565b6120016000612f91565b61200a82612f91565b61201383612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548392906120579084906001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b0385166000908152600360205260408120805485945090926120a291859116613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556000805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548493509091600c91612109918591600160601b900416613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040902080548493509091600c9161215e918591600160601b900416613b74565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550505050565b6000805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054829190600c906121d4908490600160601b90046001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038516600090815260036020526040902080548493509091600c91612229918591600160601b900416613bf5565b82546101009290920a6001600160601b03818102199093169183160217909155600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054859450909261228791859116613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b03841660009081526003602052604081208054859450909261215e91859116613b74565b6122db82612f91565b6122e483612f91565b6001600160a01b03831660009081526003602052604090208054829190600c90612109908490600160601b90046001600160601b0316613bf5565b6000836001600160e01b031981166123795760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b6001600160e01b03198516600090815260016020908152604091829020825161012081018452905460ff808216151580845261010080840490921615159484019490945263ffffffff6201000083048116958401959095526601000000000000820485166060840152600160501b820485166080840152600160701b8204851660a0840152600160901b8204851660c0840152600160b01b8204851660e0840152600160d01b909104909316928101929092526124835760405162461bcd60e51b815260206004820152602260248201527f5374616b696e673a205465726d7320756e6b6e6f776e206f722064697361626c604482015261195960f21b60648201526084016107e3565b600087116124d35760405162461bcd60e51b815260206004820152601760248201527f5374616b696e673a20416d6f756e74206e6f742073657400000000000000000060448201526064016107e3565b600080546124ea906001600160601b031689613b5c565b9050600160601b811061253f5760405162461bcd60e51b815260206004820152601760248201527f5374616b696e673a20546f6f2062696720616d6f756e7400000000000000000060448201526064016107e3565b604082015163ffffffff1615806125725750604082015161256e9063ffffffff16670de0b6b3a7640000613bbf565b8810155b6125be5760405162461bcd60e51b815260206004820152601960248201527f5374616b696e673a20546f6f20736d616c6c20616d6f756e740000000000000060448201526064016107e3565b606082015163ffffffff1615806125f1575060608201516125ed9063ffffffff16670de0b6b3a7640000613bbf565b8811155b61263d5760405162461bcd60e51b815260206004820152601960248201527f5374616b696e673a20546f6f206c6172676520616d6f756e740000000000000060448201526064016107e3565b6000612647612d24565b9050826080015163ffffffff16600014806126725750826080015163ffffffff168163ffffffff1610155b6126be5760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a204e6f742079657420616c6c6f776564000000000000000060448201526064016107e3565b60a083015163ffffffff1615806126e457508063ffffffff168360a0015163ffffffff16115b6127305760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a204e6f7420616c6c6f77656420616e796d6f72650000000060448201526064016107e3565b6040516323b872dd60e01b81526001600160a01b038b81166004830152306024830152604482018b90527f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401602060405180830381600087803b1580156127a057600080fd5b505af11580156127b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d8919061375a565b6128245760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a207472616e7366657246726f6d206661696c65640000000060448201526064016107e3565b6001600160a01b038a1660009081526002602052604090205460c084015163ffffffff81166128985760008560e0015163ffffffff1660001461286b578560e00151612872565b8561010001515b63ffffffff1690506128948463ffffffff168261288f9190613b5c565b613087565b9150505b60006040518060e001604052808463ffffffff1681526020018c6001600160e01b03191681526020018563ffffffff1681526020018363ffffffff168152602001600063ffffffff1681526020018d6001600160601b0316815260200160006001600160a01b03168152509050600260008e6001600160a01b03166001600160a01b0316815260200190815260200160002081908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908360e01c021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060c08201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050846000806101000a8154816001600160601b0302191690836001600160601b03160217905550612aa08d8d6130dd565b604080518d81526001600160e01b03198d16602082015263ffffffff84169181019190915283906001600160a01b038f16907f0a48826ba73bb7c5bdedec0209a3e40a05d0c40f2d1e00da1e381e845f7dc8459060600160405180910390a3856020015115612b1557612b158d828c8c61317f565b50909b9a5050505050505050505050565b600081610100015163ffffffff166000141580612b4c575060e082015163ffffffff1615155b80610dad57505060c0015163ffffffff16151590565b6040805160608101825260008082526020820181905291810191909152612b888361326e565b6001600160a01b038416600090815260046020526040902080548311801590612bf35750821580612bf357508381612bc1600186613bde565b81548110612bdf57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b8015612c3a57508054831480612c3a575083818481548110612c2557634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1610155b15612d12578054831015612cbb57808381548110612c6857634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015291506115869050565b50506040805160608101825263ffffffff841681526001600160a01b038516600081815260036020818152858320546001600160601b03808216838801529490935252600160601b90041691810191909152611586565b612d1c85856132cb565b915050611586565b600061155642613087565b612d396000612f91565b612d4282612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054839290612d869084906001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040812080548594509092612dd191859116613bf5565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050565b6000600160601b8210612e4e5760405162461bcd60e51b815260206004820152600860248201527f554e53414645393600000000000000000000000000000000000000000000000060448201526064016107e3565b5090565b6000612e6185602001516134df565b90506000612e7187878787613523565b604051630dc3282360e11b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631b86504690612ec29085908590600401613ac0565b600060405180830381600087803b158015612edc57600080fd5b505af1925050508015612eed575060015b612f88578551604080516001600160a01b038a16815263ffffffff90921660208301527fd496f27946fc12806531d73524a978ff3424ad0667a52e27d51a4a732b2f2e75910160405180910390a182612f885760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a205245574152445f4d41535445522072657665727473000060448201526064016107e3565b50505050505050565b6000612f9b613571565b90508063ffffffff16612fad83611a97565b1015613083576001600160a01b0382166000818152600460209081526040808320815160608101835263ffffffff80881682529585526003808552838620546001600160601b03808216848801908152928752600160601b9091048116948301948552835460018101855593875294909520905191018054945192518416600160801b027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff93909416640100000000026fffffffffffffffffffffffffffffffff19909516919095161792909217919091161790555b5050565b60006401000000008210612e4e5760405162461bcd60e51b815260206004820152600860248201527f554e53414645333200000000000000000000000000000000000000000000000060448201526064016107e3565b6130e76000612f91565b6130f082612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548392906131349084906001600160601b0316613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040812080548594509092612dd191859116613b74565b600061318e846020015161357c565b9050600061319e86868686613523565b604051630dc3282360e11b81529091506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690631b865046906131ef9085908590600401613ac0565b600060405180830381600087803b15801561320957600080fd5b505af192505050801561321a575060015b6132665760405162461bcd60e51b815260206004820152601b60248201527f5374616b696e673a206f6e5374616b65206d7367206661696c6564000000000060448201526064016107e3565b505050505050565b613276613571565b63ffffffff168111156115475760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20546f6f2062696720626c6f636b206e756d62657200000060448201526064016107e3565b60408051606081018252600080825260208201819052918101919091526132f18261326e565b6001600160a01b0383166000908152600460205260408120805490919081905b8082101561338857600060026133278385613b5c565b6133319190613b9f565b90508685828154811061335457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16111561337457809150613382565b61337f816001613b5c565b92505b50613311565b6000821180156133d2575085846133a0600185613bde565b815481106133be57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16145b1561345757836133e3600184613bde565b8154811061340157634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b9004909216908201529450610dad9350505050565b81925083548314156134bf5750506040805160608101825263ffffffff861681526001600160a01b038716600081815260036020818152858320546001600160601b03808216838801529490935252600160601b900416918101919091529250610dad915050565b83838154811061340157634e487b7160e01b600052603260045260246000fd5b604051637a3e3dfd60e01b60208201526001600160e01b0319821660248201526000906028015b604051602081830303815290604052805190602001209050919050565b6060848460a0015185600001518660400151876060015188608001518888604051602001613558989796959493929190613987565b6040516020818303038152906040529050949350505050565b600061155643613087565b60405163c3a0479560e01b60208201526001600160e01b031982166024820152600090602801613506565b80356001600160a01b03811681146135be57600080fd5b919050565b80356135be81613c33565b80356001600160e01b0319811681146135be57600080fd5b60008083601f8401126135f7578182fd5b50813567ffffffffffffffff81111561360e578182fd5b60208301915083602082850101111561362657600080fd5b9250929050565b803563ffffffff811681146135be57600080fd5b600060208284031215613652578081fd5b611586826135a7565b6000806040838503121561366d578081fd5b613676836135a7565b946020939093013593505050565b600080600060608486031215613698578081fd5b6136a1846135a7565b95602085013595506040909401359392505050565b60008060008060008060008060006101008a8c0312156136d4578485fd5b6136dd8a6135a7565b985060208a0135975060408a0135965060608a013560ff81168114613700578586fd5b955060808a0135945060a08a0135935061371c60c08b016135ce565b925060e08a013567ffffffffffffffff811115613737578283fd5b6137438c828d016135e6565b915080935050809150509295985092959850929598565b60006020828403121561376b578081fd5b815161158681613c33565b600060208284031215613787578081fd5b611586826135ce565b6000808284036101408112156137a4578283fd5b6137ad846135ce565b925061012080601f19830112156137c2578283fd5b6137ca613b24565b91506137d8602086016135c3565b82526137e6604086016135c3565b60208301526137f76060860161362d565b60408301526138086080860161362d565b606083015261381960a0860161362d565b608083015261382a60c0860161362d565b60a083015261383b60e0860161362d565b60c083015261010061384e81870161362d565b60e084015261385e82870161362d565b9083015250919491935090915050565b60006020828403121561387f578081fd5b5035919050565b60008060408385031215613898578182fd5b823591506138a8602084016135a7565b90509250929050565b600080600080606085870312156138c6578384fd5b843593506138d6602086016135ce565b9250604085013567ffffffffffffffff8111156138f1578283fd5b6138fd878288016135e6565b95989497509550505050565b6000806000806060858703121561391e578081fd5b84359350602085013567ffffffffffffffff81111561393b578182fd5b613947878288016135e6565b909450925050604085013561395b81613c33565b939692955090935050565b60008060408385031215613978578182fd5b50508035926020909101359150565b6001600160601b03198960601b1681527fffffffffffffffffffffffff00000000000000000000000000000000000000008860a01b166014820152600063ffffffff60e01b808960e01b166020840152808860e01b166024840152808760e01b166028840152808660e01b16602c84015250828460308401379101603001908152979650505050505050565b602080825282518282018190526000919060409081850190868401855b82811015613ab3578151805163ffffffff9081168652878201516001600160e01b03191688870152868201518116878701526060808301518216908701526080808301519091169086015260a0808201516001600160601b03169086015260c0908101516001600160a01b03169085015260e09093019290850190600101613a30565b5091979650505050505050565b63ffffffff60e01b83168152600060206040818401528351806040850152825b81811015613afc57858101830151858201606001528201613ae0565b81811115613b0d5783606083870101525b50601f01601f191692909201606001949350505050565b604051610120810167ffffffffffffffff81118282101715613b5657634e487b7160e01b600052604160045260246000fd5b60405290565b60008219821115613b6f57613b6f613c1d565b500190565b60006001600160601b03808316818516808303821115613b9657613b96613c1d565b01949350505050565b600082613bba57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615613bd957613bd9613c1d565b500290565b600082821015613bf057613bf0613c1d565b500390565b60006001600160601b0383811690831681811015613c1557613c15613c1d565b039392505050565b634e487b7160e01b600052601160045260246000fd5b801515811461154757600080fdfea164736f6c6343000804000a000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa173000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd77

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101b95760003560e01c8063584b62a1116100f957806382bfefc811610097578063ce24b29311610071578063ce24b293146105e1578063db3ad22c146105f4578063f9b7ab161461066e578063fc114a811461068157600080fd5b806382bfefc8146104d7578063a281edf6146104fe578063a55743001461051157600080fd5b80636fa5734a116100d35780636fa5734a1461047e578063729aedad146104865780637f67833414610499578063817b1cd2146104ac57600080fd5b8063584b62a1146103ee578063671b3793146104635780636c68c0e11461046b57600080fd5b806323574e40116101665780633aaf59e4116101405780633aaf59e41461034d578063503371a5146103605780635391dff5146103b4578063576eadd2146103c757600080fd5b806323574e40146102ea57806332f0c5341461031357806339b3e8261461032657600080fd5b806309fe7dd81161019757806309fe7dd814610236578063117803e3146102825780631ea06bba146102c157600080fd5b806305517146146101be578063074bc01d146101e757806308bbb82414610221575b600080fd5b6101d16101cc366004613641565b610694565b6040516101de9190613a13565b60405180910390f35b6000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec545b6040519081526020016101de565b61023461022f366004613886565b610787565b005b61024961024436600461386e565b610b33565b60408051825163ffffffff1681526020808401516001600160601b039081169183019190915292820151909216908201526060016101de565b6102a97f000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd7781565b6040516001600160a01b0390911681526020016101de565b6102136102cf366004613641565b6001600160a01b031660009081526004602052604090205490565b6102136102f8366004613641565b6001600160a01b031660009081526002602052604090205490565b6102136103213660046136b6565b610bea565b6102137f0000000000000000000000000000000000000000000000000000000000d6e91381565b61024961035b36600461365b565b610d0f565b61039461036e366004613641565b6003602052600090815260409020546001600160601b0380821691600160601b90041682565b604080516001600160601b039384168152929091166020830152016101de565b6102346103c2366004613790565b610db3565b6102a97f000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc81565b6104016103fc36600461365b565b611441565b6040805163ffffffff98891681526001600160e01b031990971660208801529487169486019490945291851660608501529390931660808301526001600160601b0390921660a08201526001600160a01b0390911660c082015260e0016101de565b6102136114ce565b61023461047936600461386e565b61153d565b61021361154a565b610249610494366004613684565b61155b565b6102346104a7366004613909565b61158d565b6000546104bf906001600160601b031681565b6040516001600160601b0390911681526020016101de565b6102a97f000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa17381565b61021361050c3660046138b1565b611a7f565b61058c61051f366004613776565b60016020526000908152604090205460ff8082169161010081049091169063ffffffff62010000820481169166010000000000008104821691600160501b8204811691600160701b8104821691600160901b8204811691600160b01b8104821691600160d01b9091041689565b604080519915158a5297151560208a015263ffffffff9687169789019790975293851660608801529184166080870152831660a0860152821660c0850152811660e084015216610100820152610120016101de565b6102136105ef366004613641565b611a97565b60408051808201825260008082526020918201819052805260038152815180830183527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff546001600160601b03808216808452600160601b90920481169284019283528451918252915190911691810191909152016101de565b61023461067c366004613776565b611b18565b61024961068f366004613966565b611fce565b6001600160a01b0381166000908152600260209081526040808320805482518185028101850190935280835260609493849084015b8282101561077b5760008481526020908190206040805160e0808201835260028702909301805463ffffffff8082168452640100000000820490951b6001600160e01b03191683870152680100000000000000008104851693830193909352600160601b830484166060830152600160801b83049093166080820152600160a01b9091046001600160601b031660a08201526001918201546001600160a01b031660c0820152835290920191016106c9565b50929695505050505050565b33600081815260026020526040902054839081106107ec5760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a205374616b6520646f65736e27742065786973740000000060448201526064015b60405180910390fd5b6001600160a01b0383166108685760405162461bcd60e51b815260206004820152602960248201527f5374616b696e673a2043616e27742064656c656761746520746f20474c4f424160448201527f4c5f4143434f554e54000000000000000000000000000000000000000000000060648201526084016107e3565b33600090815260026020526040812080548690811061089757634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160e08082018352600294909402909201805463ffffffff8082168552640100000000820490951b6001600160e01b03191695840195909552680100000000000000008504841691830191909152600160601b840483166060830152600160801b840490921660808201819052600160a01b9093046001600160601b031660a08201526001909101546001600160a01b031660c082015291501561098b5760405162461bcd60e51b815260206004820152601660248201527f5374616b696e673a205374616b6520636c61696d65640000000000000000000060448201526064016107e3565b836001600160a01b03168160c001516001600160a01b031614156109f15760405162461bcd60e51b815260206004820152601a60248201527f5374616b696e673a20416c72656164792064656c65676174656400000000000060448201526064016107e3565b60c08101516001600160a01b0316610a2057610a1b33858360a001516001600160601b0316611ff7565b610a69565b6001600160a01b038416331415610a4d57610a1b8160c00151338360a001516001600160601b0316612187565b610a698160c00151858360a001516001600160601b03166122d2565b60c081015160a0820151604080518881526001600160601b0390921660208301526001600160a01b0380881693169133917f35139ff50199d80fb2041281ddf20e81c33e5506d58d42848aed916b7dfc9902910160405180910390a4336000908152600260205260409020805485919087908110610af757634e487b7160e01b600052603260045260246000fd5b906000526020600020906002020160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050505050565b60408051606081018252600080825260208201819052918101919091526000805260046020527f17ef568e3e12ab5b9c7254a8d58478811de00f9e6eb34345acd53bf8fd09d3ec805483908110610b9a57634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015292915050565b60006001600160a01b038a163314610c4e5760405162461bcd60e51b815260206004820152602160248201527f5374616b696e673a206f776e6572206d757374206265206d73672e73656e64656044820152603960f91b60648201526084016107e3565b60405163d505accf60e01b81526001600160a01b038b81166004830152306024830152604482018b9052606482018a905260ff8916608483015260a4820188905260c482018790527f000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa173169063d505accf9060e401600060405180830381600087803b158015610cdc57600080fd5b505af1158015610cf0573d6000803e3d6000fd5b50505050610d018a8a86868661231f565b9a9950505050505050505050565b60408051606081018252600080825260208083018290528284018290526001600160a01b03861682526004905291909120805483908110610d6057634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015290505b92915050565b7f000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd776001600160a01b03163314610e2b5760405162461bcd60e51b815260206004820152601460248201527f496d6d4f776e3a20756e617574686f72697a656400000000000000000000000060448201526064016107e3565b816001600160e01b03198116610e835760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b6001600160e01b03198316600090815260016020908152604091829020825161012081018452905460ff8082161515835261010080830490911615159383019390935263ffffffff6201000082048116948301949094526601000000000000810484166060830152600160501b810484166080830152600160701b8104841660a0830152600160901b8104841660c0830152600160b01b8104841660e0830152600160d01b900490921690820152610f3a81612b26565b15610f875760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45310000000000000000000000000000000000000000000060448201526064016107e3565b8251610fd55760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45320000000000000000000000000000000000000000000060448201526064016107e3565b60a0830151429063ffffffff16156110a357808460a0015163ffffffff16116110405760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45330000000000000000000000000000000000000000000060448201526064016107e3565b836080015163ffffffff168460a0015163ffffffff16116110a35760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45340000000000000000000000000000000000000000000060448201526064016107e3565b606084015163ffffffff161561111657836040015163ffffffff16846060015163ffffffff16116111165760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45350000000000000000000000000000000000000000000060448201526064016107e3565b60c084015163ffffffff16156112115760e084015163ffffffff16158015611147575061010084015163ffffffff16155b6111935760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45360000000000000000000000000000000000000000000060448201526064016107e3565b808460c0015163ffffffff161180156111c057508360a0015163ffffffff168460c0015163ffffffff1610155b61120c5760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45370000000000000000000000000000000000000000000060448201526064016107e3565b611276565b61010084015160e085015163ffffffff9081161591161514156112765760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45380000000000000000000000000000000000000000000060448201526064016107e3565b8360016000876001600160e01b0319166001600160e01b031916815260200190815260200160002060008201518160000160006101000a81548160ff02191690831515021790555060208201518160000160016101000a81548160ff02191690831515021790555060408201518160000160026101000a81548163ffffffff021916908363ffffffff16021790555060608201518160000160066101000a81548163ffffffff021916908363ffffffff160217905550608082015181600001600a6101000a81548163ffffffff021916908363ffffffff16021790555060a082015181600001600e6101000a81548163ffffffff021916908363ffffffff16021790555060c08201518160000160126101000a81548163ffffffff021916908363ffffffff16021790555060e08201518160000160166101000a81548163ffffffff021916908363ffffffff16021790555061010082015181600001601a6101000a81548163ffffffff021916908363ffffffff1602179055509050507f5b115698ff2b7b4225a2027f36fbf8ed56c057120b7286510f6a4792b124c3da8560405161143291906001600160e01b031991909116815260200190565b60405180910390a15050505050565b6002602052816000526040600020818154811061145d57600080fd5b60009182526020909120600290910201805460019091015463ffffffff8083169450640100000000830460e01b9350680100000000000000008304811692600160601b8104821692600160801b820490921691600160a01b9091046001600160601b0316906001600160a01b031687565b600080805260036020908152604080518082019091527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff546001600160601b03808216808452600160601b90920416928201839052909161152e91613b74565b6001600160601b031691505090565b6115478133610787565b50565b60006115566000611a97565b905090565b6040805160608101825260008082526020820181905291810191909152611583848484612b62565b90505b9392505050565b33600081815260026020526040902054859081106115ed5760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a205374616b6520646f65736e27742065786973740000000060448201526064016107e3565b33600090815260026020526040812080548890811061161c57634e487b7160e01b600052603260045260246000fd5b60009182526020918290206040805160e08082018352600294909402909201805463ffffffff8082168552640100000000820490951b6001600160e01b03191695840195909552680100000000000000008504841691830191909152600160601b840483166060830152600160801b840490921660808201819052600160a01b9093046001600160601b031660a08201526001909101546001600160a01b031660c08201529150156117105760405162461bcd60e51b815260206004820152601660248201527f5374616b696e673a205374616b6520636c61696d65640000000000000000000060448201526064016107e3565b611718612d24565b63ffffffff16816060015163ffffffff16106117765760405162461bcd60e51b815260206004820152601560248201527f5374616b696e673a205374616b65206c6f636b6564000000000000000000000060448201526064016107e3565b60c08101516001600160a01b0316156117a5576117a58160c00151338360a001516001600160601b0316612187565b6117bc338260a001516001600160601b0316612d2f565b6117c4612d24565b3360009081526002602052604090208054899081106117f357634e487b7160e01b600052603260045260246000fd5b600091825260208220600290910201805463ffffffff93909316600160801b027fffffffffffffffffffffffff00000000ffffffffffffffffffffffffffffffff9093169290921790915560a082015190546118649161185f916001600160601b039182169116613bde565b612df9565b600080546bffffffffffffffffffffffff19166001600160601b0392909216919091178155604051889133917f2aeea59856f5616c244717fd488ead1d1b5fd33608d9583a4607b4c4ba3631e49190a360a081015160405163a9059cbb60e01b81523360048201526001600160601b0390911660248201527f000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa1736001600160a01b03169063a9059cbb90604401602060405180830381600087803b15801561192a57600080fd5b505af115801561193e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611962919061375a565b6119ae5760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a207472616e73666572206661696c6564000000000000000060448201526064016107e3565b6020808201516001600160e01b031916600090815260018252604090819020815161012081018352905460ff808216151583526101008083049091161580159584019590955263ffffffff6201000083048116948401949094526601000000000000820484166060840152600160501b820484166080840152600160701b8204841660a0840152600160901b8204841660c0840152600160b01b8204841660e0840152600160d01b9091049092169181019190915290611a7557611a753383898989612e52565b5050505050505050565b6000611a8e338686868661231f565b95945050505050565b6001600160a01b038116600090815260046020526040812054611abc57506000919050565b6001600160a01b03821660009081526004602052604090208054611ae290600190613bde565b81548110611b0057634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1692915050565b7f000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd776001600160a01b03163314611b905760405162461bcd60e51b815260206004820152601460248201527f496d6d4f776e3a20756e617574686f72697a656400000000000000000000000060448201526064016107e3565b806001600160e01b03198116611be85760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b600060016000846001600160e01b0319166001600160e01b0319168152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600e9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160129054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160169054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815250509050611eda60016000856001600160e01b0319166001600160e01b0319168152602001908152602001600020604051806101200160405290816000820160009054906101000a900460ff161515151581526020016000820160019054906101000a900460ff161515151581526020016000820160029054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160069054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600a9054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201600e9054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160129054906101000a900463ffffffff1663ffffffff1663ffffffff1681526020016000820160169054906101000a900463ffffffff1663ffffffff1663ffffffff16815260200160008201601a9054906101000a900463ffffffff1663ffffffff1663ffffffff1681525050612b26565b611f265760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45390000000000000000000000000000000000000000000060448201526064016107e3565b8051611f745760405162461bcd60e51b815260206004820152600a60248201527f5374616b696e673a45410000000000000000000000000000000000000000000060448201526064016107e3565b6001600160e01b03198316600081815260016020908152604091829020805460ff1916905590519182527f8a38309c2f745d8049207b437f03ddd33259692a1e387c7ab67dceb1cf1b29bf910160405180910390a1505050565b604080516060810182526000808252602082018190529181019190915261158660008484612b62565b6120016000612f91565b61200a82612f91565b61201383612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548392906120579084906001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b0385166000908152600360205260408120805485945090926120a291859116613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556000805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548493509091600c91612109918591600160601b900416613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040902080548493509091600c9161215e918591600160601b900416613b74565b92506101000a8154816001600160601b0302191690836001600160601b03160217905550505050565b6000805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054829190600c906121d4908490600160601b90046001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038516600090815260036020526040902080548493509091600c91612229918591600160601b900416613bf5565b82546101009290920a6001600160601b03818102199093169183160217909155600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054859450909261228791859116613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b03841660009081526003602052604081208054859450909261215e91859116613b74565b6122db82612f91565b6122e483612f91565b6001600160a01b03831660009081526003602052604090208054829190600c90612109908490600160601b90046001600160601b0316613bf5565b6000836001600160e01b031981166123795760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20496e76616c6964207374616b652074797065203000000060448201526064016107e3565b6001600160e01b03198516600090815260016020908152604091829020825161012081018452905460ff808216151580845261010080840490921615159484019490945263ffffffff6201000083048116958401959095526601000000000000820485166060840152600160501b820485166080840152600160701b8204851660a0840152600160901b8204851660c0840152600160b01b8204851660e0840152600160d01b909104909316928101929092526124835760405162461bcd60e51b815260206004820152602260248201527f5374616b696e673a205465726d7320756e6b6e6f776e206f722064697361626c604482015261195960f21b60648201526084016107e3565b600087116124d35760405162461bcd60e51b815260206004820152601760248201527f5374616b696e673a20416d6f756e74206e6f742073657400000000000000000060448201526064016107e3565b600080546124ea906001600160601b031689613b5c565b9050600160601b811061253f5760405162461bcd60e51b815260206004820152601760248201527f5374616b696e673a20546f6f2062696720616d6f756e7400000000000000000060448201526064016107e3565b604082015163ffffffff1615806125725750604082015161256e9063ffffffff16670de0b6b3a7640000613bbf565b8810155b6125be5760405162461bcd60e51b815260206004820152601960248201527f5374616b696e673a20546f6f20736d616c6c20616d6f756e740000000000000060448201526064016107e3565b606082015163ffffffff1615806125f1575060608201516125ed9063ffffffff16670de0b6b3a7640000613bbf565b8811155b61263d5760405162461bcd60e51b815260206004820152601960248201527f5374616b696e673a20546f6f206c6172676520616d6f756e740000000000000060448201526064016107e3565b6000612647612d24565b9050826080015163ffffffff16600014806126725750826080015163ffffffff168163ffffffff1610155b6126be5760405162461bcd60e51b815260206004820152601860248201527f5374616b696e673a204e6f742079657420616c6c6f776564000000000000000060448201526064016107e3565b60a083015163ffffffff1615806126e457508063ffffffff168360a0015163ffffffff16115b6127305760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a204e6f7420616c6c6f77656420616e796d6f72650000000060448201526064016107e3565b6040516323b872dd60e01b81526001600160a01b038b81166004830152306024830152604482018b90527f000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa17316906323b872dd90606401602060405180830381600087803b1580156127a057600080fd5b505af11580156127b4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906127d8919061375a565b6128245760405162461bcd60e51b815260206004820152601c60248201527f5374616b696e673a207472616e7366657246726f6d206661696c65640000000060448201526064016107e3565b6001600160a01b038a1660009081526002602052604090205460c084015163ffffffff81166128985760008560e0015163ffffffff1660001461286b578560e00151612872565b8561010001515b63ffffffff1690506128948463ffffffff168261288f9190613b5c565b613087565b9150505b60006040518060e001604052808463ffffffff1681526020018c6001600160e01b03191681526020018563ffffffff1681526020018363ffffffff168152602001600063ffffffff1681526020018d6001600160601b0316815260200160006001600160a01b03168152509050600260008e6001600160a01b03166001600160a01b0316815260200190815260200160002081908060018154018082558091505060019003906000526020600020906002020160009091909190915060008201518160000160006101000a81548163ffffffff021916908363ffffffff16021790555060208201518160000160046101000a81548163ffffffff021916908360e01c021790555060408201518160000160086101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001600c6101000a81548163ffffffff021916908363ffffffff16021790555060808201518160000160106101000a81548163ffffffff021916908363ffffffff16021790555060a08201518160000160146101000a8154816001600160601b0302191690836001600160601b0316021790555060c08201518160010160006101000a8154816001600160a01b0302191690836001600160a01b031602179055505050846000806101000a8154816001600160601b0302191690836001600160601b03160217905550612aa08d8d6130dd565b604080518d81526001600160e01b03198d16602082015263ffffffff84169181019190915283906001600160a01b038f16907f0a48826ba73bb7c5bdedec0209a3e40a05d0c40f2d1e00da1e381e845f7dc8459060600160405180910390a3856020015115612b1557612b158d828c8c61317f565b50909b9a5050505050505050505050565b600081610100015163ffffffff166000141580612b4c575060e082015163ffffffff1615155b80610dad57505060c0015163ffffffff16151590565b6040805160608101825260008082526020820181905291810191909152612b888361326e565b6001600160a01b038416600090815260046020526040902080548311801590612bf35750821580612bf357508381612bc1600186613bde565b81548110612bdf57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16105b8015612c3a57508054831480612c3a575083818481548110612c2557634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff1610155b15612d12578054831015612cbb57808381548110612c6857634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b90049092169082015291506115869050565b50506040805160608101825263ffffffff841681526001600160a01b038516600081815260036020818152858320546001600160601b03808216838801529490935252600160601b90041691810191909152611586565b612d1c85856132cb565b915050611586565b600061155642613087565b612d396000612f91565b612d4282612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff8054839290612d869084906001600160601b0316613bf5565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040812080548594509092612dd191859116613bf5565b92506101000a8154816001600160601b0302191690836001600160601b031602179055505050565b6000600160601b8210612e4e5760405162461bcd60e51b815260206004820152600860248201527f554e53414645393600000000000000000000000000000000000000000000000060448201526064016107e3565b5090565b6000612e6185602001516134df565b90506000612e7187878787613523565b604051630dc3282360e11b81529091506001600160a01b037f000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc1690631b86504690612ec29085908590600401613ac0565b600060405180830381600087803b158015612edc57600080fd5b505af1925050508015612eed575060015b612f88578551604080516001600160a01b038a16815263ffffffff90921660208301527fd496f27946fc12806531d73524a978ff3424ad0667a52e27d51a4a732b2f2e75910160405180910390a182612f885760405162461bcd60e51b815260206004820152601e60248201527f5374616b696e673a205245574152445f4d41535445522072657665727473000060448201526064016107e3565b50505050505050565b6000612f9b613571565b90508063ffffffff16612fad83611a97565b1015613083576001600160a01b0382166000818152600460209081526040808320815160608101835263ffffffff80881682529585526003808552838620546001600160601b03808216848801908152928752600160601b9091048116948301948552835460018101855593875294909520905191018054945192518416600160801b027fffffffff000000000000000000000000ffffffffffffffffffffffffffffffff93909416640100000000026fffffffffffffffffffffffffffffffff19909516919095161792909217919091161790555b5050565b60006401000000008210612e4e5760405162461bcd60e51b815260206004820152600860248201527f554e53414645333200000000000000000000000000000000000000000000000060448201526064016107e3565b6130e76000612f91565b6130f082612f91565b600080805260036020527f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff80548392906131349084906001600160601b0316613b74565b82546101009290920a6001600160601b038181021990931691831602179091556001600160a01b038416600090815260036020526040812080548594509092612dd191859116613b74565b600061318e846020015161357c565b9050600061319e86868686613523565b604051630dc3282360e11b81529091506001600160a01b037f000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc1690631b865046906131ef9085908590600401613ac0565b600060405180830381600087803b15801561320957600080fd5b505af192505050801561321a575060015b6132665760405162461bcd60e51b815260206004820152601b60248201527f5374616b696e673a206f6e5374616b65206d7367206661696c6564000000000060448201526064016107e3565b505050505050565b613276613571565b63ffffffff168111156115475760405162461bcd60e51b815260206004820152601d60248201527f5374616b696e673a20546f6f2062696720626c6f636b206e756d62657200000060448201526064016107e3565b60408051606081018252600080825260208201819052918101919091526132f18261326e565b6001600160a01b0383166000908152600460205260408120805490919081905b8082101561338857600060026133278385613b5c565b6133319190613b9f565b90508685828154811061335457634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16111561337457809150613382565b61337f816001613b5c565b92505b50613311565b6000821180156133d2575085846133a0600185613bde565b815481106133be57634e487b7160e01b600052603260045260246000fd5b60009182526020909120015463ffffffff16145b1561345757836133e3600184613bde565b8154811061340157634e487b7160e01b600052603260045260246000fd5b600091825260209182902060408051606081018252919092015463ffffffff811682526001600160601b036401000000008204811694830194909452600160801b9004909216908201529450610dad9350505050565b81925083548314156134bf5750506040805160608101825263ffffffff861681526001600160a01b038716600081815260036020818152858320546001600160601b03808216838801529490935252600160601b900416918101919091529250610dad915050565b83838154811061340157634e487b7160e01b600052603260045260246000fd5b604051637a3e3dfd60e01b60208201526001600160e01b0319821660248201526000906028015b604051602081830303815290604052805190602001209050919050565b6060848460a0015185600001518660400151876060015188608001518888604051602001613558989796959493929190613987565b6040516020818303038152906040529050949350505050565b600061155643613087565b60405163c3a0479560e01b60208201526001600160e01b031982166024820152600090602801613506565b80356001600160a01b03811681146135be57600080fd5b919050565b80356135be81613c33565b80356001600160e01b0319811681146135be57600080fd5b60008083601f8401126135f7578182fd5b50813567ffffffffffffffff81111561360e578182fd5b60208301915083602082850101111561362657600080fd5b9250929050565b803563ffffffff811681146135be57600080fd5b600060208284031215613652578081fd5b611586826135a7565b6000806040838503121561366d578081fd5b613676836135a7565b946020939093013593505050565b600080600060608486031215613698578081fd5b6136a1846135a7565b95602085013595506040909401359392505050565b60008060008060008060008060006101008a8c0312156136d4578485fd5b6136dd8a6135a7565b985060208a0135975060408a0135965060608a013560ff81168114613700578586fd5b955060808a0135945060a08a0135935061371c60c08b016135ce565b925060e08a013567ffffffffffffffff811115613737578283fd5b6137438c828d016135e6565b915080935050809150509295985092959850929598565b60006020828403121561376b578081fd5b815161158681613c33565b600060208284031215613787578081fd5b611586826135ce565b6000808284036101408112156137a4578283fd5b6137ad846135ce565b925061012080601f19830112156137c2578283fd5b6137ca613b24565b91506137d8602086016135c3565b82526137e6604086016135c3565b60208301526137f76060860161362d565b60408301526138086080860161362d565b606083015261381960a0860161362d565b608083015261382a60c0860161362d565b60a083015261383b60e0860161362d565b60c083015261010061384e81870161362d565b60e084015261385e82870161362d565b9083015250919491935090915050565b60006020828403121561387f578081fd5b5035919050565b60008060408385031215613898578182fd5b823591506138a8602084016135a7565b90509250929050565b600080600080606085870312156138c6578384fd5b843593506138d6602086016135ce565b9250604085013567ffffffffffffffff8111156138f1578283fd5b6138fd878288016135e6565b95989497509550505050565b6000806000806060858703121561391e578081fd5b84359350602085013567ffffffffffffffff81111561393b578182fd5b613947878288016135e6565b909450925050604085013561395b81613c33565b939692955090935050565b60008060408385031215613978578182fd5b50508035926020909101359150565b6001600160601b03198960601b1681527fffffffffffffffffffffffff00000000000000000000000000000000000000008860a01b166014820152600063ffffffff60e01b808960e01b166020840152808860e01b166024840152808760e01b166028840152808660e01b16602c84015250828460308401379101603001908152979650505050505050565b602080825282518282018190526000919060409081850190868401855b82811015613ab3578151805163ffffffff9081168652878201516001600160e01b03191688870152868201518116878701526060808301518216908701526080808301519091169086015260a0808201516001600160601b03169086015260c0908101516001600160a01b03169085015260e09093019290850190600101613a30565b5091979650505050505050565b63ffffffff60e01b83168152600060206040818401528351806040850152825b81811015613afc57858101830151858201606001528201613ae0565b81811115613b0d5783606083870101525b50601f01601f191692909201606001949350505050565b604051610120810167ffffffffffffffff81118282101715613b5657634e487b7160e01b600052604160045260246000fd5b60405290565b60008219821115613b6f57613b6f613c1d565b500190565b60006001600160601b03808316818516808303821115613b9657613b96613c1d565b01949350505050565b600082613bba57634e487b7160e01b81526012600452602481fd5b500490565b6000816000190483118215151615613bd957613bd9613c1d565b500290565b600082821015613bf057613bf0613c1d565b500390565b60006001600160601b0383811690831681811015613c1557613c15613c1d565b039392505050565b634e487b7160e01b600052601160045260246000fd5b801515811461154757600080fdfea164736f6c6343000804000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa173000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd77

-----Decoded View---------------
Arg [0] : stakingToken (address): 0x909E34d3f6124C324ac83DccA84b74398a6fa173
Arg [1] : rewardMaster (address): 0x347a58878D04951588741d4d16d54B742c7f60fC
Arg [2] : owner (address): 0x505796f5Bc290269D2522cf19135aD7Aa60dfd77

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000909e34d3f6124c324ac83dcca84b74398a6fa173
Arg [1] : 000000000000000000000000347a58878d04951588741d4d16d54b742c7f60fc
Arg [2] : 000000000000000000000000505796f5bc290269d2522cf19135ad7aa60dfd77


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.

Validator Index Block Amount
View All Withdrawals

Txn Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

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.