ETH Price: $2,112.66 (+6.60%)

Contract

0xCE15294273CFb9D9b628F4D61636623decDF4fdC
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Deposit245880092026-03-05 1:34:3522 mins ago1772674475IN
0xCE152942...decDF4fdC
1.6 ETH0.000014560.09051901
Withdraw Credit245869382026-03-04 21:59:473 hrs ago1772661587IN
0xCE152942...decDF4fdC
0 ETH0.000013530.08620372
Assign Deposits245867792026-03-04 21:27:474 hrs ago1772659667IN
0xCE152942...decDF4fdC
0 ETH0.000227350.12038303
Deposit245863622026-03-04 20:03:595 hrs ago1772654639IN
0xCE152942...decDF4fdC
1 ETH0.000035120.21833944
Deposit245861882026-03-04 19:28:596 hrs ago1772652539IN
0xCE152942...decDF4fdC
0.5492 ETH0.000103160.5796
Deposit245830122026-03-04 8:51:2317 hrs ago1772614283IN
0xCE152942...decDF4fdC
6.87128353 ETH0.000369812.07779438
Deposit245828582026-03-04 8:20:3517 hrs ago1772612435IN
0xCE152942...decDF4fdC
8 ETH0.000051120.28722365
Withdraw Credit245820202026-03-04 5:31:3520 hrs ago1772602295IN
0xCE152942...decDF4fdC
0 ETH0.000019980.142785
Withdraw Credit245819452026-03-04 5:16:3520 hrs ago1772601395IN
0xCE152942...decDF4fdC
0 ETH0.000019510.139439
Deposit245812632026-03-04 2:59:5922 hrs ago1772593199IN
0xCE152942...decDF4fdC
0.1 ETH0.000007450.03918091
Deposit245811582026-03-04 2:38:4723 hrs ago1772591927IN
0xCE152942...decDF4fdC
2.77322148 ETH0.000370062.1379639
Deposit245807552026-03-04 1:17:3524 hrs ago1772587055IN
0xCE152942...decDF4fdC
0.3 ETH0.000008580.04957722
Deposit245806262026-03-04 0:51:3525 hrs ago1772585495IN
0xCE152942...decDF4fdC
0.1988 ETH0.000355582.05430275
Assign Deposits245803502026-03-03 23:55:3526 hrs ago1772582135IN
0xCE152942...decDF4fdC
0 ETH0.000153040.10680381
Deposit245803472026-03-03 23:54:5926 hrs ago1772582099IN
0xCE152942...decDF4fdC
79 ETH0.000114660.2
Deposit245803282026-03-03 23:51:1126 hrs ago1772581871IN
0xCE152942...decDF4fdC
79 ETH0.00014920.2
Deposit245803052026-03-03 23:46:3526 hrs ago1772581595IN
0xCE152942...decDF4fdC
75 ETH0.000114040.2
Deposit245802352026-03-03 23:32:2326 hrs ago1772580743IN
0xCE152942...decDF4fdC
2.747 ETH0.000011890.06256292
Deposit245801862026-03-03 23:22:2326 hrs ago1772580143IN
0xCE152942...decDF4fdC
50 ETH0.00008880.2
Deposit245796902026-03-03 21:42:5928 hrs ago1772574179IN
0xCE152942...decDF4fdC
5 ETH0.000029910.17280098
Deposit245793082026-03-03 20:26:3529 hrs ago1772569595IN
0xCE152942...decDF4fdC
0.0277 ETH0.00003660.21146813
Deposit245775072026-03-03 14:24:2335 hrs ago1772547863IN
0xCE152942...decDF4fdC
1,500 ETH0.000822880.12115962
Deposit245774722026-03-03 14:17:2335 hrs ago1772547443IN
0xCE152942...decDF4fdC
1.185 ETH0.000023750.12488902
Deposit245769272026-03-03 12:27:2337 hrs ago1772540843IN
0xCE152942...decDF4fdC
0.015 ETH0.000380952.140381
Deposit245768752026-03-03 12:16:5937 hrs ago1772540219IN
0xCE152942...decDF4fdC
0.87 ETH0.000026650.16567009
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Method Block
From
To
Deposit Excess245880092026-03-05 1:34:3522 mins ago1772674475
0xCE152942...decDF4fdC
1.6 ETH
Assign Funds245878672026-03-05 1:06:1150 mins ago1772672771
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245878672026-03-05 1:06:1150 mins ago1772672771
0xCE152942...decDF4fdC
32 ETH
Deposit Ether245878672026-03-05 1:06:1150 mins ago1772672771
0xCE152942...decDF4fdC
24 ETH
Node Deposit245878672026-03-05 1:06:1150 mins ago1772672771
0xCE152942...decDF4fdC
24 ETH
Assign Funds245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Assign Funds245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Assign Funds245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
32 ETH
Deposit Ether245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
88 ETH
Node Deposit245869002026-03-04 21:51:594 hrs ago1772661119
0xCE152942...decDF4fdC
88 ETH
Assign Funds245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
32 ETH
Assign Funds245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
32 ETH
Deposit Ether245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
80 ETH
Node Deposit245868942026-03-04 21:50:474 hrs ago1772661047
0xCE152942...decDF4fdC
80 ETH
Assign Funds245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
Assign Funds245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
Assign Funds245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
Receive Vault Wi...245868882026-03-04 21:49:354 hrs ago1772660975
0xCE152942...decDF4fdC
32 ETH
View All Internal Transactions
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Validator Index Block Amount
View All Withdrawals

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

Contract Source Code Verified (Exact Match)

Contract Name:
RocketDepositPool

Compiler Version
v0.8.30+commit.73712a01

Optimization Enabled:
Yes with 15000 runs

Other Settings:
paris EvmVersion, GNU GPLv3 license
File 1 of 30 : RocketDepositPool.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.30;

import {SafeCast} from "@openzeppelin4/contracts/utils/math/SafeCast.sol";

import {RocketNetworkBalancesInterface} from "../../interface/network/RocketNetworkBalancesInterface.sol";
import {AddressQueueStorageInterface} from "../../interface/util/AddressQueueStorageInterface.sol";
import {LinkedListStorageInterface} from "../../interface/util/LinkedListStorageInterface.sol";
import {RocketBase} from "../RocketBase.sol";
import {RocketDAOProtocolSettingsDepositInterface} from "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsDepositInterface.sol";
import {RocketDAOProtocolSettingsMinipoolInterface} from "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
import {RocketDAOProtocolSettingsNetworkInterface} from "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNetworkInterface.sol";
import {RocketDepositPoolInterface} from "../../interface/deposit/RocketDepositPoolInterface.sol";
import {RocketMegapoolDelegateInterface} from "../../interface/megapool/RocketMegapoolDelegateInterface.sol";
import {RocketMegapoolInterface} from "../../interface/megapool/RocketMegapoolInterface.sol";
import {RocketMinipoolInterface} from "../../interface/minipool/RocketMinipoolInterface.sol";
import {RocketMinipoolQueueInterface} from "../../interface/minipool/RocketMinipoolQueueInterface.sol";
import {RocketNetworkSnapshotsInterface} from "../../interface/network/RocketNetworkSnapshotsInterface.sol";
import {RocketNodeManagerInterface} from "../../interface/node/RocketNodeManagerInterface.sol";
import {RocketStorageInterface} from "../../interface/RocketStorageInterface.sol";
import {RocketTokenRETHInterface} from "../../interface/token/RocketTokenRETHInterface.sol";
import {RocketVaultInterface} from "../../interface/RocketVaultInterface.sol";
import {RocketVaultWithdrawerInterface} from "../../interface/RocketVaultWithdrawerInterface.sol";
import {RocketMegapoolFactoryInterface} from "../../interface/megapool/RocketMegapoolFactoryInterface.sol";

/// @notice Accepts user deposits and mints rETH; handles assignment of deposited ETH to megapools
contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaultWithdrawerInterface {
    // Constants
    uint256 internal constant milliToWei = 10 ** 15;
    bytes32 internal constant queueKeyMinipoolVariable = keccak256("minipools.available.variable");
    bytes32 internal constant expressQueueNamespace = keccak256("deposit.queue.express");
    bytes32 internal constant standardQueueNamespace = keccak256("deposit.queue.standard");
    bytes32 internal constant queueMovedKey = keccak256("megapool.queue.moved");
    bytes32 internal constant nodeBalanceKey = "deposit.pool.node.balance"; // Note: this is not hashed due to bug in earlier contract
    bytes32 internal constant requestedTotalKey = keccak256("deposit.pool.requested.total");
    bytes32 internal constant queueIndexKey = keccak256("megapool.queue.index");

    // Immutables
    RocketVaultInterface immutable internal rocketVault;
    RocketTokenRETHInterface immutable internal rocketTokenRETH;

    // Events
    event DepositReceived(address indexed from, uint256 amount, uint256 time);
    event DepositRecycled(address indexed from, uint256 amount, uint256 time);
    event DepositAssigned(address indexed minipool, uint256 amount, uint256 time);
    event ExcessWithdrawn(address indexed to, uint256 amount, uint256 time);
    event FundsRequested(address indexed receiver, uint256 validatorId, uint256 amount, bool expressQueue, uint256 time);
    event FundsAssigned(address indexed receiver, uint256 amount, uint256 time);
    event QueueExited(address indexed nodeAddress, uint256 time);
    event CreditWithdrawn(address indexed nodeAddress, uint256 amount, uint256 time);

    // Structs
    struct MinipoolAssignment {
        address minipoolAddress;
        uint256 etherAssigned;
    }

    // Modifiers
    modifier onlyThisLatestContract() {
        // Compiler can optimise out this keccak at compile time
        require(address(this) == getAddress(keccak256("contract.addressrocketDepositPool")), "Invalid or outdated contract");
        _;
    }

    constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
        version = 4;
        // Pre-retrieve non-upgradable contract addresses to save gas
        rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
        rocketTokenRETH = RocketTokenRETHInterface(getContractAddress("rocketTokenRETH"));
    }

    /// @notice Returns the current deposit pool balance
    function getBalance() override public view returns (uint256) {
        return rocketVault.balanceOf("rocketDepositPool");
    }

    /// @notice Returns the amount of ETH contributed to the deposit pool by node operators waiting in the queue
    function getNodeBalance() override public view returns (uint256) {
        return getUint(nodeBalanceKey);
    }

    /// @notice Returns the user owned portion of the deposit pool
    /// @dev Negative indicates more ETH has been "lent" to the deposit pool by node operators in the queue
    ///      than is available from user deposits
    function getUserBalance() override public view returns (int256) {
        return int256(getBalance()) - int256(getNodeBalance());
    }

    /// @notice Returns the credit balance for a given node operator
    /// @param _nodeAddress Address of the node operator to query
    function getNodeCreditBalance(address _nodeAddress) override public view returns (uint256) {
        return getUint(keccak256(abi.encodePacked("node.deposit.credit.balance", _nodeAddress)));
    }

    /// @notice Excess deposit pool balance (in excess of validator queue)
    function getExcessBalance() override public view returns (uint256) {
        // Get minipool queue capacity
        RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
        uint256 capacity = rocketMinipoolQueue.getEffectiveCapacity();
        capacity += getUint(requestedTotalKey);
        uint256 balance = getBalance();
        // Calculate and return
        if (capacity >= balance) {
            return 0;
        } else {
            return balance - capacity;
        }
    }

    /// @dev Callback required to receive ETH withdrawal from the vault
    function receiveVaultWithdrawalETH() override external payable onlyThisLatestContract onlyLatestContract("rocketVault", msg.sender) {}

    /// @notice Deposits ETH into Rocket Pool and mints the corresponding amount of rETH to the caller
    function deposit() override external payable onlyThisLatestContract {
        // Check deposit settings
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled");
        require(msg.value >= rocketDAOProtocolSettingsDeposit.getMinimumDeposit(), "The deposited amount is less than the minimum deposit size");
        /*
            Check if deposit exceeds limit based on current deposit size and minipool queue capacity.

            The deposit pool can, at most, accept a deposit that, after assignments, matches ETH to every minipool in
            the queue and leaves the deposit pool with maximumDepositPoolSize ETH.

            capacityNeeded = depositPoolBalance + msg.value
            maxCapacity = maximumDepositPoolSize + queueEffectiveCapacity
            assert(capacityNeeded <= maxCapacity)
        */
        uint256 capacityNeeded;
        unchecked { // Infeasible overflow
            capacityNeeded = getBalance() + msg.value;
        }
        uint256 maxDepositPoolSize = rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize();
        if (capacityNeeded > maxDepositPoolSize) {
            // Doing a conditional require() instead of a single one optimises for the common
            // case where capacityNeeded fits in the deposit pool without looking at the queue
            if (rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
                RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
                uint256 capacity = rocketMinipoolQueue.getEffectiveCapacity();
                capacity += getUint(requestedTotalKey);
                require(capacityNeeded <= maxDepositPoolSize + capacity, "The deposit pool size after depositing exceeds the maximum size");
            } else {
                revert("The deposit pool size after depositing exceeds the maximum size");
            }
        }
        // Calculate deposit fee
        unchecked { // depositFee < msg.value
            uint256 depositFee = msg.value * rocketDAOProtocolSettingsDeposit.getDepositFee() / calcBase;
            uint256 depositNet = msg.value - depositFee;
            // Mint rETH to user account
            rocketTokenRETH.mint(depositNet, msg.sender);
        }
        // Emit deposit received event
        emit DepositReceived(msg.sender, msg.value, block.timestamp);
        // Process deposit
        processDeposit();
    }

    /// @notice Returns the maximum amount that can be accepted into the deposit pool at this time in wei
    function getMaximumDepositAmount() override external view returns (uint256) {
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        // If deposits are disabled max deposit is 0
        if (!rocketDAOProtocolSettingsDeposit.getDepositEnabled()) {
            return 0;
        }
        uint256 depositPoolBalance = getBalance();
        uint256 maxCapacity = rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize();
        // When assignments are enabled, we can accept the max amount plus whatever space is available in the minipool queue
        if (rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
            RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
            maxCapacity += rocketMinipoolQueue.getEffectiveCapacity();
            maxCapacity += getUint(requestedTotalKey);
        }
        // Check we aren't already over
        if (depositPoolBalance >= maxCapacity) {
            return 0;
        }
        return maxCapacity - depositPoolBalance;
    }

    /// @notice Accepts ETH deposit from the node deposit contract (does not mint rETH)
    /// @param _bondAmount The total node deposit amount including any credit balance used
    function nodeDeposit(uint256 _bondAmount) override external payable onlyThisLatestContract onlyLatestContract("rocketNodeDeposit", msg.sender) {
        // Deposit ETH into the vault
        if (msg.value > 0) {
            rocketVault.depositEther{value: msg.value}();
        }
        // Increase recorded node balance
        addUint(nodeBalanceKey, _bondAmount);
    }

    /// @notice Recycle a deposit from a dissolved validator
    function recycleDissolvedDeposit() override external payable onlyThisLatestContract onlyRegisteredMinipoolOrMegapool(msg.sender) {
        _recycleValue();
    }

    /// @notice Recycle excess ETH from the rETH token contract
    function recycleExcessCollateral() override external payable onlyThisLatestContract onlyLatestContract("rocketTokenRETH", msg.sender) {
        _recycleValue();
    }

    /// @notice Recycle a liquidated RPL stake from a slashed minipool
    function recycleLiquidatedStake() override external payable onlyThisLatestContract onlyLatestContract("rocketAuctionManager", msg.sender) {
        _recycleValue();
    }

    /// @dev Recycles msg.value into the deposit pool
    function _recycleValue() internal {
        // Recycle ETH
        emit DepositRecycled(msg.sender, msg.value, block.timestamp);
        processDeposit();
    }

    /// @dev Deposits incoming funds into rETH buffer and excess into vault then performs assignment
    function processDeposit() internal {
        // Direct deposit ETH to rETH until target collateral is reached
        uint256 toReth = _getRethCollateralShortfall();
        if (toReth > msg.value) {
            toReth = msg.value;
        }
        uint256 toVault = msg.value - toReth;
        if (toReth > 0) {
            rocketTokenRETH.depositExcess{value: toReth}();
        }
        if (toVault > 0) {
            rocketVault.depositEther{value: toVault}();
        }
        // Assign deposits if enabled
        _assignByDeposit();
    }

    /// @dev Returns the shortfall in ETH from the target collateral rate of rETH
    function _getRethCollateralShortfall() internal returns (uint256) {
        // Load contracts
        RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork"));
        RocketNetworkBalancesInterface rocketNetworkBalances = RocketNetworkBalancesInterface(getContractAddress("rocketNetworkBalances"));
        // Calculate target collateral
        uint256 targetCollateralRate = rocketDAOProtocolSettingsNetwork.getTargetRethCollateralRate();
        uint256 rocketTokenRETHBalance = address(rocketTokenRETH).balance;
        uint256 totalCollateral = rocketNetworkBalances.getTotalETHBalance();
        uint256 targetCollateral = totalCollateral * targetCollateralRate / calcBase;
        // Calculate shortfall
        if (targetCollateral > rocketTokenRETHBalance) {
            return targetCollateral - rocketTokenRETHBalance;
        }
        return 0;
    }

    /// @notice If deposit assignments are enabled, assigns up to specified number of minipools/megapools
    /// @param _max Maximum number of minipools/megapools to assign
    function maybeAssignDeposits(uint256 _max) override external onlyThisLatestContract {
        require(_max > 0, "Must assign at least 1");
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        if (!rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
            return;
        }
        _assignDeposits(_max, rocketDAOProtocolSettingsDeposit);
    }

    /// @notice Assigns up to specified number of minipools or megapools, reverts if assignments are disabled
    /// @param _max Maximum number of minipools/megapools to assign
    function assignDeposits(uint256 _max) override external onlyThisLatestContract {
        require(_max > 0, "Must assign at least 1");
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        require(rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled(), "Deposit assignments are disabled");
        _assignDeposits(_max, rocketDAOProtocolSettingsDeposit);
    }

    /// @dev Assigns up to specified number of minipools or megapools
    /// @param _max Maximum number of minipools/megapools to assign
    function _assignDeposits(uint256 _max, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
        // Get contracts
        AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
        // Process minipool queue first
        uint256 minipoolQueueLength = addressQueueStorage.getLength(queueKeyMinipoolVariable);
        if (minipoolQueueLength > 0) {
            if (minipoolQueueLength >= _max) {
                _assignMinipools(_max, _rocketDAOProtocolSettingsDeposit);
                return;
            } else {
                unchecked { // _max > minipoolQueueLength
                    _max -= minipoolQueueLength;
                }
                _assignMinipools(minipoolQueueLength, _rocketDAOProtocolSettingsDeposit);
            }
        }
        // Assign remainder to megapools
        if (_max > 0) {
            _assignMegapools(_max, _rocketDAOProtocolSettingsDeposit);
        }
    }

    /// @dev Assigns to minipools/megapools based on `msg.value`, does nothing if assignments are disabled
    function _assignByDeposit() internal {
        // Get contracts
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        // Check if assigning deposits is enabled
        if (!rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
            return;
        }
        // Continue processing legacy minipool queue until empty
        AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
        if (addressQueueStorage.getLength(queueKeyMinipoolVariable) > 0) {
            RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
            _assignMinipoolsByDeposit(rocketMinipoolQueue, rocketDAOProtocolSettingsDeposit);
        } else {
            // Then assign megapools
            _assignMegapoolsByDeposit(rocketDAOProtocolSettingsDeposit);
        }
    }

    /// @dev Assigns a number of minipools based on `msg.value`
    function _assignMinipoolsByDeposit(RocketMinipoolQueueInterface _rocketMinipoolQueue, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
        // Load contracts
        RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
        // Calculate the number of minipools to assign
        uint256 maxAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments();
        uint256 variableDepositAmount = rocketDAOProtocolSettingsMinipool.getVariableDepositAmount();
        uint256 scalingCount = msg.value / variableDepositAmount;
        uint256 totalEthCount = getBalance() / variableDepositAmount;
        uint256 assignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositSocialisedAssignments() + scalingCount;
        if (assignments > totalEthCount) {
            assignments = totalEthCount;
        }
        if (assignments > maxAssignments) {
            assignments = maxAssignments;
        }
        if (assignments > 0) {
            _assignMinipools(assignments, _rocketDAOProtocolSettingsDeposit);
        }
    }

    /// @dev Assigns a number of megapools based on `msg.value`
    function _assignMegapoolsByDeposit(RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
        // Calculate the number of megapool validators to assign
        uint256 maxAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments();
        uint256 scalingCount = msg.value / 32 ether;
        uint256 assignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositSocialisedAssignments() + scalingCount;
        if (assignments > maxAssignments) {
            assignments = maxAssignments;
        }
        if (assignments > 0) {
            _assignMegapools(assignments, _rocketDAOProtocolSettingsDeposit);
        }
    }

    /// @dev Assigns up to `_count` number of minipools
    /// @param _count Maximum number of entries to assign
    function _assignMinipools(uint256 _count, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
        // Get contracts
        RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
        RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
        // Calculate max possible assignments based on current balance
        uint256 variableDepositAmount = rocketDAOProtocolSettingsMinipool.getVariableDepositAmount();
        uint256 maxPossible = getBalance() / variableDepositAmount;
        if (maxPossible == 0) {
            return;
        }
        if (_count > maxPossible) {
            _count = maxPossible;
        }
        // Dequeue minipools
        address[] memory minipools = rocketMinipoolQueue.dequeueMinipools(_count);
        if (minipools.length > 0) {
            // Withdraw ETH from vault
            uint256 totalEther = minipools.length * variableDepositAmount;
            rocketVault.withdrawEther(totalEther);
            uint256 nodeBalanceUsed = 0;
            // Loop over minipools and deposit the amount required to reach launch balance
            for (uint256 i = 0; i < minipools.length; ++i) {
                RocketMinipoolInterface minipool = RocketMinipoolInterface(minipools[i]);
                // Assign deposit to minipool
                minipool.deposit{value: variableDepositAmount}();
                nodeBalanceUsed = nodeBalanceUsed + minipool.getNodeTopUpValue();
                // Emit deposit assigned event
                emit DepositAssigned(minipools[i], variableDepositAmount, block.timestamp);
            }
            // Decrease node balance
            subUint(nodeBalanceKey, nodeBalanceUsed);
        }
    }

    /// @dev Assigns up to `_count` number of megapools
    /// @param _count Maximum number of entries to assign
    function _assignMegapools(uint256 _count, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
        // Get contracts
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        // Get required inputs
        uint256 expressQueueLength = linkedListStorage.getLength(expressQueueNamespace);
        uint256 standardQueueLength = linkedListStorage.getLength(standardQueueNamespace);
        uint256 queueIndex = getUint(queueIndexKey);
        uint256 expressQueueRate = _rocketDAOProtocolSettingsDeposit.getExpressQueueRate();
        // Keep track of changes to applied at the end
        uint256 nodeBalanceUsed = 0;
        uint256 totalSent = 0;
        uint256 vaultBalance = getBalance();
        // Keep track of whether heads move
        bool expressHeadMoved = false;
        bool standardHeadMoved = false;
        // Iterate over maximum of `_count` entries
        for (uint256 i = 0; i < _count; i++) {
            if (expressQueueLength == 0 && standardQueueLength == 0) {
                break;
            }
            // Determine if we are assigning an express queue entry
            bool express = queueIndex % (expressQueueRate + 1) != expressQueueRate;
            if (express && expressQueueLength == 0) {
                express = false;
            }
            if (!express && standardQueueLength == 0) {
                express = true;
            }
            // Get the entry
            bytes32 namespace = getQueueNamespace(express);
            LinkedListStorageInterface.DepositQueueValue memory head = linkedListStorage.peekItem(namespace);
            uint256 ethRequired = head.requestedValue * milliToWei;
            // Check if we have enough available to assign
            if (vaultBalance < ethRequired) {
                break;
            }
            // Withdraw the funds from the vault
            rocketVault.withdrawEther(ethRequired);
            vaultBalance -= ethRequired;
            // Assign funds and dequeue megapool
            RocketMegapoolInterface(head.receiver).assignFunds{value: ethRequired}(head.validatorId);
            emit FundsAssigned(head.receiver, ethRequired, block.timestamp);
            linkedListStorage.dequeueItem(namespace);
            // Account for node balance
            unchecked { // Infeasible overflows and impossible underflows
                nodeBalanceUsed += head.suppliedValue * milliToWei;
                totalSent += ethRequired;
            // Update counts for next iteration
                queueIndex += 1;
                if (express) {
                    expressQueueLength -= 1;
                    expressHeadMoved = true;
                } else {
                    standardQueueLength -= 1;
                    standardHeadMoved = true;
                }
            }
        }
        // Store state changes
        subUint(nodeBalanceKey, nodeBalanceUsed);
        setUint(queueIndexKey, queueIndex);
        subUint(requestedTotalKey, totalSent);
        _setQueueMoved(expressHeadMoved, standardHeadMoved);
    }

    /// @dev Stores block number when the queues moved
    function _setQueueMoved(bool expressHeadMoved, bool standardHeadMoved) internal {
        uint256 packed = getUint(queueMovedKey);
        uint128 express = expressHeadMoved ? uint128(block.number) : uint128(packed >> 0);
        uint128 standard = standardHeadMoved ? uint128(block.number) : uint128(packed >> 128);
        packed = express << 0;
        packed |= uint256(standard) << 128;
        setUint(queueMovedKey, packed);
    }

    /// @dev Withdraw excess deposit pool balance for rETH collateral
    /// @param _amount The amount of excess ETH to withdraw
    function withdrawExcessBalance(uint256 _amount) override external onlyThisLatestContract onlyLatestContract("rocketTokenRETH", msg.sender) {
        // Check amount
        require(_amount <= getExcessBalance(), "Insufficient excess balance for withdrawal");
        // Withdraw ETH from vault
        rocketVault.withdrawEther(_amount);
        // Transfer to rETH contract
        rocketTokenRETH.depositExcess{value: _amount}();
        // Emit excess withdrawn event
        emit ExcessWithdrawn(msg.sender, _amount, block.timestamp);
    }

    /// @notice Requests funds from the deposit queue by a megapool, places the request in the relevant queue
    /// @param _bondAmount The bond amount supplied by the NO for the fund request
    /// @param _validatorId The megapool-managed ID of the validator requesting funds
    /// @param _amount The amount of ETH requested by the node operator
    /// @param _expressQueue Whether to consume an express ticket to be placed in the express queue
    function requestFunds(uint256 _bondAmount, uint32 _validatorId, uint256 _amount, bool _expressQueue) external onlyRegisteredMegapool(msg.sender) onlyThisLatestContract {
        // Validate arguments
        require(_bondAmount % milliToWei == 0, "Invalid supplied amount");
        require(_amount % milliToWei == 0, "Invalid requested amount");
        // Use an express ticket if requested
        address nodeAddress = RocketMegapoolInterface(msg.sender).getNodeAddress();
        RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
        if (_expressQueue) {
            rocketNodeManager.useExpressTicket(nodeAddress);
        } else {
            rocketNodeManager.provisionExpressTickets(nodeAddress);
        }
        // Enqueue megapool
        bytes32 namespace = getQueueNamespace(_expressQueue);
        LinkedListStorageInterface.DepositQueueValue memory value = LinkedListStorageInterface.DepositQueueValue({
            receiver: msg.sender,                                        // Megapool address
            validatorId: _validatorId,                                   // Incrementing id per validator in a megapool
            suppliedValue: SafeCast.toUint32(_bondAmount / milliToWei),  // NO bond amount
            requestedValue: SafeCast.toUint32(_amount / milliToWei)      // Amount being requested
        });
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        linkedListStorage.enqueueItem(namespace, value);
        // Increase requested balance
        addUint(requestedTotalKey, _amount);
        // Check if head moved
        if (_expressQueue) {
            uint256 expressQueueLength = linkedListStorage.getLength(expressQueueNamespace);
            if (expressQueueLength == 1) {
                _setQueueMoved(true, false);
            }
        } else {
            uint256 standardQueueLength = linkedListStorage.getLength(standardQueueNamespace);
            if (standardQueueLength == 1) {
                _setQueueMoved(false, true);
            }
        }
        {
            // Update collateral balances
            _increaseETHBonded(nodeAddress, _bondAmount);
            _increaseETHBorrowed(nodeAddress, _amount - _bondAmount);
        }
        // Emit event
        emit FundsRequested(msg.sender, _validatorId, _amount, _expressQueue, block.timestamp);
    }

    /// @dev Called from a megapool to remove an entry in the validator queue and returns funds to node by credit mechanism
    /// @param _validatorId Internal ID of the validator to be removed
    /// @param _expressQueue Whether the entry is in the express queue or not
    function exitQueue(address _nodeAddress, uint32 _validatorId, bool _expressQueue) external onlyRegisteredMegapool(msg.sender) onlyThisLatestContract {
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        LinkedListStorageInterface.DepositQueueKey memory key = LinkedListStorageInterface.DepositQueueKey({
            receiver: msg.sender,
            validatorId: _validatorId
        });
        bytes32 namespace = getQueueNamespace(_expressQueue);
        uint256 index = linkedListStorage.getIndexOf(namespace, key);
        LinkedListStorageInterface.DepositQueueValue memory value = linkedListStorage.getItem(namespace, index);
        bool isAtHead = linkedListStorage.getHeadIndex(namespace) == index;
        linkedListStorage.removeItem(namespace, key);
        // Perform balance accounting
        subUint(requestedTotalKey, value.requestedValue * milliToWei);
        if (_expressQueue) {
            // Refund express ticket
            RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
            rocketNodeManager.refundExpressTicket(_nodeAddress);
            // Update head moved block
            if (isAtHead) {
                _setQueueMoved(true, false);
            }
        } else {
            // Update head moved block
            if (isAtHead) {
                _setQueueMoved(false, true);
            }
        }
        // Remove bond from node balance
        uint256 nodeBalanceUsed = value.suppliedValue * milliToWei;
        subUint(nodeBalanceKey, nodeBalanceUsed);
        // Emit event
        emit QueueExited(_nodeAddress, block.timestamp);
    }

    /// @dev Called from megapool to increase a node operator's credit
    function applyCredit(address _nodeAddress, uint256 _amount) override external onlyRegisteredMegapool(msg.sender) onlyThisLatestContract {
        // Add to node's credit for the amount supplied
        addUint(keccak256(abi.encodePacked("node.deposit.credit.balance", _nodeAddress)), _amount);
    }

    /// @notice Allows node operator to withdraw any ETH credit they have as rETH
    /// @param _amount Amount in ETH to withdraw
    function withdrawCredit(uint256 _amount) override external onlyRegisteredNode(msg.sender) onlyThisLatestContract {
        address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(msg.sender);
        _withdrawCreditFor(msg.sender, withdrawalAddress, _amount);
    }

    /// @notice Allows node operator to withdraw any ETH credit they have as rETH from their withdrawal address
    /// @param _nodeAddress Address of the node operator
    /// @param _amount Amount in ETH to withdraw
    function withdrawCreditFor(address _nodeAddress, uint256 _amount) override public onlyRegisteredNode(_nodeAddress) onlyThisLatestContract {
        // Check caller
        address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
        require(msg.sender == withdrawalAddress, "Must be called from withdrawal address");
        // Withdraw credit
        _withdrawCreditFor(_nodeAddress, withdrawalAddress, _amount);
    }

    /// @dev Withdraws credit from a given node operator as rETH
    function _withdrawCreditFor(address _nodeAddress, address _recipient, uint256 _amount) internal {
        // Check deposits are enabled
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
        require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled");
        // Ensure no debt exists on the node operator's megapool
        RocketMegapoolFactoryInterface rocketMegapoolFactory = RocketMegapoolFactoryInterface(getContractAddress("rocketMegapoolFactory"));
        require(rocketMegapoolFactory.getMegapoolDeployed(_nodeAddress), "Megapool must be deployed");
        RocketMegapoolDelegateInterface megapool = RocketMegapoolDelegateInterface(rocketMegapoolFactory.getExpectedAddress(_nodeAddress));
        require(megapool.getDebt() == 0, "Cannot withdraw credit while debt exists");
        // Check node operator has sufficient credit
        bytes32 creditKey = keccak256(abi.encodePacked("node.deposit.credit.balance", _nodeAddress));
        uint256 credit = getUint(creditKey);
        require(credit >= _amount, "Amount exceeds credit available");
        // Account for balance changes
        subUint(creditKey, _amount);
        // Note: The funds are already stored in RocketVault under RocketDepositPool so no ETH transfer is required
        RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
        // Calculate deposit fee
        unchecked { // depositFee < msg.value
            uint256 depositFee = _amount * rocketDAOProtocolSettingsDeposit.getDepositFee() / calcBase;
            uint256 depositNet = _amount - depositFee;
            // Mint rETH to recipient address
            rocketTokenRETH.mint(depositNet, _recipient);
        }
        // Emit event
        emit CreditWithdrawn(_nodeAddress, _amount, block.timestamp);
    }

    /// @notice Gets the receiver next to be assigned and whether it can be assigned immediately
    /// @dev During the transition period from the legacy minipool queue, this will always return null address
    /// @return receiver Address of the receiver of the next assignment or null address for an empty queue
    /// @return assignmentPossible Whether there is enough funds in the pool to perform an assignment now
    /// @return headMovedBlock The block at which the receiver entered the top of the queue
    function getQueueTop() override external view returns (address receiver, bool assignmentPossible, uint256 headMovedBlock) {
        // If legacy queue is still being processed, return null address
        AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
        if (addressQueueStorage.getLength(queueKeyMinipoolVariable) > 0) {
            return (address(0x0), false, 0);
        }

        // Get contracts
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));

        uint256 expressQueueLength = linkedListStorage.getLength(expressQueueNamespace);
        uint256 standardQueueLength = linkedListStorage.getLength(standardQueueNamespace);

        // If both queues are empty, return null address
        if (expressQueueLength == 0 && standardQueueLength == 0) {
            return (address(0x0), false, 0);
        }

        uint256 queueIndex = getUint(queueIndexKey);

        uint256 expressQueueRate = rocketDAOProtocolSettingsDeposit.getExpressQueueRate();

        bool express = queueIndex % (expressQueueRate + 1) != expressQueueRate;
        if (express && expressQueueLength == 0) {
            express = false;
        }

        if (!express && standardQueueLength == 0) {
            express = true;
        }

        // Check if enough value is in the deposit pool to assign the requested value
        bytes32 namespace = getQueueNamespace(express);
        LinkedListStorageInterface.DepositQueueValue memory head = linkedListStorage.peekItem(namespace);
        assignmentPossible = rocketVault.balanceOf("rocketDepositPool") >= head.requestedValue * milliToWei;

        // Check assignments are enabled
        if (!rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
            assignmentPossible = false;
        }

        // Retrieve the block at which the entry at the top of the queue got to that position
        uint256 packed = getUint(queueMovedKey);
        if (express) {
            headMovedBlock = uint128(packed);
        } else {
            headMovedBlock = uint128(packed >> 128);
        }

        return (head.receiver, assignmentPossible, headMovedBlock);
    }

    /// @notice Retrieves the queue index (used for deciding whether to assign express or standard queue next)
    function getQueueIndex() override external view returns (uint256) {
        return getUint(queueIndexKey);
    }

    /// @notice Returns the number of minipools in the queue
    function getMinipoolQueueLength() override public view returns (uint256) {
        AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
        return addressQueueStorage.getLength(queueKeyMinipoolVariable);
    }

    /// @notice Returns the number of megapool validators in the express queue
    function getExpressQueueLength() override public view returns (uint256) {
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        return linkedListStorage.getLength(expressQueueNamespace);
    }

    /// @notice Returns the number of megapool validators in the standard queue
    function getStandardQueueLength() override public view returns (uint256) {
        LinkedListStorageInterface linkedListStorage = LinkedListStorageInterface(getContractAddress("linkedListStorage"));
        return linkedListStorage.getLength(standardQueueNamespace);
    }

    /// @notice Returns the total number of minipools/megapools in the queue
    function getTotalQueueLength() override external view returns (uint256) {
        return getMinipoolQueueLength() + getExpressQueueLength() + getStandardQueueLength();
    }

    /// @dev Convenience method to return queue key for express and non-express queues
    function getQueueNamespace(bool _expressQueue) internal pure returns (bytes32) {
        if (_expressQueue) {
            return expressQueueNamespace;
        }
        return standardQueueNamespace;
    }

    /// @dev Called by a megapool during a bond reduction to adjust its capital ratio
    function reduceBond(address _nodeAddress, uint256 _amount) override external onlyRegisteredMegapool(msg.sender) onlyThisLatestContract {
        // Update collateral balances
        _increaseETHBorrowed(_nodeAddress, _amount);
        _decreaseETHBonded(_nodeAddress, _amount);
    }

    /// @dev Called by a megapool when exiting to handle change in capital ratio
    function fundsReturned(address _nodeAddress, uint256 _nodeAmount, uint256 _userAmount) override external onlyRegisteredMegapool(msg.sender) onlyThisLatestContract {
        // Update collateral balances
        _decreaseETHBonded(_nodeAddress, _nodeAmount);
        _decreaseETHBorrowed(_nodeAddress, _userAmount);
    }

    /// @dev Increases the amount of ETH supplied by a node operator as bond
    function _increaseETHBonded(address _nodeAddress, uint256 _amount) internal {
        RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
        bytes32 key = keccak256(abi.encodePacked("megapool.eth.provided.node.amount", _nodeAddress));
        uint256 ethBonded = uint256(rocketNetworkSnapshots.latestValue(key)) + _amount;
        rocketNetworkSnapshots.push(key, uint224(ethBonded));
    }

    /// @dev Increases the amount of ETH borrowed by a node operator
    function _increaseETHBorrowed(address _nodeAddress, uint256 _amount) internal {
        bytes32 key = keccak256(abi.encodePacked("megapool.eth.matched.node.amount", _nodeAddress));
        addUint(key, _amount);
    }

    /// @dev Decreases the amount of ETH bonded by a node operator as bond
    function _decreaseETHBonded(address _nodeAddress, uint256 _amount) internal {
        RocketNetworkSnapshotsInterface rocketNetworkSnapshots = RocketNetworkSnapshotsInterface(getContractAddress("rocketNetworkSnapshots"));
        bytes32 key = keccak256(abi.encodePacked("megapool.eth.provided.node.amount", _nodeAddress));
        uint256 ethBonded = uint256(rocketNetworkSnapshots.latestValue(key)) - _amount;
        rocketNetworkSnapshots.push(key, uint224(ethBonded));
    }

    /// @dev Decreases the amount of ETH borrowed by a node operator
    function _decreaseETHBorrowed(address _nodeAddress, uint256 _amount) internal {
        bytes32 key = keccak256(abi.encodePacked("megapool.eth.matched.node.amount", _nodeAddress));
        subUint(key, _amount);
    }
}

File 2 of 30 : SafeCast.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.

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 uint248 from uint256, reverting on
     * overflow (when the input is greater than largest uint248).
     *
     * Counterpart to Solidity's `uint248` operator.
     *
     * Requirements:
     *
     * - input must fit into 248 bits
     *
     * _Available since v4.7._
     */
    function toUint248(uint256 value) internal pure returns (uint248) {
        require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
        return uint248(value);
    }

    /**
     * @dev Returns the downcasted uint240 from uint256, reverting on
     * overflow (when the input is greater than largest uint240).
     *
     * Counterpart to Solidity's `uint240` operator.
     *
     * Requirements:
     *
     * - input must fit into 240 bits
     *
     * _Available since v4.7._
     */
    function toUint240(uint256 value) internal pure returns (uint240) {
        require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
        return uint240(value);
    }

    /**
     * @dev Returns the downcasted uint232 from uint256, reverting on
     * overflow (when the input is greater than largest uint232).
     *
     * Counterpart to Solidity's `uint232` operator.
     *
     * Requirements:
     *
     * - input must fit into 232 bits
     *
     * _Available since v4.7._
     */
    function toUint232(uint256 value) internal pure returns (uint232) {
        require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
        return uint232(value);
    }

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

    /**
     * @dev Returns the downcasted uint216 from uint256, reverting on
     * overflow (when the input is greater than largest uint216).
     *
     * Counterpart to Solidity's `uint216` operator.
     *
     * Requirements:
     *
     * - input must fit into 216 bits
     *
     * _Available since v4.7._
     */
    function toUint216(uint256 value) internal pure returns (uint216) {
        require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
        return uint216(value);
    }

    /**
     * @dev Returns the downcasted uint208 from uint256, reverting on
     * overflow (when the input is greater than largest uint208).
     *
     * Counterpart to Solidity's `uint208` operator.
     *
     * Requirements:
     *
     * - input must fit into 208 bits
     *
     * _Available since v4.7._
     */
    function toUint208(uint256 value) internal pure returns (uint208) {
        require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
        return uint208(value);
    }

    /**
     * @dev Returns the downcasted uint200 from uint256, reverting on
     * overflow (when the input is greater than largest uint200).
     *
     * Counterpart to Solidity's `uint200` operator.
     *
     * Requirements:
     *
     * - input must fit into 200 bits
     *
     * _Available since v4.7._
     */
    function toUint200(uint256 value) internal pure returns (uint200) {
        require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
        return uint200(value);
    }

    /**
     * @dev Returns the downcasted uint192 from uint256, reverting on
     * overflow (when the input is greater than largest uint192).
     *
     * Counterpart to Solidity's `uint192` operator.
     *
     * Requirements:
     *
     * - input must fit into 192 bits
     *
     * _Available since v4.7._
     */
    function toUint192(uint256 value) internal pure returns (uint192) {
        require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
        return uint192(value);
    }

    /**
     * @dev Returns the downcasted uint184 from uint256, reverting on
     * overflow (when the input is greater than largest uint184).
     *
     * Counterpart to Solidity's `uint184` operator.
     *
     * Requirements:
     *
     * - input must fit into 184 bits
     *
     * _Available since v4.7._
     */
    function toUint184(uint256 value) internal pure returns (uint184) {
        require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
        return uint184(value);
    }

    /**
     * @dev Returns the downcasted uint176 from uint256, reverting on
     * overflow (when the input is greater than largest uint176).
     *
     * Counterpart to Solidity's `uint176` operator.
     *
     * Requirements:
     *
     * - input must fit into 176 bits
     *
     * _Available since v4.7._
     */
    function toUint176(uint256 value) internal pure returns (uint176) {
        require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
        return uint176(value);
    }

    /**
     * @dev Returns the downcasted uint168 from uint256, reverting on
     * overflow (when the input is greater than largest uint168).
     *
     * Counterpart to Solidity's `uint168` operator.
     *
     * Requirements:
     *
     * - input must fit into 168 bits
     *
     * _Available since v4.7._
     */
    function toUint168(uint256 value) internal pure returns (uint168) {
        require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
        return uint168(value);
    }

    /**
     * @dev Returns the downcasted uint160 from uint256, reverting on
     * overflow (when the input is greater than largest uint160).
     *
     * Counterpart to Solidity's `uint160` operator.
     *
     * Requirements:
     *
     * - input must fit into 160 bits
     *
     * _Available since v4.7._
     */
    function toUint160(uint256 value) internal pure returns (uint160) {
        require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
        return uint160(value);
    }

    /**
     * @dev Returns the downcasted uint152 from uint256, reverting on
     * overflow (when the input is greater than largest uint152).
     *
     * Counterpart to Solidity's `uint152` operator.
     *
     * Requirements:
     *
     * - input must fit into 152 bits
     *
     * _Available since v4.7._
     */
    function toUint152(uint256 value) internal pure returns (uint152) {
        require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
        return uint152(value);
    }

    /**
     * @dev Returns the downcasted uint144 from uint256, reverting on
     * overflow (when the input is greater than largest uint144).
     *
     * Counterpart to Solidity's `uint144` operator.
     *
     * Requirements:
     *
     * - input must fit into 144 bits
     *
     * _Available since v4.7._
     */
    function toUint144(uint256 value) internal pure returns (uint144) {
        require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
        return uint144(value);
    }

    /**
     * @dev Returns the downcasted uint136 from uint256, reverting on
     * overflow (when the input is greater than largest uint136).
     *
     * Counterpart to Solidity's `uint136` operator.
     *
     * Requirements:
     *
     * - input must fit into 136 bits
     *
     * _Available since v4.7._
     */
    function toUint136(uint256 value) internal pure returns (uint136) {
        require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
        return uint136(value);
    }

    /**
     * @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
     *
     * _Available since v2.5._
     */
    function toUint128(uint256 value) internal pure returns (uint128) {
        require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
        return uint128(value);
    }

    /**
     * @dev Returns the downcasted uint120 from uint256, reverting on
     * overflow (when the input is greater than largest uint120).
     *
     * Counterpart to Solidity's `uint120` operator.
     *
     * Requirements:
     *
     * - input must fit into 120 bits
     *
     * _Available since v4.7._
     */
    function toUint120(uint256 value) internal pure returns (uint120) {
        require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
        return uint120(value);
    }

    /**
     * @dev Returns the downcasted uint112 from uint256, reverting on
     * overflow (when the input is greater than largest uint112).
     *
     * Counterpart to Solidity's `uint112` operator.
     *
     * Requirements:
     *
     * - input must fit into 112 bits
     *
     * _Available since v4.7._
     */
    function toUint112(uint256 value) internal pure returns (uint112) {
        require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
        return uint112(value);
    }

    /**
     * @dev Returns the downcasted uint104 from uint256, reverting on
     * overflow (when the input is greater than largest uint104).
     *
     * Counterpart to Solidity's `uint104` operator.
     *
     * Requirements:
     *
     * - input must fit into 104 bits
     *
     * _Available since v4.7._
     */
    function toUint104(uint256 value) internal pure returns (uint104) {
        require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
        return uint104(value);
    }

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

    /**
     * @dev Returns the downcasted uint88 from uint256, reverting on
     * overflow (when the input is greater than largest uint88).
     *
     * Counterpart to Solidity's `uint88` operator.
     *
     * Requirements:
     *
     * - input must fit into 88 bits
     *
     * _Available since v4.7._
     */
    function toUint88(uint256 value) internal pure returns (uint88) {
        require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
        return uint88(value);
    }

    /**
     * @dev Returns the downcasted uint80 from uint256, reverting on
     * overflow (when the input is greater than largest uint80).
     *
     * Counterpart to Solidity's `uint80` operator.
     *
     * Requirements:
     *
     * - input must fit into 80 bits
     *
     * _Available since v4.7._
     */
    function toUint80(uint256 value) internal pure returns (uint80) {
        require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
        return uint80(value);
    }

    /**
     * @dev Returns the downcasted uint72 from uint256, reverting on
     * overflow (when the input is greater than largest uint72).
     *
     * Counterpart to Solidity's `uint72` operator.
     *
     * Requirements:
     *
     * - input must fit into 72 bits
     *
     * _Available since v4.7._
     */
    function toUint72(uint256 value) internal pure returns (uint72) {
        require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
        return uint72(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
     *
     * _Available since v2.5._
     */
    function toUint64(uint256 value) internal pure returns (uint64) {
        require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
        return uint64(value);
    }

    /**
     * @dev Returns the downcasted uint56 from uint256, reverting on
     * overflow (when the input is greater than largest uint56).
     *
     * Counterpart to Solidity's `uint56` operator.
     *
     * Requirements:
     *
     * - input must fit into 56 bits
     *
     * _Available since v4.7._
     */
    function toUint56(uint256 value) internal pure returns (uint56) {
        require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
        return uint56(value);
    }

    /**
     * @dev Returns the downcasted uint48 from uint256, reverting on
     * overflow (when the input is greater than largest uint48).
     *
     * Counterpart to Solidity's `uint48` operator.
     *
     * Requirements:
     *
     * - input must fit into 48 bits
     *
     * _Available since v4.7._
     */
    function toUint48(uint256 value) internal pure returns (uint48) {
        require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
        return uint48(value);
    }

    /**
     * @dev Returns the downcasted uint40 from uint256, reverting on
     * overflow (when the input is greater than largest uint40).
     *
     * Counterpart to Solidity's `uint40` operator.
     *
     * Requirements:
     *
     * - input must fit into 40 bits
     *
     * _Available since v4.7._
     */
    function toUint40(uint256 value) internal pure returns (uint40) {
        require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
        return uint40(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
     *
     * _Available since v2.5._
     */
    function toUint32(uint256 value) internal pure returns (uint32) {
        require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
        return uint32(value);
    }

    /**
     * @dev Returns the downcasted uint24 from uint256, reverting on
     * overflow (when the input is greater than largest uint24).
     *
     * Counterpart to Solidity's `uint24` operator.
     *
     * Requirements:
     *
     * - input must fit into 24 bits
     *
     * _Available since v4.7._
     */
    function toUint24(uint256 value) internal pure returns (uint24) {
        require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
        return uint24(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
     *
     * _Available since v2.5._
     */
    function toUint16(uint256 value) internal pure returns (uint16) {
        require(value <= type(uint16).max, "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
     *
     * _Available since v2.5._
     */
    function toUint8(uint256 value) internal pure returns (uint8) {
        require(value <= type(uint8).max, "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.
     *
     * _Available since v3.0._
     */
    function toUint256(int256 value) internal pure returns (uint256) {
        require(value >= 0, "SafeCast: value must be positive");
        return uint256(value);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    /**
     * @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 downcasted) {
        downcasted = int128(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
    }

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

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

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

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

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

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

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

    /**
     * @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 downcasted) {
        downcasted = int64(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
    }

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

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

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

    /**
     * @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 downcasted) {
        downcasted = int32(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
    }

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

    /**
     * @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 downcasted) {
        downcasted = int16(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
    }

    /**
     * @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 downcasted) {
        downcasted = int8(value);
        require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
    }

    /**
     * @dev Converts an unsigned uint256 into a signed int256.
     *
     * Requirements:
     *
     * - input must be less than or equal to maxInt256.
     *
     * _Available since v3.0._
     */
    function toInt256(uint256 value) internal pure returns (int256) {
        // Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
        require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
        return int256(value);
    }
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
// SPDX-License-Identifier: GPL-3.0-only

interface RocketNetworkBalancesInterface {
    function getBalancesTimestamp() external view returns (uint256);
    function getBalancesBlock() external view returns (uint256);
    function getTotalETHBalance() external view returns (uint256);
    function getStakingETHBalance() external view returns (uint256);
    function getTotalRETHSupply() external view returns (uint256);
    function getETHUtilizationRate() external view returns (uint256);
    function submitBalances(uint256 _block, uint256 _slotTimestamp, uint256 _total, uint256 _staking, uint256 _rethSupply) external;
    function executeUpdateBalances(uint256 _block, uint256 _slotTimestamp, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

interface AddressQueueStorageInterface {
    function getLength(bytes32 _key) external view returns (uint);
    function getItem(bytes32 _key, uint _index) external view returns (address);
    function getIndexOf(bytes32 _key, address _value) external view returns (int);
    function enqueueItem(bytes32 _key, address _value) external;
    function dequeueItem(bytes32 _key) external returns (address);
    function removeItem(bytes32 _key, address _value) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;

interface LinkedListStorageInterface {
    struct DepositQueueValue {
        address receiver;      // the address that will receive the requested value
        uint32 validatorId;    // internal validator id
        uint32 suppliedValue;  // in milliether
        uint32 requestedValue; // in milliether
    }

    struct DepositQueueKey {
        address receiver;      // the address that will receive the requested value
        uint32 validatorId;    // internal validator id
    }

    function getLength(bytes32 _namespace) external view returns (uint256);
    function getItem(bytes32 _namespace, uint256 _index) external view returns (DepositQueueValue memory);
    function peekItem(bytes32 _namespace) external view returns (DepositQueueValue memory);
    function getIndexOf(bytes32 _namespace, DepositQueueKey memory _key) external view returns (uint256);
    function getHeadIndex(bytes32 _namespace) external view returns (uint256);
    function enqueueItem(bytes32 _namespace, DepositQueueValue memory _value) external;
    function dequeueItem(bytes32 _namespace) external returns (DepositQueueValue memory);
    function removeItem(bytes32 _namespace, DepositQueueKey memory _key) external;
    function scan(bytes32 _namespace, uint256 _startIndex, uint256 _count) external view returns (DepositQueueValue[] memory entries, uint256 nextIndex);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

interface RocketStorageInterface {

    // Deploy status
    function getDeployedStatus() external view returns (bool);

    // Guardian
    function getGuardian() external view returns(address);
    function setGuardian(address _newAddress) external;
    function confirmGuardian() external;

    // Getters
    function getAddress(bytes32 _key) external view returns (address);
    function getUint(bytes32 _key) external view returns (uint);
    function getString(bytes32 _key) external view returns (string memory);
    function getBytes(bytes32 _key) external view returns (bytes memory);
    function getBool(bytes32 _key) external view returns (bool);
    function getInt(bytes32 _key) external view returns (int);
    function getBytes32(bytes32 _key) external view returns (bytes32);

    // Setters
    function setAddress(bytes32 _key, address _value) external;
    function setUint(bytes32 _key, uint _value) external;
    function setString(bytes32 _key, string calldata _value) external;
    function setBytes(bytes32 _key, bytes calldata _value) external;
    function setBool(bytes32 _key, bool _value) external;
    function setInt(bytes32 _key, int _value) external;
    function setBytes32(bytes32 _key, bytes32 _value) external;

    // Deleters
    function deleteAddress(bytes32 _key) external;
    function deleteUint(bytes32 _key) external;
    function deleteString(bytes32 _key) external;
    function deleteBytes(bytes32 _key) external;
    function deleteBool(bytes32 _key) external;
    function deleteInt(bytes32 _key) external;
    function deleteBytes32(bytes32 _key) external;

    // Arithmetic
    function addUint(bytes32 _key, uint256 _amount) external;
    function subUint(bytes32 _key, uint256 _amount) external;

    // Protected storage
    function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
    function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
    function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
    function confirmWithdrawalAddress(address _nodeAddress) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

import "../interface/RocketStorageInterface.sol";

/// @title Base settings / modifiers for each contract in Rocket Pool
/// @author David Rugendyke

abstract contract RocketBase {

    // Calculate using this as the base
    uint256 constant calcBase = 1 ether;

    // Version of the contract
    uint8 public version;

    // The main storage contract where primary persistant storage is maintained
    RocketStorageInterface rocketStorage = RocketStorageInterface(address(0));


    /*** Modifiers **********************************************************/

    /**
    * @dev Throws if called by any sender that doesn't match a Rocket Pool network contract
    */
    modifier onlyLatestNetworkContract() {
        require(getBool(keccak256(abi.encodePacked("contract.exists", msg.sender))), "Invalid or outdated network contract");
        _;
    }

    /**
    * @dev Throws if called by any sender that doesn't match one of the supplied contract or is the latest version of that contract
    */
    modifier onlyLatestContract(string memory _contractName, address _contractAddress) {
        require(_contractAddress == getAddress(keccak256(abi.encodePacked("contract.address", _contractName))), "Invalid or outdated contract");
        _;
    }

    /**
    * @dev Throws if called by any sender that isn't a registered node
    */
    modifier onlyRegisteredNode(address _nodeAddress) {
        require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
        _;
    }

    /**
    * @dev Throws if called by any sender that isn't a trusted node DAO member
    */
    modifier onlyTrustedNode(address _nodeAddress) {
        require(getBool(keccak256(abi.encodePacked("dao.trustednodes.", "member", _nodeAddress))), "Invalid trusted node");
        _;
    }

    /**
    * @dev Throws if called by any sender that isn't a registered minipool
    */
    modifier onlyRegisteredMinipool(address _minipoolAddress) {
        require(getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress))), "Invalid minipool");
        _;
    }

    /**
    * @dev Throws if called by any sender that isn't a registered megapool
    */
    modifier onlyRegisteredMegapool(address _megapoolAddress) {
        require(getBool(keccak256(abi.encodePacked("megapool.exists", _megapoolAddress))), "Invalid megapool");
        _;
    }

    /**
    * @dev Throws if called by any sender that isn't a registered minipool or megapool
    */
    modifier onlyRegisteredMinipoolOrMegapool(address _caller) {
        require(
            getBool(keccak256(abi.encodePacked("megapool.exists", _caller))) ||
            getBool(keccak256(abi.encodePacked("minipool.exists", _caller)))
        , "Invalid caller");
        _;
    }

    /**
    * @dev Throws if called by any account other than a guardian account (temporary account allowed access to settings before DAO is fully enabled)
    */
    modifier onlyGuardian() {
        require(msg.sender == rocketStorage.getGuardian(), "Account is not a temporary guardian");
        _;
    }




    /*** Methods **********************************************************/

    /// @dev Set the main Rocket Storage address
    constructor(RocketStorageInterface _rocketStorageAddress) {
        // Update the contract address
        rocketStorage = RocketStorageInterface(_rocketStorageAddress);
    }


    /// @dev Get the address of a network contract by name
    function getContractAddress(string memory _contractName) internal view returns (address) {
        // Get the current contract address
        address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
        // Check it
        require(contractAddress != address(0x0), "Contract not found");
        // Return
        return contractAddress;
    }


    /// @dev Get the address of a network contract by name (returns address(0x0) instead of reverting if contract does not exist)
    function getContractAddressUnsafe(string memory _contractName) internal view returns (address) {
        // Get the current contract address
        address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
        // Return
        return contractAddress;
    }


    /// @dev Get the name of a network contract by address
    function getContractName(address _contractAddress) internal view returns (string memory) {
        // Get the contract name
        string memory contractName = getString(keccak256(abi.encodePacked("contract.name", _contractAddress)));
        // Check it
        require(bytes(contractName).length > 0, "Contract not found");
        // Return
        return contractName;
    }

    /// @dev Get revert error message from a .call method
    function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
        // If the _res length is less than 68, then the transaction failed silently (without a revert message)
        if (_returnData.length < 68) return "Transaction reverted silently";
        assembly {
            // Slice the sighash.
            _returnData := add(_returnData, 0x04)
        }
        return abi.decode(_returnData, (string)); // All that remains is the revert string
    }



    /*** Rocket Storage Methods ****************************************/

    // Note: Unused helpers have been removed to keep contract sizes down

    /// @dev Storage get methods
    function getAddress(bytes32 _key) internal view returns (address) { return rocketStorage.getAddress(_key); }
    function getUint(bytes32 _key) internal view returns (uint) { return rocketStorage.getUint(_key); }
    function getString(bytes32 _key) internal view returns (string memory) { return rocketStorage.getString(_key); }
    function getBytes(bytes32 _key) internal view returns (bytes memory) { return rocketStorage.getBytes(_key); }
    function getBool(bytes32 _key) internal view returns (bool) { return rocketStorage.getBool(_key); }
    function getInt(bytes32 _key) internal view returns (int) { return rocketStorage.getInt(_key); }
    function getBytes32(bytes32 _key) internal view returns (bytes32) { return rocketStorage.getBytes32(_key); }

    /// @dev Storage set methods
    function setAddress(bytes32 _key, address _value) internal { rocketStorage.setAddress(_key, _value); }
    function setUint(bytes32 _key, uint _value) internal { rocketStorage.setUint(_key, _value); }
    function setString(bytes32 _key, string memory _value) internal { rocketStorage.setString(_key, _value); }
    function setBytes(bytes32 _key, bytes memory _value) internal { rocketStorage.setBytes(_key, _value); }
    function setBool(bytes32 _key, bool _value) internal { rocketStorage.setBool(_key, _value); }
    function setInt(bytes32 _key, int _value) internal { rocketStorage.setInt(_key, _value); }
    function setBytes32(bytes32 _key, bytes32 _value) internal { rocketStorage.setBytes32(_key, _value); }

    /// @dev Storage delete methods
    function deleteAddress(bytes32 _key) internal { rocketStorage.deleteAddress(_key); }
    function deleteUint(bytes32 _key) internal { rocketStorage.deleteUint(_key); }
    function deleteString(bytes32 _key) internal { rocketStorage.deleteString(_key); }
    function deleteBytes(bytes32 _key) internal { rocketStorage.deleteBytes(_key); }
    function deleteBool(bytes32 _key) internal { rocketStorage.deleteBool(_key); }
    function deleteInt(bytes32 _key) internal { rocketStorage.deleteInt(_key); }
    function deleteBytes32(bytes32 _key) internal { rocketStorage.deleteBytes32(_key); }

    /// @dev Storage arithmetic methods
    function addUint(bytes32 _key, uint256 _amount) internal { rocketStorage.addUint(_key, _amount); }
    function subUint(bytes32 _key, uint256 _amount) internal { rocketStorage.subUint(_key, _amount); }
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

interface RocketDAOProtocolSettingsDepositInterface {
    function getDepositEnabled() external view returns (bool);
    function getAssignDepositsEnabled() external view returns (bool);
    function getMinimumDeposit() external view returns (uint256);
    function getMaximumDepositPoolSize() external view returns (uint256);
    function getMaximumDepositAssignments() external view returns (uint256);
    function getMaximumDepositSocialisedAssignments() external view returns (uint256);
    function getDepositFee() external view returns (uint256);
    function getExpressQueueRate() external view returns (uint256);
    function getExpressQueueTicketsBaseProvision() external view returns (uint256);
}

File 9 of 30 : MinipoolDeposit.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

// Represents the type of deposits required by a minipool

enum MinipoolDeposit {
    None,       // Marks an invalid deposit type
    Full,       // The minipool requires 32 ETH from the node operator, 16 ETH of which will be refinanced from user deposits
    Half,       // The minipool required 16 ETH from the node operator to be matched with 16 ETH from user deposits
    Empty,      // The minipool requires 0 ETH from the node operator to be matched with 32 ETH from user deposits (trusted nodes only)
    Variable    // Indicates this minipool is of the new generation that supports a variable deposit amount
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

import "../../../../types/MinipoolDeposit.sol";

interface RocketDAOProtocolSettingsMinipoolInterface {
    function getLaunchBalance() external view returns (uint256);
    function getPreLaunchValue() external pure returns (uint256);
    function getDepositUserAmount(MinipoolDeposit _depositType) external view returns (uint256);
    function getFullDepositUserAmount() external view returns (uint256);
    function getHalfDepositUserAmount() external view returns (uint256);
    function getVariableDepositAmount() external view returns (uint256);
    function getSubmitWithdrawableEnabled() external view returns (bool);
    function getBondReductionEnabled() external view returns (bool);
    function getLaunchTimeout() external view returns (uint256);
    function getMaximumCount() external view returns (uint256);
    function isWithinUserDistributeWindow(uint256 _time) external view returns (bool);
    function hasUserDistributeWindowPassed(uint256 _time) external view returns (bool);
    function getUserDistributeWindowStart() external view returns (uint256);
    function getUserDistributeWindowLength() external view returns (uint256);
    function getMaximumPenaltyCount() external view returns (uint256);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

interface RocketDAOProtocolSettingsNetworkInterface {
    function getNodeConsensusThreshold() external view returns (uint256);
    function getNodePenaltyThreshold() external view returns (uint256);
    function getPerPenaltyRate() external view returns (uint256);
    function getSubmitBalancesEnabled() external view returns (bool);
    function getSubmitBalancesFrequency() external view returns (uint256);
    function getSubmitPricesEnabled() external view returns (bool);
    function getSubmitPricesFrequency() external view returns (uint256);
    function getMinimumNodeFee() external view returns (uint256);
    function getTargetNodeFee() external view returns (uint256);
    function getMaximumNodeFee() external view returns (uint256);
    function getNodeFeeDemandRange() external view returns (uint256);
    function getTargetRethCollateralRate() external view returns (uint256);
    function getRethDepositDelay() external view returns (uint256);
    function getSubmitRewardsEnabled() external view returns (bool);
    function getMaxNodeShareSecurityCouncilAdder() external view returns (uint256);
    function getVoterShare() external view returns (uint256);
    function getProtocolDAOShare() external view returns (uint256);
    function getNodeShare() external view returns (uint256);
    function getNodeShareSecurityCouncilAdder() external view returns (uint256);
    function getRethCommission() external view returns (uint256);
    function getEffectiveVoterShare() external view returns (uint256);
    function getEffectiveNodeShare() external view returns (uint256);
    function getAllowListedControllers() external view returns (address[] memory);
    function getMaxRethDelta() external view returns (uint256);
    function isAllowListedController(address _address) external view returns (bool);
    function setNodeShareSecurityCouncilAdder(uint256 _value) external;
    function setNodeCommissionShare(uint256 _value) external;
    function setVoterShare(uint256 _value) external;
    function setProtocolDAOShare(uint256 _value) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

interface RocketDepositPoolInterface {
    function getBalance() external view returns (uint256);
    function getNodeBalance() external view returns (uint256);
    function getUserBalance() external view returns (int256);
    function getNodeCreditBalance(address _nodeAddress) external view returns (uint256);
    function getExcessBalance() external view returns (uint256);
    function deposit() external payable;
    function getMaximumDepositAmount() external view returns (uint256);
    function nodeDeposit(uint256 _totalAmount) external payable;
    function recycleDissolvedDeposit() external payable;
    function recycleExcessCollateral() external payable;
    function recycleLiquidatedStake() external payable;
    function maybeAssignDeposits(uint256 _max) external;
    function assignDeposits(uint256 _max) external;
    function withdrawExcessBalance(uint256 _amount) external;
    function requestFunds(uint256 _bondAmount, uint32 _validatorId, uint256 _amount, bool _useExpressTicket) external;
    function exitQueue(address _nodeAddress, uint32 _validatorId, bool _expressQueue) external;
    function applyCredit(address _nodeAddress, uint256 _amount) external;
    function reduceBond(address _nodeAddress, uint256 _amount) external;
    function fundsReturned(address _nodeAddress, uint256 _nodeAmount, uint256 _userAmount) external;
    function withdrawCredit(uint256 _amount) external;
    function withdrawCreditFor(address _nodeAddress, uint256 _amount) external;
    function getQueueTop() external view returns (address receiver, bool assignmentPossible, uint256 headMovedBlock);
    function getQueueIndex() external view returns (uint256);
    function getMinipoolQueueLength() external view returns (uint256);
    function getExpressQueueLength() external view returns (uint256);
    function getStandardQueueLength() external view returns (uint256);
    function getTotalQueueLength() external view returns (uint256);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

    struct Withdrawal {
        uint64 index;
        uint64 validatorIndex;
        bytes20 withdrawalCredentials;
        uint64 amountInGwei;
    }

    struct WithdrawalProof {
        uint64 withdrawalSlot;
        uint16 withdrawalNum;
        Withdrawal withdrawal;
        bytes32[] witnesses;
    }

    struct Validator {
        bytes pubkey;
        bytes32 withdrawalCredentials;
        uint64 effectiveBalance;
        bool slashed;
        uint64 activationEligibilityEpoch;
        uint64 activationEpoch;
        uint64 exitEpoch;
        uint64 withdrawableEpoch;
    }

    struct ValidatorProof {
        uint40 validatorIndex;
        Validator validator;
        bytes32[] witnesses;
    }

    struct SlotProof {
        uint64 slot;
        bytes32[] witnesses;
    }

interface BeaconStateVerifierInterface {
    function verifyValidator(uint64 _slotTimestamp, uint64 _slot, ValidatorProof calldata _proof) external view returns (bool);
    function verifyWithdrawal(uint64 _slotTimestamp, uint64 _slot, WithdrawalProof calldata _proof) external view returns (bool);
    function verifySlot(uint64 _slotTimestamp, SlotProof calldata _proof) external view returns (bool);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

import "../../interface/RocketStorageInterface.sol";

interface RocketMegapoolDelegateBaseInterface {
    function deprecate() external;
    function getExpirationTime() external view returns (uint256);
}

File 15 of 30 : RocketMegapoolStorageLayout.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.30;

import {RocketStorageInterface} from "../../interface/RocketStorageInterface.sol";

// ******************************************************
// Note: This contract MUST only be appended to. All
// deployed megapool contracts must maintain a
// consistent storage layout with RocketMegapoolDelegate.
// ******************************************************

/// @dev The RocketMegapool contract storage layout, shared by RocketMegapoolDelegate and RocketMegapoolBase
abstract contract RocketMegapoolStorageLayout {
    // Status of individual validators
    enum Status {
        InQueue,
        PreStaked,
        Staking,
        Exited,
        Dissolved
    }

    // Information about individual validators
    struct ValidatorInfo {
        uint32 lastAssignmentTime;  // Timestamp of when the last fund assignment took place
        uint32 lastRequestedValue;  // Value in milliether last requested
        uint32 lastRequestedBond;   // Value in milliether of the bond supplied for last request for funds
        uint32 depositValue;        // Total amount deposited to beaconchain in gwei

        bool staked;        // Whether the validator has staked the minimum required to begin validating (32 ETH)
        bool exited;        // Whether the validator has exited the beacon chain
        bool inQueue;       // Whether the validator is currently awaiting funds from the deposit pool
        bool inPrestake;    // Whether the validator is currently awaiting the stake operation
        bool expressUsed;   // Whether the last request for funds consumed an express ticket
        bool dissolved;     // Whether the validator failed to prestake their initial deposit in time
        bool exiting;       // Whether the validator is queued to exit on the beaconchain
        bool locked;        // Whether the validator has been locked by the oDAO for not exiting

        uint64 exitBalance;         // Final balance of the validator at withdrawable_epoch in gwei (amount returned to EL)
        uint64 lockedTime;          // The slot this validator was challenged about its exit status
    }

    //
    // Delegate state
    //

    bool internal storageState;           // Used to prevent direct calls to the delegate contract
    uint256 internal expirationTime;      // Used to store the expiry timestamp of this delegate (0 meaning not expiring)

    //
    // Proxy state
    //

    address internal rocketMegapoolDelegate;  // The current delegate contract address
    bool internal useLatestDelegate;          // Whether this proxy always uses the latest delegate

    //
    // Megapool state
    //

    address internal nodeAddress;             // Megapool owner
    uint32 internal numValidators;            // Number of individual validators handled by this megapool
    uint32 internal numInactiveValidators;    // Number of validators that are no longer contributing to bond requirement

    uint256 internal assignedValue;   // ETH assigned from DP pending prestake/stake
    uint256 internal refundValue;     // ETH refunded to the owner after a dissolution

    uint256 internal nodeBond;              // Value of node ETH bond (including value yet to be assigned/deposited)
    uint256 internal userCapital;           // Value of user supplied capital (including value yet to be assigned/deposited)
    uint256 internal nodeQueuedBond;        // Value of node ETH bond (yet to be assigned/deposited to beacon chain)
    uint256 internal userQueuedCapital;     // Value of user supplied capital (yet to be assigned/deposited to beacon chain)

    uint256 internal debt;            // Amount the owner owes the DP

    uint256 internal lastDistributionTime; // The block of the last time a distribution of rewards was executed

    mapping(uint32 => ValidatorInfo) internal validators;
    mapping(uint32 => bytes) internal prestakeSignatures;
    mapping(uint32 => bytes) internal pubkeys;

    uint32 internal numLockedValidators;        // Number of validators currently locked
    uint32 internal numExitingValidators;       // Number of validators currently exiting

    uint256 internal __version1Boundary;        // Unused full slot width boundary
}

File 16 of 30 : RocketMegapoolDelegateInterface.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

import "../util/BeaconStateVerifierInterface.sol";
import {RocketMegapoolDelegateBaseInterface} from "./RocketMegapoolDelegateBaseInterface.sol";
import {RocketMegapoolStorageLayout} from "../../contract/megapool/RocketMegapoolStorageLayout.sol";

interface RocketMegapoolDelegateInterface is RocketMegapoolDelegateBaseInterface {
    struct StateProof {
        bytes data;
    }

    function newValidator(uint256 _bondAmount, bool _useExpressTicket, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot) external;
    function dequeue(uint32 _validatorId) external;
    function reduceBond(uint256 _amount) external;
    function assignFunds(uint32 _validatorId) external payable;
    function stake(uint32 _validatorId) external;
    function dissolveValidator(uint32 _validatorId) external;
    function getNodeAddress() external returns (address);
    function distribute() external;
    function claim() external;
    function repayDebt() external payable;

    function challengeExit(uint32 _validatorId) external;
    function notifyNotExit(uint32 _validatorId, uint64 _slotTimestamp) external;
    function notifyExit(uint32 _validatorId, uint64 _withdrawableEpoch, uint64 _recentEpoch) external;
    function notifyFinalBalance(uint32 _validatorId, uint64 _amountInGwei, address _caller, uint64 _withdrawalEpoch, uint64 _recentEpoch) external;
    function applyPenalty(uint256 _amount) external;

    function getValidatorCount() external view returns (uint32);
    function getActiveValidatorCount() external view returns (uint32);
    function getExitingValidatorCount() external view returns (uint32);
    function getLockedValidatorCount() external view returns (uint32);
    function getValidatorInfo(uint32 _validatorId) external view returns (RocketMegapoolStorageLayout.ValidatorInfo memory);
    function getValidatorPubkey(uint32 _validatorId) external view returns (bytes memory);
    function getValidatorInfoAndPubkey(uint32 _validatorId) external view returns (RocketMegapoolStorageLayout.ValidatorInfo memory info, bytes memory pubkey);
    function getAssignedValue() external view returns (uint256);
    function getDebt() external view returns (uint256);
    function getRefundValue() external view returns (uint256);
    function getNodeBond() external view returns (uint256);
    function getUserCapital() external view returns (uint256);
    function getNodeQueuedBond() external view returns (uint256);
    function getUserQueuedCapital() external view returns (uint256);
    function calculatePendingRewards() external view returns (uint256 nodeRewards, uint256 voterRewards, uint256 protocolDAORewards, uint256 rethRewards);
    function calculateRewards(uint256 _amount) external view returns (uint256 nodeRewards, uint256 voterRewards, uint256 protocolDAORewards, uint256 rethRewards);
    function getPendingRewards() external view returns (uint256);
    function getLastDistributionTime() external view returns (uint256);
    function getNewValidatorBondRequirement() external view returns (uint256);

    function getWithdrawalCredentials() external view returns (bytes32);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

import "../../interface/RocketStorageInterface.sol";

interface RocketMegapoolProxyInterface {
    function initialise(address _nodeAddress) external;
    function delegateUpgrade() external;
    function setUseLatestDelegate(bool _state) external;
    function getUseLatestDelegate() external view returns (bool);
    function getDelegate() external view returns (address);
    function getEffectiveDelegate() external view returns (address);
    function getDelegateExpired() external view returns (bool);
}

File 18 of 30 : RocketMegapoolInterface.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

import {RocketMegapoolDelegateInterface} from "./RocketMegapoolDelegateInterface.sol";
import {RocketMegapoolProxyInterface} from "./RocketMegapoolProxyInterface.sol";

interface RocketMegapoolInterface is RocketMegapoolDelegateInterface, RocketMegapoolProxyInterface {
}

File 19 of 30 : MinipoolStatus.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

// Represents a minipool's status within the network

enum MinipoolStatus {
    Initialised,    // The minipool has been initialised and is awaiting a deposit of user ETH
    Prelaunch,      // The minipool has enough ETH to begin staking and is awaiting launch by the node operator
    Staking,        // The minipool is currently staking
    Withdrawable,   // NO LONGER USED
    Dissolved       // The minipool has been dissolved and its user deposited ETH has been returned to the deposit pool
}

File 20 of 30 : RocketMinipoolInterface.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

import "../../types/MinipoolDeposit.sol";
import "../../types/MinipoolStatus.sol";
import "../RocketStorageInterface.sol";

interface RocketMinipoolInterface {
    function version() external view returns (uint8);
    function initialise(address _nodeAddress) external;
    function getStatus() external view returns (MinipoolStatus);
    function getFinalised() external view returns (bool);
    function getStatusBlock() external view returns (uint256);
    function getStatusTime() external view returns (uint256);
    function getScrubVoted(address _member) external view returns (bool);
    function getDepositType() external view returns (MinipoolDeposit);
    function getNodeAddress() external view returns (address);
    function getNodeFee() external view returns (uint256);
    function getNodeDepositBalance() external view returns (uint256);
    function getNodeRefundBalance() external view returns (uint256);
    function getNodeDepositAssigned() external view returns (bool);
    function getPreLaunchValue() external view returns (uint256);
    function getNodeTopUpValue() external view returns (uint256);
    function getVacant() external view returns (bool);
    function getPreMigrationBalance() external view returns (uint256);
    function getUserDistributed() external view returns (bool);
    function getUserDepositBalance() external view returns (uint256);
    function getUserDepositAssigned() external view returns (bool);
    function getUserDepositAssignedTime() external view returns (uint256);
    function getTotalScrubVotes() external view returns (uint256);
    function calculateNodeShare(uint256 _balance) external view returns (uint256);
    function calculateUserShare(uint256 _balance) external view returns (uint256);
    function preDeposit(uint256 _bondingValue, bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot) external payable;
    function deposit() external payable;
    function userDeposit() external payable;
    function distributeBalance(bool _rewardsOnly) external;
    function beginUserDistribute() external;
    function userDistributeAllowed() external view returns (bool);
    function refund() external;
    function slash() external;
    function finalise() external;
    function canStake() external view returns (bool);
    function canPromote() external view returns (bool);
    function stake(bytes calldata _validatorSignature, bytes32 _depositDataRoot) external;
    function prepareVacancy(uint256 _bondAmount, uint256 _currentBalance) external;
    function promote() external;
    function dissolve() external;
    function close() external;
    function voteScrub() external;
    function reduceBondAmount() external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

import "../../types/MinipoolDeposit.sol";

interface RocketMinipoolQueueInterface {
    function getTotalLength() external view returns (uint256);
    function getContainsLegacy() external view returns (bool);
    function getLengthLegacy(MinipoolDeposit _depositType) external view returns (uint256);
    function getLength() external view returns (uint256);
    function getTotalCapacity() external view returns (uint256);
    function getEffectiveCapacity() external view returns (uint256);
    function getNextCapacityLegacy() external view returns (uint256);
    function getNextDepositLegacy() external view returns (MinipoolDeposit, uint256);
    function enqueueMinipool(address _minipool) external;
    function dequeueMinipoolByDepositLegacy(MinipoolDeposit _depositType) external returns (address minipoolAddress);
    function dequeueMinipools(uint256 _maxToDequeue) external returns (address[] memory minipoolAddress);
    function removeMinipool(MinipoolDeposit _depositType) external;
    function getMinipoolAt(uint256 _index) external view returns(address);
    function getMinipoolPosition(address _minipool) external view returns (int256);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

/// @notice Accounting for snapshotting of values based on block numbers
interface RocketNetworkSnapshotsInterface {
    struct Checkpoint224 {
        uint32 _block;
        uint224 _value;
    }

    function push(bytes32 _key, uint224 _value) external;
    function length(bytes32 _key) external view returns (uint256);
    function latest(bytes32 _key) external view returns (bool exists, uint32 block, uint224 value);
    function latestBlock(bytes32 _key) external view returns (uint32);
    function latestValue(bytes32 _key) external view returns (uint224);
    function lookup(bytes32 _key, uint32 _block) external view returns (uint224);
    function lookupCheckpoint(bytes32 _key, uint32 _block) external view returns (bool exists, uint32 block, uint224 value);
    function lookupRecent(bytes32 _key, uint32 _block, uint256 _recency) external view returns (uint224);
}

File 23 of 30 : NodeDetails.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

// A struct containing all the information on-chain about a specific node

struct NodeDetails {
    bool exists;
    uint256 registrationTime;
    string timezoneLocation;
    bool feeDistributorInitialised;
    address feeDistributorAddress;
    uint256 rewardNetwork;
    uint256 rplStake;
    uint256 effectiveRPLStake;
    uint256 minimumRPLStake;
    uint256 maximumRPLStake;
    uint256 ethMatched;
    uint256 ethMatchedLimit;
    uint256 minipoolCount;
    uint256 balanceETH;
    uint256 balanceRETH;
    uint256 balanceRPL;
    uint256 balanceOldRPL;
    uint256 depositCreditBalance;
    uint256 distributorBalanceUserETH;
    uint256 distributorBalanceNodeETH;
    address withdrawalAddress;
    address pendingWithdrawalAddress;
    bool smoothingPoolRegistrationState;
    uint256 smoothingPoolRegistrationChanged;
    address nodeAddress;
}

File 24 of 30 : RocketNodeManagerInterface.sol
/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;

import "../../types/NodeDetails.sol";

interface RocketNodeManagerInterface {

    // Structs
    struct TimezoneCount {
        string timezone;
        uint256 count;
    }

    function getNodeCount() external view returns (uint256);
    function getNodeCountPerTimezone(uint256 offset, uint256 limit) external view returns (TimezoneCount[] memory);
    function getNodeAt(uint256 _index) external view returns (address);
    function getNodeExists(address _nodeAddress) external view returns (bool);
    function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
    function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
    function getNodeRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
    function getNodeRPLWithdrawalAddressIsSet(address _nodeAddress) external view returns (bool);
    function unsetRPLWithdrawalAddress(address _nodeAddress) external;
    function setRPLWithdrawalAddress(address _nodeAddress, address _newRPLWithdrawalAddress, bool _confirm) external;
    function confirmRPLWithdrawalAddress(address _nodeAddress) external;
    function getNodePendingRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
    function getNodeTimezoneLocation(address _nodeAddress) external view returns (string memory);
    function registerNode(string calldata _timezoneLocation) external;
    function getNodeRegistrationTime(address _nodeAddress) external view returns (uint256);
    function setTimezoneLocation(string calldata _timezoneLocation) external;
    function setRewardNetwork(address _nodeAddress, uint256 network) external;
    function getRewardNetwork(address _nodeAddress) external view returns (uint256);
    function getFeeDistributorInitialised(address _nodeAddress) external view returns (bool);
    function initialiseFeeDistributor() external;
    function getAverageNodeFee(address _nodeAddress) external view returns (uint256);
    function setSmoothingPoolRegistrationState(bool _state) external;
    function getSmoothingPoolRegistrationState(address _nodeAddress) external returns (bool);
    function getSmoothingPoolRegistrationChanged(address _nodeAddress) external returns (uint256);
    function getSmoothingPoolRegisteredNodeCount(uint256 _offset, uint256 _limit) external view returns (uint256);
    function getNodeAddresses(uint256 _offset, uint256 _limit) external view returns (address[] memory);
    function deployMegapool() external returns (address);
    function getExpressTicketCount(address _nodeAddress) external view returns (uint256);
    function useExpressTicket(address _nodeAddress) external;
    function provisionExpressTickets(address _nodeAddress) external;
    function getExpressTicketsProvisioned(address _nodeAddress) external view returns (bool);
    function refundExpressTicket(address _nodeAddress) external;
    function getMegapoolAddress(address _nodeAddress) external view returns (address);
    function getUnclaimedRewards(address _nodeAddress) external view returns (uint256);
    function addUnclaimedRewards(address _nodeAddress) external payable;
    function claimUnclaimedRewards(address _nodeAddress) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity >0.5.0 <0.9.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @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);

    /**
     * @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 `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, 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 `from` to `to` 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 from, address to, uint256 amount) external returns (bool);
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

import "../util/IERC20.sol";

interface RocketTokenRETHInterface is IERC20 {
    function getEthValue(uint256 _rethAmount) external view returns (uint256);
    function getRethValue(uint256 _ethAmount) external view returns (uint256);
    function getExchangeRate() external view returns (uint256);
    function getTotalCollateral() external view returns (uint256);
    function getCollateralRate() external view returns (uint256);
    function depositExcess() external payable;
    function depositExcessCollateral() external;
    function mint(uint256 _ethAmount, address _to) external;
    function burn(uint256 _rethAmount) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

import "./IERC20.sol";

pragma solidity >0.5.0 <0.9.0;

interface IERC20Burnable is IERC20 {
    function burn(uint256 amount) external;
    function burnFrom(address account, uint256 amount) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only
import "./util/IERC20Burnable.sol";

interface RocketVaultInterface {
    function balanceOf(string memory _networkContractName) external view returns (uint256);
    function depositEther() external payable;
    function withdrawEther(uint256 _amount) external;
    function depositToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
    function withdrawToken(address _withdrawalAddress, IERC20 _tokenAddress, uint256 _amount) external;
    function balanceOfToken(string memory _networkContractName, IERC20 _tokenAddress) external view returns (uint256);
    function transferToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
    function burnToken(IERC20Burnable _tokenAddress, uint256 _amount) external;
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

pragma solidity >0.5.0 <0.9.0;

// SPDX-License-Identifier: GPL-3.0-only

interface RocketVaultWithdrawerInterface {
    function receiveVaultWithdrawalETH() external payable; 
}

/**
   *       .
   *      / \
   *     |.'.|
   *     |'.'|
   *   ,'|   |'.
   *  |,-'-|-'-.|
   *   __|_| |         _        _      _____           _
   *  | ___ \|        | |      | |    | ___ \         | |
   *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
   *  |    // _ \ / __| |/ / _ \ __|  |  __/ _ \ / _ \| |
   *  | |\ \ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
   *  \_| \_\___/ \___|_|\_\___|\__|  \_|  \___/ \___/|_|
   * +---------------------------------------------------+
   * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
   * +---------------------------------------------------+
   *
   *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
   *  be community-owned, decentralised, permissionless, & trustless.
   *
   *  For more information about Rocket Pool, visit https://rocketpool.net
   *
   *  Authored by the Rocket Pool Core Team
   *  Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
   *  A special thanks to the Rocket Pool community for all their contributions.
   *
   */

// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;

interface RocketMegapoolFactoryInterface {
    function initialise() external;
    function getExpectedAddress(address _nodeAddress) external view returns (address);
    function getMegapoolDeployed(address _nodeAddress) external view returns (bool);
    function deployContract(address _nodeAddress) external returns (address);
    function getOrDeployContract(address _nodeAddress) external  returns (address);
    function upgradeDelegate(address _newDelegateAddress) external;
    function getDelegateExpiry(address _delegateAddress) external view returns (uint256);
}

Settings
{
  "viaIR": true,
  "optimizer": {
    "enabled": true,
    "runs": 15000
  },
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"contract RocketStorageInterface","name":"_rocketStorageAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"CreditWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"minipool","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"DepositAssigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"DepositReceived","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"DepositRecycled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"ExcessWithdrawn","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"FundsAssigned","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"validatorId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"bool","name":"expressQueue","type":"bool"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"FundsRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"nodeAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"time","type":"uint256"}],"name":"QueueExited","type":"event"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"applyCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_max","type":"uint256"}],"name":"assignDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint32","name":"_validatorId","type":"uint32"},{"internalType":"bool","name":"_expressQueue","type":"bool"}],"name":"exitQueue","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_nodeAmount","type":"uint256"},{"internalType":"uint256","name":"_userAmount","type":"uint256"}],"name":"fundsReturned","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExcessBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getExpressQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMaximumDepositAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMinipoolQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getNodeBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"}],"name":"getNodeCreditBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQueueIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getQueueTop","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"bool","name":"assignmentPossible","type":"bool"},{"internalType":"uint256","name":"headMovedBlock","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStandardQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTotalQueueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUserBalance","outputs":[{"internalType":"int256","name":"","type":"int256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_max","type":"uint256"}],"name":"maybeAssignDeposits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondAmount","type":"uint256"}],"name":"nodeDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"receiveVaultWithdrawalETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"recycleDissolvedDeposit","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"recycleExcessCollateral","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"recycleLiquidatedStake","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"reduceBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_bondAmount","type":"uint256"},{"internalType":"uint32","name":"_validatorId","type":"uint32"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"bool","name":"_expressQueue","type":"bool"}],"name":"requestFunds","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawCredit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawCreditFor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdrawExcessBalance","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c08060405234610145576020816159a0803803809161001f828561014a565b83398101031261014557516001600160a01b038116810361014557600080546001600160a81b03191660089290921b610100600160a81b03169190911760041790556040805190610070908261014a565b600b81526a1c9bd8dad95d15985d5b1d60aa1b60208201526001600160a01b039061009a90610183565b166080526040516100ac60408261014a565b600f81526e0e4dec6d6cae8a8ded6cadca48aa89608b1b60208201526001600160a01b03906100da90610183565b1660a0526040516156d490816102cc8239608051818181611d4e0152818161221c015281816125aa015281816130c5015281816143ad0152818161467c0152614ac7015260a05181818161054401528181611dc2015281816140d30152818161442e01526151910152f35b600080fd5b601f909101601f19168101906001600160401b0382119082101761016d57604052565b634e487b7160e01b600052604160045260246000fd5b60405160208101916f636f6e74726163742e6164647265737360801b83528181519160005b8381106102b3575050806101cf92603092016000838201520301601f19810183528261014a565b5190206000546040516321f8a72160e01b815260048101929092526020908290602490829060081c6001600160a01b03165afa9081156102a75760009161025e575b506001600160a01b038116156102245790565b60405162461bcd60e51b815260206004820152601260248201527110dbdb9d1c9858dd081b9bdd08199bdd5b9960721b6044820152606490fd5b6020813d60201161029f575b816102776020938361014a565b8101031261029b5751906001600160a01b0382168203610298575038610211565b80fd5b5080fd5b3d915061026a565b6040513d6000823e3d90fd5b602082820181015160308784010152859350016101a856fe6080604052600436101561001257600080fd5b6000803560e01c806312065fe0146124785780631666f5e21461237c5780631b7dd4c0146122db5780631e35fed8146122c05780631eddb626146122a557806322b1751d146120d4578063258260951461205d57806327afc6f5146120425780633350677b1461202757806342e6dfa214611ff657806354fd4d5014611fd657806360be2e1c14611ef057806363a5db9e14611cf157806372f5158d14611ba8578063791d25b114611b8d5780637aab9e1614611af25780637d9d607414611612578063888b042f146115f75780639a8dd16f14610d915780639e2c0c1914610d6e578063a559a64514610bc6578063a673c8e114610b96578063a9a9482214610a73578063b7013dc114610a02578063c095415d14610961578063c6f20e6d14610928578063d0e30db0146103b4578063db82047b146102c95763ef6f886a1461015c57600080fd5b346102c65760206003193601126102c6576101fe6101f960405160208101906101f1816101c533856bffffffffffffffffffffffff19601f927f6e6f64652e657869737473000000000000000000000000000000000000000000835260601b16600b8201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612507565b5190206138dc565b612d27565b6102196001600160a01b036102116133ad565b163014612621565b602460206001600160a01b03835460081c16604051928380927f5b49ff620000000000000000000000000000000000000000000000000000000082523360048301525afa80156102bb57829061027c575b61027991506004359033613e44565b80f35b506020813d6020116102b3575b8161029660209383612507565b810103126102af576102aa61027991612b19565b61026a565b5080fd5b3d9150610289565b6040513d84823e3d90fd5b80fd5b50806003193601126102c6576102e86001600160a01b036102116133ad565b61037a6001600160a01b03610372604051610304604082612507565b600f81527f726f636b6574546f6b656e524554480000000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b519020613458565b163314612621565b6040513481524260208201527f3a6614e80d02b57255cbb1f8305fbeca53d7e05a4b779d40627919660851292560403392a261027961436d565b50806003193601126102c6576103d36001600160a01b036102116133ad565b6001600160a01b0361041b6040516103ec604082612507565b602081527f726f636b657444414f50726f746f636f6c53657474696e67734465706f73697460208201526134af565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa80156108fe57610462918491610909575b5061333c565b6040517f035cf142000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156108fe5783916108cc575b503410610862578190346104b1612548565b016040517ffd6ce89e000000000000000000000000000000000000000000000000000000008152602081600481865afa908115610857578491610822575b50808211610653575b50506020600491604051928380927f0de705b50000000000000000000000000000000000000000000000000000000082525afa9081156102bb578291610619575b506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b15610615576040517f94bf804d000000000000000000000000000000000000000000000000000000008152670de0b6b3a76400003493840204909203600483015233602483015282908290604490829084905af180156102bb57610600575b506040513481524260208201527f7aa1a8eb998c779420645fc14513bf058edb347d95c2fc2e6845bdc22f88863160403392a261027961436d565b8161060a91612507565b6102c65780386105c5565b5050fd5b9150506020813d60201161064b575b8161063560209383612507565b810103126106465781905138610539565b600080fd5b3d9150610628565b909192506040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481875afa9081156107e85785916107f3575b50156107475760049060206001600160a01b036106e66040516106b8604082612507565b601381527f726f636b65744d696e69706f6f6c517565756500000000000000000000000000848201526134af565b16604051938480927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa9182156107e85785926107b2575b5061073161073792610731613726565b906126fa565b10610747578190602060046104f8565b60405162461bcd60e51b815260206004820152603f60248201527f546865206465706f73697420706f6f6c2073697a65206166746572206465706f60448201527f736974696e67206578636565647320746865206d6178696d756d2073697a65006064820152608490fd5b91506020823d6020116107e0575b816107cd60209383612507565b8101031261064657905190610731610721565b3d91506107c0565b6040513d87823e3d90fd5b610815915060203d60201161081b575b61080d8183612507565b8101906126b7565b38610694565b503d610803565b9350506020833d60201161084f575b8161083e60209383612507565b8101031261064657839251386104ef565b3d9150610831565b6040513d86823e3d90fd5b608460405162461bcd60e51b815260206004820152603a60248201527f546865206465706f736974656420616d6f756e74206973206c6573732074686160448201527f6e20746865206d696e696d756d206465706f7369742073697a650000000000006064820152fd5b90506020813d6020116108f6575b816108e760209383612507565b8101031261064657513861049f565b3d91506108da565b6040513d85823e3d90fd5b610922915060203d60201161081b5761080d8183612507565b3861045c565b50346102c657806003193601126102c6576060610943612e09565b906001600160a01b0360405193168352151560208301526040820152f35b50806003193601126102c6576109806001600160a01b036102116133ad565b6102796001600160a01b0361037260405161099c604082612507565b600b81527f726f636b65745661756c74000000000000000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b50346102c657806003193601126102c657610a1b612548565b90610a24613638565b91818382039312818412811691841390151617610a4657602082604051908152f35b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b50346102c65760606003193601126102c657610279610a90612493565b610aed610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b612ace565b610b006001600160a01b036102116133ad565b610b0c602435826139de565b60405190610b8a82610b5e6020820193846bffffffffffffffffffffffff196034927f6d656761706f6f6c2e6574682e6d6174636865642e6e6f64652e616d6f756e74835260601b1660208201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283612507565b60443591519020613cd3565b50346102c65760206003193601126102c657610bbb6001600160a01b036102116133ad565b610279600435612d72565b50346102c65760406003193601126102c6576024610be2612493565b610c3a6101f960405160208101906101f1816101c587856bffffffffffffffffffffffff19601f927f6e6f64652e657869737473000000000000000000000000000000000000000000835260601b16600b8201520190565b610c4d6001600160a01b036102116133ad565b60206001600160a01b03845460081c16604051938480927f5b49ff620000000000000000000000000000000000000000000000000000000082526001600160a01b03861660048301525afa9182156108fe578392610d2e575b506001600160a01b0382163303610cc4576102799160243591613e44565b608460405162461bcd60e51b815260206004820152602660248201527f4d7573742062652063616c6c65642066726f6d207769746864726177616c206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b9091506020813d602011610d66575b81610d4a60209383612507565b81010312610d6257610d5b90612b19565b9038610ca6565b8280fd5b3d9150610d3d565b50346102c657806003193601126102c6576020610d89612ca5565b604051908152f35b50346102c65760806003193601126102c657600435610dae6124a9565b90604435606435918215159283810361135957610e19610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b610e2c6001600160a01b036102116133ad565b66038d7ea4c6800082066115b35766038d7ea4c68000830661156f57604051907f70dabc9e0000000000000000000000000000000000000000000000000000000082526020826004818a335af19182156113d0578792611533575b50866001600160a01b03610ed1604051610ea2604082612507565b601181527f726f636b65744e6f64654d616e6167657200000000000000000000000000000060208201526134af565b1682156114c557803b156102af578180916024604051809481937fc220f0920000000000000000000000000000000000000000000000000000000083526001600160a01b038a1660048401525af180156102bb576114ac575b50505b610f3681613b7d565b9087610f4a66038d7ea4c680008604613dc6565b92610f5d66038d7ea4c680008804613dc6565b60405190610f6a826124bc565b33825263ffffffff602083019b169a8b815263ffffffff604084019716875263ffffffff60608401921682526001600160a01b03610fde604051610faf604082612507565b601181527f6c696e6b65644c69737453746f7261676500000000000000000000000000000060208201526134af565b1696873b156113595763ffffffff8094926001600160a01b038294604051987fea58ecf5000000000000000000000000000000000000000000000000000000008a5260048a015251166024880152511660448601525116606484015251166084820152818160a48183885af180156102bb57611497575b506001600160a01b03815460081c16803b156102af578180916044604051809481937fadb353dc0000000000000000000000000000000000000000000000000000000083527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce060048401528c60248401525af180156102bb5761147e575b50506024916020916000146113db57604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b60048301525afa80156113d057879061139d575b6001915014611390575b856001600160a01b03611194604051611165604082612507565b601681527f726f636b65744e6574776f726b536e617073686f74730000000000000000000060208201526134af565b16604051602081019061120d816101c587856bffffffffffffffffffffffff196035927f6d656761706f6f6c2e6574682e70726f76696465642e6e6f64652e616d6f756e83527f7400000000000000000000000000000000000000000000000000000000000000602084015260601b1660218201520190565b5190206040517f6838444b000000000000000000000000000000000000000000000000000000008152816004820152602081602481865afa90811561085757867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff809361127e938891611361575b50166126fa565b16823b1561135d576040517f5ba5964900000000000000000000000000000000000000000000000000000000815260048101929092527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660248201529082908290604490829084905af180156102bb57611344575b50506112ff6113059284612736565b9061394c565b604051928352602083015260408201524260608201527f4040156d881bd2ba289490b90281b228e6c221621274ce90999669f12d74ddfb60803392a280f35b8161134e91612507565b6113595785386112f0565b8580fd5b8380fd5b611383915060203d602011611389575b61137b8183612507565b8101906139aa565b38611277565b503d611371565b611398613d80565b61114b565b506020813d6020116113c8575b816113b760209383612507565b810103126106465760019051611141565b3d91506113aa565b6040513d89823e3d90fd5b604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e60048301525afa80156113d057879061144b575b600191500361114b57611398613d37565b506020813d602011611476575b8161146560209383612507565b81010312610646576001905161143a565b3d9150611458565b8161148891612507565b6114935787386110d3565b8780fd5b816114a191612507565b611493578738611055565b816114b691612507565b6114c1578638610f2a565b8680fd5b803b156102af578180916024604051809481937f4395fb740000000000000000000000000000000000000000000000000000000083526001600160a01b038a1660048401525af180156102bb5761151e575b5050610f2d565b8161152891612507565b6114c1578638611517565b9091506020813d602011611567575b8161154f60209383612507565b810103126114c15761156090612b19565b9038610e87565b3d9150611542565b606460405162461bcd60e51b815260206004820152601860248201527f496e76616c69642072657175657374656420616d6f756e7400000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601760248201527f496e76616c696420737570706c69656420616d6f756e740000000000000000006044820152fd5b50346102c657806003193601126102c6576020610d89612ba9565b50346102c65760606003193601126102c65761162c612493565b6116346124a9565b60443590811515820361135d57611699610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b6116ac6001600160a01b036102116133ad565b6001600160a01b036116c5604051610faf604082612507565b1691604051916040830183811067ffffffffffffffff821117611ac55760405233835263ffffffff166020830152846116fd82613b7d565b6040517fed8ef8fb0000000000000000000000000000000000000000000000000000000081526004810182905284516001600160a01b0316602482015260208086015163ffffffff1660448301529095919086606481855afa9586156108fe578396611a8e575b50604051957ff3358a3a000000000000000000000000000000000000000000000000000000008752816004880152806024880152608087604481865afa968715610857578497611a5d575b506040517f45134808000000000000000000000000000000000000000000000000000000008152826004820152602081602481875afa9081156107e8578591611a28575b501494823b1561135d576040517f41b93d1b000000000000000000000000000000000000000000000000000000008152600481019290925280516001600160a01b031660248301526020015163ffffffff1660448201529082908290606490829084905af180156102bb57611a0f575b505063ffffffff60608401511666038d7ea4c6800081029080820466038d7ea4c6800014901517156119e25761189890613bc9565b156119cc57836001600160a01b036118b7604051610ea2604082612507565b16803b156102af578180916024604051809481937fa90e35a60000000000000000000000000000000000000000000000000000000083526001600160a01b038b1660048401525af180156102bb576119b7575b505063ffffffff916040916119aa575b01511666038d7ea4c6800081029080820466038d7ea4c68000149015171561197d5761194590613c4e565b7f795bf47f48111f2d01d87912d6b77fa833a62f0c4e2221ae9ecd474ec50d8b3360206001600160a01b03604051934285521692a280f35b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6119b2613d80565b61191a565b816119c191612507565b61135d57833861190a565b63ffffffff916040911561191a576119b2613d37565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b81611a1991612507565b611a24578438611863565b8480fd5b9450506020843d602011611a55575b81611a4460209383612507565b8101031261064657889351386117f3565b3d9150611a37565b611a8091975060803d608011611a87575b611a788183612507565b810190612b3e565b95386117af565b503d611a6e565b925094506020823d602011611abd575b81611aab60209383612507565b81010312610646578691519438611764565b3d9150611a9e565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50346102c65760406003193601126102c657610279611b0f612493565b60243590611b6b610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b611b7e6001600160a01b036102116133ad565b611b88828261394c565b6139de565b50346102c657806003193601126102c6576020610d896136af565b50806003193601126102c657611bc76001600160a01b036102116133ad565b6040517f6d656761706f6f6c2e6578697374730000000000000000000000000000000000602082019081523360601b6bffffffffffffffffffffffff1916602f830152611c1b916101f181604381016101c5565b8015611ca5575b15611c61576040513481524260208201527f3a6614e80d02b57255cbb1f8305fbeca53d7e05a4b779d40627919660851292560403392a261027961436d565b606460405162461bcd60e51b815260206004820152600e60248201527f496e76616c69642063616c6c65720000000000000000000000000000000000006044820152fd5b50611cec60405160208101907f6d696e69706f6f6c2e657869737473000000000000000000000000000000000082523360601b602f820152602381526101f1604382612507565b611c22565b50346102c65760206003193601126102c657600435611d196001600160a01b036102116133ad565b611d356001600160a01b03610372604051610304604082612507565b611d3d612ba9565b8111611e8657816001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102af578180916024604051809481937f3bed33ce0000000000000000000000000000000000000000000000000000000083528860048401525af180156102bb57611e71575b506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b156102af578183916004604051809481937f6c985a880000000000000000000000000000000000000000000000000000000083525af180156102bb57611e5c575b50506040519081524260208201527f992f462cfb62e164bd03bf07baf2cffce83fbd9370cae10635842b202001212060403392a280f35b81611e6691612507565b6102af578138611e25565b81611e7b91612507565b6102af578138611db7565b608460405162461bcd60e51b815260206004820152602a60248201527f496e73756666696369656e74206578636573732062616c616e636520666f722060448201527f7769746864726177616c000000000000000000000000000000000000000000006064820152fd5b50346102c65760406003193601126102c657610279611f0d612493565b611f65610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b611f786001600160a01b036102116133ad565b60405190611fca82610b5e6020820193846bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b6024359151902061386b565b50346102c657806003193601126102c65760ff6020915416604051908152f35b50346102c657806003193601126102c6576020610d8961201f61201761296e565b610731612a1e565b610731612ca5565b50346102c657806003193601126102c6576020610d89612a1e565b50346102c657806003193601126102c6576020610d8961296e565b50346102c65760206003193601126102c6576020610d8961207c612493565b6040516120cc816101c586820194856bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b519020613814565b5060206003193601126102c6576120f46001600160a01b036102116133ad565b6121766001600160a01b03610372604051612110604082612507565b601181527f726f636b65744e6f64654465706f736974000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b34612212575b806001600160a01b03815460081c16803b1561220f578180916044604051809481937fadb353dc0000000000000000000000000000000000000000000000000000000083527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e636500000000000000600484015260043560248401525af180156102bb576121fe5750f35b8161220891612507565b6102c65780f35b50fd5b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001681813b156102c65780600492604051938480927f98ea5fca00000000000000000000000000000000000000000000000000000000825234905af1801561229857612288575b505061217c565b61229191612507565b3881612281565b50604051903d90823e3d90fd5b50346102c657806003193601126102c6576020610d89612743565b50346102c657806003193601126102c6576020610d89613638565b50806003193601126102c6576122fa6001600160a01b036102116133ad565b61037a6001600160a01b03610372604051612316604082612507565b601481527f726f636b657441756374696f6e4d616e61676572000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b50346102c65760206003193601126102c6576004356123a46001600160a01b036102116133ad565b6123af81151561266c565b6001600160a01b036123c86040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa908115610857578491612459575b50156124155761027991613545565b606460405162461bcd60e51b815260206004820152602060248201527f4465706f7369742061737369676e6d656e7473206172652064697361626c65646044820152fd5b612472915060203d60201161081b5761080d8183612507565b38612406565b50346102c657806003193601126102c6576020610d89612548565b600435906001600160a01b038216820361064657565b6024359063ffffffff8216820361064657565b6080810190811067ffffffffffffffff8211176124d857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176124d857604052565b6040517f35ee5f87000000000000000000000000000000000000000000000000000000008152602060048201819052601160248301527f726f636b65744465706f736974506f6f6c0000000000000000000000000000006044830152816064817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115612615576000916125e6575090565b90506020813d60201161260d575b8161260160209383612507565b81010312610646575190565b3d91506125f4565b6040513d6000823e3d90fd5b1561262857565b606460405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964206f72206f7574646174656420636f6e7472616374000000006044820152fd5b1561267357565b606460405162461bcd60e51b815260206004820152601660248201527f4d7573742061737369676e206174206c656173742031000000000000000000006044820152fd5b90816020910312610646575180151581036106465790565b9081519160005b8381106126e7575050016000815290565b80602080928401015181850152016126d6565b9190820180921161270757565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161270757565b6001600160a01b0361275c6040516103ec604082612507565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156126155760009161294f575b5015612949576127a9612548565b6040517ffd6ce89e000000000000000000000000000000000000000000000000000000008152602081600481865afa90811561261557600091612917575b50600460208294604051928380927f47fa434a0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916128f8575b5061284b575b50818110156128445761284191612736565b90565b5050600090565b909150600460206001600160a01b0361286b6040516106b8604082612507565b16604051928380927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916128c4575b506128b5906128bd926126fa565b610731613726565b903861282f565b90506020813d6020116128f0575b816128df60209383612507565b8101031261064657516128bd6128a7565b3d91506128d2565b612911915060203d60201161081b5761080d8183612507565b38612829565b906020823d602011612941575b8161293160209383612507565b810103126102c6575051386127e7565b3d9150612924565b50600090565b612968915060203d60201161081b5761080d8183612507565b3861279b565b602460206001600160a01b036129b960405161298b604082612507565b601381527f61646472657373517565756553746f7261676500000000000000000000000000848201526134af565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa908115612615576000916125e6575090565b602460206001600160a01b03612a69604051612a3b604082612507565b601181527f6c696e6b65644c69737453746f72616765000000000000000000000000000000848201526134af565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b60048301525afa908115612615576000916125e6575090565b15612ad557565b606460405162461bcd60e51b815260206004820152601060248201527f496e76616c6964206d656761706f6f6c000000000000000000000000000000006044820152fd5b51906001600160a01b038216820361064657565b519063ffffffff8216820361064657565b9081608091031261064657612b8e606060405192612b5b846124bc565b612b6481612b19565b8452612b7260208201612b2d565b6020850152612b8360408201612b2d565b604085015201612b2d565b606082015290565b8181029291811591840414171561270757565b600460206001600160a01b03612bc66040516106b8604082612507565b16604051928380927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa801561261557600090612c2e575b612c0e9150610731613726565b612c16612548565b90818110612c25575050600090565b61284191612736565b506020813d602011612c5a575b81612c4860209383612507565b8101031261064657612c0e9051612c01565b3d9150612c3b565b8115612c6c570690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612c6c570490565b602460206001600160a01b03612cc2604051612a3b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e60048301525afa908115612615576000916125e6575090565b15612d2e57565b606460405162461bcd60e51b815260206004820152600c60248201527f496e76616c6964206e6f646500000000000000000000000000000000000000006044820152fd5b612d7d81151561266c565b6001600160a01b03612d966040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa90811561261557600091612dea575b5015612de657612de491613545565b565b5050565b612e03915060203d60201161081b5761080d8183612507565b38612dd5565b602460206001600160a01b03612e2660405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa9081156126155760009161330a575b506132ff576001600160a01b03612ea6604051610faf604082612507565b166001600160a01b03612ec06040516103ec604082612507565b16916040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b6004820152602081602481865afa908115612615576000916132cd575b50604051907ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e6004830152602082602481875afa91821561261557600092613299575b5015908180613291575b61328157612fa26136af565b604051907f1aff58eb0000000000000000000000000000000000000000000000000000000082526020826004818a5afa9182156126155760009261324d575b506001820180831161270757612ff691612c62565b1415809281613245575b5061323c575b81159081613233575b5061322b575b608061302082613b7d565b6024604051809681937f4fd8f05400000000000000000000000000000000000000000000000000000000835260048301525afa9283156126155760009361320a575b506040517f35ee5f87000000000000000000000000000000000000000000000000000000008152602060048201819052601160248301527f726f636b65744465706f736974506f6f6c0000000000000000000000000000006044830152816064817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115612615576000916131d8575b5063ffffffff6060850151169066038d7ea4c6800082029180830466038d7ea4c68000149015171561270757600491602091101595604051928380927f47fa434a0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916131b9575b50156131b0575b6001600160a01b039061318661379d565b90156131a7576fffffffffffffffffffffffffffffffff16925b5116929190565b60801c926131a0565b60009350613175565b6131d2915060203d60201161081b5761080d8183612507565b3861316e565b90506020813d602011613202575b816131f360209383612507565b810103126106465751386130fe565b3d91506131e6565b61322491935060803d608011611a8757611a788183612507565b9138613062565b506001613015565b9050153861300f565b60009150613006565b905038613000565b90916020823d602011613279575b8161326860209383612507565b810103126102c65750519038612fe1565b3d915061325b565b5050915050600090600090600090565b508015612f96565b90916020823d6020116132c5575b816132b460209383612507565b810103126102c65750519038612f8c565b3d91506132a7565b90506020813d6020116132f7575b816132e860209383612507565b81010312610646575138612f26565b3d91506132db565b600090600090600090565b90506020813d602011613334575b8161332560209383612507565b81010312610646575138612e88565b3d9150613318565b1561334357565b608460405162461bcd60e51b815260206004820152603060248201527f4465706f7369747320696e746f20526f636b657420506f6f6c2061726520637560448201527f7272656e746c792064697361626c6564000000000000000000000000000000006064820152fd5b602460206001600160a01b0360005460081c16604051928380927f21f8a7210000000000000000000000000000000000000000000000000000000082527f65dd923ddfc8d8ae6088f80077201d2403cbd565f0ba25e09841e2799ec90bb260048301525afa90811561261557600091613424575090565b90506020813d602011613450575b8161343f60209383612507565b810103126106465761284190612b19565b3d9150613432565b60206001600160a01b0360005460081c16916024604051809481937f21f8a72100000000000000000000000000000000000000000000000000000000835260048301525afa90811561261557600091613424575090565b6134ef9060405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b6001600160a01b038116156135015790565b606460405162461bcd60e51b815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152fd5b90602460206001600160a01b0361356360405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa90811561261557600091613606575b50806135df575b50816135d6575050565b612de49161496f565b91908183106135f35750612de4915061454b565b908261360091039261454b565b386135cc565b906020823d602011613630575b8161362060209383612507565b810103126102c6575051386135c5565b3d9150613613565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e63650000000000000060048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527fb869ecac5aab3eca31bf3f499f9eb526669f14aa1402bb5674c73cd5a5b2611f60048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce060048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527fe854d579bb35988f8f3715377be8a57a13d9f9db42d0eaf95a3a8f39a96bca4460048301525afa908115612615576000916125e6575090565b60206001600160a01b0360005460081c16916024604051809481937fbd02d0f500000000000000000000000000000000000000000000000000000000835260048301525afa908115612615576000916125e6575090565b6000916001600160a01b03835460081c1691823b1561135d5790604484928360405195869485937fadb353dc000000000000000000000000000000000000000000000000000000008552600485015260248401525af180156102bb576138cf575050565b816138d991612507565b50565b60206001600160a01b0360005460081c16916024604051809481937f7ae1cfca00000000000000000000000000000000000000000000000000000000835260048301525afa90811561261557600091613933575090565b612841915060203d60201161081b5761080d8183612507565b90612de4916040516139a2816101c56020820194856bffffffffffffffffffffffff196034927f6d656761706f6f6c2e6574682e6d6174636865642e6e6f64652e616d6f756e74835260601b1660208201520190565b51902061386b565b9081602091031261064657517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036106465790565b906000916001600160a01b036139fb604051611165604082612507565b1690604051613a74816101c56020820194856bffffffffffffffffffffffff196035927f6d656761706f6f6c2e6574682e70726f76696465642e6e6f64652e616d6f756e83527f7400000000000000000000000000000000000000000000000000000000000000602084015260601b1660218201520190565b519020916040517f6838444b000000000000000000000000000000000000000000000000000000008152836004820152602081602481865afa9081156107e857917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff613ae69281948891613b5e575b5016612736565b1691813b1561135d576040517f5ba5964900000000000000000000000000000000000000000000000000000000815260048101919091527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216602483015282908290604490829084905af180156102bb576138cf575050565b613b77915060203d6020116113895761137b8183612507565b38613adf565b613ba5577f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e90565b7f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b90565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927febb9d8c90000000000000000000000000000000000000000000000000000000084527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce0600485015260248401525af180156102bb576138cf575050565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927febb9d8c90000000000000000000000000000000000000000000000000000000084527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e636500000000000000600485015260248401525af180156102bb576138cf575050565b6000916001600160a01b03835460081c1691823b1561135d5790604484928360405195869485937febb9d8c9000000000000000000000000000000000000000000000000000000008552600485015260248401525af180156102bb576138cf575050565b612de46fffffffffffffffffffffffffffffffff613d5361379d565b167fffffffffffffffffffffffffffffffff000000000000000000000000000000004360801b161761502c565b612de4613d8b61379d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016436fffffffffffffffffffffffffffffffff161761502c565b63ffffffff8111613dda5763ffffffff1690565b608460405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201527f32206269747300000000000000000000000000000000000000000000000000006064820152fd5b91906000906001600160a01b03613e626040516103ec604082612507565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156108575790613eaa918591610909575061333c565b6001600160a01b03613ef2604051613ec3604082612507565b601581527f726f636b65744d656761706f6f6c466163746f7279000000000000000000000060208201526134af565b1694604051957f4e1ccaf10000000000000000000000000000000000000000000000000000000087526001600160a01b03821696876004820152602081602481855afa908115614362578691614343575b50156142ff576020602491604051928380927f74db6b880000000000000000000000000000000000000000000000000000000082528b60048301525afa9081156107e85785916142ba575b5060206001600160a01b03916004604051809481937f14a6bf0f000000000000000000000000000000000000000000000000000000008352165afa9081156107e8578591614288575b5061421e5760405161402d816101c56020820194856bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b5190208461403a82613814565b106141da5760049161404e86602093613cd3565b61408d60405161405f604082612507565b601181527f726f636b65744e6f64654d616e61676572000000000000000000000000000000848201526134af565b50604051928380927f0de705b50000000000000000000000000000000000000000000000000000000082525afa9081156108fe5783916141a8575b506001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690813b1561135d576040517f94bf804d000000000000000000000000000000000000000000000000000000008152670de0b6b3a764000091860291909104850360048201526001600160a01b0392909216602483015282908290604490829084905af180156102bb57917f77982616940619ddbda4afe3675280fff7c605d31503336add3633fbea69d8ba9391604093614198575b50508151908152426020820152a2565b816141a291612507565b38614188565b90506020813d6020116141d2575b816141c360209383612507565b81010312610d625751386140c8565b3d91506141b6565b606460405162461bcd60e51b815260206004820152601f60248201527f416d6f756e7420657863656564732063726564697420617661696c61626c65006044820152fd5b608460405162461bcd60e51b815260206004820152602860248201527f43616e6e6f7420776974686472617720637265646974207768696c652064656260448201527f74206578697374730000000000000000000000000000000000000000000000006064820152fd5b90506020813d6020116142b2575b816142a360209383612507565b81010312611a24575138613fd7565b3d9150614296565b90506020813d6020116142f7575b816142d560209383612507565b81010312611a245760206142f06001600160a01b0392612b19565b9150613f8e565b3d91506142c8565b606460405162461bcd60e51b815260206004820152601960248201527f4d656761706f6f6c206d757374206265206465706c6f796564000000000000006044820152fd5b61435c915060203d60201161081b5761080d8183612507565b38613f43565b6040513d88823e3d90fd5b6143756150b1565b3481116144a0575b6143878134612736565b9060009080614424575b5090806143a3575b5050612de461527e565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b15610d625782906004604051809481937f98ea5fca0000000000000000000000000000000000000000000000000000000083525af180156102bb57156143995761441a828092612507565b6102c65780614399565b6001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016803b15610d625782906004604051809481937f6c985a880000000000000000000000000000000000000000000000000000000083525af180156102bb5715614391578161449a91612507565b38614391565b503461437d565b604051906144b6606083612507565b602182527f6c000000000000000000000000000000000000000000000000000000000000006040837f726f636b657444414f50726f746f636f6c53657474696e67734d696e69706f6f60208201520152565b805182101561451c5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060046000926001600160a01b0361459960405161456a604082612507565b601381527f726f636b65744d696e69706f6f6c51756575650000000000000000000000000060208201526134af565b169060206001600160a01b036145b56145b06144a7565b6134af565b16604051948580927f3469f7b40000000000000000000000000000000000000000000000000000000082525afa9283156107e857859361493b575b50614602836145fd612548565b612c9b565b8015614933579160248284889586951161492b575b5060405197889384927f7e0e497b00000000000000000000000000000000000000000000000000000000845260048401525af1938415612298578194614858575b50835180614668575b5050509050565b8261467291612b96565b6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001690813b15610d625782916024839260405194859384927f3bed33ce00000000000000000000000000000000000000000000000000000000845260048401525af180156102bb578290614848575b8291505b8551821015614830576001600160a01b036147088388614508565b5116803b1561135d576040517fd0e30db0000000000000000000000000000000000000000000000000000000008152848160048189865af180156107e85790859161481b575b50506020600491604051928380927fd2ceebd10000000000000000000000000000000000000000000000000000000082525afa9081156108575784916147e7575b5061479c906001926126fa565b916001600160a01b036147af8289614508565b51167fa1811054b7d96716259cff0d366c2f6405951e0efe00c8db3e237cbf77fe7be960408051888152426020820152a201906146ed565b905060203d8111614814575b6147fd8183612507565b602082600092810103126102c6575051600161478f565b503d6147f3565b8161482591612507565b61135d57833861474e565b9250505061483f919250613c4e565b80388080614661565b61485191612507565b38816146e9565b9093503d8085833e61486a8183612507565b810190602081830312611a245780519067ffffffffffffffff821161135957019080601f83011215611a245781519167ffffffffffffffff83116148fe578260051b90604051936148be6020840186612507565b84526020808501928201019283116114c157602001905b8282106148e6575050509238614658565b602080916148f384612b19565b8152019101906148d5565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905038614617565b505050509050565b9092506020813d602011614967575b8161495760209383612507565b81010312611a24575191386145f0565b3d915061494a565b6001600160a01b03614988604051610faf604082612507565b166040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b6004820152602081602481855afa90811561261557600091614ffa575b506040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e6004820152602081602481865afa90811561261557600091614fc8575b50906001600160a01b036020614a666136af565b966004604051809481937f1aff58eb000000000000000000000000000000000000000000000000000000008352165afa90811561261557600091614f96575b509293916000918293614ab6612548565b928496859886946001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016905b858710614c62575b5050505050505050614b0290613c4e565b6001600160a01b0360005460081c1693843b15610646576000946044869260405197889384927fe2a4853a0000000000000000000000000000000000000000000000000000000084527fb869ecac5aab3eca31bf3f499f9eb526669f14aa1402bb5674c73cd5a5b2611f600485015260248401525af190811561261557612de494614b9292614c51575b50613bc9565b614b9a61379d565b9015614c38576fffffffffffffffffffffffffffffffff4316915b15614bfd57506fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000008143165b60801b1691161761502c565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff9160801c614bf1565b6fffffffffffffffffffffffffffffffff811691614bb5565b6000614c5c91612507565b38614b8c565b9091929394969b9897959981159c8d809e614f8e575b614f82576001860180871161270757614c9287918d612c62565b1415809e81614f7a575b50614f71575b8d1580614f69575b614f60575b614cb88e613b7d565b90604051987f4fd8f054000000000000000000000000000000000000000000000000000000008a528260048b015260808a6024818a5afa998a156126155760009a614f40575b5063ffffffff60608b0151169166038d7ea4c6800083029280840466038d7ea4c68000149015171561270757828110614f3357863b1561064657604051907f3bed33ce000000000000000000000000000000000000000000000000000000008252836004830152600082602481838c5af190811561261557614d87928592614f22575b50612736565b996001600160a01b0381511663ffffffff602083015116813b15610646578491602460009260405194859384927f7685e80b00000000000000000000000000000000000000000000000000000000845260048401525af1801561261557614f11575b506001600160a01b038151167f21d4fea1e00248ceff22105d25fec21f17b7134ab4881761ab27ac2d4249fdee60408051868152426020820152a2604051937fdc5be997000000000000000000000000000000000000000000000000000000008552600485015260808460248160008c5af193841561261557604066038d7ea4c680009263ffffffff92600197614ef5575b5001511602019a019a019c600014614ec457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01946001809a5b019596949392919096614ae9565b999a5094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01936001809b614eb6565b614f0c9060803d8111611a8757611a788183612507565b614e7b565b6000614f1c91612507565b38614de9565b6000614f2d91612507565b38614d81565b509a9b9e50505099614af1565b614f59919a5060803d8111611a8757611a788183612507565b9838614cfe565b60019d50614caf565b508615614caa565b60009d50614ca2565b905038614c9c565b50998698999c50614af1565b508615614c78565b906020823d602011614fc0575b81614fb060209383612507565b810103126102c657505138614aa5565b3d9150614fa3565b90506020813d602011614ff2575b81614fe360209383612507565b81010312610646575138614a52565b3d9150614fd6565b90506020813d602011615024575b8161501560209383612507565b810103126106465751386149ed565b3d9150615008565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927fe2a4853a0000000000000000000000000000000000000000000000000000000084527fe854d579bb35988f8f3715377be8a57a13d9f9db42d0eaf95a3a8f39a96bca44600485015260248401525af180156102bb576138cf575050565b6001600160a01b036150f96040516150ca604082612507565b602081527f726f636b657444414f50726f746f636f6c53657474696e67734e6574776f726b60208201526134af565b16600460206001600160a01b03615145604051615117604082612507565b601581527f726f636b65744e6574776f726b42616c616e6365730000000000000000000000848201526134af565b1692604051928380927fe28767130000000000000000000000000000000000000000000000000000000082525afa9081156126155760009161524c575b50600460206001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163193604051928380927f964d042c0000000000000000000000000000000000000000000000000000000082525afa90811561261557600091615212575b50670de0b6b3a76400009161520291612b96565b0490808211612c25575050600090565b90506020813d602011615244575b8161522d60209383612507565b810103126106465751670de0b6b3a76400006151ee565b3d9150615220565b90506020813d602011615276575b8161526760209383612507565b81010312610646575138615182565b3d915061525a565b6001600160a01b036152976040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156126155760009161567f575b50156138d957602460206001600160a01b036152f960405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa9081156126155760009161564d575b50156155375761537260405161456a604082612507565b506001600160a01b036153866145b06144a7565b16604051907f3b474a65000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561261557600092615502575b506020600491604051928380927f3469f7b40000000000000000000000000000000000000000000000000000000082525afa8015612615576000906154cf575b6004915060206154226154198334612c9b565b926145fd612548565b94604051938480927ff19b41060000000000000000000000000000000000000000000000000000000082525afa80156126155760009061549b575b61546792506126fa565b91808311615493575b5080821161548b575b50806154825750565b612de49061454b565b905038615479565b915038615470565b506020823d6020116154c7575b816154b560209383612507565b8101031261064657615467915161545d565b3d91506154a8565b6020823d6020116154fa575b816154e860209383612507565b810103126102c6575060049051615406565b3d91506154db565b90916020823d60201161552f575b8161551d60209383612507565b810103126102c65750519060206153c6565b3d9150615510565b604051907f3b474a65000000000000000000000000000000000000000000000000000000008252602082600481845afa91821561261557600092615619575b506040517ff19b4106000000000000000000000000000000000000000000000000000000008152602081600481855afa8015612615576000906155e5575b6155cb91506801bc16d674ec8000003404906126fa565b918083116155dd5750816135d6575050565b9150386135cc565b506020813d602011615611575b816155ff60209383612507565b81010312610646576155cb90516155b4565b3d91506155f2565b90916020823d602011615645575b8161563460209383612507565b810103126102c65750519038615576565b3d9150615627565b90506020813d602011615677575b8161566860209383612507565b8101031261064657513861535b565b3d915061565b565b615698915060203d60201161081b5761080d8183612507565b386152d656fea26469706673582212208dd5003687e3781407bc3a73ee56aad724c9a77056eaf616c7b60f77ef68cc5364736f6c634300081e00330000000000000000000000001d8f8f00cfa6758d7be78336684788fb0ee0fa46

Deployed Bytecode

0x6080604052600436101561001257600080fd5b6000803560e01c806312065fe0146124785780631666f5e21461237c5780631b7dd4c0146122db5780631e35fed8146122c05780631eddb626146122a557806322b1751d146120d4578063258260951461205d57806327afc6f5146120425780633350677b1461202757806342e6dfa214611ff657806354fd4d5014611fd657806360be2e1c14611ef057806363a5db9e14611cf157806372f5158d14611ba8578063791d25b114611b8d5780637aab9e1614611af25780637d9d607414611612578063888b042f146115f75780639a8dd16f14610d915780639e2c0c1914610d6e578063a559a64514610bc6578063a673c8e114610b96578063a9a9482214610a73578063b7013dc114610a02578063c095415d14610961578063c6f20e6d14610928578063d0e30db0146103b4578063db82047b146102c95763ef6f886a1461015c57600080fd5b346102c65760206003193601126102c6576101fe6101f960405160208101906101f1816101c533856bffffffffffffffffffffffff19601f927f6e6f64652e657869737473000000000000000000000000000000000000000000835260601b16600b8201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101835282612507565b5190206138dc565b612d27565b6102196001600160a01b036102116133ad565b163014612621565b602460206001600160a01b03835460081c16604051928380927f5b49ff620000000000000000000000000000000000000000000000000000000082523360048301525afa80156102bb57829061027c575b61027991506004359033613e44565b80f35b506020813d6020116102b3575b8161029660209383612507565b810103126102af576102aa61027991612b19565b61026a565b5080fd5b3d9150610289565b6040513d84823e3d90fd5b80fd5b50806003193601126102c6576102e86001600160a01b036102116133ad565b61037a6001600160a01b03610372604051610304604082612507565b600f81527f726f636b6574546f6b656e524554480000000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b519020613458565b163314612621565b6040513481524260208201527f3a6614e80d02b57255cbb1f8305fbeca53d7e05a4b779d40627919660851292560403392a261027961436d565b50806003193601126102c6576103d36001600160a01b036102116133ad565b6001600160a01b0361041b6040516103ec604082612507565b602081527f726f636b657444414f50726f746f636f6c53657474696e67734465706f73697460208201526134af565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa80156108fe57610462918491610909575b5061333c565b6040517f035cf142000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156108fe5783916108cc575b503410610862578190346104b1612548565b016040517ffd6ce89e000000000000000000000000000000000000000000000000000000008152602081600481865afa908115610857578491610822575b50808211610653575b50506020600491604051928380927f0de705b50000000000000000000000000000000000000000000000000000000082525afa9081156102bb578291610619575b506001600160a01b037f000000000000000000000000ae78736cd615f374d3085123a210448e74fc639316803b15610615576040517f94bf804d000000000000000000000000000000000000000000000000000000008152670de0b6b3a76400003493840204909203600483015233602483015282908290604490829084905af180156102bb57610600575b506040513481524260208201527f7aa1a8eb998c779420645fc14513bf058edb347d95c2fc2e6845bdc22f88863160403392a261027961436d565b8161060a91612507565b6102c65780386105c5565b5050fd5b9150506020813d60201161064b575b8161063560209383612507565b810103126106465781905138610539565b600080fd5b3d9150610628565b909192506040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481875afa9081156107e85785916107f3575b50156107475760049060206001600160a01b036106e66040516106b8604082612507565b601381527f726f636b65744d696e69706f6f6c517565756500000000000000000000000000848201526134af565b16604051938480927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa9182156107e85785926107b2575b5061073161073792610731613726565b906126fa565b10610747578190602060046104f8565b60405162461bcd60e51b815260206004820152603f60248201527f546865206465706f73697420706f6f6c2073697a65206166746572206465706f60448201527f736974696e67206578636565647320746865206d6178696d756d2073697a65006064820152608490fd5b91506020823d6020116107e0575b816107cd60209383612507565b8101031261064657905190610731610721565b3d91506107c0565b6040513d87823e3d90fd5b610815915060203d60201161081b575b61080d8183612507565b8101906126b7565b38610694565b503d610803565b9350506020833d60201161084f575b8161083e60209383612507565b8101031261064657839251386104ef565b3d9150610831565b6040513d86823e3d90fd5b608460405162461bcd60e51b815260206004820152603a60248201527f546865206465706f736974656420616d6f756e74206973206c6573732074686160448201527f6e20746865206d696e696d756d206465706f7369742073697a650000000000006064820152fd5b90506020813d6020116108f6575b816108e760209383612507565b8101031261064657513861049f565b3d91506108da565b6040513d85823e3d90fd5b610922915060203d60201161081b5761080d8183612507565b3861045c565b50346102c657806003193601126102c6576060610943612e09565b906001600160a01b0360405193168352151560208301526040820152f35b50806003193601126102c6576109806001600160a01b036102116133ad565b6102796001600160a01b0361037260405161099c604082612507565b600b81527f726f636b65745661756c74000000000000000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b50346102c657806003193601126102c657610a1b612548565b90610a24613638565b91818382039312818412811691841390151617610a4657602082604051908152f35b807f4e487b7100000000000000000000000000000000000000000000000000000000602492526011600452fd5b50346102c65760606003193601126102c657610279610a90612493565b610aed610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b612ace565b610b006001600160a01b036102116133ad565b610b0c602435826139de565b60405190610b8a82610b5e6020820193846bffffffffffffffffffffffff196034927f6d656761706f6f6c2e6574682e6d6174636865642e6e6f64652e616d6f756e74835260601b1660208201520190565b037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08101845283612507565b60443591519020613cd3565b50346102c65760206003193601126102c657610bbb6001600160a01b036102116133ad565b610279600435612d72565b50346102c65760406003193601126102c6576024610be2612493565b610c3a6101f960405160208101906101f1816101c587856bffffffffffffffffffffffff19601f927f6e6f64652e657869737473000000000000000000000000000000000000000000835260601b16600b8201520190565b610c4d6001600160a01b036102116133ad565b60206001600160a01b03845460081c16604051938480927f5b49ff620000000000000000000000000000000000000000000000000000000082526001600160a01b03861660048301525afa9182156108fe578392610d2e575b506001600160a01b0382163303610cc4576102799160243591613e44565b608460405162461bcd60e51b815260206004820152602660248201527f4d7573742062652063616c6c65642066726f6d207769746864726177616c206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152fd5b9091506020813d602011610d66575b81610d4a60209383612507565b81010312610d6257610d5b90612b19565b9038610ca6565b8280fd5b3d9150610d3d565b50346102c657806003193601126102c6576020610d89612ca5565b604051908152f35b50346102c65760806003193601126102c657600435610dae6124a9565b90604435606435918215159283810361135957610e19610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b610e2c6001600160a01b036102116133ad565b66038d7ea4c6800082066115b35766038d7ea4c68000830661156f57604051907f70dabc9e0000000000000000000000000000000000000000000000000000000082526020826004818a335af19182156113d0578792611533575b50866001600160a01b03610ed1604051610ea2604082612507565b601181527f726f636b65744e6f64654d616e6167657200000000000000000000000000000060208201526134af565b1682156114c557803b156102af578180916024604051809481937fc220f0920000000000000000000000000000000000000000000000000000000083526001600160a01b038a1660048401525af180156102bb576114ac575b50505b610f3681613b7d565b9087610f4a66038d7ea4c680008604613dc6565b92610f5d66038d7ea4c680008804613dc6565b60405190610f6a826124bc565b33825263ffffffff602083019b169a8b815263ffffffff604084019716875263ffffffff60608401921682526001600160a01b03610fde604051610faf604082612507565b601181527f6c696e6b65644c69737453746f7261676500000000000000000000000000000060208201526134af565b1696873b156113595763ffffffff8094926001600160a01b038294604051987fea58ecf5000000000000000000000000000000000000000000000000000000008a5260048a015251166024880152511660448601525116606484015251166084820152818160a48183885af180156102bb57611497575b506001600160a01b03815460081c16803b156102af578180916044604051809481937fadb353dc0000000000000000000000000000000000000000000000000000000083527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce060048401528c60248401525af180156102bb5761147e575b50506024916020916000146113db57604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b60048301525afa80156113d057879061139d575b6001915014611390575b856001600160a01b03611194604051611165604082612507565b601681527f726f636b65744e6574776f726b536e617073686f74730000000000000000000060208201526134af565b16604051602081019061120d816101c587856bffffffffffffffffffffffff196035927f6d656761706f6f6c2e6574682e70726f76696465642e6e6f64652e616d6f756e83527f7400000000000000000000000000000000000000000000000000000000000000602084015260601b1660218201520190565b5190206040517f6838444b000000000000000000000000000000000000000000000000000000008152816004820152602081602481865afa90811561085757867bffffffffffffffffffffffffffffffffffffffffffffffffffffffff809361127e938891611361575b50166126fa565b16823b1561135d576040517f5ba5964900000000000000000000000000000000000000000000000000000000815260048101929092527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff1660248201529082908290604490829084905af180156102bb57611344575b50506112ff6113059284612736565b9061394c565b604051928352602083015260408201524260608201527f4040156d881bd2ba289490b90281b228e6c221621274ce90999669f12d74ddfb60803392a280f35b8161134e91612507565b6113595785386112f0565b8580fd5b8380fd5b611383915060203d602011611389575b61137b8183612507565b8101906139aa565b38611277565b503d611371565b611398613d80565b61114b565b506020813d6020116113c8575b816113b760209383612507565b810103126106465760019051611141565b3d91506113aa565b6040513d89823e3d90fd5b604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e60048301525afa80156113d057879061144b575b600191500361114b57611398613d37565b506020813d602011611476575b8161146560209383612507565b81010312610646576001905161143a565b3d9150611458565b8161148891612507565b6114935787386110d3565b8780fd5b816114a191612507565b611493578738611055565b816114b691612507565b6114c1578638610f2a565b8680fd5b803b156102af578180916024604051809481937f4395fb740000000000000000000000000000000000000000000000000000000083526001600160a01b038a1660048401525af180156102bb5761151e575b5050610f2d565b8161152891612507565b6114c1578638611517565b9091506020813d602011611567575b8161154f60209383612507565b810103126114c15761156090612b19565b9038610e87565b3d9150611542565b606460405162461bcd60e51b815260206004820152601860248201527f496e76616c69642072657175657374656420616d6f756e7400000000000000006044820152fd5b606460405162461bcd60e51b815260206004820152601760248201527f496e76616c696420737570706c69656420616d6f756e740000000000000000006044820152fd5b50346102c657806003193601126102c6576020610d89612ba9565b50346102c65760606003193601126102c65761162c612493565b6116346124a9565b60443590811515820361135d57611699610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b6116ac6001600160a01b036102116133ad565b6001600160a01b036116c5604051610faf604082612507565b1691604051916040830183811067ffffffffffffffff821117611ac55760405233835263ffffffff166020830152846116fd82613b7d565b6040517fed8ef8fb0000000000000000000000000000000000000000000000000000000081526004810182905284516001600160a01b0316602482015260208086015163ffffffff1660448301529095919086606481855afa9586156108fe578396611a8e575b50604051957ff3358a3a000000000000000000000000000000000000000000000000000000008752816004880152806024880152608087604481865afa968715610857578497611a5d575b506040517f45134808000000000000000000000000000000000000000000000000000000008152826004820152602081602481875afa9081156107e8578591611a28575b501494823b1561135d576040517f41b93d1b000000000000000000000000000000000000000000000000000000008152600481019290925280516001600160a01b031660248301526020015163ffffffff1660448201529082908290606490829084905af180156102bb57611a0f575b505063ffffffff60608401511666038d7ea4c6800081029080820466038d7ea4c6800014901517156119e25761189890613bc9565b156119cc57836001600160a01b036118b7604051610ea2604082612507565b16803b156102af578180916024604051809481937fa90e35a60000000000000000000000000000000000000000000000000000000083526001600160a01b038b1660048401525af180156102bb576119b7575b505063ffffffff916040916119aa575b01511666038d7ea4c6800081029080820466038d7ea4c68000149015171561197d5761194590613c4e565b7f795bf47f48111f2d01d87912d6b77fa833a62f0c4e2221ae9ecd474ec50d8b3360206001600160a01b03604051934285521692a280f35b6024837f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b6119b2613d80565b61191a565b816119c191612507565b61135d57833861190a565b63ffffffff916040911561191a576119b2613d37565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526011600452fd5b81611a1991612507565b611a24578438611863565b8480fd5b9450506020843d602011611a55575b81611a4460209383612507565b8101031261064657889351386117f3565b3d9150611a37565b611a8091975060803d608011611a87575b611a788183612507565b810190612b3e565b95386117af565b503d611a6e565b925094506020823d602011611abd575b81611aab60209383612507565b81010312610646578691519438611764565b3d9150611a9e565b6024877f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b50346102c65760406003193601126102c657610279611b0f612493565b60243590611b6b610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b611b7e6001600160a01b036102116133ad565b611b88828261394c565b6139de565b50346102c657806003193601126102c6576020610d896136af565b50806003193601126102c657611bc76001600160a01b036102116133ad565b6040517f6d656761706f6f6c2e6578697374730000000000000000000000000000000000602082019081523360601b6bffffffffffffffffffffffff1916602f830152611c1b916101f181604381016101c5565b8015611ca5575b15611c61576040513481524260208201527f3a6614e80d02b57255cbb1f8305fbeca53d7e05a4b779d40627919660851292560403392a261027961436d565b606460405162461bcd60e51b815260206004820152600e60248201527f496e76616c69642063616c6c65720000000000000000000000000000000000006044820152fd5b50611cec60405160208101907f6d696e69706f6f6c2e657869737473000000000000000000000000000000000082523360601b602f820152602381526101f1604382612507565b611c22565b50346102c65760206003193601126102c657600435611d196001600160a01b036102116133ad565b611d356001600160a01b03610372604051610304604082612507565b611d3d612ba9565b8111611e8657816001600160a01b037f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d616803b156102af578180916024604051809481937f3bed33ce0000000000000000000000000000000000000000000000000000000083528860048401525af180156102bb57611e71575b506001600160a01b037f000000000000000000000000ae78736cd615f374d3085123a210448e74fc639316803b156102af578183916004604051809481937f6c985a880000000000000000000000000000000000000000000000000000000083525af180156102bb57611e5c575b50506040519081524260208201527f992f462cfb62e164bd03bf07baf2cffce83fbd9370cae10635842b202001212060403392a280f35b81611e6691612507565b6102af578138611e25565b81611e7b91612507565b6102af578138611db7565b608460405162461bcd60e51b815260206004820152602a60248201527f496e73756666696369656e74206578636573732062616c616e636520666f722060448201527f7769746864726177616c000000000000000000000000000000000000000000006064820152fd5b50346102c65760406003193601126102c657610279611f0d612493565b611f65610ae860405160208101906101f1816101c533856bffffffffffffffffffffffff196023927f6d656761706f6f6c2e6578697374730000000000000000000000000000000000835260601b16600f8201520190565b611f786001600160a01b036102116133ad565b60405190611fca82610b5e6020820193846bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b6024359151902061386b565b50346102c657806003193601126102c65760ff6020915416604051908152f35b50346102c657806003193601126102c6576020610d8961201f61201761296e565b610731612a1e565b610731612ca5565b50346102c657806003193601126102c6576020610d89612a1e565b50346102c657806003193601126102c6576020610d8961296e565b50346102c65760206003193601126102c6576020610d8961207c612493565b6040516120cc816101c586820194856bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b519020613814565b5060206003193601126102c6576120f46001600160a01b036102116133ad565b6121766001600160a01b03610372604051612110604082612507565b601181527f726f636b65744e6f64654465706f736974000000000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b34612212575b806001600160a01b03815460081c16803b1561220f578180916044604051809481937fadb353dc0000000000000000000000000000000000000000000000000000000083527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e636500000000000000600484015260043560248401525af180156102bb576121fe5750f35b8161220891612507565b6102c65780f35b50fd5b6001600160a01b037f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d61681813b156102c65780600492604051938480927f98ea5fca00000000000000000000000000000000000000000000000000000000825234905af1801561229857612288575b505061217c565b61229191612507565b3881612281565b50604051903d90823e3d90fd5b50346102c657806003193601126102c6576020610d89612743565b50346102c657806003193601126102c6576020610d89613638565b50806003193601126102c6576122fa6001600160a01b036102116133ad565b61037a6001600160a01b03610372604051612316604082612507565b601481527f726f636b657441756374696f6e4d616e61676572000000000000000000000000602082015260405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b50346102c65760206003193601126102c6576004356123a46001600160a01b036102116133ad565b6123af81151561266c565b6001600160a01b036123c86040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa908115610857578491612459575b50156124155761027991613545565b606460405162461bcd60e51b815260206004820152602060248201527f4465706f7369742061737369676e6d656e7473206172652064697361626c65646044820152fd5b612472915060203d60201161081b5761080d8183612507565b38612406565b50346102c657806003193601126102c6576020610d89612548565b600435906001600160a01b038216820361064657565b6024359063ffffffff8216820361064657565b6080810190811067ffffffffffffffff8211176124d857604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff8211176124d857604052565b6040517f35ee5f87000000000000000000000000000000000000000000000000000000008152602060048201819052601160248301527f726f636b65744465706f736974506f6f6c0000000000000000000000000000006044830152816064817f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d66001600160a01b03165afa908115612615576000916125e6575090565b90506020813d60201161260d575b8161260160209383612507565b81010312610646575190565b3d91506125f4565b6040513d6000823e3d90fd5b1561262857565b606460405162461bcd60e51b815260206004820152601c60248201527f496e76616c6964206f72206f7574646174656420636f6e7472616374000000006044820152fd5b1561267357565b606460405162461bcd60e51b815260206004820152601660248201527f4d7573742061737369676e206174206c656173742031000000000000000000006044820152fd5b90816020910312610646575180151581036106465790565b9081519160005b8381106126e7575050016000815290565b80602080928401015181850152016126d6565b9190820180921161270757565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9190820391821161270757565b6001600160a01b0361275c6040516103ec604082612507565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156126155760009161294f575b5015612949576127a9612548565b6040517ffd6ce89e000000000000000000000000000000000000000000000000000000008152602081600481865afa90811561261557600091612917575b50600460208294604051928380927f47fa434a0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916128f8575b5061284b575b50818110156128445761284191612736565b90565b5050600090565b909150600460206001600160a01b0361286b6040516106b8604082612507565b16604051928380927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916128c4575b506128b5906128bd926126fa565b610731613726565b903861282f565b90506020813d6020116128f0575b816128df60209383612507565b8101031261064657516128bd6128a7565b3d91506128d2565b612911915060203d60201161081b5761080d8183612507565b38612829565b906020823d602011612941575b8161293160209383612507565b810103126102c6575051386127e7565b3d9150612924565b50600090565b612968915060203d60201161081b5761080d8183612507565b3861279b565b602460206001600160a01b036129b960405161298b604082612507565b601381527f61646472657373517565756553746f7261676500000000000000000000000000848201526134af565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa908115612615576000916125e6575090565b602460206001600160a01b03612a69604051612a3b604082612507565b601181527f6c696e6b65644c69737453746f72616765000000000000000000000000000000848201526134af565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b60048301525afa908115612615576000916125e6575090565b15612ad557565b606460405162461bcd60e51b815260206004820152601060248201527f496e76616c6964206d656761706f6f6c000000000000000000000000000000006044820152fd5b51906001600160a01b038216820361064657565b519063ffffffff8216820361064657565b9081608091031261064657612b8e606060405192612b5b846124bc565b612b6481612b19565b8452612b7260208201612b2d565b6020850152612b8360408201612b2d565b604085015201612b2d565b606082015290565b8181029291811591840414171561270757565b600460206001600160a01b03612bc66040516106b8604082612507565b16604051928380927fe60b40bf0000000000000000000000000000000000000000000000000000000082525afa801561261557600090612c2e575b612c0e9150610731613726565b612c16612548565b90818110612c25575050600090565b61284191612736565b506020813d602011612c5a575b81612c4860209383612507565b8101031261064657612c0e9051612c01565b3d9150612c3b565b8115612c6c570690565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b8115612c6c570490565b602460206001600160a01b03612cc2604051612a3b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e60048301525afa908115612615576000916125e6575090565b15612d2e57565b606460405162461bcd60e51b815260206004820152600c60248201527f496e76616c6964206e6f646500000000000000000000000000000000000000006044820152fd5b612d7d81151561266c565b6001600160a01b03612d966040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa90811561261557600091612dea575b5015612de657612de491613545565b565b5050565b612e03915060203d60201161081b5761080d8183612507565b38612dd5565b602460206001600160a01b03612e2660405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa9081156126155760009161330a575b506132ff576001600160a01b03612ea6604051610faf604082612507565b166001600160a01b03612ec06040516103ec604082612507565b16916040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b6004820152602081602481865afa908115612615576000916132cd575b50604051907ffd82e9dd0000000000000000000000000000000000000000000000000000000082527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e6004830152602082602481875afa91821561261557600092613299575b5015908180613291575b61328157612fa26136af565b604051907f1aff58eb0000000000000000000000000000000000000000000000000000000082526020826004818a5afa9182156126155760009261324d575b506001820180831161270757612ff691612c62565b1415809281613245575b5061323c575b81159081613233575b5061322b575b608061302082613b7d565b6024604051809681937f4fd8f05400000000000000000000000000000000000000000000000000000000835260048301525afa9283156126155760009361320a575b506040517f35ee5f87000000000000000000000000000000000000000000000000000000008152602060048201819052601160248301527f726f636b65744465706f736974506f6f6c0000000000000000000000000000006044830152816064817f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d66001600160a01b03165afa908115612615576000916131d8575b5063ffffffff6060850151169066038d7ea4c6800082029180830466038d7ea4c68000149015171561270757600491602091101595604051928380927f47fa434a0000000000000000000000000000000000000000000000000000000082525afa908115612615576000916131b9575b50156131b0575b6001600160a01b039061318661379d565b90156131a7576fffffffffffffffffffffffffffffffff16925b5116929190565b60801c926131a0565b60009350613175565b6131d2915060203d60201161081b5761080d8183612507565b3861316e565b90506020813d602011613202575b816131f360209383612507565b810103126106465751386130fe565b3d91506131e6565b61322491935060803d608011611a8757611a788183612507565b9138613062565b506001613015565b9050153861300f565b60009150613006565b905038613000565b90916020823d602011613279575b8161326860209383612507565b810103126102c65750519038612fe1565b3d915061325b565b5050915050600090600090600090565b508015612f96565b90916020823d6020116132c5575b816132b460209383612507565b810103126102c65750519038612f8c565b3d91506132a7565b90506020813d6020116132f7575b816132e860209383612507565b81010312610646575138612f26565b3d91506132db565b600090600090600090565b90506020813d602011613334575b8161332560209383612507565b81010312610646575138612e88565b3d9150613318565b1561334357565b608460405162461bcd60e51b815260206004820152603060248201527f4465706f7369747320696e746f20526f636b657420506f6f6c2061726520637560448201527f7272656e746c792064697361626c6564000000000000000000000000000000006064820152fd5b602460206001600160a01b0360005460081c16604051928380927f21f8a7210000000000000000000000000000000000000000000000000000000082527f65dd923ddfc8d8ae6088f80077201d2403cbd565f0ba25e09841e2799ec90bb260048301525afa90811561261557600091613424575090565b90506020813d602011613450575b8161343f60209383612507565b810103126106465761284190612b19565b3d9150613432565b60206001600160a01b0360005460081c16916024604051809481937f21f8a72100000000000000000000000000000000000000000000000000000000835260048301525afa90811561261557600091613424575090565b6134ef9060405161036a816101c560208201947f636f6e74726163742e6164647265737300000000000000000000000000000000865260308301906126cf565b6001600160a01b038116156135015790565b606460405162461bcd60e51b815260206004820152601260248201527f436f6e7472616374206e6f7420666f756e6400000000000000000000000000006044820152fd5b90602460206001600160a01b0361356360405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa90811561261557600091613606575b50806135df575b50816135d6575050565b612de49161496f565b91908183106135f35750612de4915061454b565b908261360091039261454b565b386135cc565b906020823d602011613630575b8161362060209383612507565b810103126102c6575051386135c5565b3d9150613613565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e63650000000000000060048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527fb869ecac5aab3eca31bf3f499f9eb526669f14aa1402bb5674c73cd5a5b2611f60048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce060048301525afa908115612615576000916125e6575090565b602460206001600160a01b0360005460081c16604051928380927fbd02d0f50000000000000000000000000000000000000000000000000000000082527fe854d579bb35988f8f3715377be8a57a13d9f9db42d0eaf95a3a8f39a96bca4460048301525afa908115612615576000916125e6575090565b60206001600160a01b0360005460081c16916024604051809481937fbd02d0f500000000000000000000000000000000000000000000000000000000835260048301525afa908115612615576000916125e6575090565b6000916001600160a01b03835460081c1691823b1561135d5790604484928360405195869485937fadb353dc000000000000000000000000000000000000000000000000000000008552600485015260248401525af180156102bb576138cf575050565b816138d991612507565b50565b60206001600160a01b0360005460081c16916024604051809481937f7ae1cfca00000000000000000000000000000000000000000000000000000000835260048301525afa90811561261557600091613933575090565b612841915060203d60201161081b5761080d8183612507565b90612de4916040516139a2816101c56020820194856bffffffffffffffffffffffff196034927f6d656761706f6f6c2e6574682e6d6174636865642e6e6f64652e616d6f756e74835260601b1660208201520190565b51902061386b565b9081602091031261064657517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff811681036106465790565b906000916001600160a01b036139fb604051611165604082612507565b1690604051613a74816101c56020820194856bffffffffffffffffffffffff196035927f6d656761706f6f6c2e6574682e70726f76696465642e6e6f64652e616d6f756e83527f7400000000000000000000000000000000000000000000000000000000000000602084015260601b1660218201520190565b519020916040517f6838444b000000000000000000000000000000000000000000000000000000008152836004820152602081602481865afa9081156107e857917bffffffffffffffffffffffffffffffffffffffffffffffffffffffff613ae69281948891613b5e575b5016612736565b1691813b1561135d576040517f5ba5964900000000000000000000000000000000000000000000000000000000815260048101919091527bffffffffffffffffffffffffffffffffffffffffffffffffffffffff92909216602483015282908290604490829084905af180156102bb576138cf575050565b613b77915060203d6020116113895761137b8183612507565b38613adf565b613ba5577f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e90565b7f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b90565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927febb9d8c90000000000000000000000000000000000000000000000000000000084527f43d6a8fcdd5ecf01f71d0e1d9b20163adaa8fbb9e896e8263c967735d0ae5ce0600485015260248401525af180156102bb576138cf575050565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927febb9d8c90000000000000000000000000000000000000000000000000000000084527f6465706f7369742e706f6f6c2e6e6f64652e62616c616e636500000000000000600485015260248401525af180156102bb576138cf575050565b6000916001600160a01b03835460081c1691823b1561135d5790604484928360405195869485937febb9d8c9000000000000000000000000000000000000000000000000000000008552600485015260248401525af180156102bb576138cf575050565b612de46fffffffffffffffffffffffffffffffff613d5361379d565b167fffffffffffffffffffffffffffffffff000000000000000000000000000000004360801b161761502c565b612de4613d8b61379d565b7fffffffffffffffffffffffffffffffff0000000000000000000000000000000016436fffffffffffffffffffffffffffffffff161761502c565b63ffffffff8111613dda5763ffffffff1690565b608460405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203360448201527f32206269747300000000000000000000000000000000000000000000000000006064820152fd5b91906000906001600160a01b03613e626040516103ec604082612507565b166040517f6ada7847000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156108575790613eaa918591610909575061333c565b6001600160a01b03613ef2604051613ec3604082612507565b601581527f726f636b65744d656761706f6f6c466163746f7279000000000000000000000060208201526134af565b1694604051957f4e1ccaf10000000000000000000000000000000000000000000000000000000087526001600160a01b03821696876004820152602081602481855afa908115614362578691614343575b50156142ff576020602491604051928380927f74db6b880000000000000000000000000000000000000000000000000000000082528b60048301525afa9081156107e85785916142ba575b5060206001600160a01b03916004604051809481937f14a6bf0f000000000000000000000000000000000000000000000000000000008352165afa9081156107e8578591614288575b5061421e5760405161402d816101c56020820194856bffffffffffffffffffffffff19602f927f6e6f64652e6465706f7369742e6372656469742e62616c616e63650000000000835260601b16601b8201520190565b5190208461403a82613814565b106141da5760049161404e86602093613cd3565b61408d60405161405f604082612507565b601181527f726f636b65744e6f64654d616e61676572000000000000000000000000000000848201526134af565b50604051928380927f0de705b50000000000000000000000000000000000000000000000000000000082525afa9081156108fe5783916141a8575b506001600160a01b037f000000000000000000000000ae78736cd615f374d3085123a210448e74fc63931690813b1561135d576040517f94bf804d000000000000000000000000000000000000000000000000000000008152670de0b6b3a764000091860291909104850360048201526001600160a01b0392909216602483015282908290604490829084905af180156102bb57917f77982616940619ddbda4afe3675280fff7c605d31503336add3633fbea69d8ba9391604093614198575b50508151908152426020820152a2565b816141a291612507565b38614188565b90506020813d6020116141d2575b816141c360209383612507565b81010312610d625751386140c8565b3d91506141b6565b606460405162461bcd60e51b815260206004820152601f60248201527f416d6f756e7420657863656564732063726564697420617661696c61626c65006044820152fd5b608460405162461bcd60e51b815260206004820152602860248201527f43616e6e6f7420776974686472617720637265646974207768696c652064656260448201527f74206578697374730000000000000000000000000000000000000000000000006064820152fd5b90506020813d6020116142b2575b816142a360209383612507565b81010312611a24575138613fd7565b3d9150614296565b90506020813d6020116142f7575b816142d560209383612507565b81010312611a245760206142f06001600160a01b0392612b19565b9150613f8e565b3d91506142c8565b606460405162461bcd60e51b815260206004820152601960248201527f4d656761706f6f6c206d757374206265206465706c6f796564000000000000006044820152fd5b61435c915060203d60201161081b5761080d8183612507565b38613f43565b6040513d88823e3d90fd5b6143756150b1565b3481116144a0575b6143878134612736565b9060009080614424575b5090806143a3575b5050612de461527e565b6001600160a01b037f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d616803b15610d625782906004604051809481937f98ea5fca0000000000000000000000000000000000000000000000000000000083525af180156102bb57156143995761441a828092612507565b6102c65780614399565b6001600160a01b037f000000000000000000000000ae78736cd615f374d3085123a210448e74fc639316803b15610d625782906004604051809481937f6c985a880000000000000000000000000000000000000000000000000000000083525af180156102bb5715614391578161449a91612507565b38614391565b503461437d565b604051906144b6606083612507565b602182527f6c000000000000000000000000000000000000000000000000000000000000006040837f726f636b657444414f50726f746f636f6c53657474696e67734d696e69706f6f60208201520152565b805182101561451c5760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b9060046000926001600160a01b0361459960405161456a604082612507565b601381527f726f636b65744d696e69706f6f6c51756575650000000000000000000000000060208201526134af565b169060206001600160a01b036145b56145b06144a7565b6134af565b16604051948580927f3469f7b40000000000000000000000000000000000000000000000000000000082525afa9283156107e857859361493b575b50614602836145fd612548565b612c9b565b8015614933579160248284889586951161492b575b5060405197889384927f7e0e497b00000000000000000000000000000000000000000000000000000000845260048401525af1938415612298578194614858575b50835180614668575b5050509050565b8261467291612b96565b6001600160a01b037f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d61690813b15610d625782916024839260405194859384927f3bed33ce00000000000000000000000000000000000000000000000000000000845260048401525af180156102bb578290614848575b8291505b8551821015614830576001600160a01b036147088388614508565b5116803b1561135d576040517fd0e30db0000000000000000000000000000000000000000000000000000000008152848160048189865af180156107e85790859161481b575b50506020600491604051928380927fd2ceebd10000000000000000000000000000000000000000000000000000000082525afa9081156108575784916147e7575b5061479c906001926126fa565b916001600160a01b036147af8289614508565b51167fa1811054b7d96716259cff0d366c2f6405951e0efe00c8db3e237cbf77fe7be960408051888152426020820152a201906146ed565b905060203d8111614814575b6147fd8183612507565b602082600092810103126102c6575051600161478f565b503d6147f3565b8161482591612507565b61135d57833861474e565b9250505061483f919250613c4e565b80388080614661565b61485191612507565b38816146e9565b9093503d8085833e61486a8183612507565b810190602081830312611a245780519067ffffffffffffffff821161135957019080601f83011215611a245781519167ffffffffffffffff83116148fe578260051b90604051936148be6020840186612507565b84526020808501928201019283116114c157602001905b8282106148e6575050509238614658565b602080916148f384612b19565b8152019101906148d5565b6024867f4e487b710000000000000000000000000000000000000000000000000000000081526041600452fd5b905038614617565b505050509050565b9092506020813d602011614967575b8161495760209383612507565b81010312611a24575191386145f0565b3d915061494a565b6001600160a01b03614988604051610faf604082612507565b166040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f5a55531ca116b9495f14b748a940f79340b078cefcdd2db09ea1ce8b68bad15b6004820152602081602481855afa90811561261557600091614ffa575b506040517ffd82e9dd0000000000000000000000000000000000000000000000000000000081527f3676a2bfaf1dbda572dffd9f1bf1596b6bda293af53a4f0eb0ecb236bf64075e6004820152602081602481865afa90811561261557600091614fc8575b50906001600160a01b036020614a666136af565b966004604051809481937f1aff58eb000000000000000000000000000000000000000000000000000000008352165afa90811561261557600091614f96575b509293916000918293614ab6612548565b928496859886946001600160a01b037f0000000000000000000000003bdc69c4e5e13e52a65f5583c23efb9636b469d616905b858710614c62575b5050505050505050614b0290613c4e565b6001600160a01b0360005460081c1693843b15610646576000946044869260405197889384927fe2a4853a0000000000000000000000000000000000000000000000000000000084527fb869ecac5aab3eca31bf3f499f9eb526669f14aa1402bb5674c73cd5a5b2611f600485015260248401525af190811561261557612de494614b9292614c51575b50613bc9565b614b9a61379d565b9015614c38576fffffffffffffffffffffffffffffffff4316915b15614bfd57506fffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffff000000000000000000000000000000008143165b60801b1691161761502c565b7fffffffffffffffffffffffffffffffff000000000000000000000000000000006fffffffffffffffffffffffffffffffff9160801c614bf1565b6fffffffffffffffffffffffffffffffff811691614bb5565b6000614c5c91612507565b38614b8c565b9091929394969b9897959981159c8d809e614f8e575b614f82576001860180871161270757614c9287918d612c62565b1415809e81614f7a575b50614f71575b8d1580614f69575b614f60575b614cb88e613b7d565b90604051987f4fd8f054000000000000000000000000000000000000000000000000000000008a528260048b015260808a6024818a5afa998a156126155760009a614f40575b5063ffffffff60608b0151169166038d7ea4c6800083029280840466038d7ea4c68000149015171561270757828110614f3357863b1561064657604051907f3bed33ce000000000000000000000000000000000000000000000000000000008252836004830152600082602481838c5af190811561261557614d87928592614f22575b50612736565b996001600160a01b0381511663ffffffff602083015116813b15610646578491602460009260405194859384927f7685e80b00000000000000000000000000000000000000000000000000000000845260048401525af1801561261557614f11575b506001600160a01b038151167f21d4fea1e00248ceff22105d25fec21f17b7134ab4881761ab27ac2d4249fdee60408051868152426020820152a2604051937fdc5be997000000000000000000000000000000000000000000000000000000008552600485015260808460248160008c5af193841561261557604066038d7ea4c680009263ffffffff92600197614ef5575b5001511602019a019a019c600014614ec457507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01946001809a5b019596949392919096614ae9565b999a5094937fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01936001809b614eb6565b614f0c9060803d8111611a8757611a788183612507565b614e7b565b6000614f1c91612507565b38614de9565b6000614f2d91612507565b38614d81565b509a9b9e50505099614af1565b614f59919a5060803d8111611a8757611a788183612507565b9838614cfe565b60019d50614caf565b508615614caa565b60009d50614ca2565b905038614c9c565b50998698999c50614af1565b508615614c78565b906020823d602011614fc0575b81614fb060209383612507565b810103126102c657505138614aa5565b3d9150614fa3565b90506020813d602011614ff2575b81614fe360209383612507565b81010312610646575138614a52565b3d9150614fd6565b90506020813d602011615024575b8161501560209383612507565b810103126106465751386149ed565b3d9150615008565b6000906001600160a01b03825460081c1690813b15610d625782916044839260405194859384927fe2a4853a0000000000000000000000000000000000000000000000000000000084527fe854d579bb35988f8f3715377be8a57a13d9f9db42d0eaf95a3a8f39a96bca44600485015260248401525af180156102bb576138cf575050565b6001600160a01b036150f96040516150ca604082612507565b602081527f726f636b657444414f50726f746f636f6c53657474696e67734e6574776f726b60208201526134af565b16600460206001600160a01b03615145604051615117604082612507565b601581527f726f636b65744e6574776f726b42616c616e6365730000000000000000000000848201526134af565b1692604051928380927fe28767130000000000000000000000000000000000000000000000000000000082525afa9081156126155760009161524c575b50600460206001600160a01b037f000000000000000000000000ae78736cd615f374d3085123a210448e74fc6393163193604051928380927f964d042c0000000000000000000000000000000000000000000000000000000082525afa90811561261557600091615212575b50670de0b6b3a76400009161520291612b96565b0490808211612c25575050600090565b90506020813d602011615244575b8161522d60209383612507565b810103126106465751670de0b6b3a76400006151ee565b3d9150615220565b90506020813d602011615276575b8161526760209383612507565b81010312610646575138615182565b3d915061525a565b6001600160a01b036152976040516103ec604082612507565b166040517f47fa434a000000000000000000000000000000000000000000000000000000008152602081600481855afa9081156126155760009161567f575b50156138d957602460206001600160a01b036152f960405161298b604082612507565b16604051928380927ffd82e9dd0000000000000000000000000000000000000000000000000000000082527fa7c30d79bac38383b63cf527b2a68c8a7efff3ba22dfd5b81d98030643ef0fca60048301525afa9081156126155760009161564d575b50156155375761537260405161456a604082612507565b506001600160a01b036153866145b06144a7565b16604051907f3b474a65000000000000000000000000000000000000000000000000000000008252602082600481865afa91821561261557600092615502575b506020600491604051928380927f3469f7b40000000000000000000000000000000000000000000000000000000082525afa8015612615576000906154cf575b6004915060206154226154198334612c9b565b926145fd612548565b94604051938480927ff19b41060000000000000000000000000000000000000000000000000000000082525afa80156126155760009061549b575b61546792506126fa565b91808311615493575b5080821161548b575b50806154825750565b612de49061454b565b905038615479565b915038615470565b506020823d6020116154c7575b816154b560209383612507565b8101031261064657615467915161545d565b3d91506154a8565b6020823d6020116154fa575b816154e860209383612507565b810103126102c6575060049051615406565b3d91506154db565b90916020823d60201161552f575b8161551d60209383612507565b810103126102c65750519060206153c6565b3d9150615510565b604051907f3b474a65000000000000000000000000000000000000000000000000000000008252602082600481845afa91821561261557600092615619575b506040517ff19b4106000000000000000000000000000000000000000000000000000000008152602081600481855afa8015612615576000906155e5575b6155cb91506801bc16d674ec8000003404906126fa565b918083116155dd5750816135d6575050565b9150386135cc565b506020813d602011615611575b816155ff60209383612507565b81010312610646576155cb90516155b4565b3d91506155f2565b90916020823d602011615645575b8161563460209383612507565b810103126102c65750519038615576565b3d9150615627565b90506020813d602011615677575b8161566860209383612507565b8101031261064657513861535b565b3d915061565b565b615698915060203d60201161081b5761080d8183612507565b386152d656fea26469706673582212208dd5003687e3781407bc3a73ee56aad724c9a77056eaf616c7b60f77ef68cc5364736f6c634300081e0033

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

0000000000000000000000001d8f8f00cfa6758d7be78336684788fb0ee0fa46

-----Decoded View---------------
Arg [0] : _rocketStorageAddress (address): 0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001d8f8f00cfa6758d7be78336684788fb0ee0fa46


Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ 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.