ETH Price: $2,511.12 (+0.19%)

Transaction Decoder

Block:
19903925 at May-19-2024 12:17:11 PM +UTC
Transaction Fee:
0.000452478 ETH $1.14
Gas Used:
150,826 Gas / 3 Gwei

Emitted Events:

295 RocketTokenRPL.Transfer( from=RocketVault, to=0x9C2f5BAA4ce6E14023ad93baD09D065111DAF2eE, value=5108815105033757433 )
296 RocketVault.TokenWithdrawn( by=2FD1739279B2E1B2AAA95D73C946D92BD9DE612EABEAC66BB95312D24DF21F8C, tokenAddress=RocketTokenRPL, amount=5108815105033757433, time=1716121031 )
297 RocketVault.EtherWithdrawn( 0xfc06bd2dc22238bad571c0432cfc04aee3d074be8cd974c9a9151e99df57e72b, 0x300d72f0f6d20efe7f0fc11d91b50a248223f46a5bb0f3d2b2622d4642a8c011, 000000000000000000000000000000000000000000000000001538466b5d225a, 000000000000000000000000000000000000000000000000000000006649edc7 )
298 RocketMerkleDistributorMainnet.RewardsClaimed( claimer=[Sender] 0xd1ba69980a5cf970f6e17a6a896262808adc190b, rewardIndex=[22], amountRPL=[5108815105033757433], amountETH=[5972849611055706] )

Account State Difference:

  Address   Before After State Difference Code
0x1d8f8f00...b0ee0Fa46
(Rocket Pool: Storage)
0x3bDC69C4...636b469d6
(Rocket Pool: Vault)
14,361.065894113926660043 Eth14,361.059921264315604337 Eth0.005972849611055706
(beaverbuild)
10.809385257979384239 Eth10.809394081165545795 Eth0.000008823186161556
0x9C2f5BAA...111DAF2eE 0.013124667015 Eth0.019097516626055706 Eth0.005972849611055706
0xd1BA6998...08adC190B
0.000809368328069081 Eth
Nonce: 29
0.000356890328069081 Eth
Nonce: 30
0.000452478
0xD3352606...04F21A51f

Execution Trace

RocketMerkleDistributorMainnet.claim( _nodeAddress=0xd1BA69980a5cF970f6e17A6A896262808adC190B, _rewardIndex=[22], _amountRPL=[5108815105033757433], _amountETH=[5972849611055706], _merkleProof=[[g1y+QiXLOcyCqEzod/yU1nK0d9gCDMloc2OX4A2rocc=, WsWYkWOIgd4mTVgzpj6Rjci5/qUCLzCa/lDPVowEifE=, PVjUGfuXcTawrxWlFH4S0xtQAtKXodBCaA5olvfR+CQ=, 6OekeZ2BasrQhd5lfJj1SwHeFiLu5m7+0MyucLuGTXA=, QKyoHdlwF0VMHrpZYRrXy5bTyv3U5jcSH4R8KJo40wM=, /PhFPBlYRigc4RXKFrSW9UdfhrSI/cUwSN+YCPk0e38=, lw/T1JNarq7nbmuyQ7ReuNR0vEGtClBXJY9hs4X4vOg=, DvY/S5Uo2OhTdeL+tQavY6WfQ2ag5KDu0kOLUrydalk=, H48i5DtNtykO4bzxBvUPxE9QfIiSyadZWDrSa61TT8M=, 9TH5g2sp6kfn4tDBKObrt5q4/cVzmKo/oljRV20CP00=, OUaecMaIXbixY3P9OEJPeLj4DR7s6O/nhnj7482sk/M=, 39emHGTmSwqmDL/pWrp6Mb6Solm13z3jNO9s0KmhXQg=]] )
  • RocketStorage.getAddress( _key=41C30D91BFAF5FA8D610263B0554366F2159A2B6807BF2FDBEB8F2B21A62F17B ) => ( r=0x3bDC69C4E5e13E52A65f5583c23EFB9636b469d6 )
  • RocketStorage.getAddress( _key=1B80652F417157FE4774177F7D33C8B600483B9193E3F00D2AB1ACE8FA6BDC9C ) => ( r=0xD33526068D116cE69F19A9ee46F0bd304F21A51f )
  • RocketStorage.getUint( _key=D5BB38E4B1E5EE62A67B054EE91F5457490D91E4920754F10A779B7B126A8092 ) => ( r=4193280 )
  • RocketStorage.getBytes32( _key=EA00FCA629BCB36ED774D37827839CFABC64BEEA36D171CBFB64DD86E08FB5BD ) => ( r=C2724D07659BB0CB7BBC926B873A56226EBF368BEA729C007E214F464E8AA69D )
  • RocketStorage.setUint( _key=D5BB38E4B1E5EE62A67B054EE91F5457490D91E4920754F10A779B7B126A8092, _value=8387584 )
  • RocketStorage.getNodeWithdrawalAddress( _nodeAddress=0xd1BA69980a5cF970f6e17A6A896262808adC190B ) => ( 0x9C2f5BAA4ce6E14023ad93baD09D065111DAF2eE )
  • RocketVault.withdrawToken( _withdrawalAddress=0x9C2f5BAA4ce6E14023ad93baD09D065111DAF2eE, _tokenAddress=0xD33526068D116cE69F19A9ee46F0bd304F21A51f, _amount=5108815105033757433 )
    • RocketStorage.getBool( _key=C30C24F272F5342011AAA1116C2684F698F9D143B28CEF139D954696616478E9 ) => ( r=True )
    • RocketStorage.getString( _key=80E9D7B699E5EB7C75DF96E11FDD65B157A5F4ACDE04C0BD9DFF91816F0B518E ) => ( rocketMerkleDistributorMainnet )
    • RocketTokenRPL.transfer( recipient=0x9C2f5BAA4ce6E14023ad93baD09D065111DAF2eE, amount=5108815105033757433 ) => ( True )
    • RocketVault.withdrawEther( _amount=5972849611055706 )
      • RocketStorage.getBool( _key=C30C24F272F5342011AAA1116C2684F698F9D143B28CEF139D954696616478E9 ) => ( r=True )
      • RocketStorage.getString( _key=80E9D7B699E5EB7C75DF96E11FDD65B157A5F4ACDE04C0BD9DFF91816F0B518E ) => ( rocketMerkleDistributorMainnet )
      • ETH 0.005972849611055706 RocketMerkleDistributorMainnet.CALL( )
      • ETH 0.005972849611055706 0x9c2f5baa4ce6e14023ad93bad09d065111daf2ee.CALL( )
        File 1 of 4: RocketMerkleDistributorMainnet
        // SPDX-License-Identifier: MIT
        pragma solidity >=0.6.0 <0.8.0;
        /**
         * @dev These functions deal with verification of Merkle trees (hash trees),
         */
        library MerkleProof {
            /**
             * @dev Returns true if a `leaf` can be proved to be a part of a Merkle tree
             * defined by `root`. For this, a `proof` must be provided, containing
             * sibling hashes on the branch from the leaf to the root of the tree. Each
             * pair of leaves and each pair of pre-images are assumed to be sorted.
             */
            function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
                bytes32 computedHash = leaf;
                for (uint256 i = 0; i < proof.length; i++) {
                    bytes32 proofElement = proof[i];
                    if (computedHash <= proofElement) {
                        // Hash(current computed hash + current element of the proof)
                        computedHash = keccak256(abi.encodePacked(computedHash, proofElement));
                    } else {
                        // Hash(current element of the proof + current computed hash)
                        computedHash = keccak256(abi.encodePacked(proofElement, computedHash));
                    }
                }
                // Check if the computed hash (root) is equal to the provided root
                return computedHash == root;
            }
        }
        // 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 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;
        pragma abicoder v2;
        // SPDX-License-Identifier: GPL-3.0-only
        import "../RocketBase.sol";
        import "../../interface/token/RocketTokenRPLInterface.sol";
        import "../../interface/RocketVaultInterface.sol";
        import "../../interface/node/RocketNodeStakingInterface.sol";
        import "../../interface/rewards/RocketRewardsRelayInterface.sol";
        import "../../interface/rewards/RocketSmoothingPoolInterface.sol";
        import "../../interface/RocketVaultWithdrawerInterface.sol";
        import "@openzeppelin/contracts/cryptography/MerkleProof.sol";
        /*
        * On mainnet, the relay and the distributor are the same contract as there is no need for an intermediate contract to
        * handle cross-chain messaging.
        */
        contract RocketMerkleDistributorMainnet is RocketBase, RocketRewardsRelayInterface, RocketVaultWithdrawerInterface {
            // Libs
            using SafeMath for uint;
            // Events
            event RewardsClaimed(address indexed claimer, uint256[] rewardIndex, uint256[] amountRPL, uint256[] amountETH);
            // Constants
            uint256 constant network = 0;
            // Immutables
            bytes32 immutable rocketVaultKey;
            bytes32 immutable rocketTokenRPLKey;
            // Allow receiving ETH
            receive() payable external {}
            // Construct
            constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) {
                // Version
                version = 1;
                // Precompute keys
                rocketVaultKey = keccak256(abi.encodePacked("contract.address", "rocketVault"));
                rocketTokenRPLKey = keccak256(abi.encodePacked("contract.address", "rocketTokenRPL"));
            }
            // Called by RocketRewardsPool to include a snapshot into this distributor
            function relayRewards(uint256 _rewardIndex, bytes32 _root, uint256 _rewardsRPL, uint256 _rewardsETH) external override onlyLatestContract("rocketMerkleDistributorMainnet", address(this)) onlyLatestContract("rocketRewardsPool", msg.sender) {
                bytes32 key = keccak256(abi.encodePacked('rewards.merkle.root', _rewardIndex));
                require(getBytes32(key) == bytes32(0));
                setBytes32(key, _root);
                // Send the ETH and RPL to the vault
                RocketVaultInterface rocketVault = RocketVaultInterface(getAddress(rocketVaultKey));
                if (_rewardsETH > 0) {
                    rocketVault.depositEther{value: _rewardsETH}();
                }
                if (_rewardsRPL > 0) {
                    IERC20 rocketTokenRPL = IERC20(getAddress(rocketTokenRPLKey));
                    rocketTokenRPL.approve(address(rocketVault), _rewardsRPL);
                    rocketVault.depositToken("rocketMerkleDistributorMainnet", rocketTokenRPL, _rewardsRPL);
                }
            }
            // Reward recipients can call this method with a merkle proof to claim rewards for one or more reward intervals
            function claim(address _nodeAddress, uint256[] calldata _rewardIndex, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof) external override {
                claimAndStake(_nodeAddress, _rewardIndex, _amountRPL, _amountETH, _merkleProof, 0);
            }
            // Node operators can call this method to claim rewards for one or more reward intervals and specify an amount of RPL to stake at the same time
            function claimAndStake(address _nodeAddress, uint256[] calldata _rewardIndex, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof, uint256 _stakeAmount) public override {
                // Get contracts
                RocketVaultInterface rocketVault = RocketVaultInterface(getAddress(rocketVaultKey));
                address rocketTokenRPLAddress = getAddress(rocketTokenRPLKey);
                // Verify claims
                _claim(_rewardIndex, _nodeAddress, _amountRPL, _amountETH, _merkleProof);
                {
                    // Get withdrawal address
                    address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
                    require(msg.sender == _nodeAddress || msg.sender == withdrawalAddress, "Can only claim from node or withdrawal address");
                    // Calculate totals
                    uint256 totalAmountRPL = 0;
                    uint256 totalAmountETH = 0;
                    for (uint256 i = 0; i < _rewardIndex.length; i++) {
                        totalAmountRPL = totalAmountRPL.add(_amountRPL[i]);
                        totalAmountETH = totalAmountETH.add(_amountETH[i]);
                    }
                    // Validate input
                    require(_stakeAmount <= totalAmountRPL, "Invalid stake amount");
                    // Distribute any remaining tokens to the node's withdrawal address
                    uint256 remaining = totalAmountRPL.sub(_stakeAmount);
                    if (remaining > 0) {
                        rocketVault.withdrawToken(withdrawalAddress, IERC20(rocketTokenRPLAddress), remaining);
                    }
                    // Distribute ETH
                    if (totalAmountETH > 0) {
                        rocketVault.withdrawEther(totalAmountETH);
                        (bool result,) = withdrawalAddress.call{value: totalAmountETH}("");
                        require(result, "Failed to claim ETH");
                    }
                }
                // Restake requested amount
                if (_stakeAmount > 0) {
                    RocketTokenRPLInterface rocketTokenRPL = RocketTokenRPLInterface(rocketTokenRPLAddress);
                    RocketNodeStakingInterface rocketNodeStaking = RocketNodeStakingInterface(getContractAddress("rocketNodeStaking"));
                    rocketVault.withdrawToken(address(this), IERC20(rocketTokenRPLAddress), _stakeAmount);
                    rocketTokenRPL.approve(address(rocketNodeStaking), _stakeAmount);
                    rocketNodeStaking.stakeRPLFor(_nodeAddress, _stakeAmount);
                }
                // Emit event
                emit RewardsClaimed(_nodeAddress, _rewardIndex, _amountRPL, _amountETH);
            }
            // Verifies the given data exists as a leaf nodes for the specified reward interval and marks them as claimed if they are valid
            // Note: this function is optimised for gas when _rewardIndex is ordered numerically
            function _claim(uint256[] calldata _rewardIndex, address _nodeAddress, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof) internal {
                // Set initial parameters to the first reward index in the array
                uint256 indexWordIndex = _rewardIndex[0] / 256;
                bytes32 claimedWordKey = keccak256(abi.encodePacked('rewards.interval.claimed', _nodeAddress, indexWordIndex));
                uint256 claimedWord = getUint(claimedWordKey);
                // Loop over every entry
                for (uint256 i = 0; i < _rewardIndex.length; i++) {
                    // Prevent accidental claim of 0
                    require(_amountRPL[i] > 0 || _amountETH[i] > 0, "Invalid amount");
                    // Check if this entry has a different word index than the previous
                    if (indexWordIndex != _rewardIndex[i] / 256) {
                        // Store the previous word
                        setUint(claimedWordKey, claimedWord);
                        // Load the word for this entry
                        indexWordIndex = _rewardIndex[i] / 256;
                        claimedWordKey = keccak256(abi.encodePacked('rewards.interval.claimed', _nodeAddress, indexWordIndex));
                        claimedWord = getUint(claimedWordKey);
                    }
                    // Calculate the bit index for this entry
                    uint256 indexBitIndex = _rewardIndex[i] % 256;
                    // Ensure the bit is not yet set on this word
                    uint256 mask = (1 << indexBitIndex);
                    require(claimedWord & mask != mask, "Already claimed");
                    // Verify the merkle proof
                    require(_verifyProof(_rewardIndex[i], _nodeAddress, _amountRPL[i], _amountETH[i], _merkleProof[i]), "Invalid proof");
                    // Set the bit for the current reward index
                    claimedWord = claimedWord | (1 << indexBitIndex);
                }
                // Store the word
                setUint(claimedWordKey, claimedWord);
            }
            // Verifies that the
            function _verifyProof(uint256 _rewardIndex, address _nodeAddress, uint256 _amountRPL, uint256 _amountETH, bytes32[] calldata _merkleProof) internal view returns (bool) {
                bytes32 node = keccak256(abi.encodePacked(_nodeAddress, network, _amountRPL, _amountETH));
                bytes32 key = keccak256(abi.encodePacked('rewards.merkle.root', _rewardIndex));
                bytes32 merkleRoot = getBytes32(key);
                return MerkleProof.verify(_merkleProof, merkleRoot, node);
            }
            // Returns true if the given claimer has claimed for the given reward interval
            function isClaimed(uint256 _rewardIndex, address _claimer) public override view returns (bool) {
                uint256 indexWordIndex = _rewardIndex / 256;
                uint256 indexBitIndex = _rewardIndex % 256;
                uint256 claimedWord = getUint(keccak256(abi.encodePacked('rewards.interval.claimed', _claimer, indexWordIndex)));
                uint256 mask = (1 << indexBitIndex);
                return claimedWord & mask == mask;
            }
            // Allow receiving ETH from RocketVault, no action required
            function receiveVaultWithdrawalETH() external override payable {}
        }
        /**
          *       .
          *      / \\
          *     |.'.|
          *     |'.'|
          *   ,'|   |`.
          *  |,-'-|-'-.|
          *   __|_| |         _        _      _____           _
          *  | ___ \\|        | |      | |    | ___ \\         | |
          *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
          *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
          *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
          *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
          * +---------------------------------------------------+
          * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
          * +---------------------------------------------------+
          *
          *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
          *  decentralised, trustless and compatible with staking in Ethereum 2.0.
          *
          *  For more information about Rocket Pool, visit https://rocketpool.net
          *
          *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
          *
          */
        pragma solidity 0.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 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 "@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.7.6;
        // SPDX-License-Identifier: GPL-3.0-only
        interface RocketVaultWithdrawerInterface {
            function receiveVaultWithdrawalETH() external payable; 
        }
        /**
          *       .
          *      / \\
          *     |.'.|
          *     |'.'|
          *   ,'|   |`.
          *  |,-'-|-'-.|
          *   __|_| |         _        _      _____           _
          *  | ___ \\|        | |      | |    | ___ \\         | |
          *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
          *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
          *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
          *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
          * +---------------------------------------------------+
          * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
          * +---------------------------------------------------+
          *
          *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
          *  decentralised, trustless and compatible with staking in Ethereum 2.0.
          *
          *  For more information about Rocket Pool, visit https://rocketpool.net
          *
          *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
          *
          */
        pragma solidity 0.7.6;
        // SPDX-License-Identifier: GPL-3.0-only
        interface RocketNodeStakingInterface {
            function getTotalRPLStake() external view returns (uint256);
            function getNodeRPLStake(address _nodeAddress) external view returns (uint256);
            function getNodeRPLStakedTime(address _nodeAddress) external view returns (uint256);
            function getTotalEffectiveRPLStake() external view returns (uint256);
            function calculateTotalEffectiveRPLStake(uint256 offset, uint256 limit, uint256 rplPrice) 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 getNodeMinipoolLimit(address _nodeAddress) external view returns (uint256);
            function stakeRPL(uint256 _amount) external;
            function stakeRPLFor(address _nodeAddress, uint256 _amount) 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.7.6;
        pragma abicoder v2;
        // SPDX-License-Identifier: GPL-3.0-only
        interface RocketRewardsRelayInterface {
            function relayRewards(uint256 _intervalIndex, bytes32 _merkleRoot, uint256 _rewardsRPL, uint256 _rewardsETH) external;
            function claim(address _nodeAddress, uint256[] calldata _intervalIndex, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof) external;
            function claimAndStake(address _nodeAddress, uint256[] calldata _intervalIndex, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof, uint256 _stakeAmount) external;
            function isClaimed(uint256 _intervalIndex, address _claimer) external view returns (bool);
        }
        /**
          *       .
          *      / \\
          *     |.'.|
          *     |'.'|
          *   ,'|   |`.
          *  |,-'-|-'-.|
          *   __|_| |         _        _      _____           _
          *  | ___ \\|        | |      | |    | ___ \\         | |
          *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
          *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
          *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
          *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
          * +---------------------------------------------------+
          * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
          * +---------------------------------------------------+
          *
          *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
          *  decentralised, trustless and compatible with staking in Ethereum 2.0.
          *
          *  For more information about Rocket Pool, visit https://rocketpool.net
          *
          *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
          *
          */
        pragma solidity 0.7.6;
        pragma abicoder v2;
        // SPDX-License-Identifier: GPL-3.0-only
        interface RocketSmoothingPoolInterface {
            function withdrawEther(address _to, uint256 _amount) external;
        }
        /**
          *       .
          *      / \\
          *     |.'.|
          *     |'.'|
          *   ,'|   |`.
          *  |,-'-|-'-.|
          *   __|_| |         _        _      _____           _
          *  | ___ \\|        | |      | |    | ___ \\         | |
          *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
          *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
          *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
          *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
          * +---------------------------------------------------+
          * |  DECENTRALISED STAKING PROTOCOL FOR ETHEREUM 2.0  |
          * +---------------------------------------------------+
          *
          *  Rocket Pool is a first-of-its-kind ETH2 Proof of Stake protocol, designed to be community owned,
          *  decentralised, trustless and compatible with staking in Ethereum 2.0.
          *
          *  For more information about Rocket Pool, visit https://rocketpool.net
          *
          *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
          *
          */
        pragma solidity 0.7.6;
        // SPDX-License-Identifier: GPL-3.0-only
        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 2 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 3 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 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;
        }