ETH Price: $2,888.07 (-1.62%)

Contract

0x2ba0F45f7368d2A56d0c9e5a29af363987BE1d02

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
_become81129962025-02-06 17:02:35353 days ago1738861355IN
0x2ba0F45f...987BE1d02
0 ETH0.000000610.00100025

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
XVSVault

Compiler Version
v0.5.16+commit.9c3226ce

Optimization Enabled:
Yes with 200 runs

Other Settings:
istanbul EvmVersion, BSD-3-Clause license
File 1 of 15 : XVSVault.sol
// SPDX-License-Identifier: BSD-3-Clause

pragma solidity 0.5.16;
pragma experimental ABIEncoderV2;

import "../Utils/ECDSA.sol";
import "../Utils/SafeBEP20.sol";
import "../Utils/IBEP20.sol";
import "./XVSVaultStorage.sol";
import "../Tokens/Prime/IPrime.sol";
import "../Utils/SafeCast.sol";
import "@venusprotocol/governance-contracts/contracts/Governance/AccessControlledV5.sol";
import "@venusprotocol/solidity-utilities/contracts/TimeManagerV5.sol";

import { XVSStore } from "./XVSStore.sol";
import { XVSVaultProxy } from "./XVSVaultProxy.sol";

/**
 * @title XVS Vault
 * @author Venus
 * @notice The XVS Vault allows XVS holders to lock their XVS to recieve voting rights in Venus governance and are rewarded with XVS.
 */
contract XVSVault is XVSVaultStorage, ECDSA, AccessControlledV5, TimeManagerV5 {
    using SafeMath for uint256;
    using SafeCast for uint256;
    using SafeBEP20 for IBEP20;

    /// @notice The upper bound for the lock period in a pool, 10 years
    uint256 public constant MAX_LOCK_PERIOD = 60 * 60 * 24 * 365 * 10;

    /// @notice Event emitted when deposit
    event Deposit(address indexed user, address indexed rewardToken, uint256 indexed pid, uint256 amount);

    /// @notice Event emitted when execute withrawal
    event ExecutedWithdrawal(address indexed user, address indexed rewardToken, uint256 indexed pid, uint256 amount);

    /// @notice Event emitted when request withrawal
    event RequestedWithdrawal(address indexed user, address indexed rewardToken, uint256 indexed pid, uint256 amount);

    /// @notice An event thats emitted when an account changes its delegate
    event DelegateChangedV2(address indexed delegator, address indexed fromDelegate, address indexed toDelegate);

    /// @notice An event thats emitted when a delegate account's vote balance changes
    event DelegateVotesChangedV2(address indexed delegate, uint previousBalance, uint newBalance);

    /// @notice An event emitted when the reward store address is updated
    event StoreUpdated(address oldXvs, address oldStore, address newXvs, address newStore);

    /// @notice An event emitted when the withdrawal locking period is updated for a pool
    event WithdrawalLockingPeriodUpdated(address indexed rewardToken, uint indexed pid, uint oldPeriod, uint newPeriod);

    /// @notice An event emitted when the reward amount per block or second is modified for a pool
    event RewardAmountUpdated(address indexed rewardToken, uint oldReward, uint newReward);

    /// @notice An event emitted when a new pool is added
    event PoolAdded(
        address indexed rewardToken,
        uint indexed pid,
        address indexed token,
        uint allocPoints,
        uint rewardPerBlockOrSecond,
        uint lockPeriod
    );

    /// @notice An event emitted when a pool allocation points are updated
    event PoolUpdated(address indexed rewardToken, uint indexed pid, uint oldAllocPoints, uint newAllocPoints);

    /// @notice Event emitted when reward claimed
    event Claim(address indexed user, address indexed rewardToken, uint256 indexed pid, uint256 amount);

    /// @notice Event emitted when vault is paused
    event VaultPaused(address indexed admin);

    /// @notice Event emitted when vault is resumed after pause
    event VaultResumed(address indexed admin);

    /// @notice Event emitted when protocol logs a debt to a user due to insufficient funds for pending reward distribution
    event VaultDebtUpdated(
        address indexed rewardToken,
        address indexed userAddress,
        uint256 oldOwedAmount,
        uint256 newOwedAmount
    );

    /// @notice Emitted when prime token contract address is changed
    event NewPrimeToken(
        IPrime indexed oldPrimeToken,
        IPrime indexed newPrimeToken,
        address oldPrimeRewardToken,
        address newPrimeRewardToken,
        uint256 oldPrimePoolId,
        uint256 newPrimePoolId
    );

    /**
     * @notice XVSVault constructor
     */
    constructor() public {
        admin = msg.sender;
    }

    modifier onlyAdmin() {
        require(msg.sender == admin, "only admin can");
        _;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     */
    modifier nonReentrant() {
        require(_notEntered, "re-entered");
        _notEntered = false;
        _;
        _notEntered = true; // get a gas-refund post-Istanbul
    }

    /**
     * @dev Prevents functions to execute when vault is paused.
     */
    modifier isActive() {
        require(!vaultPaused, "Vault is paused");
        _;
    }

    /**
     * @notice Pauses vault
     */
    function pause() external {
        _checkAccessAllowed("pause()");
        require(!vaultPaused, "Vault is already paused");
        vaultPaused = true;
        emit VaultPaused(msg.sender);
    }

    /**
     * @notice Resume vault
     */
    function resume() external {
        _checkAccessAllowed("resume()");
        require(vaultPaused, "Vault is not paused");
        vaultPaused = false;
        emit VaultResumed(msg.sender);
    }

    /**
     * @notice Returns the number of pools with the specified reward token
     * @param rewardToken Reward token address
     * @return Number of pools that distribute the specified token as a reward
     */
    function poolLength(address rewardToken) external view returns (uint256) {
        return poolInfos[rewardToken].length;
    }

    /**
     * @notice Returns the number of reward tokens created per block or second
     * @param _rewardToken Reward token address
     * @return Number of reward tokens created per block or second
     */
    function rewardTokenAmountsPerBlock(address _rewardToken) external view returns (uint256) {
        return rewardTokenAmountsPerBlockOrSecond[_rewardToken];
    }

    /**
     * @notice Add a new token pool
     * @dev This vault DOES NOT support deflationary tokens — it expects that
     *   the amount of transferred tokens would equal the actually deposited
     *   amount. In practice this means that this vault DOES NOT support USDT
     *   and similar tokens (that do not provide these guarantees).
     * @param _rewardToken Reward token address
     * @param _allocPoint Number of allocation points assigned to this pool
     * @param _token Staked token
     * @param _rewardPerBlockOrSecond Initial reward per block or second, in terms of _rewardToken
     * @param _lockPeriod A period between withdrawal request and a moment when it's executable
     */
    function add(
        address _rewardToken,
        uint256 _allocPoint,
        IBEP20 _token,
        uint256 _rewardPerBlockOrSecond,
        uint256 _lockPeriod
    ) external {
        _checkAccessAllowed("add(address,uint256,address,uint256,uint256)");
        _ensureNonzeroAddress(_rewardToken);
        _ensureNonzeroAddress(address(_token));
        require(address(xvsStore) != address(0), "Store contract address is empty");
        require(_allocPoint > 0, "Alloc points must not be zero");

        massUpdatePools(_rewardToken);

        PoolInfo[] storage poolInfo = poolInfos[_rewardToken];

        uint256 length = poolInfo.length;
        for (uint256 pid = 0; pid < length; ++pid) {
            require(poolInfo[pid].token != _token, "Pool already added");
        }

        // We use balanceOf to get the supply amount, so shouldn't be possible to
        // configure pools with different reward token but the same staked token
        require(!isStakedToken[address(_token)], "Token exists in other pool");

        totalAllocPoints[_rewardToken] = totalAllocPoints[_rewardToken].add(_allocPoint);

        rewardTokenAmountsPerBlockOrSecond[_rewardToken] = _rewardPerBlockOrSecond;

        poolInfo.push(
            PoolInfo({
                token: _token,
                allocPoint: _allocPoint,
                lastRewardBlockOrSecond: getBlockNumberOrTimestamp(),
                accRewardPerShare: 0,
                lockPeriod: _lockPeriod
            })
        );
        isStakedToken[address(_token)] = true;

        XVSStore(xvsStore).setRewardToken(_rewardToken, true);

        emit PoolAdded(
            _rewardToken,
            poolInfo.length - 1,
            address(_token),
            _allocPoint,
            _rewardPerBlockOrSecond,
            _lockPeriod
        );
    }

    /**
     * @notice Update the given pool's reward allocation point
     * @param _rewardToken Reward token address
     * @param _pid Pool index
     * @param _allocPoint Number of allocation points assigned to this pool
     */
    function set(address _rewardToken, uint256 _pid, uint256 _allocPoint) external {
        _checkAccessAllowed("set(address,uint256,uint256)");
        _ensureValidPool(_rewardToken, _pid);

        massUpdatePools(_rewardToken);

        PoolInfo[] storage poolInfo = poolInfos[_rewardToken];
        uint256 newTotalAllocPoints = totalAllocPoints[_rewardToken].sub(poolInfo[_pid].allocPoint).add(_allocPoint);
        require(newTotalAllocPoints > 0, "Alloc points per reward token must not be zero");

        uint256 oldAllocPoints = poolInfo[_pid].allocPoint;
        poolInfo[_pid].allocPoint = _allocPoint;
        totalAllocPoints[_rewardToken] = newTotalAllocPoints;

        emit PoolUpdated(_rewardToken, _pid, oldAllocPoints, _allocPoint);
    }

    /**
     * @notice Update the given reward token's amount per block or second
     * @param _rewardToken Reward token address
     * @param _rewardAmount Number of allocation points assigned to this pool
     */
    function setRewardAmountPerBlockOrSecond(address _rewardToken, uint256 _rewardAmount) external {
        _checkAccessAllowed("setRewardAmountPerBlockOrSecond(address,uint256)");
        require(XVSStore(xvsStore).rewardTokens(_rewardToken), "Invalid reward token");
        massUpdatePools(_rewardToken);
        uint256 oldReward = rewardTokenAmountsPerBlockOrSecond[_rewardToken];
        rewardTokenAmountsPerBlockOrSecond[_rewardToken] = _rewardAmount;

        emit RewardAmountUpdated(_rewardToken, oldReward, _rewardAmount);
    }

    /**
     * @notice Update the lock period after which a requested withdrawal can be executed
     * @param _rewardToken Reward token address
     * @param _pid Pool index
     * @param _newPeriod New lock period
     */
    function setWithdrawalLockingPeriod(address _rewardToken, uint256 _pid, uint256 _newPeriod) external {
        _checkAccessAllowed("setWithdrawalLockingPeriod(address,uint256,uint256)");
        _ensureValidPool(_rewardToken, _pid);
        require(_newPeriod > 0 && _newPeriod < MAX_LOCK_PERIOD, "Invalid new locking period");
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        uint256 oldPeriod = pool.lockPeriod;
        pool.lockPeriod = _newPeriod;

        emit WithdrawalLockingPeriodUpdated(_rewardToken, _pid, oldPeriod, _newPeriod);
    }

    /**
     * @notice Deposit XVSVault for XVS allocation
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _amount The amount to deposit to vault
     */
    function deposit(address _rewardToken, uint256 _pid, uint256 _amount) external nonReentrant isActive {
        _ensureValidPool(_rewardToken, _pid);
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        UserInfo storage user = userInfos[_rewardToken][_pid][msg.sender];
        _updatePool(_rewardToken, _pid);
        require(pendingWithdrawalsBeforeUpgrade(_rewardToken, _pid, msg.sender) == 0, "execute pending withdrawal");

        if (user.amount > 0) {
            uint256 pending = _computeReward(user, pool);
            if (pending > 0) {
                _transferReward(_rewardToken, msg.sender, pending);
                emit Claim(msg.sender, _rewardToken, _pid, pending);
            }
        }
        pool.token.safeTransferFrom(msg.sender, address(this), _amount);
        user.amount = user.amount.add(_amount);
        user.rewardDebt = _cumulativeReward(user, pool);

        // Update Delegate Amount
        if (address(pool.token) == xvsAddress) {
            _moveDelegates(address(0), delegates[msg.sender], safe96(_amount, "XVSVault::deposit: votes overflow"));
        }

        if (primeRewardToken == _rewardToken && _pid == primePoolId) {
            primeToken.xvsUpdated(msg.sender);
        }

        emit Deposit(msg.sender, _rewardToken, _pid, _amount);
    }

    /**
     * @notice Claim rewards for pool
     * @param _account The account for which to claim rewards
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     */
    function claim(address _account, address _rewardToken, uint256 _pid) external nonReentrant isActive {
        _ensureValidPool(_rewardToken, _pid);
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        UserInfo storage user = userInfos[_rewardToken][_pid][_account];
        _updatePool(_rewardToken, _pid);
        require(pendingWithdrawalsBeforeUpgrade(_rewardToken, _pid, _account) == 0, "execute pending withdrawal");

        if (user.amount > 0) {
            uint256 pending = _computeReward(user, pool);

            if (pending > 0) {
                user.rewardDebt = _cumulativeReward(user, pool);

                _transferReward(_rewardToken, _account, pending);
                emit Claim(_account, _rewardToken, _pid, pending);
            }
        }
    }

    /**
     * @notice Pushes withdrawal request to the requests array and updates
     *   the pending withdrawals amount. The requests are always sorted
     *   by unlock time (descending) so that the earliest to execute requests
     *   are always at the end of the array.
     * @param _user The user struct storage pointer
     * @param _requests The user's requests array storage pointer
     * @param _amount The amount being requested
     */
    function pushWithdrawalRequest(
        UserInfo storage _user,
        WithdrawalRequest[] storage _requests,
        uint _amount,
        uint _lockedUntil
    ) internal {
        uint i = _requests.length;
        _requests.push(WithdrawalRequest(0, 0, 1));
        // Keep it sorted so that the first to get unlocked request is always at the end
        for (; i > 0 && _requests[i - 1].lockedUntil <= _lockedUntil; --i) {
            _requests[i] = _requests[i - 1];
        }
        _requests[i] = WithdrawalRequest(_amount, _lockedUntil.toUint128(), 1);
        _user.pendingWithdrawals = _user.pendingWithdrawals.add(_amount);
    }

    /**
     * @notice Pops the requests with unlock time < now from the requests
     *   array and deducts the computed amount from the user's pending
     *   withdrawals counter. Assumes that the requests array is sorted
     *   by unclock time (descending).
     * @dev This function **removes** the eligible requests from the requests
     *   array. If this function is called, the withdrawal should actually
     *   happen (or the transaction should be reverted).
     * @param _user The user struct storage pointer
     * @param _requests The user's requests array storage pointer
     * @return beforeUpgradeWithdrawalAmount The amount eligible for withdrawal before upgrade (this amount should be
     *   sent to the user, otherwise the state would be inconsistent).
     * @return afterUpgradeWithdrawalAmount The amount eligible for withdrawal after upgrade (this amount should be
     *   sent to the user, otherwise the state would be inconsistent).
     */
    function popEligibleWithdrawalRequests(
        UserInfo storage _user,
        WithdrawalRequest[] storage _requests
    ) internal returns (uint beforeUpgradeWithdrawalAmount, uint afterUpgradeWithdrawalAmount) {
        // Since the requests are sorted by their unlock time, we can just
        // pop them from the array and stop at the first not-yet-eligible one
        for (uint i = _requests.length; i > 0 && isUnlocked(_requests[i - 1]); --i) {
            if (_requests[i - 1].afterUpgrade == 1) {
                afterUpgradeWithdrawalAmount = afterUpgradeWithdrawalAmount.add(_requests[i - 1].amount);
            } else {
                beforeUpgradeWithdrawalAmount = beforeUpgradeWithdrawalAmount.add(_requests[i - 1].amount);
            }

            _requests.pop();
        }
        _user.pendingWithdrawals = _user.pendingWithdrawals.sub(
            afterUpgradeWithdrawalAmount.add(beforeUpgradeWithdrawalAmount)
        );
        return (beforeUpgradeWithdrawalAmount, afterUpgradeWithdrawalAmount);
    }

    /**
     * @notice Checks if the request is eligible for withdrawal.
     * @param _request The request struct storage pointer
     * @return True if the request is eligible for withdrawal, false otherwise
     */
    function isUnlocked(WithdrawalRequest storage _request) private view returns (bool) {
        return _request.lockedUntil <= block.timestamp;
    }

    /**
     * @notice Execute withdrawal to XVSVault for XVS allocation
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     */
    function executeWithdrawal(address _rewardToken, uint256 _pid) external nonReentrant isActive {
        _ensureValidPool(_rewardToken, _pid);
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        UserInfo storage user = userInfos[_rewardToken][_pid][msg.sender];
        WithdrawalRequest[] storage requests = withdrawalRequests[_rewardToken][_pid][msg.sender];

        uint256 beforeUpgradeWithdrawalAmount;
        uint256 afterUpgradeWithdrawalAmount;

        (beforeUpgradeWithdrawalAmount, afterUpgradeWithdrawalAmount) = popEligibleWithdrawalRequests(user, requests);
        require(beforeUpgradeWithdrawalAmount > 0 || afterUpgradeWithdrawalAmount > 0, "nothing to withdraw");

        // Having both old-style and new-style requests is not allowed and shouldn't be possible
        require(beforeUpgradeWithdrawalAmount == 0 || afterUpgradeWithdrawalAmount == 0, "inconsistent state");

        if (beforeUpgradeWithdrawalAmount > 0) {
            _updatePool(_rewardToken, _pid);
            uint256 pending = user.amount.mul(pool.accRewardPerShare).div(1e12).sub(user.rewardDebt);
            XVSStore(xvsStore).safeRewardTransfer(_rewardToken, msg.sender, pending);
            user.amount = user.amount.sub(beforeUpgradeWithdrawalAmount);
            user.rewardDebt = user.amount.mul(pool.accRewardPerShare).div(1e12);
            pool.token.safeTransfer(address(msg.sender), beforeUpgradeWithdrawalAmount);
        } else {
            user.amount = user.amount.sub(afterUpgradeWithdrawalAmount);
            totalPendingWithdrawals[_rewardToken][_pid] = totalPendingWithdrawals[_rewardToken][_pid].sub(
                afterUpgradeWithdrawalAmount
            );
            pool.token.safeTransfer(address(msg.sender), afterUpgradeWithdrawalAmount);
        }

        emit ExecutedWithdrawal(
            msg.sender,
            _rewardToken,
            _pid,
            beforeUpgradeWithdrawalAmount.add(afterUpgradeWithdrawalAmount)
        );
    }

    /**
     * @notice Returns before and after upgrade pending withdrawal amount
     * @param _requests The user's requests array storage pointer
     * @return beforeUpgradeWithdrawalAmount The amount eligible for withdrawal before upgrade
     * @return afterUpgradeWithdrawalAmount The amount eligible for withdrawal after upgrade
     */
    function getRequestedWithdrawalAmount(
        WithdrawalRequest[] storage _requests
    ) internal view returns (uint beforeUpgradeWithdrawalAmount, uint afterUpgradeWithdrawalAmount) {
        for (uint i = _requests.length; i > 0; --i) {
            if (_requests[i - 1].afterUpgrade == 1) {
                afterUpgradeWithdrawalAmount = afterUpgradeWithdrawalAmount.add(_requests[i - 1].amount);
            } else {
                beforeUpgradeWithdrawalAmount = beforeUpgradeWithdrawalAmount.add(_requests[i - 1].amount);
            }
        }
        return (beforeUpgradeWithdrawalAmount, afterUpgradeWithdrawalAmount);
    }

    /**
     * @notice Request withdrawal to XVSVault for XVS allocation
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _amount The amount to withdraw from the vault
     */
    function requestWithdrawal(address _rewardToken, uint256 _pid, uint256 _amount) external nonReentrant isActive {
        _ensureValidPool(_rewardToken, _pid);
        require(_amount > 0, "requested amount cannot be zero");
        UserInfo storage user = userInfos[_rewardToken][_pid][msg.sender];
        require(user.amount >= user.pendingWithdrawals.add(_amount), "requested amount is invalid");

        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        WithdrawalRequest[] storage requests = withdrawalRequests[_rewardToken][_pid][msg.sender];

        uint beforeUpgradeWithdrawalAmount;

        (beforeUpgradeWithdrawalAmount, ) = getRequestedWithdrawalAmount(requests);
        require(beforeUpgradeWithdrawalAmount == 0, "execute pending withdrawal");

        _updatePool(_rewardToken, _pid);
        uint256 pending = _computeReward(user, pool);
        _transferReward(_rewardToken, msg.sender, pending);

        uint lockedUntil = pool.lockPeriod.add(block.timestamp);

        pushWithdrawalRequest(user, requests, _amount, lockedUntil);
        totalPendingWithdrawals[_rewardToken][_pid] = totalPendingWithdrawals[_rewardToken][_pid].add(_amount);
        user.rewardDebt = _cumulativeReward(user, pool);

        // Update Delegate Amount
        if (address(pool.token) == xvsAddress) {
            _moveDelegates(
                delegates[msg.sender],
                address(0),
                safe96(_amount, "XVSVault::requestWithdrawal: votes overflow")
            );
        }

        if (primeRewardToken == _rewardToken && _pid == primePoolId) {
            primeToken.xvsUpdated(msg.sender);
        }

        emit Claim(msg.sender, _rewardToken, _pid, pending);
        emit RequestedWithdrawal(msg.sender, _rewardToken, _pid, _amount);
    }

    /**
     * @notice Get unlocked withdrawal amount
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _user The User Address
     * @return withdrawalAmount Amount that the user can withdraw
     */
    function getEligibleWithdrawalAmount(
        address _rewardToken,
        uint256 _pid,
        address _user
    ) external view returns (uint withdrawalAmount) {
        _ensureValidPool(_rewardToken, _pid);
        WithdrawalRequest[] storage requests = withdrawalRequests[_rewardToken][_pid][_user];
        // Since the requests are sorted by their unlock time, we can take
        // the entries from the end of the array and stop at the first
        // not-yet-eligible one
        for (uint i = requests.length; i > 0 && isUnlocked(requests[i - 1]); --i) {
            withdrawalAmount = withdrawalAmount.add(requests[i - 1].amount);
        }
        return withdrawalAmount;
    }

    /**
     * @notice Get requested amount
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _user The User Address
     * @return Total amount of requested but not yet executed withdrawals (including both executable and locked ones)
     */
    function getRequestedAmount(address _rewardToken, uint256 _pid, address _user) external view returns (uint256) {
        _ensureValidPool(_rewardToken, _pid);
        UserInfo storage user = userInfos[_rewardToken][_pid][_user];
        return user.pendingWithdrawals;
    }

    /**
     * @notice Returns the array of withdrawal requests that have not been executed yet
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _user The User Address
     * @return An array of withdrawal requests
     */
    function getWithdrawalRequests(
        address _rewardToken,
        uint256 _pid,
        address _user
    ) external view returns (WithdrawalRequest[] memory) {
        _ensureValidPool(_rewardToken, _pid);
        return withdrawalRequests[_rewardToken][_pid][_user];
    }

    /**
     * @notice View function to see pending XVSs on frontend
     * @param _rewardToken Reward token address
     * @param _pid Pool index
     * @param _user User address
     * @return Reward the user is eligible for in this pool, in terms of _rewardToken
     */
    function pendingReward(address _rewardToken, uint256 _pid, address _user) external view returns (uint256) {
        _ensureValidPool(_rewardToken, _pid);
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        UserInfo storage user = userInfos[_rewardToken][_pid][_user];
        uint256 accRewardPerShare = pool.accRewardPerShare;
        uint256 supply = pool.token.balanceOf(address(this)).sub(totalPendingWithdrawals[_rewardToken][_pid]);
        uint256 curBlockNumberOrSecond = getBlockNumberOrTimestamp();
        uint256 rewardTokenPerBlockOrSecond = rewardTokenAmountsPerBlockOrSecond[_rewardToken];
        if (curBlockNumberOrSecond > pool.lastRewardBlockOrSecond && supply != 0) {
            uint256 multiplier = curBlockNumberOrSecond.sub(pool.lastRewardBlockOrSecond);
            uint256 reward = multiplier.mul(rewardTokenPerBlockOrSecond).mul(pool.allocPoint).div(
                totalAllocPoints[_rewardToken]
            );
            accRewardPerShare = accRewardPerShare.add(reward.mul(1e12).div(supply));
        }
        WithdrawalRequest[] storage requests = withdrawalRequests[_rewardToken][_pid][_user];
        (, uint256 afterUpgradeWithdrawalAmount) = getRequestedWithdrawalAmount(requests);
        return user.amount.sub(afterUpgradeWithdrawalAmount).mul(accRewardPerShare).div(1e12).sub(user.rewardDebt);
    }

    // Update reward variables for all pools. Be careful of gas spending!
    function massUpdatePools(address _rewardToken) internal {
        uint256 length = poolInfos[_rewardToken].length;
        for (uint256 pid = 0; pid < length; ++pid) {
            _updatePool(_rewardToken, pid);
        }
    }

    /**
     * @notice Update reward variables of the given pool to be up-to-date
     * @param _rewardToken Reward token address
     * @param _pid Pool index
     */
    function updatePool(address _rewardToken, uint256 _pid) external isActive {
        _ensureValidPool(_rewardToken, _pid);
        _updatePool(_rewardToken, _pid);
    }

    // Update reward variables of the given pool to be up-to-date.
    function _updatePool(address _rewardToken, uint256 _pid) internal {
        PoolInfo storage pool = poolInfos[_rewardToken][_pid];
        if (getBlockNumberOrTimestamp() <= pool.lastRewardBlockOrSecond) {
            return;
        }
        uint256 supply = pool.token.balanceOf(address(this));
        supply = supply.sub(totalPendingWithdrawals[_rewardToken][_pid]);
        if (supply == 0) {
            pool.lastRewardBlockOrSecond = getBlockNumberOrTimestamp();
            return;
        }
        uint256 curBlockNumberOrSecond = getBlockNumberOrTimestamp();
        uint256 multiplier = curBlockNumberOrSecond.sub(pool.lastRewardBlockOrSecond);
        uint256 reward = multiplier.mul(rewardTokenAmountsPerBlockOrSecond[_rewardToken]).mul(pool.allocPoint).div(
            totalAllocPoints[_rewardToken]
        );
        pool.accRewardPerShare = pool.accRewardPerShare.add(reward.mul(1e12).div(supply));
        pool.lastRewardBlockOrSecond = getBlockNumberOrTimestamp();
    }

    function _ensureValidPool(address rewardToken, uint256 pid) internal view {
        require(pid < poolInfos[rewardToken].length, "vault: pool exists?");
    }

    /**
     * @notice Get user info with reward token address and pid
     * @param _rewardToken Reward token address
     * @param _pid Pool index
     * @param _user User address
     * @return amount Deposited amount
     * @return rewardDebt Reward debt (technical value used to track past payouts)
     * @return pendingWithdrawals Requested but not yet executed withdrawals
     */
    function getUserInfo(
        address _rewardToken,
        uint256 _pid,
        address _user
    ) external view returns (uint256 amount, uint256 rewardDebt, uint256 pendingWithdrawals) {
        _ensureValidPool(_rewardToken, _pid);
        UserInfo storage user = userInfos[_rewardToken][_pid][_user];
        amount = user.amount;
        rewardDebt = user.rewardDebt;
        pendingWithdrawals = user.pendingWithdrawals;
    }

    /**
     * @notice Gets the total pending withdrawal amount of a user before upgrade
     * @param _rewardToken The Reward Token Address
     * @param _pid The Pool Index
     * @param _user The address of the user
     * @return beforeUpgradeWithdrawalAmount Total pending withdrawal amount in requests made before the vault upgrade
     */
    function pendingWithdrawalsBeforeUpgrade(
        address _rewardToken,
        uint256 _pid,
        address _user
    ) public view returns (uint256 beforeUpgradeWithdrawalAmount) {
        WithdrawalRequest[] storage requests = withdrawalRequests[_rewardToken][_pid][_user];
        (beforeUpgradeWithdrawalAmount, ) = getRequestedWithdrawalAmount(requests);
        return beforeUpgradeWithdrawalAmount;
    }

    /**
     * @notice Get the XVS stake balance of an account (excluding the pending withdrawals)
     * @param account The address of the account to check
     * @return The balance that user staked
     */
    function getStakeAmount(address account) internal view returns (uint96) {
        require(xvsAddress != address(0), "XVSVault::getStakeAmount: xvs address is not set");

        PoolInfo[] storage poolInfo = poolInfos[xvsAddress];

        uint256 length = poolInfo.length;
        for (uint256 pid = 0; pid < length; ++pid) {
            if (address(poolInfo[pid].token) == address(xvsAddress)) {
                UserInfo storage user = userInfos[xvsAddress][pid][account];
                return safe96(user.amount.sub(user.pendingWithdrawals), "XVSVault::getStakeAmount: votes overflow");
            }
        }
        return uint96(0);
    }

    /**
     * @notice Delegate votes from `msg.sender` to `delegatee`
     * @param delegatee The address to delegate votes to
     */
    function delegate(address delegatee) external isActive {
        return _delegate(msg.sender, delegatee);
    }

    /**
     * @notice Delegates votes from signatory to `delegatee`
     * @param delegatee The address to delegate votes to
     * @param nonce The contract state required to match the signature
     * @param expiry The time at which to expire the signature
     * @param v The recovery byte of the signature
     * @param r Half of the ECDSA signature pair
     * @param s Half of the ECDSA signature pair
     */
    function delegateBySig(
        address delegatee,
        uint nonce,
        uint expiry,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external isActive {
        bytes32 domainSeparator = keccak256(
            abi.encode(DOMAIN_TYPEHASH, keccak256(bytes("XVSVault")), getChainId(), address(this))
        );
        bytes32 structHash = keccak256(abi.encode(DELEGATION_TYPEHASH, delegatee, nonce, expiry));
        bytes32 digest = keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
        address signatory = ECDSA.recover(digest, v, r, s);
        require(nonce == nonces[signatory]++, "XVSVault::delegateBySig: invalid nonce");
        require(block.timestamp <= expiry, "XVSVault::delegateBySig: signature expired");
        return _delegate(signatory, delegatee);
    }

    /**
     * @notice Gets the current votes balance for `account`
     * @param account The address to get votes balance
     * @return The number of current votes for `account`
     */
    function getCurrentVotes(address account) external view returns (uint96) {
        uint32 nCheckpoints = numCheckpoints[account];
        return nCheckpoints > 0 ? checkpoints[account][nCheckpoints - 1].votes : 0;
    }

    function _delegate(address delegator, address delegatee) internal {
        address currentDelegate = delegates[delegator];
        uint96 delegatorBalance = getStakeAmount(delegator);
        delegates[delegator] = delegatee;

        emit DelegateChangedV2(delegator, currentDelegate, delegatee);

        _moveDelegates(currentDelegate, delegatee, delegatorBalance);
    }

    function _moveDelegates(address srcRep, address dstRep, uint96 amount) internal {
        if (srcRep != dstRep && amount > 0) {
            if (srcRep != address(0)) {
                uint32 srcRepNum = numCheckpoints[srcRep];
                uint96 srcRepOld = srcRepNum > 0 ? checkpoints[srcRep][srcRepNum - 1].votes : 0;
                uint96 srcRepNew = sub96(srcRepOld, amount, "XVSVault::_moveVotes: vote amount underflows");
                _writeCheckpoint(srcRep, srcRepNum, srcRepOld, srcRepNew);
            }

            if (dstRep != address(0)) {
                uint32 dstRepNum = numCheckpoints[dstRep];
                uint96 dstRepOld = dstRepNum > 0 ? checkpoints[dstRep][dstRepNum - 1].votes : 0;
                uint96 dstRepNew = add96(dstRepOld, amount, "XVSVault::_moveVotes: vote amount overflows");
                _writeCheckpoint(dstRep, dstRepNum, dstRepOld, dstRepNew);
            }
        }
    }

    function _writeCheckpoint(address delegatee, uint32 nCheckpoints, uint96 oldVotes, uint96 newVotes) internal {
        uint32 blockNumberOrSecond = safe32(
            getBlockNumberOrTimestamp(),
            "XVSVault::_writeCheckpoint: block number or second exceeds 32 bits"
        );

        if (nCheckpoints > 0 && checkpoints[delegatee][nCheckpoints - 1].fromBlockOrSecond == blockNumberOrSecond) {
            checkpoints[delegatee][nCheckpoints - 1].votes = newVotes;
        } else {
            checkpoints[delegatee][nCheckpoints] = Checkpoint(blockNumberOrSecond, newVotes);
            numCheckpoints[delegatee] = nCheckpoints + 1;
        }

        emit DelegateVotesChangedV2(delegatee, oldVotes, newVotes);
    }

    function safe32(uint n, string memory errorMessage) internal pure returns (uint32) {
        require(n < 2 ** 32, errorMessage);
        return uint32(n);
    }

    function safe96(uint n, string memory errorMessage) internal pure returns (uint96) {
        require(n < 2 ** 96, errorMessage);
        return uint96(n);
    }

    function add96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        uint96 c = a + b;
        require(c >= a, errorMessage);
        return c;
    }

    function sub96(uint96 a, uint96 b, string memory errorMessage) internal pure returns (uint96) {
        require(b <= a, errorMessage);
        return a - b;
    }

    function getChainId() internal pure returns (uint) {
        uint256 chainId;
        assembly {
            chainId := chainid()
        }
        return chainId;
    }

    /**
     * @notice Determine the xvs stake balance for an account
     * @param account The address of the account to check
     * @param blockNumberOrSecond The block number or second to get the vote balance at
     * @return The balance that user staked
     */
    function getPriorVotes(address account, uint256 blockNumberOrSecond) external view returns (uint96) {
        require(blockNumberOrSecond < getBlockNumberOrTimestamp(), "XVSVault::getPriorVotes: not yet determined");

        uint32 nCheckpoints = numCheckpoints[account];
        if (nCheckpoints == 0) {
            return 0;
        }

        // First check most recent balance
        if (checkpoints[account][nCheckpoints - 1].fromBlockOrSecond <= blockNumberOrSecond) {
            return checkpoints[account][nCheckpoints - 1].votes;
        }

        // Next check implicit zero balance
        if (checkpoints[account][0].fromBlockOrSecond > blockNumberOrSecond) {
            return 0;
        }

        uint32 lower = 0;
        uint32 upper = nCheckpoints - 1;
        while (upper > lower) {
            uint32 center = upper - (upper - lower) / 2; // ceil, avoiding overflow
            Checkpoint memory cp = checkpoints[account][center];
            if (cp.fromBlockOrSecond == blockNumberOrSecond) {
                return cp.votes;
            } else if (cp.fromBlockOrSecond < blockNumberOrSecond) {
                lower = center;
            } else {
                upper = center - 1;
            }
        }
        return checkpoints[account][lower].votes;
    }

    /*** Admin Functions ***/

    function _become(XVSVaultProxy xvsVaultProxy) external {
        require(msg.sender == xvsVaultProxy.admin(), "only proxy admin can change brains");
        require(xvsVaultProxy._acceptImplementation() == 0, "change not authorized");
    }

    function setXvsStore(address _xvs, address _xvsStore) external onlyAdmin {
        _ensureNonzeroAddress(_xvs);
        _ensureNonzeroAddress(_xvsStore);

        address oldXvsContract = xvsAddress;
        address oldStore = xvsStore;
        require(oldXvsContract == address(0), "already initialized");

        xvsAddress = _xvs;
        xvsStore = _xvsStore;

        _notEntered = true;

        emit StoreUpdated(oldXvsContract, oldStore, _xvs, _xvsStore);
    }

    /**
     * @notice Sets the address of the prime token contract
     * @param _primeToken address of the prime token contract
     * @param _primeRewardToken address of reward token
     * @param _primePoolId pool id for reward
     */
    function setPrimeToken(IPrime _primeToken, address _primeRewardToken, uint256 _primePoolId) external onlyAdmin {
        require(address(_primeToken) != address(0), "prime token cannot be zero address");
        require(_primeRewardToken != address(0), "reward cannot be zero address");

        _ensureValidPool(_primeRewardToken, _primePoolId);

        emit NewPrimeToken(primeToken, _primeToken, primeRewardToken, _primeRewardToken, primePoolId, _primePoolId);

        primeToken = _primeToken;
        primeRewardToken = _primeRewardToken;
        primePoolId = _primePoolId;
    }

    /**
     * @dev Initializes the contract to use either blocks or seconds
     * @param timeBased_ A boolean indicating whether the contract is based on time or block
     * If timeBased is true than blocksPerYear_ param is ignored as blocksOrSecondsPerYear is set to SECONDS_PER_YEAR
     * @param blocksPerYear_ The number of blocks per year
     */
    function initializeTimeManager(bool timeBased_, uint256 blocksPerYear_) external onlyAdmin {
        _initializeTimeManager(timeBased_, blocksPerYear_);
    }

    /**
     * @notice Sets the address of the access control of this contract
     * @dev Admin function to set the access control address
     * @param newAccessControlAddress New address for the access control
     */
    function setAccessControl(address newAccessControlAddress) external onlyAdmin {
        _setAccessControlManager(newAccessControlAddress);
    }

    /**
     * @dev Reverts if the provided address is a zero address
     * @param address_ Address to check
     */
    function _ensureNonzeroAddress(address address_) internal pure {
        require(address_ != address(0), "zero address not allowed");
    }

    /**
     * @dev Transfers the reward to the user, taking into account the rewards store
     *   balance and the previous debt. If there are not enough rewards in the store,
     *   transfers the available funds and records the debt amount in pendingRewardTransfers.
     * @param rewardToken Reward token address
     * @param userAddress User address
     * @param amount Reward amount, in reward tokens
     */
    function _transferReward(address rewardToken, address userAddress, uint256 amount) internal {
        address xvsStore_ = xvsStore;
        uint256 storeBalance = IBEP20(rewardToken).balanceOf(xvsStore_);
        uint256 debtDueToFailedTransfers = pendingRewardTransfers[rewardToken][userAddress];
        uint256 fullAmount = amount.add(debtDueToFailedTransfers);

        if (fullAmount <= storeBalance) {
            if (debtDueToFailedTransfers != 0) {
                pendingRewardTransfers[rewardToken][userAddress] = 0;
                emit VaultDebtUpdated(rewardToken, userAddress, debtDueToFailedTransfers, 0);
            }
            XVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, fullAmount);
            return;
        }
        // Overflow isn't possible due to the check above
        uint256 newOwedAmount = fullAmount - storeBalance;
        pendingRewardTransfers[rewardToken][userAddress] = newOwedAmount;
        emit VaultDebtUpdated(rewardToken, userAddress, debtDueToFailedTransfers, newOwedAmount);
        XVSStore(xvsStore_).safeRewardTransfer(rewardToken, userAddress, storeBalance);
    }

    /**
     * @dev Computes cumulative reward for all user's shares
     * @param user UserInfo storage struct
     * @param pool PoolInfo storage struct
     */
    function _cumulativeReward(UserInfo storage user, PoolInfo storage pool) internal view returns (uint256) {
        return user.amount.sub(user.pendingWithdrawals).mul(pool.accRewardPerShare).div(1e12);
    }

    /**
     * @dev Computes the reward for all user's shares
     * @param user UserInfo storage struct
     * @param pool PoolInfo storage struct
     */
    function _computeReward(UserInfo storage user, PoolInfo storage pool) internal view returns (uint256) {
        return _cumulativeReward(user, pool).sub(user.rewardDebt);
    }
}

// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.5.16;

import "./IAccessControlManagerV5.sol";

/**
 * @title AccessControlledV5
 * @author Venus
 * @notice This contract is helper between access control manager and actual contract. This contract further inherited by other contract (using solidity 0.5.16)
 * to integrate access controlled mechanism. It provides initialise methods and verifying access methods.
 */
contract AccessControlledV5 {
    /// @notice Access control manager contract
    IAccessControlManagerV5 private _accessControlManager;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[49] private __gap;

    /// @notice Emitted when access control manager contract address is changed
    event NewAccessControlManager(address oldAccessControlManager, address newAccessControlManager);

    /**
     * @notice Returns the address of the access control manager contract
     */
    function accessControlManager() external view returns (IAccessControlManagerV5) {
        return _accessControlManager;
    }

    /**
     * @dev Internal function to set address of AccessControlManager
     * @param accessControlManager_ The new address of the AccessControlManager
     */
    function _setAccessControlManager(address accessControlManager_) internal {
        require(address(accessControlManager_) != address(0), "invalid acess control manager address");
        address oldAccessControlManager = address(_accessControlManager);
        _accessControlManager = IAccessControlManagerV5(accessControlManager_);
        emit NewAccessControlManager(oldAccessControlManager, accessControlManager_);
    }

    /**
     * @notice Reverts if the call is not allowed by AccessControlManager
     * @param signature Method signature
     */
    function _checkAccessAllowed(string memory signature) internal view {
        bool isAllowedToCall = _accessControlManager.isAllowedToCall(msg.sender, signature);

        if (!isAllowedToCall) {
            revert("Unauthorized");
        }
    }
}

// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.5.16;

/**
 * @title IAccessControlManagerV5
 * @author Venus
 * @notice Interface implemented by the `AccessControlManagerV5` contract.
 */
interface IAccessControlManagerV5 {
    /**
     * @dev Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`
     *
     * `DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite
     * {RoleAdminChanged} not being emitted signaling this.
     *
     */
    event RoleAdminChanged(bytes32 indexed role, bytes32 indexed previousAdminRole, bytes32 indexed newAdminRole);

    /**
     * @dev Emitted when `account` is granted `role`.
     *
     * `sender` is the account that originated the contract call, an admin role
     * bearer except when using {AccessControl-_setupRole}.
     */
    event RoleGranted(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Emitted when `account` is revoked `role`.
     *
     * `sender` is the account that originated the contract call:
     *   - if using `revokeRole`, it is the admin role bearer
     *   - if using `renounceRole`, it is the role bearer (i.e. `account`)
     */
    event RoleRevoked(bytes32 indexed role, address indexed account, address indexed sender);

    /**
     * @dev Returns `true` if `account` has been granted `role`.
     */
    function hasRole(bytes32 role, address account) external view returns (bool);

    /**
     * @dev Returns the admin role that controls `role`. See {grantRole} and
     * {revokeRole}.
     *
     * To change a role's admin, use {AccessControl-_setRoleAdmin}.
     */
    function getRoleAdmin(bytes32 role) external view returns (bytes32);

    /**
     * @dev Grants `role` to `account`.
     *
     * If `account` had not been already granted `role`, emits a {RoleGranted}
     * event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function grantRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from `account`.
     *
     * If `account` had been granted `role`, emits a {RoleRevoked} event.
     *
     * Requirements:
     *
     * - the caller must have ``role``'s admin role.
     */
    function revokeRole(bytes32 role, address account) external;

    /**
     * @dev Revokes `role` from the calling account.
     *
     * Roles are often managed via {grantRole} and {revokeRole}: this function's
     * purpose is to provide a mechanism for accounts to lose their privileges
     * if they are compromised (such as when a trusted device is misplaced).
     *
     * If the calling account had been granted `role`, emits a {RoleRevoked}
     * event.
     *
     * Requirements:
     *
     * - the caller must be `account`.
     */
    function renounceRole(bytes32 role, address account) external;

    /**
     * @notice Gives a function call permission to one single account
     * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE
     * 		May emit a {RoleGranted} event.
     * @param contractAddress address of contract for which call permissions will be granted
     * @param functionSig signature e.g. "functionName(uint,bool)"
     */
    function giveCallPermission(address contractAddress, string calldata functionSig, address accountToPermit) external;

    /**
     * @notice Revokes an account's permission to a particular function call
     * @dev this function can be called only from Role Admin or DEFAULT_ADMIN_ROLE
     * 		May emit a {RoleRevoked} event.
     * @param contractAddress address of contract for which call permissions will be revoked
     * @param functionSig signature e.g. "functionName(uint,bool)"
     */
    function revokeCallPermission(
        address contractAddress,
        string calldata functionSig,
        address accountToRevoke
    ) external;

    /**
     * @notice Verifies if the given account can call a praticular contract's function
     * @dev Since the contract is calling itself this function, we can get contracts address with msg.sender
     * @param account address (eoa or contract) for which call permissions will be checked
     * @param functionSig signature e.g. "functionName(uint,bool)"
     * @return false if the user account cannot call the particular contract function
     *
     */
    function isAllowedToCall(address account, string calldata functionSig) external view returns (bool);

    function hasPermission(
        address account,
        address contractAddress,
        string calldata functionSig
    ) external view returns (bool);
}

// SPDX-License-Identifier: BSD-3-Clause
pragma solidity 0.5.16;

contract TimeManagerV5 {
    /// @dev The approximate number of seconds per year
    uint256 public constant SECONDS_PER_YEAR = 31_536_000;

    /// @notice Number of blocks per year or seconds per year
    uint256 public blocksOrSecondsPerYear;

    /// @dev Sets true when block timestamp is used
    bool public isTimeBased;

    /// @dev Sets true when contract is initialized
    bool private isInitialized;

    /// @notice Deprecated slot for _getCurrentSlot function pointer
    bytes8 private __deprecatedSlot1;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[48] private __gap;

    /**
     * @dev Function to simply retrieve block number or block timestamp
     * @return Current block number or block timestamp
     */
    function getBlockNumberOrTimestamp() public view returns (uint256) {
        return isTimeBased ? _getBlockTimestamp() : _getBlockNumber();
    }

    /**
     * @dev Initializes the contract to use either blocks or seconds
     * @param timeBased_ A boolean indicating whether the contract is based on time or block
     * If timeBased is true than blocksPerYear_ param is ignored as blocksOrSecondsPerYear is set to SECONDS_PER_YEAR
     * @param blocksPerYear_ The number of blocks per year
     */
    function _initializeTimeManager(bool timeBased_, uint256 blocksPerYear_) internal {
        if (isInitialized) revert("Already initialized TimeManager");

        if (!timeBased_ && blocksPerYear_ == 0) {
            revert("Invalid blocks per year");
        }
        if (timeBased_ && blocksPerYear_ != 0) {
            revert("Invalid time based configuration");
        }

        isTimeBased = timeBased_;
        blocksOrSecondsPerYear = timeBased_ ? SECONDS_PER_YEAR : blocksPerYear_;
        isInitialized = true;
    }

    /**
     * @dev Returns the current timestamp in seconds
     * @return The current timestamp
     */
    function _getBlockTimestamp() private view returns (uint256) {
        return block.timestamp;
    }

    /**
     * @dev Returns the current block number
     * @return The current block number
     */
    function _getBlockNumber() private view returns (uint256) {
        return block.number;
    }
}

// SPDX-License-Identifier: BSD-3-Clause
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

/**
 * @title IPrime
 * @author Venus
 * @notice Interface for Prime Token
 */
interface IPrime {
    /**
     * @notice Executed by XVSVault whenever user's XVSVault balance changes
     * @param user the account address whose balance was updated
     */
    function xvsUpdated(address user) external;

    /**
     * @notice accrues interest and updates score for an user for a specific market
     * @param user the account address for which to accrue interest and update score
     * @param market the market for which to accrue interest and update score
     */
    function accrueInterestAndUpdateScore(address user, address market) external;

    /**
     * @notice Distributes income from market since last distribution
     * @param vToken the market for which to distribute the income
     */
    function accrueInterest(address vToken) external;

    /**
     * @notice Returns if user is a prime holder
     * @param isPrimeHolder returns if the user is a prime holder
     */
    function isUserPrimeHolder(address user) external view returns (bool isPrimeHolder);
}

pragma solidity ^0.5.5;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts
        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned
        // for accounts without code, i.e. `keccak256('')`
        bytes32 codehash;
        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;
        // solhint-disable-next-line no-inline-assembly
        assembly {
            codehash := extcodehash(account)
        }
        return (codehash != accountHash && codehash != 0x0);
    }

    /**
     * @dev Converts an `address` into `address payable`. Note that this is
     * simply a type cast: the actual underlying value is not changed.
     *
     * _Available since v2.4.0._
     */
    function toPayable(address account) internal pure returns (address payable) {
        return address(uint160(account));
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     *
     * _Available since v2.4.0._
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        // solhint-disable-next-line avoid-call-value
        // solium-disable-next-line security/no-call-value
        (bool success, ) = recipient.call.value(amount)("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }
}

// SPDX-License-Identifier: MIT
// Adapted from OpenZeppelin Contracts v4.3.2 (utils/cryptography/ECDSA.sol)

// SPDX-Copyright-Text: OpenZeppelin, 2021
// SPDX-Copyright-Text: Venus, 2021

pragma solidity ^0.5.16;

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
contract ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }
}

pragma solidity ^0.5.0;

/**
 * @dev Interface of the BEP20 standard as defined in the EIP. Does not include
 * the optional functions; to access them see {BEP20Detailed}.
 */
interface IBEP20 {
    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

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

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

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

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

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

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

pragma solidity ^0.5.0;

import "./SafeMath.sol";
import "./IBEP20.sol";
import "./Address.sol";

/**
 * @title SafeBEP20
 * @dev Wrappers around BEP20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeBEP20 for BEP20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeBEP20 {
    using SafeMath for uint256;
    using Address for address;

    function safeTransfer(IBEP20 token, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(IBEP20 token, address from, address to, uint256 value) internal {
        callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    function safeApprove(IBEP20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        // solhint-disable-next-line max-line-length
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeBEP20: approve from non-zero to non-zero allowance"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(IBEP20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).add(value);
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(IBEP20 token, address spender, uint256 value) internal {
        uint256 newAllowance = token.allowance(address(this), spender).sub(
            value,
            "SafeBEP20: decreased allowance below zero"
        );
        callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function callOptionalReturn(IBEP20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves.

        // A Solidity high level call has three parts:
        //  1. The target address is checked to verify it contains contract code
        //  2. The call itself is made, and success asserted
        //  3. The return value is decoded, which in turn checks the size of the returned data.
        // solhint-disable-next-line max-line-length
        require(address(token).isContract(), "SafeBEP20: call to non-contract");

        // solhint-disable-next-line avoid-low-level-calls
        (bool success, bytes memory returndata) = address(token).call(data);
        require(success, "SafeBEP20: low-level call failed");

        if (returndata.length > 0) {
            // Return data is optional
            // solhint-disable-next-line max-line-length
            require(abi.decode(returndata, (bool)), "SafeBEP20: BEP20 operation did not succeed");
        }
    }
}

pragma solidity ^0.5.16;

/**
 * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
 * checks.
 *
 * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
 * easily result in undesired exploitation or bugs, since developers usually
 * assume that overflows raise errors. `SafeCast` restores this intuition by
 * reverting the transaction when such an operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 *
 * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
 * all math on `uint256` and `int256` and then downcasting.
 */
library SafeCast {
    /**
     * @dev Returns the downcasted uint128 from uint256, reverting on
     * overflow (when the input is greater than largest uint128).
     *
     * Counterpart to Solidity's `uint128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value < 2 ** 128, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint64 from uint256, reverting on
     * overflow (when the input is greater than largest uint64).
     *
     * Counterpart to Solidity's `uint64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value < 2 ** 64, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint32 from uint256, reverting on
     * overflow (when the input is greater than largest uint32).
     *
     * Counterpart to Solidity's `uint32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value < 2 ** 32, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint16 from uint256, reverting on
     * overflow (when the input is greater than largest uint16).
     *
     * Counterpart to Solidity's `uint16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value < 2 ** 16, "SafeCast: value doesn't fit in 16 bits");
        return uint16(value);
    }

    /**
     * @dev Returns the downcasted uint8 from uint256, reverting on
     * overflow (when the input is greater than largest uint8).
     *
     * Counterpart to Solidity's `uint8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value < 2 ** 8, "SafeCast: value doesn't fit in 8 bits");
        return uint8(value);
    }

    /**
     * @dev Converts a signed int256 into an unsigned uint256.
     *
     * Requirements:
     *
     * - input must be greater than or equal to 0.
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

    /**
     * @dev Returns the downcasted int128 from int256, reverting on
     * overflow (when the input is less than smallest int128 or
     * greater than largest int128).
     *
     * Counterpart to Solidity's `int128` operator.
     *
     * Requirements:
     *
     * - input must fit into 128 bits
     *
     * _Available since v3.1._
     */
    function toInt128(int256 value) internal pure returns (int128) {
        require(value >= -2 ** 127 && value < 2 ** 127, "SafeCast: value doesn't fit in 128 bits");
        return int128(value);
    }

    /**
     * @dev Returns the downcasted int64 from int256, reverting on
     * overflow (when the input is less than smallest int64 or
     * greater than largest int64).
     *
     * Counterpart to Solidity's `int64` operator.
     *
     * Requirements:
     *
     * - input must fit into 64 bits
     *
     * _Available since v3.1._
     */
    function toInt64(int256 value) internal pure returns (int64) {
        require(value >= -2 ** 63 && value < 2 ** 63, "SafeCast: value doesn't fit in 64 bits");
        return int64(value);
    }

    /**
     * @dev Returns the downcasted int32 from int256, reverting on
     * overflow (when the input is less than smallest int32 or
     * greater than largest int32).
     *
     * Counterpart to Solidity's `int32` operator.
     *
     * Requirements:
     *
     * - input must fit into 32 bits
     *
     * _Available since v3.1._
     */
    function toInt32(int256 value) internal pure returns (int32) {
        require(value >= -2 ** 31 && value < 2 ** 31, "SafeCast: value doesn't fit in 32 bits");
        return int32(value);
    }

    /**
     * @dev Returns the downcasted int16 from int256, reverting on
     * overflow (when the input is less than smallest int16 or
     * greater than largest int16).
     *
     * Counterpart to Solidity's `int16` operator.
     *
     * Requirements:
     *
     * - input must fit into 16 bits
     *
     * _Available since v3.1._
     */
    function toInt16(int256 value) internal pure returns (int16) {
        require(value >= -2 ** 15 && value < 2 ** 15, "SafeCast: value doesn't fit in 16 bits");
        return int16(value);
    }

    /**
     * @dev Returns the downcasted int8 from int256, reverting on
     * overflow (when the input is less than smallest int8 or
     * greater than largest int8).
     *
     * Counterpart to Solidity's `int8` operator.
     *
     * Requirements:
     *
     * - input must fit into 8 bits.
     *
     * _Available since v3.1._
     */
    function toInt8(int256 value) internal pure returns (int8) {
        require(value >= -2 ** 7 && value < 2 ** 7, "SafeCast: value doesn't fit in 8 bits");
        return int8(value);
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        require(value < 2 ** 255, "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

pragma solidity ^0.5.16;

/**
 * @dev Wrappers over Solidity's arithmetic operations with added overflow
 * checks.
 *
 * Arithmetic operations in Solidity wrap on overflow. This can easily result
 * in bugs, because programmers usually assume that an overflow raises an
 * error, which is the standard behavior in high level programming languages.
 * `SafeMath` restores this intuition by reverting the transaction when an
 * operation overflows.
 *
 * Using this library instead of the unchecked operations eliminates an entire
 * class of bugs, so it's recommended to use it always.
 */
library SafeMath {
    /**
     * @dev Returns the addition of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `+` operator.
     *
     * Requirements:
     * - Addition cannot overflow.
     */
    function add(uint256 a, uint256 b) internal pure returns (uint256) {
        return add(a, b, "SafeMath: addition overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function add(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        uint256 c = a + b;
        require(c >= a, errorMessage);

        return c;
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b) internal pure returns (uint256) {
        return sub(a, b, "SafeMath: subtraction overflow");
    }

    /**
     * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
     * overflow (when the result is negative).
     *
     * Counterpart to Solidity's `-` operator.
     *
     * Requirements:
     * - Subtraction cannot overflow.
     */
    function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b <= a, errorMessage);
        uint256 c = a - b;

        return c;
    }

    /**
     * @dev Returns the multiplication of two unsigned integers, reverting on
     * overflow.
     *
     * Counterpart to Solidity's `*` operator.
     *
     * Requirements:
     * - Multiplication cannot overflow.
     */
    function mul(uint256 a, uint256 b) internal pure returns (uint256) {
        // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
        // benefit is lost if 'b' is also tested.
        // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
        if (a == 0) {
            return 0;
        }

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

        return c;
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b) internal pure returns (uint256) {
        return div(a, b, "SafeMath: division by zero");
    }

    /**
     * @dev Returns the integer division of two unsigned integers. Reverts with custom message on
     * division by zero. The result is rounded towards zero.
     *
     * Counterpart to Solidity's `/` operator. Note: this function uses a
     * `revert` opcode (which leaves remaining gas untouched) while Solidity
     * uses an invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        // Solidity only automatically asserts when dividing by 0
        require(b > 0, errorMessage);
        uint256 c = a / b;
        // assert(a == b * c + a % b); // There is no case in which this doesn't hold

        return c;
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b) internal pure returns (uint256) {
        return mod(a, b, "SafeMath: modulo by zero");
    }

    /**
     * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
     * Reverts with custom message when dividing by zero.
     *
     * Counterpart to Solidity's `%` operator. This function uses a `revert`
     * opcode (which leaves remaining gas untouched) while Solidity uses an
     * invalid opcode to revert (consuming all remaining gas).
     *
     * Requirements:
     * - The divisor cannot be zero.
     */
    function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
        require(b != 0, errorMessage);
        return a % b;
    }
}

pragma solidity 0.5.16;
import "../Utils/SafeBEP20.sol";
import "../Utils/IBEP20.sol";

/**
 * @title XVS Store
 * @author Venus
 * @notice XVS Store responsible for distributing XVS rewards
 */
contract XVSStore {
    using SafeMath for uint256;
    using SafeBEP20 for IBEP20;

    /// @notice The Admin Address
    address public admin;

    /// @notice The pending admin address
    address public pendingAdmin;

    /// @notice The Owner Address
    address public owner;

    /// @notice The reward tokens
    mapping(address => bool) public rewardTokens;

    /// @notice Emitted when pendingAdmin is changed
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /// @notice Event emitted when admin changed
    event AdminTransferred(address indexed oldAdmin, address indexed newAdmin);

    /// @notice Event emitted when owner changed
    event OwnerTransferred(address indexed oldOwner, address indexed newOwner);

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

    modifier onlyAdmin() {
        require(msg.sender == admin, "only admin can");
        _;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "only owner can");
        _;
    }

    /**
     * @notice Safely transfer rewards. Only active reward tokens can be sent using this function.
     * Only callable by owner
     * @dev Safe reward token transfer function, just in case if rounding error causes pool to not have enough tokens.
     * @param token Reward token to transfer
     * @param _to Destination address of the reward
     * @param _amount Amount to transfer
     */
    function safeRewardTransfer(address token, address _to, uint256 _amount) external onlyOwner {
        require(rewardTokens[token] == true, "only reward token can");

        if (address(token) != address(0)) {
            uint256 tokenBalance = IBEP20(token).balanceOf(address(this));
            if (_amount > tokenBalance) {
                IBEP20(token).safeTransfer(_to, tokenBalance);
            } else {
                IBEP20(token).safeTransfer(_to, _amount);
            }
        }
    }

    /**
     * @notice Allows the admin to propose a new admin
     * Only callable admin
     * @param _admin Propose an account as admin of the XVS store
     */
    function setPendingAdmin(address _admin) external onlyAdmin {
        address oldPendingAdmin = pendingAdmin;
        pendingAdmin = _admin;
        emit NewPendingAdmin(oldPendingAdmin, _admin);
    }

    /**
     * @notice Allows an account that is pending as admin to accept the role
     * nly calllable by the pending admin
     */
    function acceptAdmin() external {
        require(msg.sender == pendingAdmin, "only pending admin");
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        admin = pendingAdmin;
        pendingAdmin = address(0);

        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);
        emit AdminTransferred(oldAdmin, admin);
    }

    /**
     * @notice Set the contract owner
     * @param _owner The address of the owner to set
     * Only callable admin
     */
    function setNewOwner(address _owner) external onlyAdmin {
        require(_owner != address(0), "new owner is the zero address");
        address oldOwner = owner;
        owner = _owner;
        emit OwnerTransferred(oldOwner, _owner);
    }

    /**
     * @notice Set or disable a reward token
     * @param _tokenAddress The address of a token to set as active or inactive
     * @param status Set whether a reward token is active or not
     */
    function setRewardToken(address _tokenAddress, bool status) external {
        require(msg.sender == admin || msg.sender == owner, "only admin or owner can");
        rewardTokens[_tokenAddress] = status;
    }

    /**
     * @notice Security function to allow the owner of the contract to withdraw from the contract
     * @param _tokenAddress Reward token address to withdraw
     * @param _amount Amount of token to withdraw
     */
    function emergencyRewardWithdraw(address _tokenAddress, uint256 _amount) external onlyOwner {
        IBEP20(_tokenAddress).safeTransfer(address(msg.sender), _amount);
    }
}

pragma solidity ^0.5.16;

contract XVSVaultErrorReporter {
    enum Error {
        NO_ERROR,
        UNAUTHORIZED
    }

    enum FailureInfo {
        ACCEPT_ADMIN_PENDING_ADMIN_CHECK,
        ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK,
        SET_PENDING_ADMIN_OWNER_CHECK,
        SET_PENDING_IMPLEMENTATION_OWNER_CHECK
    }

    /**
     * @dev `error` corresponds to enum Error; `info` corresponds to enum FailureInfo, and `detail` is an arbitrary
     * contract-specific code that enables us to report opaque error codes from upgradeable contracts.
     **/
    event Failure(uint error, uint info, uint detail);

    /**
     * @dev use this when reporting a known error from the money market or a non-upgradeable collaborator
     */
    function fail(Error err, FailureInfo info) internal returns (uint) {
        emit Failure(uint(err), uint(info), 0);

        return uint(err);
    }

    /**
     * @dev use this when reporting an opaque error from an upgradeable collaborator contract
     */
    function failOpaque(Error err, FailureInfo info, uint opaqueError) internal returns (uint) {
        emit Failure(uint(err), uint(info), opaqueError);

        return uint(err);
    }
}

pragma solidity ^0.5.16;

import "./XVSVaultStorage.sol";
import "./XVSVaultErrorReporter.sol";

/**
 * @title XVS Vault Proxy
 * @author Venus
 * @notice XVS Vault Proxy contract
 */
contract XVSVaultProxy is XVSVaultAdminStorage, XVSVaultErrorReporter {
    /**
     * @notice Emitted when pendingXVSVaultImplementation is changed
     */
    event NewPendingImplementation(address oldPendingImplementation, address newPendingImplementation);

    /**
     * @notice Emitted when pendingXVSVaultImplementation is accepted, which means XVS Vault implementation is updated
     */
    event NewImplementation(address oldImplementation, address newImplementation);

    /**
     * @notice Emitted when pendingAdmin is changed
     */
    event NewPendingAdmin(address oldPendingAdmin, address newPendingAdmin);

    /**
     * @notice Emitted when pendingAdmin is accepted, which means admin is updated
     */
    event NewAdmin(address oldAdmin, address newAdmin);

    constructor() public {
        // Set admin to caller
        admin = msg.sender;
    }

    /*** Admin Functions ***/
    function _setPendingImplementation(address newPendingImplementation) public returns (uint) {
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_IMPLEMENTATION_OWNER_CHECK);
        }

        address oldPendingImplementation = pendingXVSVaultImplementation;

        pendingXVSVaultImplementation = newPendingImplementation;

        emit NewPendingImplementation(oldPendingImplementation, pendingXVSVaultImplementation);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Accepts new implementation of XVS Vault. msg.sender must be pendingImplementation
     * @dev Admin function for new implementation to accept it's role as implementation
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _acceptImplementation() public returns (uint) {
        // Check caller is pendingImplementation
        if (msg.sender != pendingXVSVaultImplementation) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_PENDING_IMPLEMENTATION_ADDRESS_CHECK);
        }

        // Save current values for inclusion in log
        address oldImplementation = implementation;
        address oldPendingImplementation = pendingXVSVaultImplementation;

        implementation = pendingXVSVaultImplementation;

        pendingXVSVaultImplementation = address(0);

        emit NewImplementation(oldImplementation, implementation);
        emit NewPendingImplementation(oldPendingImplementation, pendingXVSVaultImplementation);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Begins transfer of admin rights. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @dev Admin function to begin change of admin. The newPendingAdmin must call `_acceptAdmin` to finalize the transfer.
     * @param newPendingAdmin New pending admin.
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _setPendingAdmin(address newPendingAdmin) public returns (uint) {
        // Check caller = admin
        if (msg.sender != admin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.SET_PENDING_ADMIN_OWNER_CHECK);
        }

        // Save current value, if any, for inclusion in log
        address oldPendingAdmin = pendingAdmin;

        // Store pendingAdmin with value newPendingAdmin
        pendingAdmin = newPendingAdmin;

        // Emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin)
        emit NewPendingAdmin(oldPendingAdmin, newPendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
     * @notice Accepts transfer of admin rights. msg.sender must be pendingAdmin
     * @dev Admin function for pending admin to accept role and update admin
     * @return uint 0=success, otherwise a failure (see ErrorReporter.sol for details)
     */
    function _acceptAdmin() public returns (uint) {
        // Check caller is pendingAdmin
        if (msg.sender != pendingAdmin) {
            return fail(Error.UNAUTHORIZED, FailureInfo.ACCEPT_ADMIN_PENDING_ADMIN_CHECK);
        }

        // Save current values for inclusion in log
        address oldAdmin = admin;
        address oldPendingAdmin = pendingAdmin;

        // Store admin with value pendingAdmin
        admin = pendingAdmin;

        // Clear the pending value
        pendingAdmin = address(0);

        emit NewAdmin(oldAdmin, admin);
        emit NewPendingAdmin(oldPendingAdmin, pendingAdmin);

        return uint(Error.NO_ERROR);
    }

    /**
     * @dev Delegates execution to an implementation contract.
     * It returns to the external caller whatever the implementation returns
     * or forwards reverts.
     */
    function() external payable {
        // delegate all other functions to current implementation
        (bool success, ) = implementation.delegatecall(msg.data);

        assembly {
            let free_mem_ptr := mload(0x40)
            returndatacopy(free_mem_ptr, 0, returndatasize)

            switch success
            case 0 {
                revert(free_mem_ptr, returndatasize)
            }
            default {
                return(free_mem_ptr, returndatasize)
            }
        }
    }
}

pragma solidity ^0.5.16;

import "../Utils/SafeMath.sol";
import "../Utils/IBEP20.sol";
import "../Tokens/Prime/IPrime.sol";

contract XVSVaultAdminStorage {
    /**
     * @notice Administrator for this contract
     */
    address public admin;

    /**
     * @notice Pending administrator for this contract
     */
    address public pendingAdmin;

    /**
     * @notice Active brains of XVS Vault
     */
    address public implementation;

    /**
     * @notice Pending brains of XVS Vault
     */
    address public pendingXVSVaultImplementation;
}

contract XVSVaultStorageV1 is XVSVaultAdminStorage {
    /// @notice Guard variable for re-entrancy checks
    bool internal _notEntered;

    /// @notice The reward token store
    address public xvsStore;

    /// @notice The xvs token address
    address public xvsAddress;

    // Reward tokens created per block or second indentified by reward token address.
    mapping(address => uint256) public rewardTokenAmountsPerBlockOrSecond;

    /// @notice Info of each user.
    struct UserInfo {
        uint256 amount;
        uint256 rewardDebt;
        uint256 pendingWithdrawals;
    }

    // Info of each pool.
    struct PoolInfo {
        IBEP20 token; // Address of token contract to stake.
        uint256 allocPoint; // How many allocation points assigned to this pool.
        uint256 lastRewardBlockOrSecond; // Last block number or second that reward tokens distribution occurs.
        uint256 accRewardPerShare; // Accumulated per share, times 1e12. See below.
        uint256 lockPeriod; // Min time between withdrawal request and its execution.
    }

    // Infomation about a withdrawal request
    struct WithdrawalRequest {
        uint256 amount;
        uint128 lockedUntil;
        uint128 afterUpgrade;
    }

    // Info of each user that stakes tokens.
    mapping(address => mapping(uint256 => mapping(address => UserInfo))) internal userInfos;

    // Info of each pool.
    mapping(address => PoolInfo[]) public poolInfos;

    // Total allocation points. Must be the sum of all allocation points in all pools.
    mapping(address => uint256) public totalAllocPoints;

    // Info of requested but not yet executed withdrawals
    mapping(address => mapping(uint256 => mapping(address => WithdrawalRequest[]))) internal withdrawalRequests;

    /// @notice DEPRECATED A record of each accounts delegate (before the voting power fix)
    mapping(address => address) private __oldDelegatesSlot;

    /// @notice A checkpoint for marking number of votes from a given block or second
    struct Checkpoint {
        uint32 fromBlockOrSecond;
        uint96 votes;
    }

    /// @notice DEPRECATED A record of votes checkpoints for each account, by index (before the voting power fix)
    mapping(address => mapping(uint32 => Checkpoint)) private __oldCheckpointsSlot;

    /// @notice DEPRECATED The number of checkpoints for each account (before the voting power fix)
    mapping(address => uint32) private __oldNumCheckpointsSlot;

    /// @notice A record of states for signing / validating signatures
    mapping(address => uint) public nonces;

    /// @notice The EIP-712 typehash for the contract's domain
    bytes32 public constant DOMAIN_TYPEHASH =
        keccak256("EIP712Domain(string name,uint256 chainId,address verifyingContract)");

    /// @notice The EIP-712 typehash for the delegation struct used by the contract
    bytes32 public constant DELEGATION_TYPEHASH =
        keccak256("Delegation(address delegatee,uint256 nonce,uint256 expiry)");
}

contract XVSVaultStorage is XVSVaultStorageV1 {
    /// @notice A record of each accounts delegate
    mapping(address => address) public delegates;

    /// @notice A record of votes checkpoints for each account, by index
    mapping(address => mapping(uint32 => Checkpoint)) public checkpoints;

    /// @notice The number of checkpoints for each account
    mapping(address => uint32) public numCheckpoints;

    /// @notice Tracks pending withdrawals for all users for a particular reward token and pool id
    mapping(address => mapping(uint256 => uint256)) public totalPendingWithdrawals;

    /// @notice pause indicator for Vault
    bool public vaultPaused;

    /// @notice if the token is added to any of the pools
    mapping(address => bool) public isStakedToken;

    /// @notice Amount we owe to users because of failed transfer attempts
    mapping(address => mapping(address => uint256)) public pendingRewardTransfers;

    /// @notice Prime token contract address
    IPrime public primeToken;

    /// @notice Reward token for which prime token is issued for staking
    address public primeRewardToken;

    /// @notice Pool ID for which prime token is issued for staking
    uint256 public primePoolId;

    /**
     * @dev This empty reserved space is put in place to allow future versions to add new
     * variables without shifting down storage in the inheritance chain.
     * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
     */
    uint256[46] private __gap;
}

Settings
{
  "evmVersion": "istanbul",
  "libraries": {},
  "metadata": {
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegator","type":"address"},{"indexed":true,"internalType":"address","name":"fromDelegate","type":"address"},{"indexed":true,"internalType":"address","name":"toDelegate","type":"address"}],"name":"DelegateChangedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"previousBalance","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newBalance","type":"uint256"}],"name":"DelegateVotesChangedV2","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"ExecutedWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldAccessControlManager","type":"address"},{"indexed":false,"internalType":"address","name":"newAccessControlManager","type":"address"}],"name":"NewAccessControlManager","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"contract IPrime","name":"oldPrimeToken","type":"address"},{"indexed":true,"internalType":"contract IPrime","name":"newPrimeToken","type":"address"},{"indexed":false,"internalType":"address","name":"oldPrimeRewardToken","type":"address"},{"indexed":false,"internalType":"address","name":"newPrimeRewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldPrimePoolId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPrimePoolId","type":"uint256"}],"name":"NewPrimeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":true,"internalType":"address","name":"token","type":"address"},{"indexed":false,"internalType":"uint256","name":"allocPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rewardPerBlockOrSecond","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"name":"PoolAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldAllocPoints","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newAllocPoints","type":"uint256"}],"name":"PoolUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"RequestedWithdrawal","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldReward","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newReward","type":"uint256"}],"name":"RewardAmountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldXvs","type":"address"},{"indexed":false,"internalType":"address","name":"oldStore","type":"address"},{"indexed":false,"internalType":"address","name":"newXvs","type":"address"},{"indexed":false,"internalType":"address","name":"newStore","type":"address"}],"name":"StoreUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"address","name":"userAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldOwedAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newOwedAmount","type":"uint256"}],"name":"VaultDebtUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"}],"name":"VaultPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"}],"name":"VaultResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"rewardToken","type":"address"},{"indexed":true,"internalType":"uint256","name":"pid","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"oldPeriod","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newPeriod","type":"uint256"}],"name":"WithdrawalLockingPeriodUpdated","type":"event"},{"constant":true,"inputs":[],"name":"DELEGATION_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"DOMAIN_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"MAX_LOCK_PERIOD","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"SECONDS_PER_YEAR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"contract XVSVaultProxy","name":"xvsVaultProxy","type":"address"}],"name":"_become","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"accessControlManager","outputs":[{"internalType":"contract IAccessControlManagerV5","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"},{"internalType":"contract IBEP20","name":"_token","type":"address"},{"internalType":"uint256","name":"_rewardPerBlockOrSecond","type":"uint256"},{"internalType":"uint256","name":"_lockPeriod","type":"uint256"}],"name":"add","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"admin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"blocksOrSecondsPerYear","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint32","name":"","type":"uint32"}],"name":"checkpoints","outputs":[{"internalType":"uint32","name":"fromBlockOrSecond","type":"uint32"},{"internalType":"uint96","name":"votes","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_account","type":"address"},{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"claim","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegatee","type":"address"}],"name":"delegate","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"delegatee","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"expiry","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"delegateBySig","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegates","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"executeWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"getBlockNumberOrTimestamp","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"getCurrentVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getEligibleWithdrawalAmount","outputs":[{"internalType":"uint256","name":"withdrawalAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"blockNumberOrSecond","type":"uint256"}],"name":"getPriorVotes","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getRequestedAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getUserInfo","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"rewardDebt","type":"uint256"},{"internalType":"uint256","name":"pendingWithdrawals","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"getWithdrawalRequests","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint128","name":"lockedUntil","type":"uint128"},{"internalType":"uint128","name":"afterUpgrade","type":"uint128"}],"internalType":"struct XVSVaultStorageV1.WithdrawalRequest[]","name":"","type":"tuple[]"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"implementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bool","name":"timeBased_","type":"bool"},{"internalType":"uint256","name":"blocksPerYear_","type":"uint256"}],"name":"initializeTimeManager","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isStakedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"isTimeBased","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"numCheckpoints","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"pause","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"pendingAdmin","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingReward","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"pendingRewardTransfers","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"address","name":"_user","type":"address"}],"name":"pendingWithdrawalsBeforeUpgrade","outputs":[{"internalType":"uint256","name":"beforeUpgradeWithdrawalAmount","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"pendingXVSVaultImplementation","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"poolInfos","outputs":[{"internalType":"contract IBEP20","name":"token","type":"address"},{"internalType":"uint256","name":"allocPoint","type":"uint256"},{"internalType":"uint256","name":"lastRewardBlockOrSecond","type":"uint256"},{"internalType":"uint256","name":"accRewardPerShare","type":"uint256"},{"internalType":"uint256","name":"lockPeriod","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"rewardToken","type":"address"}],"name":"poolLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"primePoolId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"primeRewardToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"primeToken","outputs":[{"internalType":"contract IPrime","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"requestWithdrawal","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"resume","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"}],"name":"rewardTokenAmountsPerBlock","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"rewardTokenAmountsPerBlockOrSecond","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_allocPoint","type":"uint256"}],"name":"set","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"newAccessControlAddress","type":"address"}],"name":"setAccessControl","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"contract IPrime","name":"_primeToken","type":"address"},{"internalType":"address","name":"_primeRewardToken","type":"address"},{"internalType":"uint256","name":"_primePoolId","type":"uint256"}],"name":"setPrimeToken","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_rewardAmount","type":"uint256"}],"name":"setRewardAmountPerBlockOrSecond","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"},{"internalType":"uint256","name":"_newPeriod","type":"uint256"}],"name":"setWithdrawalLockingPeriod","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_xvs","type":"address"},{"internalType":"address","name":"_xvsStore","type":"address"}],"name":"setXvsStore","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"totalAllocPoints","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalPendingWithdrawals","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_rewardToken","type":"address"},{"internalType":"uint256","name":"_pid","type":"uint256"}],"name":"updatePool","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"vaultPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"xvsAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"xvsStore","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b50600080546001600160a01b0319163317905561578980620000336000396000f3fe608060405234801561001057600080fd5b50600436106103785760003560e01c806392e35000116101d3578063c7ad089511610104578063e7a324dc116100a2578063f55401621161007c578063f554016214610732578063f851a4401461073a578063fba1b1f914610742578063fe5a451a1461075557610378565b8063e7a324dc14610701578063e8f2be6f14610709578063f1127ed81461071157610378565b8063dae66bbe116100de578063dae66bbe146106d6578063de0368b2146106e9578063e1d146fb146106f1578063e6a69ab8146106f957610378565b8063c7ad0895146106a8578063cd9b94e7146106b0578063d7ae45e2146106c357610378565b8063add8933711610171578063b6a5fd2f1161014b578063b6a5fd2f1461064f578063c210259614610662578063c3c754a814610682578063c3cda5201461069557610378565b8063add893371461061f578063b4a0bdf314610627578063b4b5ea571461063c57610378565b80639e2b6c4d116101ad5780639e2b6c4d146105d3578063a09eab7a146105e6578063a6997762146105f9578063a9d69a691461060c57610378565b806392e350001461057a57806398e1b31b1461059e578063996cba68146105c057610378565b80635c19a95c116102ad57806373d025d61161024b5780637ecebe00116102255780637ecebe00146105395780638308d7e91461054c5780638456cb591461055f5780638ed7333d1461056757610378565b806373d025d6146104f1578063782d6fe1146105065780637ac924561461052657610378565b80635ff56315116102875780635ff56315146104a35780636857249c146104b65780636dd77cbd146104be5780636fcfff45146104d157610378565b80635c19a95c146104755780635c60da1b146104885780635f14e7001461049057610378565b806324f52bbf1161031a578063358ae036116102f4578063358ae036146104345780633d4180f91461043c5780634298bdbd1461044f578063587cde1e1461046257610378565b806324f52bbf1461040457806326782247146104195780632eda5c6c1461042157610378565b8063115b512f11610356578063115b512f146103c357806319129e5a146103d65780631d504dc6146103e957806320606b70146103fc57610378565b8063046f7da21461037d5780630af13728146103875780630efe6a8b146103b0575b600080fd5b61038561075d565b005b61039a6103953660046140be565b6107e8565b6040516103a791906150ae565b60405180910390f35b6103856103be366004614176565b61082e565b6103856103d1366004614176565b610b23565b6103856103e4366004613fcb565b610ed7565b6103856103f73660046142bd565b610f0d565b61039a61103e565b61040c611055565b6040516103a79190614f4c565b61040c611064565b61039a61042f366004613fcb565b611073565b61040c611092565b61039a61044a366004614007565b6110a1565b61039a61045d366004613fcb565b6110be565b61040c610470366004613fcb565b6110d0565b610385610483366004613fcb565b6110eb565b61040c611118565b61039a61049e36600461408e565b611127565b6103856104b1366004614007565b611144565b61039a611238565b61039a6104cc3660046140be565b61123e565b6104e46104df366004613fcb565b6112f3565b6040516103a7919061545c565b6104f961130b565b6040516103a791906150a0565b61051961051436600461408e565b611314565b6040516103a79190615485565b61038561053436600461408e565b61152a565b61039a610547366004613fcb565b611873565b61038561055a366004614176565b611885565b610385611a2b565b61038561057536600461408e565b611ab0565b61058d61058836600461408e565b611aeb565b6040516103a795949392919061511b565b6105b16105ac3660046140be565b611b40565b6040516103a793929190615441565b6103856105ce366004614041565b611b92565b6103856105e1366004614176565b611d24565b61039a6105f43660046140be565b611e0f565b61038561060736600461427d565b61205f565b61039a61061a3660046140be565b612093565b61040c6120d5565b61062f6120e4565b6040516103a7919061510d565b61051961064a366004613fcb565b6120f3565b61038561065d36600461408e565b612163565b6106756106703660046140be565b612289565b6040516103a7919061508f565b6104f9610690366004613fcb565b612343565b6103856106a33660046141a8565b612358565b6104f96124fc565b61039a6106be366004613fcb565b612505565b61039a6106d1366004613fcb565b612517565b6103856106e436600461429c565b612532565b61040c61263e565b61039a61264d565b61039a612674565b61039a61267c565b61039a612688565b61072461071f36600461422f565b61268e565b6040516103a792919061546a565b61039a6126c3565b61040c6126cb565b610385610750366004614101565b6126da565b61062f6129bf565b61078660405180604001604052806008815260200167726573756d65282960c01b8152506129ce565b60135460ff166107b15760405162461bcd60e51b81526004016107a8906151d8565b60405180910390fd5b6013805460ff1916905560405133907fd2619572a1464e0df0bb351d834fd47f3350984d7bfdb1ab69cfcb0b8e42141590600090a2565b60006107f48484612a70565b506001600160a01b0380841660009081526007602090815260408083208684528252808320938516835292905220600201545b9392505050565b600354600160a01b900460ff166108575760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff16156108875760405162461bcd60e51b81526004016107a8906151c8565b6108918383612a70565b6001600160a01b03831660009081526008602052604081208054849081106108b557fe5b600091825260208083206001600160a01b038816845260078252604080852088865283528085203386529092529220600590910290910191506108f88585612aa7565b610903858533612093565b156109205760405162461bcd60e51b81526004016107a8906152e8565b8054156109955760006109338284612c84565b9050801561099357610946863383612c98565b84866001600160a01b0316336001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e946458460405161098a91906150ae565b60405180910390a45b505b81546109b2906001600160a01b031633308663ffffffff612f1116565b80546109c4908463ffffffff612f7216565b81556109d08183612fb4565b600182015560055482546001600160a01b0390811691161415610a3757336000908152600f60209081526040808320548151606081019092526021808352610a3794936001600160a01b0390921692610a329289929061562990830139612fe2565b613011565b6017546001600160a01b038681169116148015610a55575060185484145b15610abd576016546040516337f23cd360e01b81526001600160a01b03909116906337f23cd390610a8a903390600401614f5a565b600060405180830381600087803b158015610aa457600080fd5b505af1158015610ab8573d6000803e3d6000fd5b505050505b83856001600160a01b0316336001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d786604051610b0191906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b179055505050565b600354600160a01b900460ff16610b4c5760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff1615610b7c5760405162461bcd60e51b81526004016107a8906151c8565b610b868383612a70565b60008111610ba65760405162461bcd60e51b81526004016107a890615308565b6001600160a01b0383166000908152600760209081526040808320858452825280832033845290915290206002810154610be6908363ffffffff612f7216565b81541015610c065760405162461bcd60e51b81526004016107a8906153e8565b6001600160a01b0384166000908152600860205260408120805485908110610c2a57fe5b600091825260208083206001600160a01b0389168452600a825260408085208986528352808520338652909252908320600590920201925090610c6c826131a3565b5090508015610c8d5760405162461bcd60e51b81526004016107a8906152e8565b610c978787612aa7565b6000610ca38585612c84565b9050610cb0883383612c98565b6004840154600090610cc8904263ffffffff612f7216565b9050610cd686858984613247565b6001600160a01b03891660009081526012602090815260408083208b8452909152902054610d0a908863ffffffff612f7216565b6001600160a01b038a1660009081526012602090815260408083208c8452909152902055610d388686612fb4565b600187015560055485546001600160a01b0390811691161415610d9b57336000908152600f6020908152604080832054815160608101909252602b808352610d9b946001600160a01b03909216939192610a32928d92906155d690830139612fe2565b6017546001600160a01b038a81169116148015610db9575060185488145b15610e21576016546040516337f23cd360e01b81526001600160a01b03909116906337f23cd390610dee903390600401614f5a565b600060405180830381600087803b158015610e0857600080fd5b505af1158015610e1c573d6000803e3d6000fd5b505050505b87896001600160a01b0316336001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e9464585604051610e6591906150ae565b60405180910390a487896001600160a01b0316336001600160a01b03167f88a254a0ef28a0b9e957ff600beae69870f6f924065147f3627c3f814e60ec118a604051610eb191906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b17905550505050505050565b6000546001600160a01b03163314610f015760405162461bcd60e51b81526004016107a890615368565b610f0a8161342b565b50565b806001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015610f4657600080fd5b505afa158015610f5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f7e9190810190613fe9565b6001600160a01b0316336001600160a01b031614610fae5760405162461bcd60e51b81526004016107a8906153f8565b806001600160a01b031663c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610fe957600080fd5b505af1158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061102191908101906142db565b15610f0a5760405162461bcd60e51b81526004016107a890615378565b60405161104a90614f36565b604051809103902081565b6004546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152600660205260409020545b919050565b6005546001600160a01b031681565b601560209081526000928352604080842090915290825290205481565b60096020526000908152604090205481565b600f602052600090815260409020546001600160a01b031681565b60135460ff161561110e5760405162461bcd60e51b81526004016107a8906151c8565b610f0a33826134b0565b6002546001600160a01b031681565b601260209081526000928352604080842090915290825290205481565b6000546001600160a01b0316331461116e5760405162461bcd60e51b81526004016107a890615368565b6111778261353f565b6111808161353f565b6005546004546001600160a01b03918216911681156111b15760405162461bcd60e51b81526004016107a8906152a8565b600580546001600160a01b038087166001600160a01b03199283161790925560048054928616929091169190911790556003805460ff60a01b1916600160a01b1790556040517f559f314bb90394a4a9ceb724f365b36a53587d894352c43d12901fd6801014569061122a908490849088908890614fcb565b60405180910390a150505050565b60795481565b600061124a8484612a70565b6001600160a01b038085166000908152600a60209081526040808320878452825280832093861683529290522080545b6000811180156112aa57506112aa82600183038154811061129757fe5b9060005260206000209060020201613565565b156112ea576112df8260018303815481106112c157fe5b6000918252602090912060029091020154849063ffffffff612f7216565b92506000190161127a565b50509392505050565b60116020526000908152604090205463ffffffff1681565b60135460ff1681565b600061131e61264d565b821061133c5760405162461bcd60e51b81526004016107a8906152b8565b6001600160a01b03831660009081526011602052604090205463ffffffff168061136a576000915050611524565b6001600160a01b038416600090815260106020908152604080832063ffffffff6000198601811685529252909120541683106113e6576001600160a01b03841660009081526010602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050611524565b6001600160a01b038416600090815260106020908152604080832083805290915290205463ffffffff16831015611421576000915050611524565b600060001982015b8163ffffffff168163ffffffff1611156114e457600282820363ffffffff16048103611453613f51565b506001600160a01b038716600090815260106020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b031691810191909152908714156114bf576020015194506115249350505050565b805163ffffffff168711156114d6578193506114dd565b6001820392505b5050611429565b506001600160a01b038516600090815260106020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b600354600160a01b900460ff166115535760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff16156115835760405162461bcd60e51b81526004016107a8906151c8565b61158d8282612a70565b6001600160a01b03821660009081526008602052604081208054839081106115b157fe5b600091825260208083206001600160a01b038716808552600783526040808620888752845280862033808852908552818720928752600a8552818720898852855281872090875290935291842060059093020193509180611612848461357a565b9092509050811515806116255750600081115b6116415760405162461bcd60e51b81526004016107a890615388565b81158061164c575080155b6116685760405162461bcd60e51b81526004016107a890615188565b8115611781576116788787612aa7565b60006116be85600101546116b264e8d4a510006116a68a600301548a6000015461367190919063ffffffff16565b9063ffffffff6136ab16565b9063ffffffff6136ed16565b6004805460405163135b33cd60e31b81529293506001600160a01b031691639ad99e68916116f2918c913391879101614fa3565b600060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b50508654611737925090508463ffffffff6136ed16565b808655600387015461175a9164e8d4a51000916116a6919063ffffffff61367116565b6001860155855461177b906001600160a01b0316338563ffffffff61372f16565b50611805565b8354611793908263ffffffff6136ed16565b84556001600160a01b03871660009081526012602090815260408083208984529091529020546117c9908263ffffffff6136ed16565b6001600160a01b0380891660009081526012602090815260408083208b845290915290209190915585546118059116338363ffffffff61372f16565b856001600160a01b038816337fe31da05fae6db869f5ea51f4b638aa6884070b6c87f18f63bd2291a12cb2f518611842868663ffffffff612f7216565b60405161184f91906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b1790555050505050565b600e6020526000908152604090205481565b6118c36040518060400160405280601c81526020017f73657428616464726573732c75696e743235362c75696e7432353629000000008152506129ce565b6118cd8383612a70565b6118d683613751565b6001600160a01b0383166000908152600860205260408120805490919061194f9084906119439085908890811061190957fe5b60009182526020808320600160059093020191909101546001600160a01b038b16835260099091526040909120549063ffffffff6136ed16565b9063ffffffff612f7216565b9050600081116119715760405162461bcd60e51b81526004016107a890615408565b600082858154811061197f57fe5b9060005260206000209060050201600101549050838386815481106119a057fe5b9060005260206000209060050201600101819055508160096000886001600160a01b03166001600160a01b031681526020019081526020016000208190555084866001600160a01b03167f6ee09c6cb801194690c195c69f465aaf7c80255cbeafaab9600f47ed79de2ca98387604051611a1b929190615433565b60405180910390a3505050505050565b611a53604051806040016040528060078152602001667061757365282960c81b8152506129ce565b60135460ff1615611a765760405162461bcd60e51b81526004016107a890615268565b6013805460ff1916600117905560405133907fdffada2889ebfab9224c24069d833f3de835d8cf99872d49e7b7ba5fccb7a46f90600090a2565b60135460ff1615611ad35760405162461bcd60e51b81526004016107a8906151c8565b611add8282612a70565b611ae78282612aa7565b5050565b60086020528160005260406000208181548110611b0457fe5b6000918252602090912060059091020180546001820154600283015460038401546004909401546001600160a01b039093169550909350919085565b6000806000611b4f8686612a70565b5050506001600160a01b03928316600090815260076020908152604080832094835293815283822092909416815292529020805460018201546002909201549092565b600354600160a01b900460ff16611bbb5760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff1615611beb5760405162461bcd60e51b81526004016107a8906151c8565b611bf58282612a70565b6001600160a01b0382166000908152600860205260408120805483908110611c1957fe5b600091825260208083206001600160a01b0380881685526007835260408086208887528452808620918a1686529252922060059091029091019150611c5e8484612aa7565b611c69848487612093565b15611c865760405162461bcd60e51b81526004016107a8906152e8565b805415611d0a576000611c998284612c84565b90508015611d0857611cab8284612fb4565b6001830155611cbb858783612c98565b83856001600160a01b0316876001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e9464584604051611cff91906150ae565b60405180910390a45b505b50506003805460ff60a01b1916600160a01b179055505050565b611d4560405180606001604052806033815260200161568c603391396129ce565b611d4f8383612a70565b600081118015611d6257506312cc030081105b611d7e5760405162461bcd60e51b81526004016107a890615398565b6001600160a01b0383166000908152600860205260408120805484908110611da257fe5b9060005260206000209060050201905060008160040154905082826004018190555083856001600160a01b03167f0bcf80c5060ccf99b7a993c57a94b232fc2c5c04bd74c7c7d174595fee6bc31f8386604051611e00929190615433565b60405180910390a35050505050565b6000611e1b8484612a70565b6001600160a01b0384166000908152600860205260408120805485908110611e3f57fe5b600091825260208083206001600160a01b03808a168086526007845260408087208b885285528087208a8416885285528087206003600590970290940195860154918752601285528087208b885290945283862054855494516370a0823160e01b8152959750929590949093611f16939216906370a0823190611ec6903090600401614f4c565b60206040518083038186803b158015611ede57600080fd5b505afa158015611ef2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b291908101906142db565b90506000611f2261264d565b6001600160a01b038a1660009081526006602052604090205460028701549192509082118015611f5157508215155b15611fe7576000611f6f8760020154846136ed90919063ffffffff16565b6001600160a01b038c1660009081526009602052604081205460018a01549293509091611fb791906116a690611fab868863ffffffff61367116565b9063ffffffff61367116565b9050611fe2611fd5866116a68464e8d4a5100063ffffffff61367116565b879063ffffffff612f7216565b955050505b6001600160a01b03808b166000908152600a602090815260408083208d84528252808320938c16835292905290812090612020826131a3565b91505061204f87600101546116b264e8d4a510006116a68a611fab878e600001546136ed90919063ffffffff16565b9c9b505050505050505050505050565b6000546001600160a01b031633146120895760405162461bcd60e51b81526004016107a890615368565b611ae78282613786565b6001600160a01b038084166000908152600a60209081526040808320868452825280832093851683529290529081206120cb816131a3565b5095945050505050565b6017546001600160a01b031681565b6047546001600160a01b031690565b6001600160a01b03811660009081526011602052604081205463ffffffff168061211e576000610827565b6001600160a01b0383166000908152601060209081526040808320600019850163ffffffff168452909152902054600160201b90046001600160601b03169392505050565b6121846040518060600160405280603081526020016156eb603091396129ce565b60048054604051633d6ac5b360e21b81526001600160a01b039091169163f5ab16cc916121b391869101614f4c565b60206040518083038186803b1580156121cb57600080fd5b505afa1580156121df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612203919081019061425f565b61221f5760405162461bcd60e51b81526004016107a890615358565b61222882613751565b6001600160a01b0382166000818152600660205260409081902080549084905590519091907fad96cee0d692f0250b98e085504f399da6733854908215f6203fe3c69366d9f59061227c9084908690615433565b60405180910390a2505050565b60606122958484612a70565b6001600160a01b038085166000908152600a602090815260408083208784528252808320938616835292815282822080548451818402810184019095528085529092909184015b828210156123365760008481526020908190206040805160608101825260028602909201805483526001908101546001600160801b0380821685870152600160801b909104169183019190915290835290920191016122dc565b5050505090509392505050565b60146020526000908152604090205460ff1681565b60135460ff161561237b5760405162461bcd60e51b81526004016107a8906151c8565b600060405161238990614f36565b604080519182900382208282019091526008825267161594d5985d5b1d60c21b6020909201919091527fddfcc46608a8bd52ebf900f03a24cc97b73a6046cec8c5d0f74a211e376e967a6123db613835565b306040516020016123ef94939291906150ca565b604051602081830303815290604052805190602001209050600060405161241590614f41565b604051908190038120612430918a908a908a906020016150bc565b6040516020818303038152906040528051906020012090506000828260405160200161245d929190614f05565b604051602081830303815290604052805190602001209050600061248382888888613839565b6001600160a01b0381166000908152600e6020526040902080546001810190915590915089146124c55760405162461bcd60e51b81526004016107a890615238565b874211156124e55760405162461bcd60e51b81526004016107a890615218565b6124ef818b6134b0565b505050505b505050505050565b607a5460ff1681565b60066020526000908152604090205481565b6001600160a01b031660009081526008602052604090205490565b6000546001600160a01b0316331461255c5760405162461bcd60e51b81526004016107a890615368565b6001600160a01b0383166125825760405162461bcd60e51b81526004016107a890615228565b6001600160a01b0382166125a85760405162461bcd60e51b81526004016107a8906152c8565b6125b28282612a70565b6016546017546018546040516001600160a01b03808816948116937f8def9436d6e31b89ed00948ba91d0cb6936eada5154cb1b45b55683fb9e492379361260193919092169188918890615024565b60405180910390a3601680546001600160a01b039485166001600160a01b0319918216179091556017805493909416921691909117909155601855565b6003546001600160a01b031681565b607a5460009060ff1661266757612662613863565b61266f565b61266f613867565b905090565b6301e1338081565b60405161104a90614f41565b60185481565b601060209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b6312cc030081565b6000546001600160a01b031681565b6126fb6040518060600160405280602c815260200161571b602c91396129ce565b6127048561353f565b61270d8361353f565b6004546001600160a01b03166127355760405162461bcd60e51b81526004016107a8906151a8565b600084116127555760405162461bcd60e51b81526004016107a8906153a8565b61275e85613751565b6001600160a01b0385166000908152600860205260408120805490915b818110156127d957856001600160a01b031683828154811061279957fe5b60009182526020909120600590910201546001600160a01b031614156127d15760405162461bcd60e51b81526004016107a890615328565b60010161277b565b506001600160a01b03851660009081526014602052604090205460ff16156128135760405162461bcd60e51b81526004016107a890615298565b6001600160a01b03871660009081526009602052604090205461283c908763ffffffff612f7216565b6001600160a01b038089166000908152600960209081526040808320949094556006815290839020879055825160a081018452918816825281018890528391810161288561264d565b8152600060208083018290526040928301889052845460018082018755958352818320855160059092020180546001600160a01b0319166001600160a01b039283161781558583015181880155858501516002820155606086015160038201556080909501516004958601558a81168352601490915290829020805460ff1916851790558254915163fb66fb4d60e01b815291169263fb66fb4d9261292d928c929101615059565b600060405180830381600087803b15801561294757600080fd5b505af115801561295b573d6000803e3d6000fd5b50505050846001600160a01b03166001838054905003886001600160a01b03167fd7fa4bff1cd2253c0789c3291a786a6f6b1a3b4569a75af683a15d52abb6a0bf8988886040516129ae93929190615441565b60405180910390a450505050505050565b6016546001600160a01b031681565b6047546040516318c5e8ab60e01b81526000916001600160a01b0316906318c5e8ab90612a019033908690600401614f68565b60206040518083038186803b158015612a1957600080fd5b505afa158015612a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a51919081019061425f565b905080611ae75760405162461bcd60e51b81526004016107a8906151e8565b6001600160a01b0382166000908152600860205260409020548110611ae75760405162461bcd60e51b81526004016107a890615198565b6001600160a01b0382166000908152600860205260408120805483908110612acb57fe5b906000526020600020906005020190508060020154612ae861264d565b11612af35750611ae7565b80546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612b23903090600401614f4c565b60206040518083038186803b158015612b3b57600080fd5b505afa158015612b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612b7391908101906142db565b6001600160a01b0385166000908152601260209081526040808320878452909152902054909150612bab90829063ffffffff6136ed16565b905080612bc957612bba61264d565b82600201819055505050611ae7565b6000612bd361264d565b90506000612bee8460020154836136ed90919063ffffffff16565b6001600160a01b03871660009081526009602090815260408083205460018901546006909352908320549394509192612c3792916116a691611fab90879063ffffffff61367116565b9050612c66612c55856116a68464e8d4a5100063ffffffff61367116565b60038701549063ffffffff612f7216565b6003860155612c7361264d565b856002018190555050505050505050565b600061082783600101546116b28585612fb4565b600480546040516370a0823160e01b81526001600160a01b03918216926000928716916370a0823191612ccd91869101614f4c565b60206040518083038186803b158015612ce557600080fd5b505afa158015612cf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d1d91908101906142db565b6001600160a01b038087166000908152601560209081526040808320938916835292905290812054919250612d58858363ffffffff612f7216565b9050828111612e36578115612dcb576001600160a01b038088166000818152601560209081526040808320948b1680845294909152808220829055517f6bdfd5e51d01475945224d3d37965916fd8df699ef9e8888af4359aa8622216091612dc291879190615418565b60405180910390a35b60405163135b33cd60e31b81526001600160a01b03851690639ad99e6890612dfb908a908a908690600401615009565b600060405180830381600087803b158015612e1557600080fd5b505af1158015612e29573d6000803e3d6000fd5b5050505050505050612f0c565b6001600160a01b038088166000818152601560209081526040808320948b168084529490915290819020868503908190559051909291907f6bdfd5e51d01475945224d3d37965916fd8df699ef9e8888af4359aa8622216090612e9c9087908690615433565b60405180910390a360405163135b33cd60e31b81526001600160a01b03861690639ad99e6890612ed4908b908b908990600401615009565b600060405180830381600087803b158015612eee57600080fd5b505af1158015612f02573d6000803e3d6000fd5b5050505050505050505b505050565b604051612f6c9085906323b872dd60e01b90612f3590879087908790602401615009565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261386b565b50505050565b600061082783836040518060400160405280601b81526020017f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815250613950565b600061082764e8d4a510006116a68460030154611fab876002015488600001546136ed90919063ffffffff16565b600081600160601b84106130095760405162461bcd60e51b81526004016107a89190615167565b509192915050565b816001600160a01b0316836001600160a01b03161415801561303c57506000816001600160601b0316115b15612f0c576001600160a01b038316156130f4576001600160a01b03831660009081526011602052604081205463ffffffff16908161307c5760006130bb565b6001600160a01b0385166000908152601060209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006130e282856040518060600160405280602c81526020016156bf602c9139613980565b90506130f0868484846139bf565b5050505b6001600160a01b03821615612f0c576001600160a01b03821660009081526011602052604081205463ffffffff16908161312f57600061316e565b6001600160a01b0384166000908152601060209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061319582856040518060600160405280602b81526020016155ab602b9139613b7b565b90506124f4858484846139bf565b805460009081905b8015613241578360018203815481106131c057fe5b6000918252602090912060016002909202018101546001600160801b03600160801b9091041614156132235761321c8460018303815481106131fe57fe5b6000918252602090912060029091020154839063ffffffff612f7216565b9150613238565b6132358460018303815481106112c157fe5b92505b600019016131ab565b50915091565b8254604080516060810182526000808252602080830182815260019484018581528587018a5589845291909220925160028602909301928355905191909201805492516001600160801b03908116600160801b029281166001600160801b0319909416939093179092161790555b6000811180156132f05750818460018303815481106132d057fe5b60009182526020909120600160029092020101546001600160801b031611155b156133775783600182038154811061330457fe5b906000526020600020906002020184828154811061331e57fe5b600091825260209091208254600290920201908155600191820180549290910180546001600160801b0319166001600160801b03938416178082559154600160801b9081900484160291909216179055600019016132b5565b604051806060016040528084815260200161339184613bae565b6001600160801b0316815260200160016001600160801b03168152508482815481106133b957fe5b60009182526020918290208351600292830290910190815591830151600190920180546040909401516001600160801b03199094166001600160801b03938416178316600160801b939094169290920292909217905585015461341c9084612f72565b85600201819055505050505050565b6001600160a01b0381166134515760405162461bcd60e51b81526004016107a890615278565b604780546001600160a01b038381166001600160a01b03198316179092556040519116907f66fd58e82f7b31a2a5c30e0888f3093efe4e111b00cd2b0c31fe014601293aa0906134a49083908590614f88565b60405180910390a15050565b6001600160a01b038083166000908152600f6020526040812054909116906134d784613bd7565b6001600160a01b038581166000818152600f602052604080822080546001600160a01b031916898616908117909155905194955093928616927f0cc323ffec3ea49cbcddc0de1480978126d350c6a45dff33ad2f1cda6ae992619190a4612f6c828483613011565b6001600160a01b038116610f0a5760405162461bcd60e51b81526004016107a8906152d8565b60010154426001600160801b03909116111590565b805460009081905b60008111801561359f575061359f84600183038154811061129757fe5b15613640578360018203815481106135b357fe5b6000918252602090912060016002909202018101546001600160801b03600160801b9091041614156135f8576135f18460018303815481106131fe57fe5b915061360d565b61360a8460018303815481106112c157fe5b92505b8380548061361757fe5b600082815260208120600019928301600281029091018281556001019190915590915501613582565b50613665613654828463ffffffff612f7216565b60028601549063ffffffff6136ed16565b60028501559250929050565b60008261368057506000611524565b8282028284828161368d57fe5b04146108275760405162461bcd60e51b81526004016107a890615318565b600061082783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ced565b600061082783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613d24565b604051612f0c90849063a9059cbb60e01b90612f359086908690602401615074565b6001600160a01b038116600090815260086020526040812054905b81811015612f0c5761377e8382612aa7565b60010161376c565b607a54610100900460ff16156137ae5760405162461bcd60e51b81526004016107a8906153b8565b811580156137ba575080155b156137d75760405162461bcd60e51b81526004016107a890615338565b8180156137e357508015155b156138005760405162461bcd60e51b81526004016107a890615258565b607a805460ff191683151517905581613819578061381f565b6301e133805b6079555050607a805461ff001916610100179055565b4690565b600080600061384a87878787613d48565b9150915061385781613e28565b5090505b949350505050565b4390565b4290565b61387d826001600160a01b0316613ef1565b6138995760405162461bcd60e51b81526004016107a8906153d8565b60006060836001600160a01b0316836040516138b59190614ef9565b6000604051808303816000865af19150503d80600081146138f2576040519150601f19603f3d011682016040523d82523d6000602084013e6138f7565b606091505b5091509150816139195760405162461bcd60e51b81526004016107a8906153c8565b805115612f6c5780806020019051613934919081019061425f565b612f6c5760405162461bcd60e51b81526004016107a890615208565b600083830182858210156139775760405162461bcd60e51b81526004016107a89190615167565b50949350505050565b6000836001600160601b0316836001600160601b0316111582906139b75760405162461bcd60e51b81526004016107a89190615167565b505050900390565b60006139ea6139cc61264d565b60405180608001604052806042815260200161564a60429139613f2a565b905060008463ffffffff16118015613a3357506001600160a01b038516600090815260106020908152604080832063ffffffff6000198901811685529252909120548282169116145b15613a92576001600160a01b0385166000908152601060209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b03851602179055613b31565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152601083528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252601190935292909220805460018801909316929091169190911790555b846001600160a01b03167f6adb589fed1e8542fb7a6b10f00a85e02265e77f9ae3ca8ff93b22983e1af9a08484604051613b6c929190615493565b60405180910390a25050505050565b6000838301826001600160601b0380871690831610156139775760405162461bcd60e51b81526004016107a89190615167565b6000600160801b8210613bd35760405162461bcd60e51b81526004016107a890615248565b5090565b6005546000906001600160a01b0316613c025760405162461bcd60e51b81526004016107a8906151f8565b6005546001600160a01b03166000908152600860205260408120805490915b81811015613ce25760055483546001600160a01b0390911690849083908110613c4657fe5b60009182526020909120600590910201546001600160a01b03161415613cda576005546001600160a01b039081166000908152600760209081526040808320858452825280832093891683529290522060028101548154613ccf91613cb1919063ffffffff6136ed16565b60405180606001604052806028815260200161560160289139612fe2565b94505050505061108d565b600101613c21565b506000949350505050565b60008183613d0e5760405162461bcd60e51b81526004016107a89190615167565b506000838581613d1a57fe5b0495945050505050565b600081848411156139b75760405162461bcd60e51b81526004016107a89190615167565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613d7f5750600090506003613e1f565b8460ff16601b14158015613d9757508460ff16601c14155b15613da85750600090506004613e1f565b600060018787878760405160008152602001604052604051613dcd94939291906150f2565b6020604051602081039080840390855afa158015613def573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613e1857506000915060019050613e1f565b9150600090505b94509492505050565b6000816004811115613e3657fe5b1415613e4157610f0a565b6001816004811115613e4f57fe5b1415613e6d5760405162461bcd60e51b81526004016107a890615178565b6002816004811115613e7b57fe5b1415613e995760405162461bcd60e51b81526004016107a8906151b8565b6003816004811115613ea757fe5b1415613ec55760405162461bcd60e51b81526004016107a890615288565b6004816004811115613ed357fe5b1415610f0a5760405162461bcd60e51b81526004016107a8906152f8565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061385b575050151592915050565b600081600160201b84106130095760405162461bcd60e51b81526004016107a89190615167565b604080518082019091526000808252602082015290565b803561152481615569565b805161152481615569565b80356115248161557d565b80516115248161557d565b803561152481615586565b80356115248161558f565b805161152481615586565b803561152481615598565b8035611524816155a1565b600060208284031215613fdd57600080fd5b600061385b8484613f68565b600060208284031215613ffb57600080fd5b600061385b8484613f73565b6000806040838503121561401a57600080fd5b60006140268585613f68565b925050602061403785828601613f68565b9150509250929050565b60008060006060848603121561405657600080fd5b60006140628686613f68565b935050602061407386828701613f68565b925050604061408486828701613f94565b9150509250925092565b600080604083850312156140a157600080fd5b60006140ad8585613f68565b925050602061403785828601613f94565b6000806000606084860312156140d357600080fd5b60006140df8686613f68565b93505060206140f086828701613f94565b925050604061408486828701613f68565b600080600080600060a0868803121561411957600080fd5b60006141258888613f68565b955050602061413688828901613f94565b945050604061414788828901613f9f565b935050606061415888828901613f94565b925050608061416988828901613f94565b9150509295509295909350565b60008060006060848603121561418b57600080fd5b60006141978686613f68565b935050602061407386828701613f94565b60008060008060008060c087890312156141c157600080fd5b60006141cd8989613f68565b96505060206141de89828a01613f94565b95505060406141ef89828a01613f94565b945050606061420089828a01613fc0565b935050608061421189828a01613f94565b92505060a061422289828a01613f94565b9150509295509295509295565b6000806040838503121561424257600080fd5b600061424e8585613f68565b925050602061403785828601613fb5565b60006020828403121561427157600080fd5b600061385b8484613f89565b6000806040838503121561429057600080fd5b60006140ad8585613f7e565b6000806000606084860312156142b157600080fd5b60006140628686613f9f565b6000602082840312156142cf57600080fd5b600061385b8484613f9f565b6000602082840312156142ed57600080fd5b600061385b8484613faa565b60006143058383614e99565b505060600190565b61431681615512565b82525050565b614316816154c1565b6000614330826154b4565b61433a81856154b8565b9350614345836154ae565b8060005b8381101561437357815161435d88826142f9565b9750614368836154ae565b925050600101614349565b509495945050505050565b614316816154cc565b614316816154d1565b61431661439c826154d1565b6154d1565b60006143ac826154b4565b6143b6818561108d565b93506143c6818560208601615533565b9290920192915050565b614316816154d4565b6143168161551d565b60006143ed826154b4565b6143f781856154b8565b9350614407818560208601615533565b6144108161555f565b9093019392505050565b60006144276018836154b8565b7f45434453413a20696e76616c6964207369676e61747572650000000000000000815260200192915050565b60006144606012836154b8565b71696e636f6e73697374656e7420737461746560701b815260200192915050565b600061448e6013836154b8565b727661756c743a20706f6f6c206578697374733f60681b815260200192915050565b60006144bd601f836154b8565b7f53746f726520636f6e7472616374206164647265737320697320656d70747900815260200192915050565b60006144f6601f836154b8565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800815260200192915050565b600061452f600f836154b8565b6e15985d5b1d081a5cc81c185d5cd959608a1b815260200192915050565b600061455a6013836154b8565b7215985d5b1d081a5cc81b9bdd081c185d5cd959606a1b815260200192915050565b6000614589600c836154b8565b6b155b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145b16030836154b8565b7f5856535661756c743a3a6765745374616b65416d6f756e743a2078767320616481526f191c995cdcc81a5cc81b9bdd081cd95d60821b602082015260400192915050565b6000614603602a836154b8565b7f5361666542455032303a204245503230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061464f602a836154b8565b7f5856535661756c743a3a64656c656761746542795369673a207369676e6174758152691c9948195e1c1a5c995960b21b602082015260400192915050565b600061469b6022836154b8565b7f7072696d6520746f6b656e2063616e6e6f74206265207a65726f206164647265815261737360f01b602082015260400192915050565b60006146df6026836154b8565b7f5856535661756c743a3a64656c656761746542795369673a20696e76616c6964815265206e6f6e636560d01b602082015260400192915050565b600061472760028361108d565b61190160f01b815260020192915050565b60006147456027836154b8565b7f53616665436173743a2076616c756520646f65736e27742066697420696e20318152663238206269747360c81b602082015260400192915050565b600061478e6020836154b8565b7f496e76616c69642074696d6520626173656420636f6e66696775726174696f6e815260200192915050565b60006147c76017836154b8565b7f5661756c7420697320616c726561647920706175736564000000000000000000815260200192915050565b60006148006025836154b8565b7f696e76616c696420616365737320636f6e74726f6c206d616e61676572206164815264647265737360d81b602082015260400192915050565b60006148476022836154b8565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b602082015260400192915050565b600061488b601a836154b8565b7f546f6b656e2065786973747320696e206f7468657220706f6f6c000000000000815260200192915050565b60006148c46013836154b8565b72185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b815260200192915050565b60006148f3602b836154b8565b7f5856535661756c743a3a6765745072696f72566f7465733a206e6f742079657481526a0819195d195c9b5a5b995960aa1b602082015260400192915050565b6000614940601d836154b8565b7f7265776172642063616e6e6f74206265207a65726f2061646472657373000000815260200192915050565b60006149796018836154b8565b7f7a65726f2061646472657373206e6f7420616c6c6f7765640000000000000000815260200192915050565b60006149b2601a836154b8565b7f657865637574652070656e64696e67207769746864726177616c000000000000815260200192915050565b60006149eb6022836154b8565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b602082015260400192915050565b6000614a2f60438361108d565b7f454950373132446f6d61696e28737472696e67206e616d652c75696e7432353681527f20636861696e49642c6164647265737320766572696679696e67436f6e74726160208201526263742960e81b604082015260430192915050565b6000614a9a601f836154b8565b7f72657175657374656420616d6f756e742063616e6e6f74206265207a65726f00815260200192915050565b6000614ad36021836154b8565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614b166012836154b8565b71141bdbdb08185b1c9958591e48185919195960721b815260200192915050565b6000614b446017836154b8565b7f496e76616c696420626c6f636b73207065722079656172000000000000000000815260200192915050565b6000614b7d600a836154b8565b691c994b595b9d195c995960b21b815260200192915050565b6000614ba36014836154b8565b7324b73b30b634b2103932bbb0b932103a37b5b2b760611b815260200192915050565b6000614bd3600e836154b8565b6d37b7363c9030b236b4b71031b0b760911b815260200192915050565b6000614bfd6015836154b8565b7418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b815260200192915050565b6000614c2e6013836154b8565b726e6f7468696e6720746f20776974686472617760681b815260200192915050565b6000614c5d601a836154b8565b7f496e76616c6964206e6577206c6f636b696e6720706572696f64000000000000815260200192915050565b6000614c96601d836154b8565b7f416c6c6f6320706f696e7473206d757374206e6f74206265207a65726f000000815260200192915050565b6000614ccf601f836154b8565b7f416c726561647920696e697469616c697a65642054696d654d616e6167657200815260200192915050565b6000614d086020836154b8565b7f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000614d41603a8361108d565b7f44656c65676174696f6e28616464726573732064656c6567617465652c75696e81527f74323536206e6f6e63652c75696e7432353620657870697279290000000000006020820152603a0192915050565b6000614da0601f836154b8565b7f5361666542455032303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b6000614dd9601b836154b8565b7f72657175657374656420616d6f756e7420697320696e76616c69640000000000815260200192915050565b6000614e126022836154b8565b7f6f6e6c792070726f78792061646d696e2063616e206368616e676520627261698152616e7360f01b602082015260400192915050565b6000614e56602e836154b8565b7f416c6c6f6320706f696e7473207065722072657761726420746f6b656e206d7581526d7374206e6f74206265207a65726f60901b602082015260400192915050565b80516060830190614eaa8482614387565b506020820151614ebd6020850182614ecc565b506040820151612f6c60408501825b614316816154df565b614316816154f7565b61431681615500565b61431681615528565b61431681615506565b600061082782846143a1565b6000614f108261471a565b9150614f1c8285614390565b602082019150614f2c8284614390565b5060200192915050565b600061152482614a22565b600061152482614d34565b60208101611524828461431c565b60208101611524828461430d565b60408101614f76828561430d565b818103602083015261385b81846143e2565b60408101614f96828561431c565b610827602083018461431c565b60608101614fb1828661431c565b614fbe602083018561430d565b61385b6040830184614387565b60808101614fd9828761431c565b614fe6602083018661431c565b614ff3604083018561431c565b615000606083018461431c565b95945050505050565b60608101615017828661431c565b614fbe602083018561431c565b60808101615032828761431c565b61503f602083018661431c565b61504c6040830185614387565b6150006060830184614387565b60408101615067828561431c565b610827602083018461437e565b60408101615082828561431c565b6108276020830184614387565b602080825281016108278184614325565b60208101611524828461437e565b602081016115248284614387565b608081016150328287614387565b608081016150d88287614387565b6150e56020830186614387565b614ff36040830185614387565b608081016151008287614387565b61503f6020830186614ede565b6020810161152482846143d0565b60a0810161512982886143d0565b6151366020830187614387565b6151436040830186614387565b6151506060830185614387565b61515d6080830184614387565b9695505050505050565b6020808252810161082781846143e2565b602080825281016115248161441a565b6020808252810161152481614453565b6020808252810161152481614481565b60208082528101611524816144b0565b60208082528101611524816144e9565b6020808252810161152481614522565b602080825281016115248161454d565b602080825281016115248161457c565b60208082528101611524816145a4565b60208082528101611524816145f6565b6020808252810161152481614642565b602080825281016115248161468e565b60208082528101611524816146d2565b6020808252810161152481614738565b6020808252810161152481614781565b60208082528101611524816147ba565b60208082528101611524816147f3565b602080825281016115248161483a565b602080825281016115248161487e565b60208082528101611524816148b7565b60208082528101611524816148e6565b6020808252810161152481614933565b602080825281016115248161496c565b60208082528101611524816149a5565b60208082528101611524816149de565b6020808252810161152481614a8d565b6020808252810161152481614ac6565b6020808252810161152481614b09565b6020808252810161152481614b37565b6020808252810161152481614b70565b6020808252810161152481614b96565b6020808252810161152481614bc6565b6020808252810161152481614bf0565b6020808252810161152481614c21565b6020808252810161152481614c50565b6020808252810161152481614c89565b6020808252810161152481614cc2565b6020808252810161152481614cfb565b6020808252810161152481614d93565b6020808252810161152481614dcc565b6020808252810161152481614e05565b6020808252810161152481614e49565b604081016154268285614387565b61082760208301846143d9565b604081016150828285614387565b6060810161544f8286614387565b614fbe6020830185614387565b602081016115248284614ed5565b604081016154788285614ed5565b6108276020830184614ef0565b602081016115248284614ef0565b604081016154a18285614ee7565b6108276020830184614ee7565b60200190565b5190565b90815260200190565b6000611524826154eb565b151590565b90565b6000611524826154c1565b6001600160801b031690565b6001600160a01b031690565b63ffffffff1690565b60ff1690565b6001600160601b031690565b6000611524826154d4565b6000611524826154d1565b600061152482615506565b60005b8381101561554e578181015183820152602001615536565b83811115612f6c5750506000910152565b601f01601f191690565b615572816154c1565b8114610f0a57600080fd5b615572816154cc565b615572816154d1565b615572816154d4565b615572816154f7565b6155728161550056fe5856535661756c743a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f77735856535661756c743a3a726571756573745769746864726177616c3a20766f746573206f766572666c6f775856535661756c743a3a6765745374616b65416d6f756e743a20766f746573206f766572666c6f775856535661756c743a3a6465706f7369743a20766f746573206f766572666c6f775856535661756c743a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d626572206f72207365636f6e64206578636565647320333220626974737365745769746864726177616c4c6f636b696e67506572696f6428616464726573732c75696e743235362c75696e74323536295856535661756c743a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773736574526577617264416d6f756e74506572426c6f636b4f725365636f6e6428616464726573732c75696e743235362961646428616464726573732c75696e743235362c616464726573732c75696e743235362c75696e7432353629a365627a7a7231582053ba350123a86f07263e7bddf3bcee0f7cf11e72f5d2678781f0eb1ebd599dc16c6578706572696d656e74616cf564736f6c63430005100040

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106103785760003560e01c806392e35000116101d3578063c7ad089511610104578063e7a324dc116100a2578063f55401621161007c578063f554016214610732578063f851a4401461073a578063fba1b1f914610742578063fe5a451a1461075557610378565b8063e7a324dc14610701578063e8f2be6f14610709578063f1127ed81461071157610378565b8063dae66bbe116100de578063dae66bbe146106d6578063de0368b2146106e9578063e1d146fb146106f1578063e6a69ab8146106f957610378565b8063c7ad0895146106a8578063cd9b94e7146106b0578063d7ae45e2146106c357610378565b8063add8933711610171578063b6a5fd2f1161014b578063b6a5fd2f1461064f578063c210259614610662578063c3c754a814610682578063c3cda5201461069557610378565b8063add893371461061f578063b4a0bdf314610627578063b4b5ea571461063c57610378565b80639e2b6c4d116101ad5780639e2b6c4d146105d3578063a09eab7a146105e6578063a6997762146105f9578063a9d69a691461060c57610378565b806392e350001461057a57806398e1b31b1461059e578063996cba68146105c057610378565b80635c19a95c116102ad57806373d025d61161024b5780637ecebe00116102255780637ecebe00146105395780638308d7e91461054c5780638456cb591461055f5780638ed7333d1461056757610378565b806373d025d6146104f1578063782d6fe1146105065780637ac924561461052657610378565b80635ff56315116102875780635ff56315146104a35780636857249c146104b65780636dd77cbd146104be5780636fcfff45146104d157610378565b80635c19a95c146104755780635c60da1b146104885780635f14e7001461049057610378565b806324f52bbf1161031a578063358ae036116102f4578063358ae036146104345780633d4180f91461043c5780634298bdbd1461044f578063587cde1e1461046257610378565b806324f52bbf1461040457806326782247146104195780632eda5c6c1461042157610378565b8063115b512f11610356578063115b512f146103c357806319129e5a146103d65780631d504dc6146103e957806320606b70146103fc57610378565b8063046f7da21461037d5780630af13728146103875780630efe6a8b146103b0575b600080fd5b61038561075d565b005b61039a6103953660046140be565b6107e8565b6040516103a791906150ae565b60405180910390f35b6103856103be366004614176565b61082e565b6103856103d1366004614176565b610b23565b6103856103e4366004613fcb565b610ed7565b6103856103f73660046142bd565b610f0d565b61039a61103e565b61040c611055565b6040516103a79190614f4c565b61040c611064565b61039a61042f366004613fcb565b611073565b61040c611092565b61039a61044a366004614007565b6110a1565b61039a61045d366004613fcb565b6110be565b61040c610470366004613fcb565b6110d0565b610385610483366004613fcb565b6110eb565b61040c611118565b61039a61049e36600461408e565b611127565b6103856104b1366004614007565b611144565b61039a611238565b61039a6104cc3660046140be565b61123e565b6104e46104df366004613fcb565b6112f3565b6040516103a7919061545c565b6104f961130b565b6040516103a791906150a0565b61051961051436600461408e565b611314565b6040516103a79190615485565b61038561053436600461408e565b61152a565b61039a610547366004613fcb565b611873565b61038561055a366004614176565b611885565b610385611a2b565b61038561057536600461408e565b611ab0565b61058d61058836600461408e565b611aeb565b6040516103a795949392919061511b565b6105b16105ac3660046140be565b611b40565b6040516103a793929190615441565b6103856105ce366004614041565b611b92565b6103856105e1366004614176565b611d24565b61039a6105f43660046140be565b611e0f565b61038561060736600461427d565b61205f565b61039a61061a3660046140be565b612093565b61040c6120d5565b61062f6120e4565b6040516103a7919061510d565b61051961064a366004613fcb565b6120f3565b61038561065d36600461408e565b612163565b6106756106703660046140be565b612289565b6040516103a7919061508f565b6104f9610690366004613fcb565b612343565b6103856106a33660046141a8565b612358565b6104f96124fc565b61039a6106be366004613fcb565b612505565b61039a6106d1366004613fcb565b612517565b6103856106e436600461429c565b612532565b61040c61263e565b61039a61264d565b61039a612674565b61039a61267c565b61039a612688565b61072461071f36600461422f565b61268e565b6040516103a792919061546a565b61039a6126c3565b61040c6126cb565b610385610750366004614101565b6126da565b61062f6129bf565b61078660405180604001604052806008815260200167726573756d65282960c01b8152506129ce565b60135460ff166107b15760405162461bcd60e51b81526004016107a8906151d8565b60405180910390fd5b6013805460ff1916905560405133907fd2619572a1464e0df0bb351d834fd47f3350984d7bfdb1ab69cfcb0b8e42141590600090a2565b60006107f48484612a70565b506001600160a01b0380841660009081526007602090815260408083208684528252808320938516835292905220600201545b9392505050565b600354600160a01b900460ff166108575760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff16156108875760405162461bcd60e51b81526004016107a8906151c8565b6108918383612a70565b6001600160a01b03831660009081526008602052604081208054849081106108b557fe5b600091825260208083206001600160a01b038816845260078252604080852088865283528085203386529092529220600590910290910191506108f88585612aa7565b610903858533612093565b156109205760405162461bcd60e51b81526004016107a8906152e8565b8054156109955760006109338284612c84565b9050801561099357610946863383612c98565b84866001600160a01b0316336001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e946458460405161098a91906150ae565b60405180910390a45b505b81546109b2906001600160a01b031633308663ffffffff612f1116565b80546109c4908463ffffffff612f7216565b81556109d08183612fb4565b600182015560055482546001600160a01b0390811691161415610a3757336000908152600f60209081526040808320548151606081019092526021808352610a3794936001600160a01b0390921692610a329289929061562990830139612fe2565b613011565b6017546001600160a01b038681169116148015610a55575060185484145b15610abd576016546040516337f23cd360e01b81526001600160a01b03909116906337f23cd390610a8a903390600401614f5a565b600060405180830381600087803b158015610aa457600080fd5b505af1158015610ab8573d6000803e3d6000fd5b505050505b83856001600160a01b0316336001600160a01b03167fdcbc1c05240f31ff3ad067ef1ee35ce4997762752e3a095284754544f4c709d786604051610b0191906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b179055505050565b600354600160a01b900460ff16610b4c5760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff1615610b7c5760405162461bcd60e51b81526004016107a8906151c8565b610b868383612a70565b60008111610ba65760405162461bcd60e51b81526004016107a890615308565b6001600160a01b0383166000908152600760209081526040808320858452825280832033845290915290206002810154610be6908363ffffffff612f7216565b81541015610c065760405162461bcd60e51b81526004016107a8906153e8565b6001600160a01b0384166000908152600860205260408120805485908110610c2a57fe5b600091825260208083206001600160a01b0389168452600a825260408085208986528352808520338652909252908320600590920201925090610c6c826131a3565b5090508015610c8d5760405162461bcd60e51b81526004016107a8906152e8565b610c978787612aa7565b6000610ca38585612c84565b9050610cb0883383612c98565b6004840154600090610cc8904263ffffffff612f7216565b9050610cd686858984613247565b6001600160a01b03891660009081526012602090815260408083208b8452909152902054610d0a908863ffffffff612f7216565b6001600160a01b038a1660009081526012602090815260408083208c8452909152902055610d388686612fb4565b600187015560055485546001600160a01b0390811691161415610d9b57336000908152600f6020908152604080832054815160608101909252602b808352610d9b946001600160a01b03909216939192610a32928d92906155d690830139612fe2565b6017546001600160a01b038a81169116148015610db9575060185488145b15610e21576016546040516337f23cd360e01b81526001600160a01b03909116906337f23cd390610dee903390600401614f5a565b600060405180830381600087803b158015610e0857600080fd5b505af1158015610e1c573d6000803e3d6000fd5b505050505b87896001600160a01b0316336001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e9464585604051610e6591906150ae565b60405180910390a487896001600160a01b0316336001600160a01b03167f88a254a0ef28a0b9e957ff600beae69870f6f924065147f3627c3f814e60ec118a604051610eb191906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b17905550505050505050565b6000546001600160a01b03163314610f015760405162461bcd60e51b81526004016107a890615368565b610f0a8161342b565b50565b806001600160a01b031663f851a4406040518163ffffffff1660e01b815260040160206040518083038186803b158015610f4657600080fd5b505afa158015610f5a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250610f7e9190810190613fe9565b6001600160a01b0316336001600160a01b031614610fae5760405162461bcd60e51b81526004016107a8906153f8565b806001600160a01b031663c1e803346040518163ffffffff1660e01b8152600401602060405180830381600087803b158015610fe957600080fd5b505af1158015610ffd573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525061102191908101906142db565b15610f0a5760405162461bcd60e51b81526004016107a890615378565b60405161104a90614f36565b604051809103902081565b6004546001600160a01b031681565b6001546001600160a01b031681565b6001600160a01b0381166000908152600660205260409020545b919050565b6005546001600160a01b031681565b601560209081526000928352604080842090915290825290205481565b60096020526000908152604090205481565b600f602052600090815260409020546001600160a01b031681565b60135460ff161561110e5760405162461bcd60e51b81526004016107a8906151c8565b610f0a33826134b0565b6002546001600160a01b031681565b601260209081526000928352604080842090915290825290205481565b6000546001600160a01b0316331461116e5760405162461bcd60e51b81526004016107a890615368565b6111778261353f565b6111808161353f565b6005546004546001600160a01b03918216911681156111b15760405162461bcd60e51b81526004016107a8906152a8565b600580546001600160a01b038087166001600160a01b03199283161790925560048054928616929091169190911790556003805460ff60a01b1916600160a01b1790556040517f559f314bb90394a4a9ceb724f365b36a53587d894352c43d12901fd6801014569061122a908490849088908890614fcb565b60405180910390a150505050565b60795481565b600061124a8484612a70565b6001600160a01b038085166000908152600a60209081526040808320878452825280832093861683529290522080545b6000811180156112aa57506112aa82600183038154811061129757fe5b9060005260206000209060020201613565565b156112ea576112df8260018303815481106112c157fe5b6000918252602090912060029091020154849063ffffffff612f7216565b92506000190161127a565b50509392505050565b60116020526000908152604090205463ffffffff1681565b60135460ff1681565b600061131e61264d565b821061133c5760405162461bcd60e51b81526004016107a8906152b8565b6001600160a01b03831660009081526011602052604090205463ffffffff168061136a576000915050611524565b6001600160a01b038416600090815260106020908152604080832063ffffffff6000198601811685529252909120541683106113e6576001600160a01b03841660009081526010602090815260408083206000199490940163ffffffff1683529290522054600160201b90046001600160601b03169050611524565b6001600160a01b038416600090815260106020908152604080832083805290915290205463ffffffff16831015611421576000915050611524565b600060001982015b8163ffffffff168163ffffffff1611156114e457600282820363ffffffff16048103611453613f51565b506001600160a01b038716600090815260106020908152604080832063ffffffff858116855290835292819020815180830190925254928316808252600160201b9093046001600160601b031691810191909152908714156114bf576020015194506115249350505050565b805163ffffffff168711156114d6578193506114dd565b6001820392505b5050611429565b506001600160a01b038516600090815260106020908152604080832063ffffffff909416835292905220546001600160601b03600160201b909104169150505b92915050565b600354600160a01b900460ff166115535760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff16156115835760405162461bcd60e51b81526004016107a8906151c8565b61158d8282612a70565b6001600160a01b03821660009081526008602052604081208054839081106115b157fe5b600091825260208083206001600160a01b038716808552600783526040808620888752845280862033808852908552818720928752600a8552818720898852855281872090875290935291842060059093020193509180611612848461357a565b9092509050811515806116255750600081115b6116415760405162461bcd60e51b81526004016107a890615388565b81158061164c575080155b6116685760405162461bcd60e51b81526004016107a890615188565b8115611781576116788787612aa7565b60006116be85600101546116b264e8d4a510006116a68a600301548a6000015461367190919063ffffffff16565b9063ffffffff6136ab16565b9063ffffffff6136ed16565b6004805460405163135b33cd60e31b81529293506001600160a01b031691639ad99e68916116f2918c913391879101614fa3565b600060405180830381600087803b15801561170c57600080fd5b505af1158015611720573d6000803e3d6000fd5b50508654611737925090508463ffffffff6136ed16565b808655600387015461175a9164e8d4a51000916116a6919063ffffffff61367116565b6001860155855461177b906001600160a01b0316338563ffffffff61372f16565b50611805565b8354611793908263ffffffff6136ed16565b84556001600160a01b03871660009081526012602090815260408083208984529091529020546117c9908263ffffffff6136ed16565b6001600160a01b0380891660009081526012602090815260408083208b845290915290209190915585546118059116338363ffffffff61372f16565b856001600160a01b038816337fe31da05fae6db869f5ea51f4b638aa6884070b6c87f18f63bd2291a12cb2f518611842868663ffffffff612f7216565b60405161184f91906150ae565b60405180910390a450506003805460ff60a01b1916600160a01b1790555050505050565b600e6020526000908152604090205481565b6118c36040518060400160405280601c81526020017f73657428616464726573732c75696e743235362c75696e7432353629000000008152506129ce565b6118cd8383612a70565b6118d683613751565b6001600160a01b0383166000908152600860205260408120805490919061194f9084906119439085908890811061190957fe5b60009182526020808320600160059093020191909101546001600160a01b038b16835260099091526040909120549063ffffffff6136ed16565b9063ffffffff612f7216565b9050600081116119715760405162461bcd60e51b81526004016107a890615408565b600082858154811061197f57fe5b9060005260206000209060050201600101549050838386815481106119a057fe5b9060005260206000209060050201600101819055508160096000886001600160a01b03166001600160a01b031681526020019081526020016000208190555084866001600160a01b03167f6ee09c6cb801194690c195c69f465aaf7c80255cbeafaab9600f47ed79de2ca98387604051611a1b929190615433565b60405180910390a3505050505050565b611a53604051806040016040528060078152602001667061757365282960c81b8152506129ce565b60135460ff1615611a765760405162461bcd60e51b81526004016107a890615268565b6013805460ff1916600117905560405133907fdffada2889ebfab9224c24069d833f3de835d8cf99872d49e7b7ba5fccb7a46f90600090a2565b60135460ff1615611ad35760405162461bcd60e51b81526004016107a8906151c8565b611add8282612a70565b611ae78282612aa7565b5050565b60086020528160005260406000208181548110611b0457fe5b6000918252602090912060059091020180546001820154600283015460038401546004909401546001600160a01b039093169550909350919085565b6000806000611b4f8686612a70565b5050506001600160a01b03928316600090815260076020908152604080832094835293815283822092909416815292529020805460018201546002909201549092565b600354600160a01b900460ff16611bbb5760405162461bcd60e51b81526004016107a890615348565b6003805460ff60a01b1916905560135460ff1615611beb5760405162461bcd60e51b81526004016107a8906151c8565b611bf58282612a70565b6001600160a01b0382166000908152600860205260408120805483908110611c1957fe5b600091825260208083206001600160a01b0380881685526007835260408086208887528452808620918a1686529252922060059091029091019150611c5e8484612aa7565b611c69848487612093565b15611c865760405162461bcd60e51b81526004016107a8906152e8565b805415611d0a576000611c998284612c84565b90508015611d0857611cab8284612fb4565b6001830155611cbb858783612c98565b83856001600160a01b0316876001600160a01b03167f865ca08d59f5cb456e85cd2f7ef63664ea4f73327414e9d8152c4158b0e9464584604051611cff91906150ae565b60405180910390a45b505b50506003805460ff60a01b1916600160a01b179055505050565b611d4560405180606001604052806033815260200161568c603391396129ce565b611d4f8383612a70565b600081118015611d6257506312cc030081105b611d7e5760405162461bcd60e51b81526004016107a890615398565b6001600160a01b0383166000908152600860205260408120805484908110611da257fe5b9060005260206000209060050201905060008160040154905082826004018190555083856001600160a01b03167f0bcf80c5060ccf99b7a993c57a94b232fc2c5c04bd74c7c7d174595fee6bc31f8386604051611e00929190615433565b60405180910390a35050505050565b6000611e1b8484612a70565b6001600160a01b0384166000908152600860205260408120805485908110611e3f57fe5b600091825260208083206001600160a01b03808a168086526007845260408087208b885285528087208a8416885285528087206003600590970290940195860154918752601285528087208b885290945283862054855494516370a0823160e01b8152959750929590949093611f16939216906370a0823190611ec6903090600401614f4c565b60206040518083038186803b158015611ede57600080fd5b505afa158015611ef2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052506116b291908101906142db565b90506000611f2261264d565b6001600160a01b038a1660009081526006602052604090205460028701549192509082118015611f5157508215155b15611fe7576000611f6f8760020154846136ed90919063ffffffff16565b6001600160a01b038c1660009081526009602052604081205460018a01549293509091611fb791906116a690611fab868863ffffffff61367116565b9063ffffffff61367116565b9050611fe2611fd5866116a68464e8d4a5100063ffffffff61367116565b879063ffffffff612f7216565b955050505b6001600160a01b03808b166000908152600a602090815260408083208d84528252808320938c16835292905290812090612020826131a3565b91505061204f87600101546116b264e8d4a510006116a68a611fab878e600001546136ed90919063ffffffff16565b9c9b505050505050505050505050565b6000546001600160a01b031633146120895760405162461bcd60e51b81526004016107a890615368565b611ae78282613786565b6001600160a01b038084166000908152600a60209081526040808320868452825280832093851683529290529081206120cb816131a3565b5095945050505050565b6017546001600160a01b031681565b6047546001600160a01b031690565b6001600160a01b03811660009081526011602052604081205463ffffffff168061211e576000610827565b6001600160a01b0383166000908152601060209081526040808320600019850163ffffffff168452909152902054600160201b90046001600160601b03169392505050565b6121846040518060600160405280603081526020016156eb603091396129ce565b60048054604051633d6ac5b360e21b81526001600160a01b039091169163f5ab16cc916121b391869101614f4c565b60206040518083038186803b1580156121cb57600080fd5b505afa1580156121df573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612203919081019061425f565b61221f5760405162461bcd60e51b81526004016107a890615358565b61222882613751565b6001600160a01b0382166000818152600660205260409081902080549084905590519091907fad96cee0d692f0250b98e085504f399da6733854908215f6203fe3c69366d9f59061227c9084908690615433565b60405180910390a2505050565b60606122958484612a70565b6001600160a01b038085166000908152600a602090815260408083208784528252808320938616835292815282822080548451818402810184019095528085529092909184015b828210156123365760008481526020908190206040805160608101825260028602909201805483526001908101546001600160801b0380821685870152600160801b909104169183019190915290835290920191016122dc565b5050505090509392505050565b60146020526000908152604090205460ff1681565b60135460ff161561237b5760405162461bcd60e51b81526004016107a8906151c8565b600060405161238990614f36565b604080519182900382208282019091526008825267161594d5985d5b1d60c21b6020909201919091527fddfcc46608a8bd52ebf900f03a24cc97b73a6046cec8c5d0f74a211e376e967a6123db613835565b306040516020016123ef94939291906150ca565b604051602081830303815290604052805190602001209050600060405161241590614f41565b604051908190038120612430918a908a908a906020016150bc565b6040516020818303038152906040528051906020012090506000828260405160200161245d929190614f05565b604051602081830303815290604052805190602001209050600061248382888888613839565b6001600160a01b0381166000908152600e6020526040902080546001810190915590915089146124c55760405162461bcd60e51b81526004016107a890615238565b874211156124e55760405162461bcd60e51b81526004016107a890615218565b6124ef818b6134b0565b505050505b505050505050565b607a5460ff1681565b60066020526000908152604090205481565b6001600160a01b031660009081526008602052604090205490565b6000546001600160a01b0316331461255c5760405162461bcd60e51b81526004016107a890615368565b6001600160a01b0383166125825760405162461bcd60e51b81526004016107a890615228565b6001600160a01b0382166125a85760405162461bcd60e51b81526004016107a8906152c8565b6125b28282612a70565b6016546017546018546040516001600160a01b03808816948116937f8def9436d6e31b89ed00948ba91d0cb6936eada5154cb1b45b55683fb9e492379361260193919092169188918890615024565b60405180910390a3601680546001600160a01b039485166001600160a01b0319918216179091556017805493909416921691909117909155601855565b6003546001600160a01b031681565b607a5460009060ff1661266757612662613863565b61266f565b61266f613867565b905090565b6301e1338081565b60405161104a90614f41565b60185481565b601060209081526000928352604080842090915290825290205463ffffffff811690600160201b90046001600160601b031682565b6312cc030081565b6000546001600160a01b031681565b6126fb6040518060600160405280602c815260200161571b602c91396129ce565b6127048561353f565b61270d8361353f565b6004546001600160a01b03166127355760405162461bcd60e51b81526004016107a8906151a8565b600084116127555760405162461bcd60e51b81526004016107a8906153a8565b61275e85613751565b6001600160a01b0385166000908152600860205260408120805490915b818110156127d957856001600160a01b031683828154811061279957fe5b60009182526020909120600590910201546001600160a01b031614156127d15760405162461bcd60e51b81526004016107a890615328565b60010161277b565b506001600160a01b03851660009081526014602052604090205460ff16156128135760405162461bcd60e51b81526004016107a890615298565b6001600160a01b03871660009081526009602052604090205461283c908763ffffffff612f7216565b6001600160a01b038089166000908152600960209081526040808320949094556006815290839020879055825160a081018452918816825281018890528391810161288561264d565b8152600060208083018290526040928301889052845460018082018755958352818320855160059092020180546001600160a01b0319166001600160a01b039283161781558583015181880155858501516002820155606086015160038201556080909501516004958601558a81168352601490915290829020805460ff1916851790558254915163fb66fb4d60e01b815291169263fb66fb4d9261292d928c929101615059565b600060405180830381600087803b15801561294757600080fd5b505af115801561295b573d6000803e3d6000fd5b50505050846001600160a01b03166001838054905003886001600160a01b03167fd7fa4bff1cd2253c0789c3291a786a6f6b1a3b4569a75af683a15d52abb6a0bf8988886040516129ae93929190615441565b60405180910390a450505050505050565b6016546001600160a01b031681565b6047546040516318c5e8ab60e01b81526000916001600160a01b0316906318c5e8ab90612a019033908690600401614f68565b60206040518083038186803b158015612a1957600080fd5b505afa158015612a2d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612a51919081019061425f565b905080611ae75760405162461bcd60e51b81526004016107a8906151e8565b6001600160a01b0382166000908152600860205260409020548110611ae75760405162461bcd60e51b81526004016107a890615198565b6001600160a01b0382166000908152600860205260408120805483908110612acb57fe5b906000526020600020906005020190508060020154612ae861264d565b11612af35750611ae7565b80546040516370a0823160e01b81526000916001600160a01b0316906370a0823190612b23903090600401614f4c565b60206040518083038186803b158015612b3b57600080fd5b505afa158015612b4f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612b7391908101906142db565b6001600160a01b0385166000908152601260209081526040808320878452909152902054909150612bab90829063ffffffff6136ed16565b905080612bc957612bba61264d565b82600201819055505050611ae7565b6000612bd361264d565b90506000612bee8460020154836136ed90919063ffffffff16565b6001600160a01b03871660009081526009602090815260408083205460018901546006909352908320549394509192612c3792916116a691611fab90879063ffffffff61367116565b9050612c66612c55856116a68464e8d4a5100063ffffffff61367116565b60038701549063ffffffff612f7216565b6003860155612c7361264d565b856002018190555050505050505050565b600061082783600101546116b28585612fb4565b600480546040516370a0823160e01b81526001600160a01b03918216926000928716916370a0823191612ccd91869101614f4c565b60206040518083038186803b158015612ce557600080fd5b505afa158015612cf9573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250612d1d91908101906142db565b6001600160a01b038087166000908152601560209081526040808320938916835292905290812054919250612d58858363ffffffff612f7216565b9050828111612e36578115612dcb576001600160a01b038088166000818152601560209081526040808320948b1680845294909152808220829055517f6bdfd5e51d01475945224d3d37965916fd8df699ef9e8888af4359aa8622216091612dc291879190615418565b60405180910390a35b60405163135b33cd60e31b81526001600160a01b03851690639ad99e6890612dfb908a908a908690600401615009565b600060405180830381600087803b158015612e1557600080fd5b505af1158015612e29573d6000803e3d6000fd5b5050505050505050612f0c565b6001600160a01b038088166000818152601560209081526040808320948b168084529490915290819020868503908190559051909291907f6bdfd5e51d01475945224d3d37965916fd8df699ef9e8888af4359aa8622216090612e9c9087908690615433565b60405180910390a360405163135b33cd60e31b81526001600160a01b03861690639ad99e6890612ed4908b908b908990600401615009565b600060405180830381600087803b158015612eee57600080fd5b505af1158015612f02573d6000803e3d6000fd5b5050505050505050505b505050565b604051612f6c9085906323b872dd60e01b90612f3590879087908790602401615009565b60408051601f198184030181529190526020810180516001600160e01b03166001600160e01b03199093169290921790915261386b565b50505050565b600061082783836040518060400160405280601b81526020017f536166654d6174683a206164646974696f6e206f766572666c6f770000000000815250613950565b600061082764e8d4a510006116a68460030154611fab876002015488600001546136ed90919063ffffffff16565b600081600160601b84106130095760405162461bcd60e51b81526004016107a89190615167565b509192915050565b816001600160a01b0316836001600160a01b03161415801561303c57506000816001600160601b0316115b15612f0c576001600160a01b038316156130f4576001600160a01b03831660009081526011602052604081205463ffffffff16908161307c5760006130bb565b6001600160a01b0385166000908152601060209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b905060006130e282856040518060600160405280602c81526020016156bf602c9139613980565b90506130f0868484846139bf565b5050505b6001600160a01b03821615612f0c576001600160a01b03821660009081526011602052604081205463ffffffff16908161312f57600061316e565b6001600160a01b0384166000908152601060209081526040808320600019860163ffffffff168452909152902054600160201b90046001600160601b03165b9050600061319582856040518060600160405280602b81526020016155ab602b9139613b7b565b90506124f4858484846139bf565b805460009081905b8015613241578360018203815481106131c057fe5b6000918252602090912060016002909202018101546001600160801b03600160801b9091041614156132235761321c8460018303815481106131fe57fe5b6000918252602090912060029091020154839063ffffffff612f7216565b9150613238565b6132358460018303815481106112c157fe5b92505b600019016131ab565b50915091565b8254604080516060810182526000808252602080830182815260019484018581528587018a5589845291909220925160028602909301928355905191909201805492516001600160801b03908116600160801b029281166001600160801b0319909416939093179092161790555b6000811180156132f05750818460018303815481106132d057fe5b60009182526020909120600160029092020101546001600160801b031611155b156133775783600182038154811061330457fe5b906000526020600020906002020184828154811061331e57fe5b600091825260209091208254600290920201908155600191820180549290910180546001600160801b0319166001600160801b03938416178082559154600160801b9081900484160291909216179055600019016132b5565b604051806060016040528084815260200161339184613bae565b6001600160801b0316815260200160016001600160801b03168152508482815481106133b957fe5b60009182526020918290208351600292830290910190815591830151600190920180546040909401516001600160801b03199094166001600160801b03938416178316600160801b939094169290920292909217905585015461341c9084612f72565b85600201819055505050505050565b6001600160a01b0381166134515760405162461bcd60e51b81526004016107a890615278565b604780546001600160a01b038381166001600160a01b03198316179092556040519116907f66fd58e82f7b31a2a5c30e0888f3093efe4e111b00cd2b0c31fe014601293aa0906134a49083908590614f88565b60405180910390a15050565b6001600160a01b038083166000908152600f6020526040812054909116906134d784613bd7565b6001600160a01b038581166000818152600f602052604080822080546001600160a01b031916898616908117909155905194955093928616927f0cc323ffec3ea49cbcddc0de1480978126d350c6a45dff33ad2f1cda6ae992619190a4612f6c828483613011565b6001600160a01b038116610f0a5760405162461bcd60e51b81526004016107a8906152d8565b60010154426001600160801b03909116111590565b805460009081905b60008111801561359f575061359f84600183038154811061129757fe5b15613640578360018203815481106135b357fe5b6000918252602090912060016002909202018101546001600160801b03600160801b9091041614156135f8576135f18460018303815481106131fe57fe5b915061360d565b61360a8460018303815481106112c157fe5b92505b8380548061361757fe5b600082815260208120600019928301600281029091018281556001019190915590915501613582565b50613665613654828463ffffffff612f7216565b60028601549063ffffffff6136ed16565b60028501559250929050565b60008261368057506000611524565b8282028284828161368d57fe5b04146108275760405162461bcd60e51b81526004016107a890615318565b600061082783836040518060400160405280601a81526020017f536166654d6174683a206469766973696f6e206279207a65726f000000000000815250613ced565b600061082783836040518060400160405280601e81526020017f536166654d6174683a207375627472616374696f6e206f766572666c6f770000815250613d24565b604051612f0c90849063a9059cbb60e01b90612f359086908690602401615074565b6001600160a01b038116600090815260086020526040812054905b81811015612f0c5761377e8382612aa7565b60010161376c565b607a54610100900460ff16156137ae5760405162461bcd60e51b81526004016107a8906153b8565b811580156137ba575080155b156137d75760405162461bcd60e51b81526004016107a890615338565b8180156137e357508015155b156138005760405162461bcd60e51b81526004016107a890615258565b607a805460ff191683151517905581613819578061381f565b6301e133805b6079555050607a805461ff001916610100179055565b4690565b600080600061384a87878787613d48565b9150915061385781613e28565b5090505b949350505050565b4390565b4290565b61387d826001600160a01b0316613ef1565b6138995760405162461bcd60e51b81526004016107a8906153d8565b60006060836001600160a01b0316836040516138b59190614ef9565b6000604051808303816000865af19150503d80600081146138f2576040519150601f19603f3d011682016040523d82523d6000602084013e6138f7565b606091505b5091509150816139195760405162461bcd60e51b81526004016107a8906153c8565b805115612f6c5780806020019051613934919081019061425f565b612f6c5760405162461bcd60e51b81526004016107a890615208565b600083830182858210156139775760405162461bcd60e51b81526004016107a89190615167565b50949350505050565b6000836001600160601b0316836001600160601b0316111582906139b75760405162461bcd60e51b81526004016107a89190615167565b505050900390565b60006139ea6139cc61264d565b60405180608001604052806042815260200161564a60429139613f2a565b905060008463ffffffff16118015613a3357506001600160a01b038516600090815260106020908152604080832063ffffffff6000198901811685529252909120548282169116145b15613a92576001600160a01b0385166000908152601060209081526040808320600019880163ffffffff168452909152902080546fffffffffffffffffffffffff000000001916600160201b6001600160601b03851602179055613b31565b60408051808201825263ffffffff80841682526001600160601b0380861660208085019182526001600160a01b038b166000818152601083528781208c871682528352878120965187549451909516600160201b026fffffffffffffffffffffffff000000001995871663ffffffff19958616179590951694909417909555938252601190935292909220805460018801909316929091169190911790555b846001600160a01b03167f6adb589fed1e8542fb7a6b10f00a85e02265e77f9ae3ca8ff93b22983e1af9a08484604051613b6c929190615493565b60405180910390a25050505050565b6000838301826001600160601b0380871690831610156139775760405162461bcd60e51b81526004016107a89190615167565b6000600160801b8210613bd35760405162461bcd60e51b81526004016107a890615248565b5090565b6005546000906001600160a01b0316613c025760405162461bcd60e51b81526004016107a8906151f8565b6005546001600160a01b03166000908152600860205260408120805490915b81811015613ce25760055483546001600160a01b0390911690849083908110613c4657fe5b60009182526020909120600590910201546001600160a01b03161415613cda576005546001600160a01b039081166000908152600760209081526040808320858452825280832093891683529290522060028101548154613ccf91613cb1919063ffffffff6136ed16565b60405180606001604052806028815260200161560160289139612fe2565b94505050505061108d565b600101613c21565b506000949350505050565b60008183613d0e5760405162461bcd60e51b81526004016107a89190615167565b506000838581613d1a57fe5b0495945050505050565b600081848411156139b75760405162461bcd60e51b81526004016107a89190615167565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0831115613d7f5750600090506003613e1f565b8460ff16601b14158015613d9757508460ff16601c14155b15613da85750600090506004613e1f565b600060018787878760405160008152602001604052604051613dcd94939291906150f2565b6020604051602081039080840390855afa158015613def573d6000803e3d6000fd5b5050604051601f1901519150506001600160a01b038116613e1857506000915060019050613e1f565b9150600090505b94509492505050565b6000816004811115613e3657fe5b1415613e4157610f0a565b6001816004811115613e4f57fe5b1415613e6d5760405162461bcd60e51b81526004016107a890615178565b6002816004811115613e7b57fe5b1415613e995760405162461bcd60e51b81526004016107a8906151b8565b6003816004811115613ea757fe5b1415613ec55760405162461bcd60e51b81526004016107a890615288565b6004816004811115613ed357fe5b1415610f0a5760405162461bcd60e51b81526004016107a8906152f8565b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061385b575050151592915050565b600081600160201b84106130095760405162461bcd60e51b81526004016107a89190615167565b604080518082019091526000808252602082015290565b803561152481615569565b805161152481615569565b80356115248161557d565b80516115248161557d565b803561152481615586565b80356115248161558f565b805161152481615586565b803561152481615598565b8035611524816155a1565b600060208284031215613fdd57600080fd5b600061385b8484613f68565b600060208284031215613ffb57600080fd5b600061385b8484613f73565b6000806040838503121561401a57600080fd5b60006140268585613f68565b925050602061403785828601613f68565b9150509250929050565b60008060006060848603121561405657600080fd5b60006140628686613f68565b935050602061407386828701613f68565b925050604061408486828701613f94565b9150509250925092565b600080604083850312156140a157600080fd5b60006140ad8585613f68565b925050602061403785828601613f94565b6000806000606084860312156140d357600080fd5b60006140df8686613f68565b93505060206140f086828701613f94565b925050604061408486828701613f68565b600080600080600060a0868803121561411957600080fd5b60006141258888613f68565b955050602061413688828901613f94565b945050604061414788828901613f9f565b935050606061415888828901613f94565b925050608061416988828901613f94565b9150509295509295909350565b60008060006060848603121561418b57600080fd5b60006141978686613f68565b935050602061407386828701613f94565b60008060008060008060c087890312156141c157600080fd5b60006141cd8989613f68565b96505060206141de89828a01613f94565b95505060406141ef89828a01613f94565b945050606061420089828a01613fc0565b935050608061421189828a01613f94565b92505060a061422289828a01613f94565b9150509295509295509295565b6000806040838503121561424257600080fd5b600061424e8585613f68565b925050602061403785828601613fb5565b60006020828403121561427157600080fd5b600061385b8484613f89565b6000806040838503121561429057600080fd5b60006140ad8585613f7e565b6000806000606084860312156142b157600080fd5b60006140628686613f9f565b6000602082840312156142cf57600080fd5b600061385b8484613f9f565b6000602082840312156142ed57600080fd5b600061385b8484613faa565b60006143058383614e99565b505060600190565b61431681615512565b82525050565b614316816154c1565b6000614330826154b4565b61433a81856154b8565b9350614345836154ae565b8060005b8381101561437357815161435d88826142f9565b9750614368836154ae565b925050600101614349565b509495945050505050565b614316816154cc565b614316816154d1565b61431661439c826154d1565b6154d1565b60006143ac826154b4565b6143b6818561108d565b93506143c6818560208601615533565b9290920192915050565b614316816154d4565b6143168161551d565b60006143ed826154b4565b6143f781856154b8565b9350614407818560208601615533565b6144108161555f565b9093019392505050565b60006144276018836154b8565b7f45434453413a20696e76616c6964207369676e61747572650000000000000000815260200192915050565b60006144606012836154b8565b71696e636f6e73697374656e7420737461746560701b815260200192915050565b600061448e6013836154b8565b727661756c743a20706f6f6c206578697374733f60681b815260200192915050565b60006144bd601f836154b8565b7f53746f726520636f6e7472616374206164647265737320697320656d70747900815260200192915050565b60006144f6601f836154b8565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800815260200192915050565b600061452f600f836154b8565b6e15985d5b1d081a5cc81c185d5cd959608a1b815260200192915050565b600061455a6013836154b8565b7215985d5b1d081a5cc81b9bdd081c185d5cd959606a1b815260200192915050565b6000614589600c836154b8565b6b155b985d5d1a1bdc9a5e995960a21b815260200192915050565b60006145b16030836154b8565b7f5856535661756c743a3a6765745374616b65416d6f756e743a2078767320616481526f191c995cdcc81a5cc81b9bdd081cd95d60821b602082015260400192915050565b6000614603602a836154b8565b7f5361666542455032303a204245503230206f7065726174696f6e20646964206e8152691bdd081cdd58d8d9595960b21b602082015260400192915050565b600061464f602a836154b8565b7f5856535661756c743a3a64656c656761746542795369673a207369676e6174758152691c9948195e1c1a5c995960b21b602082015260400192915050565b600061469b6022836154b8565b7f7072696d6520746f6b656e2063616e6e6f74206265207a65726f206164647265815261737360f01b602082015260400192915050565b60006146df6026836154b8565b7f5856535661756c743a3a64656c656761746542795369673a20696e76616c6964815265206e6f6e636560d01b602082015260400192915050565b600061472760028361108d565b61190160f01b815260020192915050565b60006147456027836154b8565b7f53616665436173743a2076616c756520646f65736e27742066697420696e20318152663238206269747360c81b602082015260400192915050565b600061478e6020836154b8565b7f496e76616c69642074696d6520626173656420636f6e66696775726174696f6e815260200192915050565b60006147c76017836154b8565b7f5661756c7420697320616c726561647920706175736564000000000000000000815260200192915050565b60006148006025836154b8565b7f696e76616c696420616365737320636f6e74726f6c206d616e61676572206164815264647265737360d81b602082015260400192915050565b60006148476022836154b8565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c815261756560f01b602082015260400192915050565b600061488b601a836154b8565b7f546f6b656e2065786973747320696e206f7468657220706f6f6c000000000000815260200192915050565b60006148c46013836154b8565b72185b1c9958591e481a5b9a5d1a585b1a5e9959606a1b815260200192915050565b60006148f3602b836154b8565b7f5856535661756c743a3a6765745072696f72566f7465733a206e6f742079657481526a0819195d195c9b5a5b995960aa1b602082015260400192915050565b6000614940601d836154b8565b7f7265776172642063616e6e6f74206265207a65726f2061646472657373000000815260200192915050565b60006149796018836154b8565b7f7a65726f2061646472657373206e6f7420616c6c6f7765640000000000000000815260200192915050565b60006149b2601a836154b8565b7f657865637574652070656e64696e67207769746864726177616c000000000000815260200192915050565b60006149eb6022836154b8565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c815261756560f01b602082015260400192915050565b6000614a2f60438361108d565b7f454950373132446f6d61696e28737472696e67206e616d652c75696e7432353681527f20636861696e49642c6164647265737320766572696679696e67436f6e74726160208201526263742960e81b604082015260430192915050565b6000614a9a601f836154b8565b7f72657175657374656420616d6f756e742063616e6e6f74206265207a65726f00815260200192915050565b6000614ad36021836154b8565b7f536166654d6174683a206d756c7469706c69636174696f6e206f766572666c6f8152607760f81b602082015260400192915050565b6000614b166012836154b8565b71141bdbdb08185b1c9958591e48185919195960721b815260200192915050565b6000614b446017836154b8565b7f496e76616c696420626c6f636b73207065722079656172000000000000000000815260200192915050565b6000614b7d600a836154b8565b691c994b595b9d195c995960b21b815260200192915050565b6000614ba36014836154b8565b7324b73b30b634b2103932bbb0b932103a37b5b2b760611b815260200192915050565b6000614bd3600e836154b8565b6d37b7363c9030b236b4b71031b0b760911b815260200192915050565b6000614bfd6015836154b8565b7418da185b99d9481b9bdd08185d5d1a1bdc9a5e9959605a1b815260200192915050565b6000614c2e6013836154b8565b726e6f7468696e6720746f20776974686472617760681b815260200192915050565b6000614c5d601a836154b8565b7f496e76616c6964206e6577206c6f636b696e6720706572696f64000000000000815260200192915050565b6000614c96601d836154b8565b7f416c6c6f6320706f696e7473206d757374206e6f74206265207a65726f000000815260200192915050565b6000614ccf601f836154b8565b7f416c726561647920696e697469616c697a65642054696d654d616e6167657200815260200192915050565b6000614d086020836154b8565b7f5361666542455032303a206c6f772d6c6576656c2063616c6c206661696c6564815260200192915050565b6000614d41603a8361108d565b7f44656c65676174696f6e28616464726573732064656c6567617465652c75696e81527f74323536206e6f6e63652c75696e7432353620657870697279290000000000006020820152603a0192915050565b6000614da0601f836154b8565b7f5361666542455032303a2063616c6c20746f206e6f6e2d636f6e747261637400815260200192915050565b6000614dd9601b836154b8565b7f72657175657374656420616d6f756e7420697320696e76616c69640000000000815260200192915050565b6000614e126022836154b8565b7f6f6e6c792070726f78792061646d696e2063616e206368616e676520627261698152616e7360f01b602082015260400192915050565b6000614e56602e836154b8565b7f416c6c6f6320706f696e7473207065722072657761726420746f6b656e206d7581526d7374206e6f74206265207a65726f60901b602082015260400192915050565b80516060830190614eaa8482614387565b506020820151614ebd6020850182614ecc565b506040820151612f6c60408501825b614316816154df565b614316816154f7565b61431681615500565b61431681615528565b61431681615506565b600061082782846143a1565b6000614f108261471a565b9150614f1c8285614390565b602082019150614f2c8284614390565b5060200192915050565b600061152482614a22565b600061152482614d34565b60208101611524828461431c565b60208101611524828461430d565b60408101614f76828561430d565b818103602083015261385b81846143e2565b60408101614f96828561431c565b610827602083018461431c565b60608101614fb1828661431c565b614fbe602083018561430d565b61385b6040830184614387565b60808101614fd9828761431c565b614fe6602083018661431c565b614ff3604083018561431c565b615000606083018461431c565b95945050505050565b60608101615017828661431c565b614fbe602083018561431c565b60808101615032828761431c565b61503f602083018661431c565b61504c6040830185614387565b6150006060830184614387565b60408101615067828561431c565b610827602083018461437e565b60408101615082828561431c565b6108276020830184614387565b602080825281016108278184614325565b60208101611524828461437e565b602081016115248284614387565b608081016150328287614387565b608081016150d88287614387565b6150e56020830186614387565b614ff36040830185614387565b608081016151008287614387565b61503f6020830186614ede565b6020810161152482846143d0565b60a0810161512982886143d0565b6151366020830187614387565b6151436040830186614387565b6151506060830185614387565b61515d6080830184614387565b9695505050505050565b6020808252810161082781846143e2565b602080825281016115248161441a565b6020808252810161152481614453565b6020808252810161152481614481565b60208082528101611524816144b0565b60208082528101611524816144e9565b6020808252810161152481614522565b602080825281016115248161454d565b602080825281016115248161457c565b60208082528101611524816145a4565b60208082528101611524816145f6565b6020808252810161152481614642565b602080825281016115248161468e565b60208082528101611524816146d2565b6020808252810161152481614738565b6020808252810161152481614781565b60208082528101611524816147ba565b60208082528101611524816147f3565b602080825281016115248161483a565b602080825281016115248161487e565b60208082528101611524816148b7565b60208082528101611524816148e6565b6020808252810161152481614933565b602080825281016115248161496c565b60208082528101611524816149a5565b60208082528101611524816149de565b6020808252810161152481614a8d565b6020808252810161152481614ac6565b6020808252810161152481614b09565b6020808252810161152481614b37565b6020808252810161152481614b70565b6020808252810161152481614b96565b6020808252810161152481614bc6565b6020808252810161152481614bf0565b6020808252810161152481614c21565b6020808252810161152481614c50565b6020808252810161152481614c89565b6020808252810161152481614cc2565b6020808252810161152481614cfb565b6020808252810161152481614d93565b6020808252810161152481614dcc565b6020808252810161152481614e05565b6020808252810161152481614e49565b604081016154268285614387565b61082760208301846143d9565b604081016150828285614387565b6060810161544f8286614387565b614fbe6020830185614387565b602081016115248284614ed5565b604081016154788285614ed5565b6108276020830184614ef0565b602081016115248284614ef0565b604081016154a18285614ee7565b6108276020830184614ee7565b60200190565b5190565b90815260200190565b6000611524826154eb565b151590565b90565b6000611524826154c1565b6001600160801b031690565b6001600160a01b031690565b63ffffffff1690565b60ff1690565b6001600160601b031690565b6000611524826154d4565b6000611524826154d1565b600061152482615506565b60005b8381101561554e578181015183820152602001615536565b83811115612f6c5750506000910152565b601f01601f191690565b615572816154c1565b8114610f0a57600080fd5b615572816154cc565b615572816154d1565b615572816154d4565b615572816154f7565b6155728161550056fe5856535661756c743a3a5f6d6f7665566f7465733a20766f746520616d6f756e74206f766572666c6f77735856535661756c743a3a726571756573745769746864726177616c3a20766f746573206f766572666c6f775856535661756c743a3a6765745374616b65416d6f756e743a20766f746573206f766572666c6f775856535661756c743a3a6465706f7369743a20766f746573206f766572666c6f775856535661756c743a3a5f7772697465436865636b706f696e743a20626c6f636b206e756d626572206f72207365636f6e64206578636565647320333220626974737365745769746864726177616c4c6f636b696e67506572696f6428616464726573732c75696e743235362c75696e74323536295856535661756c743a3a5f6d6f7665566f7465733a20766f746520616d6f756e7420756e646572666c6f7773736574526577617264416d6f756e74506572426c6f636b4f725365636f6e6428616464726573732c75696e743235362961646428616464726573732c75696e743235362c616464726573732c75696e743235362c75696e7432353629a365627a7a7231582053ba350123a86f07263e7bddf3bcee0f7cf11e72f5d2678781f0eb1ebd599dc16c6578706572696d656e74616cf564736f6c63430005100040

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ 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.