Contract 0x891F6825afEbfbB4Bf6889b86724ac859477E4C4

Txn Hash Method
Block
From
To
Value [Txn Fee]
0xdcbefc5fa10e210e798d9851808846c4bc1d07d4a1bbd9bece0cab3c5b9a79b20x608060409066562022-04-27 6:50:36285 days 23 hrs agoLido Staked Polkadot: Deployer IN  Create: Ledger0 GLMR0.1900539
[ Download CSV Export 
Parent Txn Hash Block From To Value
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Ledger

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 10 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

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

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

import "IOracleMaster.sol";
import "ILido.sol";
import "IAuthManager.sol";
import "IRelayEncoder.sol";
import "IXcmTransactor.sol";
import "IController.sol";
import "Types.sol";

import "LedgerUtils.sol";
import "ReportUtils.sol";



contract Ledger {
    using LedgerUtils for Types.OracleData;
    using SafeCast for uint256;

    event DownwardComplete(uint128 amount);
    event UpwardComplete(uint128 amount);
    event Rewards(uint128 amount, uint128 balance);
    event Slash(uint128 amount, uint128 balance);

    // Lido main contract address
    ILido public LIDO;

    // vKSM precompile
    IERC20 internal VKSM;

    // controller for sending xcm messages to relay chain
    IController internal CONTROLLER;

    // ledger stash account
    bytes32 public stashAccount;

    // ledger controller account
    bytes32 public controllerAccount;

    // Stash balance that includes locked (bounded in stake) and free to transfer balance
    uint128 public totalBalance;

    // Locked, or bonded in stake module, balance
    uint128 public lockedBalance;

    // last reported active ledger balance
    uint128 public activeBalance;

    // last reported ledger status
    Types.LedgerStatus public status;

    // Cached stash balance. Need to calculate rewards between successfull up/down transfers
    uint128 public cachedTotalBalance;

    // Pending transfers
    uint128 public transferUpwardBalance;
    uint128 public transferDownwardBalance;

    // Pending bonding
    uint128 public pendingBonds;

    // Minimal allowed balance to being a nominator
    uint128 public MIN_NOMINATOR_BALANCE;

    // Minimal allowable active balance
    uint128 public MINIMUM_BALANCE;

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

    // Maximum allowable unlocking chunks amount
    uint256 public MAX_UNLOCKING_CHUNKS;

    // Allows function calls only from LIDO
    modifier onlyLido() {
        require(msg.sender == address(LIDO), "LEDGER: NOT_LIDO");
        _;
    }

    // Allows function calls only from Oracle
    modifier onlyOracle() {
        address oracle = IOracleMaster(ILido(LIDO).ORACLE_MASTER()).getOracle(address(this));
        require(msg.sender == oracle, "LEDGER: NOT_ORACLE");
        _;
    }

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

    /**
    * @notice Initialize ledger contract.
    * @param _stashAccount - stash account id
    * @param _controllerAccount - controller account id
    * @param _vKSM - vKSM contract address
    * @param _controller - xcmTransactor(relaychain calls relayer) contract address
    * @param _minNominatorBalance - minimal allowed nominator balance
    * @param _lido - LIDO address
    * @param _minimumBalance - minimal allowed active balance for ledger
    * @param _maxUnlockingChunks - maximum amount of unlocking chunks
    */
    function initialize(
        bytes32 _stashAccount,
        bytes32 _controllerAccount,
        address _vKSM,
        address _controller,
        uint128 _minNominatorBalance,
        address _lido,
        uint128 _minimumBalance,
        uint256 _maxUnlockingChunks
    ) external {
        require(_vKSM != address(0), "LEDGER: INCORRECT_VKSM");
        require(address(VKSM) == address(0), "LEDGER: ALREADY_INITIALIZED");

        // The owner of the funds
        stashAccount = _stashAccount;
        // The account which handles bounded part of stash funds (unbond, rebond, withdraw, nominate)
        controllerAccount = _controllerAccount;

        status = Types.LedgerStatus.None;

        LIDO = ILido(_lido);

        VKSM = IERC20(_vKSM);

        CONTROLLER = IController(_controller);

        MIN_NOMINATOR_BALANCE = _minNominatorBalance;

        MINIMUM_BALANCE = _minimumBalance;
        
        MAX_UNLOCKING_CHUNKS = _maxUnlockingChunks;

        _refreshAllowances();
    }

    /**
    * @notice Set new minimal allowed nominator balance and minimal active balance, allowed to call only by lido contract
    * @dev That method designed to be called by lido contract when relay spec is changed
    * @param _minNominatorBalance - minimal allowed nominator balance
    * @param _minimumBalance - minimal allowed ledger active balance
    * @param _maxUnlockingChunks - maximum amount of unlocking chunks
    */
    function setRelaySpecs(uint128 _minNominatorBalance, uint128 _minimumBalance, uint256 _maxUnlockingChunks) external onlyLido {
        MIN_NOMINATOR_BALANCE = _minNominatorBalance;
        MINIMUM_BALANCE = _minimumBalance;
        MAX_UNLOCKING_CHUNKS = _maxUnlockingChunks;
    }

    /**
    * @notice Refresh allowances for ledger
    */
    function refreshAllowances() external auth(ROLE_LEDGER_MANAGER) {
        _refreshAllowances();
    }

    /**
    * @notice Return target stake amount for this ledger
    * @return target stake amount
    */
    function ledgerStake() public view returns (uint256) {
        return LIDO.ledgerStake(address(this));
    }

    /**
    * @notice Return true if ledger doesn't have any funds
    */
    function isEmpty() external view returns (bool) {
        return totalBalance == 0 && transferUpwardBalance == 0 && transferDownwardBalance == 0;
    }

    /**
    * @notice Nominate on behalf of this ledger, allowed to call only by lido contract
    * @dev Method spawns xcm call to relaychain.
    * @param _validators - array of choosen validator to be nominated
    */
    function nominate(bytes32[] calldata _validators) external onlyLido {
        require(activeBalance >= MIN_NOMINATOR_BALANCE, "LEDGER: NOT_ENOUGH_STAKE");
        CONTROLLER.nominate(_validators);
    }

    /**
    * @notice Provide portion of relaychain data about current ledger, allowed to call only by oracle contract
    * @dev Basically, ledger can obtain data from any source, but for now it allowed to recieve only from oracle.
           Method perform calculation of current state based on report data and saved state and expose
           required instructions(relaychain pallet calls) via xcm to adjust bonded amount to required target stake.
    * @param _eraId - reporting era id
    * @param _report - data that represent state of ledger on relaychain for `_eraId`
    */
    function pushData(uint64 _eraId, Types.OracleData memory _report) external onlyOracle {
        require(stashAccount == _report.stashAccount, "LEDGER: STASH_ACCOUNT_MISMATCH");

        status = _report.stakeStatus;
        activeBalance = _report.activeBalance;

        (uint128 unlockingBalance, uint128 withdrawableBalance) = _report.getTotalUnlocking(_eraId);

        if (!_processRelayTransfers(_report)) {
            return;
        }
        uint128 _cachedTotalBalance = cachedTotalBalance;
        
        if (cachedTotalBalance > 0) {
            uint128 relativeDifference = _report.stashBalance > cachedTotalBalance ? 
                _report.stashBalance - cachedTotalBalance :
                cachedTotalBalance - _report.stashBalance;
            // NOTE: 1 / 10000 - one base point
            relativeDifference = relativeDifference * 10000 / cachedTotalBalance;
            require(relativeDifference < LIDO.MAX_ALLOWABLE_DIFFERENCE(), "LEDGER: DIFFERENCE_EXCEEDS_BALANCE");
        }

        if (_cachedTotalBalance < _report.stashBalance) { // if cached balance > real => we have reward
            uint128 reward = _report.stashBalance - _cachedTotalBalance;
            LIDO.distributeRewards(reward, _report.stashBalance);

            emit Rewards(reward, _report.stashBalance);
        }
        else if (_cachedTotalBalance > _report.stashBalance) {
            uint128 slash = _cachedTotalBalance - _report.stashBalance;
            LIDO.distributeLosses(slash, _report.stashBalance);

            emit Slash(slash, _report.stashBalance);
        }

        uint128 _ledgerStake = ledgerStake().toUint128();

        // Always transfer deficit to relay chain
        if (_report.stashBalance < _ledgerStake) {
            uint128 deficit = _ledgerStake - _report.stashBalance;
            require(VKSM.balanceOf(address(LIDO)) >= deficit, "LEDGER: TRANSFER_EXCEEDS_BALANCE");
            LIDO.transferToLedger(deficit);
            CONTROLLER.transferToRelaychain(deficit);
            transferUpwardBalance += deficit;
        }

        uint128 relayFreeBalance = _report.getFreeBalance();
        pendingBonds = 0; // Always set bonds to zero (if we have old free balance then it will bond again)

        if (activeBalance < _ledgerStake) {
            // NOTE: if ledger stake > active balance we are trying to bond all funds
            uint128 diff = _ledgerStake - activeBalance;
            uint128 diffToRebond = diff > unlockingBalance ? unlockingBalance : diff;
            if (diffToRebond > 0) {
                CONTROLLER.rebond(diffToRebond, MAX_UNLOCKING_CHUNKS);
                diff -= diffToRebond;
            }

            if (transferUpwardBalance > 0 && relayFreeBalance == transferUpwardBalance) {
                // In case if bond amount = transferUpwardBalance we can't distinguish 2 messages were success or 2 messages were failed
                relayFreeBalance -= 1;
            }

            if (diff > 0 && relayFreeBalance > 0) {
                uint128 diffToBond = diff > relayFreeBalance ? relayFreeBalance : diff;
                if (_report.stakeStatus == Types.LedgerStatus.Nominator || _report.stakeStatus == Types.LedgerStatus.Idle) {
                    CONTROLLER.bondExtra(diffToBond);
                    pendingBonds = diffToBond;
                } else if (_report.stakeStatus == Types.LedgerStatus.None && diffToBond >= MIN_NOMINATOR_BALANCE) {
                    CONTROLLER.bond(controllerAccount, diffToBond);
                    pendingBonds = diffToBond;
                }
                relayFreeBalance -= diffToBond;
            }
        }
        else {
            if (_ledgerStake < MIN_NOMINATOR_BALANCE && status != Types.LedgerStatus.Idle && activeBalance > 0) {
                CONTROLLER.chill();
            }

            // NOTE: if ledger stake < active balance we unbond
            uint128 diff = activeBalance - _ledgerStake;
            if (diff > 0) {
                CONTROLLER.unbond(diff);
            }

            // NOTE: if ledger stake == active balance we only withdraw unlocked balance
            if (withdrawableBalance > 0) {
                uint32 slashSpans = 0;
                if (_report.unlocking.length == 0 && _report.activeBalance <= MINIMUM_BALANCE) {
                    slashSpans = _report.slashingSpans;
                }
                CONTROLLER.withdrawUnbonded(slashSpans);
            }
        }
        
        // NOTE: always transfer all free baalance to parachain
        if (relayFreeBalance > 0) {
            CONTROLLER.transferToParachain(relayFreeBalance);
            transferDownwardBalance += relayFreeBalance;
        }

        cachedTotalBalance = _report.stashBalance;
    }

    /**
    * @notice Await for all transfers from/to relay chain
    * @param _report - data that represent state of ledger on relaychain
    */
    function _processRelayTransfers(Types.OracleData memory _report) internal returns(bool) {
        // wait for the downward transfer to complete
        uint128 _transferDownwardBalance = transferDownwardBalance;
        if (_transferDownwardBalance > 0) {
            uint128 totalDownwardTransferred = uint128(VKSM.balanceOf(address(this)));

            if (totalDownwardTransferred >= _transferDownwardBalance ) {
                // send all funds to lido
                LIDO.transferFromLedger(_transferDownwardBalance, totalDownwardTransferred - _transferDownwardBalance);

                // Clear transfer flag
                cachedTotalBalance -= _transferDownwardBalance;
                transferDownwardBalance = 0;

                emit DownwardComplete(_transferDownwardBalance);
                _transferDownwardBalance = 0;
            }
        }

        // wait for the upward transfer to complete
        uint128 _transferUpwardBalance = transferUpwardBalance;
        if (_transferUpwardBalance > 0) {
            // NOTE: pending Bonds allows to control balance which was bonded in previous era, but not in lockedBalance yet
            // (see single_ledger_test:test_equal_deposit_bond)
            uint128 ledgerFreeBalance = (totalBalance - lockedBalance);
            int128 freeBalanceDiff = int128(_report.getFreeBalance()) - int128(ledgerFreeBalance);
            int128 expectedBalanceDiff = int128(transferUpwardBalance) - int128(pendingBonds);

            if (freeBalanceDiff >= expectedBalanceDiff) {
                cachedTotalBalance += _transferUpwardBalance;

                transferUpwardBalance = 0;
                // pendingBonds = 0;
                emit UpwardComplete(_transferUpwardBalance);
                _transferUpwardBalance = 0;
            }
        }

        if (_transferDownwardBalance == 0 && _transferUpwardBalance == 0) {
            // update ledger data from oracle report
            totalBalance = _report.stashBalance;
            lockedBalance = _report.totalBalance;
            return true;
        }

        return false;
    }

    /**
    * @notice Refresh allowances for ledger
    */
    function _refreshAllowances() internal {
        VKSM.approve(address(LIDO), type(uint256).max);
        VKSM.approve(address(CONTROLLER), type(uint256).max);
    }
}

File 2 of 12 : 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 12 : 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 12 : 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 5 of 12 : ILido.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "Types.sol";

interface ILido {
    function MAX_ALLOWABLE_DIFFERENCE() external view returns(uint128);

    function deposit(uint256 amount) external returns (uint256);

    function distributeRewards(uint256 totalRewards, uint256 ledgerBalance) external;

    function distributeLosses(uint256 totalLosses, uint256 ledgerBalance) external;

    function getStashAccounts() external view returns (bytes32[] memory);

    function getLedgerAddresses() external view returns (address[] memory);

    function ledgerStake(address ledger) external view returns (uint256);

    function transferFromLedger(uint256 amount, uint256 excess) external;

    function transferFromLedger(uint256 amount) external;

    function transferToLedger(uint256 amount) external;

    function flushStakes() external;

    function findLedger(bytes32 stash) external view returns (address);

    function AUTH_MANAGER() external returns(address);

    function ORACLE_MASTER() external view returns (address);

    function decimals() external view returns (uint8);

    function getPooledKSMByShares(uint256 sharesAmount) external view returns (uint256);

    function getSharesByPooledKSM(uint256 amount) external view returns (uint256);

    function transfer(address recipient, uint256 amount) external returns (bool);

    function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
}

File 6 of 12 : 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 7 of 12 : 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 8 of 12 : IRelayEncoder.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/// @author The Moonbeam Team
/// @title The interface through which solidity contracts will interact with Relay Encoder
/// We follow this same interface including four-byte function selectors, in the precompile that
/// wraps the pallet
interface IRelayEncoder {
    // dev Encode 'bond' relay call
    // Selector: 31627376
    // @param controller_address: Address of the controller
    // @param amount: The amount to bond
    // @param reward_destination: the account that should receive the reward
    // @returns The bytes associated with the encoded call
    function encode_bond(uint256 controller_address, uint256 amount, bytes memory reward_destination) external view returns (bytes memory result);

    // dev Encode 'bond_extra' relay call
    // Selector: 49def326
    // @param amount: The extra amount to bond
    // @returns The bytes associated with the encoded call
    function encode_bond_extra(uint256 amount) external view returns (bytes memory result);

    // dev Encode 'unbond' relay call
    // Selector: bc4b2187
    // @param amount: The amount to unbond
    // @returns The bytes associated with the encoded call
    function encode_unbond(uint256 amount) external view returns (bytes memory result);

    // dev Encode 'withdraw_unbonded' relay call
    // Selector: 2d220331
    // @param slashes: Weight hint, number of slashing spans
    // @returns The bytes associated with the encoded call
    function encode_withdraw_unbonded(uint32 slashes) external view returns (bytes memory result);

    // dev Encode 'validate' relay call
    // Selector: 3a0d803a
    // @param comission: Comission of the validator as parts_per_billion
    // @param blocked: Whether or not the validator is accepting more nominations
    // @returns The bytes associated with the encoded call
    // selector: 3a0d803a
    // function encode_validate(uint256 comission, bool blocked) external pure returns (bytes memory result);

    // dev Encode 'nominate' relay call
    // Selector: a7cb124b
    // @param nominees: An array of AccountIds corresponding to the accounts we will nominate
    // @param blocked: Whether or not the validator is accepting more nominations
    // @returns The bytes associated with the encoded call
    function encode_nominate(uint256 [] memory nominees) external view returns (bytes memory result);

    // dev Encode 'chill' relay call
    // Selector: bc4b2187
    // @returns The bytes associated with the encoded call
    function encode_chill() external view returns (bytes memory result);

    // dev Encode 'set_payee' relay call
    // Selector: 9801b147
    // @param reward_destination: the account that should receive the reward
    // @returns The bytes associated with the encoded call
    // function encode_set_payee(bytes memory reward_destination) external pure returns (bytes memory result);

    // dev Encode 'set_controller' relay call
    // Selector: 7a8f48c2
    // @param controller: The controller address
    // @returns The bytes associated with the encoded call
    // function encode_set_controller(uint256 controller) external pure returns (bytes memory result);

    // dev Encode 'rebond' relay call
    // Selector: add6b3bf
    // @param amount: The amount to rebond
    // @returns The bytes associated with the encoded call
    function encode_rebond(uint256 amount) external view returns (bytes memory result);
}

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

/**
 * @title Xcm Transactor Interface
 *
 * The interface through which solidity contracts will interact with xcm transactor pallet
 *
 */
interface IXcmTransactor {
    // A multilocation is defined by its number of parents and the encoded junctions (interior)
    struct Multilocation {
        uint8 parents;
        bytes [] interior;
    }

    /** Get index of an account in xcm transactor
     *
     * @param index The index of which we want to retrieve the account
     */
    function index_to_account(uint16 index) external view returns(address);

    /** Get transact info of a multilocation
     * Selector 71b0edfa
     * @param multilocation The location for which we want to retrieve transact info
     */
    function transact_info(Multilocation memory multilocation)
        external view  returns(uint64, uint256, uint64, uint64, uint256);

    /** Transact through XCM using fee based on its multilocation
     *
     * @dev The token transfer burns/transfers the corresponding amount before sending
     * @param transactor The transactor to be used
     * @param index The index to be used
     * @param fee_asset The asset in which we want to pay fees.
     * It has to be a reserve of the destination chain
     * @param weight The weight we want to buy in the destination chain
     * @param inner_call The inner call to be executed in the destination chain
     */
    function transact_through_derivative_multilocation(
        uint8 transactor,
        uint16 index,
        Multilocation memory fee_asset,
        uint64 weight,
        bytes memory inner_call
    ) external;

    /** Transact through XCM using fee based on its currency_id
     *
     * @dev The token transfer burns/transfers the corresponding amount before sending
     * @param transactor The transactor to be used
     * @param index The index to be used
     * @param currency_id Address of the currencyId of the asset to be used for fees
     * It has to be a reserve of the destination chain
     * @param weight The weight we want to buy in the destination chain
     * @param inner_call The inner call to be executed in the destination chain
     */
    function transact_through_derivative(
        uint8 transactor,
        uint16 index,
        address currency_id,
        uint64 weight,
        bytes memory inner_call
    ) external;
}

File 10 of 12 : 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 11 of 12 : LedgerUtils.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "Types.sol";


library LedgerUtils {
    /// @notice Return unlocking and withdrawable balances
    function getTotalUnlocking(Types.OracleData memory report, uint64 _eraId) internal pure returns (uint128, uint128) {
        uint128 _total = 0;
        uint128 _withdrawble = 0;
        for (uint i = 0; i < report.unlocking.length; i++) {
            _total += report.unlocking[i].balance;
            if (report.unlocking[i].era <= _eraId) {
                _withdrawble += report.unlocking[i].balance;
            }
        }
        return (_total, _withdrawble);
    }
    /// @notice Return stash balance that can be freely transfer or allocated for stake
    function getFreeBalance(Types.OracleData memory report) internal pure returns (uint128) {
        return report.stashBalance - report.totalBalance;
    }

    /// @notice Return true if report is consistent
    function isConsistent(Types.OracleData memory report) internal pure returns (bool) {
        (uint128 _total,) = getTotalUnlocking(report, 0);
        return report.unlocking.length < type(uint8).max
            && report.totalBalance == (report.activeBalance + _total)
            && report.stashBalance >= report.totalBalance;
    }
}

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


library ReportUtils {
    // last bytes used to count votes
    uint256 constant internal COUNT_OUTMASK = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00;

    /// @notice Check if the given reports are different, not considering the counter of the first
    function isDifferent(uint256 value, uint256 that) internal pure returns (bool) {
        return (value & COUNT_OUTMASK) != that;
    }

    /// @notice Return the total number of votes recorded for the variant
    function getCount(uint256 value) internal pure returns (uint8) {
        return uint8(value);
    }
}

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

Contract ABI

[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"DownwardComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"balance","type":"uint128"}],"name":"Rewards","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"},{"indexed":false,"internalType":"uint128","name":"balance","type":"uint128"}],"name":"Slash","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint128","name":"amount","type":"uint128"}],"name":"UpwardComplete","type":"event"},{"inputs":[],"name":"LIDO","outputs":[{"internalType":"contract ILido","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_UNLOCKING_CHUNKS","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MINIMUM_BALANCE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MIN_NOMINATOR_BALANCE","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"activeBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cachedTotalBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"controllerAccount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_stashAccount","type":"bytes32"},{"internalType":"bytes32","name":"_controllerAccount","type":"bytes32"},{"internalType":"address","name":"_vKSM","type":"address"},{"internalType":"address","name":"_controller","type":"address"},{"internalType":"uint128","name":"_minNominatorBalance","type":"uint128"},{"internalType":"address","name":"_lido","type":"address"},{"internalType":"uint128","name":"_minimumBalance","type":"uint128"},{"internalType":"uint256","name":"_maxUnlockingChunks","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isEmpty","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ledgerStake","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockedBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32[]","name":"_validators","type":"bytes32[]"}],"name":"nominate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingBonds","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"_eraId","type":"uint64"},{"components":[{"internalType":"bytes32","name":"stashAccount","type":"bytes32"},{"internalType":"bytes32","name":"controllerAccount","type":"bytes32"},{"internalType":"enum Types.LedgerStatus","name":"stakeStatus","type":"uint8"},{"internalType":"uint128","name":"activeBalance","type":"uint128"},{"internalType":"uint128","name":"totalBalance","type":"uint128"},{"components":[{"internalType":"uint128","name":"balance","type":"uint128"},{"internalType":"uint64","name":"era","type":"uint64"}],"internalType":"struct Types.UnlockingChunk[]","name":"unlocking","type":"tuple[]"},{"internalType":"uint32[]","name":"claimedRewards","type":"uint32[]"},{"internalType":"uint128","name":"stashBalance","type":"uint128"},{"internalType":"uint32","name":"slashingSpans","type":"uint32"}],"internalType":"struct Types.OracleData","name":"_report","type":"tuple"}],"name":"pushData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"refreshAllowances","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint128","name":"_minNominatorBalance","type":"uint128"},{"internalType":"uint128","name":"_minimumBalance","type":"uint128"},{"internalType":"uint256","name":"_maxUnlockingChunks","type":"uint256"}],"name":"setRelaySpecs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stashAccount","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"status","outputs":[{"internalType":"enum Types.LedgerStatus","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferDownwardBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"transferUpwardBalance","outputs":[{"internalType":"uint128","name":"","type":"uint128"}],"stateMutability":"view","type":"function"}]

608060405234801561001057600080fd5b5061216c806100206000396000f3fe608060405234801561001057600080fd5b50600436106101075760003560e01c806308998c931461010c5780630ab306a01461013557806311b5aede1461014a578063200d2ed214610161578063231aebf2146101825780633113a1a61461018b578063454ea6471461019e578063489ebdd5146101b857806353498cdd146101c0578063681fe70c146101da57806368d52c77146101f25780637b80889b1461020557806382d59f161461021f5780638b21f170146102325780639ca8bddc14610252578063a5baabf01461026c578063ab28c9351461027f578063ad7a672f14610288578063c80f38821461029b578063d70477a6146102ae578063f5330e96146102b6575b600080fd5b60065461011f906001600160801b031681565b60405161012c91906119f2565b60405180910390f35b610148610143366004611c1a565b6102c9565b005b61015360045481565b60405190815260200161012c565b60065461017590600160801b900460ff1681565b60405161012c9190611d40565b61015360035481565b60075461011f906001600160801b031681565b60075461011f90600160801b90046001600160801b031681565b610148611024565b60095461011f90600160801b90046001600160801b031681565b6101e261117b565b604051901515815260200161012c565b60095461011f906001600160801b031681565b60055461011f90600160801b90046001600160801b031681565b61014861022d366004611d68565b6111c1565b600054610245906001600160a01b031681565b60405161012c9190611da9565b60085461011f90600160801b90046001600160801b031681565b60085461011f906001600160801b031681565b610153600a5481565b60055461011f906001600160801b031681565b6101486102a9366004611dd2565b611209565b61015361133b565b6101486102c4366004611e60565b6113ad565b60008060009054906101000a90046001600160a01b03166001600160a01b0316633fd2c16a6040518163ffffffff1660e01b8152600401602060405180830381865afa15801561031d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103419190611ed4565b6001600160a01b03166310d3d22e306040518263ffffffff1660e01b815260040161036c9190611da9565b602060405180830381865afa158015610389573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906103ad9190611ed4565b9050336001600160a01b038216146104015760405162461bcd60e51b81526020600482015260126024820152714c45444745523a204e4f545f4f5241434c4560701b60448201526064015b60405180910390fd5b8151600354146104535760405162461bcd60e51b815260206004820152601e60248201527f4c45444745523a2053544153485f4143434f554e545f4d49534d41544348000060448201526064016103f8565b60408201516006805460ff60801b1916600160801b83600381111561047a5761047a611d2a565b02179055506060820151600680546001600160801b0319166001600160801b039092169190911790556000806104b0848661149b565b915091506104bd84611568565b6104c8575050505050565b6007546001600160801b0316801561063b5760075460e08601516000916001600160801b039081169116116105175760e086015160075461051291906001600160801b0316611f0e565b610532565b60075460e0870151610532916001600160801b031690611f0e565b6007549091506001600160801b031661054d82612710611f36565b6105579190611f65565b905060008054906101000a90046001600160a01b03166001600160a01b0316636a92b5866040518163ffffffff1660e01b8152600401602060405180830381865afa1580156105aa573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105ce9190611f99565b6001600160801b0316816001600160801b0316106106395760405162461bcd60e51b815260206004820152602260248201527f4c45444745523a20444946464552454e43455f455843454544535f42414c414e604482015261434560f01b60648201526084016103f8565b505b8460e001516001600160801b0316816001600160801b03161015610719576000818660e0015161066b9190611f0e565b60005460e088015160405163df6c39fb60e01b81529293506001600160a01b039091169163df6c39fb916106a491859190600401611fb6565b600060405180830381600087803b1580156106be57600080fd5b505af11580156106d2573d6000803e3d6000fd5b505050507f01f4c73b3c8ac2c1250442f70c34f73e178a6707f5771700a53041a31130a7d4818760e0015160405161070b929190611fb6565b60405180910390a1506107f3565b8460e001516001600160801b0316816001600160801b031611156107f35760008560e00151826107499190611f0e565b60005460e088015160405163278325c160e21b81529293506001600160a01b0390911691639e0c97049161078291859190600401611fb6565b600060405180830381600087803b15801561079c57600080fd5b505af11580156107b0573d6000803e3d6000fd5b505050507fe5d0b30e3563f10570c76e157a83c7399a16a326e4b2a34546ebcab1b8da3faf818760e001516040516107e9929190611fb6565b60405180910390a1505b600061080561080061133b565b611876565b9050806001600160801b03168660e001516001600160801b03161015610a165760008660e00151826108379190611f0e565b6001546000546040516370a0823160e01b81529293506001600160801b038416926001600160a01b03928316926370a082319261087992911690600401611da9565b602060405180830381865afa158015610896573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108ba9190611fd0565b10156109085760405162461bcd60e51b815260206004820181905260248201527f4c45444745523a205452414e534645525f455843454544535f42414c414e434560448201526064016103f8565b60005460405163e100610760e01b81526001600160a01b039091169063e1006107906109389084906004016119f2565b600060405180830381600087803b15801561095257600080fd5b505af1158015610966573d6000803e3d6000fd5b505060025460405163c210aefd60e01b81526001600160a01b03909116925063c210aefd915061099a9084906004016119f2565b600060405180830381600087803b1580156109b457600080fd5b505af11580156109c8573d6000803e3d6000fd5b5050505080600760108282829054906101000a90046001600160801b03166109f09190611fe9565b92506101000a8154816001600160801b0302191690836001600160801b03160217905550505b6000610a21876118df565b600880546001600160801b0390811690915560065491925083811691161015610d3e57600654600090610a5d906001600160801b031684611f0e565b90506000866001600160801b0316826001600160801b031611610a805781610a82565b865b90506001600160801b03811615610b1357600254600a546040516332bd45dd60e11b81526001600160801b038416600482015260248101919091526001600160a01b039091169063657a8bba90604401600060405180830381600087803b158015610aec57600080fd5b505af1158015610b00573d6000803e3d6000fd5b505050508082610b109190611f0e565b91505b600754600160801b90046001600160801b031615801590610b4857506007546001600160801b03848116600160801b90920416145b15610b5b57610b58600184611f0e565b92505b6000826001600160801b0316118015610b7d57506000836001600160801b0316115b15610d37576000836001600160801b0316836001600160801b031611610ba35782610ba5565b835b905060018a604001516003811115610bbf57610bbf611d2a565b1480610be0575060008a604001516003811115610bde57610bde611d2a565b145b15610c6757600254604051637565446f60e11b81526001600160a01b039091169063eaca88de90610c159084906004016119f2565b600060405180830381600087803b158015610c2f57600080fd5b505af1158015610c43573d6000803e3d6000fd5b5050600880546001600160801b03808616600160801b02911617905550610d299050565b60038a604001516003811115610c7f57610c7f611d2a565b148015610c9b57506009546001600160801b0390811690821610155b15610d2957600254600480546040516351f9321560e01b8152918201526001600160801b03831660248201526001600160a01b03909116906351f9321590604401600060405180830381600087803b158015610cf657600080fd5b505af1158015610d0a573d6000803e3d6000fd5b5050600880546001600160801b03808616600160801b02911617905550505b610d338185611f0e565b9350505b5050610f40565b6009546001600160801b03908116908316108015610d7a57506000600654600160801b900460ff166003811115610d7757610d77611d2a565b14155b8015610d9057506006546001600160801b031615155b15610dfe57600260009054906101000a90046001600160a01b03166001600160a01b0316632b8a3ae66040518163ffffffff1660e01b8152600401600060405180830381600087803b158015610de557600080fd5b505af1158015610df9573d6000803e3d6000fd5b505050505b600654600090610e189084906001600160801b0316611f0e565b90506001600160801b03811615610e8c576002546040516313ef4f1960e11b81526001600160a01b03909116906327de9e3290610e599084906004016119f2565b600060405180830381600087803b158015610e7357600080fd5b505af1158015610e87573d6000803e3d6000fd5b505050505b6001600160801b03851615610f3e5760008860a00151516000148015610ecc575060095460608a01516001600160801b03600160801b9092048216911611155b15610ed957506101008801515b600254604051632a45338360e11b815263ffffffff831660048201526001600160a01b039091169063548a670690602401600060405180830381600087803b158015610f2457600080fd5b505af1158015610f38573d6000803e3d6000fd5b50505050505b505b6001600160801b03811615610ff5576002546040516301753af160e61b81526001600160a01b0390911690635d4ebc4090610f7f9084906004016119f2565b600060405180830381600087803b158015610f9957600080fd5b505af1158015610fad573d6000803e3d6000fd5b505060088054849350909150600090610fd09084906001600160801b0316611fe9565b92506101000a8154816001600160801b0302191690836001600160801b031602179055505b5050505060e09290920151600780546001600160801b0319166001600160801b03909216919091179055505050565b7f585c6e254ec74f8e72b5cff099811ed8721d9039f710d9a1cb67eed6c74aa82760008054906101000a90046001600160a01b03166001600160a01b031663a1e206c76040518163ffffffff1660e01b81526004016020604051808303816000875af1158015611098573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906110bc9190611ed4565b604051633bfc46cb60e21b8152600481018390523360248201526001600160a01b03919091169063eff11b2c90604401602060405180830381865afa158015611109573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061112d9190612014565b6111705760405162461bcd60e51b815260206004820152601460248201527313115111d1548e8815539055551213d493d6915160621b60448201526064016103f8565b6111786118fb565b50565b6005546000906001600160801b03161580156111a75750600754600160801b90046001600160801b0316155b80156111bc57506008546001600160801b0316155b905090565b6000546001600160a01b031633146111eb5760405162461bcd60e51b81526004016103f890612036565b6001600160801b03918216600160801b029190921617600955600a55565b6001600160a01b0386166112585760405162461bcd60e51b81526020600482015260166024820152754c45444745523a20494e434f52524543545f564b534d60501b60448201526064016103f8565b6001546001600160a01b0316156112af5760405162461bcd60e51b815260206004820152601b60248201527a13115111d1548e881053149150511657d253925512505312569151602a1b60448201526064016103f8565b600388815560048890556006805460ff60801b1916600160801b830217905550600080546001600160a01b038086166001600160a01b0319928316179092556001805489841690831617905560028054928816929091169190911790556001600160801b03828116600160801b0290851617600955600a8190556113316118fb565b5050505050505050565b6000805460405163f144719560e01b81526001600160a01b039091169063f14471959061136c903090600401611da9565b602060405180830381865afa158015611389573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111bc9190611fd0565b6000546001600160a01b031633146113d75760405162461bcd60e51b81526004016103f890612036565b6009546006546001600160801b03918216911610156114335760405162461bcd60e51b81526020600482015260186024820152774c45444745523a204e4f545f454e4f5547485f5354414b4560401b60448201526064016103f8565b600254604051637a99874b60e11b81526001600160a01b039091169063f5330e96906114659085908590600401612060565b600060405180830381600087803b15801561147f57600080fd5b505af1158015611493573d6000803e3d6000fd5b505050505050565b60008060008060005b8660a001515181101561155c578660a0015181815181106114c7576114c761209c565b602002602001015160000151836114de9190611fe9565b9250856001600160401b03168760a0015182815181106115005761150061209c565b6020026020010151602001516001600160401b03161161154a578660a0015181815181106115305761153061209c565b602002602001015160000151826115479190611fe9565b91505b80611554816120b2565b9150506114a4565b50909590945092505050565b6008546000906001600160801b03168015611706576001546040516370a0823160e01b81526000916001600160a01b0316906370a08231906115ae903090600401611da9565b602060405180830381865afa1580156115cb573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115ef9190611fd0565b9050816001600160801b0316816001600160801b031610611704576000546001600160a01b03166361f9c3da836116268185611f0e565b6040518363ffffffff1660e01b8152600401611643929190611fb6565b600060405180830381600087803b15801561165d57600080fd5b505af1158015611671573d6000803e3d6000fd5b5050600780548593509091506000906116949084906001600160801b0316611f0e565b82546001600160801b039182166101009390930a928302919092021990911617905550600880546001600160801b03191690556040517f52a25fb647d899c87c6b0cab19bee2192a1dfd24a218ce175ac71e3b71963c32906116f79084906119f2565b60405180910390a1600091505b505b600754600160801b90046001600160801b0316801561181f57600554600090611741906001600160801b03600160801b820481169116611f0e565b905060008161174f876118df565b61175991906120cd565b600854600754919250600091611787916001600160801b03600160801b9182900481169291909104166120cd565b905080600f0b82600f0b1261181b57600780548591906000906117b49084906001600160801b0316611fe9565b82546101009290920a6001600160801b03818102199093169183160217909155600780549091169055506040517f5cc8f2d8958f89eface0ae3413232fdf21e4c334f8b030f014e056c77db694ee9061180e9086906119f2565b60405180910390a1600093505b5050505b6001600160801b03821615801561183d57506001600160801b038116155b1561186c5750505060e08101516080909101516001600160801b03908116600160801b02911617600555600190565b5060009392505050565b6000600160801b82106118db5760405162461bcd60e51b815260206004820152602760248201527f53616665436173743a2076616c756520646f65736e27742066697420696e20316044820152663238206269747360c81b60648201526084016103f8565b5090565b600081608001518260e001516118f59190611f0e565b92915050565b60015460005460405163095ea7b360e01b81526001600160a01b039283169263095ea7b392611933929116906000199060040161211d565b6020604051808303816000875af1158015611952573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119769190612014565b5060015460025460405163095ea7b360e01b81526001600160a01b039283169263095ea7b3926119af929116906000199060040161211d565b6020604051808303816000875af11580156119ce573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111789190612014565b6001600160801b0391909116815260200190565b80356001600160401b0381168114611a1d57600080fd5b919050565b634e487b7160e01b600052604160045260246000fd5b604080519081016001600160401b0381118282101715611a5a57611a5a611a22565b60405290565b60405161012081016001600160401b0381118282101715611a5a57611a5a611a22565b604051601f8201601f191681016001600160401b0381118282101715611aab57611aab611a22565b604052919050565b803560048110611a1d57600080fd5b6001600160801b038116811461117857600080fd5b8035611a1d81611ac2565b60006001600160401b03821115611afb57611afb611a22565b5060051b60200190565b600082601f830112611b1657600080fd5b81356020611b2b611b2683611ae2565b611a83565b82815260069290921b84018101918181019086841115611b4a57600080fd5b8286015b84811015611b995760408189031215611b675760008081fd5b611b6f611a38565b8135611b7a81611ac2565b8152611b87828601611a06565b81860152835291830191604001611b4e565b509695505050505050565b803563ffffffff81168114611a1d57600080fd5b600082601f830112611bc957600080fd5b81356020611bd9611b2683611ae2565b82815260059290921b84018101918181019086841115611bf857600080fd5b8286015b84811015611b9957611c0d81611ba4565b8352918301918301611bfc565b60008060408385031215611c2d57600080fd5b611c3683611a06565b915060208301356001600160401b0380821115611c5257600080fd5b908401906101208287031215611c6757600080fd5b611c6f611a60565b8235815260208301356020820152611c8960408401611ab3565b6040820152611c9a60608401611ad7565b6060820152611cab60808401611ad7565b608082015260a083013582811115611cc257600080fd5b611cce88828601611b05565b60a08301525060c083013582811115611ce657600080fd5b611cf288828601611bb8565b60c083015250611d0460e08401611ad7565b60e08201526101009150611d19828401611ba4565b828201528093505050509250929050565b634e487b7160e01b600052602160045260246000fd5b6020810160048310611d6257634e487b7160e01b600052602160045260246000fd5b91905290565b600080600060608486031215611d7d57600080fd5b8335611d8881611ac2565b92506020840135611d9881611ac2565b929592945050506040919091013590565b6001600160a01b0391909116815260200190565b6001600160a01b038116811461117857600080fd5b600080600080600080600080610100898b031215611def57600080fd5b88359750602089013596506040890135611e0881611dbd565b95506060890135611e1881611dbd565b94506080890135611e2881611ac2565b935060a0890135611e3881611dbd565b925060c0890135611e4881611ac2565b8092505060e089013590509295985092959890939650565b60008060208385031215611e7357600080fd5b82356001600160401b0380821115611e8a57600080fd5b818501915085601f830112611e9e57600080fd5b813581811115611ead57600080fd5b8660208260051b8501011115611ec257600080fd5b60209290920196919550909350505050565b600060208284031215611ee657600080fd5b8151611ef181611dbd565b9392505050565b634e487b7160e01b600052601160045260246000fd5b60006001600160801b0383811690831681811015611f2e57611f2e611ef8565b039392505050565b60006001600160801b0382811684821681151582840482111615611f5c57611f5c611ef8565b02949350505050565b60006001600160801b0383811680611f8d57634e487b7160e01b600052601260045260246000fd5b92169190910492915050565b600060208284031215611fab57600080fd5b8151611ef181611ac2565b6001600160801b0392831681529116602082015260400190565b600060208284031215611fe257600080fd5b5051919050565b60006001600160801b0382811684821680830382111561200b5761200b611ef8565b01949350505050565b60006020828403121561202657600080fd5b81518015158114611ef157600080fd5b60208082526010908201526f4c45444745523a204e4f545f4c49444f60801b604082015260600190565b6020808252810182905260006001600160fb1b0383111561208057600080fd5b8260051b80856040850137600092016040019182525092915050565b634e487b7160e01b600052603260045260246000fd5b60006000198214156120c6576120c6611ef8565b5060010190565b6000600f82810b9084900b828112801560016001607f1b03198301841216156120f8576120f8611ef8565b60016001607f1b038201831381161561211357612113611ef8565b5090039392505050565b6001600160a01b0392909216825260208201526040019056fea2646970667358221220974b79ea7b426a01eaf2a7031459f6803c9f75ed39dcd6d3bce79de80974c95964736f6c634300080a0033

Block Transaction Gas Used Reward
Age Block Fee Address BC Fee Address Voting Power Jailed Incoming
Block Uncle Number Difficulty Gas Used Reward
Loading
Make sure to use the "Vote Down" button for any spammy posts, and the "Vote Up" for interesting conversations.