ETH Price: $2,446.32 (-4.20%)

Transaction Decoder

Block:
17789013 at Jul-28-2023 03:56:47 AM +UTC
Transaction Fee:
0.00223296907436869 ETH $5.46
Gas Used:
124,330 Gas / 17.960018293 Gwei

Emitted Events:

268 RocketTokenRPL.Transfer( from=[Sender] 0xa6fb1a1fff573466295ed477219ca1419bc9a400, to=[Receiver] RocketNodeStaking, value=56070147676739744000 )
269 RocketTokenRPL.Approval( owner=[Sender] 0xa6fb1a1fff573466295ed477219ca1419bc9a400, spender=[Receiver] RocketNodeStaking, value=999999943929852323260256000 )
270 RocketTokenRPL.Approval( owner=[Receiver] RocketNodeStaking, spender=RocketVault, value=56070147676739744000 )
271 RocketTokenRPL.Transfer( from=[Receiver] RocketNodeStaking, to=RocketVault, value=56070147676739744000 )
272 RocketTokenRPL.Approval( owner=[Receiver] RocketNodeStaking, spender=RocketVault, value=0 )
273 RocketVault.TokenDeposited( by=E2390B72DFDD3EE64764589B670E97CB05DE272B6555CDBF214AB8CE931ADB8A, tokenAddress=RocketTokenRPL, amount=56070147676739744000, time=1690516607 )
274 RocketNodeStaking.RPLStaked( from=0x23fde06A...31d28Eb43, amount=56070147676739744000, time=1690516607 )

Account State Difference:

  Address   Before After State Difference Code
0x1d8f8f00...b0ee0Fa46
(Rocket Pool: Storage)
0.627708996724162258 Eth0.627715213224162258 Eth0.0000062165
0x3bDC69C4...636b469d6
(Rocket Pool: Vault)
0xa6FB1a1f...19bC9A400
0.178001732871526835 Eth
Nonce: 164
0.175768763797158145 Eth
Nonce: 165
0.00223296907436869
0xD3352606...04F21A51f

Execution Trace

RocketNodeStaking.stakeRPLFor( _nodeAddress=0x23fde06A96496CF55F121b55d14c66131d28Eb43, _amount=56070147676739744000 )
  • RocketStorage.getAddress( _key=8FC06385DE84508EAF7EB3D75B93167987C9629589FE0A868A2B4E0E90862DD8 ) => ( r=0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec )
  • RocketStorage.getBool( _key=3C3C20A3D2FF66D2E62AC857CF3F8A972509FC668B89F8CC494632B15FDFDCB8 ) => ( r=True )
  • RocketStorage.getAddress( _key=759D15219B5ADBAF4EC95EE41B49B3F96FCFF9BE0258E4A1CD69074965F237D1 ) => ( r=0x7EcCBbd05830EdF593d30005B8F69E965AF4D59f )
  • RocketStorage.getNodeWithdrawalAddress( _nodeAddress=0x23fde06A96496CF55F121b55d14c66131d28Eb43 ) => ( 0xa6FB1a1fFF573466295ed477219CA1419bC9A400 )
  • RocketStorage.getAddress( _key=1B80652F417157FE4774177F7D33C8B600483B9193E3F00D2AB1ACE8FA6BDC9C ) => ( r=0xD33526068D116cE69F19A9ee46F0bd304F21A51f )
  • RocketStorage.getAddress( _key=41C30D91BFAF5FA8D610263B0554366F2159A2B6807BF2FDBEB8F2B21A62F17B ) => ( r=0x3bDC69C4E5e13E52A65f5583c23EFB9636b469d6 )
  • RocketTokenRPL.transferFrom( sender=0xa6FB1a1fFF573466295ed477219CA1419bC9A400, recipient=0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec, amount=56070147676739744000 ) => ( True )
  • RocketTokenRPL.approve( spender=0x3bDC69C4E5e13E52A65f5583c23EFB9636b469d6, amount=56070147676739744000 ) => ( True )
  • RocketVault.depositToken( _networkContractName=rocketNodeStaking, _tokenContract=0xD33526068D116cE69F19A9ee46F0bd304F21A51f, _amount=56070147676739744000 )
    • RocketStorage.getAddress( _key=8FC06385DE84508EAF7EB3D75B93167987C9629589FE0A868A2B4E0E90862DD8 ) => ( r=0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec )
    • RocketTokenRPL.transferFrom( sender=0x0d8D8f8541B12A0e1194B7CC4b6D954b90AB82ec, recipient=0x3bDC69C4E5e13E52A65f5583c23EFB9636b469d6, amount=56070147676739744000 ) => ( True )
    • RocketStorage.addUint( _key=E9120B7223AE2A37E3E3D2DFB439C54EBBDEABE89BCE6D355F59122854C4A306, _amount=56070147676739744000 )
    • RocketStorage.addUint( _key=4382D200372B196DA9B3C2D9E796914D364E458E64F27F8CFB8B161D0BC42538, _amount=56070147676739744000 )
    • RocketStorage.setUint( _key=51A7497496130974B93079D0DFD38682F4CD267DB2EAD300635DAD927501603E, _value=1690516607 )
      File 1 of 4: RocketNodeStaking
      // 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;
      /**
       * @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);
      }
      /**
        *       .
        *      / \\
        *     |.'.|
        *     |'.'|
        *   ,'|   |`.
        *  |,-'-|-'-.|
        *   __|_| |         _        _      _____           _
        *  | ___ \\|        | |      | |    | ___ \\         | |
        *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
        *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
        *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
        *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
        * +---------------------------------------------------+
        * |  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.7.6;
      // SPDX-License-Identifier: GPL-3.0-only
      import "./MinipoolDeposit.sol";
      import "./MinipoolStatus.sol";
      // A struct containing all the information on-chain about a specific minipool
      struct MinipoolDetails {
          bool exists;
          address minipoolAddress;
          bytes pubkey;
          MinipoolStatus status;
          uint256 statusBlock;
          uint256 statusTime;
          bool finalised;
          MinipoolDeposit depositType;
          uint256 nodeFee;
          uint256 nodeDepositBalance;
          bool nodeDepositAssigned;
          uint256 userDepositBalance;
          bool userDepositAssigned;
          uint256 userDepositAssignedTime;
          bool useLatestDelegate;
          address delegate;
          address previousDelegate;
          address effectiveDelegate;
          uint256 penaltyCount;
          uint256 penaltyRate;
          address nodeAddress;
      }
      /**
        *       .
        *      / \\
        *     |.'.|
        *     |'.'|
        *   ,'|   |`.
        *  |,-'-|-'-.|
        *   __|_| |         _        _      _____           _
        *  | ___ \\|        | |      | |    | ___ \\         | |
        *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
        *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
        *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
        *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
        * +---------------------------------------------------+
        * |  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;
      pragma abicoder v2;
      // SPDX-License-Identifier: GPL-3.0-only
      import "../../types/MinipoolDeposit.sol";
      import "../../types/MinipoolDetails.sol";
      import "./RocketMinipoolInterface.sol";
      interface RocketMinipoolManagerInterface {
          function getMinipoolCount() external view returns (uint256);
          function getStakingMinipoolCount() external view returns (uint256);
          function getFinalisedMinipoolCount() external view returns (uint256);
          function getActiveMinipoolCount() external view returns (uint256);
          function getMinipoolRPLSlashed(address _minipoolAddress) external view returns (bool);
          function getMinipoolCountPerStatus(uint256 offset, uint256 limit) external view returns (uint256, uint256, uint256, uint256, uint256);
          function getPrelaunchMinipools(uint256 offset, uint256 limit) external view returns (address[] memory);
          function getMinipoolAt(uint256 _index) external view returns (address);
          function getNodeMinipoolCount(address _nodeAddress) external view returns (uint256);
          function getNodeActiveMinipoolCount(address _nodeAddress) external view returns (uint256);
          function getNodeFinalisedMinipoolCount(address _nodeAddress) external view returns (uint256);
          function getNodeStakingMinipoolCount(address _nodeAddress) external view returns (uint256);
          function getNodeStakingMinipoolCountBySize(address _nodeAddress, uint256 _depositSize) external view returns (uint256);
          function getNodeMinipoolAt(address _nodeAddress, uint256 _index) external view returns (address);
          function getNodeValidatingMinipoolCount(address _nodeAddress) external view returns (uint256);
          function getNodeValidatingMinipoolAt(address _nodeAddress, uint256 _index) external view returns (address);
          function getMinipoolByPubkey(bytes calldata _pubkey) external view returns (address);
          function getMinipoolExists(address _minipoolAddress) external view returns (bool);
          function getMinipoolDestroyed(address _minipoolAddress) external view returns (bool);
          function getMinipoolPubkey(address _minipoolAddress) external view returns (bytes memory);
          function updateNodeStakingMinipoolCount(uint256 _previousBond, uint256 _newBond, uint256 _previousFee, uint256 _newFee) external;
          function getMinipoolWithdrawalCredentials(address _minipoolAddress) external pure returns (bytes memory);
          function createMinipool(address _nodeAddress, uint256 _salt) external returns (RocketMinipoolInterface);
          function createVacantMinipool(address _nodeAddress, uint256 _salt, bytes calldata _validatorPubkey, uint256 _bondAmount, uint256 _currentBalance) external returns (RocketMinipoolInterface);
          function removeVacantMinipool() external;
          function getVacantMinipoolCount() external view returns (uint256);
          function getVacantMinipoolAt(uint256 _index) external view returns (address);
          function destroyMinipool() external;
          function incrementNodeStakingMinipoolCount(address _nodeAddress) external;
          function decrementNodeStakingMinipoolCount(address _nodeAddress) external;
          function incrementNodeFinalisedMinipoolCount(address _nodeAddress) external;
          function setMinipoolPubkey(bytes calldata _pubkey) external;
          function getMinipoolDepositType(address _minipoolAddress) external view returns (MinipoolDeposit);
      }
      /**
        *       .
        *      / \\
        *     |.'.|
        *     |'.'|
        *   ,'|   |`.
        *  |,-'-|-'-.|
        *   __|_| |         _        _      _____           _
        *  | ___ \\|        | |      | |    | ___ \\         | |
        *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
        *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
        *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
        *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
        * +---------------------------------------------------+
        * |  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 RocketNetworkPricesInterface {
          function getPricesBlock() external view returns (uint256);
          function getRPLPrice() external view returns (uint256);
          function getLatestReportableBlock() external view returns (uint256);
          function submitPrices(uint256 _block, uint256 _rplPrice) external;
          function executeUpdatePrices(uint256 _block, uint256 _rplPrice) 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 RocketNodeStakingInterface {
          function getTotalRPLStake() external view returns (uint256);
          function getNodeRPLStake(address _nodeAddress) external view returns (uint256);
          function getNodeETHMatched(address _nodeAddress) external view returns (uint256);
          function getNodeETHProvided(address _nodeAddress) external view returns (uint256);
          function getNodeETHCollateralisationRatio(address _nodeAddress) external view returns (uint256);
          function getNodeRPLStakedTime(address _nodeAddress) external view returns (uint256);
          function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256);
          function getNodeMinimumRPLStake(address _nodeAddress) external view returns (uint256);
          function getNodeMaximumRPLStake(address _nodeAddress) external view returns (uint256);
          function getNodeETHMatchedLimit(address _nodeAddress) external view returns (uint256);
          function stakeRPL(uint256 _amount) external;
          function stakeRPLFor(address _nodeAddress, uint256 _amount) external;
          function setStakeRPLForAllowed(address _caller, bool _allowed) external;
          function withdrawRPL(uint256 _amount) external;
          function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) 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 RocketDAOProtocolSettingsRewardsInterface {
          function setSettingRewardsClaimer(string memory _contractName, uint256 _perc) external;
          function getRewardsClaimerPerc(string memory _contractName) external view returns (uint256);
          function getRewardsClaimerPercTimeUpdated(string memory _contractName) external view returns (uint256);
          function getRewardsClaimersPercTotal() external view returns (uint256);
          function getRewardsClaimIntervalTime() 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 RocketDAOProtocolSettingsNodeInterface {
          function getRegistrationEnabled() external view returns (bool);
          function getSmoothingPoolRegistrationEnabled() external view returns (bool);
          function getDepositEnabled() external view returns (bool);
          function getVacantMinipoolsEnabled() external view returns (bool);
          function getMinimumPerMinipoolStake() external view returns (uint256);
          function getMaximumPerMinipoolStake() external view returns (uint256);
      }
      // 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 AddressSetStorageInterface {
          function getCount(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 addItem(bytes32 _key, address _value) external;
          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/token/ERC20/IERC20.sol";
      import "../RocketBase.sol";
      import "../../interface/minipool/RocketMinipoolManagerInterface.sol";
      import "../../interface/network/RocketNetworkPricesInterface.sol";
      import "../../interface/node/RocketNodeStakingInterface.sol";
      import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsRewardsInterface.sol";
      import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol";
      import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNodeInterface.sol";
      import "../../interface/RocketVaultInterface.sol";
      import "../../interface/util/AddressSetStorageInterface.sol";
      /// @notice Handles node deposits and minipool creation
      contract RocketNodeStaking is RocketBase, RocketNodeStakingInterface {
          // Libs
          using SafeMath for uint;
          // Events
          event RPLStaked(address indexed from, uint256 amount, uint256 time);
          event RPLWithdrawn(address indexed to, uint256 amount, uint256 time);
          event RPLSlashed(address indexed node, uint256 amount, uint256 ethValue, uint256 time);
          event StakeRPLForAllowed(address indexed node, address indexed caller, bool allowed, uint256 time);
          constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
              version = 4;
          }
          /// @notice Returns the total quantity of RPL staked on the network
          function getTotalRPLStake() override external view returns (uint256) {
              return getUint(keccak256("rpl.staked.total.amount"));
          }
          /// @dev Increases the total network RPL stake
          /// @param _amount How much to increase by
          function increaseTotalRPLStake(uint256 _amount) private {
              addUint(keccak256("rpl.staked.total.amount"), _amount);
          }
          /// @dev Decrease the total network RPL stake
          /// @param _amount How much to decrease by
          function decreaseTotalRPLStake(uint256 _amount) private {
              subUint(keccak256("rpl.staked.total.amount"), _amount);
          }
          /// @notice Returns the amount a given node operator has staked
          /// @param _nodeAddress The address of the node operator to query
          function getNodeRPLStake(address _nodeAddress) override public view returns (uint256) {
              return getUint(keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress)));
          }
          /// @dev Increases a node operator's RPL stake
          /// @param _amount How much to increase by
          function increaseNodeRPLStake(address _nodeAddress, uint256 _amount) private {
              addUint(keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress)), _amount);
          }
          /// @dev Decrease a node operator's RPL stake
          /// @param _amount How much to decrease by
          function decreaseNodeRPLStake(address _nodeAddress, uint256 _amount) private {
              subUint(keccak256(abi.encodePacked("rpl.staked.node.amount", _nodeAddress)), _amount);
          }
          /// @notice Returns a node's matched ETH amount (amount taken from protocol to stake)
          /// @param _nodeAddress The address of the node operator to query
          function getNodeETHMatched(address _nodeAddress) override public view returns (uint256) {
              uint256 ethMatched = getUint(keccak256(abi.encodePacked("eth.matched.node.amount", _nodeAddress)));
              if (ethMatched > 0) {
                  return ethMatched;
              } else {
                  // Fallback for backwards compatibility before ETH matched was recorded (all minipools matched 16 ETH from protocol)
                  RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
                  return rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress).mul(16 ether);
              }
          }
          /// @notice Returns a node's provided ETH amount (amount supplied to create minipools)
          /// @param _nodeAddress The address of the node operator to query
          function getNodeETHProvided(address _nodeAddress) override public view returns (uint256) {
              // Get contracts
              RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
              uint256 activeMinipoolCount = rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress);
              // Retrieve stored ETH matched value
              uint256 ethMatched = getUint(keccak256(abi.encodePacked("eth.matched.node.amount", _nodeAddress)));
              if (ethMatched > 0) {
                  RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                  uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance();
                  // ETH provided is number of staking minipools * 32 - eth matched
                  uint256 totalEthStaked = activeMinipoolCount.mul(launchAmount);
                  return totalEthStaked.sub(ethMatched);
              } else {
                  // Fallback for legacy minipools is number of staking minipools * 16
                  return activeMinipoolCount.mul(16 ether);
              }
          }
          /// @notice Returns the ratio between capital taken from users and provided by a node operator.
          ///         The value is a 1e18 precision fixed point integer value of (node capital + user capital) / node capital.
          /// @param _nodeAddress The address of the node operator to query
          function getNodeETHCollateralisationRatio(address _nodeAddress) override public view returns (uint256) {
              uint256 ethMatched = getUint(keccak256(abi.encodePacked("eth.matched.node.amount", _nodeAddress)));
              if (ethMatched == 0) {
                  // Node operator only has legacy minipools and all legacy minipools had a 1:1 ratio
                  return calcBase.mul(2);
              } else {
                  RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
                  uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance();
                  RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager"));
                  uint256 totalEthStaked = rocketMinipoolManager.getNodeActiveMinipoolCount(_nodeAddress).mul(launchAmount);
                  return totalEthStaked.mul(calcBase).div(totalEthStaked.sub(ethMatched));
              }
          }
          /// @notice Returns the timestamp at which a node last staked RPL
          function getNodeRPLStakedTime(address _nodeAddress) override public view returns (uint256) {
              return getUint(keccak256(abi.encodePacked("rpl.staked.node.time", _nodeAddress)));
          }
          /// @dev Sets the timestamp at which a node last staked RPL
          /// @param _nodeAddress The address of the node operator to set the value for
          /// @param _time The timestamp to set
          function setNodeRPLStakedTime(address _nodeAddress, uint256 _time) private {
              setUint(keccak256(abi.encodePacked("rpl.staked.node.time", _nodeAddress)), _time);
          }
          /// @notice Calculate and return a node's effective RPL stake amount
          /// @param _nodeAddress The address of the node operator to calculate for
          function getNodeEffectiveRPLStake(address _nodeAddress) override external view returns (uint256) {
              // Load contracts
              RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
              RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
              // Get node's current RPL stake
              uint256 rplStake = getNodeRPLStake(_nodeAddress);
              // Retrieve variables for calculations
              uint256 matchedETH = getNodeETHMatched(_nodeAddress);
              uint256 providedETH = getNodeETHProvided(_nodeAddress);
              uint256 rplPrice = rocketNetworkPrices.getRPLPrice();
              // RPL stake cannot exceed maximum
              uint256 maximumStakePercent = rocketDAOProtocolSettingsNode.getMaximumPerMinipoolStake();
              uint256 maximumStake = providedETH.mul(maximumStakePercent).div(rplPrice);
              if (rplStake > maximumStake) {
                  return maximumStake;
              }
              // If RPL stake is lower than minimum, node has no effective stake
              uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
              uint256 minimumStake = matchedETH.mul(minimumStakePercent).div(rplPrice);
              if (rplStake < minimumStake) {
                  return 0;
              }
              // Otherwise, return the actual stake
              return rplStake;
          }
          /// @notice Calculate and return a node's minimum RPL stake to collateralize their minipools
          /// @param _nodeAddress The address of the node operator to calculate for
          function getNodeMinimumRPLStake(address _nodeAddress) override external view returns (uint256) {
              // Load contracts
              RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
              RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
              // Retrieve variables
              uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
              uint256 matchedETH = getNodeETHMatched(_nodeAddress);
              return matchedETH
                  .mul(minimumStakePercent)
                  .div(rocketNetworkPrices.getRPLPrice());
          }
          /// @notice Calculate and return a node's maximum RPL stake to fully collateralise their minipools
          /// @param _nodeAddress The address of the node operator to calculate for
          function getNodeMaximumRPLStake(address _nodeAddress) override public view returns (uint256) {
              // Load contracts
              RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
              RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
              // Retrieve variables
              uint256 maximumStakePercent = rocketDAOProtocolSettingsNode.getMaximumPerMinipoolStake();
              uint256 providedETH = getNodeETHProvided(_nodeAddress);
              return providedETH
                  .mul(maximumStakePercent)
                  .div(rocketNetworkPrices.getRPLPrice());
          }
          /// @notice Calculate and return a node's limit of how much user ETH they can use based on RPL stake
          /// @param _nodeAddress The address of the node operator to calculate for
          function getNodeETHMatchedLimit(address _nodeAddress) override external view returns (uint256) {
              // Load contracts
              RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
              RocketDAOProtocolSettingsNodeInterface rocketDAOProtocolSettingsNode = RocketDAOProtocolSettingsNodeInterface(getContractAddress("rocketDAOProtocolSettingsNode"));
              // Calculate & return limit
              uint256 minimumStakePercent = rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake();
              return getNodeRPLStake(_nodeAddress)
                  .mul(rocketNetworkPrices.getRPLPrice())
                  .div(minimumStakePercent);
          }
          /// @notice Accept an RPL stake
          ///         Only accepts calls from registered nodes
          ///         Requires call to have approved this contract to spend RPL
          /// @param _amount The amount of RPL to stake
          function stakeRPL(uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredNode(msg.sender) {
              _stakeRPL(msg.sender, _amount);
          }
          /// @notice Accept an RPL stake from any address for a specified node
          ///         Requires caller to have approved this contract to spend RPL
          ///         Requires caller to be on the node operator's allow list (see `setStakeForAllowed`)
          /// @param _nodeAddress The address of the node operator to stake on behalf of
          /// @param _amount The amount of RPL to stake
          function stakeRPLFor(address _nodeAddress, uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredNode(_nodeAddress) {
             // Must be node's withdrawal address, allow listed address or rocketMerkleDistributorMainnet
             if (msg.sender != getAddress(keccak256(abi.encodePacked("contract.address", "rocketMerkleDistributorMainnet")))) {
                 address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
                 if (msg.sender != withdrawalAddress) {
                     require(getBool(keccak256(abi.encodePacked("node.stake.for.allowed", _nodeAddress, msg.sender))), "Not allowed to stake for");
                 }
             }
             _stakeRPL(_nodeAddress, _amount);
          }
          /// @notice Explicitly allow or remove allowance of an address to be able to stake on behalf of a node
          /// @param _caller The address you wish to allow
          /// @param _allowed Whether the address is allowed or denied
          function setStakeRPLForAllowed(address _caller, bool _allowed) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredNode(msg.sender) {
              setBool(keccak256(abi.encodePacked("node.stake.for.allowed", msg.sender, _caller)), _allowed);
              emit StakeRPLForAllowed(msg.sender, _caller, _allowed, block.timestamp);
          }
          /// @dev Internal logic for staking RPL
          /// @param _nodeAddress The address to increase the RPL stake of
          /// @param _amount The amount of RPL to stake
          function _stakeRPL(address _nodeAddress, uint256 _amount) internal {
              // Load contracts
              address rplTokenAddress = getContractAddress("rocketTokenRPL");
              address rocketVaultAddress = getContractAddress("rocketVault");
              IERC20 rplToken = IERC20(rplTokenAddress);
              RocketVaultInterface rocketVault = RocketVaultInterface(rocketVaultAddress);
              // Transfer RPL tokens
              require(rplToken.transferFrom(msg.sender, address(this), _amount), "Could not transfer RPL to staking contract");
              // Deposit RPL tokens to vault
              require(rplToken.approve(rocketVaultAddress, _amount), "Could not approve vault RPL deposit");
              rocketVault.depositToken("rocketNodeStaking", rplToken, _amount);
              // Update RPL stake amounts & node RPL staked block
              increaseTotalRPLStake(_amount);
              increaseNodeRPLStake(_nodeAddress, _amount);
              setNodeRPLStakedTime(_nodeAddress, block.timestamp);
              // Emit RPL staked event
              emit RPLStaked(_nodeAddress, _amount, block.timestamp);
          }
          /// @notice Withdraw staked RPL back to the node account
          ///         Only accepts calls from registered nodes
          ///         Withdraws to withdrawal address if set, otherwise defaults to node address
          /// @param _amount The amount of RPL to withdraw
          function withdrawRPL(uint256 _amount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredNode(msg.sender) {
              // Load contracts
              RocketDAOProtocolSettingsRewardsInterface rocketDAOProtocolSettingsRewards = RocketDAOProtocolSettingsRewardsInterface(getContractAddress("rocketDAOProtocolSettingsRewards"));
              RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
              // Check cooldown period (one claim period) has passed since RPL last staked
              require(block.timestamp.sub(getNodeRPLStakedTime(msg.sender)) >= rocketDAOProtocolSettingsRewards.getRewardsClaimIntervalTime(), "The withdrawal cooldown period has not passed");
              // Get & check node's current RPL stake
              uint256 rplStake = getNodeRPLStake(msg.sender);
              require(rplStake >= _amount, "Withdrawal amount exceeds node's staked RPL balance");
              // Check withdrawal would not undercollateralize node
              require(rplStake.sub(_amount) >= getNodeMaximumRPLStake(msg.sender), "Node's staked RPL balance after withdrawal is less than required balance");
              // Update RPL stake amounts
              decreaseTotalRPLStake(_amount);
              decreaseNodeRPLStake(msg.sender, _amount);
              // Transfer RPL tokens to node address
              rocketVault.withdrawToken(rocketStorage.getNodeWithdrawalAddress(msg.sender), IERC20(getContractAddress("rocketTokenRPL")), _amount);
              // Emit RPL withdrawn event
              emit RPLWithdrawn(msg.sender, _amount, block.timestamp);
          }
          /// @notice Slash a node's RPL by an ETH amount
          ///         Only accepts calls from registered minipools
          /// @param _nodeAddress The address to slash RPL from
          /// @param _ethSlashAmount The amount of RPL to slash denominated in ETH value
          function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) override external onlyLatestContract("rocketNodeStaking", address(this)) onlyRegisteredMinipool(msg.sender) {
              // Load contracts
              RocketNetworkPricesInterface rocketNetworkPrices = RocketNetworkPricesInterface(getContractAddress("rocketNetworkPrices"));
              RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault"));
              // Calculate RPL amount to slash
              uint256 rplSlashAmount = calcBase.mul(_ethSlashAmount).div(rocketNetworkPrices.getRPLPrice());
              // Cap slashed amount to node's RPL stake
              uint256 rplStake = getNodeRPLStake(_nodeAddress);
              if (rplSlashAmount > rplStake) { rplSlashAmount = rplStake; }
              // Transfer slashed amount to auction contract
              if(rplSlashAmount > 0) rocketVault.transferToken("rocketAuctionManager", IERC20(getContractAddress("rocketTokenRPL")), rplSlashAmount);
              // Update RPL stake amounts
              decreaseTotalRPLStake(rplSlashAmount);
              decreaseNodeRPLStake(_nodeAddress, rplSlashAmount);
              // Mark minipool as slashed
              setBool(keccak256(abi.encodePacked("minipool.rpl.slashed", msg.sender)), true);
              // Emit RPL slashed event
              emit RPLSlashed(_nodeAddress, rplSlashAmount, _ethSlashAmount, block.timestamp);
          }
      }
      

      File 2 of 4: RocketTokenRPL
      // 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;
      /*
       * @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/ERC20Burnable.sol";
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      import "../RocketBase.sol";
      import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsInflationInterface.sol";
      import "../../interface/token/RocketTokenRPLInterface.sol";
      import "../../interface/RocketVaultInterface.sol";
      // RPL Governance and utility token
      // Inlfationary with rate determined by DAO
      contract RocketTokenRPL is RocketBase, ERC20Burnable, RocketTokenRPLInterface {
          // Libs
          using SafeMath for uint;
          /**** Properties ***********/
          // How many RPL tokens minted to date (18m from fixed supply)
          uint256 constant totalInitialSupply = 18000000000000000000000000;
          // The RPL inflation interval
          uint256 constant inflationInterval = 1 days;
          // How many RPL tokens have been swapped for new ones
          uint256 public totalSwappedRPL = 0;
          // Timestamp of last block inflation was calculated at
          uint256 private inflationCalcTime = 0;
          /**** Contracts ************/
          // The address of our fixed supply RPL ERC20 token contract
          IERC20 rplFixedSupplyContract = IERC20(address(0));
          /**** Events ***********/
          event RPLInflationLog(address sender, uint256 value, uint256 inflationCalcTime);
          event RPLFixedSupplyBurn(address indexed from, uint256 amount, uint256 time);
          // Construct
          constructor(RocketStorageInterface _rocketStorageAddress, IERC20 _rocketTokenRPLFixedSupplyAddress) RocketBase(_rocketStorageAddress) ERC20("Rocket Pool Protocol", "RPL") {
              // Version
              version = 1;
              // Set the mainnet RPL fixed supply token address
              rplFixedSupplyContract = IERC20(_rocketTokenRPLFixedSupplyAddress);
              // Mint the 18m tokens that currently exist and allow them to be sent to people burning existing fixed supply RPL
              _mint(address(this), totalInitialSupply);
          }
          /**
          * Get the last time that inflation was calculated at
          * @return uint256 Last timestamp since inflation was calculated
          */
          function getInflationCalcTime() override public view returns(uint256) {
              // Get the last time inflation was calculated if it has even started
              uint256 inflationStartTime = getInflationIntervalStartTime();
              // If inflation has just begun but not been calculated previously, use the start block as the last calculated point if it has passed
              return inflationCalcTime == 0 && inflationStartTime < block.timestamp ? inflationStartTime : inflationCalcTime;
          }
          /**
          * How many seconds to calculate inflation at
          * @return uint256 how many seconds to calculate inflation at
          */
          function getInflationIntervalTime() override external pure returns(uint256) {
              return inflationInterval;
          }
          /**
          * The current inflation rate per interval (eg 1000133680617113500 = 5% annual)
          * @return uint256 The current inflation rate per interval
          */
          function getInflationIntervalRate() override public view returns(uint256) {
              // Inflation rate controlled by the DAO
              RocketDAOProtocolSettingsInflationInterface daoSettingsInflation = RocketDAOProtocolSettingsInflationInterface(getContractAddress("rocketDAOProtocolSettingsInflation"));
              return daoSettingsInflation.getInflationIntervalRate();
          }
          /**
          * The current block to begin inflation at
          * @return uint256 The current block to begin inflation at
          */
          function getInflationIntervalStartTime() override public view returns(uint256) {
              // Inflation rate start time controlled by the DAO
              RocketDAOProtocolSettingsInflationInterface daoSettingsInflation = RocketDAOProtocolSettingsInflationInterface(getContractAddress("rocketDAOProtocolSettingsInflation"));
              return daoSettingsInflation.getInflationIntervalStartTime();
          }
          /**
          * The current rewards pool address that receives the inflation
          * @return address The rewards pool contract address
          */
          function getInflationRewardsContractAddress() override external view returns(address) {
              // Inflation rate start block controlled by the DAO
              return getContractAddress("rocketRewardsPool");
          }
          /**
          * Compute interval since last inflation update (on call)
          * @return uint256 Time intervals since last update
          */
          function getInflationIntervalsPassed() override public view returns(uint256) {
              // The time that inflation was last calculated at
              uint256 inflationLastCalculatedTime = getInflationCalcTime();
              return _getInflationIntervalsPassed(inflationLastCalculatedTime);
          }
          function _getInflationIntervalsPassed(uint256 _inflationLastCalcTime) private view returns(uint256) {
              // Calculate now if inflation has begun
              if(_inflationLastCalcTime > 0) {
                  return (block.timestamp).sub(_inflationLastCalcTime).div(inflationInterval);
              }else{
                  return 0;
              }
          }
          /**
          * @dev Function to compute how many tokens should be minted
          * @return A uint256 specifying number of new tokens to mint
          */
          function inflationCalculate() override external view returns (uint256) {
              uint256 intervalsSinceLastMint = getInflationIntervalsPassed();
              return _inflationCalculate(intervalsSinceLastMint);
          }
          function _inflationCalculate(uint256 _intervalsSinceLastMint) private view returns (uint256) {
              // The inflation amount
              uint256 inflationTokenAmount = 0;
              // Only update  if last interval has passed and inflation rate is > 0
              if(_intervalsSinceLastMint > 0) {
                  // Optimisation
                  uint256 inflationRate = getInflationIntervalRate();
                  if(inflationRate > 0) {
                      // Get the total supply now
                      uint256 totalSupplyCurrent = totalSupply();
                      uint256 newTotalSupply = totalSupplyCurrent;
                      // Compute inflation for total inflation intervals elapsed
                      for (uint256 i = 0; i < _intervalsSinceLastMint; i++) {
                          newTotalSupply = newTotalSupply.mul(inflationRate).div(10**18);
                      }
                      // Return inflation amount
                      inflationTokenAmount = newTotalSupply.sub(totalSupplyCurrent);
                  }
              }
              // Done
              return inflationTokenAmount;
          }
          /**
          * @dev Mint new tokens if enough time has elapsed since last mint
          * @return A uint256 specifying number of new tokens that were minted
          */
          function inflationMintTokens() override external returns (uint256) {
              // Only run inflation process if at least 1 interval has passed (function returns 0 otherwise)
              uint256 inflationLastCalcTime = getInflationCalcTime();
              uint256 intervalsSinceLastMint = _getInflationIntervalsPassed(inflationLastCalcTime);
              if (intervalsSinceLastMint == 0) {
                  return 0;
              }
              // Address of the vault where to send tokens
              address rocketVaultAddress = getContractAddress("rocketVault");
              require(rocketVaultAddress != address(0x0), "rocketVault address not set");
              // Only mint if we have new tokens to mint since last interval and an address is set to receive them
              RocketVaultInterface rocketVaultContract = RocketVaultInterface(rocketVaultAddress);
              // Calculate the amount of tokens now based on inflation rate
              uint256 newTokens = _inflationCalculate(intervalsSinceLastMint);
              // Update last inflation calculation timestamp even if inflation rate is 0
              inflationCalcTime = inflationLastCalcTime.add(inflationInterval.mul(intervalsSinceLastMint));
              // Check if actually need to mint tokens (e.g. inflation rate > 0)
              if (newTokens > 0) {
                  // Mint to itself, then allocate tokens for transfer to rewards contract, this will update balance & supply
                  _mint(address(this), newTokens);
                  // Initialise itself and allow from it's own balance (cant just do an allow as it could be any user calling this so they are msg.sender)
                  IERC20 rplInflationContract = IERC20(address(this));
                  // Get the current allowance for Rocket Vault
                  uint256 vaultAllowance = rplFixedSupplyContract.allowance(rocketVaultAddress, address(this));
                  // Now allow Rocket Vault to move those tokens, we also need to account of any other allowances for this token from other contracts in the same block
                  require(rplInflationContract.approve(rocketVaultAddress, vaultAllowance.add(newTokens)), "Allowance for Rocket Vault could not be approved");
                  // Let vault know it can move these tokens to itself now and credit the balance to the RPL rewards pool contract
                  rocketVaultContract.depositToken("rocketRewardsPool", IERC20(address(this)), newTokens);
              }
              // Log it
              emit RPLInflationLog(msg.sender, newTokens, inflationCalcTime);
              // return number minted
              return newTokens;
          }   
         /**
         * @dev Swap current RPL fixed supply tokens for new RPL 1:1 to the same address from the user calling it
         * @param _amount The amount of RPL fixed supply tokens to swap
         */
          function swapTokens(uint256 _amount) override external {
              // Valid amount?
              require(_amount > 0, "Please enter valid amount of RPL to swap");
              // Send the tokens to this contract now and mint new ones for them
              require(rplFixedSupplyContract.transferFrom(msg.sender, address(this), _amount), "Token transfer from existing RPL contract was not successful");
              // Transfer from the contracts RPL balance to the user
              require(this.transfer(msg.sender, _amount), "Token transfer from RPL inflation contract was not successful");
              // Update the total swapped
              totalSwappedRPL = totalSwappedRPL.add(_amount);
              // Log it
              emit RPLFixedSupplyBurn(msg.sender, _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 RocketDAOProtocolSettingsInflationInterface {
          function getInflationIntervalRate() external view returns (uint256);
          function getInflationIntervalStartTime() 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
      import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
      interface RocketTokenRPLInterface is IERC20 {
          function getInflationCalcTime() external view returns(uint256);
          function getInflationIntervalTime() external view returns(uint256);
          function getInflationIntervalRate() external view returns(uint256);
          function getInflationIntervalsPassed() external view returns(uint256);
          function getInflationIntervalStartTime() external view returns(uint256);
          function getInflationRewardsContractAddress() external view returns(address);
          function inflationCalculate() external view returns (uint256);
          function inflationMintTokens() external returns (uint256);
          function swapTokens(uint256 _amount) external;
      }
      

      File 3 of 4: 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; 
      }
      

      File 4 of 4: 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;
      }