MOVR Price: $21.61 (-0.00%)
Gas: 3 GWei

Contract

0xd75C5063baEe40D162156397324a587372Fe493B

Overview

MOVR Balance

Moonriver Chain LogoMoonriver Chain LogoMoonriver Chain Logo0 MOVR

MOVR Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Value
0x6080604028425392022-10-24 14:58:48521 days ago1666623528IN
 Create: Lido
0 MOVR0.015695233

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Lido

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 5 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 14 : Lido.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
pragma abicoder v2;

import "IERC20.sol";
import "SafeCast.sol";
import "Initializable.sol";

import "IOracleMaster.sol";
import "ILedgerFactory.sol";
import "ILedger.sol";
import "IController.sol";
import "IAuthManager.sol";
import "IWithdrawal.sol";

import "stKSM.sol";


contract Lido is stKSM, Initializable {
    using SafeCast for uint256;

    // Records a deposit made by a user
    event Deposited(address indexed sender, uint256 amount);

    // Created redeem order
    event Redeemed(address indexed receiver, uint256 amount);

    // Claimed vKSM tokens back
    event Claimed(address indexed receiver, uint256 amount);

    // Fee was updated
    event FeeSet(uint16 fee, uint16 feeOperatorsBP, uint16 feeTreasuryBP,  uint16 feeDevelopersBP);

    // Rewards distributed
    event Rewards(address ledger, uint256 rewards, uint256 balance);

    // Losses distributed
    event Losses(address ledger, uint256 losses, uint256 balance);

    // Added new ledger
    event LedgerAdd(
        address addr,
        bytes32 stashAccount,
        bytes32 controllerAccount
    );

    // Ledger removed
    event LedgerRemove(
        address addr
    );

    // Ledger disabled
    event LedgerDisable(
        address addr
    );

    // Ledger paused
    event LedgerPaused(
        address addr
    );

    // Ledger resumed
    event LedgerResumed(
        address addr
    );

    // Referral program
    event Referral(
        address userAddr,
        address referralAddr,
        uint256 amount,
        uint256 shares
    );

    // sum of all deposits and rewards
    uint256 public fundRaisedBalance;

    // haven't executed buffrered deposits:
    //
    // this is the amount of funds that must either sent to the ledgers
    // or rebalanced to buffered redeems
    uint256 public bufferedDeposits;

    // haven't executed buffrered redeems:
    // this is the amount of funds that should be sent to the WITHDRAWAL contract
    uint256 public bufferedRedeems;

    // this is the active stake on the ledger = [ledgerBorrow] - unbonded funds - free funds
    mapping(address => uint256) public ledgerStake;

    // this is the total amount of funds in the ledger = active stake + unbonded funds + free funds
    mapping(address => uint256) public ledgerBorrow;

    // Disabled ledgers
    address[] private disabledLedgers;

    // Enabled ledgers
    address[] private enabledLedgers;

    // Cap for deposits for v1
    uint256 public depositCap;

    // vKSM precompile
    IERC20 private VKSM;

    // controller
    address private CONTROLLER;

    // auth manager contract address
    address public AUTH_MANAGER;

    // Maximum number of ledgers
    uint256 private MAX_LEDGERS_AMOUNT;

    // oracle master contract
    address public ORACLE_MASTER;

    // relay spec
    Types.RelaySpec private RELAY_SPEC;

    // developers fund
    address private developers;

    // treasury fund
    address private treasury;

    // ledger beacon
    address public LEDGER_BEACON;

    // ledger factory
    address private LEDGER_FACTORY;

    // withdrawal contract
    address private WITHDRAWAL;

    // Max allowable difference for oracle reports
    uint128 public MAX_ALLOWABLE_DIFFERENCE;

    // Ledger address by stash account id
    mapping(bytes32 => address) private ledgerByStash;

    // Map to check ledger existence by address
    mapping(address => bool) private ledgerByAddress;

    // Map to check ledger paused to redeem state
    mapping(address => bool) private pausedledgers;

    /* fee interest in basis points.
    It's packed uint256 consist of three uint16 (total_fee, treasury_fee, developers_fee).
    where total_fee = treasury_fee + developers_fee + 3000 (3% operators fee)
    */
    Types.Fee private FEE;

    // default interest value in base points.
    uint16 internal constant DEFAULT_DEVELOPERS_FEE = 200;
    uint16 internal constant DEFAULT_OPERATORS_FEE = 0;
    uint16 internal constant DEFAULT_TREASURY_FEE = 800;

    // Missing member index
    uint256 internal constant MEMBER_NOT_FOUND = type(uint256).max;

    // Spec manager role
    bytes32 internal constant ROLE_SPEC_MANAGER = keccak256("ROLE_SPEC_MANAGER");

    // Beacon manager role
    bytes32 internal constant ROLE_BEACON_MANAGER = keccak256("ROLE_BEACON_MANAGER");

    // Pause manager role
    bytes32 internal constant ROLE_PAUSE_MANAGER = keccak256("ROLE_PAUSE_MANAGER");

    // Fee manager role
    bytes32 internal constant ROLE_FEE_MANAGER = keccak256("ROLE_FEE_MANAGER");

    // Ledger manager role
    bytes32 internal constant ROLE_LEDGER_MANAGER = keccak256("ROLE_LEDGER_MANAGER");

    // Stake manager role
    bytes32 internal constant ROLE_STAKE_MANAGER = keccak256("ROLE_STAKE_MANAGER");

    // Treasury manager role
    bytes32 internal constant ROLE_TREASURY = keccak256("ROLE_SET_TREASURY");

    // Developers address change role
    bytes32 internal constant ROLE_DEVELOPERS = keccak256("ROLE_SET_DEVELOPERS");

    // Token name
    string internal _name;

    // Token symbol
    string internal _symbol;

    // Token decimals
    uint8 internal _decimals;

    // Allow function calls only from member with specific role
    modifier auth(bytes32 role) {
        require(IAuthManager(AUTH_MANAGER).has(role, msg.sender), "LIDO: UNAUTHORIZED");
        _;
    }

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

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

    /**
     * @return the number of decimals for getting user representation of a token amount.
     */
    function decimals() public view returns (uint8) {
        return _decimals;
    }

    /**
     * @notice setting token parameters
     */
    // NOTE: function was removed from Lido, because it can be called only once to set parameters and after that
    // it is unnecessary in the code. It was removed to decrease contract bytecode size
    // function setTokenInfo(string memory __name, string memory __symbol, uint8 __decimals) external {
    //     require(bytes(__name).length > 0, "LIDO: EMPTY_NAME");
    //     require(bytes(__symbol).length > 0, "LIDO: EMPTY_SYMBOL");
    //     require(__decimals > 0, "LIDO: ZERO_DECIMALS");
    //     require(bytes(_name).length == 0, "LIDO: NAME_SETTED");
    //     _name = __name;
    //     _symbol = __symbol;
    //     _decimals = __decimals;
    // }

    /**
    * @notice Initialize lido contract.
    * @param _authManager - auth manager contract address
    * @param _vKSM - vKSM contract address
    * @param _controller - relay controller address
    * @param _developers - devs address
    * @param _treasury - treasury address
    * @param _oracleMaster - oracle master address
    * @param _withdrawal - withdrawal address
    * @param _depositCap - cap for deposits
    * @param _maxAllowableDifference - max allowable difference for oracle reports
    */
    function initialize(
        address _authManager,
        address _vKSM,
        address _controller,
        address _developers,
        address _treasury,
        address _oracleMaster,
        address _withdrawal,
        uint256 _depositCap,
        uint128 _maxAllowableDifference
    ) external initializer {
        require(_depositCap > 0, "LIDO: ZERO_CAP");
        require(_vKSM != address(0), "LIDO: INCORRECT_VKSM_ADDRESS");
        require(_oracleMaster != address(0), "LIDO: INCORRECT_ORACLE_MASTER_ADDRESS");
        require(_withdrawal != address(0), "LIDO: INCORRECT_WITHDRAWAL_ADDRESS");
        require(_authManager != address(0), "LIDO: INCORRECT_AUTHMANAGER_ADDRESS");
        require(_controller != address(0), "LIDO: INCORRECT_CONTROLLER_ADDRESS");

        VKSM = IERC20(_vKSM);
        CONTROLLER = _controller;
        AUTH_MANAGER = _authManager;

        depositCap = _depositCap;

        MAX_LEDGERS_AMOUNT = 200;
        Types.Fee memory _fee;
        _fee.total = DEFAULT_OPERATORS_FEE + DEFAULT_DEVELOPERS_FEE + DEFAULT_TREASURY_FEE;
        _fee.operators = DEFAULT_OPERATORS_FEE;
        _fee.developers = DEFAULT_DEVELOPERS_FEE;
        _fee.treasury = DEFAULT_TREASURY_FEE;
        FEE = _fee;

        treasury = _treasury;
        developers =_developers;

        ORACLE_MASTER = _oracleMaster;
        IOracleMaster(ORACLE_MASTER).setLido(address(this));

        WITHDRAWAL = _withdrawal;
        IWithdrawal(WITHDRAWAL).setStKSM(address(this));

        MAX_ALLOWABLE_DIFFERENCE = _maxAllowableDifference;
    }

    /**
    * @notice Set treasury address to '_treasury'
    */
    function setTreasury(address _treasury) external auth(ROLE_TREASURY) {
        require(_treasury != address(0), "LIDO: INCORRECT_TREASURY_ADDRESS");
        treasury = _treasury;
    }

    /**
    * @notice Set deposit cap to new value
    */
    function setDepositCap(uint256 _depositCap) external auth(ROLE_PAUSE_MANAGER) {
        require(_depositCap > 0, "LIDO: INCORRECT_NEW_CAP");
        depositCap = _depositCap;
    }

    /**
    * @notice Set ledger beacon address to '_ledgerBeacon'
    */
    function setLedgerBeacon(address _ledgerBeacon) external auth(ROLE_BEACON_MANAGER) {
        require(_ledgerBeacon != address(0), "LIDO: INCORRECT_BEACON_ADDRESS");
        LEDGER_BEACON = _ledgerBeacon;
    }

    function setMaxAllowableDifference(uint128 _maxAllowableDifference) external auth(ROLE_BEACON_MANAGER) {
        require(_maxAllowableDifference > 0, "LIDO: INCORRECT_MAX_ALLOWABLE_DIFFERENCE");
        MAX_ALLOWABLE_DIFFERENCE = _maxAllowableDifference;
    }

    /**
    * @notice Set ledger factory address to '_ledgerFactory'
    */
    function setLedgerFactory(address _ledgerFactory) external auth(ROLE_BEACON_MANAGER) {
        require(_ledgerFactory != address(0), "LIDO: INCORRECT_FACTORY_ADDRESS");
        LEDGER_FACTORY = _ledgerFactory;
    }

    /**
    * @notice Set developers address to '_developers'
    */
    function setDevelopers(address _developers) external auth(ROLE_DEVELOPERS) {
        require(_developers != address(0), "LIDO: INCORRECT_DEVELOPERS_ADDRESS");
        developers = _developers;
    }

    /**
    * @notice Set relay chain spec, allowed to call only by ROLE_SPEC_MANAGER
    * @dev if some params are changed function will iterate over oracles and ledgers, be careful
    * @param _relaySpec - new relaychain spec
    */
    function setRelaySpec(Types.RelaySpec calldata _relaySpec) external auth(ROLE_SPEC_MANAGER) {
        require(_relaySpec.maxValidatorsPerLedger > 0, "LIDO: BAD_MAX_VALIDATORS_PER_LEDGER");
        require(_relaySpec.maxUnlockingChunks > 0, "LIDO: BAD_MAX_UNLOCKING_CHUNKS");

        RELAY_SPEC = _relaySpec;

        _updateLedgerRelaySpecs(_relaySpec.minNominatorBalance, _relaySpec.ledgerMinimumActiveBalance, _relaySpec.maxUnlockingChunks);
    }

    /**
    * @notice Set new lido fee, allowed to call only by ROLE_FEE_MANAGER
    * @param _feeOperators - Operators percentage in basis points. It's always 3%
    * @param _feeTreasury - Treasury fund percentage in basis points
    * @param _feeDevelopers - Developers percentage in basis points
    */
    function setFee(uint16 _feeOperators, uint16 _feeTreasury,  uint16 _feeDevelopers) external auth(ROLE_FEE_MANAGER) {
        Types.Fee memory _fee;
        _fee.total = _feeTreasury + _feeOperators + _feeDevelopers;
        require(_fee.total <= 10000 && (_feeTreasury > 0 || _feeDevelopers > 0) && _feeOperators < 10000, "LIDO: FEE_DONT_ADD_UP");

        emit FeeSet(_fee.total, _feeOperators, _feeTreasury, _feeDevelopers);

        _fee.developers = _feeDevelopers;
        _fee.operators = _feeOperators;
        _fee.treasury = _feeTreasury;
        FEE = _fee;
    }

    /**
    * @notice Return unbonded tokens amount for user
    * @param _holder - user account for whom need to calculate unbonding
    * @return waiting - amount of tokens which are not unbonded yet
    * @return unbonded - amount of token which unbonded and ready to claim
    */
    function getUnbonded(address _holder) external view returns (uint256 waiting, uint256 unbonded) {
        return IWithdrawal(WITHDRAWAL).getRedeemStatus(_holder);
    }

    /**
    * @notice Return relay chain stash account addresses
    * @return Array of bytes32 relaychain stash accounts
    */
    function getStashAccounts() public view returns (bytes32[] memory) {
        bytes32[] memory _stashes = new bytes32[](enabledLedgers.length + disabledLedgers.length);

        for (uint i = 0; i < enabledLedgers.length + disabledLedgers.length; i++) {
            address ledgerAddr = i < enabledLedgers.length ?
                enabledLedgers[i] : disabledLedgers[i - enabledLedgers.length];
                
            _stashes[i] = bytes32(ILedger(ledgerAddr).stashAccount());
        }

        return _stashes;
    }

    /**
    * @notice Return ledger contract addresses
    * @dev Each ledger contract linked with single stash account on the relaychain side
    * @return Array of ledger contract addresses
    */
    function getLedgerAddresses() public view returns (address[] memory) {
        address[] memory _ledgers = new address[](enabledLedgers.length + disabledLedgers.length);

        for (uint i = 0; i < enabledLedgers.length + disabledLedgers.length; i++) {
            _ledgers[i] = i < enabledLedgers.length ?
                enabledLedgers[i] : disabledLedgers[i - enabledLedgers.length];
        }

        return _ledgers;
    }

    /**
    * @notice Return ledger address by stash account id
    * @dev If ledger not found function returns ZERO address
    * @param _stashAccount - relaychain stash account id
    * @return Linked ledger contract address
    */
    function findLedger(bytes32 _stashAccount) external view returns (address) {
        return ledgerByStash[_stashAccount];
    }

    /**
    * @notice Stop pool routine operations (deposit, redeem, claimUnbonded),
    *         allowed to call only by ROLE_PAUSE_MANAGER
    */
    function pause() external auth(ROLE_PAUSE_MANAGER) {
        _pause();
    }

    /**
    * @notice Resume pool routine operations (deposit, redeem, claimUnbonded),
    *         allowed to call only by ROLE_PAUSE_MANAGER
    */
    function resume() external auth(ROLE_PAUSE_MANAGER) {
        _unpause();
    }

    /**
    * @notice Add new ledger, allowed to call only by ROLE_LEDGER_MANAGER
    * @dev That function deploys new ledger for provided stash account
    *      Also method triggers rebalancing stakes accross ledgers,
           recommended to carefully calculate share value to avoid significant rebalancing.
    * @param _stashAccount - relaychain stash account id
    * @param _controllerAccount - controller account id for given stash
    * @return created ledger address
    */
    function addLedger(
        bytes32 _stashAccount,
        bytes32 _controllerAccount,
        uint16 _index
    )
        external
        auth(ROLE_LEDGER_MANAGER)
        returns(address)
    {
        require(LEDGER_BEACON != address(0), "LIDO: UNSPECIFIED_LEDGER_BEACON");
        require(LEDGER_FACTORY != address(0), "LIDO: UNSPECIFIED_LEDGER_FACTORY");
        require(ORACLE_MASTER != address(0), "LIDO: NO_ORACLE_MASTER");
        require(enabledLedgers.length + disabledLedgers.length < MAX_LEDGERS_AMOUNT, "LIDO: LEDGERS_POOL_LIMIT");
        require(ledgerByStash[_stashAccount] == address(0), "LIDO: STASH_ALREADY_EXISTS");

        address ledger = ILedgerFactory(LEDGER_FACTORY).createLedger( 
            _stashAccount,
            _controllerAccount,
            address(VKSM),
            CONTROLLER,
            RELAY_SPEC.minNominatorBalance,
            RELAY_SPEC.ledgerMinimumActiveBalance,
            RELAY_SPEC.maxUnlockingChunks
        );

        enabledLedgers.push(ledger);
        ledgerByStash[_stashAccount] = ledger;
        ledgerByAddress[ledger] = true;

        IOracleMaster(ORACLE_MASTER).addLedger(ledger);

        IController(CONTROLLER).newSubAccount(_index, _stashAccount, ledger);

        emit LedgerAdd(ledger, _stashAccount, _controllerAccount);
        return ledger;
    }

    /**
    * @notice Disable ledger, allowed to call only by ROLE_LEDGER_MANAGER
    * @dev That method put ledger to "draining" mode, after ledger drained it can be removed
    * @param _ledgerAddress - target ledger address
    */
    function disableLedger(address _ledgerAddress) external auth(ROLE_LEDGER_MANAGER) {
        _disableLedger(_ledgerAddress);
    }

    /**
    * @notice Disable ledger and pause all redeems for that ledger, allowed to call only by ROLE_LEDGER_MANAGER
    * @dev That method pause all stake changes for ledger
    * @param _ledgerAddress - target ledger address
    */
    function emergencyPauseLedger(address _ledgerAddress) external auth(ROLE_LEDGER_MANAGER) {
        _disableLedger(_ledgerAddress);
        pausedledgers[_ledgerAddress] = true;
        emit LedgerPaused(_ledgerAddress);
    }

    /**
    * @notice Allow redeems from paused ledger, allowed to call only by ROLE_LEDGER_MANAGER
    * @param _ledgerAddress - target ledger address
    */
    function resumeLedger(address _ledgerAddress) external auth(ROLE_LEDGER_MANAGER) {
        require(pausedledgers[_ledgerAddress], "LIDO: LEDGER_NOT_PAUSED");
        delete pausedledgers[_ledgerAddress];
        emit LedgerResumed(_ledgerAddress);
    }

    /**
    * @notice Remove ledger, allowed to call only by ROLE_LEDGER_MANAGER
    * @dev That method cannot be executed for running ledger, so need to drain funds
    * @param _ledgerAddress - target ledger address
    */
    function removeLedger(address _ledgerAddress) external auth(ROLE_LEDGER_MANAGER) {
        require(ledgerByAddress[_ledgerAddress], "LIDO: LEDGER_NOT_FOUND");
        require(ledgerStake[_ledgerAddress] == 0, "LIDO: LEDGER_HAS_NON_ZERO_STAKE");
        // uint256 ledgerIdx = _findDisabledLedger(_ledgerAddress);
        uint256 ledgerIdx = _findLedger(_ledgerAddress, false);
        require(ledgerIdx != type(uint256).max, "LIDO: LEDGER_NOT_DISABLED");

        ILedger ledger = ILedger(_ledgerAddress);
        require(ledger.isEmpty(), "LIDO: LEDGER_IS_NOT_EMPTY");

        address lastLedger = disabledLedgers[disabledLedgers.length - 1];
        disabledLedgers[ledgerIdx] = lastLedger;
        disabledLedgers.pop();

        delete ledgerByAddress[_ledgerAddress];
        delete ledgerByStash[ledger.stashAccount()];

        if (pausedledgers[_ledgerAddress]) {
            delete pausedledgers[_ledgerAddress];
        }

        IOracleMaster(ORACLE_MASTER).removeLedger(_ledgerAddress);

        IController(CONTROLLER).deleteSubAccount(_ledgerAddress);

        emit LedgerRemove(_ledgerAddress);
    }

    /**
    * @notice Nominate on behalf of gived array of stash accounts, allowed to call only by ROLE_STAKE_MANAGER
    * @dev Method spawns xcm call to relaychain
    * @param _stashAccounts - target stash accounts id
    * @param _validators - validators set to be nominated
    */
    function nominateBatch(bytes32[] calldata _stashAccounts, bytes32[][] calldata _validators) external auth(ROLE_STAKE_MANAGER) {
        require(_stashAccounts.length == _validators.length, "LIDO: INCORRECT_INPUT");

        for (uint256 i = 0; i < _stashAccounts.length; ++i) {
            require(ledgerByStash[_stashAccounts[i]] != address(0),  "LIDO: UNKNOWN_STASH_ACCOUNT");

            require(_validators[i].length <= RELAY_SPEC.maxValidatorsPerLedger, "LIDO: VALIDATORS_AMOUNT_TOO_BIG");

            ILedger(ledgerByStash[_stashAccounts[i]]).nominate(_validators[i]);
        }
    }

    function deposit(uint256 _amount) external returns (uint256) {
        return _deposit(_amount);
    }

    function deposit(uint256 _amount, address _referral) external returns (uint256) {
        uint256 shares = _deposit(_amount);
        emit Referral(msg.sender, _referral, _amount, shares);
        return shares;
    }

    /**
    * @notice Deposit vKSM tokens to the pool and recieve stKSM(liquid staked tokens) instead.
              User should approve tokens before executing this call.
    * @dev Method accoumulate vKSMs on contract
    * @param _amount - amount of vKSM tokens to be deposited
    */
    function _deposit(uint256 _amount) internal whenNotPaused returns (uint256) {
        require(fundRaisedBalance + _amount < depositCap, "LIDO: DEPOSITS_EXCEED_CAP");

        VKSM.transferFrom(msg.sender, address(this), _amount);

        require(_amount != 0, "LIDO: ZERO_DEPOSIT");

        uint256 shares = getSharesByPooledKSM(_amount);
        if (shares == 0) {
            // totalPooledKSM is 0: either the first-ever deposit or complete slashing
            // assume that shares correspond to KSM as 1-to-1
            shares = _amount;
        }

        fundRaisedBalance += _amount;
        bufferedDeposits += _amount;
        _mintShares(msg.sender, shares);

        _emitTransferAfterMintingShares(msg.sender, shares);

        emit Deposited(msg.sender, _amount);

        return shares;
    }

    /**
    * @notice Create request to redeem vKSM in exchange of stKSM. stKSM will be instantly burned and
              created claim order, (see `getUnbonded` method).
              User can have up to 20 redeem requests in parallel.
    * @param _amount - amount of stKSM tokens to be redeemed
    */
    function redeem(uint256 _amount) external whenNotPaused {
        uint256 _shares = getSharesByPooledKSM(_amount);
        require(_shares > 0, "LIDO: AMOUNT_TOO_LOW");
        require(_shares <= _sharesOf(msg.sender), "LIDO: REDEEM_AMOUNT_EXCEEDS_BALANCE");

        _burnShares(msg.sender, _shares);
        fundRaisedBalance -= _amount;
        bufferedRedeems += _amount;

        IWithdrawal(WITHDRAWAL).redeem(msg.sender, _amount);

        // emit event about burning (compatible with ERC20)
        emit Transfer(msg.sender, address(0), _amount);

        // lido event about redeemed
        emit Redeemed(msg.sender, _amount);
    }

    /**
    * @notice Claim all unbonded tokens at this point of time. Executed redeem requests will be removed
              and approproate amount of vKSM transferred to calling account.
    */
    function claimUnbonded() external whenNotPaused {
        uint256 amount = IWithdrawal(WITHDRAWAL).claim(msg.sender);
        emit Claimed(msg.sender, amount);
    }

    /**
    * @notice Distribute rewards earned by ledger, allowed to call only by ledger
    */
    function distributeRewards(uint256 _totalRewards, uint256 _ledgerBalance) external {
        require(ledgerByAddress[msg.sender], "LIDO: NOT_FROM_LEDGER");

        Types.Fee memory _fee = FEE;

        // it's `feeDevelopers` + `feeTreasure`
        uint256 _feeDevTreasure = uint256(_fee.developers + _fee.treasury);
        assert(_feeDevTreasure>0);

        fundRaisedBalance += _totalRewards;
        ledgerStake[msg.sender] += _totalRewards;
        ledgerBorrow[msg.sender] += _totalRewards;

        uint256 _rewards = _totalRewards * _feeDevTreasure / uint256(10000 - _fee.operators);
        uint256 denom = _getTotalPooledKSM()  - _rewards;
        uint256 shares2mint = _getTotalPooledKSM();
        if (denom > 0) shares2mint = _rewards * _getTotalShares() / denom;

        _mintShares(treasury, shares2mint);

        uint256 _devShares = shares2mint *  uint256(_fee.developers) / _feeDevTreasure;
        _transferShares(treasury, developers, _devShares);
        _emitTransferAfterMintingShares(developers, _devShares);
        _emitTransferAfterMintingShares(treasury, shares2mint - _devShares);

        emit Rewards(msg.sender, _totalRewards, _ledgerBalance);
    }

    /**
    * @notice Distribute lossed by ledger, allowed to call only by ledger
    */
    function distributeLosses(uint256 _totalLosses, uint256 _ledgerBalance) external {
        require(ledgerByAddress[msg.sender], "LIDO: NOT_FROM_LEDGER");

        uint256 withdrawalBalance = IWithdrawal(WITHDRAWAL).totalBalanceForLosses();
        uint256 withdrawalPendingForClaiming = IWithdrawal(WITHDRAWAL).pendingForClaiming();
        uint256 withdrawalVKSMBalance = VKSM.balanceOf(WITHDRAWAL);
        // NOTE: VKSM balance that was "fasttracked" to Withdrawal can't receive slash
        uint256 virtualWithdrawalBalance = 0;
        if (withdrawalBalance + withdrawalPendingForClaiming > withdrawalVKSMBalance) {
            // NOTE: protection from ddos
            virtualWithdrawalBalance =
                withdrawalBalance - (withdrawalVKSMBalance - withdrawalPendingForClaiming);
        }

        // lidoPart = _totalLosses * lido_xcKSM_balance / sum_xcKSM_balance
        uint256 lidoPart = (_totalLosses * fundRaisedBalance) / (fundRaisedBalance + virtualWithdrawalBalance);

        fundRaisedBalance -= lidoPart;
        if ((_totalLosses - lidoPart) > 0) {
            IWithdrawal(WITHDRAWAL).ditributeLosses(_totalLosses - lidoPart);
        }

        // edge case when loss can be more than stake
        ledgerStake[msg.sender] -= ledgerStake[msg.sender] >= lidoPart ? lidoPart : ledgerStake[msg.sender];
        ledgerBorrow[msg.sender] -= _totalLosses;

        emit Losses(msg.sender, _totalLosses, _ledgerBalance);
    }

    /**
    * @notice Transfer vKSM from ledger to LIDO. Can be called only from ledger
    * @param _amount - amount of vKSM that should be transfered
    * @param _excess - excess of vKSM that was transfered
    */
    function transferFromLedger(uint256 _amount, uint256 _excess) external {
        require(ledgerByAddress[msg.sender], "LIDO: NOT_FROM_LEDGER");

        if (_excess > 0) { // some donations
            fundRaisedBalance += _excess; //just distribute it as rewards
            bufferedDeposits += _excess;
            VKSM.transferFrom(msg.sender, address(this), _excess);
        }

        ledgerBorrow[msg.sender] -= _amount;
        VKSM.transferFrom(msg.sender, WITHDRAWAL, _amount);
    }

    /**
    * @notice Transfer vKSM from LIDO to ledger. Can be called only from ledger
    * @param _amount - amount of transfered vKSM
    */
    function transferToLedger(uint256 _amount) external {
        require(ledgerByAddress[msg.sender], "LIDO: NOT_FROM_LEDGER");
        require(ledgerBorrow[msg.sender] + _amount <= ledgerStake[msg.sender], "LIDO: LEDGER_NOT_ENOUGH_STAKE");

        ledgerBorrow[msg.sender] += _amount;
        VKSM.transfer(msg.sender, _amount);
    }

    /**
    * @notice Flush stakes, allowed to call only by oracle master
    * @dev This method distributes buffered stakes between ledgers by soft manner
    */
    function flushStakes() external {
        require(msg.sender == ORACLE_MASTER, "LIDO: NOT_FROM_ORACLE_MASTER");

        IWithdrawal(WITHDRAWAL).newEra();
        _softRebalanceStakes();
    }

    /**
    * @notice Rebalance stake accross ledgers by soft manner.
    */
    function _softRebalanceStakes() internal {
        uint256 totalStakeExcess = 0;
        for (uint256 i = 0; i < enabledLedgers.length + disabledLedgers.length; ++i) {
            address ledgerAddr = i < enabledLedgers.length ? 
                enabledLedgers[i] : disabledLedgers[i - enabledLedgers.length];

            // consider an incorrect case when our records about the ledger are wrong:
            // the ledger's active stake > the ledger's total amount of funds
            if (ledgerStake[ledgerAddr] > ledgerBorrow[ledgerAddr]) {

                uint256 ledgerStakeExcess = ledgerStake[ledgerAddr] - ledgerBorrow[ledgerAddr];

                // new total stake excess <= the amount of funds that won't be sent to the ledgers
                if (totalStakeExcess + ledgerStakeExcess <= VKSM.balanceOf(address(this)) - bufferedDeposits) {
                    totalStakeExcess += ledgerStakeExcess;

                    // correcting the ledger's active stake record
                    ledgerStake[ledgerAddr] -= ledgerStakeExcess;
                }
            }
        }

        // the amount of funds to be sent to the ledgers should decrease the ledgers' stake excess
        bufferedDeposits += totalStakeExcess;

        if (bufferedDeposits > 0 || bufferedRedeems > 0) {
            // first try to distribute redeems accross disabled ledgers
            if (disabledLedgers.length > 0 && bufferedRedeems > 0) {
                bufferedRedeems = _processDisabledLedgers(bufferedRedeems);
            }

            // NOTE: if we have deposits and redeems in one era we need to send all possible xcKSMs to Withdrawal
            if (bufferedDeposits > 0 && bufferedRedeems > 0) {
                uint256 maxImmediateTransfer = bufferedDeposits > bufferedRedeems ? bufferedRedeems : bufferedDeposits;
                bufferedDeposits -= maxImmediateTransfer;
                bufferedRedeems -= maxImmediateTransfer;
                VKSM.transfer(WITHDRAWAL, maxImmediateTransfer);
            }

            // distribute remaining stakes and redeems accross enabled
            if (enabledLedgers.length > 0) {
                int256 stake = bufferedDeposits.toInt256() - bufferedRedeems.toInt256();
                if (stake != 0) {
                    _processEnabled(stake);
                }
                bufferedDeposits = 0;
                bufferedRedeems = 0;
            }
        }
    }

    /**
    * @notice Spread redeems accross disabled ledgers
    * @return remainingRedeems - redeems amount which didn't distributed
    */
    function _processDisabledLedgers(uint256 redeems) internal returns(uint256 remainingRedeems) {
        uint256 disabledLength = disabledLedgers.length;
        assert(disabledLength > 0);

        uint256 stakesSum = 0;
        uint256 actualRedeems = 0;

        for (uint256 i = 0; i < disabledLength; ++i) {
            if (!pausedledgers[disabledLedgers[i]]) {
                stakesSum += ledgerStake[disabledLedgers[i]];
            }
        }

        if (stakesSum == 0) return redeems;

        for (uint256 i = 0; i < disabledLength; ++i) {
            if (!pausedledgers[disabledLedgers[i]]) {
                uint256 currentStake = ledgerStake[disabledLedgers[i]];
                uint256 decrement = redeems * currentStake / stakesSum;
                decrement = decrement > currentStake ? currentStake : decrement;
                ledgerStake[disabledLedgers[i]] = currentStake - decrement;
                actualRedeems += decrement;
            }
        }

        return redeems - actualRedeems;
    }

    /**
    * @notice Distribute stakes and redeems accross enabled ledgers with relaxation
    * @dev this function should never mix bond/unbond
    */
    function _processEnabled(int256 _stake) internal {
        uint256 ledgersLength = enabledLedgers.length;
        assert(ledgersLength > 0);

        int256[] memory diffs = new int256[](ledgersLength);
        address[] memory ledgersCache = new address[](ledgersLength);
        int256[] memory ledgerStakesCache = new int256[](ledgersLength);
        // NOTE: cache can't be used, because it can be changed or not in algorithm
        uint256[] memory ledgerStakePrevious = new uint256[](ledgersLength);

        int256 activeDiffsSum = 0;
        int256 totalChange = 0;
        int256 preciseDiffSum = 0;

        {
            uint256 targetStake = getTotalPooledKSM() / ledgersLength;
            int256 diff = 0;
            for (uint256 i = 0; i < ledgersLength; ++i) {
                ledgersCache[i] = enabledLedgers[i];
                ledgerStakesCache[i] = int256(ledgerStake[ledgersCache[i]]);
                ledgerStakePrevious[i] = ledgerStake[ledgersCache[i]];

                diff = int256(targetStake) - int256(ledgerStakesCache[i]);
                if (_stake * diff > 0) {
                    activeDiffsSum += diff;
                }
                diffs[i] = diff;
                preciseDiffSum += diff;
            }
        }

        if (preciseDiffSum == 0 || activeDiffsSum == 0) {
            return;
        }

        int8 direction = 1;
        if (activeDiffsSum < 0) {
            direction = -1;
            activeDiffsSum = -activeDiffsSum;
        }

        for (uint256 i = 0; i < ledgersLength; ++i) {
            diffs[i] *= direction;
            if (diffs[i] > 0) {
                int256 change = diffs[i] * _stake / activeDiffsSum;
                int256 newStake = ledgerStakesCache[i] + change;
                ledgerStake[ledgersCache[i]] = uint256(newStake);
                ledgerStakesCache[i] = newStake;
                totalChange += change;
            }
        }

        {
            int256 remaining = _stake - totalChange;
            if (remaining > 0) {
                // just add to first ledger
                ledgerStake[ledgersCache[0]] += uint256(remaining);
            }
            else if (remaining < 0) {
                for (uint256 i = 0; i < ledgersLength && remaining < 0; ++i) {
                    uint256 stake = uint256(ledgerStakesCache[i]);
                    if (stake > 0) {
                        uint256 decrement = stake > uint256(-remaining) ? uint256(-remaining) : stake;
                        ledgerStake[ledgersCache[i]] -= decrement;
                        remaining += int256(decrement);
                    }
                }
            }
        }

        // NOTE: this check used to catch cases when one user redeem some funds and another deposit in next era
        // so ledgers stake would increase and they return less xcKSMs and remaining funds would be locked on Lido
        uint256 freeToTransferFunds = 0;
        for (uint256 i = 0; i < ledgersLength; ++i) {
            // NOTE: protection from double sending of funds
            uint256 updatedLedgerBorrow = ledgerBorrow[ledgersCache[i]] - uint256(ILedger(ledgersCache[i]).transferDownwardBalance());
            if (
                // NOTE: this means that we wait transfer from ledger
                updatedLedgerBorrow > ledgerStakePrevious[i] &&
                // NOTE: and new deposits increase ledger stake
                ledgerStake[ledgersCache[i]] > ledgerStakePrevious[i]
                ) {
                    freeToTransferFunds += 
                        ledgerStake[ledgersCache[i]] > updatedLedgerBorrow ? 
                        updatedLedgerBorrow - ledgerStakePrevious[i] :
                        ledgerStake[ledgersCache[i]] - ledgerStakePrevious[i];
            }
        }

        if (freeToTransferFunds > 0) {
            VKSM.transfer(WITHDRAWAL, uint256(freeToTransferFunds));
        }
    }

    /**
    * @notice Set new minimum balance for ledger
    * @param _minNominatorBalance - new minimum nominator balance
    * @param _minimumBalance - new minimum active balance for ledger
    * @param _maxUnlockingChunks - new maximum unlocking chunks
    */
    function _updateLedgerRelaySpecs(uint128 _minNominatorBalance, uint128 _minimumBalance, uint256 _maxUnlockingChunks) internal {
        for (uint i = 0; i < enabledLedgers.length + disabledLedgers.length; i++) {
            address ledgerAddress = i < enabledLedgers.length ?
                enabledLedgers[i] : disabledLedgers[i - enabledLedgers.length];
            ILedger(ledgerAddress).setRelaySpecs(_minNominatorBalance, _minimumBalance, _maxUnlockingChunks);
        }
    }

    /**
    * @notice Disable ledger
    * @dev That method put ledger to "draining" mode, after ledger drained it can be removed
    * @param _ledgerAddress - target ledger address
    */
    function _disableLedger(address _ledgerAddress) internal {
        require(ledgerByAddress[_ledgerAddress], "LIDO: LEDGER_NOT_FOUND");
        uint256 ledgerIdx = _findLedger(_ledgerAddress, true);
        require(ledgerIdx != type(uint256).max, "LIDO: LEDGER_NOT_ENABLED");

        address lastLedger = enabledLedgers[enabledLedgers.length - 1];
        enabledLedgers[ledgerIdx] = lastLedger;
        enabledLedgers.pop();

        disabledLedgers.push(_ledgerAddress);

        emit LedgerDisable(_ledgerAddress);
    }

    /**
    * @notice Emits an {Transfer} event where from is 0 address. Indicates mint events.
    */
    function _emitTransferAfterMintingShares(address _to, uint256 _sharesAmount) internal {
        emit Transfer(address(0), _to, getPooledKSMByShares(_sharesAmount));
    }

    /**
    * @notice Returns amount of total pooled tokens by contract.
    * @return amount of pooled vKSM in contract
    */
    function _getTotalPooledKSM() internal view override returns (uint256) {
        return fundRaisedBalance;
    }

    /**
    * @notice Returns enabled or disabled ledger index by given address
    * @return enabled or disabled ledger index or uint256_max if not found
    */
    function _findLedger(address _ledgerAddress, bool _enabled) internal view returns(uint256) {
        uint256 length = _enabled ? enabledLedgers.length : disabledLedgers.length;
        for (uint256 i = 0; i < length; ++i) {
            address ledgerAddress = _enabled ? enabledLedgers[i] : disabledLedgers[i];
            if (ledgerAddress == _ledgerAddress) {
                return i;
            }
        }
        return type(uint256).max;
    }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 3 of 14 : SafeCast.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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);
    }
}

File 4 of 14 : Initializable.sol
// SPDX-License-Identifier: MIT

// solhint-disable-next-line compiler-version
pragma solidity ^0.8.0;

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

    /**
     * @dev Indicates that the contract has been initialized.
     */
    bool private _initialized;

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

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

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

        _;

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

File 5 of 14 : IOracleMaster.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IOracleMaster {
    function addLedger(address ledger) external;

    function removeLedger(address ledger) external;

    function getOracle(address ledger) view external returns (address);

    function eraId() view external returns (uint64);

    function setLido(address lido) external;
}

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

interface ILedgerFactory {
    function createLedger(
        bytes32 _stashAccount,
        bytes32 _controllerAccount,
        address _vKSM,
        address _controller,
        uint128 _minNominatorBalance,
        uint128 _minimumBalance,
        uint256 _maxUnlockingChunks
    ) external returns (address);
}

File 7 of 14 : ILedger.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "Types.sol";

interface ILedger {
    function initialize(
        bytes32 _stashAccount,
        bytes32 controllerAccount,
        address vKSM,
        address controller,
        uint128 minNominatorBalance,
        address lido,
        uint128 _minimumBalance,
        uint256 _maxUnlockingChunks
    ) external;

    function pushData(uint64 eraId, Types.OracleData calldata staking) external;

    function nominate(bytes32[] calldata validators) external;

    function status() external view returns (Types.LedgerStatus);

    function isEmpty() external view returns (bool);

    function stashAccount() external view returns (bytes32);

    function totalBalance() external view returns (uint128);

    function setRelaySpecs(uint128 minNominatorBalance, uint128 minimumBalance, uint256 _maxUnlockingChunks) external;

    function cachedTotalBalance() external view returns (uint128);

    function transferDownwardBalance() external view returns (uint128);
}

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

interface Types {
    struct Fee{
        uint16 total;
        uint16 operators;
        uint16 developers;
        uint16 treasury;
    }

    struct Stash {
        bytes32 stashAccount;
        uint64  eraId;
    }

    enum LedgerStatus {
        // bonded but not participate in staking
        Idle,
        // participate as nominator
        Nominator,
        // participate as validator
        Validator,
        // not bonded not participate in staking
        None
    }

    struct UnlockingChunk {
        uint128 balance;
        uint64 era;
    }

    struct OracleData {
        bytes32 stashAccount;
        bytes32 controllerAccount;
        LedgerStatus stakeStatus;
        // active part of stash balance
        uint128 activeBalance;
        // locked for stake stash balance.
        uint128 totalBalance;
        // totalBalance = activeBalance + sum(unlocked.balance)
        UnlockingChunk[] unlocking;
        uint32[] claimedRewards;
        // stash account balance. It includes locked (totalBalance) balance assigned
        // to a controller.
        uint128 stashBalance;
        // slashing spans for ledger
        uint32 slashingSpans;
    }

    struct RelaySpec {
        uint16 maxValidatorsPerLedger;
        uint128 minNominatorBalance;
        uint128 ledgerMinimumActiveBalance;
        uint256 maxUnlockingChunks;
    }
}

File 9 of 14 : IController.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;


interface IController {
    function newSubAccount(uint16 index, bytes32 accountId, address paraAddress) external;

    function deleteSubAccount(address paraAddress) external;

    function nominate(bytes32[] calldata _validators) external;

    function bond(bytes32 controller, uint256 amount) external;

    function bondExtra(uint256 amount) external;

    function unbond(uint256 amount) external;

    function withdrawUnbonded(uint32 slashingSpans) external;

    function rebond(uint256 amount, uint256 unbondingChunks) external;

    function chill() external;

    function transferToParachain(uint256 amount) external;

    function transferToRelaychain(uint256 amount) external;
}

File 10 of 14 : IAuthManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IAuthManager {
    function has(bytes32 role, address member) external view returns (bool);

    function add(bytes32 role, address member) external;

    function remove(bytes32 role, address member) external;
}

File 11 of 14 : IWithdrawal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IWithdrawal {
    // total virtual xcKSM amount on contract
    function totalVirtualXcKSMAmount() external returns (uint256);

    // Set stKSM contract address, allowed to only once
    function setStKSM(address _stKSM) external;

    // Returns total virtual xcKSM balance of contract for which losses can be applied
    function totalBalanceForLosses() external view returns (uint256);

    // Returns total xcKSM balance of contract which waiting for claim
    function pendingForClaiming() external view returns (uint256);

    // Burn pool shares from first element of queue and move index for allow claiming. After that add new batch
    function newEra() external;

    // Mint equal amount of pool shares for user. Adjust current amount of virtual xcKSM on Withdrawal contract.
    // Burn shares on LIDO side
    function redeem(address _from, uint256 _amount) external;

    // Returns available for claiming xcKSM amount for user
    function claim(address _holder) external returns (uint256);

    // Apply losses to current stKSM shares on this contract
    function ditributeLosses(uint256 _losses) external;

    // Check available for claim xcKSM balance for user
    function getRedeemStatus(address _holder) external view returns(uint256 _waiting, uint256 _available);
}

File 12 of 14 : stKSM.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "IERC20.sol";
import "Pausable.sol";

abstract contract stKSM is IERC20, Pausable {

    /**
     * @dev stKSM balances are dynamic and are calculated based on the accounts' shares
     * and the total amount of KSM controlled by the protocol. Account shares aren't
     * normalized, so the contract also stores the sum of all shares to calculate
     * each account's token balance which equals to:
     *
     *   shares[account] * _getTotalPooledKSM() / _getTotalShares()
    */
    mapping (address => uint256) private shares;

    /**
     * @dev Allowances are nominated in tokens, not token shares.
     */
    mapping (address => mapping (address => uint256)) private allowances;

    /**
     * @dev Storage position used for holding the total amount of shares in existence.
     */
    uint256 internal totalShares;

    /**
     * @return the amount of tokens in existence.
     *
     * @dev Always equals to `_getTotalPooledKSM()` since token amount
     * is pegged to the total amount of KSM controlled by the protocol.
     */
    function totalSupply() public view override returns (uint256) {
        return _getTotalPooledKSM();
    }

    /**
     * @return the entire amount of KSMs controlled by the protocol.
     *
     * @dev The sum of all KSM balances in the protocol.
     */
    function getTotalPooledKSM() public view returns (uint256) {
        return _getTotalPooledKSM();
    }

    /**
     * @return the amount of tokens owned by the `_account`.
     *
     * @dev Balances are dynamic and equal the `_account`'s share in the amount of the
     * total KSM controlled by the protocol. See `sharesOf`.
     */
    function balanceOf(address _account) public view override returns (uint256) {
        return getPooledKSMByShares(_sharesOf(_account));
    }

    /**
     * @notice Moves `_amount` tokens from the caller's account to the `_recipient` account.
     *
     * @return a boolean value indicating whether the operation succeeded.
     * Emits a `Transfer` event.
     *
     * Requirements:
     *
     * - `_recipient` cannot be the zero address.
     * - the caller must have a balance of at least `_amount`.
     * - the contract must not be paused.
     *
     * @dev The `_amount` argument is the amount of tokens, not shares.
     */
    function transfer(address _recipient, uint256 _amount) public override returns (bool) {
        _transfer(msg.sender, _recipient, _amount);
        return true;
    }

    /**
     * @return the remaining number of tokens that `_spender` is allowed to spend
     * on behalf of `_owner` through `transferFrom`. This is zero by default.
     *
     * @dev This value changes when `approve` or `transferFrom` is called.
     */
    function allowance(address _owner, address _spender) public view override returns (uint256) {
        return allowances[_owner][_spender];
    }

    /**
     * @notice Sets `_amount` as the allowance of `_spender` over the caller's tokens.
     *
     * @return a boolean value indicating whether the operation succeeded.
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `_spender` cannot be the zero address.
     * - the contract must not be paused.
     *
     * @dev The `_amount` argument is the amount of tokens, not shares.
     */
    function approve(address _spender, uint256 _amount) public override returns (bool) {
        _approve(msg.sender, _spender, _amount);
        return true;
    }

    /**
     * @notice Moves `_amount` tokens from `_sender` to `_recipient` using the
     * allowance mechanism. `_amount` is then deducted from the caller's
     * allowance.
     *
     * @return a boolean value indicating whether the operation succeeded.
     *
     * Emits a `Transfer` event.
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `_sender` and `_recipient` cannot be the zero addresses.
     * - `_sender` must have a balance of at least `_amount`.
     * - the caller must have allowance for `_sender`'s tokens of at least `_amount`.
     * - the contract must not be paused.
     *
     * @dev The `_amount` argument is the amount of tokens, not shares.
     */
    function transferFrom(address _sender, address _recipient, uint256 _amount) public override returns (bool) {
        uint256 currentAllowance = allowances[_sender][msg.sender];
        require(currentAllowance >= _amount, "TRANSFER_AMOUNT_EXCEEDS_ALLOWANCE");

        _transfer(_sender, _recipient, _amount);
        _approve(_sender, msg.sender, currentAllowance -_amount);
        return true;
    }

    /**
     * @notice Atomically increases the allowance granted to `_spender` by the caller by `_addedValue`.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in:
     * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `_spender` cannot be the the zero address.
     * - the contract must not be paused.
     */
    function increaseAllowance(address _spender, uint256 _addedValue) public returns (bool) {
        _approve(msg.sender, _spender, allowances[msg.sender][_spender] + _addedValue);
        return true;
    }

    /**
     * @notice Atomically decreases the allowance granted to `_spender` by the caller by `_subtractedValue`.
     *
     * This is an alternative to `approve` that can be used as a mitigation for
     * problems described in:
     * https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/IERC20.sol#L42
     * Emits an `Approval` event indicating the updated allowance.
     *
     * Requirements:
     *
     * - `_spender` cannot be the zero address.
     * - `_spender` must have allowance for the caller of at least `_subtractedValue`.
     * - the contract must not be paused.
     */
    function decreaseAllowance(address _spender, uint256 _subtractedValue) public returns (bool) {
        uint256 currentAllowance = allowances[msg.sender][_spender];
        require(currentAllowance >= _subtractedValue, "DECREASED_ALLOWANCE_BELOW_ZERO");
        _approve(msg.sender, _spender, currentAllowance-_subtractedValue);
        return true;
    }

    /**
     * @return the total amount of shares in existence.
     *
     * @dev The sum of all accounts' shares can be an arbitrary number, therefore
     * it is necessary to store it in order to calculate each account's relative share.
     */
    function getTotalShares() public view returns (uint256) {
        return _getTotalShares();
    }

    /**
     * @return the amount of shares owned by `_account`.
     */
    function sharesOf(address _account) public view returns (uint256) {
        return _sharesOf(_account);
    }

    /**
     * @return the amount of shares that corresponds to `_ethAmount` protocol-controlled KSM.
     */
    function getSharesByPooledKSM(uint256 _amount) public view returns (uint256) {
        uint256 totalPooledKSM = _getTotalPooledKSM();
        if (totalPooledKSM == 0) {
            return 0;
        } else {
            return _amount * _getTotalShares() / totalPooledKSM;
        }
    }

    /**
     * @return the amount of KSM that corresponds to `_sharesAmount` token shares.
     */
    function getPooledKSMByShares(uint256 _sharesAmount) public view returns (uint256) {
        uint256 _totalShares = _getTotalShares();
        if (totalShares == 0) {
            return 0;
        } else {
            return _sharesAmount * _getTotalPooledKSM() / _totalShares;
        }
    }

    /**
     * @return the total amount (in wei) of KSM controlled by the protocol.
     * @dev This is used for calaulating tokens from shares and vice versa.
     * @dev This function is required to be implemented in a derived contract.
     */
    function _getTotalPooledKSM() internal view virtual returns (uint256);

    /**
     * @notice Moves `_amount` tokens from `_sender` to `_recipient`.
     * Emits a `Transfer` event.
     */
    function _transfer(address _sender, address _recipient, uint256 _amount) internal {
        uint256 _sharesToTransfer = getSharesByPooledKSM(_amount);
        _transferShares(_sender, _recipient, _sharesToTransfer);
        emit Transfer(_sender, _recipient, _amount);
    }

    /**
     * @notice Sets `_amount` as the allowance of `_spender` over the `_owner` s tokens.
     *
     * Emits an `Approval` event.
     *
     * Requirements:
     *
     * - `_owner` cannot be the zero address.
     * - `_spender` cannot be the zero address.
     * - the contract must not be paused.
     */
    function _approve(address _owner, address _spender, uint256 _amount) internal whenNotPaused {
        require(_owner != address(0), "APPROVE_FROM_ZERO_ADDRESS");
        require(_spender != address(0), "APPROVE_TO_ZERO_ADDRESS");

        allowances[_owner][_spender] = _amount;
        emit Approval(_owner, _spender, _amount);
    }

    /**
     * @return the total amount of shares in existence.
     */
    function _getTotalShares() internal view returns (uint256) {
        return totalShares;
    }

    /**
     * @return the amount of shares owned by `_account`.
     */
    function _sharesOf(address _account) internal view returns (uint256) {
        return shares[_account];
    }

    /**
     * @notice Moves `_sharesAmount` shares from `_sender` to `_recipient`.
     *
     * Requirements:
     *
     * - `_sender` cannot be the zero address.
     * - `_recipient` cannot be the zero address.
     * - `_sender` must hold at least `_sharesAmount` shares.
     * - the contract must not be paused.
     */
    function _transferShares(address _sender, address _recipient, uint256 _sharesAmount) internal whenNotPaused {
        require(_sender != address(0), "TRANSFER_FROM_THE_ZERO_ADDRESS");
        require(_recipient != address(0), "TRANSFER_TO_THE_ZERO_ADDRESS");

        uint256 currentSenderShares = shares[_sender];
        require(_sharesAmount <= currentSenderShares, "TRANSFER_AMOUNT_EXCEEDS_BALANCE");

        shares[_sender] = currentSenderShares - _sharesAmount;
        shares[_recipient] = shares[_recipient] + _sharesAmount;
    }

    /**
     * @notice Creates `_sharesAmount` shares and assigns them to `_recipient`, increasing the total amount of shares.
     * @dev This doesn't increase the token total supply.
     *
     * Requirements:
     *
     * - `_recipient` cannot be the zero address.
     * - the contract must not be paused.
     */
    function _mintShares(address _recipient, uint256 _sharesAmount) internal whenNotPaused returns (uint256 newTotalShares) {
        require(_recipient != address(0), "MINT_TO_THE_ZERO_ADDRESS");

        newTotalShares = _getTotalShares() + _sharesAmount;
        totalShares = newTotalShares;

        shares[_recipient] = shares[_recipient] + _sharesAmount;

        // Notice: we're not emitting a Transfer event from the zero address here since shares mint
        // works by taking the amount of tokens corresponding to the minted shares from all other
        // token holders, proportionally to their share. The total supply of the token doesn't change
        // as the result. This is equivalent to performing a send from each other token holder's
        // address to `address`, but we cannot reflect this as it would require sending an unbounded
        // number of events.
    }

    /**
     * @notice Destroys `_sharesAmount` shares from `_account`'s holdings, decreasing the total amount of shares.
     * @dev This doesn't decrease the token total supply.
     *
     * Requirements:
     *
     * - `_account` cannot be the zero address.
     * - `_account` must hold at least `_sharesAmount` shares.
     * - the contract must not be paused.
     */
    function _burnShares(address _account, uint256 _sharesAmount) internal whenNotPaused returns (uint256 newTotalShares) {
        require(_account != address(0), "BURN_FROM_THE_ZERO_ADDRESS");

        uint256 accountShares = shares[_account];
        require(_sharesAmount <= accountShares, "BURN_AMOUNT_EXCEEDS_BALANCE");

        newTotalShares = _getTotalShares() - _sharesAmount;
        totalShares = newTotalShares;

        shares[_account] = accountShares - _sharesAmount;

        // Notice: we're not emitting a Transfer event to the zero address here since shares burn
        // works by redistributing the amount of tokens corresponding to the burned shares between
        // all other token holders. The total supply of the token doesn't change as the result.
        // This is equivalent to performing a send from `address` to each other token holder address,
        // but we cannot reflect this as it would require sending an unbounded number of events.
    }
}

File 13 of 14 : Pausable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import "Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    bool private _paused;

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor () {
        _paused = false;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        require(!paused(), "Pausable: paused");
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        require(paused(), "Pausable: not paused");
        _;
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

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

pragma solidity ^0.8.0;

/*
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
        return msg.data;
    }
}

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

Contract Security Audit

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Claimed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Deposited","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"fee","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"feeOperatorsBP","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"feeTreasuryBP","type":"uint16"},{"indexed":false,"internalType":"uint16","name":"feeDevelopersBP","type":"uint16"}],"name":"FeeSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"},{"indexed":false,"internalType":"bytes32","name":"stashAccount","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"controllerAccount","type":"bytes32"}],"name":"LedgerAdd","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"LedgerDisable","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"LedgerPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"LedgerRemove","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"addr","type":"address"}],"name":"LedgerResumed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ledger","type":"address"},{"indexed":false,"internalType":"uint256","name":"losses","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Losses","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Redeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"userAddr","type":"address"},{"indexed":false,"internalType":"address","name":"referralAddr","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"shares","type":"uint256"}],"name":"Referral","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ledger","type":"address"},{"indexed":false,"internalType":"uint256","name":"rewards","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"balance","type":"uint256"}],"name":"Rewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"inputs":[],"name":"AUTH_MANAGER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEDGER_BEACON","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_ALLOWABLE_DIFFERENCE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ORACLE_MASTER","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_stashAccount","type":"bytes32"},{"internalType":"bytes32","name":"_controllerAccount","type":"bytes32"},{"internalType":"uint16","name":"_index","type":"uint16"}],"name":"addLedger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bufferedDeposits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"bufferedRedeems","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimUnbonded","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"address","name":"_referral","type":"address"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"deposit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"depositCap","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerAddress","type":"address"}],"name":"disableLedger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalLosses","type":"uint256"},{"internalType":"uint256","name":"_ledgerBalance","type":"uint256"}],"name":"distributeLosses","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_totalRewards","type":"uint256"},{"internalType":"uint256","name":"_ledgerBalance","type":"uint256"}],"name":"distributeRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerAddress","type":"address"}],"name":"emergencyPauseLedger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_stashAccount","type":"bytes32"}],"name":"findLedger","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flushStakes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"fundRaisedBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLedgerAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_sharesAmount","type":"uint256"}],"name":"getPooledKSMByShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"getSharesByPooledKSM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStashAccounts","outputs":[{"internalType":"bytes32[]","name":"","type":"bytes32[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalPooledKSM","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalShares","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_holder","type":"address"}],"name":"getUnbonded","outputs":[{"internalType":"uint256","name":"waiting","type":"uint256"},{"internalType":"uint256","name":"unbonded","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_authManager","type":"address"},{"internalType":"address","name":"_vKSM","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"address","name":"_developers","type":"address"},{"internalType":"address","name":"_treasury","type":"address"},{"internalType":"address","name":"_oracleMaster","type":"address"},{"internalType":"address","name":"_withdrawal","type":"address"},{"internalType":"uint256","name":"_depositCap","type":"uint256"},{"internalType":"uint128","name":"_maxAllowableDifference","type":"uint128"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ledgerBorrow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"ledgerStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_stashAccounts","type":"bytes32[]"},{"internalType":"bytes32[][]","name":"_validators","type":"bytes32[][]"}],"name":"nominateBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"redeem","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerAddress","type":"address"}],"name":"removeLedger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"resume","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerAddress","type":"address"}],"name":"resumeLedger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_depositCap","type":"uint256"}],"name":"setDepositCap","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_developers","type":"address"}],"name":"setDevelopers","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"_feeOperators","type":"uint16"},{"internalType":"uint16","name":"_feeTreasury","type":"uint16"},{"internalType":"uint16","name":"_feeDevelopers","type":"uint16"}],"name":"setFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerBeacon","type":"address"}],"name":"setLedgerBeacon","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_ledgerFactory","type":"address"}],"name":"setLedgerFactory","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_maxAllowableDifference","type":"uint128"}],"name":"setMaxAllowableDifference","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"maxValidatorsPerLedger","type":"uint16"},{"internalType":"uint128","name":"minNominatorBalance","type":"uint128"},{"internalType":"uint128","name":"ledgerMinimumActiveBalance","type":"uint128"},{"internalType":"uint256","name":"maxUnlockingChunks","type":"uint256"}],"internalType":"struct Types.RelaySpec","name":"_relaySpec","type":"tuple"}],"name":"setRelaySpec","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_account","type":"address"}],"name":"sharesOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_sender","type":"address"},{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_excess","type":"uint256"}],"name":"transferFromLedger","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"transferToLedger","outputs":[],"stateMutability":"nonpayable","type":"function"}]

608060405234801561001057600080fd5b506000805460ff19169055615d9e806200002b6000396000f3fe608060405234801561001057600080fd5b50600436106102935760003560e01c8063046f7da21461029857806306fdde03146102a2578063095ea7b3146102c057806318160ddd146102e35780631a813a3c146102f95780631ab81cba146103015780631d55fde41461031457806323b872dd14610329578063240359bc1461033c578063313ce5671461037257806338dee1d314610387578063395093511461039a5780633ca3bca3146103ad5780633fd2c16a146103c057806341c262c5146103d357806347376473146103e657806348c696c0146103f95780634fe28e3a146104025780635c975abb146104155780635e442a9b146104205780635f3f2cac1461044057806361f9c3da1461045357806363ca402d146104665780636a92b586146104795780636e553f65146104a457806370a08231146104b757806373ece435146104ca57806377c96574146104dd5780638456cb5914610505578063866512031461050d5780638ab476bf1461052057806395d89b41146105335780639e0c97041461053b578063a1e206c71461054e578063a457c2d714610561578063a9042441146102e3578063a9059cbb14610574578063b09f532014610587578063b31207f214610590578063b6b55f25146105a3578063cdd8f598146105b6578063d381787a146105c9578063d5002f2e146105dc578063db006a75146105e4578063dbd5edc7146105f7578063dd62ed3e14610600578063df19795614610639578063df6c39fb1461064e578063e100610714610661578063e40b925514610674578063ec70d8001461067d578063f0f4426014610690578063f1447195146106a3578063f339a70d146106c3578063f5eb42dc146106d6578063f7eba420146106e9578063fa597e07146106fc575b600080fd5b6102a0610704565b005b6102aa6107b5565b6040516102b791906152cb565b60405180910390f35b6102d36102ce366004615335565b610847565b60405190151581526020016102b7565b6102eb61085e565b6040519081526020016102b7565b6102a061086e565b6102a061030f366004615361565b610940565b61031c610a9b565b6040516102b7919061537e565b6102d36103373660046153c2565b610c17565b61036561034a366004615403565b6000908152601b60205260409020546001600160a01b031690565b6040516102b7919061541c565b60215460405160ff90911681526020016102b7565b6102a0610395366004615430565b610cbf565b6102d36103a8366004615335565b610e6f565b6102a06103bb366004615457565b610ea6565b601154610365906001600160a01b031681565b6102a06103e1366004615555565b61134f565b6102a06103f4366004615361565b61161b565b6102eb60075481565b6103656104103660046155d0565b611731565b60005460ff166102d3565b6102eb61042e366004615361565b60096020526000908152604090205481565b6102a061044e366004615609565b611bd9565b6102a0610461366004615626565b611d03565b6102eb610474366004615403565b611e86565b601a5461048c906001600160801b031681565b6040516001600160801b0390911681526020016102b7565b6102eb6104b2366004615648565b611ecd565b6102eb6104c5366004615361565b611f33565b6102a06104d8366004615678565b611f41565b6104f06104eb366004615361565b61214b565b604080519283526020830191909152016102b7565b6102a06121c9565b6102a061051b366004615403565b61226e565b6102a061052e366004615361565b61235b565b6102aa61248e565b6102a0610549366004615626565b61249d565b600f54610365906001600160a01b031681565b6102d361056f366004615335565b6127d6565b6102d3610582366004615335565b612863565b6102eb60065481565b6102eb61059e366004615403565b612870565b6102eb6105b1366004615403565b612896565b6102a06105c4366004615361565b6128a1565b6102a06105d7366004615361565b61299a565b6102eb612e79565b6102a06105f2366004615403565b612e84565b6102eb600c5481565b6102eb61060e3660046156b8565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b61064161305d565b6040516102b791906156e6565b6102a061065c366004615626565b613178565b6102a061066f366004615403565b6133b7565b6102eb60055481565b601754610365906001600160a01b031681565b6102a061069e366004615361565b6134f4565b6102eb6106b1366004615361565b60086020526000908152604090205481565b6102a06106d1366004615361565b61361c565b6102eb6106e4366004615361565b6136c2565b6102a06106f7366004615361565b6136cd565b6102a06137e3565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906107449084903390600401615727565b602060405180830381865afa158015610761573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610785919061573e565b6107aa5760405162461bcd60e51b81526004016107a190615760565b60405180910390fd5b6107b26138ae565b50565b6060601f80546107c49061578c565b80601f01602080910402602001604051908101604052809291908181526020018280546107f09061578c565b801561083d5780601f106108125761010080835404028352916020019161083d565b820191906000526020600020905b81548152906001019060200180831161082057829003601f168201915b5050505050905090565b600061085433848461393b565b5060015b92915050565b600061086960055490565b905090565b60005460ff16156108915760405162461bcd60e51b81526004016107a1906157c1565b601954604051630f41a04d60e11b81526000916001600160a01b031690631e83409a906108c290339060040161541c565b6020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906157eb565b60405181815290915033907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a250565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906109809084903390600401615727565b602060405180830381865afa15801561099d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c1919061573e565b6109dd5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166000908152601d602052604090205460ff16610a3f5760405162461bcd60e51b815260206004820152601760248201527613125113ce8813115111d15497d393d517d4105554d151604a1b60448201526064016107a1565b6001600160a01b0382166000908152601d602052604090819020805460ff19169055517f8c097d4c8d964b147a04f3a822a31e3aa5a9104dc7db3dde0166a248b8f106c590610a8f90849061541c565b60405180910390a15050565b600a54600b54606091600091610ab1919061581a565b6001600160401b03811115610ac857610ac8615832565b604051908082528060200260200182016040528015610af1578160200160208202803683370190505b50905060005b600a54600b54610b07919061581a565b811015610c1157600b546000908210610b5457600b54600a90610b2a9084615848565b81548110610b3a57610b3a61585f565b6000918252602090912001546001600160a01b0316610b7d565b600b8281548110610b6757610b6761585f565b6000918252602090912001546001600160a01b03165b9050806001600160a01b031663231aebf26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be191906157eb565b838381518110610bf357610bf361585f565b60209081029190910101525080610c0981615875565b915050610af7565b50919050565b6001600160a01b038316600090815260026020908152604080832033845290915281205482811015610c955760405162461bcd60e51b815260206004820152602160248201527f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e436044820152604560f81b60648201526084016107a1565b610ca0858585613a61565b610cb48533610caf8685615848565b61393b565b506001949350505050565b600f54604051633bfc46cb60e21b81527f2c204f3ef59cc164f843cf6919920470e37721ba425db7893d02e60cfd0bafdc916001600160a01b03169063eff11b2c90610d119084903390600401615727565b602060405180830381865afa158015610d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d52919061573e565b610d6e5760405162461bcd60e51b81526004016107a190615760565b6000610d7d6020840184615890565b61ffff1611610dda5760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a204241445f4d41585f56414c494441544f52535f5045525f4c454460448201526223a2a960e91b60648201526084016107a1565b6000826060013511610e2e5760405162461bcd60e51b815260206004820152601e60248201527f4c49444f3a204241445f4d41585f554e4c4f434b494e475f4348554e4b53000060448201526064016107a1565b816012610e3b82826158ad565b50610e6b9050610e516040840160208501615609565b610e616060850160408601615609565b8460600135613aba565b5050565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610854918590610caf90869061581a565b600454610100900460ff1680610ebf575060045460ff16155b610f225760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107a1565b600454610100900460ff16158015610f44576004805461ffff19166101011790555b60008311610f855760405162461bcd60e51b815260206004820152600e60248201526d04c49444f3a205a45524f5f4341560941b60448201526064016107a1565b6001600160a01b038916610fda5760405162461bcd60e51b815260206004820152601c60248201527b4c49444f3a20494e434f52524543545f564b534d5f4144445245535360201b60448201526064016107a1565b6001600160a01b03851661103e5760405162461bcd60e51b815260206004820152602560248201527f4c49444f3a20494e434f52524543545f4f5241434c455f4d41535445525f4144604482015264445245535360d81b60648201526084016107a1565b6001600160a01b03841661109f5760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f5749544844524157414c5f4144445245604482015261535360f01b60648201526084016107a1565b6001600160a01b038a166111015760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a20494e434f52524543545f415554484d414e414745525f4144445260448201526245535360e81b60648201526084016107a1565b6001600160a01b0388166111625760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f434f4e54524f4c4c45525f4144445245604482015261535360f01b60648201526084016107a1565b600d80546001600160a01b03808c166001600160a01b031992831617909255600e80548b8416908316179055600f8054928d1692909116919091179055600c83905560c86010556111b16152a4565b6103206111c060c8600061593a565b6111ca919061593a565b61ffff168082526000602083015260c86040808401919091526103206060840152601e805465ffffffffffff1916909217601960231b1761ffff60301b1916601960351b17909155601680546001600160a01b03199081166001600160a01b038b8116919091179092556015805482168c84161790556011805490911691891691821790559051637d774e3160e01b8152637d774e319061126f90309060040161541c565b600060405180830381600087803b15801561128957600080fd5b505af115801561129d573d6000803e3d6000fd5b5050601980546001600160a01b0319166001600160a01b03891690811790915560405163015cda1760e41b81529092506315cda17091506112e290309060040161541c565b600060405180830381600087803b1580156112fc57600080fd5b505af1158015611310573d6000803e3d6000fd5b5050601a80546001600160801b0319166001600160801b038716179055505081159050611343576004805461ff00191690555b50505050505050505050565b600f54604051633bfc46cb60e21b81527fdefdc47e8c8311059971baa7eda778fd22d6ea93a75a917e77534b8ce74fe4f9916001600160a01b03169063eff11b2c906113a19084903390600401615727565b602060405180830381865afa1580156113be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e2919061573e565b6113fe5760405162461bcd60e51b81526004016107a190615760565b8382146114455760405162461bcd60e51b815260206004820152601560248201527413125113ce88125390d3d4949150d517d253941555605a1b60448201526064016107a1565b60005b84811015611613576000601b818888858181106114675761146761585f565b60209081029290920135835250810191909152604001600020546001600160a01b031614156114d65760405162461bcd60e51b815260206004820152601b60248201527a13125113ce88155392d393d5d397d4d51054d217d050d0d3d55395602a1b60448201526064016107a1565b60125461ffff168484838181106114ef576114ef61585f565b90506020028101906115019190615960565b905011156115515760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a2056414c494441544f52535f414d4f554e545f544f4f5f4249470060448201526064016107a1565b601b60008787848181106115675761156761585f565b60209081029290920135835250810191909152604001600020546001600160a01b031663f5330e968585848181106115a1576115a161585f565b90506020028101906115b39190615960565b6040518363ffffffff1660e01b81526004016115d09291906159a9565b600060405180830381600087803b1580156115ea57600080fd5b505af11580156115fe573d6000803e3d6000fd5b505050508061160c90615875565b9050611448565b505050505050565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c9061165b9084903390600401615727565b602060405180830381865afa158015611678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169c919061573e565b6116b85760405162461bcd60e51b81526004016107a190615760565b6001600160a01b03821661170e5760405162461bcd60e51b815260206004820152601e60248201527f4c49444f3a20494e434f52524543545f424541434f4e5f41444452455353000060448201526064016107a1565b50601780546001600160a01b0319166001600160a01b0392909216919091179055565b600f54604051633bfc46cb60e21b8152600091600080516020615ce9833981519152916001600160a01b039091169063eff11b2c906117769084903390600401615727565b602060405180830381865afa158015611793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b7919061573e565b6117d35760405162461bcd60e51b81526004016107a190615760565b6017546001600160a01b031661182b5760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a20554e5350454349464945445f4c45444745525f424541434f4e0060448201526064016107a1565b6018546001600160a01b03166118835760405162461bcd60e51b815260206004820181905260248201527f4c49444f3a20554e5350454349464945445f4c45444745525f464143544f525960448201526064016107a1565b6011546001600160a01b03166118d45760405162461bcd60e51b81526020600482015260166024820152752624a2279d102727afa7a920a1a622afa6a0a9aa22a960511b60448201526064016107a1565b601054600a54600b546118e7919061581a565b1061192f5760405162461bcd60e51b815260206004820152601860248201527713125113ce8813115111d15494d7d413d3d317d31253525560421b60448201526064016107a1565b6000858152601b60205260409020546001600160a01b0316156119915760405162461bcd60e51b815260206004820152601a6024820152794c49444f3a2053544153485f414c52454144595f45584953545360301b60448201526064016107a1565b601854600d54600e5460125460135460145460405163776aecef60e11b8152600481018c9052602481018b90526001600160a01b0395861660448201529385166064850152620100009092046001600160801b0390811660848501521660a483015260c4820152600092919091169063eed5d9de9060e4016020604051808303816000875af1158015611a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c91906159e5565b600b805460018181019092557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90180546001600160a01b038085166001600160a01b0319928316811790935560008b8152601b6020908152604080832080549095168617909455938152601c90935291819020805460ff191690931790925560115491516327c13a6b60e21b81529293501690639f04e9ac90611af390849060040161541c565b600060405180830381600087803b158015611b0d57600080fd5b505af1158015611b21573d6000803e3d6000fd5b5050600e54604051639632acf760e01b815261ffff88166004820152602481018a90526001600160a01b0385811660448301529091169250639632acf79150606401600060405180830381600087803b158015611b7d57600080fd5b505af1158015611b91573d6000803e3d6000fd5b505050507f4522989a180263bb7fbc1471718de7bdd69a5d36b5d29511958afa11d2e9da04818787604051611bc893929190615a02565b60405180910390a195945050505050565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c90611c199084903390600401615727565b602060405180830381865afa158015611c36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5a919061573e565b611c765760405162461bcd60e51b81526004016107a190615760565b6000826001600160801b031611611ce05760405162461bcd60e51b815260206004820152602860248201527f4c49444f3a20494e434f52524543545f4d41585f414c4c4f5741424c455f444960448201526746464552454e434560c01b60648201526084016107a1565b50601a80546001600160801b0319166001600160801b0392909216919091179055565b336000908152601c602052604090205460ff16611d325760405162461bcd60e51b81526004016107a190615a23565b8015611de1578060056000828254611d4a919061581a565b925050819055508060066000828254611d63919061581a565b9091555050600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611d9c90339030908690600401615a52565b6020604051808303816000875af1158015611dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddf919061573e565b505b3360009081526009602052604081208054849290611e00908490615848565b9091555050600d546019546040516323b872dd60e01b81526001600160a01b03928316926323b872dd92611e3e923392909116908790600401615a52565b6020604051808303816000875af1158015611e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e81919061573e565b505050565b600080611e9260035490565b905060035460001415611ea85750600092915050565b80611eb260055490565b611ebc9085615a76565b611ec69190615aab565b9392505050565b600080611ed984613bd1565b604080513381526001600160a01b0386166020820152908101869052606081018290529091507f90f46099733ed637df811df4fcc5cae4961192ca04f36da9ab64b4dd8dc9b7f59060800160405180910390a19392505050565b600061085861047483613d9f565b600f54604051633bfc46cb60e21b81527f0fc26914248bb9568b0afb008dd993637f6fb6bdc9598c222c68a21e90ca53c1916001600160a01b03169063eff11b2c90611f939084903390600401615727565b602060405180830381865afa158015611fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd4919061573e565b611ff05760405162461bcd60e51b81526004016107a190615760565b611ff86152a4565b82612003868661593a565b61200d919061593a565b61ffff1680825261271010801590612037575060008461ffff161180612037575060008361ffff16115b801561204857506127108561ffff16105b61208c5760405162461bcd60e51b815260206004820152601560248201527404c49444f3a204645455f444f4e545f4144445f555605c1b60448201526064016107a1565b80516040805161ffff92831681528783166020820152868316818301529185166060830152517fb01998f6d1382c5b6c7a4b477769ce2ffbbb91adc291994665b24def9a47e4509181900360800190a161ffff9283166040820181905294831660208201819052938316606082018190529051601e80549190941663ffffffff1990911617620100009094029390931763ffffffff60201b1916600160201b90940261ffff60301b191693909317600160301b90920291909117905550565b601954604051630aff799160e41b815260009182916001600160a01b039091169063aff799109061218090869060040161541c565b6040805180830381865afa15801561219c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c09190615abf565b91509150915091565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906122099084903390600401615727565b602060405180830381865afa158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a919061573e565b6122665760405162461bcd60e51b81526004016107a190615760565b6107b2613dba565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906122ae9084903390600401615727565b602060405180830381865afa1580156122cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ef919061573e565b61230b5760405162461bcd60e51b81526004016107a190615760565b600082116123555760405162461bcd60e51b815260206004820152601760248201527604c49444f3a20494e434f52524543545f4e45575f43415604c1b60448201526064016107a1565b50600c55565b600f54604051633bfc46cb60e21b81527fbd1ecc6a842ff1f2601eedd75a87543c45753bbba85c665c9f8870558fb3a2cf916001600160a01b03169063eff11b2c906123ad9084903390600401615727565b602060405180830381865afa1580156123ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ee919061573e565b61240a5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b03821661246b5760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f444556454c4f504552535f4144445245604482015261535360f01b60648201526084016107a1565b50601580546001600160a01b0319166001600160a01b0392909216919091179055565b6060602080546107c49061578c565b336000908152601c602052604090205460ff166124cc5760405162461bcd60e51b81526004016107a190615a23565b601954604080516301b7603360e11b815290516000926001600160a01b03169163036ec0669160048083019260209291908290030181865afa158015612516573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253a91906157eb565b90506000601960009054906101000a90046001600160a01b03166001600160a01b0316633dbfe6cb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b591906157eb565b600d546019546040516370a0823160e01b81529293506000926001600160a01b03928316926370a08231926125ef9291169060040161541c565b602060405180830381865afa15801561260c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061263091906157eb565b905060008161263f848661581a565b111561265c5761264f8383615848565b6126599085615848565b90505b60008160055461266c919061581a565b6005546126799089615a76565b6126839190615aab565b905080600560008282546126979190615848565b90915550600090506126a98289615848565b111561271b576019546001600160a01b0316634f5b636c6126ca838a615848565b6040518263ffffffff1660e01b81526004016126e891815260200190565b600060405180830381600087803b15801561270257600080fd5b505af1158015612716573d6000803e3d6000fd5b505050505b336000908152600860205260409020548111156127475733600090815260086020526040902054612749565b805b3360009081526008602052604081208054909190612768908490615848565b9091555050336000908152600960205260408120805489929061278c908490615848565b90915550506040517f28457ba4ae46aeb68ba5c1a1c15506fb3212bfff27da04dee70b81023a9ebc04906127c59033908a908a90615a02565b60405180910390a150505050505050565b3360009081526002602090815260408083206001600160a01b03861684529091528120548281101561284a5760405162461bcd60e51b815260206004820152601e60248201527f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f000060448201526064016107a1565b6128593385610caf8685615848565b5060019392505050565b6000610854338484613a61565b60008061287c60055490565b90508061288c5750600092915050565b80611eb260035490565b600061085882613bd1565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906128e19084903390600401615727565b602060405180830381865afa1580156128fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612922919061573e565b61293e5760405162461bcd60e51b81526004016107a190615760565b61294782613e12565b6001600160a01b0382166000908152601d602052604090819020805460ff19166001179055517fe5526d35f0db491e3e7690717b21c8148a1b5eef07240279db75404df228a59390610a8f90849061541c565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906129da9084903390600401615727565b602060405180830381865afa1580156129f7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1b919061573e565b612a375760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166000908152601c602052604090205460ff16612a6f5760405162461bcd60e51b81526004016107a190615ae3565b6001600160a01b03821660009081526008602052604090205415612ad55760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a204c45444745525f4841535f4e4f4e5f5a45524f5f5354414b450060448201526064016107a1565b6000612ae2836000613fde565b9050600019811415612b325760405162461bcd60e51b815260206004820152601960248201527813125113ce8813115111d15497d393d517d11254d050931151603a1b60448201526064016107a1565b6000839050806001600160a01b031663681fe70c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061573e565b612be15760405162461bcd60e51b81526020600482015260196024820152784c49444f3a204c45444745525f49535f4e4f545f454d50545960381b60448201526064016107a1565b600a805460009190612bf590600190615848565b81548110612c0557612c0561585f565b600091825260209091200154600a80546001600160a01b039092169250829185908110612c3457612c3461585f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600a805480612c7357612c73615b13565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038781168352601c82526040808420805460ff19169055805163118d75f960e11b81529051601b94939287169263231aebf292600480820193918290030181865afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1791906157eb565b81526020808201929092526040908101600090812080546001600160a01b03191690556001600160a01b0388168152601d90925290205460ff1615612d77576001600160a01b0385166000908152601d60205260409020805460ff191690555b6011546040516369c0bc3d60e11b81526001600160a01b039091169063d381787a90612da790889060040161541c565b600060405180830381600087803b158015612dc157600080fd5b505af1158015612dd5573d6000803e3d6000fd5b5050600e5460405163aac271ed60e01b81526001600160a01b03909116925063aac271ed9150612e0990889060040161541c565b600060405180830381600087803b158015612e2357600080fd5b505af1158015612e37573d6000803e3d6000fd5b505050507fd80173368774864e15485d9749961d73c4199e9ef55d044c8ad3427a15ee151785604051612e6a919061541c565b60405180910390a15050505050565b600061086960035490565b60005460ff1615612ea75760405162461bcd60e51b81526004016107a1906157c1565b6000612eb282612870565b905060008111612efb5760405162461bcd60e51b81526020600482015260146024820152734c49444f3a20414d4f554e545f544f4f5f4c4f5760601b60448201526064016107a1565b612f0433613d9f565b811115612f5f5760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a2052454445454d5f414d4f554e545f455843454544535f42414c416044820152624e434560e81b60648201526084016107a1565b612f69338261409f565b508160056000828254612f7c9190615848565b925050819055508160076000828254612f95919061581a565b90915550506019546040516301e9a69560e41b81526001600160a01b0390911690631e9a695090612fcc9033908690600401615b29565b600060405180830381600087803b158015612fe657600080fd5b505af1158015612ffa573d6000803e3d6000fd5b505060405184815260009250339150600080516020615d498339815191529060200160405180910390a360405182815233907f4896181ff8f4543cc00db9fe9b6fb7e6f032b7eb772c72ab1ec1b4d2e03b93699060200160405180910390a25050565b600a54600b54606091600091613073919061581a565b6001600160401b0381111561308a5761308a615832565b6040519080825280602002602001820160405280156130b3578160200160208202803683370190505b50905060005b600a54600b546130c9919061581a565b811015610c1157600b54811061311357600b54600a906130e99083615848565b815481106130f9576130f961585f565b6000918252602090912001546001600160a01b031661313c565b600b81815481106131265761312661585f565b6000918252602090912001546001600160a01b03165b82828151811061314e5761314e61585f565b6001600160a01b03909216602092830291909101909101528061317081615875565b9150506130b9565b336000908152601c602052604090205460ff166131a75760405162461bcd60e51b81526004016107a190615a23565b60408051608081018252601e5461ffff808216835262010000820481166020840152600160201b82048116938301849052600160301b909104166060820181905290916000916131f69161593a565b61ffff1690506000811161320c5761320c615b42565b836005600082825461321e919061581a565b9091555050336000908152600860205260408120805486929061324290849061581a565b9091555050336000908152600960205260408120805486929061326690849061581a565b9091555050602082015160009061327f90612710615b58565b61ffff1661328d8387615a76565b6132979190615aab565b90506000816132a560055490565b6132af9190615848565b905060006132bc60055490565b905081156132e557816132ce60035490565b6132d89085615a76565b6132e29190615aab565b90505b6016546132fb906001600160a01b0316826141c5565b50600084866040015161ffff16836133139190615a76565b61331d9190615aab565b60165460155491925061333d916001600160a01b0391821691168361429b565b601554613353906001600160a01b03168261442e565b601654613372906001600160a01b031661336d8385615848565b61442e565b7f61953b03ced70bb23c53b5a7058e431e3db88cf84a72660faea0849b785c43bd3389896040516133a593929190615a02565b60405180910390a15050505050505050565b336000908152601c602052604090205460ff166133e65760405162461bcd60e51b81526004016107a190615a23565b3360009081526008602090815260408083205460099092529091205461340d90839061581a565b111561345b5760405162461bcd60e51b815260206004820152601d60248201527f4c49444f3a204c45444745525f4e4f545f454e4f5547485f5354414b4500000060448201526064016107a1565b336000908152600960205260408120805483929061347a90849061581a565b9091555050600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906134b19033908590600401615b29565b6020604051808303816000875af11580156134d0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6b919061573e565b600f54604051633bfc46cb60e21b81527fe6f5d3a94b3b2e5137a1b6bff43c8dde49b099cd4958238240e4ab304e4a2b68916001600160a01b03169063eff11b2c906135469084903390600401615727565b602060405180830381865afa158015613563573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613587919061573e565b6135a35760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166135f95760405162461bcd60e51b815260206004820181905260248201527f4c49444f3a20494e434f52524543545f54524541535552595f4144445245535360448201526064016107a1565b50601680546001600160a01b0319166001600160a01b0392909216919091179055565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c9061365c9084903390600401615727565b602060405180830381865afa158015613679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369d919061573e565b6136b95760405162461bcd60e51b81526004016107a190615760565b610e6b82613e12565b600061085882613d9f565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c9061370d9084903390600401615727565b602060405180830381865afa15801561372a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374e919061573e565b61376a5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166137c05760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a20494e434f52524543545f464143544f52595f414444524553530060448201526064016107a1565b50601880546001600160a01b0319166001600160a01b0392909216919091179055565b6011546001600160a01b0316331461383c5760405162461bcd60e51b815260206004820152601c60248201527b2624a2279d102727aa2fa32927a6afa7a920a1a622afa6a0a9aa22a960211b60448201526064016107a1565b601960009054906101000a90046001600160a01b03166001600160a01b0316637b2077276040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506138ac614467565b565b60005460ff166138f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016107a1565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051613931919061541c565b60405180910390a1565b60005460ff161561395e5760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166139b05760405162461bcd60e51b8152602060048201526019602482015278415050524f56455f46524f4d5f5a45524f5f4144445245535360381b60448201526064016107a1565b6001600160a01b038216613a005760405162461bcd60e51b8152602060048201526017602482015276415050524f56455f544f5f5a45524f5f4144445245535360481b60448201526064016107a1565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000613a6c82612870565b9050613a7984848361429b565b826001600160a01b0316846001600160a01b0316600080516020615d4983398151915284604051613aac91815260200190565b60405180910390a350505050565b60005b600a54600b54613acd919061581a565b811015613bcb57600b546000908210613b1a57600b54600a90613af09084615848565b81548110613b0057613b0061585f565b6000918252602090912001546001600160a01b0316613b43565b600b8281548110613b2d57613b2d61585f565b6000918252602090912001546001600160a01b03165b60405163416acf8b60e11b81526001600160801b03808816600483015286166024820152604481018590529091506001600160a01b038216906382d59f1690606401600060405180830381600087803b158015613b9f57600080fd5b505af1158015613bb3573d6000803e3d6000fd5b50505050508080613bc390615875565b915050613abd565b50505050565b6000805460ff1615613bf55760405162461bcd60e51b81526004016107a1906157c1565b600c5482600554613c06919061581a565b10613c4f5760405162461bcd60e51b815260206004820152601960248201527804c49444f3a204445504f534954535f4558434545445f43415603c1b60448201526064016107a1565b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90613c8390339030908790600401615a52565b6020604051808303816000875af1158015613ca2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc6919061573e565b5081613d095760405162461bcd60e51b815260206004820152601260248201527113125113ce8816915493d7d1115413d4d25560721b60448201526064016107a1565b6000613d1483612870565b905080613d1e5750815b8260056000828254613d30919061581a565b925050819055508260066000828254613d49919061581a565b90915550613d59905033826141c5565b50613d64338261442e565b60405183815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c49060200160405180910390a292915050565b6001600160a01b031660009081526001602052604090205490565b60005460ff1615613ddd5760405162461bcd60e51b81526004016107a1906157c1565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139243390565b6001600160a01b0381166000908152601c602052604090205460ff16613e4a5760405162461bcd60e51b81526004016107a190615ae3565b6000613e57826001613fde565b9050600019811415613ea65760405162461bcd60e51b815260206004820152601860248201527713125113ce8813115111d15497d393d517d153905093115160421b60448201526064016107a1565b600b805460009190613eba90600190615848565b81548110613eca57613eca61585f565b600091825260209091200154600b80546001600160a01b039092169250829184908110613ef957613ef961585f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600b805480613f3857613f38615b13565b600082815260208120600019908301810180546001600160a01b03199081169091559201909255600a805460018101825592527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910180549091166001600160a01b0385161790556040517f85accaad76657cef23e292273789ae7a13d87db42feff1d70d4056c20d78d07190613fd190859061541c565b60405180910390a1505050565b60008082613fee57600a54613ff2565b600b545b905060005b818110156140935760008461403357600a82815481106140195761401961585f565b6000918252602090912001546001600160a01b031661405c565b600b82815481106140465761404661585f565b6000918252602090912001546001600160a01b03165b9050856001600160a01b0316816001600160a01b03161415614082575091506108589050565b5061408c81615875565b9050613ff7565b50600019949350505050565b6000805460ff16156140c35760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166141165760405162461bcd60e51b815260206004820152601a6024820152794255524e5f46524f4d5f5448455f5a45524f5f4144445245535360301b60448201526064016107a1565b6001600160a01b0383166000908152600160205260409020548083111561417d5760405162461bcd60e51b815260206004820152601b60248201527a4255524e5f414d4f554e545f455843454544535f42414c414e434560281b60448201526064016107a1565b8261418760035490565b6141919190615848565b600381905591506141a28382615848565b6001600160a01b0390941660009081526001602052604090209390935592915050565b6000805460ff16156141e95760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b03831661423a5760405162461bcd60e51b81526020600482015260186024820152774d494e545f544f5f5448455f5a45524f5f4144445245535360401b60448201526064016107a1565b8161424460035490565b61424e919061581a565b60038190556001600160a01b03841660009081526001602052604090205490915061427a90839061581a565b6001600160a01b039093166000908152600160205260409020929092555090565b60005460ff16156142be5760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166143145760405162461bcd60e51b815260206004820152601e60248201527f5452414e534645525f46524f4d5f5448455f5a45524f5f41444452455353000060448201526064016107a1565b6001600160a01b0382166143695760405162461bcd60e51b815260206004820152601c60248201527b5452414e534645525f544f5f5448455f5a45524f5f4144445245535360201b60448201526064016107a1565b6001600160a01b038316600090815260016020526040902054808211156143d25760405162461bcd60e51b815260206004820152601f60248201527f5452414e534645525f414d4f554e545f455843454544535f42414c414e43450060448201526064016107a1565b6143dc8282615848565b6001600160a01b03808616600090815260016020526040808220939093559085168152205461440c90839061581a565b6001600160a01b03909316600090815260016020526040902092909255505050565b6001600160a01b0382166000600080516020615d4983398151915261445284611e86565b60405190815260200160405180910390a35050565b6000805b600a54600b5461447b919061581a565b81101561462f57600b5460009082106144c857600b54600a9061449e9084615848565b815481106144ae576144ae61585f565b6000918252602090912001546001600160a01b03166144f1565b600b82815481106144db576144db61585f565b6000918252602090912001546001600160a01b03165b6001600160a01b038116600090815260096020908152604080832054600890925290912054919250101561461e576001600160a01b038116600090815260096020908152604080832054600890925282205461454d9190615848565b600654600d546040516370a0823160e01b815292935090916001600160a01b03909116906370a082319061458590309060040161541c565b602060405180830381865afa1580156145a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c691906157eb565b6145d09190615848565b6145da828661581a565b1161461c576145e9818561581a565b6001600160a01b038316600090815260086020526040812080549296508392909190614616908490615848565b90915550505b505b5061462881615875565b905061446b565b508060066000828254614642919061581a565b909155505060065415158061465957506000600754115b156107b257600a541580159061467157506000600754115b15614685576146816007546147ae565b6007555b600060065411801561469957506000600754115b15614765576000600754600654116146b3576006546146b7565b6007545b905080600660008282546146cb9190615848565b9250508190555080600760008282546146e49190615848565b9091555050600d5460195460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb9261471f929116908590600401615b29565b6020604051808303816000875af115801561473e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614762919061573e565b50505b600b54156107b257600061477a6007546149a9565b6147856006546149a9565b61478f9190615b7b565b905080156147a0576147a081614a13565b506000600681905560075550565b600a54600090806147c1576147c1615b42565b60008060005b8381101561486b57601d6000600a83815481106147e6576147e661585f565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1661485b5760086000600a83815481106148295761482961585f565b60009182526020808320909101546001600160a01b03168352820192909252604001902054614858908461581a565b92505b61486481615875565b90506147c7565b508161487a5750929392505050565b60005b8381101561499557601d6000600a838154811061489c5761489c61585f565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1661498557600060086000600a84815481106148e1576148e161585f565b60009182526020808320909101546001600160a01b03168352820192909252604001812054915084614913838a615a76565b61491d9190615aab565b905081811161492c578061492e565b815b905061493a8183615848565b60086000600a86815481106149515761495161585f565b60009182526020808320909101546001600160a01b03168352820192909252604001902055614980818561581a565b935050505b61498e81615875565b905061487d565b506149a08186615848565b95945050505050565b6000600160ff1b8210614a0f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016107a1565b5090565b600b5480614a2357614a23615b42565b6000816001600160401b03811115614a3d57614a3d615832565b604051908082528060200260200182016040528015614a66578160200160208202803683370190505b5090506000826001600160401b03811115614a8357614a83615832565b604051908082528060200260200182016040528015614aac578160200160208202803683370190505b5090506000836001600160401b03811115614ac957614ac9615832565b604051908082528060200260200182016040528015614af2578160200160208202803683370190505b5090506000846001600160401b03811115614b0f57614b0f615832565b604051908082528060200260200182016040528015614b38578160200160208202803683370190505b50905060008060008088614b4a61085e565b614b549190615aab565b90506000805b8a811015614cff57600b8181548110614b7557614b7561585f565b9060005260206000200160009054906101000a90046001600160a01b0316898281518110614ba557614ba561585f565b60200260200101906001600160a01b031690816001600160a01b031681525050600860008a8381518110614bdb57614bdb61585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054888281518110614c1657614c1661585f565b602002602001018181525050600860008a8381518110614c3857614c3861585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054878281518110614c7357614c7361585f565b602002602001018181525050878181518110614c9157614c9161585f565b602002602001015183614ca49190615b7b565b91506000614cb2838e615bba565b1315614cc557614cc28287615c3f565b95505b818a8281518110614cd857614cd861585f565b6020908102919091010152614ced8285615c3f565b9350614cf881615875565b9050614b5a565b5050508060001480614d0f575082155b15614d1f57505050505050505050565b60016000841215614d3a5750600019614d3784615c80565b93505b60005b89811015614e74578160000b898281518110614d5b57614d5b61585f565b60200260200101818151614d6f9190615bba565b90525088516000908a9083908110614d8957614d8961585f565b60200260200101511315614e64576000858c8b8481518110614dad57614dad61585f565b6020026020010151614dbf9190615bba565b614dc99190615c9d565b9050600081898481518110614de057614de061585f565b6020026020010151614df29190615c3f565b905080600860008c8681518110614e0b57614e0b61585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555080898481518110614e4a57614e4a61585f565b6020908102919091010152614e5f8287615c3f565b955050505b614e6d81615875565b9050614d3d565b506000614e81848c615b7b565b90506000811315614ee65780600860008a600081518110614ea457614ea461585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614edb919061581a565b90915550614fc49050565b6000811215614fc45760005b8a81108015614f015750600082125b15614fc2576000888281518110614f1a57614f1a61585f565b602002602001015190506000811115614fb1576000614f3884615c80565b8211614f445781614f4d565b614f4d84615c80565b905080600860008d8681518110614f6657614f6661585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614f9d9190615848565b90915550614fad90508185615c3f565b9350505b50614fbb81615875565b9050614ef2565b505b506000805b8a811015615215576000898281518110614fe557614fe561585f565b60200260200101516001600160a01b031663a5baabf06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561502a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061504e9190615ccb565b6001600160801b0316600960008c858151811061506d5761506d61585f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546150a09190615848565b90508782815181106150b4576150b461585f565b60200260200101518111801561512057508782815181106150d7576150d761585f565b6020026020010151600860008c85815181106150f5576150f561585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054115b156152045780600860008c858151811061513c5761513c61585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054116151d25787828151811061517c5761517c61585f565b6020026020010151600860008c858151811061519a5761519a61585f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546151cd9190615848565b6151f7565b8782815181106151e4576151e461585f565b6020026020010151816151f79190615848565b615201908461581a565b92505b5061520e81615875565b9050614fc9565b50801561529757600d5460195460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92615252929116908590600401615b29565b6020604051808303816000875af1158015615271573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615295919061573e565b505b5050505050505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b600060208083528351808285015260005b818110156152f8578581018301518582016040015282016152dc565b8181111561530a576000604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146107b257600080fd5b6000806040838503121561534857600080fd5b823561535381615320565b946020939093013593505050565b60006020828403121561537357600080fd5b8135611ec681615320565b6020808252825182820181905260009190848201906040850190845b818110156153b65783518352928401929184019160010161539a565b50909695505050505050565b6000806000606084860312156153d757600080fd5b83356153e281615320565b925060208401356153f281615320565b929592945050506040919091013590565b60006020828403121561541557600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060808284031215610c1157600080fd5b6001600160801b03811681146107b257600080fd5b60008060008060008060008060006101208a8c03121561547657600080fd5b893561548181615320565b985060208a013561549181615320565b975060408a01356154a181615320565b965060608a01356154b181615320565b955060808a01356154c181615320565b945060a08a01356154d181615320565b935060c08a01356154e181615320565b925060e08a013591506101008a01356154f981615442565b809150509295985092959850929598565b60008083601f84011261551c57600080fd5b5081356001600160401b0381111561553357600080fd5b6020830191508360208260051b850101111561554e57600080fd5b9250929050565b6000806000806040858703121561556b57600080fd5b84356001600160401b038082111561558257600080fd5b61558e8883890161550a565b909650945060208701359150808211156155a757600080fd5b506155b48782880161550a565b95989497509550505050565b61ffff811681146107b257600080fd5b6000806000606084860312156155e557600080fd5b833592506020840135915060408401356155fe816155c0565b809150509250925092565b60006020828403121561561b57600080fd5b8135611ec681615442565b6000806040838503121561563957600080fd5b50508035926020909101359150565b6000806040838503121561565b57600080fd5b82359150602083013561566d81615320565b809150509250929050565b60008060006060848603121561568d57600080fd5b8335615698816155c0565b925060208401356156a8816155c0565b915060408401356155fe816155c0565b600080604083850312156156cb57600080fd5b82356156d681615320565b9150602083013561566d81615320565b6020808252825182820181905260009190848201906040850190845b818110156153b65783516001600160a01b031683529284019291840191600101615702565b9182526001600160a01b0316602082015260400190565b60006020828403121561575057600080fd5b81518015158114611ec657600080fd5b60208082526012908201527113125113ce8815539055551213d49256915160721b604082015260600190565b600181811c908216806157a057607f821691505b60208210811415610c1157634e487b7160e01b600052602260045260246000fd5b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6000602082840312156157fd57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561582d5761582d615804565b500190565b634e487b7160e01b600052604160045260246000fd5b60008282101561585a5761585a615804565b500390565b634e487b7160e01b600052603260045260246000fd5b600060001982141561588957615889615804565b5060010190565b6000602082840312156158a257600080fd5b8135611ec6816155c0565b81356158b8816155c0565b61ffff8116905081548161ffff19821617835560208401356158d981615442565b6001600160901b03199190911690911760109190911b62010000600160901b031617815560018101604083013561590f81615442565b81546001600160801b0319166001600160801b03919091161790556060919091013560029190910155565b600061ffff80831681851680830382111561595757615957615804565b01949350505050565b6000808335601e1984360301811261597757600080fd5b8301803591506001600160401b0382111561599157600080fd5b6020019150600581901b360382131561554e57600080fd5b6020808252810182905260006001600160fb1b038311156159c957600080fd5b8260051b80856040850137600092016040019182525092915050565b6000602082840312156159f757600080fd5b8151611ec681615320565b6001600160a01b039390931683526020830191909152604082015260600190565b6020808252601590820152742624a2279d102727aa2fa32927a6afa622a223a2a960591b604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000816000190483118215151615615a9057615a90615804565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615aba57615aba615a95565b500490565b60008060408385031215615ad257600080fd5b505080516020909101519092909150565b60208082526016908201527513125113ce8813115111d15497d393d517d193d5539160521b604082015260600190565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052600160045260246000fd5b600061ffff83811690831681811015615b7357615b73615804565b039392505050565b60008083128015600160ff1b850184121615615b9957615b99615804565b6001600160ff1b0384018313811615615bb457615bb4615804565b50500390565b60006001600160ff1b0381841382841380821686840486111615615be057615be0615804565b600160ff1b6000871282811687830589121615615bff57615bff615804565b60008712925087820587128484161615615c1b57615c1b615804565b87850587128184161615615c3157615c31615804565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615615c6157615c61615804565b600160ff1b8390038412811615615c7a57615c7a615804565b50500190565b6000600160ff1b821415615c9657615c96615804565b5060000390565b600082615cac57615cac615a95565b600160ff1b821460001984141615615cc657615cc6615804565b500590565b600060208284031215615cdd57600080fd5b8151611ec68161544256fe585c6e254ec74f8e72b5cff099811ed8721d9039f710d9a1cb67eed6c74aa8279336eb28e461adb6ba7e620f5006a6952a65a21a4db92c2edb104bf7f1c38c63d76e3374742c17bd14ffaf46cd349ec292baf7d8425512fa8fe132557a4c967bddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220464e927a57b5491842c3381984e580b32914e13b803fa68067ac25932e631ea864736f6c634300080a0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106102935760003560e01c8063046f7da21461029857806306fdde03146102a2578063095ea7b3146102c057806318160ddd146102e35780631a813a3c146102f95780631ab81cba146103015780631d55fde41461031457806323b872dd14610329578063240359bc1461033c578063313ce5671461037257806338dee1d314610387578063395093511461039a5780633ca3bca3146103ad5780633fd2c16a146103c057806341c262c5146103d357806347376473146103e657806348c696c0146103f95780634fe28e3a146104025780635c975abb146104155780635e442a9b146104205780635f3f2cac1461044057806361f9c3da1461045357806363ca402d146104665780636a92b586146104795780636e553f65146104a457806370a08231146104b757806373ece435146104ca57806377c96574146104dd5780638456cb5914610505578063866512031461050d5780638ab476bf1461052057806395d89b41146105335780639e0c97041461053b578063a1e206c71461054e578063a457c2d714610561578063a9042441146102e3578063a9059cbb14610574578063b09f532014610587578063b31207f214610590578063b6b55f25146105a3578063cdd8f598146105b6578063d381787a146105c9578063d5002f2e146105dc578063db006a75146105e4578063dbd5edc7146105f7578063dd62ed3e14610600578063df19795614610639578063df6c39fb1461064e578063e100610714610661578063e40b925514610674578063ec70d8001461067d578063f0f4426014610690578063f1447195146106a3578063f339a70d146106c3578063f5eb42dc146106d6578063f7eba420146106e9578063fa597e07146106fc575b600080fd5b6102a0610704565b005b6102aa6107b5565b6040516102b791906152cb565b60405180910390f35b6102d36102ce366004615335565b610847565b60405190151581526020016102b7565b6102eb61085e565b6040519081526020016102b7565b6102a061086e565b6102a061030f366004615361565b610940565b61031c610a9b565b6040516102b7919061537e565b6102d36103373660046153c2565b610c17565b61036561034a366004615403565b6000908152601b60205260409020546001600160a01b031690565b6040516102b7919061541c565b60215460405160ff90911681526020016102b7565b6102a0610395366004615430565b610cbf565b6102d36103a8366004615335565b610e6f565b6102a06103bb366004615457565b610ea6565b601154610365906001600160a01b031681565b6102a06103e1366004615555565b61134f565b6102a06103f4366004615361565b61161b565b6102eb60075481565b6103656104103660046155d0565b611731565b60005460ff166102d3565b6102eb61042e366004615361565b60096020526000908152604090205481565b6102a061044e366004615609565b611bd9565b6102a0610461366004615626565b611d03565b6102eb610474366004615403565b611e86565b601a5461048c906001600160801b031681565b6040516001600160801b0390911681526020016102b7565b6102eb6104b2366004615648565b611ecd565b6102eb6104c5366004615361565b611f33565b6102a06104d8366004615678565b611f41565b6104f06104eb366004615361565b61214b565b604080519283526020830191909152016102b7565b6102a06121c9565b6102a061051b366004615403565b61226e565b6102a061052e366004615361565b61235b565b6102aa61248e565b6102a0610549366004615626565b61249d565b600f54610365906001600160a01b031681565b6102d361056f366004615335565b6127d6565b6102d3610582366004615335565b612863565b6102eb60065481565b6102eb61059e366004615403565b612870565b6102eb6105b1366004615403565b612896565b6102a06105c4366004615361565b6128a1565b6102a06105d7366004615361565b61299a565b6102eb612e79565b6102a06105f2366004615403565b612e84565b6102eb600c5481565b6102eb61060e3660046156b8565b6001600160a01b03918216600090815260026020908152604080832093909416825291909152205490565b61064161305d565b6040516102b791906156e6565b6102a061065c366004615626565b613178565b6102a061066f366004615403565b6133b7565b6102eb60055481565b601754610365906001600160a01b031681565b6102a061069e366004615361565b6134f4565b6102eb6106b1366004615361565b60086020526000908152604090205481565b6102a06106d1366004615361565b61361c565b6102eb6106e4366004615361565b6136c2565b6102a06106f7366004615361565b6136cd565b6102a06137e3565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906107449084903390600401615727565b602060405180830381865afa158015610761573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610785919061573e565b6107aa5760405162461bcd60e51b81526004016107a190615760565b60405180910390fd5b6107b26138ae565b50565b6060601f80546107c49061578c565b80601f01602080910402602001604051908101604052809291908181526020018280546107f09061578c565b801561083d5780601f106108125761010080835404028352916020019161083d565b820191906000526020600020905b81548152906001019060200180831161082057829003601f168201915b5050505050905090565b600061085433848461393b565b5060015b92915050565b600061086960055490565b905090565b60005460ff16156108915760405162461bcd60e51b81526004016107a1906157c1565b601954604051630f41a04d60e11b81526000916001600160a01b031690631e83409a906108c290339060040161541c565b6020604051808303816000875af11580156108e1573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061090591906157eb565b60405181815290915033907fd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a9060200160405180910390a250565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906109809084903390600401615727565b602060405180830381865afa15801561099d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109c1919061573e565b6109dd5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166000908152601d602052604090205460ff16610a3f5760405162461bcd60e51b815260206004820152601760248201527613125113ce8813115111d15497d393d517d4105554d151604a1b60448201526064016107a1565b6001600160a01b0382166000908152601d602052604090819020805460ff19169055517f8c097d4c8d964b147a04f3a822a31e3aa5a9104dc7db3dde0166a248b8f106c590610a8f90849061541c565b60405180910390a15050565b600a54600b54606091600091610ab1919061581a565b6001600160401b03811115610ac857610ac8615832565b604051908082528060200260200182016040528015610af1578160200160208202803683370190505b50905060005b600a54600b54610b07919061581a565b811015610c1157600b546000908210610b5457600b54600a90610b2a9084615848565b81548110610b3a57610b3a61585f565b6000918252602090912001546001600160a01b0316610b7d565b600b8281548110610b6757610b6761585f565b6000918252602090912001546001600160a01b03165b9050806001600160a01b031663231aebf26040518163ffffffff1660e01b8152600401602060405180830381865afa158015610bbd573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610be191906157eb565b838381518110610bf357610bf361585f565b60209081029190910101525080610c0981615875565b915050610af7565b50919050565b6001600160a01b038316600090815260026020908152604080832033845290915281205482811015610c955760405162461bcd60e51b815260206004820152602160248201527f5452414e534645525f414d4f554e545f455843454544535f414c4c4f57414e436044820152604560f81b60648201526084016107a1565b610ca0858585613a61565b610cb48533610caf8685615848565b61393b565b506001949350505050565b600f54604051633bfc46cb60e21b81527f2c204f3ef59cc164f843cf6919920470e37721ba425db7893d02e60cfd0bafdc916001600160a01b03169063eff11b2c90610d119084903390600401615727565b602060405180830381865afa158015610d2e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d52919061573e565b610d6e5760405162461bcd60e51b81526004016107a190615760565b6000610d7d6020840184615890565b61ffff1611610dda5760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a204241445f4d41585f56414c494441544f52535f5045525f4c454460448201526223a2a960e91b60648201526084016107a1565b6000826060013511610e2e5760405162461bcd60e51b815260206004820152601e60248201527f4c49444f3a204241445f4d41585f554e4c4f434b494e475f4348554e4b53000060448201526064016107a1565b816012610e3b82826158ad565b50610e6b9050610e516040840160208501615609565b610e616060850160408601615609565b8460600135613aba565b5050565b3360008181526002602090815260408083206001600160a01b03871684529091528120549091610854918590610caf90869061581a565b600454610100900460ff1680610ebf575060045460ff16155b610f225760405162461bcd60e51b815260206004820152602e60248201527f496e697469616c697a61626c653a20636f6e747261637420697320616c72656160448201526d191e481a5b9a5d1a585b1a5e995960921b60648201526084016107a1565b600454610100900460ff16158015610f44576004805461ffff19166101011790555b60008311610f855760405162461bcd60e51b815260206004820152600e60248201526d04c49444f3a205a45524f5f4341560941b60448201526064016107a1565b6001600160a01b038916610fda5760405162461bcd60e51b815260206004820152601c60248201527b4c49444f3a20494e434f52524543545f564b534d5f4144445245535360201b60448201526064016107a1565b6001600160a01b03851661103e5760405162461bcd60e51b815260206004820152602560248201527f4c49444f3a20494e434f52524543545f4f5241434c455f4d41535445525f4144604482015264445245535360d81b60648201526084016107a1565b6001600160a01b03841661109f5760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f5749544844524157414c5f4144445245604482015261535360f01b60648201526084016107a1565b6001600160a01b038a166111015760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a20494e434f52524543545f415554484d414e414745525f4144445260448201526245535360e81b60648201526084016107a1565b6001600160a01b0388166111625760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f434f4e54524f4c4c45525f4144445245604482015261535360f01b60648201526084016107a1565b600d80546001600160a01b03808c166001600160a01b031992831617909255600e80548b8416908316179055600f8054928d1692909116919091179055600c83905560c86010556111b16152a4565b6103206111c060c8600061593a565b6111ca919061593a565b61ffff168082526000602083015260c86040808401919091526103206060840152601e805465ffffffffffff1916909217601960231b1761ffff60301b1916601960351b17909155601680546001600160a01b03199081166001600160a01b038b8116919091179092556015805482168c84161790556011805490911691891691821790559051637d774e3160e01b8152637d774e319061126f90309060040161541c565b600060405180830381600087803b15801561128957600080fd5b505af115801561129d573d6000803e3d6000fd5b5050601980546001600160a01b0319166001600160a01b03891690811790915560405163015cda1760e41b81529092506315cda17091506112e290309060040161541c565b600060405180830381600087803b1580156112fc57600080fd5b505af1158015611310573d6000803e3d6000fd5b5050601a80546001600160801b0319166001600160801b038716179055505081159050611343576004805461ff00191690555b50505050505050505050565b600f54604051633bfc46cb60e21b81527fdefdc47e8c8311059971baa7eda778fd22d6ea93a75a917e77534b8ce74fe4f9916001600160a01b03169063eff11b2c906113a19084903390600401615727565b602060405180830381865afa1580156113be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906113e2919061573e565b6113fe5760405162461bcd60e51b81526004016107a190615760565b8382146114455760405162461bcd60e51b815260206004820152601560248201527413125113ce88125390d3d4949150d517d253941555605a1b60448201526064016107a1565b60005b84811015611613576000601b818888858181106114675761146761585f565b60209081029290920135835250810191909152604001600020546001600160a01b031614156114d65760405162461bcd60e51b815260206004820152601b60248201527a13125113ce88155392d393d5d397d4d51054d217d050d0d3d55395602a1b60448201526064016107a1565b60125461ffff168484838181106114ef576114ef61585f565b90506020028101906115019190615960565b905011156115515760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a2056414c494441544f52535f414d4f554e545f544f4f5f4249470060448201526064016107a1565b601b60008787848181106115675761156761585f565b60209081029290920135835250810191909152604001600020546001600160a01b031663f5330e968585848181106115a1576115a161585f565b90506020028101906115b39190615960565b6040518363ffffffff1660e01b81526004016115d09291906159a9565b600060405180830381600087803b1580156115ea57600080fd5b505af11580156115fe573d6000803e3d6000fd5b505050508061160c90615875565b9050611448565b505050505050565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c9061165b9084903390600401615727565b602060405180830381865afa158015611678573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061169c919061573e565b6116b85760405162461bcd60e51b81526004016107a190615760565b6001600160a01b03821661170e5760405162461bcd60e51b815260206004820152601e60248201527f4c49444f3a20494e434f52524543545f424541434f4e5f41444452455353000060448201526064016107a1565b50601780546001600160a01b0319166001600160a01b0392909216919091179055565b600f54604051633bfc46cb60e21b8152600091600080516020615ce9833981519152916001600160a01b039091169063eff11b2c906117769084903390600401615727565b602060405180830381865afa158015611793573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906117b7919061573e565b6117d35760405162461bcd60e51b81526004016107a190615760565b6017546001600160a01b031661182b5760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a20554e5350454349464945445f4c45444745525f424541434f4e0060448201526064016107a1565b6018546001600160a01b03166118835760405162461bcd60e51b815260206004820181905260248201527f4c49444f3a20554e5350454349464945445f4c45444745525f464143544f525960448201526064016107a1565b6011546001600160a01b03166118d45760405162461bcd60e51b81526020600482015260166024820152752624a2279d102727afa7a920a1a622afa6a0a9aa22a960511b60448201526064016107a1565b601054600a54600b546118e7919061581a565b1061192f5760405162461bcd60e51b815260206004820152601860248201527713125113ce8813115111d15494d7d413d3d317d31253525560421b60448201526064016107a1565b6000858152601b60205260409020546001600160a01b0316156119915760405162461bcd60e51b815260206004820152601a6024820152794c49444f3a2053544153485f414c52454144595f45584953545360301b60448201526064016107a1565b601854600d54600e5460125460135460145460405163776aecef60e11b8152600481018c9052602481018b90526001600160a01b0395861660448201529385166064850152620100009092046001600160801b0390811660848501521660a483015260c4820152600092919091169063eed5d9de9060e4016020604051808303816000875af1158015611a28573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a4c91906159e5565b600b805460018181019092557f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db90180546001600160a01b038085166001600160a01b0319928316811790935560008b8152601b6020908152604080832080549095168617909455938152601c90935291819020805460ff191690931790925560115491516327c13a6b60e21b81529293501690639f04e9ac90611af390849060040161541c565b600060405180830381600087803b158015611b0d57600080fd5b505af1158015611b21573d6000803e3d6000fd5b5050600e54604051639632acf760e01b815261ffff88166004820152602481018a90526001600160a01b0385811660448301529091169250639632acf79150606401600060405180830381600087803b158015611b7d57600080fd5b505af1158015611b91573d6000803e3d6000fd5b505050507f4522989a180263bb7fbc1471718de7bdd69a5d36b5d29511958afa11d2e9da04818787604051611bc893929190615a02565b60405180910390a195945050505050565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c90611c199084903390600401615727565b602060405180830381865afa158015611c36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611c5a919061573e565b611c765760405162461bcd60e51b81526004016107a190615760565b6000826001600160801b031611611ce05760405162461bcd60e51b815260206004820152602860248201527f4c49444f3a20494e434f52524543545f4d41585f414c4c4f5741424c455f444960448201526746464552454e434560c01b60648201526084016107a1565b50601a80546001600160801b0319166001600160801b0392909216919091179055565b336000908152601c602052604090205460ff16611d325760405162461bcd60e51b81526004016107a190615a23565b8015611de1578060056000828254611d4a919061581a565b925050819055508060066000828254611d63919061581a565b9091555050600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90611d9c90339030908690600401615a52565b6020604051808303816000875af1158015611dbb573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ddf919061573e565b505b3360009081526009602052604081208054849290611e00908490615848565b9091555050600d546019546040516323b872dd60e01b81526001600160a01b03928316926323b872dd92611e3e923392909116908790600401615a52565b6020604051808303816000875af1158015611e5d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e81919061573e565b505050565b600080611e9260035490565b905060035460001415611ea85750600092915050565b80611eb260055490565b611ebc9085615a76565b611ec69190615aab565b9392505050565b600080611ed984613bd1565b604080513381526001600160a01b0386166020820152908101869052606081018290529091507f90f46099733ed637df811df4fcc5cae4961192ca04f36da9ab64b4dd8dc9b7f59060800160405180910390a19392505050565b600061085861047483613d9f565b600f54604051633bfc46cb60e21b81527f0fc26914248bb9568b0afb008dd993637f6fb6bdc9598c222c68a21e90ca53c1916001600160a01b03169063eff11b2c90611f939084903390600401615727565b602060405180830381865afa158015611fb0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611fd4919061573e565b611ff05760405162461bcd60e51b81526004016107a190615760565b611ff86152a4565b82612003868661593a565b61200d919061593a565b61ffff1680825261271010801590612037575060008461ffff161180612037575060008361ffff16115b801561204857506127108561ffff16105b61208c5760405162461bcd60e51b815260206004820152601560248201527404c49444f3a204645455f444f4e545f4144445f555605c1b60448201526064016107a1565b80516040805161ffff92831681528783166020820152868316818301529185166060830152517fb01998f6d1382c5b6c7a4b477769ce2ffbbb91adc291994665b24def9a47e4509181900360800190a161ffff9283166040820181905294831660208201819052938316606082018190529051601e80549190941663ffffffff1990911617620100009094029390931763ffffffff60201b1916600160201b90940261ffff60301b191693909317600160301b90920291909117905550565b601954604051630aff799160e41b815260009182916001600160a01b039091169063aff799109061218090869060040161541c565b6040805180830381865afa15801561219c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121c09190615abf565b91509150915091565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906122099084903390600401615727565b602060405180830381865afa158015612226573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061224a919061573e565b6122665760405162461bcd60e51b81526004016107a190615760565b6107b2613dba565b600f54604051633bfc46cb60e21b8152600080516020615d29833981519152916001600160a01b03169063eff11b2c906122ae9084903390600401615727565b602060405180830381865afa1580156122cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122ef919061573e565b61230b5760405162461bcd60e51b81526004016107a190615760565b600082116123555760405162461bcd60e51b815260206004820152601760248201527604c49444f3a20494e434f52524543545f4e45575f43415604c1b60448201526064016107a1565b50600c55565b600f54604051633bfc46cb60e21b81527fbd1ecc6a842ff1f2601eedd75a87543c45753bbba85c665c9f8870558fb3a2cf916001600160a01b03169063eff11b2c906123ad9084903390600401615727565b602060405180830381865afa1580156123ca573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906123ee919061573e565b61240a5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b03821661246b5760405162461bcd60e51b815260206004820152602260248201527f4c49444f3a20494e434f52524543545f444556454c4f504552535f4144445245604482015261535360f01b60648201526084016107a1565b50601580546001600160a01b0319166001600160a01b0392909216919091179055565b6060602080546107c49061578c565b336000908152601c602052604090205460ff166124cc5760405162461bcd60e51b81526004016107a190615a23565b601954604080516301b7603360e11b815290516000926001600160a01b03169163036ec0669160048083019260209291908290030181865afa158015612516573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061253a91906157eb565b90506000601960009054906101000a90046001600160a01b03166001600160a01b0316633dbfe6cb6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612591573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906125b591906157eb565b600d546019546040516370a0823160e01b81529293506000926001600160a01b03928316926370a08231926125ef9291169060040161541c565b602060405180830381865afa15801561260c573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061263091906157eb565b905060008161263f848661581a565b111561265c5761264f8383615848565b6126599085615848565b90505b60008160055461266c919061581a565b6005546126799089615a76565b6126839190615aab565b905080600560008282546126979190615848565b90915550600090506126a98289615848565b111561271b576019546001600160a01b0316634f5b636c6126ca838a615848565b6040518263ffffffff1660e01b81526004016126e891815260200190565b600060405180830381600087803b15801561270257600080fd5b505af1158015612716573d6000803e3d6000fd5b505050505b336000908152600860205260409020548111156127475733600090815260086020526040902054612749565b805b3360009081526008602052604081208054909190612768908490615848565b9091555050336000908152600960205260408120805489929061278c908490615848565b90915550506040517f28457ba4ae46aeb68ba5c1a1c15506fb3212bfff27da04dee70b81023a9ebc04906127c59033908a908a90615a02565b60405180910390a150505050505050565b3360009081526002602090815260408083206001600160a01b03861684529091528120548281101561284a5760405162461bcd60e51b815260206004820152601e60248201527f4445435245415345445f414c4c4f57414e43455f42454c4f575f5a45524f000060448201526064016107a1565b6128593385610caf8685615848565b5060019392505050565b6000610854338484613a61565b60008061287c60055490565b90508061288c5750600092915050565b80611eb260035490565b600061085882613bd1565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906128e19084903390600401615727565b602060405180830381865afa1580156128fe573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612922919061573e565b61293e5760405162461bcd60e51b81526004016107a190615760565b61294782613e12565b6001600160a01b0382166000908152601d602052604090819020805460ff19166001179055517fe5526d35f0db491e3e7690717b21c8148a1b5eef07240279db75404df228a59390610a8f90849061541c565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c906129da9084903390600401615727565b602060405180830381865afa1580156129f7573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a1b919061573e565b612a375760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166000908152601c602052604090205460ff16612a6f5760405162461bcd60e51b81526004016107a190615ae3565b6001600160a01b03821660009081526008602052604090205415612ad55760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a204c45444745525f4841535f4e4f4e5f5a45524f5f5354414b450060448201526064016107a1565b6000612ae2836000613fde565b9050600019811415612b325760405162461bcd60e51b815260206004820152601960248201527813125113ce8813115111d15497d393d517d11254d050931151603a1b60448201526064016107a1565b6000839050806001600160a01b031663681fe70c6040518163ffffffff1660e01b8152600401602060405180830381865afa158015612b75573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b99919061573e565b612be15760405162461bcd60e51b81526020600482015260196024820152784c49444f3a204c45444745525f49535f4e4f545f454d50545960381b60448201526064016107a1565b600a805460009190612bf590600190615848565b81548110612c0557612c0561585f565b600091825260209091200154600a80546001600160a01b039092169250829185908110612c3457612c3461585f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600a805480612c7357612c73615b13565b60008281526020808220830160001990810180546001600160a01b03191690559092019092556001600160a01b038781168352601c82526040808420805460ff19169055805163118d75f960e11b81529051601b94939287169263231aebf292600480820193918290030181865afa158015612cf3573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d1791906157eb565b81526020808201929092526040908101600090812080546001600160a01b03191690556001600160a01b0388168152601d90925290205460ff1615612d77576001600160a01b0385166000908152601d60205260409020805460ff191690555b6011546040516369c0bc3d60e11b81526001600160a01b039091169063d381787a90612da790889060040161541c565b600060405180830381600087803b158015612dc157600080fd5b505af1158015612dd5573d6000803e3d6000fd5b5050600e5460405163aac271ed60e01b81526001600160a01b03909116925063aac271ed9150612e0990889060040161541c565b600060405180830381600087803b158015612e2357600080fd5b505af1158015612e37573d6000803e3d6000fd5b505050507fd80173368774864e15485d9749961d73c4199e9ef55d044c8ad3427a15ee151785604051612e6a919061541c565b60405180910390a15050505050565b600061086960035490565b60005460ff1615612ea75760405162461bcd60e51b81526004016107a1906157c1565b6000612eb282612870565b905060008111612efb5760405162461bcd60e51b81526020600482015260146024820152734c49444f3a20414d4f554e545f544f4f5f4c4f5760601b60448201526064016107a1565b612f0433613d9f565b811115612f5f5760405162461bcd60e51b815260206004820152602360248201527f4c49444f3a2052454445454d5f414d4f554e545f455843454544535f42414c416044820152624e434560e81b60648201526084016107a1565b612f69338261409f565b508160056000828254612f7c9190615848565b925050819055508160076000828254612f95919061581a565b90915550506019546040516301e9a69560e41b81526001600160a01b0390911690631e9a695090612fcc9033908690600401615b29565b600060405180830381600087803b158015612fe657600080fd5b505af1158015612ffa573d6000803e3d6000fd5b505060405184815260009250339150600080516020615d498339815191529060200160405180910390a360405182815233907f4896181ff8f4543cc00db9fe9b6fb7e6f032b7eb772c72ab1ec1b4d2e03b93699060200160405180910390a25050565b600a54600b54606091600091613073919061581a565b6001600160401b0381111561308a5761308a615832565b6040519080825280602002602001820160405280156130b3578160200160208202803683370190505b50905060005b600a54600b546130c9919061581a565b811015610c1157600b54811061311357600b54600a906130e99083615848565b815481106130f9576130f961585f565b6000918252602090912001546001600160a01b031661313c565b600b81815481106131265761312661585f565b6000918252602090912001546001600160a01b03165b82828151811061314e5761314e61585f565b6001600160a01b03909216602092830291909101909101528061317081615875565b9150506130b9565b336000908152601c602052604090205460ff166131a75760405162461bcd60e51b81526004016107a190615a23565b60408051608081018252601e5461ffff808216835262010000820481166020840152600160201b82048116938301849052600160301b909104166060820181905290916000916131f69161593a565b61ffff1690506000811161320c5761320c615b42565b836005600082825461321e919061581a565b9091555050336000908152600860205260408120805486929061324290849061581a565b9091555050336000908152600960205260408120805486929061326690849061581a565b9091555050602082015160009061327f90612710615b58565b61ffff1661328d8387615a76565b6132979190615aab565b90506000816132a560055490565b6132af9190615848565b905060006132bc60055490565b905081156132e557816132ce60035490565b6132d89085615a76565b6132e29190615aab565b90505b6016546132fb906001600160a01b0316826141c5565b50600084866040015161ffff16836133139190615a76565b61331d9190615aab565b60165460155491925061333d916001600160a01b0391821691168361429b565b601554613353906001600160a01b03168261442e565b601654613372906001600160a01b031661336d8385615848565b61442e565b7f61953b03ced70bb23c53b5a7058e431e3db88cf84a72660faea0849b785c43bd3389896040516133a593929190615a02565b60405180910390a15050505050505050565b336000908152601c602052604090205460ff166133e65760405162461bcd60e51b81526004016107a190615a23565b3360009081526008602090815260408083205460099092529091205461340d90839061581a565b111561345b5760405162461bcd60e51b815260206004820152601d60248201527f4c49444f3a204c45444745525f4e4f545f454e4f5547485f5354414b4500000060448201526064016107a1565b336000908152600960205260408120805483929061347a90849061581a565b9091555050600d5460405163a9059cbb60e01b81526001600160a01b039091169063a9059cbb906134b19033908590600401615b29565b6020604051808303816000875af11580156134d0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e6b919061573e565b600f54604051633bfc46cb60e21b81527fe6f5d3a94b3b2e5137a1b6bff43c8dde49b099cd4958238240e4ab304e4a2b68916001600160a01b03169063eff11b2c906135469084903390600401615727565b602060405180830381865afa158015613563573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613587919061573e565b6135a35760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166135f95760405162461bcd60e51b815260206004820181905260248201527f4c49444f3a20494e434f52524543545f54524541535552595f4144445245535360448201526064016107a1565b50601680546001600160a01b0319166001600160a01b0392909216919091179055565b600f54604051633bfc46cb60e21b8152600080516020615ce9833981519152916001600160a01b03169063eff11b2c9061365c9084903390600401615727565b602060405180830381865afa158015613679573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061369d919061573e565b6136b95760405162461bcd60e51b81526004016107a190615760565b610e6b82613e12565b600061085882613d9f565b600f54604051633bfc46cb60e21b8152600080516020615d09833981519152916001600160a01b03169063eff11b2c9061370d9084903390600401615727565b602060405180830381865afa15801561372a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061374e919061573e565b61376a5760405162461bcd60e51b81526004016107a190615760565b6001600160a01b0382166137c05760405162461bcd60e51b815260206004820152601f60248201527f4c49444f3a20494e434f52524543545f464143544f52595f414444524553530060448201526064016107a1565b50601880546001600160a01b0319166001600160a01b0392909216919091179055565b6011546001600160a01b0316331461383c5760405162461bcd60e51b815260206004820152601c60248201527b2624a2279d102727aa2fa32927a6afa7a920a1a622afa6a0a9aa22a960211b60448201526064016107a1565b601960009054906101000a90046001600160a01b03166001600160a01b0316637b2077276040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561388c57600080fd5b505af11580156138a0573d6000803e3d6000fd5b505050506138ac614467565b565b60005460ff166138f75760405162461bcd60e51b815260206004820152601460248201527314185d5cd8589b194e881b9bdd081c185d5cd95960621b60448201526064016107a1565b6000805460ff191690557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa335b604051613931919061541c565b60405180910390a1565b60005460ff161561395e5760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166139b05760405162461bcd60e51b8152602060048201526019602482015278415050524f56455f46524f4d5f5a45524f5f4144445245535360381b60448201526064016107a1565b6001600160a01b038216613a005760405162461bcd60e51b8152602060048201526017602482015276415050524f56455f544f5f5a45524f5f4144445245535360481b60448201526064016107a1565b6001600160a01b0383811660008181526002602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6000613a6c82612870565b9050613a7984848361429b565b826001600160a01b0316846001600160a01b0316600080516020615d4983398151915284604051613aac91815260200190565b60405180910390a350505050565b60005b600a54600b54613acd919061581a565b811015613bcb57600b546000908210613b1a57600b54600a90613af09084615848565b81548110613b0057613b0061585f565b6000918252602090912001546001600160a01b0316613b43565b600b8281548110613b2d57613b2d61585f565b6000918252602090912001546001600160a01b03165b60405163416acf8b60e11b81526001600160801b03808816600483015286166024820152604481018590529091506001600160a01b038216906382d59f1690606401600060405180830381600087803b158015613b9f57600080fd5b505af1158015613bb3573d6000803e3d6000fd5b50505050508080613bc390615875565b915050613abd565b50505050565b6000805460ff1615613bf55760405162461bcd60e51b81526004016107a1906157c1565b600c5482600554613c06919061581a565b10613c4f5760405162461bcd60e51b815260206004820152601960248201527804c49444f3a204445504f534954535f4558434545445f43415603c1b60448201526064016107a1565b600d546040516323b872dd60e01b81526001600160a01b03909116906323b872dd90613c8390339030908790600401615a52565b6020604051808303816000875af1158015613ca2573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613cc6919061573e565b5081613d095760405162461bcd60e51b815260206004820152601260248201527113125113ce8816915493d7d1115413d4d25560721b60448201526064016107a1565b6000613d1483612870565b905080613d1e5750815b8260056000828254613d30919061581a565b925050819055508260066000828254613d49919061581a565b90915550613d59905033826141c5565b50613d64338261442e565b60405183815233907f2da466a7b24304f47e87fa2e1e5a81b9831ce54fec19055ce277ca2f39ba42c49060200160405180910390a292915050565b6001600160a01b031660009081526001602052604090205490565b60005460ff1615613ddd5760405162461bcd60e51b81526004016107a1906157c1565b6000805460ff191660011790557f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2586139243390565b6001600160a01b0381166000908152601c602052604090205460ff16613e4a5760405162461bcd60e51b81526004016107a190615ae3565b6000613e57826001613fde565b9050600019811415613ea65760405162461bcd60e51b815260206004820152601860248201527713125113ce8813115111d15497d393d517d153905093115160421b60448201526064016107a1565b600b805460009190613eba90600190615848565b81548110613eca57613eca61585f565b600091825260209091200154600b80546001600160a01b039092169250829184908110613ef957613ef961585f565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550600b805480613f3857613f38615b13565b600082815260208120600019908301810180546001600160a01b03199081169091559201909255600a805460018101825592527fc65a7bb8d6351c1cf70c95a316cc6a92839c986682d98bc35f958f4883f9d2a890910180549091166001600160a01b0385161790556040517f85accaad76657cef23e292273789ae7a13d87db42feff1d70d4056c20d78d07190613fd190859061541c565b60405180910390a1505050565b60008082613fee57600a54613ff2565b600b545b905060005b818110156140935760008461403357600a82815481106140195761401961585f565b6000918252602090912001546001600160a01b031661405c565b600b82815481106140465761404661585f565b6000918252602090912001546001600160a01b03165b9050856001600160a01b0316816001600160a01b03161415614082575091506108589050565b5061408c81615875565b9050613ff7565b50600019949350505050565b6000805460ff16156140c35760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166141165760405162461bcd60e51b815260206004820152601a6024820152794255524e5f46524f4d5f5448455f5a45524f5f4144445245535360301b60448201526064016107a1565b6001600160a01b0383166000908152600160205260409020548083111561417d5760405162461bcd60e51b815260206004820152601b60248201527a4255524e5f414d4f554e545f455843454544535f42414c414e434560281b60448201526064016107a1565b8261418760035490565b6141919190615848565b600381905591506141a28382615848565b6001600160a01b0390941660009081526001602052604090209390935592915050565b6000805460ff16156141e95760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b03831661423a5760405162461bcd60e51b81526020600482015260186024820152774d494e545f544f5f5448455f5a45524f5f4144445245535360401b60448201526064016107a1565b8161424460035490565b61424e919061581a565b60038190556001600160a01b03841660009081526001602052604090205490915061427a90839061581a565b6001600160a01b039093166000908152600160205260409020929092555090565b60005460ff16156142be5760405162461bcd60e51b81526004016107a1906157c1565b6001600160a01b0383166143145760405162461bcd60e51b815260206004820152601e60248201527f5452414e534645525f46524f4d5f5448455f5a45524f5f41444452455353000060448201526064016107a1565b6001600160a01b0382166143695760405162461bcd60e51b815260206004820152601c60248201527b5452414e534645525f544f5f5448455f5a45524f5f4144445245535360201b60448201526064016107a1565b6001600160a01b038316600090815260016020526040902054808211156143d25760405162461bcd60e51b815260206004820152601f60248201527f5452414e534645525f414d4f554e545f455843454544535f42414c414e43450060448201526064016107a1565b6143dc8282615848565b6001600160a01b03808616600090815260016020526040808220939093559085168152205461440c90839061581a565b6001600160a01b03909316600090815260016020526040902092909255505050565b6001600160a01b0382166000600080516020615d4983398151915261445284611e86565b60405190815260200160405180910390a35050565b6000805b600a54600b5461447b919061581a565b81101561462f57600b5460009082106144c857600b54600a9061449e9084615848565b815481106144ae576144ae61585f565b6000918252602090912001546001600160a01b03166144f1565b600b82815481106144db576144db61585f565b6000918252602090912001546001600160a01b03165b6001600160a01b038116600090815260096020908152604080832054600890925290912054919250101561461e576001600160a01b038116600090815260096020908152604080832054600890925282205461454d9190615848565b600654600d546040516370a0823160e01b815292935090916001600160a01b03909116906370a082319061458590309060040161541c565b602060405180830381865afa1580156145a2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906145c691906157eb565b6145d09190615848565b6145da828661581a565b1161461c576145e9818561581a565b6001600160a01b038316600090815260086020526040812080549296508392909190614616908490615848565b90915550505b505b5061462881615875565b905061446b565b508060066000828254614642919061581a565b909155505060065415158061465957506000600754115b156107b257600a541580159061467157506000600754115b15614685576146816007546147ae565b6007555b600060065411801561469957506000600754115b15614765576000600754600654116146b3576006546146b7565b6007545b905080600660008282546146cb9190615848565b9250508190555080600760008282546146e49190615848565b9091555050600d5460195460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb9261471f929116908590600401615b29565b6020604051808303816000875af115801561473e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190614762919061573e565b50505b600b54156107b257600061477a6007546149a9565b6147856006546149a9565b61478f9190615b7b565b905080156147a0576147a081614a13565b506000600681905560075550565b600a54600090806147c1576147c1615b42565b60008060005b8381101561486b57601d6000600a83815481106147e6576147e661585f565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1661485b5760086000600a83815481106148295761482961585f565b60009182526020808320909101546001600160a01b03168352820192909252604001902054614858908461581a565b92505b61486481615875565b90506147c7565b508161487a5750929392505050565b60005b8381101561499557601d6000600a838154811061489c5761489c61585f565b60009182526020808320909101546001600160a01b0316835282019290925260400190205460ff1661498557600060086000600a84815481106148e1576148e161585f565b60009182526020808320909101546001600160a01b03168352820192909252604001812054915084614913838a615a76565b61491d9190615aab565b905081811161492c578061492e565b815b905061493a8183615848565b60086000600a86815481106149515761495161585f565b60009182526020808320909101546001600160a01b03168352820192909252604001902055614980818561581a565b935050505b61498e81615875565b905061487d565b506149a08186615848565b95945050505050565b6000600160ff1b8210614a0f5760405162461bcd60e51b815260206004820152602860248201527f53616665436173743a2076616c756520646f65736e27742066697420696e2061604482015267371034b73a191a9b60c11b60648201526084016107a1565b5090565b600b5480614a2357614a23615b42565b6000816001600160401b03811115614a3d57614a3d615832565b604051908082528060200260200182016040528015614a66578160200160208202803683370190505b5090506000826001600160401b03811115614a8357614a83615832565b604051908082528060200260200182016040528015614aac578160200160208202803683370190505b5090506000836001600160401b03811115614ac957614ac9615832565b604051908082528060200260200182016040528015614af2578160200160208202803683370190505b5090506000846001600160401b03811115614b0f57614b0f615832565b604051908082528060200260200182016040528015614b38578160200160208202803683370190505b50905060008060008088614b4a61085e565b614b549190615aab565b90506000805b8a811015614cff57600b8181548110614b7557614b7561585f565b9060005260206000200160009054906101000a90046001600160a01b0316898281518110614ba557614ba561585f565b60200260200101906001600160a01b031690816001600160a01b031681525050600860008a8381518110614bdb57614bdb61585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054888281518110614c1657614c1661585f565b602002602001018181525050600860008a8381518110614c3857614c3861585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054878281518110614c7357614c7361585f565b602002602001018181525050878181518110614c9157614c9161585f565b602002602001015183614ca49190615b7b565b91506000614cb2838e615bba565b1315614cc557614cc28287615c3f565b95505b818a8281518110614cd857614cd861585f565b6020908102919091010152614ced8285615c3f565b9350614cf881615875565b9050614b5a565b5050508060001480614d0f575082155b15614d1f57505050505050505050565b60016000841215614d3a5750600019614d3784615c80565b93505b60005b89811015614e74578160000b898281518110614d5b57614d5b61585f565b60200260200101818151614d6f9190615bba565b90525088516000908a9083908110614d8957614d8961585f565b60200260200101511315614e64576000858c8b8481518110614dad57614dad61585f565b6020026020010151614dbf9190615bba565b614dc99190615c9d565b9050600081898481518110614de057614de061585f565b6020026020010151614df29190615c3f565b905080600860008c8681518110614e0b57614e0b61585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000208190555080898481518110614e4a57614e4a61585f565b6020908102919091010152614e5f8287615c3f565b955050505b614e6d81615875565b9050614d3d565b506000614e81848c615b7b565b90506000811315614ee65780600860008a600081518110614ea457614ea461585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614edb919061581a565b90915550614fc49050565b6000811215614fc45760005b8a81108015614f015750600082125b15614fc2576000888281518110614f1a57614f1a61585f565b602002602001015190506000811115614fb1576000614f3884615c80565b8211614f445781614f4d565b614f4d84615c80565b905080600860008d8681518110614f6657614f6661585f565b60200260200101516001600160a01b03166001600160a01b031681526020019081526020016000206000828254614f9d9190615848565b90915550614fad90508185615c3f565b9350505b50614fbb81615875565b9050614ef2565b505b506000805b8a811015615215576000898281518110614fe557614fe561585f565b60200260200101516001600160a01b031663a5baabf06040518163ffffffff1660e01b8152600401602060405180830381865afa15801561502a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061504e9190615ccb565b6001600160801b0316600960008c858151811061506d5761506d61585f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546150a09190615848565b90508782815181106150b4576150b461585f565b60200260200101518111801561512057508782815181106150d7576150d761585f565b6020026020010151600860008c85815181106150f5576150f561585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054115b156152045780600860008c858151811061513c5761513c61585f565b60200260200101516001600160a01b03166001600160a01b0316815260200190815260200160002054116151d25787828151811061517c5761517c61585f565b6020026020010151600860008c858151811061519a5761519a61585f565b60200260200101516001600160a01b03166001600160a01b03168152602001908152602001600020546151cd9190615848565b6151f7565b8782815181106151e4576151e461585f565b6020026020010151816151f79190615848565b615201908461581a565b92505b5061520e81615875565b9050614fc9565b50801561529757600d5460195460405163a9059cbb60e01b81526001600160a01b039283169263a9059cbb92615252929116908590600401615b29565b6020604051808303816000875af1158015615271573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190615295919061573e565b505b5050505050505050505050565b60408051608081018252600080825260208201819052918101829052606081019190915290565b600060208083528351808285015260005b818110156152f8578581018301518582016040015282016152dc565b8181111561530a576000604083870101525b50601f01601f1916929092016040019392505050565b6001600160a01b03811681146107b257600080fd5b6000806040838503121561534857600080fd5b823561535381615320565b946020939093013593505050565b60006020828403121561537357600080fd5b8135611ec681615320565b6020808252825182820181905260009190848201906040850190845b818110156153b65783518352928401929184019160010161539a565b50909695505050505050565b6000806000606084860312156153d757600080fd5b83356153e281615320565b925060208401356153f281615320565b929592945050506040919091013590565b60006020828403121561541557600080fd5b5035919050565b6001600160a01b0391909116815260200190565b600060808284031215610c1157600080fd5b6001600160801b03811681146107b257600080fd5b60008060008060008060008060006101208a8c03121561547657600080fd5b893561548181615320565b985060208a013561549181615320565b975060408a01356154a181615320565b965060608a01356154b181615320565b955060808a01356154c181615320565b945060a08a01356154d181615320565b935060c08a01356154e181615320565b925060e08a013591506101008a01356154f981615442565b809150509295985092959850929598565b60008083601f84011261551c57600080fd5b5081356001600160401b0381111561553357600080fd5b6020830191508360208260051b850101111561554e57600080fd5b9250929050565b6000806000806040858703121561556b57600080fd5b84356001600160401b038082111561558257600080fd5b61558e8883890161550a565b909650945060208701359150808211156155a757600080fd5b506155b48782880161550a565b95989497509550505050565b61ffff811681146107b257600080fd5b6000806000606084860312156155e557600080fd5b833592506020840135915060408401356155fe816155c0565b809150509250925092565b60006020828403121561561b57600080fd5b8135611ec681615442565b6000806040838503121561563957600080fd5b50508035926020909101359150565b6000806040838503121561565b57600080fd5b82359150602083013561566d81615320565b809150509250929050565b60008060006060848603121561568d57600080fd5b8335615698816155c0565b925060208401356156a8816155c0565b915060408401356155fe816155c0565b600080604083850312156156cb57600080fd5b82356156d681615320565b9150602083013561566d81615320565b6020808252825182820181905260009190848201906040850190845b818110156153b65783516001600160a01b031683529284019291840191600101615702565b9182526001600160a01b0316602082015260400190565b60006020828403121561575057600080fd5b81518015158114611ec657600080fd5b60208082526012908201527113125113ce8815539055551213d49256915160721b604082015260600190565b600181811c908216806157a057607f821691505b60208210811415610c1157634e487b7160e01b600052602260045260246000fd5b60208082526010908201526f14185d5cd8589b194e881c185d5cd95960821b604082015260600190565b6000602082840312156157fd57600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b6000821982111561582d5761582d615804565b500190565b634e487b7160e01b600052604160045260246000fd5b60008282101561585a5761585a615804565b500390565b634e487b7160e01b600052603260045260246000fd5b600060001982141561588957615889615804565b5060010190565b6000602082840312156158a257600080fd5b8135611ec6816155c0565b81356158b8816155c0565b61ffff8116905081548161ffff19821617835560208401356158d981615442565b6001600160901b03199190911690911760109190911b62010000600160901b031617815560018101604083013561590f81615442565b81546001600160801b0319166001600160801b03919091161790556060919091013560029190910155565b600061ffff80831681851680830382111561595757615957615804565b01949350505050565b6000808335601e1984360301811261597757600080fd5b8301803591506001600160401b0382111561599157600080fd5b6020019150600581901b360382131561554e57600080fd5b6020808252810182905260006001600160fb1b038311156159c957600080fd5b8260051b80856040850137600092016040019182525092915050565b6000602082840312156159f757600080fd5b8151611ec681615320565b6001600160a01b039390931683526020830191909152604082015260600190565b6020808252601590820152742624a2279d102727aa2fa32927a6afa622a223a2a960591b604082015260600190565b6001600160a01b039384168152919092166020820152604081019190915260600190565b6000816000190483118215151615615a9057615a90615804565b500290565b634e487b7160e01b600052601260045260246000fd5b600082615aba57615aba615a95565b500490565b60008060408385031215615ad257600080fd5b505080516020909101519092909150565b60208082526016908201527513125113ce8813115111d15497d393d517d193d5539160521b604082015260600190565b634e487b7160e01b600052603160045260246000fd5b6001600160a01b03929092168252602082015260400190565b634e487b7160e01b600052600160045260246000fd5b600061ffff83811690831681811015615b7357615b73615804565b039392505050565b60008083128015600160ff1b850184121615615b9957615b99615804565b6001600160ff1b0384018313811615615bb457615bb4615804565b50500390565b60006001600160ff1b0381841382841380821686840486111615615be057615be0615804565b600160ff1b6000871282811687830589121615615bff57615bff615804565b60008712925087820587128484161615615c1b57615c1b615804565b87850587128184161615615c3157615c31615804565b505050929093029392505050565b600080821280156001600160ff1b0384900385131615615c6157615c61615804565b600160ff1b8390038412811615615c7a57615c7a615804565b50500190565b6000600160ff1b821415615c9657615c96615804565b5060000390565b600082615cac57615cac615a95565b600160ff1b821460001984141615615cc657615cc6615804565b500590565b600060208284031215615cdd57600080fd5b8151611ec68161544256fe585c6e254ec74f8e72b5cff099811ed8721d9039f710d9a1cb67eed6c74aa8279336eb28e461adb6ba7e620f5006a6952a65a21a4db92c2edb104bf7f1c38c63d76e3374742c17bd14ffaf46cd349ec292baf7d8425512fa8fe132557a4c967bddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220464e927a57b5491842c3381984e580b32914e13b803fa68067ac25932e631ea864736f6c634300080a0033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

Validator Index Block Amount
View All Withdrawals

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

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