ETH Price: $1,894.89 (-1.78%)

Transaction Decoder

Block:
20555441 at Aug-18-2024 12:14:11 PM +UTC
Transaction Fee:
0.00013795962476803 ETH $0.26
Gas Used:
128,983 Gas / 1.06959541 Gwei

Emitted Events:

249 RocketTokenRETH.Transfer( from=[Sender] 0xbefe358352b3ebf69c536a85247cdf2dc15e3e32, to=0x0000000000000000000000000000000000000000, value=990501009748174934 )
250 RocketTokenRETH.TokensBurned( from=[Sender] 0xbefe358352b3ebf69c536a85247cdf2dc15e3e32, amount=990501009748174934, ethAmount=1103452268652479616, time=1723983251 )

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
7.356653499710712847 Eth7.356659948860712847 Eth0.00000644915
0xae78736C...E74Fc6393 3,020.825743382276983064 Eth3,019.722291113624503448 Eth1.103452268652479616
0xBEfe3583...dC15e3e32
0.001564921845720241 Eth
Nonce: 113
1.104879230873431827 Eth
Nonce: 114
1.103314309027711586

Execution Trace

RocketTokenRETH.burn( _rethAmount=990501009748174934 )
  • RocketStorage.getAddress( _key=7630E125F1C009E5FC974F6DAE77C6D5B1802979B36E6D7145463C21782AF01E ) => ( r=0x6Cc65bF618F55ce2433f9D8d827Fc44117D81399 )
  • RocketNetworkBalances.STATICCALL( )
    • RocketStorage.getUint( _key=9DC185B46ED0F11D151F055E45FDE635375A9680C34E501B43A82EB6C09C0951 ) => ( r=552440919191412111356711 )
    • RocketNetworkBalances.STATICCALL( )
      • RocketStorage.getUint( _key=5B3A7B8BDDE2122FAD4DC45E51AE0C5CEDC887473A999474F2EAD5A8FAADFE3C ) => ( r=495892123139615592696761 )
      • RocketStorage.getAddress( _key=65DD923DDFC8D8AE6088F80077201D2403CBD565F0BA25E09841E2799EC90BB2 ) => ( r=0xDD3f50F8A6CafbE9b31a427582963f465E745AF8 )
      • RocketDepositPool.STATICCALL( )
        • RocketStorage.getAddress( _key=7F602045A039DA8AC7709E3205CD54DB6D7D9A1113DFF494A3B44D1CABA908CA ) => ( r=0x9e966733e3E9BFA56aF95f762921859417cF6FaA )
        • RocketMinipoolQueue.STATICCALL( )
          • RocketStorage.getAddress( _key=CABD9A4F404C4FFB362A3C40647A1A12F3BDAA2AD3BBCDB92EA716C2EA3FF22B ) => ( r=0xA416A7a07925d60F794E20532bc730749611A220 )
          • RocketStorage.getAddress( _key=CABD9A4F404C4FFB362A3C40647A1A12F3BDAA2AD3BBCDB92EA716C2EA3FF22B ) => ( r=0xA416A7a07925d60F794E20532bc730749611A220 )
          • RocketDAOProtocolSettingsMinipool.STATICCALL( )
          • RocketStorage.getAddress( _key=2ADDCCD64DD43C4EF1213C10626C6170F7F9BB5F4A96DFBBABDDCBED2B170FC4 ) => ( r=0x44E31944E1A6F3b8F805E105B130F8bdb7E2EBd8 )
          • AddressQueueStorage.getLength( _key=A7C30D79BAC38383B63CF527B2A68C8A7EFFF3BA22DFD5B81D98030643EF0FCA ) => ( 0 )
            • RocketStorage.getUint( _key=8865F902AF621B4F2CF327D5B224395315261CF0162DFF451FFAF06FA690A709 ) => ( r=22078 )
            • RocketStorage.getUint( _key=209FE6DEF179A25C51657DA761F6D397B1299F7424F3BB336ED82F6DC3AA0EEA ) => ( r=22078 )
            • RocketDAOProtocolSettingsMinipool.STATICCALL( )
            • RocketStorage.getAddress( _key=2ADDCCD64DD43C4EF1213C10626C6170F7F9BB5F4A96DFBBABDDCBED2B170FC4 ) => ( r=0x44E31944E1A6F3b8F805E105B130F8bdb7E2EBd8 )
            • AddressQueueStorage.getLength( _key=6EEA9E53DC9C4FB5C4B0BA0E9DB7370A823B1513965347E82945EB8966218188 ) => ( 0 )
              • RocketStorage.getUint( _key=95241176D02B112B4675AB170EC86B6AFAA12950DD1E0EF2FEC43D18C303E299 ) => ( r=13619 )
              • RocketStorage.getUint( _key=F1F06692C94A9F7B9AC29EF95E4AD442A08CD918141BBDB78EA58B554199BADD ) => ( r=13619 )
              • RocketDAOProtocolSettingsMinipool.STATICCALL( )
              • RocketStorage.getAddress( _key=2ADDCCD64DD43C4EF1213C10626C6170F7F9BB5F4A96DFBBABDDCBED2B170FC4 ) => ( r=0x44E31944E1A6F3b8F805E105B130F8bdb7E2EBd8 )
              • AddressQueueStorage.getLength( _key=885ADB3A1C7CF88A1F3627E1265F3090CD728E0FC96765288E91E8777267FF78 ) => ( 0 )
                • RocketStorage.getUint( _key=D8B6A4977457C014E88D4551BB15C633AC48CF3A509B7AD618D7F9C87179B9E2 ) => ( r=447 )
                • RocketStorage.getUint( _key=9C44AF08C16FB81C92299114DC1604F94FF10E4151B35DEE89C1E453B52DDC8F ) => ( r=447 )
                • RocketVault.balanceOf( _networkContractName=rocketDepositPool ) => ( 20696775497282262808204 )
                • RocketStorage.getUint( _key=4A5FE49BFE34A32195CEC7853E9B1BB3540B1239A0ED712D29744158F31BD34C ) => ( r=0 )
                • ETH 1.103452268652479616 0xbefe358352b3ebf69c536a85247cdf2dc15e3e32.CALL( )
                  File 1 of 8: RocketTokenRETH
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../../utils/Context.sol";
                  import "./IERC20.sol";
                  import "../../math/SafeMath.sol";
                  /**
                   * @dev Implementation of the {IERC20} interface.
                   *
                   * This implementation is agnostic to the way tokens are created. This means
                   * that a supply mechanism has to be added in a derived contract using {_mint}.
                   * For a generic mechanism see {ERC20PresetMinterPauser}.
                   *
                   * TIP: For a detailed writeup see our guide
                   * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                   * to implement supply mechanisms].
                   *
                   * We have followed general OpenZeppelin guidelines: functions revert instead
                   * of returning `false` on failure. This behavior is nonetheless conventional
                   * and does not conflict with the expectations of ERC20 applications.
                   *
                   * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                   * This allows applications to reconstruct the allowance for all accounts just
                   * by listening to said events. Other implementations of the EIP may not emit
                   * these events, as it isn't required by the specification.
                   *
                   * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                   * functions have been added to mitigate the well-known issues around setting
                   * allowances. See {IERC20-approve}.
                   */
                  contract ERC20 is Context, IERC20 {
                      using SafeMath for uint256;
                      mapping (address => uint256) private _balances;
                      mapping (address => mapping (address => uint256)) private _allowances;
                      uint256 private _totalSupply;
                      string private _name;
                      string private _symbol;
                      uint8 private _decimals;
                      /**
                       * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                       * a default value of 18.
                       *
                       * To select a different value for {decimals}, use {_setupDecimals}.
                       *
                       * All three of these values are immutable: they can only be set once during
                       * construction.
                       */
                      constructor (string memory name_, string memory symbol_) public {
                          _name = name_;
                          _symbol = symbol_;
                          _decimals = 18;
                      }
                      /**
                       * @dev Returns the name of the token.
                       */
                      function name() public view virtual returns (string memory) {
                          return _name;
                      }
                      /**
                       * @dev Returns the symbol of the token, usually a shorter version of the
                       * name.
                       */
                      function symbol() public view virtual returns (string memory) {
                          return _symbol;
                      }
                      /**
                       * @dev Returns the number of decimals used to get its user representation.
                       * For example, if `decimals` equals `2`, a balance of `505` tokens should
                       * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                       *
                       * Tokens usually opt for a value of 18, imitating the relationship between
                       * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                       * called.
                       *
                       * NOTE: This information is only used for _display_ purposes: it in
                       * no way affects any of the arithmetic of the contract, including
                       * {IERC20-balanceOf} and {IERC20-transfer}.
                       */
                      function decimals() public view virtual returns (uint8) {
                          return _decimals;
                      }
                      /**
                       * @dev See {IERC20-totalSupply}.
                       */
                      function totalSupply() public view virtual override returns (uint256) {
                          return _totalSupply;
                      }
                      /**
                       * @dev See {IERC20-balanceOf}.
                       */
                      function balanceOf(address account) public view virtual override returns (uint256) {
                          return _balances[account];
                      }
                      /**
                       * @dev See {IERC20-transfer}.
                       *
                       * Requirements:
                       *
                       * - `recipient` cannot be the zero address.
                       * - the caller must have a balance of at least `amount`.
                       */
                      function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(_msgSender(), recipient, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-allowance}.
                       */
                      function allowance(address owner, address spender) public view virtual override returns (uint256) {
                          return _allowances[owner][spender];
                      }
                      /**
                       * @dev See {IERC20-approve}.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function approve(address spender, uint256 amount) public virtual override returns (bool) {
                          _approve(_msgSender(), spender, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-transferFrom}.
                       *
                       * Emits an {Approval} event indicating the updated allowance. This is not
                       * required by the EIP. See the note at the beginning of {ERC20}.
                       *
                       * Requirements:
                       *
                       * - `sender` and `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       * - the caller must have allowance for ``sender``'s tokens of at least
                       * `amount`.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(sender, recipient, amount);
                          _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                          return true;
                      }
                      /**
                       * @dev Atomically increases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                          return true;
                      }
                      /**
                       * @dev Atomically decreases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       * - `spender` must have allowance for the caller of at least
                       * `subtractedValue`.
                       */
                      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                          return true;
                      }
                      /**
                       * @dev Moves tokens `amount` from `sender` to `recipient`.
                       *
                       * This is internal function is equivalent to {transfer}, and can be used to
                       * e.g. implement automatic token fees, slashing mechanisms, etc.
                       *
                       * Emits a {Transfer} event.
                       *
                       * Requirements:
                       *
                       * - `sender` cannot be the zero address.
                       * - `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       */
                      function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                          require(sender != address(0), "ERC20: transfer from the zero address");
                          require(recipient != address(0), "ERC20: transfer to the zero address");
                          _beforeTokenTransfer(sender, recipient, amount);
                          _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                          _balances[recipient] = _balances[recipient].add(amount);
                          emit Transfer(sender, recipient, amount);
                      }
                      /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                       * the total supply.
                       *
                       * Emits a {Transfer} event with `from` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `to` cannot be the zero address.
                       */
                      function _mint(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: mint to the zero address");
                          _beforeTokenTransfer(address(0), account, amount);
                          _totalSupply = _totalSupply.add(amount);
                          _balances[account] = _balances[account].add(amount);
                          emit Transfer(address(0), account, amount);
                      }
                      /**
                       * @dev Destroys `amount` tokens from `account`, reducing the
                       * total supply.
                       *
                       * Emits a {Transfer} event with `to` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `account` cannot be the zero address.
                       * - `account` must have at least `amount` tokens.
                       */
                      function _burn(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: burn from the zero address");
                          _beforeTokenTransfer(account, address(0), amount);
                          _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                          _totalSupply = _totalSupply.sub(amount);
                          emit Transfer(account, address(0), amount);
                      }
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                       *
                       * This internal function is equivalent to `approve`, and can be used to
                       * e.g. set automatic allowances for certain subsystems, etc.
                       *
                       * Emits an {Approval} event.
                       *
                       * Requirements:
                       *
                       * - `owner` cannot be the zero address.
                       * - `spender` cannot be the zero address.
                       */
                      function _approve(address owner, address spender, uint256 amount) internal virtual {
                          require(owner != address(0), "ERC20: approve from the zero address");
                          require(spender != address(0), "ERC20: approve to the zero address");
                          _allowances[owner][spender] = amount;
                          emit Approval(owner, spender, amount);
                      }
                      /**
                       * @dev Sets {decimals} to a value other than the default one of 18.
                       *
                       * WARNING: This function should only be called from the constructor. Most
                       * applications that interact with token contracts will not expect
                       * {decimals} to ever change, and may work incorrectly if it does.
                       */
                      function _setupDecimals(uint8 decimals_) internal virtual {
                          _decimals = decimals_;
                      }
                      /**
                       * @dev Hook that is called before any transfer of tokens. This includes
                       * minting and burning.
                       *
                       * Calling conditions:
                       *
                       * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                       * will be to transferred to `to`.
                       * - when `from` is zero, `amount` tokens will be minted for `to`.
                       * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                       * - `from` and `to` are never both zero.
                       *
                       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                       */
                      function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Interface of the ERC20 standard as defined in the EIP.
                   */
                  interface IERC20 {
                      /**
                       * @dev Returns the amount of tokens in existence.
                       */
                      function totalSupply() external view returns (uint256);
                      /**
                       * @dev Returns the amount of tokens owned by `account`.
                       */
                      function balanceOf(address account) external view returns (uint256);
                      /**
                       * @dev Moves `amount` tokens from the caller's account to `recipient`.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transfer(address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Returns the remaining number of tokens that `spender` will be
                       * allowed to spend on behalf of `owner` through {transferFrom}. This is
                       * zero by default.
                       *
                       * This value changes when {approve} or {transferFrom} are called.
                       */
                      function allowance(address owner, address spender) external view returns (uint256);
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * IMPORTANT: Beware that changing an allowance with this method brings the risk
                       * that someone may use both the old and the new allowance by unfortunate
                       * transaction ordering. One possible solution to mitigate this race
                       * condition is to first reduce the spender's allowance to 0 and set the
                       * desired value afterwards:
                       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                       *
                       * Emits an {Approval} event.
                       */
                      function approve(address spender, uint256 amount) external returns (bool);
                      /**
                       * @dev Moves `amount` tokens from `sender` to `recipient` using the
                       * allowance mechanism. `amount` is then deducted from the caller's
                       * allowance.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Emitted when `value` tokens are moved from one account (`from`) to
                       * another (`to`).
                       *
                       * Note that `value` may be zero.
                       */
                      event Transfer(address indexed from, address indexed to, uint256 value);
                      /**
                       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                       * a call to {approve}. `value` is the new allowance.
                       */
                      event Approval(address indexed owner, address indexed spender, uint256 value);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /*
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with GSN meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address payable) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes memory) {
                          this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                          return msg.data;
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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(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 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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
                  import "../RocketBase.sol";
                  import "../../interface/deposit/RocketDepositPoolInterface.sol";
                  import "../../interface/network/RocketNetworkBalancesInterface.sol";
                  import "../../interface/token/RocketTokenRETHInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNetworkInterface.sol";
                  // rETH is a tokenised stake in the Rocket Pool network
                  // rETH is backed by ETH (subject to liquidity) at a variable exchange rate
                  contract RocketTokenRETH is RocketBase, ERC20, RocketTokenRETHInterface {
                      // Libs
                      using SafeMath for uint;
                      // Events
                      event EtherDeposited(address indexed from, uint256 amount, uint256 time);
                      event TokensMinted(address indexed to, uint256 amount, uint256 ethAmount, uint256 time);
                      event TokensBurned(address indexed from, uint256 amount, uint256 ethAmount, uint256 time);
                      // Construct with our token details
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) ERC20("Rocket Pool ETH", "rETH") {
                          // Version
                          version = 1;
                      }
                      // Receive an ETH deposit from a minipool or generous individual
                      receive() external payable {
                          // Emit ether deposited event
                          emit EtherDeposited(msg.sender, msg.value, block.timestamp);
                      }
                      // Calculate the amount of ETH backing an amount of rETH
                      function getEthValue(uint256 _rethAmount) override public view returns (uint256) {
                          // Get network balances
                          RocketNetworkBalancesInterface rocketNetworkBalances = RocketNetworkBalancesInterface(getContractAddress("rocketNetworkBalances"));
                          uint256 totalEthBalance = rocketNetworkBalances.getTotalETHBalance();
                          uint256 rethSupply = rocketNetworkBalances.getTotalRETHSupply();
                          // Use 1:1 ratio if no rETH is minted
                          if (rethSupply == 0) { return _rethAmount; }
                          // Calculate and return
                          return _rethAmount.mul(totalEthBalance).div(rethSupply);
                      }
                      // Calculate the amount of rETH backed by an amount of ETH
                      function getRethValue(uint256 _ethAmount) override public view returns (uint256) {
                          // Get network balances
                          RocketNetworkBalancesInterface rocketNetworkBalances = RocketNetworkBalancesInterface(getContractAddress("rocketNetworkBalances"));
                          uint256 totalEthBalance = rocketNetworkBalances.getTotalETHBalance();
                          uint256 rethSupply = rocketNetworkBalances.getTotalRETHSupply();
                          // Use 1:1 ratio if no rETH is minted
                          if (rethSupply == 0) { return _ethAmount; }
                          // Check network ETH balance
                          require(totalEthBalance > 0, "Cannot calculate rETH token amount while total network balance is zero");
                          // Calculate and return
                          return _ethAmount.mul(rethSupply).div(totalEthBalance);
                      }
                      // Get the current ETH : rETH exchange rate
                      // Returns the amount of ETH backing 1 rETH
                      function getExchangeRate() override external view returns (uint256) {
                          return getEthValue(1 ether);
                      }
                      // Get the total amount of collateral available
                      // Includes rETH contract balance & excess deposit pool balance
                      function getTotalCollateral() override public view returns (uint256) {
                          RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
                          return rocketDepositPool.getExcessBalance().add(address(this).balance);
                      }
                      // Get the current ETH collateral rate
                      // Returns the portion of rETH backed by ETH in the contract as a fraction of 1 ether
                      function getCollateralRate() override public view returns (uint256) {
                          uint256 totalEthValue = getEthValue(totalSupply());
                          if (totalEthValue == 0) { return calcBase; }
                          return calcBase.mul(address(this).balance).div(totalEthValue);
                      }
                      // Deposit excess ETH from deposit pool
                      // Only accepts calls from the RocketDepositPool contract
                      function depositExcess() override external payable onlyLatestContract("rocketDepositPool", msg.sender) {
                          // Emit ether deposited event
                          emit EtherDeposited(msg.sender, msg.value, block.timestamp);
                      }
                      // Mint rETH
                      // Only accepts calls from the RocketDepositPool contract
                      function mint(uint256 _ethAmount, address _to) override external onlyLatestContract("rocketDepositPool", msg.sender) {
                          // Get rETH amount
                          uint256 rethAmount = getRethValue(_ethAmount);
                          // Check rETH amount
                          require(rethAmount > 0, "Invalid token mint amount");
                          // Update balance & supply
                          _mint(_to, rethAmount);
                          // Emit tokens minted event
                          emit TokensMinted(_to, rethAmount, _ethAmount, block.timestamp);
                      }
                      // Burn rETH for ETH
                      function burn(uint256 _rethAmount) override external {
                          // Check rETH amount
                          require(_rethAmount > 0, "Invalid token burn amount");
                          require(balanceOf(msg.sender) >= _rethAmount, "Insufficient rETH balance");
                          // Get ETH amount
                          uint256 ethAmount = getEthValue(_rethAmount);
                          // Get & check ETH balance
                          uint256 ethBalance = getTotalCollateral();
                          require(ethBalance >= ethAmount, "Insufficient ETH balance for exchange");
                          // Update balance & supply
                          _burn(msg.sender, _rethAmount);
                          // Withdraw ETH from deposit pool if required
                          withdrawDepositCollateral(ethAmount);
                          // Transfer ETH to sender
                          msg.sender.transfer(ethAmount);
                          // Emit tokens burned event
                          emit TokensBurned(msg.sender, _rethAmount, ethAmount, block.timestamp);
                      }
                      // Withdraw ETH from the deposit pool for collateral if required
                      function withdrawDepositCollateral(uint256 _ethRequired) private {
                          // Check rETH contract balance
                          uint256 ethBalance = address(this).balance;
                          if (ethBalance >= _ethRequired) { return; }
                          // Withdraw
                          RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
                          rocketDepositPool.withdrawExcessBalance(_ethRequired.sub(ethBalance));
                      }
                      // Sends any excess ETH from this contract to the deposit pool (as determined by target collateral rate)
                      function depositExcessCollateral() external override {
                          // Load contracts
                          RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork"));
                          RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
                          // Get collateral and target collateral rate
                          uint256 collateralRate = getCollateralRate();
                          uint256 targetCollateralRate = rocketDAOProtocolSettingsNetwork.getTargetRethCollateralRate();
                          // Check if we are in excess
                          if (collateralRate > targetCollateralRate) {
                              // Calculate our target collateral in ETH
                              uint256 targetCollateral = address(this).balance.mul(targetCollateralRate).div(collateralRate);
                              // If we have excess
                              if (address(this).balance > targetCollateral) {
                                  // Send that excess to deposit pool
                                  uint256 excessCollateral = address(this).balance.sub(targetCollateral);
                                  rocketDepositPool.recycleExcessCollateral{value: excessCollateral}();
                              }
                          }
                      }
                      // This is called by the base ERC20 contract before all transfer, mint, and burns
                      function _beforeTokenTransfer(address from, address, uint256) internal override {
                          // Don't run check if this is a mint transaction
                          if (from != address(0)) {
                              // Check which block the user's last deposit was
                              bytes32 key = keccak256(abi.encodePacked("user.deposit.block", from));
                              uint256 lastDepositBlock = getUint(key);
                              if (lastDepositBlock > 0) {
                                  // Ensure enough blocks have passed
                                  uint256 depositDelay = getUint(keccak256(abi.encodePacked(keccak256("dao.protocol.setting.network"), "network.reth.deposit.delay")));
                                  uint256 blocksPassed = block.number.sub(lastDepositBlock);
                                  require(blocksPassed > depositDelay, "Not enough time has passed since deposit");
                                  // Clear the state as it's no longer necessary to check this until another deposit is made
                                  deleteUint(key);
                              }
                          }
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  interface RocketDAOProtocolSettingsNetworkInterface {
                      function getNodeConsensusThreshold() 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);
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  interface RocketDepositPoolInterface {
                      function getBalance() external view returns (uint256);
                      function getExcessBalance() external view returns (uint256);
                      function deposit() external payable;
                      function recycleDissolvedDeposit() external payable;
                      function recycleExcessCollateral() external payable;
                      function recycleLiquidatedStake() external payable;
                      function assignDeposits() external;
                      function withdrawExcessBalance(uint256 _amount) external;
                      function getUserLastDepositBlock(address _address) 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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  interface RocketNetworkBalancesInterface {
                      function getBalancesBlock() external view returns (uint256);
                      function getLatestReportableBlock() 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 _total, uint256 _staking, uint256 _rethSupply) external;
                      function executeUpdateBalances(uint256 _block, 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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/token/ERC20/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;
                  }
                  

                  File 2 of 8: RocketStorage
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "../interface/RocketStorageInterface.sol";
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  /// @title The primary persistent storage for Rocket Pool
                  /// @author David Rugendyke
                  contract RocketStorage is RocketStorageInterface {
                      // Events
                      event NodeWithdrawalAddressSet(address indexed node, address indexed withdrawalAddress, uint256 time);
                      event GuardianChanged(address oldGuardian, address newGuardian);
                      // Libraries
                      using SafeMath for uint256;
                      // Storage maps
                      mapping(bytes32 => string)     private stringStorage;
                      mapping(bytes32 => bytes)      private bytesStorage;
                      mapping(bytes32 => uint256)    private uintStorage;
                      mapping(bytes32 => int256)     private intStorage;
                      mapping(bytes32 => address)    private addressStorage;
                      mapping(bytes32 => bool)       private booleanStorage;
                      mapping(bytes32 => bytes32)    private bytes32Storage;
                      // Protected storage (not accessible by network contracts)
                      mapping(address => address)    private withdrawalAddresses;
                      mapping(address => address)    private pendingWithdrawalAddresses;
                      // Guardian address
                      address guardian;
                      address newGuardian;
                      // Flag storage has been initialised
                      bool storageInit = false;
                      /// @dev Only allow access from the latest version of a contract in the Rocket Pool network after deployment
                      modifier onlyLatestRocketNetworkContract() {
                          if (storageInit == true) {
                              // Make sure the access is permitted to only contracts in our Dapp
                              require(booleanStorage[keccak256(abi.encodePacked("contract.exists", msg.sender))], "Invalid or outdated network contract");
                          } else {
                              // Only Dapp and the guardian account are allowed access during initialisation.
                              // tx.origin is only safe to use in this case for deployment since no external contracts are interacted with
                              require((
                                  booleanStorage[keccak256(abi.encodePacked("contract.exists", msg.sender))] || tx.origin == guardian
                              ), "Invalid or outdated network contract attempting access during deployment");
                          }
                          _;
                      }
                      /// @dev Construct RocketStorage
                      constructor() {
                          // Set the guardian upon deployment
                          guardian = msg.sender;
                      }
                      // Get guardian address
                      function getGuardian() external override view returns (address) {
                          return guardian;
                      }
                      // Transfers guardianship to a new address
                      function setGuardian(address _newAddress) external override {
                          // Check tx comes from current guardian
                          require(msg.sender == guardian, "Is not guardian account");
                          // Store new address awaiting confirmation
                          newGuardian = _newAddress;
                      }
                      // Confirms change of guardian
                      function confirmGuardian() external override {
                          // Check tx came from new guardian address
                          require(msg.sender == newGuardian, "Confirmation must come from new guardian address");
                          // Store old guardian for event
                          address oldGuardian = guardian;
                          // Update guardian and clear storage
                          guardian = newGuardian;
                          delete newGuardian;
                          // Emit event
                          emit GuardianChanged(oldGuardian, guardian);
                      }
                      // Set this as being deployed now
                      function getDeployedStatus() external override view returns (bool) {
                          return storageInit;
                      }
                      // Set this as being deployed now
                      function setDeployedStatus() external {
                          // Only guardian can lock this down
                          require(msg.sender == guardian, "Is not guardian account");
                          // Set it now
                          storageInit = true;
                      }
                      // Protected storage
                      // Get a node's withdrawal address
                      function getNodeWithdrawalAddress(address _nodeAddress) public override view returns (address) {
                          // If no withdrawal address has been set, return the nodes address
                          address withdrawalAddress = withdrawalAddresses[_nodeAddress];
                          if (withdrawalAddress == address(0)) {
                              return _nodeAddress;
                          }
                          return withdrawalAddress;
                      }
                      // Get a node's pending withdrawal address
                      function getNodePendingWithdrawalAddress(address _nodeAddress) external override view returns (address) {
                          return pendingWithdrawalAddresses[_nodeAddress];
                      }
                      // Set a node's withdrawal address
                      function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external override {
                          // Check new withdrawal address
                          require(_newWithdrawalAddress != address(0x0), "Invalid withdrawal address");
                          // Confirm the transaction is from the node's current withdrawal address
                          address withdrawalAddress = getNodeWithdrawalAddress(_nodeAddress);
                          require(withdrawalAddress == msg.sender, "Only a tx from a node's withdrawal address can update it");
                          // Update immediately if confirmed
                          if (_confirm) {
                              updateWithdrawalAddress(_nodeAddress, _newWithdrawalAddress);
                          }
                          // Set pending withdrawal address if not confirmed
                          else {
                              pendingWithdrawalAddresses[_nodeAddress] = _newWithdrawalAddress;
                          }
                      }
                      // Confirm a node's new withdrawal address
                      function confirmWithdrawalAddress(address _nodeAddress) external override {
                          // Get node by pending withdrawal address
                          require(pendingWithdrawalAddresses[_nodeAddress] == msg.sender, "Confirmation must come from the pending withdrawal address");
                          delete pendingWithdrawalAddresses[_nodeAddress];
                          // Update withdrawal address
                          updateWithdrawalAddress(_nodeAddress, msg.sender);
                      }
                      // Update a node's withdrawal address
                      function updateWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress) private {
                          // Set new withdrawal address
                          withdrawalAddresses[_nodeAddress] = _newWithdrawalAddress;
                          // Emit withdrawal address set event
                          emit NodeWithdrawalAddressSet(_nodeAddress, _newWithdrawalAddress, block.timestamp);
                      }
                      /// @param _key The key for the record
                      function getAddress(bytes32 _key) override external view returns (address r) {
                          return addressStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getUint(bytes32 _key) override external view returns (uint256 r) {
                          return uintStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getString(bytes32 _key) override external view returns (string memory) {
                          return stringStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getBytes(bytes32 _key) override external view returns (bytes memory) {
                          return bytesStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getBool(bytes32 _key) override external view returns (bool r) {
                          return booleanStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getInt(bytes32 _key) override external view returns (int r) {
                          return intStorage[_key];
                      }
                      /// @param _key The key for the record
                      function getBytes32(bytes32 _key) override external view returns (bytes32 r) {
                          return bytes32Storage[_key];
                      }
                      /// @param _key The key for the record
                      function setAddress(bytes32 _key, address _value) onlyLatestRocketNetworkContract override external {
                          addressStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setUint(bytes32 _key, uint _value) onlyLatestRocketNetworkContract override external {
                          uintStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setString(bytes32 _key, string calldata _value) onlyLatestRocketNetworkContract override external {
                          stringStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setBytes(bytes32 _key, bytes calldata _value) onlyLatestRocketNetworkContract override external {
                          bytesStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setBool(bytes32 _key, bool _value) onlyLatestRocketNetworkContract override external {
                          booleanStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setInt(bytes32 _key, int _value) onlyLatestRocketNetworkContract override external {
                          intStorage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function setBytes32(bytes32 _key, bytes32 _value) onlyLatestRocketNetworkContract override external {
                          bytes32Storage[_key] = _value;
                      }
                      /// @param _key The key for the record
                      function deleteAddress(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete addressStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteUint(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete uintStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteString(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete stringStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteBytes(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete bytesStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteBool(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete booleanStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteInt(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete intStorage[_key];
                      }
                      /// @param _key The key for the record
                      function deleteBytes32(bytes32 _key) onlyLatestRocketNetworkContract override external {
                          delete bytes32Storage[_key];
                      }
                      /// @param _key The key for the record
                      /// @param _amount An amount to add to the record's value
                      function addUint(bytes32 _key, uint256 _amount) onlyLatestRocketNetworkContract override external {
                          uintStorage[_key] = uintStorage[_key].add(_amount);
                      }
                      /// @param _key The key for the record
                      /// @param _amount An amount to subtract from the record's value
                      function subUint(bytes32 _key, uint256 _amount) onlyLatestRocketNetworkContract override external {
                          uintStorage[_key] = uintStorage[_key].sub(_amount);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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;
                  }
                  

                  File 3 of 8: RocketNetworkBalances
                  /**
                     *       .
                     *      / \\
                     *     |.'.|
                     *     |'.'|
                     *   ,'|   |'.
                     *  |,-'-|-'-.|
                     *   __|_| |         _        _      _____           _
                     *  | ___ \\|        | |      | |    | ___ \\         | |
                     *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                     *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                     *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                     *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                     * +---------------------------------------------------+
                     * |    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 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 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 RocketDAONodeTrustedInterface {
                      function getBootstrapModeDisabled() external view returns (bool);
                      function getMemberQuorumVotesRequired() external view returns (uint256);
                      function getMemberAt(uint256 _index) external view returns (address);
                      function getMemberCount() external view returns (uint256);
                      function getMemberMinRequired() external view returns (uint256);
                      function getMemberIsValid(address _nodeAddress) external view returns (bool);
                      function getMemberLastProposalTime(address _nodeAddress) external view returns (uint256);
                      function getMemberID(address _nodeAddress) external view returns (string memory);
                      function getMemberUrl(address _nodeAddress) external view returns (string memory);
                      function getMemberJoinedTime(address _nodeAddress) external view returns (uint256);
                      function getMemberProposalExecutedTime(string memory _proposalType, address _nodeAddress) external view returns (uint256);
                      function getMemberRPLBondAmount(address _nodeAddress) external view returns (uint256);
                      function getMemberIsChallenged(address _nodeAddress) external view returns (bool);
                      function getMemberUnbondedValidatorCount(address _nodeAddress) external view returns (uint256);
                      function incrementMemberUnbondedValidatorCount(address _nodeAddress) external;
                      function decrementMemberUnbondedValidatorCount(address _nodeAddress) external;
                      function bootstrapMember(string memory _id, string memory _url, address _nodeAddress) external;
                      function bootstrapSettingUint(string memory _settingContractName, string memory _settingPath, uint256 _value) external;
                      function bootstrapSettingBool(string memory _settingContractName, string memory _settingPath, bool _value) external;
                      function bootstrapUpgrade(string memory _type, string memory _name, string memory _contractAbi, address _contractAddress) external;
                      function bootstrapDisable(bool _confirmDisableBootstrapMode) external;
                      function memberJoinRequired(string memory _id, string memory _url) 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;
                  pragma abicoder v2;
                  // SPDX-License-Identifier: GPL-3.0-only
                  interface RocketNetworkBalancesInterface {
                      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 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);
                  }
                  /**
                     *       .
                     *      / \\
                     *     |.'.|
                     *     |'.'|
                     *   ,'|   |'.
                     *  |,-'-|-'-.|
                     *   __|_| |         _        _      _____           _
                     *  | ___ \\|        | |      | |    | ___ \\         | |
                     *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                     *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                     *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                     *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                     * +---------------------------------------------------+
                     * |    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.18;
                  pragma abicoder v2;
                  import "../RocketBase.sol";
                  import "../../interface/dao/node/RocketDAONodeTrustedInterface.sol";
                  import "../../interface/network/RocketNetworkBalancesInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNetworkInterface.sol";
                  /// @notice Oracle contract for network balance data
                  contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface {
                      // Events
                      event BalancesSubmitted(address indexed from, uint256 block, uint256 slotTimestamp, uint256 totalEth, uint256 stakingEth, uint256 rethSupply, uint256 blockTimestamp);
                      event BalancesUpdated(uint256 indexed block, uint256 slotTimestamp, uint256 totalEth, uint256 stakingEth, uint256 rethSupply, uint256 blockTimestamp);
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
                          version = 3;
                      }
                      /// @notice The block number which balances are current for
                      function getBalancesBlock() override public view returns (uint256) {
                          return getUint(keccak256("network.balances.updated.block"));
                      }
                      /// @notice Sets the block number which balances are current for
                      function setBalancesBlock(uint256 _value) private {
                          setUint(keccak256("network.balances.updated.block"), _value);
                      }
                      /// @notice The current RP network total ETH balance
                      function getTotalETHBalance() override public view returns (uint256) {
                          return getUint(keccak256("network.balance.total"));
                      }
                      /// @notice Sets the current RP network total ETH balance
                      function setTotalETHBalance(uint256 _value) private {
                          setUint(keccak256("network.balance.total"), _value);
                      }
                      /// @notice The current RP network staking ETH balance
                      function getStakingETHBalance() override public view returns (uint256) {
                          return getUint(keccak256("network.balance.staking"));
                      }
                      /// @notice Sets the current RP network staking ETH balance
                      function setStakingETHBalance(uint256 _value) private {
                          setUint(keccak256("network.balance.staking"), _value);
                      }
                      /// @notice The current RP network total rETH supply
                      function getTotalRETHSupply() override external view returns (uint256) {
                          return getUint(keccak256("network.balance.reth.supply"));
                      }
                      /// @notice Sets the current RP network total rETH supply
                      function setTotalRETHSupply(uint256 _value) private {
                          setUint(keccak256("network.balance.reth.supply"), _value);
                      }
                      /// @notice Get the current RP network ETH utilization rate as a fraction of 1 ETH
                      ///         Represents what % of the network's balance is actively earning rewards
                      function getETHUtilizationRate() override external view returns (uint256) {
                          uint256 totalEthBalance = getTotalETHBalance();
                          uint256 stakingEthBalance = getStakingETHBalance();
                          if (totalEthBalance == 0) { return calcBase; }
                          return calcBase * stakingEthBalance / totalEthBalance;
                      }
                      /// @notice Submit network balances for a block.
                      ///         Only accepts calls from trusted (oracle) nodes.
                      function submitBalances(uint256 _block, uint256 _slotTimestamp, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) onlyTrustedNode(msg.sender) {
                          // Check settings
                          RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork"));
                          require(rocketDAOProtocolSettingsNetwork.getSubmitBalancesEnabled(), "Submitting balances is currently disabled");
                          // Check block
                          require(_block < block.number, "Balances can not be submitted for a future block");
                          uint256 lastBalancesBlock = getBalancesBlock();
                          require(_block >= lastBalancesBlock, "Network balances for a higher block are set");
                          // Get submission keys
                          bytes32 nodeSubmissionKey = keccak256(abi.encodePacked("network.balances.submitted.node", msg.sender, _block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply));
                          bytes32 submissionCountKey = keccak256(abi.encodePacked("network.balances.submitted.count", _block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply));
                          // Check & update node submission status
                          require(!getBool(nodeSubmissionKey), "Duplicate submission from node");
                          setBool(nodeSubmissionKey, true);
                          setBool(keccak256(abi.encodePacked("network.balances.submitted.node", msg.sender, _block)), true);
                          // Increment submission count
                          uint256 submissionCount = getUint(submissionCountKey) + 1;
                          setUint(submissionCountKey, submissionCount);
                          // Emit balances submitted event
                          emit BalancesSubmitted(msg.sender, _block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply, block.timestamp);
                          // If voting past consensus, return
                          if (_block == lastBalancesBlock) {
                              return;
                          }
                          // Check submission count & update network balances
                          RocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));
                          if (calcBase * submissionCount / rocketDAONodeTrusted.getMemberCount() >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold()) {
                              updateBalances(_block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply);
                          }
                      }
                      /// @notice Executes updateBalances if consensus threshold is reached
                      function executeUpdateBalances(uint256 _block, uint256 _slotTimestamp, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) {
                          // Check settings
                          RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork"));
                          require(rocketDAOProtocolSettingsNetwork.getSubmitBalancesEnabled(), "Submitting balances is currently disabled");
                          // Check block
                          require(_block < block.number, "Balances can not be submitted for a future block");
                          require(_block > getBalancesBlock(), "Network balances for an equal or higher block are set");
                          // Check balances
                          require(_stakingEth <= _totalEth, "Invalid network balances");
                          // Get submission keys
                          bytes32 submissionCountKey = keccak256(abi.encodePacked("network.balances.submitted.count", _block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply));
                          // Get submission count
                          uint256 submissionCount = getUint(submissionCountKey);
                          // Check submission count & update network balances
                          RocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted"));
                          require(calcBase * submissionCount / rocketDAONodeTrusted.getMemberCount() >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold(), "Consensus has not been reached");
                          updateBalances(_block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply);
                      }
                      /// @dev Internal method to update network balances
                      function updateBalances(uint256 _block, uint256 _slotTimestamp, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) private {
                          // Update balances
                          setBalancesBlock(_block);
                          setTotalETHBalance(_totalEth);
                          setStakingETHBalance(_stakingEth);
                          setTotalRETHSupply(_rethSupply);
                          // Emit balances updated event
                          emit BalancesUpdated(_block, _slotTimestamp, _totalEth, _stakingEth, _rethSupply, block.timestamp);
                      }
                  }
                  

                  File 4 of 8: RocketDepositPool
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @title SignedSafeMath
                   * @dev Signed math operations with safety checks that revert on error.
                   */
                  library SignedSafeMath {
                      int256 constant private _INT256_MIN = -2**255;
                      /**
                       * @dev Returns the multiplication of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(int256 a, int256 b) internal pure returns (int256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) {
                              return 0;
                          }
                          require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
                          int256 c = a * b;
                          require(c / a == b, "SignedSafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two signed integers. Reverts on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(int256 a, int256 b) internal pure returns (int256) {
                          require(b != 0, "SignedSafeMath: division by zero");
                          require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");
                          int256 c = a / b;
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(int256 a, int256 b) internal pure returns (int256) {
                          int256 c = a - b;
                          require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the addition of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(int256 a, int256 b) internal pure returns (int256) {
                          int256 c = a + b;
                          require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
                          return c;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
                   * checks.
                   *
                   * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
                   * easily result in undesired exploitation or bugs, since developers usually
                   * assume that overflows raise errors. `SafeCast` restores this intuition by
                   * reverting the transaction when such an operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   *
                   * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
                   * all math on `uint256` and `int256` and then downcasting.
                   */
                  library SafeCast {
                      /**
                       * @dev Returns the downcasted uint128 from uint256, reverting on
                       * overflow (when the input is greater than largest uint128).
                       *
                       * Counterpart to Solidity's `uint128` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 128 bits
                       */
                      function toUint128(uint256 value) internal pure returns (uint128) {
                          require(value < 2**128, "SafeCast: value doesn\\'t fit in 128 bits");
                          return uint128(value);
                      }
                      /**
                       * @dev Returns the downcasted uint64 from uint256, reverting on
                       * overflow (when the input is greater than largest uint64).
                       *
                       * Counterpart to Solidity's `uint64` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 64 bits
                       */
                      function toUint64(uint256 value) internal pure returns (uint64) {
                          require(value < 2**64, "SafeCast: value doesn\\'t fit in 64 bits");
                          return uint64(value);
                      }
                      /**
                       * @dev Returns the downcasted uint32 from uint256, reverting on
                       * overflow (when the input is greater than largest uint32).
                       *
                       * Counterpart to Solidity's `uint32` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 32 bits
                       */
                      function toUint32(uint256 value) internal pure returns (uint32) {
                          require(value < 2**32, "SafeCast: value doesn\\'t fit in 32 bits");
                          return uint32(value);
                      }
                      /**
                       * @dev Returns the downcasted uint16 from uint256, reverting on
                       * overflow (when the input is greater than largest uint16).
                       *
                       * Counterpart to Solidity's `uint16` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 16 bits
                       */
                      function toUint16(uint256 value) internal pure returns (uint16) {
                          require(value < 2**16, "SafeCast: value doesn\\'t fit in 16 bits");
                          return uint16(value);
                      }
                      /**
                       * @dev Returns the downcasted uint8 from uint256, reverting on
                       * overflow (when the input is greater than largest uint8).
                       *
                       * Counterpart to Solidity's `uint8` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 8 bits.
                       */
                      function toUint8(uint256 value) internal pure returns (uint8) {
                          require(value < 2**8, "SafeCast: value doesn\\'t fit in 8 bits");
                          return uint8(value);
                      }
                      /**
                       * @dev Converts a signed int256 into an unsigned uint256.
                       *
                       * Requirements:
                       *
                       * - input must be greater than or equal to 0.
                       */
                      function toUint256(int256 value) internal pure returns (uint256) {
                          require(value >= 0, "SafeCast: value must be positive");
                          return uint256(value);
                      }
                      /**
                       * @dev Returns the downcasted int128 from int256, reverting on
                       * overflow (when the input is less than smallest int128 or
                       * greater than largest int128).
                       *
                       * Counterpart to Solidity's `int128` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 128 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt128(int256 value) internal pure returns (int128) {
                          require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\\'t fit in 128 bits");
                          return int128(value);
                      }
                      /**
                       * @dev Returns the downcasted int64 from int256, reverting on
                       * overflow (when the input is less than smallest int64 or
                       * greater than largest int64).
                       *
                       * Counterpart to Solidity's `int64` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 64 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt64(int256 value) internal pure returns (int64) {
                          require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\\'t fit in 64 bits");
                          return int64(value);
                      }
                      /**
                       * @dev Returns the downcasted int32 from int256, reverting on
                       * overflow (when the input is less than smallest int32 or
                       * greater than largest int32).
                       *
                       * Counterpart to Solidity's `int32` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 32 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt32(int256 value) internal pure returns (int32) {
                          require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\\'t fit in 32 bits");
                          return int32(value);
                      }
                      /**
                       * @dev Returns the downcasted int16 from int256, reverting on
                       * overflow (when the input is less than smallest int16 or
                       * greater than largest int16).
                       *
                       * Counterpart to Solidity's `int16` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 16 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt16(int256 value) internal pure returns (int16) {
                          require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\\'t fit in 16 bits");
                          return int16(value);
                      }
                      /**
                       * @dev Returns the downcasted int8 from int256, reverting on
                       * overflow (when the input is less than smallest int8 or
                       * greater than largest int8).
                       *
                       * Counterpart to Solidity's `int8` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 8 bits.
                       *
                       * _Available since v3.1._
                       */
                      function toInt8(int256 value) internal pure returns (int8) {
                          require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\\'t fit in 8 bits");
                          return int8(value);
                      }
                      /**
                       * @dev Converts an unsigned uint256 into a signed int256.
                       *
                       * Requirements:
                       *
                       * - input must be less than or equal to maxInt256.
                       */
                      function toInt256(uint256 value) internal pure returns (int256) {
                          require(value < 2**255, "SafeCast: value doesn't fit in an int256");
                          return int256(value);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity >0.5.0 <0.9.0;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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(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 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); }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Interface of the ERC20 standard as defined in the EIP.
                   */
                  interface IERC20 {
                      /**
                       * @dev Returns the amount of tokens in existence.
                       */
                      function totalSupply() external view returns (uint256);
                      /**
                       * @dev Returns the amount of tokens owned by `account`.
                       */
                      function balanceOf(address account) external view returns (uint256);
                      /**
                       * @dev Moves `amount` tokens from the caller's account to `recipient`.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transfer(address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Returns the remaining number of tokens that `spender` will be
                       * allowed to spend on behalf of `owner` through {transferFrom}. This is
                       * zero by default.
                       *
                       * This value changes when {approve} or {transferFrom} are called.
                       */
                      function allowance(address owner, address spender) external view returns (uint256);
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * IMPORTANT: Beware that changing an allowance with this method brings the risk
                       * that someone may use both the old and the new allowance by unfortunate
                       * transaction ordering. One possible solution to mitigate this race
                       * condition is to first reduce the spender's allowance to 0 and set the
                       * desired value afterwards:
                       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                       *
                       * Emits an {Approval} event.
                       */
                      function approve(address spender, uint256 amount) external returns (bool);
                      /**
                       * @dev Moves `amount` tokens from `sender` to `recipient` using the
                       * allowance mechanism. `amount` is then deducted from the caller's
                       * allowance.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Emitted when `value` tokens are moved from one account (`from`) to
                       * another (`to`).
                       *
                       * Note that `value` may be zero.
                       */
                      event Transfer(address indexed from, address indexed to, uint256 value);
                      /**
                       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                       * a call to {approve}. `value` is the new allowance.
                       */
                      event Approval(address indexed owner, address indexed spender, uint256 value);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /*
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with GSN meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address payable) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes memory) {
                          this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                          return msg.data;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../../utils/Context.sol";
                  import "./IERC20.sol";
                  import "../../math/SafeMath.sol";
                  /**
                   * @dev Implementation of the {IERC20} interface.
                   *
                   * This implementation is agnostic to the way tokens are created. This means
                   * that a supply mechanism has to be added in a derived contract using {_mint}.
                   * For a generic mechanism see {ERC20PresetMinterPauser}.
                   *
                   * TIP: For a detailed writeup see our guide
                   * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                   * to implement supply mechanisms].
                   *
                   * We have followed general OpenZeppelin guidelines: functions revert instead
                   * of returning `false` on failure. This behavior is nonetheless conventional
                   * and does not conflict with the expectations of ERC20 applications.
                   *
                   * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                   * This allows applications to reconstruct the allowance for all accounts just
                   * by listening to said events. Other implementations of the EIP may not emit
                   * these events, as it isn't required by the specification.
                   *
                   * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                   * functions have been added to mitigate the well-known issues around setting
                   * allowances. See {IERC20-approve}.
                   */
                  contract ERC20 is Context, IERC20 {
                      using SafeMath for uint256;
                      mapping (address => uint256) private _balances;
                      mapping (address => mapping (address => uint256)) private _allowances;
                      uint256 private _totalSupply;
                      string private _name;
                      string private _symbol;
                      uint8 private _decimals;
                      /**
                       * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                       * a default value of 18.
                       *
                       * To select a different value for {decimals}, use {_setupDecimals}.
                       *
                       * All three of these values are immutable: they can only be set once during
                       * construction.
                       */
                      constructor (string memory name_, string memory symbol_) public {
                          _name = name_;
                          _symbol = symbol_;
                          _decimals = 18;
                      }
                      /**
                       * @dev Returns the name of the token.
                       */
                      function name() public view virtual returns (string memory) {
                          return _name;
                      }
                      /**
                       * @dev Returns the symbol of the token, usually a shorter version of the
                       * name.
                       */
                      function symbol() public view virtual returns (string memory) {
                          return _symbol;
                      }
                      /**
                       * @dev Returns the number of decimals used to get its user representation.
                       * For example, if `decimals` equals `2`, a balance of `505` tokens should
                       * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                       *
                       * Tokens usually opt for a value of 18, imitating the relationship between
                       * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                       * called.
                       *
                       * NOTE: This information is only used for _display_ purposes: it in
                       * no way affects any of the arithmetic of the contract, including
                       * {IERC20-balanceOf} and {IERC20-transfer}.
                       */
                      function decimals() public view virtual returns (uint8) {
                          return _decimals;
                      }
                      /**
                       * @dev See {IERC20-totalSupply}.
                       */
                      function totalSupply() public view virtual override returns (uint256) {
                          return _totalSupply;
                      }
                      /**
                       * @dev See {IERC20-balanceOf}.
                       */
                      function balanceOf(address account) public view virtual override returns (uint256) {
                          return _balances[account];
                      }
                      /**
                       * @dev See {IERC20-transfer}.
                       *
                       * Requirements:
                       *
                       * - `recipient` cannot be the zero address.
                       * - the caller must have a balance of at least `amount`.
                       */
                      function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(_msgSender(), recipient, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-allowance}.
                       */
                      function allowance(address owner, address spender) public view virtual override returns (uint256) {
                          return _allowances[owner][spender];
                      }
                      /**
                       * @dev See {IERC20-approve}.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function approve(address spender, uint256 amount) public virtual override returns (bool) {
                          _approve(_msgSender(), spender, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-transferFrom}.
                       *
                       * Emits an {Approval} event indicating the updated allowance. This is not
                       * required by the EIP. See the note at the beginning of {ERC20}.
                       *
                       * Requirements:
                       *
                       * - `sender` and `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       * - the caller must have allowance for ``sender``'s tokens of at least
                       * `amount`.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(sender, recipient, amount);
                          _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                          return true;
                      }
                      /**
                       * @dev Atomically increases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                          return true;
                      }
                      /**
                       * @dev Atomically decreases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       * - `spender` must have allowance for the caller of at least
                       * `subtractedValue`.
                       */
                      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                          return true;
                      }
                      /**
                       * @dev Moves tokens `amount` from `sender` to `recipient`.
                       *
                       * This is internal function is equivalent to {transfer}, and can be used to
                       * e.g. implement automatic token fees, slashing mechanisms, etc.
                       *
                       * Emits a {Transfer} event.
                       *
                       * Requirements:
                       *
                       * - `sender` cannot be the zero address.
                       * - `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       */
                      function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                          require(sender != address(0), "ERC20: transfer from the zero address");
                          require(recipient != address(0), "ERC20: transfer to the zero address");
                          _beforeTokenTransfer(sender, recipient, amount);
                          _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                          _balances[recipient] = _balances[recipient].add(amount);
                          emit Transfer(sender, recipient, amount);
                      }
                      /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                       * the total supply.
                       *
                       * Emits a {Transfer} event with `from` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `to` cannot be the zero address.
                       */
                      function _mint(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: mint to the zero address");
                          _beforeTokenTransfer(address(0), account, amount);
                          _totalSupply = _totalSupply.add(amount);
                          _balances[account] = _balances[account].add(amount);
                          emit Transfer(address(0), account, amount);
                      }
                      /**
                       * @dev Destroys `amount` tokens from `account`, reducing the
                       * total supply.
                       *
                       * Emits a {Transfer} event with `to` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `account` cannot be the zero address.
                       * - `account` must have at least `amount` tokens.
                       */
                      function _burn(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: burn from the zero address");
                          _beforeTokenTransfer(account, address(0), amount);
                          _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                          _totalSupply = _totalSupply.sub(amount);
                          emit Transfer(account, address(0), amount);
                      }
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                       *
                       * This internal function is equivalent to `approve`, and can be used to
                       * e.g. set automatic allowances for certain subsystems, etc.
                       *
                       * Emits an {Approval} event.
                       *
                       * Requirements:
                       *
                       * - `owner` cannot be the zero address.
                       * - `spender` cannot be the zero address.
                       */
                      function _approve(address owner, address spender, uint256 amount) internal virtual {
                          require(owner != address(0), "ERC20: approve from the zero address");
                          require(spender != address(0), "ERC20: approve to the zero address");
                          _allowances[owner][spender] = amount;
                          emit Approval(owner, spender, amount);
                      }
                      /**
                       * @dev Sets {decimals} to a value other than the default one of 18.
                       *
                       * WARNING: This function should only be called from the constructor. Most
                       * applications that interact with token contracts will not expect
                       * {decimals} to ever change, and may work incorrectly if it does.
                       */
                      function _setupDecimals(uint8 decimals_) internal virtual {
                          _decimals = decimals_;
                      }
                      /**
                       * @dev Hook that is called before any transfer of tokens. This includes
                       * minting and burning.
                       *
                       * Calling conditions:
                       *
                       * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                       * will be to transferred to `to`.
                       * - when `from` is zero, `amount` tokens will be minted for `to`.
                       * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                       * - `from` and `to` are never both zero.
                       *
                       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                       */
                      function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../../utils/Context.sol";
                  import "./ERC20.sol";
                  /**
                   * @dev Extension of {ERC20} that allows token holders to destroy both their own
                   * tokens and those that they have an allowance for, in a way that can be
                   * recognized off-chain (via event analysis).
                   */
                  abstract contract ERC20Burnable is Context, ERC20 {
                      using SafeMath for uint256;
                      /**
                       * @dev Destroys `amount` tokens from the caller.
                       *
                       * See {ERC20-_burn}.
                       */
                      function burn(uint256 amount) public virtual {
                          _burn(_msgSender(), amount);
                      }
                      /**
                       * @dev Destroys `amount` tokens from `account`, deducting from the caller's
                       * allowance.
                       *
                       * See {ERC20-_burn} and {ERC20-allowance}.
                       *
                       * Requirements:
                       *
                       * - the caller must have allowance for ``accounts``'s tokens of at least
                       * `amount`.
                       */
                      function burnFrom(address account, uint256 amount) public virtual {
                          uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
                          _approve(account, _msgSender(), decreasedAllowance);
                          _burn(account, amount);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity >0.5.0 <0.9.0;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
                  import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.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(ERC20Burnable _tokenAddress, uint256 _amount) external;
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 getExcessBalance() external view returns (uint256);
                      function deposit() external payable;
                      function getMaximumDepositAmount() external view returns (uint256);
                      function nodeDeposit(uint256 _totalAmount) external payable;
                      function nodeCreditWithdrawal(uint256 _amount) external;
                      function recycleDissolvedDeposit() external payable;
                      function recycleExcessCollateral() external payable;
                      function recycleLiquidatedStake() external payable;
                      function assignDeposits() external;
                      function maybeAssignDeposits() external returns (bool);
                      function withdrawExcessBalance(uint256 _amount) external;
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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);
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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);
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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);
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity >0.5.0 <0.9.0;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/token/ERC20/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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  // SPDX-License-Identifier: GPL-3.0-only
                  pragma solidity 0.7.6;
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  import "@openzeppelin/contracts/math/SignedSafeMath.sol";
                  import "@openzeppelin/contracts/utils/SafeCast.sol";
                  import "../RocketBase.sol";
                  import "../../interface/RocketVaultInterface.sol";
                  import "../../interface/RocketVaultWithdrawerInterface.sol";
                  import "../../interface/deposit/RocketDepositPoolInterface.sol";
                  import "../../interface/minipool/RocketMinipoolInterface.sol";
                  import "../../interface/minipool/RocketMinipoolQueueInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsDepositInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNetworkInterface.sol";
                  import "../../interface/token/RocketTokenRETHInterface.sol";
                  import "../../types/MinipoolDeposit.sol";
                  /// @notice Accepts user deposits and mints rETH; handles assignment of deposited ETH to minipools
                  contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaultWithdrawerInterface {
                      // Libs
                      using SafeMath for uint256;
                      using SignedSafeMath for int256;
                      using SafeCast for uint256;
                      // Immutables
                      RocketVaultInterface immutable rocketVault;
                      RocketTokenRETHInterface immutable 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);
                      // 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 = 3;
                          // 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("deposit.pool.node.balance");
                      }
                      /// @notice Returns the user owned portion of the deposit pool (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 getBalance().toInt256().sub(getNodeBalance().toInt256());
                      }
                      /// @notice Excess deposit pool balance (in excess of minipool queue capacity)
                      function getExcessBalance() override public view returns (uint256) {
                          // Get minipool queue capacity
                          RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
                          uint256 minipoolCapacity = rocketMinipoolQueue.getEffectiveCapacity();
                          uint256 balance = getBalance();
                          // Calculate and return
                          if (minipoolCapacity >= balance) { return 0; }
                          else { return balance.sub(minipoolCapacity); }
                      }
                      /// @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 = getBalance().add(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"));
                                  require(capacityNeeded <= maxDepositPoolSize.add(rocketMinipoolQueue.getEffectiveCapacity()),
                                      "The deposit pool size after depositing (and matching with minipools) exceeds the maximum size");
                              } else {
                                  revert("The deposit pool size after depositing exceeds the maximum size");
                              }
                          }
                          // Calculate deposit fee
                          uint256 depositFee = msg.value.mul(rocketDAOProtocolSettingsDeposit.getDepositFee()).div(calcBase);
                          uint256 depositNet = msg.value.sub(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(rocketDAOProtocolSettingsDeposit);
                      }
                      /// @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 enabled 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 = maxCapacity.add(rocketMinipoolQueue.getEffectiveCapacity());
                          }
                          // Check we aren't already over
                          if (depositPoolBalance >= maxCapacity) {
                              return 0;
                          }
                          return maxCapacity.sub(depositPoolBalance);
                      }
                      /// @dev Accepts ETH deposit from the node deposit contract (does not mint rETH)
                      /// @param _totalAmount The total node deposit amount including any credit balance used
                      function nodeDeposit(uint256 _totalAmount) 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("deposit.pool.node.balance", _totalAmount);
                      }
                      /// @dev Withdraws ETH from the deposit pool to RocketNodeDeposit contract to be used for a new minipool
                      /// @param _amount The amount of ETH to withdraw
                      function nodeCreditWithdrawal(uint256 _amount) override external onlyThisLatestContract onlyLatestContract("rocketNodeDeposit", msg.sender) {
                          // Withdraw ETH from the vault
                          rocketVault.withdrawEther(_amount);
                          // Send it to msg.sender (function modifier verifies msg.sender is RocketNodeDeposit)
                          (bool success, ) = address(msg.sender).call{value: _amount}("");
                          require(success, "Failed to send ETH");
                      }
                      /// @dev Recycle a deposit from a dissolved minipool
                      function recycleDissolvedDeposit() override external payable onlyThisLatestContract onlyRegisteredMinipool(msg.sender) {
                          // Load contracts
                          RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
                          // Recycle ETH
                          emit DepositRecycled(msg.sender, msg.value, block.timestamp);
                          processDeposit(rocketDAOProtocolSettingsDeposit);
                      }
                      /// @dev Recycle excess ETH from the rETH token contract
                      function recycleExcessCollateral() override external payable onlyThisLatestContract onlyLatestContract("rocketTokenRETH", msg.sender) {
                          // Load contracts
                          RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
                          // Recycle ETH
                          emit DepositRecycled(msg.sender, msg.value, block.timestamp);
                          processDeposit(rocketDAOProtocolSettingsDeposit);
                      }
                      /// @dev Recycle a liquidated RPL stake from a slashed minipool
                      function recycleLiquidatedStake() override external payable onlyThisLatestContract onlyLatestContract("rocketAuctionManager", msg.sender) {
                          // Load contracts
                          RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
                          // Recycle ETH
                          emit DepositRecycled(msg.sender, msg.value, block.timestamp);
                          processDeposit(rocketDAOProtocolSettingsDeposit);
                      }
                      /// @dev Process a deposit
                      function processDeposit(RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) private {
                          // Transfer ETH to vault
                          rocketVault.depositEther{value: msg.value}();
                          // Assign deposits if enabled
                          _assignDeposits(_rocketDAOProtocolSettingsDeposit);
                      }
                      /// @notice Assign deposits to available minipools. Reverts if assigning deposits is disabled.
                      function assignDeposits() override external onlyThisLatestContract {
                          // Load contracts
                          RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
                          // Revert if assigning is disabled
                          require(_assignDeposits(rocketDAOProtocolSettingsDeposit), "Deposit assignments are currently disabled");
                      }
                      /// @dev Assign deposits to available minipools. Does nothing if assigning deposits is disabled.
                      function maybeAssignDeposits() override external onlyThisLatestContract returns (bool) {
                          // Load contracts
                          RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
                          // Revert if assigning is disabled
                          return _assignDeposits(rocketDAOProtocolSettingsDeposit);
                      }
                      /// @dev Assigns deposits to available minipools, returns false if assignment is currently disabled
                      function _assignDeposits(RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) private returns (bool) {
                          // Check if assigning deposits is enabled
                          if (!_rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) {
                              return false;
                          }
                          // Load contracts
                          RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
                          // Decide which queue processing implementation to use based on queue contents
                          if (rocketMinipoolQueue.getContainsLegacy()) {
                              return _assignDepositsLegacy(rocketMinipoolQueue, _rocketDAOProtocolSettingsDeposit);
                          } else {
                              return _assignDepositsNew(rocketMinipoolQueue, _rocketDAOProtocolSettingsDeposit);
                          }
                      }
                      /// @dev Assigns deposits using the new minipool queue
                      function _assignDepositsNew(RocketMinipoolQueueInterface _rocketMinipoolQueue, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) private returns (bool) {
                          // 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.div(variableDepositAmount);
                          uint256 totalEthCount = getBalance().div(variableDepositAmount);
                          uint256 assignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositSocialisedAssignments().add(scalingCount);
                          if (assignments > totalEthCount) {
                              assignments = totalEthCount;
                          }
                          if (assignments > maxAssignments) {
                              assignments = maxAssignments;
                          }
                          address[] memory minipools = _rocketMinipoolQueue.dequeueMinipools(assignments);
                          if (minipools.length > 0){
                              // Withdraw ETH from vault
                              uint256 totalEther = minipools.length.mul(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.add(minipool.getNodeTopUpValue());
                                  // Emit deposit assigned event
                                  emit DepositAssigned(minipools[i], variableDepositAmount, block.timestamp);
                              }
                              // Decrease node balance
                              subUint("deposit.pool.node.balance", nodeBalanceUsed);
                          }
                          return true;
                      }
                      /// @dev Assigns deposits using the legacy minipool queue
                      function _assignDepositsLegacy(RocketMinipoolQueueInterface _rocketMinipoolQueue, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) private returns (bool) {
                          // Load contracts
                          RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                          // Setup initial variable values
                          uint256 balance = getBalance();
                          uint256 totalEther = 0;
                          // Calculate minipool assignments
                          uint256 maxAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments();
                          MinipoolAssignment[] memory assignments = new MinipoolAssignment[](maxAssignments);
                          MinipoolDeposit depositType = MinipoolDeposit.None;
                          uint256 count = 0;
                          uint256 minipoolCapacity = 0;
                          for (uint256 i = 0; i < maxAssignments; ++i) {
                              // Optimised for multiple of the same deposit type
                              if (count == 0) {
                                  (depositType, count) = _rocketMinipoolQueue.getNextDepositLegacy();
                                  if (depositType == MinipoolDeposit.None) { break; }
                                  minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(depositType);
                              }
                              count--;
                              if (minipoolCapacity == 0 || balance.sub(totalEther) < minipoolCapacity) { break; }
                              // Dequeue the minipool
                              address minipoolAddress = _rocketMinipoolQueue.dequeueMinipoolByDepositLegacy(depositType);
                              // Update running total
                              totalEther = totalEther.add(minipoolCapacity);
                              // Add assignment
                              assignments[i].etherAssigned = minipoolCapacity;
                              assignments[i].minipoolAddress = minipoolAddress;
                          }
                          if (totalEther > 0) {
                              // Withdraw ETH from vault
                              rocketVault.withdrawEther(totalEther);
                              // Perform assignments
                              for (uint256 i = 0; i < maxAssignments; ++i) {
                                  if (assignments[i].etherAssigned == 0) { break; }
                                  RocketMinipoolInterface minipool = RocketMinipoolInterface(assignments[i].minipoolAddress);
                                  // Assign deposit to minipool
                                  minipool.userDeposit{value: assignments[i].etherAssigned}();
                                  // Emit deposit assigned event
                                  emit DepositAssigned(assignments[i].minipoolAddress, assignments[i].etherAssigned, block.timestamp);
                              }
                          }
                          return true;
                      }
                      /// @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);
                      }
                  }
                  

                  File 5 of 8: RocketMinipoolQueue
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @title SignedSafeMath
                   * @dev Signed math operations with safety checks that revert on error.
                   */
                  library SignedSafeMath {
                      int256 constant private _INT256_MIN = -2**255;
                      /**
                       * @dev Returns the multiplication of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(int256 a, int256 b) internal pure returns (int256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) {
                              return 0;
                          }
                          require(!(a == -1 && b == _INT256_MIN), "SignedSafeMath: multiplication overflow");
                          int256 c = a * b;
                          require(c / a == b, "SignedSafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two signed integers. Reverts on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(int256 a, int256 b) internal pure returns (int256) {
                          require(b != 0, "SignedSafeMath: division by zero");
                          require(!(b == -1 && a == _INT256_MIN), "SignedSafeMath: division overflow");
                          int256 c = a / b;
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(int256 a, int256 b) internal pure returns (int256) {
                          int256 c = a - b;
                          require((b >= 0 && c <= a) || (b < 0 && c > a), "SignedSafeMath: subtraction overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the addition of two signed integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(int256 a, int256 b) internal pure returns (int256) {
                          int256 c = a + b;
                          require((b >= 0 && c >= a) || (b < 0 && c < a), "SignedSafeMath: addition overflow");
                          return c;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
                   * checks.
                   *
                   * Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
                   * easily result in undesired exploitation or bugs, since developers usually
                   * assume that overflows raise errors. `SafeCast` restores this intuition by
                   * reverting the transaction when such an operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   *
                   * Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
                   * all math on `uint256` and `int256` and then downcasting.
                   */
                  library SafeCast {
                      /**
                       * @dev Returns the downcasted uint128 from uint256, reverting on
                       * overflow (when the input is greater than largest uint128).
                       *
                       * Counterpart to Solidity's `uint128` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 128 bits
                       */
                      function toUint128(uint256 value) internal pure returns (uint128) {
                          require(value < 2**128, "SafeCast: value doesn\\'t fit in 128 bits");
                          return uint128(value);
                      }
                      /**
                       * @dev Returns the downcasted uint64 from uint256, reverting on
                       * overflow (when the input is greater than largest uint64).
                       *
                       * Counterpart to Solidity's `uint64` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 64 bits
                       */
                      function toUint64(uint256 value) internal pure returns (uint64) {
                          require(value < 2**64, "SafeCast: value doesn\\'t fit in 64 bits");
                          return uint64(value);
                      }
                      /**
                       * @dev Returns the downcasted uint32 from uint256, reverting on
                       * overflow (when the input is greater than largest uint32).
                       *
                       * Counterpart to Solidity's `uint32` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 32 bits
                       */
                      function toUint32(uint256 value) internal pure returns (uint32) {
                          require(value < 2**32, "SafeCast: value doesn\\'t fit in 32 bits");
                          return uint32(value);
                      }
                      /**
                       * @dev Returns the downcasted uint16 from uint256, reverting on
                       * overflow (when the input is greater than largest uint16).
                       *
                       * Counterpart to Solidity's `uint16` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 16 bits
                       */
                      function toUint16(uint256 value) internal pure returns (uint16) {
                          require(value < 2**16, "SafeCast: value doesn\\'t fit in 16 bits");
                          return uint16(value);
                      }
                      /**
                       * @dev Returns the downcasted uint8 from uint256, reverting on
                       * overflow (when the input is greater than largest uint8).
                       *
                       * Counterpart to Solidity's `uint8` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 8 bits.
                       */
                      function toUint8(uint256 value) internal pure returns (uint8) {
                          require(value < 2**8, "SafeCast: value doesn\\'t fit in 8 bits");
                          return uint8(value);
                      }
                      /**
                       * @dev Converts a signed int256 into an unsigned uint256.
                       *
                       * Requirements:
                       *
                       * - input must be greater than or equal to 0.
                       */
                      function toUint256(int256 value) internal pure returns (uint256) {
                          require(value >= 0, "SafeCast: value must be positive");
                          return uint256(value);
                      }
                      /**
                       * @dev Returns the downcasted int128 from int256, reverting on
                       * overflow (when the input is less than smallest int128 or
                       * greater than largest int128).
                       *
                       * Counterpart to Solidity's `int128` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 128 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt128(int256 value) internal pure returns (int128) {
                          require(value >= -2**127 && value < 2**127, "SafeCast: value doesn\\'t fit in 128 bits");
                          return int128(value);
                      }
                      /**
                       * @dev Returns the downcasted int64 from int256, reverting on
                       * overflow (when the input is less than smallest int64 or
                       * greater than largest int64).
                       *
                       * Counterpart to Solidity's `int64` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 64 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt64(int256 value) internal pure returns (int64) {
                          require(value >= -2**63 && value < 2**63, "SafeCast: value doesn\\'t fit in 64 bits");
                          return int64(value);
                      }
                      /**
                       * @dev Returns the downcasted int32 from int256, reverting on
                       * overflow (when the input is less than smallest int32 or
                       * greater than largest int32).
                       *
                       * Counterpart to Solidity's `int32` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 32 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt32(int256 value) internal pure returns (int32) {
                          require(value >= -2**31 && value < 2**31, "SafeCast: value doesn\\'t fit in 32 bits");
                          return int32(value);
                      }
                      /**
                       * @dev Returns the downcasted int16 from int256, reverting on
                       * overflow (when the input is less than smallest int16 or
                       * greater than largest int16).
                       *
                       * Counterpart to Solidity's `int16` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 16 bits
                       *
                       * _Available since v3.1._
                       */
                      function toInt16(int256 value) internal pure returns (int16) {
                          require(value >= -2**15 && value < 2**15, "SafeCast: value doesn\\'t fit in 16 bits");
                          return int16(value);
                      }
                      /**
                       * @dev Returns the downcasted int8 from int256, reverting on
                       * overflow (when the input is less than smallest int8 or
                       * greater than largest int8).
                       *
                       * Counterpart to Solidity's `int8` operator.
                       *
                       * Requirements:
                       *
                       * - input must fit into 8 bits.
                       *
                       * _Available since v3.1._
                       */
                      function toInt8(int256 value) internal pure returns (int8) {
                          require(value >= -2**7 && value < 2**7, "SafeCast: value doesn\\'t fit in 8 bits");
                          return int8(value);
                      }
                      /**
                       * @dev Converts an unsigned uint256 into a signed int256.
                       *
                       * Requirements:
                       *
                       * - input must be less than or equal to maxInt256.
                       */
                      function toInt256(uint256 value) internal pure returns (int256) {
                          require(value < 2**255, "SafeCast: value doesn't fit in an int256");
                          return int256(value);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity >0.5.0 <0.9.0;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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(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 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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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);
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  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 2.0  |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
                    *  decentralised, trustless and compatible with staking in Ethereum 2.0.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  // SPDX-License-Identifier: GPL-3.0-only
                  pragma solidity 0.7.6;
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  import "@openzeppelin/contracts/math/SignedSafeMath.sol";
                  import "@openzeppelin/contracts/utils/SafeCast.sol";
                  import "../RocketBase.sol";
                  import "../../interface/minipool/RocketMinipoolInterface.sol";
                  import "../../interface/minipool/RocketMinipoolQueueInterface.sol";
                  import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
                  import "../../interface/util/AddressQueueStorageInterface.sol";
                  import "../../types/MinipoolDeposit.sol";
                  /// @notice Minipool queueing for deposit assignment
                  contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface {
                      // Libs
                      using SafeMath for uint;
                      using SignedSafeMath for int;
                      // Constants
                      bytes32 private constant queueKeyFull = keccak256("minipools.available.full");
                      bytes32 private constant queueKeyHalf = keccak256("minipools.available.half");
                      bytes32 private constant queueKeyVariable = keccak256("minipools.available.variable");
                      // Events
                      event MinipoolEnqueued(address indexed minipool, bytes32 indexed queueId, uint256 time);
                      event MinipoolDequeued(address indexed minipool, bytes32 indexed queueId, uint256 time);
                      event MinipoolRemoved(address indexed minipool, bytes32 indexed queueId, uint256 time);
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
                          version = 2;
                      }
                      /// @notice Get the total combined length of the queues
                      function getTotalLength() override external view returns (uint256) {
                          return (
                              getLengthLegacy(queueKeyFull)
                          ).add(
                              getLengthLegacy(queueKeyHalf)
                          ).add(
                              getLength()
                          );
                      }
                      /// @notice Returns true if there are any legacy minipools in the queue
                      function getContainsLegacy() override external view returns (bool) {
                          return getLengthLegacy(queueKeyFull).add(getLengthLegacy(queueKeyHalf)) > 0;
                      }
                      /// @notice Get the length of a given queue. Returns 0 for invalid queues
                      /// @param _depositType Which queue to query the length of
                      function getLengthLegacy(MinipoolDeposit _depositType) override external view returns (uint256) {
                          if (_depositType == MinipoolDeposit.Full) { return getLengthLegacy(queueKeyFull); }
                          if (_depositType == MinipoolDeposit.Half) { return getLengthLegacy(queueKeyHalf); }
                          return 0;
                      }
                      /// @dev Returns a queue length by internal key representation
                      /// @param _key The internal key representation of the queue to query the length of
                      function getLengthLegacy(bytes32 _key) private view returns (uint256) {
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          return addressQueueStorage.getLength(_key);
                      }
                      /// @notice Gets the length of the variable (global) queue
                      function getLength() override public view returns (uint256) {
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          return addressQueueStorage.getLength(queueKeyVariable);
                      }
                      /// @notice Get the total combined capacity of the queues
                      function getTotalCapacity() override external view returns (uint256) {
                          RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                          return (
                              getLengthLegacy(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount())
                          ).add(
                              getLengthLegacy(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount())
                          ).add(
                              getVariableCapacity()
                          );
                      }
                      /// @notice Get the total effective capacity of the queues (used in node demand calculation)
                      function getEffectiveCapacity() override external view returns (uint256) {
                          RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                          return (
                              getLengthLegacy(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount())
                          ).add(
                              getLengthLegacy(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount())
                          ).add(
                              getVariableCapacity()
                          );
                      }
                      /// @dev Get the ETH capacity of the variable queue
                      function getVariableCapacity() internal view returns (uint256) {
                          RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                          return getLength().mul(rocketDAOProtocolSettingsMinipool.getVariableDepositAmount());
                      }
                      /// @notice Get the capacity of the next available minipool. Returns 0 if no minipools are available
                      function getNextCapacityLegacy() override external view returns (uint256) {
                          RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                          if (getLengthLegacy(queueKeyHalf) > 0) { return rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount(); }
                          if (getLengthLegacy(queueKeyFull) > 0) { return rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount(); }
                          return 0;
                      }
                      /// @notice Get the deposit type of the next available minipool and the number of deposits in that queue.
                      ///         Returns None if no minipools are available
                      function getNextDepositLegacy() override external view returns (MinipoolDeposit, uint256) {
                          uint256 length = getLengthLegacy(queueKeyHalf);
                          if (length > 0) { return (MinipoolDeposit.Half, length); }
                          length = getLengthLegacy(queueKeyFull);
                          if (length > 0) { return (MinipoolDeposit.Full, length); }
                          return (MinipoolDeposit.None, 0);
                      }
                      /// @dev Add a minipool to the end of the appropriate queue. Only accepts calls from the RocketMinipoolManager contract
                      /// @param _minipool Address of the minipool to add to the queue
                      function enqueueMinipool(address _minipool) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketNodeDeposit", msg.sender) {
                          // Enqueue
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          addressQueueStorage.enqueueItem(queueKeyVariable, _minipool);
                          // Emit enqueued event
                          emit MinipoolEnqueued(_minipool, queueKeyVariable, block.timestamp);
                      }
                      /// @dev Dequeues a minipool from a legacy queue
                      /// @param _depositType The queue to dequeue a minipool from
                      function dequeueMinipoolByDepositLegacy(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address minipoolAddress) {
                          if (_depositType == MinipoolDeposit.Half) { return dequeueMinipool(queueKeyHalf); }
                          if (_depositType == MinipoolDeposit.Full) { return dequeueMinipool(queueKeyFull); }
                          require(false, "No minipools are available");
                      }
                      /// @dev Dequeues multiple minipools from the variable queue and returns them all
                      /// @param _maxToDequeue The maximum number of items to dequeue
                      function dequeueMinipools(uint256 _maxToDequeue) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address[] memory minipoolAddress) {
                          uint256 queueLength = getLength();
                          uint256 count = _maxToDequeue;
                          if (count > queueLength) {
                              count = queueLength;
                          }
                          address[] memory minipoolAddresses = new address[](count);
                          for (uint256 i = 0; i < count; i++) {
                              RocketMinipoolInterface minipool = RocketMinipoolInterface(dequeueMinipool(queueKeyVariable));
                              minipoolAddresses[i] = address(minipool);
                          }
                          return minipoolAddresses;
                      }
                      /// @dev Dequeues a minipool from a queue given an internal key
                      /// @param _key The internal key representation of the queue from which to dequeue a minipool from
                      function dequeueMinipool(bytes32 _key) private returns (address) {
                          // Dequeue
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          address minipool = addressQueueStorage.dequeueItem(_key);
                          // Emit dequeued event
                          emit MinipoolDequeued(minipool, _key, block.timestamp);
                          // Return
                          return minipool;
                      }
                      /// @dev Remove a minipool from a queue. Only accepts calls from registered minipools
                      function removeMinipool(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyRegisteredMinipool(msg.sender) {
                          // Remove minipool from queue
                          if (_depositType == MinipoolDeposit.Half) { return removeMinipool(queueKeyHalf, msg.sender); }
                          if (_depositType == MinipoolDeposit.Full) { return removeMinipool(queueKeyFull, msg.sender); }
                          if (_depositType == MinipoolDeposit.Variable) { return removeMinipool(queueKeyVariable, msg.sender); }
                          require(false, "Invalid minipool deposit type");
                      }
                      /// @dev Removes a minipool from a queue given an internal key
                      /// @param _key The internal key representation of the queue from which to remove a minipool from
                      /// @param _minipool The address of a minipool to remove from the specified queue
                      function removeMinipool(bytes32 _key, address _minipool) private {
                          // Remove
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          addressQueueStorage.removeItem(_key, _minipool);
                          // Emit removed event
                          emit MinipoolRemoved(_minipool, _key, block.timestamp);
                      }
                      /// @notice Returns the minipool address of the minipool in the global queue at a given index
                      /// @param _index The index into the queue to retrieve
                      function getMinipoolAt(uint256 _index) override external view returns(address) {
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          // Check if index is in the half queue
                          uint256 halfLength = addressQueueStorage.getLength(queueKeyHalf);
                          if (_index < halfLength) {
                              return addressQueueStorage.getItem(queueKeyHalf, _index);
                          }
                          _index = _index.sub(halfLength);
                          // Check if index is in the full queue
                          uint256 fullLength = addressQueueStorage.getLength(queueKeyFull);
                          if (_index < fullLength) {
                              return addressQueueStorage.getItem(queueKeyFull, _index);
                          }
                          _index = _index.sub(fullLength);
                          // Check if index is in the full queue
                          uint256 variableLength = addressQueueStorage.getLength(queueKeyVariable);
                          if (_index < variableLength) {
                              return addressQueueStorage.getItem(queueKeyVariable, _index);
                          }
                          // Index is out of bounds
                          return address(0);
                      }
                      /// @notice Returns the position a given minipool is in the queue
                      /// @param _minipool The minipool to query the position of
                      function getMinipoolPosition(address _minipool) override external view returns (int256) {
                          AddressQueueStorageInterface addressQueueStorage = AddressQueueStorageInterface(getContractAddress("addressQueueStorage"));
                          int256 position;
                          // Check in half queue
                          position = addressQueueStorage.getIndexOf(queueKeyHalf, _minipool);
                          if (position != -1) {
                              return position;
                          }
                          int256 offset = SafeCast.toInt256(addressQueueStorage.getLength(queueKeyHalf));
                          // Check in full queue
                          position = addressQueueStorage.getIndexOf(queueKeyFull, _minipool);
                          if (position != -1) {
                              return offset.add(position);
                          }
                          offset = offset.add(SafeCast.toInt256(addressQueueStorage.getLength(queueKeyFull)));
                          // Check in variable queue
                          position = addressQueueStorage.getIndexOf(queueKeyVariable, _minipool);
                          if (position != -1) {
                              return offset.add(position);
                          }
                          // Isn't in the queue
                          return -1;
                      }
                  }
                  

                  File 6 of 8: RocketDAOProtocolSettingsMinipool
                  /**
                     *       .
                     *      / \\
                     *     |.'.|
                     *     |'.'|
                     *   ,'|   |'.
                     *  |,-'-|-'-.|
                     *   __|_| |         _        _      _____           _
                     *  | ___ \\|        | |      | |    | ___ \\         | |
                     *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                     *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                     *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                     *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                     * +---------------------------------------------------+
                     * |    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 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 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 RocketDAOProtocolSettingsInterface {
                      function getSettingUint(string memory _settingPath) external view returns (uint256);
                      function setSettingUint(string memory _settingPath, uint256 _value) external;
                      function getSettingBool(string memory _settingPath) external view returns (bool);
                      function setSettingBool(string memory _settingPath, bool _value) external;
                      function getSettingAddress(string memory _settingPath) external view returns (address);
                      function setSettingAddress(string memory _settingPath, 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;
                  import "../../../RocketBase.sol";
                  import "../../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsInterface.sol";
                  // Settings in RP which the DAO will have full control over
                  // This settings contract enables storage using setting paths with namespaces, rather than explicit set methods
                  abstract contract RocketDAOProtocolSettings is RocketBase, RocketDAOProtocolSettingsInterface {
                      // The namespace for a particular group of settings
                      bytes32 settingNameSpace;
                      // Only allow updating from the DAO proposals contract
                      modifier onlyDAOProtocolProposal() {
                          // If this contract has been initialised, only allow access from the proposals contract
                          if(getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) require(getContractAddress("rocketDAOProtocolProposals") == msg.sender, "Only DAO Protocol Proposals contract can update a setting");
                          _;
                      }
                      // Construct
                      constructor(RocketStorageInterface _rocketStorageAddress, string memory _settingNameSpace) RocketBase(_rocketStorageAddress) {
                          // Apply the setting namespace
                          settingNameSpace = keccak256(abi.encodePacked("dao.protocol.setting.", _settingNameSpace));
                      }
                      /*** Uints  ****************/
                      // A general method to return any setting given the setting path is correct, only accepts uints
                      function getSettingUint(string memory _settingPath) public view override returns (uint256) {
                          return getUint(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
                      } 
                      // Update a Uint setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
                      function setSettingUint(string memory _settingPath, uint256 _value) virtual public override onlyDAOProtocolProposal {
                          // Update setting now
                          setUint(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
                      } 
                     
                      /*** Bools  ****************/
                      // A general method to return any setting given the setting path is correct, only accepts bools
                      function getSettingBool(string memory _settingPath) public view override returns (bool) {
                          return getBool(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
                      } 
                      // Update a setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
                      function setSettingBool(string memory _settingPath, bool _value) virtual public override onlyDAOProtocolProposal {
                          // Update setting now
                          setBool(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
                      }
                      
                      /*** Addresses  ****************/
                      // A general method to return any setting given the setting path is correct, only accepts addresses
                      function getSettingAddress(string memory _settingPath) external view override returns (address) {
                          return getAddress(keccak256(abi.encodePacked(settingNameSpace, _settingPath)));
                      } 
                      // Update a setting, can only be executed by the DAO contract when a majority on a setting proposal has passed and been executed
                      function setSettingAddress(string memory _settingPath, address _value) virtual external override onlyDAOProtocolProposal {
                          // Update setting now
                          setAddress(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _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;
                  // 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);
                  }
                  /**
                     *       .
                     *      / \\
                     *     |.'.|
                     *     |'.'|
                     *   ,'|   |'.
                     *  |,-'-|-'-.|
                     *   __|_| |         _        _      _____           _
                     *  | ___ \\|        | |      | |    | ___ \\         | |
                     *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                     *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                     *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                     *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                     * +---------------------------------------------------+
                     * |    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 RocketDAONodeTrustedSettingsMinipoolInterface {
                      function getScrubPeriod() external view returns(uint256);
                      function getPromotionScrubPeriod() external view returns(uint256);
                      function getScrubQuorum() external view returns(uint256);
                      function getCancelBondReductionQuorum() external view returns(uint256);
                      function getScrubPenaltyEnabled() external view returns(bool);
                      function isWithinBondReductionWindow(uint256 _time) external view returns (bool);
                      function getBondReductionWindowStart() external view returns (uint256);
                      function getBondReductionWindowLength() 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.8.18;
                  import "./RocketDAOProtocolSettings.sol";
                  import "../../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
                  import "../../../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol";
                  import "../../../../types/MinipoolDeposit.sol";
                  /// @notice Network minipool settings
                  contract RocketDAOProtocolSettingsMinipool is RocketDAOProtocolSettings, RocketDAOProtocolSettingsMinipoolInterface {
                      uint256 constant internal minipoolUserDistributeWindowStart = 90 days;
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketDAOProtocolSettings(_rocketStorageAddress, "minipool") {
                          version = 3;
                          // Initialize settings on deployment
                          if(!getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) {
                              // Apply settings
                              setSettingBool("minipool.submit.withdrawable.enabled", false);
                              setSettingBool("minipool.bond.reduction.enabled", false);
                              setSettingUint("minipool.launch.timeout", 72 hours);
                              setSettingUint("minipool.maximum.count", 14);
                              setSettingUint("minipool.user.distribute.window.length", 2 days);
                              // Settings initialised
                              setBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")), true);
                          }
                      }
                      /// @notice Update a setting, overrides inherited setting method with extra checks for this contract
                      /// @param _settingPath The path of the setting within this contract's namespace
                      /// @param _value The value to set it to
                      function setSettingUint(string memory _settingPath, uint256 _value) override public onlyDAOProtocolProposal {
                          // Some safety guards for certain settings
                          if(getBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")))) {
                              bytes32 settingKey = keccak256(abi.encodePacked(_settingPath));
                              if(settingKey == keccak256(abi.encodePacked("minipool.launch.timeout"))) {
                                  RocketDAONodeTrustedSettingsMinipoolInterface rocketDAONodeTrustedSettingsMinipool = RocketDAONodeTrustedSettingsMinipoolInterface(getContractAddress("rocketDAONodeTrustedSettingsMinipool"));
                                  require(_value >= (rocketDAONodeTrustedSettingsMinipool.getScrubPeriod() + 1 hours), "Launch timeout must be greater than scrub period");
                                  // >= 12 hours (RPIP-33)
                                  require(_value >= 12 hours, "Launch timeout must be greater than 12 hours");
                              } 
                          }
                          // Update setting now
                          setUint(keccak256(abi.encodePacked(settingNameSpace, _settingPath)), _value);
                      }
                      /// @notice Returns the balance required to launch minipool
                      function getLaunchBalance() override public pure returns (uint256) {
                          return 32 ether;
                      }
                      /// @notice Returns the value required to pre-launch a minipool
                      function getPreLaunchValue() override public pure returns (uint256) {
                          return 1 ether;
                      }
                      /// @notice Returns the deposit amount for a given deposit type (only used for legacy minipool types)
                      function getDepositUserAmount(MinipoolDeposit _depositType) override external pure returns (uint256) {
                          if (_depositType == MinipoolDeposit.Full) { return getFullDepositUserAmount(); }
                          if (_depositType == MinipoolDeposit.Half) { return getHalfDepositUserAmount(); }
                          return 0;
                      }
                      /// @notice Returns the user amount for a "Full" deposit minipool
                      function getFullDepositUserAmount() override public pure returns (uint256) {
                          return getLaunchBalance() / 2;
                      }
                      /// @notice Returns the user amount for a "Half" deposit minipool
                      function getHalfDepositUserAmount() override public pure returns (uint256) {
                          return getLaunchBalance() / 2;
                      }
                      /// @notice Returns the amount a "Variable" minipool requires to move to staking status
                      function getVariableDepositAmount() override public pure returns (uint256) {
                          return getLaunchBalance() - getPreLaunchValue();
                      }
                      /// @notice Submit minipool withdrawable events currently enabled (trusted nodes only)
                      function getSubmitWithdrawableEnabled() override external view returns (bool) {
                          return getSettingBool("minipool.submit.withdrawable.enabled");
                      }
                      /// @notice Returns true if bond reductions are currentl enabled
                      function getBondReductionEnabled() override external view returns (bool) {
                          return getSettingBool("minipool.bond.reduction.enabled");
                      }
                      /// @notice Returns the timeout period in seconds for prelaunch minipools to launch
                      function getLaunchTimeout() override external view returns (uint256) {
                          return getSettingUint("minipool.launch.timeout");
                      }
                      /// @notice Returns the maximum number of minipools allowed at one time
                      function getMaximumCount() override external view returns (uint256) {
                        return getSettingUint("minipool.maximum.count");
                      }
                      /// @notice Returns true if the given time is within the user distribute window
                      function isWithinUserDistributeWindow(uint256 _time) override external view returns (bool) {
                          uint256 start = getUserDistributeWindowStart();
                          uint256 length = getUserDistributeWindowLength();
                          return (_time >= start && _time < (start + length));
                      }
                      /// @notice Returns true if the given time has passed the distribute window
                      function hasUserDistributeWindowPassed(uint256 _time) override external view returns (bool) {
                          uint256 start = getUserDistributeWindowStart();
                          uint256 length = getUserDistributeWindowLength();
                          return _time >= start + length;
                      }
                      /// @notice Returns the start of the user distribute window
                      function getUserDistributeWindowStart() override public pure returns (uint256) {
                          return minipoolUserDistributeWindowStart;
                      }
                      /// @notice Returns the length of the user distribute window
                      function getUserDistributeWindowLength() override public view returns (uint256) {
                          return getSettingUint("minipool.user.distribute.window.length");
                      }
                  }
                  

                  File 7 of 8: AddressQueueStorage
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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(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 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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  import "../RocketBase.sol";
                  import "../../interface/util/AddressQueueStorageInterface.sol";
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  // Address queue storage helper for RocketStorage data (ring buffer implementation)
                  contract AddressQueueStorage is RocketBase, AddressQueueStorageInterface {
                      // Libs
                      using SafeMath for uint256;
                      // Settings
                      uint256 constant public capacity = 2 ** 255; // max uint256 / 2
                      // Construct
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
                          version = 1;
                      }
                      // The number of items in a queue
                      function getLength(bytes32 _key) override public view returns (uint) {
                          uint start = getUint(keccak256(abi.encodePacked(_key, ".start")));
                          uint end = getUint(keccak256(abi.encodePacked(_key, ".end")));
                          if (end < start) { end = end.add(capacity); }
                          return end.sub(start);
                      }
                      // The item in a queue by index
                      function getItem(bytes32 _key, uint _index) override external view returns (address) {
                          uint index = getUint(keccak256(abi.encodePacked(_key, ".start"))).add(_index);
                          if (index >= capacity) { index = index.sub(capacity); }
                          return getAddress(keccak256(abi.encodePacked(_key, ".item", index)));
                      }
                      // The index of an item in a queue
                      // Returns -1 if the value is not found
                      function getIndexOf(bytes32 _key, address _value) override external view returns (int) {
                          int index = int(getUint(keccak256(abi.encodePacked(_key, ".index", _value)))) - 1;
                          if (index != -1) {
                              index -= int(getUint(keccak256(abi.encodePacked(_key, ".start"))));
                              if (index < 0) { index += int(capacity); }
                          }
                          return index;
                      }
                      // Add an item to the end of a queue
                      // Requires that the queue is not at capacity
                      // Requires that the item does not exist in the queue
                      function enqueueItem(bytes32 _key, address _value) override external onlyLatestContract("addressQueueStorage", address(this)) onlyLatestNetworkContract {
                          require(getLength(_key) < capacity.sub(1), "Queue is at capacity");
                          require(getUint(keccak256(abi.encodePacked(_key, ".index", _value))) == 0, "Item already exists in queue");
                          uint index = getUint(keccak256(abi.encodePacked(_key, ".end")));
                          setAddress(keccak256(abi.encodePacked(_key, ".item", index)), _value);
                          setUint(keccak256(abi.encodePacked(_key, ".index", _value)), index.add(1));
                          index = index.add(1);
                          if (index >= capacity) { index = index.sub(capacity); }
                          setUint(keccak256(abi.encodePacked(_key, ".end")), index);
                      }
                      // Remove an item from the start of a queue and return it
                      // Requires that the queue is not empty
                      function dequeueItem(bytes32 _key) override external onlyLatestContract("addressQueueStorage", address(this)) onlyLatestNetworkContract returns (address) {
                          require(getLength(_key) > 0, "Queue is empty");
                          uint start = getUint(keccak256(abi.encodePacked(_key, ".start")));
                          address item = getAddress(keccak256(abi.encodePacked(_key, ".item", start)));
                          start = start.add(1);
                          if (start >= capacity) { start = start.sub(capacity); }
                          setUint(keccak256(abi.encodePacked(_key, ".index", item)), 0);
                          setUint(keccak256(abi.encodePacked(_key, ".start")), start);
                          return item;
                      }
                      // Remove an item from a queue
                      // Swaps the item with the last item in the queue and truncates it; computationally cheap
                      // Requires that the item exists in the queue
                      function removeItem(bytes32 _key, address _value) override external onlyLatestContract("addressQueueStorage", address(this)) onlyLatestNetworkContract {
                          uint index = getUint(keccak256(abi.encodePacked(_key, ".index", _value)));
                          require(index-- > 0, "Item does not exist in queue");
                          uint lastIndex = getUint(keccak256(abi.encodePacked(_key, ".end")));
                          if (lastIndex == 0) lastIndex = capacity;
                          lastIndex = lastIndex.sub(1);
                          if (index != lastIndex) {
                              address lastItem = getAddress(keccak256(abi.encodePacked(_key, ".item", lastIndex)));
                              setAddress(keccak256(abi.encodePacked(_key, ".item", index)), lastItem);
                              setUint(keccak256(abi.encodePacked(_key, ".index", lastItem)), index.add(1));
                          }
                          setUint(keccak256(abi.encodePacked(_key, ".index", _value)), 0);
                          setUint(keccak256(abi.encodePacked(_key, ".end")), lastIndex);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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;
                  }
                  

                  File 8 of 8: RocketVault
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Wrappers over Solidity's arithmetic operations with added overflow
                   * checks.
                   *
                   * Arithmetic operations in Solidity wrap on overflow. This can easily result
                   * in bugs, because programmers usually assume that an overflow raises an
                   * error, which is the standard behavior in high level programming languages.
                   * `SafeMath` restores this intuition by reverting the transaction when an
                   * operation overflows.
                   *
                   * Using this library instead of the unchecked operations eliminates an entire
                   * class of bugs, so it's recommended to use it always.
                   */
                  library SafeMath {
                      /**
                       * @dev Returns the addition of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          uint256 c = a + b;
                          if (c < a) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the substraction of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b > a) return (false, 0);
                          return (true, a - b);
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
                          // benefit is lost if 'b' is also tested.
                          // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
                          if (a == 0) return (true, 0);
                          uint256 c = a * b;
                          if (c / a != b) return (false, 0);
                          return (true, c);
                      }
                      /**
                       * @dev Returns the division of two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a / b);
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
                       *
                       * _Available since v3.4._
                       */
                      function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
                          if (b == 0) return (false, 0);
                          return (true, a % b);
                      }
                      /**
                       * @dev Returns the addition of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `+` operator.
                       *
                       * Requirements:
                       *
                       * - Addition cannot overflow.
                       */
                      function add(uint256 a, uint256 b) internal pure returns (uint256) {
                          uint256 c = a + b;
                          require(c >= a, "SafeMath: addition overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting on
                       * overflow (when the result is negative).
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b <= a, "SafeMath: subtraction overflow");
                          return a - b;
                      }
                      /**
                       * @dev Returns the multiplication of two unsigned integers, reverting on
                       * overflow.
                       *
                       * Counterpart to Solidity's `*` operator.
                       *
                       * Requirements:
                       *
                       * - Multiplication cannot overflow.
                       */
                      function mul(uint256 a, uint256 b) internal pure returns (uint256) {
                          if (a == 0) return 0;
                          uint256 c = a * b;
                          require(c / a == b, "SafeMath: multiplication overflow");
                          return c;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting on
                       * division by zero. The result is rounded towards zero.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: division by zero");
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting when dividing by zero.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b) internal pure returns (uint256) {
                          require(b > 0, "SafeMath: modulo by zero");
                          return a % b;
                      }
                      /**
                       * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
                       * overflow (when the result is negative).
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {trySub}.
                       *
                       * Counterpart to Solidity's `-` operator.
                       *
                       * Requirements:
                       *
                       * - Subtraction cannot overflow.
                       */
                      function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b <= a, errorMessage);
                          return a - b;
                      }
                      /**
                       * @dev Returns the integer division of two unsigned integers, reverting with custom message on
                       * division by zero. The result is rounded towards zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryDiv}.
                       *
                       * Counterpart to Solidity's `/` operator. Note: this function uses a
                       * `revert` opcode (which leaves remaining gas untouched) while Solidity
                       * uses an invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a / b;
                      }
                      /**
                       * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
                       * reverting with custom message when dividing by zero.
                       *
                       * CAUTION: This function is deprecated because it requires allocating memory for the error
                       * message unnecessarily. For custom revert reasons use {tryMod}.
                       *
                       * Counterpart to Solidity's `%` operator. This function uses a `revert`
                       * opcode (which leaves remaining gas untouched) while Solidity uses an
                       * invalid opcode to revert (consuming all remaining gas).
                       *
                       * Requirements:
                       *
                       * - The divisor cannot be zero.
                       */
                      function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
                          require(b > 0, errorMessage);
                          return a % b;
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../../utils/Context.sol";
                  import "./IERC20.sol";
                  import "../../math/SafeMath.sol";
                  /**
                   * @dev Implementation of the {IERC20} interface.
                   *
                   * This implementation is agnostic to the way tokens are created. This means
                   * that a supply mechanism has to be added in a derived contract using {_mint}.
                   * For a generic mechanism see {ERC20PresetMinterPauser}.
                   *
                   * TIP: For a detailed writeup see our guide
                   * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
                   * to implement supply mechanisms].
                   *
                   * We have followed general OpenZeppelin guidelines: functions revert instead
                   * of returning `false` on failure. This behavior is nonetheless conventional
                   * and does not conflict with the expectations of ERC20 applications.
                   *
                   * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
                   * This allows applications to reconstruct the allowance for all accounts just
                   * by listening to said events. Other implementations of the EIP may not emit
                   * these events, as it isn't required by the specification.
                   *
                   * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
                   * functions have been added to mitigate the well-known issues around setting
                   * allowances. See {IERC20-approve}.
                   */
                  contract ERC20 is Context, IERC20 {
                      using SafeMath for uint256;
                      mapping (address => uint256) private _balances;
                      mapping (address => mapping (address => uint256)) private _allowances;
                      uint256 private _totalSupply;
                      string private _name;
                      string private _symbol;
                      uint8 private _decimals;
                      /**
                       * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
                       * a default value of 18.
                       *
                       * To select a different value for {decimals}, use {_setupDecimals}.
                       *
                       * All three of these values are immutable: they can only be set once during
                       * construction.
                       */
                      constructor (string memory name_, string memory symbol_) public {
                          _name = name_;
                          _symbol = symbol_;
                          _decimals = 18;
                      }
                      /**
                       * @dev Returns the name of the token.
                       */
                      function name() public view virtual returns (string memory) {
                          return _name;
                      }
                      /**
                       * @dev Returns the symbol of the token, usually a shorter version of the
                       * name.
                       */
                      function symbol() public view virtual returns (string memory) {
                          return _symbol;
                      }
                      /**
                       * @dev Returns the number of decimals used to get its user representation.
                       * For example, if `decimals` equals `2`, a balance of `505` tokens should
                       * be displayed to a user as `5,05` (`505 / 10 ** 2`).
                       *
                       * Tokens usually opt for a value of 18, imitating the relationship between
                       * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
                       * called.
                       *
                       * NOTE: This information is only used for _display_ purposes: it in
                       * no way affects any of the arithmetic of the contract, including
                       * {IERC20-balanceOf} and {IERC20-transfer}.
                       */
                      function decimals() public view virtual returns (uint8) {
                          return _decimals;
                      }
                      /**
                       * @dev See {IERC20-totalSupply}.
                       */
                      function totalSupply() public view virtual override returns (uint256) {
                          return _totalSupply;
                      }
                      /**
                       * @dev See {IERC20-balanceOf}.
                       */
                      function balanceOf(address account) public view virtual override returns (uint256) {
                          return _balances[account];
                      }
                      /**
                       * @dev See {IERC20-transfer}.
                       *
                       * Requirements:
                       *
                       * - `recipient` cannot be the zero address.
                       * - the caller must have a balance of at least `amount`.
                       */
                      function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(_msgSender(), recipient, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-allowance}.
                       */
                      function allowance(address owner, address spender) public view virtual override returns (uint256) {
                          return _allowances[owner][spender];
                      }
                      /**
                       * @dev See {IERC20-approve}.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function approve(address spender, uint256 amount) public virtual override returns (bool) {
                          _approve(_msgSender(), spender, amount);
                          return true;
                      }
                      /**
                       * @dev See {IERC20-transferFrom}.
                       *
                       * Emits an {Approval} event indicating the updated allowance. This is not
                       * required by the EIP. See the note at the beginning of {ERC20}.
                       *
                       * Requirements:
                       *
                       * - `sender` and `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       * - the caller must have allowance for ``sender``'s tokens of at least
                       * `amount`.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
                          _transfer(sender, recipient, amount);
                          _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
                          return true;
                      }
                      /**
                       * @dev Atomically increases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       */
                      function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
                          return true;
                      }
                      /**
                       * @dev Atomically decreases the allowance granted to `spender` by the caller.
                       *
                       * This is an alternative to {approve} that can be used as a mitigation for
                       * problems described in {IERC20-approve}.
                       *
                       * Emits an {Approval} event indicating the updated allowance.
                       *
                       * Requirements:
                       *
                       * - `spender` cannot be the zero address.
                       * - `spender` must have allowance for the caller of at least
                       * `subtractedValue`.
                       */
                      function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
                          _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
                          return true;
                      }
                      /**
                       * @dev Moves tokens `amount` from `sender` to `recipient`.
                       *
                       * This is internal function is equivalent to {transfer}, and can be used to
                       * e.g. implement automatic token fees, slashing mechanisms, etc.
                       *
                       * Emits a {Transfer} event.
                       *
                       * Requirements:
                       *
                       * - `sender` cannot be the zero address.
                       * - `recipient` cannot be the zero address.
                       * - `sender` must have a balance of at least `amount`.
                       */
                      function _transfer(address sender, address recipient, uint256 amount) internal virtual {
                          require(sender != address(0), "ERC20: transfer from the zero address");
                          require(recipient != address(0), "ERC20: transfer to the zero address");
                          _beforeTokenTransfer(sender, recipient, amount);
                          _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
                          _balances[recipient] = _balances[recipient].add(amount);
                          emit Transfer(sender, recipient, amount);
                      }
                      /** @dev Creates `amount` tokens and assigns them to `account`, increasing
                       * the total supply.
                       *
                       * Emits a {Transfer} event with `from` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `to` cannot be the zero address.
                       */
                      function _mint(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: mint to the zero address");
                          _beforeTokenTransfer(address(0), account, amount);
                          _totalSupply = _totalSupply.add(amount);
                          _balances[account] = _balances[account].add(amount);
                          emit Transfer(address(0), account, amount);
                      }
                      /**
                       * @dev Destroys `amount` tokens from `account`, reducing the
                       * total supply.
                       *
                       * Emits a {Transfer} event with `to` set to the zero address.
                       *
                       * Requirements:
                       *
                       * - `account` cannot be the zero address.
                       * - `account` must have at least `amount` tokens.
                       */
                      function _burn(address account, uint256 amount) internal virtual {
                          require(account != address(0), "ERC20: burn from the zero address");
                          _beforeTokenTransfer(account, address(0), amount);
                          _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
                          _totalSupply = _totalSupply.sub(amount);
                          emit Transfer(account, address(0), amount);
                      }
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
                       *
                       * This internal function is equivalent to `approve`, and can be used to
                       * e.g. set automatic allowances for certain subsystems, etc.
                       *
                       * Emits an {Approval} event.
                       *
                       * Requirements:
                       *
                       * - `owner` cannot be the zero address.
                       * - `spender` cannot be the zero address.
                       */
                      function _approve(address owner, address spender, uint256 amount) internal virtual {
                          require(owner != address(0), "ERC20: approve from the zero address");
                          require(spender != address(0), "ERC20: approve to the zero address");
                          _allowances[owner][spender] = amount;
                          emit Approval(owner, spender, amount);
                      }
                      /**
                       * @dev Sets {decimals} to a value other than the default one of 18.
                       *
                       * WARNING: This function should only be called from the constructor. Most
                       * applications that interact with token contracts will not expect
                       * {decimals} to ever change, and may work incorrectly if it does.
                       */
                      function _setupDecimals(uint8 decimals_) internal virtual {
                          _decimals = decimals_;
                      }
                      /**
                       * @dev Hook that is called before any transfer of tokens. This includes
                       * minting and burning.
                       *
                       * Calling conditions:
                       *
                       * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
                       * will be to transferred to `to`.
                       * - when `from` is zero, `amount` tokens will be minted for `to`.
                       * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
                       * - `from` and `to` are never both zero.
                       *
                       * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
                       */
                      function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "../../utils/Context.sol";
                  import "./ERC20.sol";
                  /**
                   * @dev Extension of {ERC20} that allows token holders to destroy both their own
                   * tokens and those that they have an allowance for, in a way that can be
                   * recognized off-chain (via event analysis).
                   */
                  abstract contract ERC20Burnable is Context, ERC20 {
                      using SafeMath for uint256;
                      /**
                       * @dev Destroys `amount` tokens from the caller.
                       *
                       * See {ERC20-_burn}.
                       */
                      function burn(uint256 amount) public virtual {
                          _burn(_msgSender(), amount);
                      }
                      /**
                       * @dev Destroys `amount` tokens from `account`, deducting from the caller's
                       * allowance.
                       *
                       * See {ERC20-_burn} and {ERC20-allowance}.
                       *
                       * Requirements:
                       *
                       * - the caller must have allowance for ``accounts``'s tokens of at least
                       * `amount`.
                       */
                      function burnFrom(address account, uint256 amount) public virtual {
                          uint256 decreasedAllowance = allowance(account, _msgSender()).sub(amount, "ERC20: burn amount exceeds allowance");
                          _approve(account, _msgSender(), decreasedAllowance);
                          _burn(account, amount);
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /**
                   * @dev Interface of the ERC20 standard as defined in the EIP.
                   */
                  interface IERC20 {
                      /**
                       * @dev Returns the amount of tokens in existence.
                       */
                      function totalSupply() external view returns (uint256);
                      /**
                       * @dev Returns the amount of tokens owned by `account`.
                       */
                      function balanceOf(address account) external view returns (uint256);
                      /**
                       * @dev Moves `amount` tokens from the caller's account to `recipient`.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transfer(address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Returns the remaining number of tokens that `spender` will be
                       * allowed to spend on behalf of `owner` through {transferFrom}. This is
                       * zero by default.
                       *
                       * This value changes when {approve} or {transferFrom} are called.
                       */
                      function allowance(address owner, address spender) external view returns (uint256);
                      /**
                       * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * IMPORTANT: Beware that changing an allowance with this method brings the risk
                       * that someone may use both the old and the new allowance by unfortunate
                       * transaction ordering. One possible solution to mitigate this race
                       * condition is to first reduce the spender's allowance to 0 and set the
                       * desired value afterwards:
                       * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
                       *
                       * Emits an {Approval} event.
                       */
                      function approve(address spender, uint256 amount) external returns (bool);
                      /**
                       * @dev Moves `amount` tokens from `sender` to `recipient` using the
                       * allowance mechanism. `amount` is then deducted from the caller's
                       * allowance.
                       *
                       * Returns a boolean value indicating whether the operation succeeded.
                       *
                       * Emits a {Transfer} event.
                       */
                      function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
                      /**
                       * @dev Emitted when `value` tokens are moved from one account (`from`) to
                       * another (`to`).
                       *
                       * Note that `value` may be zero.
                       */
                      event Transfer(address indexed from, address indexed to, uint256 value);
                      /**
                       * @dev Emitted when the allowance of a `spender` for an `owner` is set by
                       * a call to {approve}. `value` is the new allowance.
                       */
                      event Approval(address indexed owner, address indexed spender, uint256 value);
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  import "./IERC20.sol";
                  import "../../math/SafeMath.sol";
                  import "../../utils/Address.sol";
                  /**
                   * @title SafeERC20
                   * @dev Wrappers around ERC20 operations that throw on failure (when the token
                   * contract returns false). Tokens that return no value (and instead revert or
                   * throw on failure) are also supported, non-reverting calls are assumed to be
                   * successful.
                   * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
                   * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
                   */
                  library SafeERC20 {
                      using SafeMath for uint256;
                      using Address for address;
                      function safeTransfer(IERC20 token, address to, uint256 value) internal {
                          _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
                      }
                      function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
                          _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
                      }
                      /**
                       * @dev Deprecated. This function has issues similar to the ones found in
                       * {IERC20-approve}, and its usage is discouraged.
                       *
                       * Whenever possible, use {safeIncreaseAllowance} and
                       * {safeDecreaseAllowance} instead.
                       */
                      function safeApprove(IERC20 token, address spender, uint256 value) internal {
                          // safeApprove should only be called when setting an initial allowance,
                          // or when resetting it to zero. To increase and decrease it, use
                          // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
                          // solhint-disable-next-line max-line-length
                          require((value == 0) || (token.allowance(address(this), spender) == 0),
                              "SafeERC20: approve from non-zero to non-zero allowance"
                          );
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
                      }
                      function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                          uint256 newAllowance = token.allowance(address(this), spender).add(value);
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                      }
                      function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
                          uint256 newAllowance = token.allowance(address(this), spender).sub(value, "SafeERC20: decreased allowance below zero");
                          _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
                      }
                      /**
                       * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
                       * on the return value: the return value is optional (but if data is returned, it must not be false).
                       * @param token The token targeted by the call.
                       * @param data The call data (encoded using abi.encode or one of its variants).
                       */
                      function _callOptionalReturn(IERC20 token, bytes memory data) private {
                          // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
                          // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
                          // the target address contains contract code and also asserts for success in the low-level call.
                          bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
                          if (returndata.length > 0) { // Return data is optional
                              // solhint-disable-next-line max-line-length
                              require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.2 <0.8.0;
                  /**
                   * @dev Collection of functions related to the address type
                   */
                  library Address {
                      /**
                       * @dev Returns true if `account` is a contract.
                       *
                       * [IMPORTANT]
                       * ====
                       * It is unsafe to assume that an address for which this function returns
                       * false is an externally-owned account (EOA) and not a contract.
                       *
                       * Among others, `isContract` will return false for the following
                       * types of addresses:
                       *
                       *  - an externally-owned account
                       *  - a contract in construction
                       *  - an address where a contract will be created
                       *  - an address where a contract lived, but was destroyed
                       * ====
                       */
                      function isContract(address account) internal view returns (bool) {
                          // This method relies on extcodesize, which returns 0 for contracts in
                          // construction, since the code is only stored at the end of the
                          // constructor execution.
                          uint256 size;
                          // solhint-disable-next-line no-inline-assembly
                          assembly { size := extcodesize(account) }
                          return size > 0;
                      }
                      /**
                       * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
                       * `recipient`, forwarding all available gas and reverting on errors.
                       *
                       * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
                       * of certain opcodes, possibly making contracts go over the 2300 gas limit
                       * imposed by `transfer`, making them unable to receive funds via
                       * `transfer`. {sendValue} removes this limitation.
                       *
                       * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
                       *
                       * IMPORTANT: because control is transferred to `recipient`, care must be
                       * taken to not create reentrancy vulnerabilities. Consider using
                       * {ReentrancyGuard} or the
                       * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
                       */
                      function sendValue(address payable recipient, uint256 amount) internal {
                          require(address(this).balance >= amount, "Address: insufficient balance");
                          // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
                          (bool success, ) = recipient.call{ value: amount }("");
                          require(success, "Address: unable to send value, recipient may have reverted");
                      }
                      /**
                       * @dev Performs a Solidity function call using a low level `call`. A
                       * plain`call` is an unsafe replacement for a function call: use this
                       * function instead.
                       *
                       * If `target` reverts with a revert reason, it is bubbled up by this
                       * function (like regular Solidity function calls).
                       *
                       * Returns the raw returned data. To convert to the expected return value,
                       * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
                       *
                       * Requirements:
                       *
                       * - `target` must be a contract.
                       * - calling `target` with `data` must not revert.
                       *
                       * _Available since v3.1._
                       */
                      function functionCall(address target, bytes memory data) internal returns (bytes memory) {
                        return functionCall(target, data, "Address: low-level call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
                       * `errorMessage` as a fallback revert reason when `target` reverts.
                       *
                       * _Available since v3.1._
                       */
                      function functionCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                          return functionCallWithValue(target, data, 0, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but also transferring `value` wei to `target`.
                       *
                       * Requirements:
                       *
                       * - the calling contract must have an ETH balance of at least `value`.
                       * - the called Solidity function must be `payable`.
                       *
                       * _Available since v3.1._
                       */
                      function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
                          return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
                       * with `errorMessage` as a fallback revert reason when `target` reverts.
                       *
                       * _Available since v3.1._
                       */
                      function functionCallWithValue(address target, bytes memory data, uint256 value, string memory errorMessage) internal returns (bytes memory) {
                          require(address(this).balance >= value, "Address: insufficient balance for call");
                          require(isContract(target), "Address: call to non-contract");
                          // solhint-disable-next-line avoid-low-level-calls
                          (bool success, bytes memory returndata) = target.call{ value: value }(data);
                          return _verifyCallResult(success, returndata, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but performing a static call.
                       *
                       * _Available since v3.3._
                       */
                      function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
                          return functionStaticCall(target, data, "Address: low-level static call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                       * but performing a static call.
                       *
                       * _Available since v3.3._
                       */
                      function functionStaticCall(address target, bytes memory data, string memory errorMessage) internal view returns (bytes memory) {
                          require(isContract(target), "Address: static call to non-contract");
                          // solhint-disable-next-line avoid-low-level-calls
                          (bool success, bytes memory returndata) = target.staticcall(data);
                          return _verifyCallResult(success, returndata, errorMessage);
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
                       * but performing a delegate call.
                       *
                       * _Available since v3.4._
                       */
                      function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
                          return functionDelegateCall(target, data, "Address: low-level delegate call failed");
                      }
                      /**
                       * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
                       * but performing a delegate call.
                       *
                       * _Available since v3.4._
                       */
                      function functionDelegateCall(address target, bytes memory data, string memory errorMessage) internal returns (bytes memory) {
                          require(isContract(target), "Address: delegate call to non-contract");
                          // solhint-disable-next-line avoid-low-level-calls
                          (bool success, bytes memory returndata) = target.delegatecall(data);
                          return _verifyCallResult(success, returndata, errorMessage);
                      }
                      function _verifyCallResult(bool success, bytes memory returndata, string memory errorMessage) private pure returns(bytes memory) {
                          if (success) {
                              return returndata;
                          } else {
                              // Look for revert reason and bubble it up if present
                              if (returndata.length > 0) {
                                  // The easiest way to bubble the revert reason is using memory via assembly
                                  // solhint-disable-next-line no-inline-assembly
                                  assembly {
                                      let returndata_size := mload(returndata)
                                      revert(add(32, returndata), returndata_size)
                                  }
                              } else {
                                  revert(errorMessage);
                              }
                          }
                      }
                  }
                  // SPDX-License-Identifier: MIT
                  pragma solidity >=0.6.0 <0.8.0;
                  /*
                   * @dev Provides information about the current execution context, including the
                   * sender of the transaction and its data. While these are generally available
                   * via msg.sender and msg.data, they should not be accessed in such a direct
                   * manner, since when dealing with GSN meta-transactions the account sending and
                   * paying for execution may not be the actual sender (as far as an application
                   * is concerned).
                   *
                   * This contract is only required for intermediate, library-like contracts.
                   */
                  abstract contract Context {
                      function _msgSender() internal view virtual returns (address payable) {
                          return msg.sender;
                      }
                      function _msgData() internal view virtual returns (bytes memory) {
                          this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
                          return msg.data;
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // 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(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 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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "./RocketBase.sol";
                  import "../interface/RocketVaultInterface.sol";
                  import "../interface/RocketVaultWithdrawerInterface.sol";
                  import "@openzeppelin/contracts/math/SafeMath.sol";
                  import "@openzeppelin/contracts/token/ERC20/SafeERC20.sol";
                  import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.sol";
                  // ETH and rETH are stored here to prevent contract upgrades from affecting balances
                  // The RocketVault contract must not be upgraded
                  contract RocketVault is RocketBase, RocketVaultInterface {
                      // Libs
                      using SafeMath for uint;
                      using SafeERC20 for IERC20;
                      // Network contract balances
                      mapping(string => uint256) etherBalances;
                      mapping(bytes32 => uint256) tokenBalances;
                      // Events
                      event EtherDeposited(string indexed by, uint256 amount, uint256 time);
                      event EtherWithdrawn(string indexed by, uint256 amount, uint256 time);
                      event TokenDeposited(bytes32 indexed by, address indexed tokenAddress, uint256 amount, uint256 time);
                      event TokenWithdrawn(bytes32 indexed by, address indexed tokenAddress, uint256 amount, uint256 time);
                      event TokenBurned(bytes32 indexed by, address indexed tokenAddress, uint256 amount, uint256 time);
                      event TokenTransfer(bytes32 indexed by, bytes32 indexed to, address indexed tokenAddress, uint256 amount, uint256 time);
                  \t// Construct
                      constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
                          version = 1;
                      }
                      // Get a contract's ETH balance by address
                      function balanceOf(string memory _networkContractName) override external view returns (uint256) {
                          // Return balance
                          return etherBalances[_networkContractName];
                      }
                      // Get the balance of a token held by a network contract
                      function balanceOfToken(string memory _networkContractName, IERC20 _tokenAddress) override external view returns (uint256) {
                          // Return balance
                          return tokenBalances[keccak256(abi.encodePacked(_networkContractName, _tokenAddress))];
                      }
                      // Accept an ETH deposit from a network contract
                      // Only accepts calls from Rocket Pool network contracts
                      function depositEther() override external payable onlyLatestNetworkContract {
                          // Valid amount?
                          require(msg.value > 0, "No valid amount of ETH given to deposit");
                          // Get contract key
                          string memory contractName = getContractName(msg.sender);
                          // Update contract balance
                          etherBalances[contractName] = etherBalances[contractName].add(msg.value);
                          // Emit ether deposited event
                          emit EtherDeposited(contractName, msg.value, block.timestamp);
                      }
                      // Withdraw an amount of ETH to a network contract
                      // Only accepts calls from Rocket Pool network contracts
                      function withdrawEther(uint256 _amount) override external onlyLatestNetworkContract {
                          // Valid amount?
                          require(_amount > 0, "No valid amount of ETH given to withdraw");
                          // Get contract key
                          string memory contractName = getContractName(msg.sender);
                          // Check and update contract balance
                          require(etherBalances[contractName] >= _amount, "Insufficient contract ETH balance");
                          etherBalances[contractName] = etherBalances[contractName].sub(_amount);
                          // Withdraw
                          RocketVaultWithdrawerInterface withdrawer = RocketVaultWithdrawerInterface(msg.sender);
                          withdrawer.receiveVaultWithdrawalETH{value: _amount}();
                          // Emit ether withdrawn event
                          emit EtherWithdrawn(contractName, _amount, block.timestamp);
                      }
                      // Accept an token deposit and assign its balance to a network contract (saves a large amount of gas this way through not needing a double token transfer via a network contract first)
                      function depositToken(string memory _networkContractName, IERC20 _tokenContract, uint256 _amount) override external {
                           // Valid amount?
                          require(_amount > 0, "No valid amount of tokens given to deposit");
                          // Make sure the network contract is valid (will throw if not)
                          require(getContractAddress(_networkContractName) != address(0x0), "Not a valid network contract");
                          // Get contract key
                          bytes32 contractKey = keccak256(abi.encodePacked(_networkContractName, address(_tokenContract)));
                          // Send the tokens to this contract now
                          require(_tokenContract.transferFrom(msg.sender, address(this), _amount), "Token transfer was not successful");
                          // Update contract balance
                          tokenBalances[contractKey] = tokenBalances[contractKey].add(_amount);
                          // Emit token transfer
                          emit TokenDeposited(contractKey, address(_tokenContract), _amount, block.timestamp);
                      }
                      // Withdraw an amount of a ERC20 token to an address
                      // Only accepts calls from Rocket Pool network contracts
                      function withdrawToken(address _withdrawalAddress, IERC20 _tokenAddress, uint256 _amount) override external onlyLatestNetworkContract {
                          // Valid amount?
                          require(_amount > 0, "No valid amount of tokens given to withdraw");
                          // Get contract key
                          bytes32 contractKey = keccak256(abi.encodePacked(getContractName(msg.sender), _tokenAddress));
                          // Update balances
                          tokenBalances[contractKey] = tokenBalances[contractKey].sub(_amount);
                          // Get the token ERC20 instance
                          IERC20 tokenContract = IERC20(_tokenAddress);
                          // Withdraw to the desired address
                          require(tokenContract.transfer(_withdrawalAddress, _amount), "Rocket Vault token withdrawal unsuccessful");
                          // Emit token withdrawn event
                          emit TokenWithdrawn(contractKey, address(_tokenAddress), _amount, block.timestamp);
                      }
                      // Transfer token from one contract to another
                      // Only accepts calls from Rocket Pool network contracts
                      function transferToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) override external onlyLatestNetworkContract {
                          // Valid amount?
                          require(_amount > 0, "No valid amount of tokens given to transfer");
                          // Make sure the network contract is valid (will throw if not)
                          require(getContractAddress(_networkContractName) != address(0x0), "Not a valid network contract");
                          // Get contract keys
                          bytes32 contractKeyFrom = keccak256(abi.encodePacked(getContractName(msg.sender), _tokenAddress));
                          bytes32 contractKeyTo = keccak256(abi.encodePacked(_networkContractName, _tokenAddress));
                          // Update balances
                          tokenBalances[contractKeyFrom] = tokenBalances[contractKeyFrom].sub(_amount);
                          tokenBalances[contractKeyTo] = tokenBalances[contractKeyTo].add(_amount);
                          // Emit token withdrawn event
                          emit TokenTransfer(contractKeyFrom, contractKeyTo, address(_tokenAddress), _amount, block.timestamp);
                      }
                      // Burns an amount of a token that implements a burn(uint256) method
                      // Only accepts calls from Rocket Pool network contracts
                      function burnToken(ERC20Burnable _tokenAddress, uint256 _amount) override external onlyLatestNetworkContract {
                          // Get contract key
                          bytes32 contractKey = keccak256(abi.encodePacked(getContractName(msg.sender), _tokenAddress));
                          // Update balances
                          tokenBalances[contractKey] = tokenBalances[contractKey].sub(_amount);
                          // Get the token ERC20 instance
                          ERC20Burnable tokenContract = ERC20Burnable(_tokenAddress);
                          // Burn the tokens
                          tokenContract.burn(_amount);
                          // Emit token burn event
                          emit TokenBurned(contractKey, address(_tokenAddress), _amount, block.timestamp);
                      }
                  }
                  /**
                    *       .
                    *      / \\
                    *     |.'.|
                    *     |'.'|
                    *   ,'|   |`.
                    *  |,-'-|-'-.|
                    *   __|_| |         _        _      _____           _
                    *  | ___ \\|        | |      | |    | ___ \\         | |
                    *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
                    *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
                    *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
                    *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
                    * +---------------------------------------------------+
                    * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
                    * +---------------------------------------------------+
                    *
                    *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
                    *  be community-owned, decentralised, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
                  import "@openzeppelin/contracts/token/ERC20/ERC20Burnable.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(ERC20Burnable _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, and trustless.
                    *
                    *  For more information about Rocket Pool, visit https://rocketpool.net
                    *
                    *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
                    *
                    */
                  pragma solidity 0.7.6;
                  // SPDX-License-Identifier: GPL-3.0-only
                  interface RocketVaultWithdrawerInterface {
                      function receiveVaultWithdrawalETH() external payable; 
                  }