ETH Price: $2,428.89 (+0.55%)

Transaction Decoder

Block:
16107514 at Dec-03-2022 11:17:35 PM +UTC
Transaction Fee:
0.000682906284233514 ETH $1.66
Gas Used:
54,681 Gas / 12.488913594 Gwei

Account State Difference:

  Address   Before After State Difference Code
0xae78736C...E74Fc6393
0xd4Fe3070...cF2B307D9
0.155102495261086736 Eth
Nonce: 21
0.154419588976853222 Eth
Nonce: 22
0.000682906284233514
(Flashbots: Builder)
1.19922307172672327 Eth1.199249603478657056 Eth0.000026531751933786

Execution Trace

RocketTokenRETH.transfer( recipient=0xF5B05e9e1CA1d622f84c3CDeac27a94E3cb6d978, amount=962980773674757220 ) => ( True )
  • RocketStorage.getUint( _key=C3DF34D16306B6970A845291EA1524CD6D981967D59A201FBFE91D63FC8677DC ) => ( r=0 )
    File 1 of 2: RocketTokenRETH
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
        /**
         * @dev Returns the substraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b <= a, "SafeMath: subtraction overflow");
            return a - b;
        }
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) return 0;
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: division by zero");
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: modulo by zero");
            return a % b;
        }
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            return a - b;
        }
        /**
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryDiv}.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a / b;
        }
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b, string memory errorMessage) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    import "../../utils/Context.sol";
    import "./IERC20.sol";
    import "../../math/SafeMath.sol";
    /**
     * @dev Implementation of the {IERC20} interface.
     *
     * This implementation is agnostic to the way tokens are created. This means
     * that a supply mechanism has to be added in a derived contract using {_mint}.
     * For a generic mechanism see {ERC20PresetMinterPauser}.
     *
     * TIP: For a detailed writeup see our guide
     * https://forum.zeppelin.solutions/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * We have followed general OpenZeppelin guidelines: functions revert instead
     * of returning `false` on failure. This behavior is nonetheless conventional
     * and does not conflict with the expectations of ERC20 applications.
     *
     * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
     * This allows applications to reconstruct the allowance for all accounts just
     * by listening to said events. Other implementations of the EIP may not emit
     * these events, as it isn't required by the specification.
     *
     * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
     * functions have been added to mitigate the well-known issues around setting
     * allowances. See {IERC20-approve}.
     */
    contract ERC20 is Context, IERC20 {
        using SafeMath for uint256;
        mapping (address => uint256) private _balances;
        mapping (address => mapping (address => uint256)) private _allowances;
        uint256 private _totalSupply;
        string private _name;
        string private _symbol;
        uint8 private _decimals;
        /**
         * @dev Sets the values for {name} and {symbol}, initializes {decimals} with
         * a default value of 18.
         *
         * To select a different value for {decimals}, use {_setupDecimals}.
         *
         * All three of these values are immutable: they can only be set once during
         * construction.
         */
        constructor (string memory name_, string memory symbol_) public {
            _name = name_;
            _symbol = symbol_;
            _decimals = 18;
        }
        /**
         * @dev Returns the name of the token.
         */
        function name() public view virtual returns (string memory) {
            return _name;
        }
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public view virtual returns (string memory) {
            return _symbol;
        }
        /**
         * @dev Returns the number of decimals used to get its user representation.
         * For example, if `decimals` equals `2`, a balance of `505` tokens should
         * be displayed to a user as `5,05` (`505 / 10 ** 2`).
         *
         * Tokens usually opt for a value of 18, imitating the relationship between
         * Ether and Wei. This is the value {ERC20} uses, unless {_setupDecimals} is
         * called.
         *
         * NOTE: This information is only used for _display_ purposes: it in
         * no way affects any of the arithmetic of the contract, including
         * {IERC20-balanceOf} and {IERC20-transfer}.
         */
        function decimals() public view virtual returns (uint8) {
            return _decimals;
        }
        /**
         * @dev See {IERC20-totalSupply}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            return _totalSupply;
        }
        /**
         * @dev See {IERC20-balanceOf}.
         */
        function balanceOf(address account) public view virtual override returns (uint256) {
            return _balances[account];
        }
        /**
         * @dev See {IERC20-transfer}.
         *
         * Requirements:
         *
         * - `recipient` cannot be the zero address.
         * - the caller must have a balance of at least `amount`.
         */
        function transfer(address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(_msgSender(), recipient, amount);
            return true;
        }
        /**
         * @dev See {IERC20-allowance}.
         */
        function allowance(address owner, address spender) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
        /**
         * @dev See {IERC20-approve}.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            _approve(_msgSender(), spender, amount);
            return true;
        }
        /**
         * @dev See {IERC20-transferFrom}.
         *
         * Emits an {Approval} event indicating the updated allowance. This is not
         * required by the EIP. See the note at the beginning of {ERC20}.
         *
         * Requirements:
         *
         * - `sender` and `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         * - the caller must have allowance for ``sender``'s tokens of at least
         * `amount`.
         */
        function transferFrom(address sender, address recipient, uint256 amount) public virtual override returns (bool) {
            _transfer(sender, recipient, amount);
            _approve(sender, _msgSender(), _allowances[sender][_msgSender()].sub(amount, "ERC20: transfer amount exceeds allowance"));
            return true;
        }
        /**
         * @dev Atomically increases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].add(addedValue));
            return true;
        }
        /**
         * @dev Atomically decreases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         * - `spender` must have allowance for the caller of at least
         * `subtractedValue`.
         */
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
            _approve(_msgSender(), spender, _allowances[_msgSender()][spender].sub(subtractedValue, "ERC20: decreased allowance below zero"));
            return true;
        }
        /**
         * @dev Moves tokens `amount` from `sender` to `recipient`.
         *
         * This is internal function is equivalent to {transfer}, and can be used to
         * e.g. implement automatic token fees, slashing mechanisms, etc.
         *
         * Emits a {Transfer} event.
         *
         * Requirements:
         *
         * - `sender` cannot be the zero address.
         * - `recipient` cannot be the zero address.
         * - `sender` must have a balance of at least `amount`.
         */
        function _transfer(address sender, address recipient, uint256 amount) internal virtual {
            require(sender != address(0), "ERC20: transfer from the zero address");
            require(recipient != address(0), "ERC20: transfer to the zero address");
            _beforeTokenTransfer(sender, recipient, amount);
            _balances[sender] = _balances[sender].sub(amount, "ERC20: transfer amount exceeds balance");
            _balances[recipient] = _balances[recipient].add(amount);
            emit Transfer(sender, recipient, amount);
        }
        /** @dev Creates `amount` tokens and assigns them to `account`, increasing
         * the total supply.
         *
         * Emits a {Transfer} event with `from` set to the zero address.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         */
        function _mint(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: mint to the zero address");
            _beforeTokenTransfer(address(0), account, amount);
            _totalSupply = _totalSupply.add(amount);
            _balances[account] = _balances[account].add(amount);
            emit Transfer(address(0), account, amount);
        }
        /**
         * @dev Destroys `amount` tokens from `account`, reducing the
         * total supply.
         *
         * Emits a {Transfer} event with `to` set to the zero address.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         * - `account` must have at least `amount` tokens.
         */
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
            _beforeTokenTransfer(account, address(0), amount);
            _balances[account] = _balances[account].sub(amount, "ERC20: burn amount exceeds balance");
            _totalSupply = _totalSupply.sub(amount);
            emit Transfer(account, address(0), amount);
        }
        /**
         * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
         *
         * This internal function is equivalent to `approve`, and can be used to
         * e.g. set automatic allowances for certain subsystems, etc.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `owner` cannot be the zero address.
         * - `spender` cannot be the zero address.
         */
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
        /**
         * @dev Sets {decimals} to a value other than the default one of 18.
         *
         * WARNING: This function should only be called from the constructor. Most
         * applications that interact with token contracts will not expect
         * {decimals} to ever change, and may work incorrectly if it does.
         */
        function _setupDecimals(uint8 decimals_) internal virtual {
            _decimals = decimals_;
        }
        /**
         * @dev Hook that is called before any transfer of tokens. This includes
         * minting and burning.
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * will be to transferred to `to`.
         * - when `from` is zero, `amount` tokens will be minted for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
         * - `from` and `to` are never both zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual { }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
        /**
         * @dev Moves `amount` tokens from the caller's account to `recipient`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
        /**
         * @dev Moves `amount` tokens from `sender` to `recipient` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.8.0;
    /*
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with GSN meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address payable) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    import "../interface/RocketStorageInterface.sol";
    /// @title Base settings / modifiers for each contract in Rocket Pool
    /// @author David Rugendyke
    abstract contract RocketBase {
        // Calculate using this as the base
        uint256 constant calcBase = 1 ether;
        // Version of the contract
        uint8 public version;
        // The main storage contract where primary persistant storage is maintained
        RocketStorageInterface rocketStorage = RocketStorageInterface(0);
        /*** Modifiers **********************************************************/
        /**
        * @dev Throws if called by any sender that doesn't match a Rocket Pool network contract
        */
        modifier onlyLatestNetworkContract() {
            require(getBool(keccak256(abi.encodePacked("contract.exists", msg.sender))), "Invalid or outdated network contract");
            _;
        }
        /**
        * @dev Throws if called by any sender that doesn't match one of the supplied contract or is the latest version of that contract
        */
        modifier onlyLatestContract(string memory _contractName, address _contractAddress) {
            require(_contractAddress == getAddress(keccak256(abi.encodePacked("contract.address", _contractName))), "Invalid or outdated contract");
            _;
        }
        /**
        * @dev Throws if called by any sender that isn't a registered node
        */
        modifier onlyRegisteredNode(address _nodeAddress) {
            require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
            _;
        }
        /**
        * @dev Throws if called by any sender that isn't a trusted node DAO member
        */
        modifier onlyTrustedNode(address _nodeAddress) {
            require(getBool(keccak256(abi.encodePacked("dao.trustednodes.", "member", _nodeAddress))), "Invalid trusted node");
            _;
        }
        /**
        * @dev Throws if called by any sender that isn't a registered minipool
        */
        modifier onlyRegisteredMinipool(address _minipoolAddress) {
            require(getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress))), "Invalid minipool");
            _;
        }
        
        /**
        * @dev Throws if called by any account other than a guardian account (temporary account allowed access to settings before DAO is fully enabled)
        */
        modifier onlyGuardian() {
            require(msg.sender == rocketStorage.getGuardian(), "Account is not a temporary guardian");
            _;
        }
        /*** Methods **********************************************************/
        /// @dev Set the main Rocket Storage address
        constructor(RocketStorageInterface _rocketStorageAddress) {
            // Update the contract address
            rocketStorage = RocketStorageInterface(_rocketStorageAddress);
        }
        /// @dev Get the address of a network contract by name
        function getContractAddress(string memory _contractName) internal view returns (address) {
            // Get the current contract address
            address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
            // Check it
            require(contractAddress != address(0x0), "Contract not found");
            // Return
            return contractAddress;
        }
        /// @dev Get the address of a network contract by name (returns address(0x0) instead of reverting if contract does not exist)
        function getContractAddressUnsafe(string memory _contractName) internal view returns (address) {
            // Get the current contract address
            address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
            // Return
            return contractAddress;
        }
        /// @dev Get the name of a network contract by address
        function getContractName(address _contractAddress) internal view returns (string memory) {
            // Get the contract name
            string memory contractName = getString(keccak256(abi.encodePacked("contract.name", _contractAddress)));
            // Check it
            require(bytes(contractName).length > 0, "Contract not found");
            // Return
            return contractName;
        }
        /// @dev Get revert error message from a .call method
        function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
            // If the _res length is less than 68, then the transaction failed silently (without a revert message)
            if (_returnData.length < 68) return "Transaction reverted silently";
            assembly {
                // Slice the sighash.
                _returnData := add(_returnData, 0x04)
            }
            return abi.decode(_returnData, (string)); // All that remains is the revert string
        }
        /*** Rocket Storage Methods ****************************************/
        // Note: Unused helpers have been removed to keep contract sizes down
        /// @dev Storage get methods
        function getAddress(bytes32 _key) internal view returns (address) { return rocketStorage.getAddress(_key); }
        function getUint(bytes32 _key) internal view returns (uint) { return rocketStorage.getUint(_key); }
        function getString(bytes32 _key) internal view returns (string memory) { return rocketStorage.getString(_key); }
        function getBytes(bytes32 _key) internal view returns (bytes memory) { return rocketStorage.getBytes(_key); }
        function getBool(bytes32 _key) internal view returns (bool) { return rocketStorage.getBool(_key); }
        function getInt(bytes32 _key) internal view returns (int) { return rocketStorage.getInt(_key); }
        function getBytes32(bytes32 _key) internal view returns (bytes32) { return rocketStorage.getBytes32(_key); }
        /// @dev Storage set methods
        function setAddress(bytes32 _key, address _value) internal { rocketStorage.setAddress(_key, _value); }
        function setUint(bytes32 _key, uint _value) internal { rocketStorage.setUint(_key, _value); }
        function setString(bytes32 _key, string memory _value) internal { rocketStorage.setString(_key, _value); }
        function setBytes(bytes32 _key, bytes memory _value) internal { rocketStorage.setBytes(_key, _value); }
        function setBool(bytes32 _key, bool _value) internal { rocketStorage.setBool(_key, _value); }
        function setInt(bytes32 _key, int _value) internal { rocketStorage.setInt(_key, _value); }
        function setBytes32(bytes32 _key, bytes32 _value) internal { rocketStorage.setBytes32(_key, _value); }
        /// @dev Storage delete methods
        function deleteAddress(bytes32 _key) internal { rocketStorage.deleteAddress(_key); }
        function deleteUint(bytes32 _key) internal { rocketStorage.deleteUint(_key); }
        function deleteString(bytes32 _key) internal { rocketStorage.deleteString(_key); }
        function deleteBytes(bytes32 _key) internal { rocketStorage.deleteBytes(_key); }
        function deleteBool(bytes32 _key) internal { rocketStorage.deleteBool(_key); }
        function deleteInt(bytes32 _key) internal { rocketStorage.deleteInt(_key); }
        function deleteBytes32(bytes32 _key) internal { rocketStorage.deleteBytes32(_key); }
        /// @dev Storage arithmetic methods
        function addUint(bytes32 _key, uint256 _amount) internal { rocketStorage.addUint(_key, _amount); }
        function subUint(bytes32 _key, uint256 _amount) internal { rocketStorage.subUint(_key, _amount); }
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import "../RocketBase.sol";
    import "../../interface/deposit/RocketDepositPoolInterface.sol";
    import "../../interface/network/RocketNetworkBalancesInterface.sol";
    import "../../interface/token/RocketTokenRETHInterface.sol";
    import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNetworkInterface.sol";
    // rETH is a tokenised stake in the Rocket Pool network
    // rETH is backed by ETH (subject to liquidity) at a variable exchange rate
    contract RocketTokenRETH is RocketBase, ERC20, RocketTokenRETHInterface {
        // Libs
        using SafeMath for uint;
        // Events
        event EtherDeposited(address indexed from, uint256 amount, uint256 time);
        event TokensMinted(address indexed to, uint256 amount, uint256 ethAmount, uint256 time);
        event TokensBurned(address indexed from, uint256 amount, uint256 ethAmount, uint256 time);
        // Construct with our token details
        constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) ERC20("Rocket Pool ETH", "rETH") {
            // Version
            version = 1;
        }
        // Receive an ETH deposit from a minipool or generous individual
        receive() external payable {
            // Emit ether deposited event
            emit EtherDeposited(msg.sender, msg.value, block.timestamp);
        }
        // Calculate the amount of ETH backing an amount of rETH
        function getEthValue(uint256 _rethAmount) override public view returns (uint256) {
            // Get network balances
            RocketNetworkBalancesInterface rocketNetworkBalances = RocketNetworkBalancesInterface(getContractAddress("rocketNetworkBalances"));
            uint256 totalEthBalance = rocketNetworkBalances.getTotalETHBalance();
            uint256 rethSupply = rocketNetworkBalances.getTotalRETHSupply();
            // Use 1:1 ratio if no rETH is minted
            if (rethSupply == 0) { return _rethAmount; }
            // Calculate and return
            return _rethAmount.mul(totalEthBalance).div(rethSupply);
        }
        // Calculate the amount of rETH backed by an amount of ETH
        function getRethValue(uint256 _ethAmount) override public view returns (uint256) {
            // Get network balances
            RocketNetworkBalancesInterface rocketNetworkBalances = RocketNetworkBalancesInterface(getContractAddress("rocketNetworkBalances"));
            uint256 totalEthBalance = rocketNetworkBalances.getTotalETHBalance();
            uint256 rethSupply = rocketNetworkBalances.getTotalRETHSupply();
            // Use 1:1 ratio if no rETH is minted
            if (rethSupply == 0) { return _ethAmount; }
            // Check network ETH balance
            require(totalEthBalance > 0, "Cannot calculate rETH token amount while total network balance is zero");
            // Calculate and return
            return _ethAmount.mul(rethSupply).div(totalEthBalance);
        }
        // Get the current ETH : rETH exchange rate
        // Returns the amount of ETH backing 1 rETH
        function getExchangeRate() override external view returns (uint256) {
            return getEthValue(1 ether);
        }
        // Get the total amount of collateral available
        // Includes rETH contract balance & excess deposit pool balance
        function getTotalCollateral() override public view returns (uint256) {
            RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
            return rocketDepositPool.getExcessBalance().add(address(this).balance);
        }
        // Get the current ETH collateral rate
        // Returns the portion of rETH backed by ETH in the contract as a fraction of 1 ether
        function getCollateralRate() override public view returns (uint256) {
            uint256 totalEthValue = getEthValue(totalSupply());
            if (totalEthValue == 0) { return calcBase; }
            return calcBase.mul(address(this).balance).div(totalEthValue);
        }
        // Deposit excess ETH from deposit pool
        // Only accepts calls from the RocketDepositPool contract
        function depositExcess() override external payable onlyLatestContract("rocketDepositPool", msg.sender) {
            // Emit ether deposited event
            emit EtherDeposited(msg.sender, msg.value, block.timestamp);
        }
        // Mint rETH
        // Only accepts calls from the RocketDepositPool contract
        function mint(uint256 _ethAmount, address _to) override external onlyLatestContract("rocketDepositPool", msg.sender) {
            // Get rETH amount
            uint256 rethAmount = getRethValue(_ethAmount);
            // Check rETH amount
            require(rethAmount > 0, "Invalid token mint amount");
            // Update balance & supply
            _mint(_to, rethAmount);
            // Emit tokens minted event
            emit TokensMinted(_to, rethAmount, _ethAmount, block.timestamp);
        }
        // Burn rETH for ETH
        function burn(uint256 _rethAmount) override external {
            // Check rETH amount
            require(_rethAmount > 0, "Invalid token burn amount");
            require(balanceOf(msg.sender) >= _rethAmount, "Insufficient rETH balance");
            // Get ETH amount
            uint256 ethAmount = getEthValue(_rethAmount);
            // Get & check ETH balance
            uint256 ethBalance = getTotalCollateral();
            require(ethBalance >= ethAmount, "Insufficient ETH balance for exchange");
            // Update balance & supply
            _burn(msg.sender, _rethAmount);
            // Withdraw ETH from deposit pool if required
            withdrawDepositCollateral(ethAmount);
            // Transfer ETH to sender
            msg.sender.transfer(ethAmount);
            // Emit tokens burned event
            emit TokensBurned(msg.sender, _rethAmount, ethAmount, block.timestamp);
        }
        // Withdraw ETH from the deposit pool for collateral if required
        function withdrawDepositCollateral(uint256 _ethRequired) private {
            // Check rETH contract balance
            uint256 ethBalance = address(this).balance;
            if (ethBalance >= _ethRequired) { return; }
            // Withdraw
            RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
            rocketDepositPool.withdrawExcessBalance(_ethRequired.sub(ethBalance));
        }
        // Sends any excess ETH from this contract to the deposit pool (as determined by target collateral rate)
        function depositExcessCollateral() external override {
            // Load contracts
            RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork"));
            RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool"));
            // Get collateral and target collateral rate
            uint256 collateralRate = getCollateralRate();
            uint256 targetCollateralRate = rocketDAOProtocolSettingsNetwork.getTargetRethCollateralRate();
            // Check if we are in excess
            if (collateralRate > targetCollateralRate) {
                // Calculate our target collateral in ETH
                uint256 targetCollateral = address(this).balance.mul(targetCollateralRate).div(collateralRate);
                // If we have excess
                if (address(this).balance > targetCollateral) {
                    // Send that excess to deposit pool
                    uint256 excessCollateral = address(this).balance.sub(targetCollateral);
                    rocketDepositPool.recycleExcessCollateral{value: excessCollateral}();
                }
            }
        }
        // This is called by the base ERC20 contract before all transfer, mint, and burns
        function _beforeTokenTransfer(address from, address, uint256) internal override {
            // Don't run check if this is a mint transaction
            if (from != address(0)) {
                // Check which block the user's last deposit was
                bytes32 key = keccak256(abi.encodePacked("user.deposit.block", from));
                uint256 lastDepositBlock = getUint(key);
                if (lastDepositBlock > 0) {
                    // Ensure enough blocks have passed
                    uint256 depositDelay = getUint(keccak256(abi.encodePacked(keccak256("dao.protocol.setting.network"), "network.reth.deposit.delay")));
                    uint256 blocksPassed = block.number.sub(lastDepositBlock);
                    require(blocksPassed > depositDelay, "Not enough time has passed since deposit");
                    // Clear the state as it's no longer necessary to check this until another deposit is made
                    deleteUint(key);
                }
            }
        }
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    interface RocketStorageInterface {
        // Deploy status
        function getDeployedStatus() external view returns (bool);
        // Guardian
        function getGuardian() external view returns(address);
        function setGuardian(address _newAddress) external;
        function confirmGuardian() external;
        // Getters
        function getAddress(bytes32 _key) external view returns (address);
        function getUint(bytes32 _key) external view returns (uint);
        function getString(bytes32 _key) external view returns (string memory);
        function getBytes(bytes32 _key) external view returns (bytes memory);
        function getBool(bytes32 _key) external view returns (bool);
        function getInt(bytes32 _key) external view returns (int);
        function getBytes32(bytes32 _key) external view returns (bytes32);
        // Setters
        function setAddress(bytes32 _key, address _value) external;
        function setUint(bytes32 _key, uint _value) external;
        function setString(bytes32 _key, string calldata _value) external;
        function setBytes(bytes32 _key, bytes calldata _value) external;
        function setBool(bytes32 _key, bool _value) external;
        function setInt(bytes32 _key, int _value) external;
        function setBytes32(bytes32 _key, bytes32 _value) external;
        // Deleters
        function deleteAddress(bytes32 _key) external;
        function deleteUint(bytes32 _key) external;
        function deleteString(bytes32 _key) external;
        function deleteBytes(bytes32 _key) external;
        function deleteBool(bytes32 _key) external;
        function deleteInt(bytes32 _key) external;
        function deleteBytes32(bytes32 _key) external;
        // Arithmetic
        function addUint(bytes32 _key, uint256 _amount) external;
        function subUint(bytes32 _key, uint256 _amount) external;
        // Protected storage
        function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
        function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
        function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
        function confirmWithdrawalAddress(address _nodeAddress) external;
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    interface RocketDAOProtocolSettingsNetworkInterface {
        function getNodeConsensusThreshold() external view returns (uint256);
        function getSubmitBalancesEnabled() external view returns (bool);
        function getSubmitBalancesFrequency() external view returns (uint256);
        function getSubmitPricesEnabled() external view returns (bool);
        function getSubmitPricesFrequency() external view returns (uint256);
        function getMinimumNodeFee() external view returns (uint256);
        function getTargetNodeFee() external view returns (uint256);
        function getMaximumNodeFee() external view returns (uint256);
        function getNodeFeeDemandRange() external view returns (uint256);
        function getTargetRethCollateralRate() external view returns (uint256);
        function getRethDepositDelay() external view returns (uint256);
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    interface RocketDepositPoolInterface {
        function getBalance() external view returns (uint256);
        function getExcessBalance() external view returns (uint256);
        function deposit() external payable;
        function recycleDissolvedDeposit() external payable;
        function recycleExcessCollateral() external payable;
        function recycleLiquidatedStake() external payable;
        function assignDeposits() external;
        function withdrawExcessBalance(uint256 _amount) external;
        function getUserLastDepositBlock(address _address) external view returns (uint256);
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    interface RocketNetworkBalancesInterface {
        function getBalancesBlock() external view returns (uint256);
        function getLatestReportableBlock() external view returns (uint256);
        function getTotalETHBalance() external view returns (uint256);
        function getStakingETHBalance() external view returns (uint256);
        function getTotalRETHSupply() external view returns (uint256);
        function getETHUtilizationRate() external view returns (uint256);
        function submitBalances(uint256 _block, uint256 _total, uint256 _staking, uint256 _rethSupply) external;
        function executeUpdateBalances(uint256 _block, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) external;
    }
    /**
      *       .
      *      / \\
      *     |.'.|
      *     |'.'|
      *   ,'|   |`.
      *  |,-'-|-'-.|
      *   __|_| |         _        _      _____           _
      *  | ___ \\|        | |      | |    | ___ \\         | |
      *  | |_/ /|__   ___| | _____| |_   | |_/ /__   ___ | |
      *  |    // _ \\ / __| |/ / _ \\ __|  |  __/ _ \\ / _ \\| |
      *  | |\\ \\ (_) | (__|   <  __/ |_   | | | (_) | (_) | |
      *  \\_| \\_\\___/ \\___|_|\\_\\___|\\__|  \\_|  \\___/ \\___/|_|
      * +---------------------------------------------------+
      * |    DECENTRALISED STAKING PROTOCOL FOR ETHEREUM    |
      * +---------------------------------------------------+
      *
      *  Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
      *  be community-owned, decentralised, and trustless.
      *
      *  For more information about Rocket Pool, visit https://rocketpool.net
      *
      *  Authors: David Rugendyke, Jake Pospischil, Kane Wallmann, Darren Langley, Joe Clapis, Nick Doherty
      *
      */
    pragma solidity 0.7.6;
    // SPDX-License-Identifier: GPL-3.0-only
    import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
    interface RocketTokenRETHInterface is IERC20 {
        function getEthValue(uint256 _rethAmount) external view returns (uint256);
        function getRethValue(uint256 _ethAmount) external view returns (uint256);
        function getExchangeRate() external view returns (uint256);
        function getTotalCollateral() external view returns (uint256);
        function getCollateralRate() external view returns (uint256);
        function depositExcess() external payable;
        function depositExcessCollateral() external;
        function mint(uint256 _ethAmount, address _to) external;
        function burn(uint256 _rethAmount) external;
    }
    

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