/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
pragma solidity >0.5.0 <0.9.0;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the amount of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the amount of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves `amount` tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 amount) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 amount) external returns (bool);
/**
* @dev Moves `amount` tokens from `from` to `to` using the
* allowance mechanism. `amount` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 amount) external returns (bool);
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
import "./IERC20.sol";
pragma solidity >0.5.0 <0.9.0;
interface IERC20Burnable is IERC20 {
function burn(uint256 amount) external;
function burnFrom(address account, uint256 amount) external;
}
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.2) (utils/cryptography/MerkleProof.sol)
pragma solidity ^0.8.0;
/**
* @dev These functions deal with verification of Merkle Tree proofs.
*
* The tree and the proofs can be generated using our
* https://github.com/OpenZeppelin/merkle-tree[JavaScript library].
* You will find a quickstart guide in the readme.
*
* WARNING: You should avoid using leaf values that are 64 bytes long prior to
* hashing, or use a hash function other than keccak256 for hashing leaves.
* This is because the concatenation of a sorted pair of internal nodes in
* the merkle tree could be reinterpreted as a leaf value.
* OpenZeppelin's JavaScript library generates merkle trees that are safe
* against this attack out of the box.
*/
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) {
return processProof(proof, leaf) == root;
}
/**
* @dev Calldata version of {verify}
*
* _Available since v4.7._
*/
function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool) {
return processProofCalldata(proof, leaf) == root;
}
/**
* @dev Returns the rebuilt hash obtained by traversing a Merkle tree up
* from `leaf` using `proof`. A `proof` is valid if and only if the rebuilt
* hash matches the root of the tree. When processing the proof, the pairs
* of leafs & pre-images are assumed to be sorted.
*
* _Available since v4.4._
*/
function processProof(bytes32[] memory proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Calldata version of {processProof}
*
* _Available since v4.7._
*/
function processProofCalldata(bytes32[] calldata proof, bytes32 leaf) internal pure returns (bytes32) {
bytes32 computedHash = leaf;
for (uint256 i = 0; i < proof.length; i++) {
computedHash = _hashPair(computedHash, proof[i]);
}
return computedHash;
}
/**
* @dev Returns true if the `leaves` can be simultaneously proven to be a part of a merkle tree defined by
* `root`, according to `proof` and `proofFlags` as described in {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerify(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProof(proof, proofFlags, leaves) == root;
}
/**
* @dev Calldata version of {multiProofVerify}
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function multiProofVerifyCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32 root,
bytes32[] memory leaves
) internal pure returns (bool) {
return processMultiProofCalldata(proof, proofFlags, leaves) == root;
}
/**
* @dev Returns the root of a tree reconstructed from `leaves` and sibling nodes in `proof`. The reconstruction
* proceeds by incrementally reconstructing all inner nodes by combining a leaf/inner node with either another
* leaf/inner node or a proof sibling node, depending on whether each `proofFlags` item is true or false
* respectively.
*
* CAUTION: Not all merkle trees admit multiproofs. To use multiproofs, it is sufficient to ensure that: 1) the tree
* is complete (but not necessarily perfect), 2) the leaves to be proven are in the opposite order they are in the
* tree (i.e., as seen from right to left starting at the deepest layer and continuing at the next layer).
*
* _Available since v4.7._
*/
function processMultiProof(
bytes32[] memory proof,
bool[] memory proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
/**
* @dev Calldata version of {processMultiProof}.
*
* CAUTION: Not all merkle trees admit multiproofs. See {processMultiProof} for details.
*
* _Available since v4.7._
*/
function processMultiProofCalldata(
bytes32[] calldata proof,
bool[] calldata proofFlags,
bytes32[] memory leaves
) internal pure returns (bytes32 merkleRoot) {
// This function rebuilds the root hash by traversing the tree up from the leaves. The root is rebuilt by
// consuming and producing values on a queue. The queue starts with the `leaves` array, then goes onto the
// `hashes` array. At the end of the process, the last hash in the `hashes` array should contain the root of
// the merkle tree.
uint256 leavesLen = leaves.length;
uint256 proofLen = proof.length;
uint256 totalHashes = proofFlags.length;
// Check proof validity.
require(leavesLen + proofLen - 1 == totalHashes, "MerkleProof: invalid multiproof");
// The xxxPos values are "pointers" to the next value to consume in each array. All accesses are done using
// `xxx[xxxPos++]`, which return the current value and increment the pointer, thus mimicking a queue's "pop".
bytes32[] memory hashes = new bytes32[](totalHashes);
uint256 leafPos = 0;
uint256 hashPos = 0;
uint256 proofPos = 0;
// At each step, we compute the next hash using two values:
// - a value from the "main queue". If not all leaves have been consumed, we get the next leaf, otherwise we
// get the next hash.
// - depending on the flag, either another value from the "main queue" (merging branches) or an element from the
// `proof` array.
for (uint256 i = 0; i < totalHashes; i++) {
bytes32 a = leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++];
bytes32 b = proofFlags[i]
? (leafPos < leavesLen ? leaves[leafPos++] : hashes[hashPos++])
: proof[proofPos++];
hashes[i] = _hashPair(a, b);
}
if (totalHashes > 0) {
require(proofPos == proofLen, "MerkleProof: invalid multiproof");
unchecked {
return hashes[totalHashes - 1];
}
} else if (leavesLen > 0) {
return leaves[0];
} else {
return proof[0];
}
}
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _efficientHash(a, b) : _efficientHash(b, a);
}
function _efficientHash(bytes32 a, bytes32 b) private pure returns (bytes32 value) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, a)
mstore(0x20, b)
value := keccak256(0x00, 0x40)
}
}
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
// A struct containing all the information on-chain about a specific node
struct NodeDetails {
bool exists;
uint256 registrationTime;
string timezoneLocation;
bool feeDistributorInitialised;
address feeDistributorAddress;
uint256 rewardNetwork;
uint256 rplStake;
uint256 effectiveRPLStake;
uint256 minimumRPLStake;
uint256 maximumRPLStake;
uint256 ethMatched;
uint256 ethMatchedLimit;
uint256 minipoolCount;
uint256 balanceETH;
uint256 balanceRETH;
uint256 balanceRPL;
uint256 balanceOldRPL;
uint256 depositCreditBalance;
uint256 distributorBalanceUserETH;
uint256 distributorBalanceNodeETH;
address withdrawalAddress;
address pendingWithdrawalAddress;
bool smoothingPoolRegistrationState;
uint256 smoothingPoolRegistrationChanged;
address nodeAddress;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
import "../interface/RocketStorageInterface.sol";
/// @title Base settings / modifiers for each contract in Rocket Pool
/// @author David Rugendyke
abstract contract RocketBase {
// Calculate using this as the base
uint256 constant calcBase = 1 ether;
// Version of the contract
uint8 public version;
// The main storage contract where primary persistant storage is maintained
RocketStorageInterface rocketStorage = RocketStorageInterface(address(0));
/*** Modifiers **********************************************************/
/**
* @dev Throws if called by any sender that doesn't match a Rocket Pool network contract
*/
modifier onlyLatestNetworkContract() {
require(getBool(keccak256(abi.encodePacked("contract.exists", msg.sender))), "Invalid or outdated network contract");
_;
}
/**
* @dev Throws if called by any sender that doesn't match one of the supplied contract or is the latest version of that contract
*/
modifier onlyLatestContract(string memory _contractName, address _contractAddress) {
require(_contractAddress == getAddress(keccak256(abi.encodePacked("contract.address", _contractName))), "Invalid or outdated contract");
_;
}
/**
* @dev Throws if called by any sender that isn't a registered node
*/
modifier onlyRegisteredNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("node.exists", _nodeAddress))), "Invalid node");
_;
}
/**
* @dev Throws if called by any sender that isn't a trusted node DAO member
*/
modifier onlyTrustedNode(address _nodeAddress) {
require(getBool(keccak256(abi.encodePacked("dao.trustednodes.", "member", _nodeAddress))), "Invalid trusted node");
_;
}
/**
* @dev Throws if called by any sender that isn't a registered minipool
*/
modifier onlyRegisteredMinipool(address _minipoolAddress) {
require(getBool(keccak256(abi.encodePacked("minipool.exists", _minipoolAddress))), "Invalid minipool");
_;
}
/**
* @dev Throws if called by any account other than a guardian account (temporary account allowed access to settings before DAO is fully enabled)
*/
modifier onlyGuardian() {
require(msg.sender == rocketStorage.getGuardian(), "Account is not a temporary guardian");
_;
}
/*** Methods **********************************************************/
/// @dev Set the main Rocket Storage address
constructor(RocketStorageInterface _rocketStorageAddress) {
// Update the contract address
rocketStorage = RocketStorageInterface(_rocketStorageAddress);
}
/// @dev Get the address of a network contract by name
function getContractAddress(string memory _contractName) internal view returns (address) {
// Get the current contract address
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
// Check it
require(contractAddress != address(0x0), "Contract not found");
// Return
return contractAddress;
}
/// @dev Get the address of a network contract by name (returns address(0x0) instead of reverting if contract does not exist)
function getContractAddressUnsafe(string memory _contractName) internal view returns (address) {
// Get the current contract address
address contractAddress = getAddress(keccak256(abi.encodePacked("contract.address", _contractName)));
// Return
return contractAddress;
}
/// @dev Get the name of a network contract by address
function getContractName(address _contractAddress) internal view returns (string memory) {
// Get the contract name
string memory contractName = getString(keccak256(abi.encodePacked("contract.name", _contractAddress)));
// Check it
require(bytes(contractName).length > 0, "Contract not found");
// Return
return contractName;
}
/// @dev Get revert error message from a .call method
function getRevertMsg(bytes memory _returnData) internal pure returns (string memory) {
// If the _res length is less than 68, then the transaction failed silently (without a revert message)
if (_returnData.length < 68) return "Transaction reverted silently";
assembly {
// Slice the sighash.
_returnData := add(_returnData, 0x04)
}
return abi.decode(_returnData, (string)); // All that remains is the revert string
}
/*** Rocket Storage Methods ****************************************/
// Note: Unused helpers have been removed to keep contract sizes down
/// @dev Storage get methods
function getAddress(bytes32 _key) internal view returns (address) { return rocketStorage.getAddress(_key); }
function getUint(bytes32 _key) internal view returns (uint) { return rocketStorage.getUint(_key); }
function getString(bytes32 _key) internal view returns (string memory) { return rocketStorage.getString(_key); }
function getBytes(bytes32 _key) internal view returns (bytes memory) { return rocketStorage.getBytes(_key); }
function getBool(bytes32 _key) internal view returns (bool) { return rocketStorage.getBool(_key); }
function getInt(bytes32 _key) internal view returns (int) { return rocketStorage.getInt(_key); }
function getBytes32(bytes32 _key) internal view returns (bytes32) { return rocketStorage.getBytes32(_key); }
/// @dev Storage set methods
function setAddress(bytes32 _key, address _value) internal { rocketStorage.setAddress(_key, _value); }
function setUint(bytes32 _key, uint _value) internal { rocketStorage.setUint(_key, _value); }
function setString(bytes32 _key, string memory _value) internal { rocketStorage.setString(_key, _value); }
function setBytes(bytes32 _key, bytes memory _value) internal { rocketStorage.setBytes(_key, _value); }
function setBool(bytes32 _key, bool _value) internal { rocketStorage.setBool(_key, _value); }
function setInt(bytes32 _key, int _value) internal { rocketStorage.setInt(_key, _value); }
function setBytes32(bytes32 _key, bytes32 _value) internal { rocketStorage.setBytes32(_key, _value); }
/// @dev Storage delete methods
function deleteAddress(bytes32 _key) internal { rocketStorage.deleteAddress(_key); }
function deleteUint(bytes32 _key) internal { rocketStorage.deleteUint(_key); }
function deleteString(bytes32 _key) internal { rocketStorage.deleteString(_key); }
function deleteBytes(bytes32 _key) internal { rocketStorage.deleteBytes(_key); }
function deleteBool(bytes32 _key) internal { rocketStorage.deleteBool(_key); }
function deleteInt(bytes32 _key) internal { rocketStorage.deleteInt(_key); }
function deleteBytes32(bytes32 _key) internal { rocketStorage.deleteBytes32(_key); }
/// @dev Storage arithmetic methods
function addUint(bytes32 _key, uint256 _amount) internal { rocketStorage.addUint(_key, _amount); }
function subUint(bytes32 _key, uint256 _amount) internal { rocketStorage.subUint(_key, _amount); }
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity 0.8.18;
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 "../../interface/node/RocketNodeManagerInterface.sol";
import "../../interface/rewards/RocketMerkleDistributorMainnetInterface.sol";
import "@openzeppelin4/contracts/utils/cryptography/MerkleProof.sol";
/// @dev 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, RocketMerkleDistributorMainnetInterface, RocketVaultWithdrawerInterface {
// 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 = 2;
// 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);
}
function claimAndStake(address _nodeAddress, uint256[] calldata _rewardIndex, uint256[] calldata _amountRPL, uint256[] calldata _amountETH, bytes32[][] calldata _merkleProof, uint256 _stakeAmount) public override {
_verifyClaim(_rewardIndex, _nodeAddress, _amountRPL, _amountETH, _merkleProof);
_claimAndStake(_nodeAddress, _rewardIndex, _amountRPL, _amountETH, _stakeAmount);
}
// 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, uint256 _stakeAmount) internal {
// Get contracts
RocketVaultInterface rocketVault = RocketVaultInterface(getAddress(rocketVaultKey));
address rplWithdrawalAddress;
address withdrawalAddress;
// Confirm caller is permitted
{
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
rplWithdrawalAddress = rocketNodeManager.getNodeRPLWithdrawalAddress(_nodeAddress);
withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
if (rocketNodeManager.getNodeRPLWithdrawalAddressIsSet(_nodeAddress)) {
if (_stakeAmount > 0) {
// If staking and RPL withdrawal address is set, must be called from RPL withdrawal address
require(msg.sender == rplWithdrawalAddress, "Can only claim and stake from RPL withdrawal address");
} else {
// Otherwise, must be called from RPL withdrawal address, node address or withdrawal address
require(msg.sender == rplWithdrawalAddress || msg.sender == _nodeAddress || msg.sender == withdrawalAddress, "Can only claim from withdrawal addresses or node address");
}
} else {
// If RPL withdrawal address isn't set, must be called from node address or withdrawal address
require(msg.sender == _nodeAddress || msg.sender == withdrawalAddress, "Can only claim from node address");
}
}
address rocketTokenRPLAddress = getAddress(rocketTokenRPLKey);
// Calculate totals
{
uint256 totalAmountRPL = 0;
uint256 totalAmountETH = 0;
for (uint256 i = 0; i < _rewardIndex.length; ++i) {
totalAmountRPL = totalAmountRPL + _amountRPL[i];
totalAmountETH = totalAmountETH + _amountETH[i];
}
// Validate input
require(_stakeAmount <= totalAmountRPL, "Invalid stake amount");
{
// Distribute any remaining tokens to the node's withdrawal address
uint256 remaining = totalAmountRPL - _stakeAmount;
if (remaining > 0) {
rocketVault.withdrawToken(rplWithdrawalAddress, IERC20(rocketTokenRPLAddress), remaining);
}
}
// Distribute ETH
if (totalAmountETH > 0) {
rocketVault.withdrawEther(totalAmountETH);
// Allow up to 10000 gas to send ETH to the withdrawal address
(bool result,) = withdrawalAddress.call{value: totalAmountETH, gas: 10000}("");
if (!result) {
// If the withdrawal address cannot accept the ETH with 10000 gas, add it to their balance to be claimed later at their own expense
bytes32 balanceKey = keccak256(abi.encodePacked('rewards.eth.balance', withdrawalAddress));
addUint(balanceKey, totalAmountETH);
// Return the ETH to the vault
rocketVault.depositEther{value: totalAmountETH}();
}
}
}
// 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);
}
// If ETH was claimed but was unable to be sent to the withdrawal address, it can be claimed via this function
function claimOutstandingEth() external override {
// Get contracts
RocketVaultInterface rocketVault = RocketVaultInterface(getAddress(rocketVaultKey));
// Get the amount and zero it out
bytes32 balanceKey = keccak256(abi.encodePacked('rewards.eth.balance', msg.sender));
uint256 amount = getUint(balanceKey);
setUint(balanceKey, 0);
// Withdraw the ETH from the vault
rocketVault.withdrawEther(amount);
// Attempt to send it to the caller
(bool result,) = payable(msg.sender).call{value: amount}("");
require(result, 'Transfer failed');
}
// Returns the amount of ETH that can be claimed by a withdrawal address
function getOutstandingEth(address _address) external override view returns (uint256) {
bytes32 balanceKey = keccak256(abi.encodePacked('rewards.eth.balance', _address));
return getUint(balanceKey);
}
// 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 _verifyClaim(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 given proof is valid
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 |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
import "./RocketRewardsRelayInterface.sol";
interface RocketMerkleDistributorMainnetInterface is RocketRewardsRelayInterface {
function claimOutstandingEth() external;
function getOutstandingEth(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, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
import "../../types/NodeDetails.sol";
interface RocketNodeManagerInterface {
// Structs
struct TimezoneCount {
string timezone;
uint256 count;
}
function getNodeCount() external view returns (uint256);
function getNodeCountPerTimezone(uint256 offset, uint256 limit) external view returns (TimezoneCount[] memory);
function getNodeAt(uint256 _index) external view returns (address);
function getNodeExists(address _nodeAddress) external view returns (bool);
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeRPLWithdrawalAddressIsSet(address _nodeAddress) external view returns (bool);
function unsetRPLWithdrawalAddress(address _nodeAddress) external;
function setRPLWithdrawalAddress(address _nodeAddress, address _newRPLWithdrawalAddress, bool _confirm) external;
function confirmRPLWithdrawalAddress(address _nodeAddress) external;
function getNodePendingRPLWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodeTimezoneLocation(address _nodeAddress) external view returns (string memory);
function registerNode(string calldata _timezoneLocation) external;
function getNodeRegistrationTime(address _nodeAddress) external view returns (uint256);
function setTimezoneLocation(string calldata _timezoneLocation) external;
function setRewardNetwork(address _nodeAddress, uint256 network) external;
function getRewardNetwork(address _nodeAddress) external view returns (uint256);
function getFeeDistributorInitialised(address _nodeAddress) external view returns (bool);
function initialiseFeeDistributor() external;
function getAverageNodeFee(address _nodeAddress) external view returns (uint256);
function setSmoothingPoolRegistrationState(bool _state) external;
function getSmoothingPoolRegistrationState(address _nodeAddress) external returns (bool);
function getSmoothingPoolRegistrationChanged(address _nodeAddress) external returns (uint256);
function getSmoothingPoolRegisteredNodeCount(uint256 _offset, uint256 _limit) external view returns (uint256);
function getNodeDetails(address _nodeAddress) external view returns (NodeDetails memory);
function getNodeAddresses(uint256 _offset, uint256 _limit) external view returns (address[] memory);
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
interface RocketNodeStakingInterface {
function getTotalRPLStake() external view returns (uint256);
function getNodeRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeETHMatched(address _nodeAddress) external view returns (uint256);
function getNodeETHProvided(address _nodeAddress) external view returns (uint256);
function getNodeETHCollateralisationRatio(address _nodeAddress) external view returns (uint256);
function getNodeRPLStakedTime(address _nodeAddress) external view returns (uint256);
function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeMinimumRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeMaximumRPLStake(address _nodeAddress) external view returns (uint256);
function getNodeETHMatchedLimit(address _nodeAddress) external view returns (uint256);
function getRPLLockingAllowed(address _nodeAddress) external view returns (bool);
function stakeRPL(uint256 _amount) external;
function stakeRPLFor(address _nodeAddress, uint256 _amount) external;
function setRPLLockingAllowed(address _nodeAddress, bool _allowed) external;
function setStakeRPLForAllowed(address _caller, bool _allowed) external;
function setStakeRPLForAllowed(address _nodeAddress, address _caller, bool _allowed) external;
function getNodeRPLLocked(address _nodeAddress) external view returns (uint256);
function lockRPL(address _nodeAddress, uint256 _amount) external;
function unlockRPL(address _nodeAddress, uint256 _amount) external;
function transferRPL(address _from, address _to, uint256 _amount) external;
function withdrawRPL(uint256 _amount) external;
function withdrawRPL(address _nodeAddress, uint256 _amount) external;
function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) external;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
interface 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 |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity >0.5.0 <0.9.0;
pragma abicoder v2;
interface RocketSmoothingPoolInterface {
function withdrawEther(address _to, uint256 _amount) external;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
interface RocketStorageInterface {
// Deploy status
function getDeployedStatus() external view returns (bool);
// Guardian
function getGuardian() external view returns(address);
function setGuardian(address _newAddress) external;
function confirmGuardian() external;
// Getters
function getAddress(bytes32 _key) external view returns (address);
function getUint(bytes32 _key) external view returns (uint);
function getString(bytes32 _key) external view returns (string memory);
function getBytes(bytes32 _key) external view returns (bytes memory);
function getBool(bytes32 _key) external view returns (bool);
function getInt(bytes32 _key) external view returns (int);
function getBytes32(bytes32 _key) external view returns (bytes32);
// Setters
function setAddress(bytes32 _key, address _value) external;
function setUint(bytes32 _key, uint _value) external;
function setString(bytes32 _key, string calldata _value) external;
function setBytes(bytes32 _key, bytes calldata _value) external;
function setBool(bytes32 _key, bool _value) external;
function setInt(bytes32 _key, int _value) external;
function setBytes32(bytes32 _key, bytes32 _value) external;
// Deleters
function deleteAddress(bytes32 _key) external;
function deleteUint(bytes32 _key) external;
function deleteString(bytes32 _key) external;
function deleteBytes(bytes32 _key) external;
function deleteBool(bytes32 _key) external;
function deleteInt(bytes32 _key) external;
function deleteBytes32(bytes32 _key) external;
// Arithmetic
function addUint(bytes32 _key, uint256 _amount) external;
function subUint(bytes32 _key, uint256 _amount) external;
// Protected storage
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
function confirmWithdrawalAddress(address _nodeAddress) external;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
import "../util/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;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
import "./util/IERC20Burnable.sol";
interface RocketVaultInterface {
function balanceOf(string memory _networkContractName) external view returns (uint256);
function depositEther() external payable;
function withdrawEther(uint256 _amount) external;
function depositToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
function withdrawToken(address _withdrawalAddress, IERC20 _tokenAddress, uint256 _amount) external;
function balanceOfToken(string memory _networkContractName, IERC20 _tokenAddress) external view returns (uint256);
function transferToken(string memory _networkContractName, IERC20 _tokenAddress, uint256 _amount) external;
function burnToken(IERC20Burnable _tokenAddress, uint256 _amount) external;
}
/**
* .
* / \
* |.'.|
* |'.'|
* ,'| |'.
* |,-'-|-'-.|
* __|_| | _ _ _____ _
* | ___ \| | | | | | ___ \ | |
* | |_/ /|__ ___| | _____| |_ | |_/ /__ ___ | |
* | // _ \ / __| |/ / _ \ __| | __/ _ \ / _ \| |
* | |\ \ (_) | (__| < __/ |_ | | | (_) | (_) | |
* \_| \_\___/ \___|_|\_\___|\__| \_| \___/ \___/|_|
* +---------------------------------------------------+
* | DECENTRALISED STAKING PROTOCOL FOR ETHEREUM |
* +---------------------------------------------------+
*
* Rocket Pool is a first-of-its-kind Ethereum staking pool protocol, designed to
* be community-owned, decentralised, permissionless, & trustless.
*
* For more information about Rocket Pool, visit https://rocketpool.net
*
* Authored by the Rocket Pool Core Team
* Contributors: https://github.com/rocket-pool/rocketpool/graphs/contributors
* A special thanks to the Rocket Pool community for all their contributions.
*
*/
pragma solidity >0.5.0 <0.9.0;
// SPDX-License-Identifier: GPL-3.0-only
interface RocketVaultWithdrawerInterface {
function receiveVaultWithdrawalETH() external payable;
}
{
"compilationTarget": {
"contracts/contract/rewards/RocketMerkleDistributorMainnet.sol": "RocketMerkleDistributorMainnet"
},
"evmVersion": "paris",
"libraries": {},
"metadata": {
"bytecodeHash": "ipfs"
},
"optimizer": {
"enabled": true,
"runs": 15000
},
"remappings": []
}
[{"inputs":[{"internalType":"contract RocketStorageInterface","name":"_rocketStorageAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"claimer","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"rewardIndex","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amountRPL","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"amountETH","type":"uint256[]"}],"name":"RewardsClaimed","type":"event"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256[]","name":"_rewardIndex","type":"uint256[]"},{"internalType":"uint256[]","name":"_amountRPL","type":"uint256[]"},{"internalType":"uint256[]","name":"_amountETH","type":"uint256[]"},{"internalType":"bytes32[][]","name":"_merkleProof","type":"bytes32[][]"}],"name":"claim","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_nodeAddress","type":"address"},{"internalType":"uint256[]","name":"_rewardIndex","type":"uint256[]"},{"internalType":"uint256[]","name":"_amountRPL","type":"uint256[]"},{"internalType":"uint256[]","name":"_amountETH","type":"uint256[]"},{"internalType":"bytes32[][]","name":"_merkleProof","type":"bytes32[][]"},{"internalType":"uint256","name":"_stakeAmount","type":"uint256"}],"name":"claimAndStake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"claimOutstandingEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_address","type":"address"}],"name":"getOutstandingEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardIndex","type":"uint256"},{"internalType":"address","name":"_claimer","type":"address"}],"name":"isClaimed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"receiveVaultWithdrawalETH","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_rewardIndex","type":"uint256"},{"internalType":"bytes32","name":"_root","type":"bytes32"},{"internalType":"uint256","name":"_rewardsRPL","type":"uint256"},{"internalType":"uint256","name":"_rewardsETH","type":"uint256"}],"name":"relayRewards","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"version","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]