Blockscape Rocketscape
Blockscape Rocketscape is a smart contract solution that enables users to stake ETH and mint NFTs that represent their stake and rewards. Blockscape offers two types of NFTs: Blockscape Validator NFT and Blockscape ETH Stake NFT.
A Blockscape Validator NFT is issued to a user who stakes 16 ETH with Blockscape. This NFT represents a Validator on the Blockscape platform, which is transparent and traceable on the beacon chain. The user can monitor their validator performance, rewards, and penalties through the NFT. The user can also transfer or sell their NFT at any time, or reedem the NFT for an Validator exit subject to the Ethereum 2.0 staking rules and penalties.
The Blockscape ETH Stake NFT is issued to a user who stakes any amount of ETH with Blockscape. This NFT entitles the user to participate in a pool of stakers that are staking for them on the Blockscape platform. The user can also transfer or sell their NFT at any time, or reedem the NFT for a validator exit subject to the Ethereum staking rules and penalties.
Blockscape aims to provide a user-friendly and secure way for users to stake ETH and earn rewards, while also creating a new market for financial NFTs that have intrinsic value and utility
This project uses Foundry. MAINNET_RPC_URL
assumes to have a shell exported ethereum mainnet node endpoint url, e.g. through export MAINNET_RPC_URL=https://mainnet.infura.io/v3/API_KEY
.
For more commands please consult the Makefile where you can run commands by using make
- e.g. make test-coverage
.
Live Deployment
Goerli Playground https://stakedev.blockscape.network/pstake/ETH/solo/
Deploy by yourself
forge script script/DeployGoerli_BlockscapeValidatorNFTGoerli.s.sol --fork-url $GOERLI_RPC_URL --broadcast --verify --optimize
Workflow Diagram: Blockscape Validator NFT
Workflow Diagram: Blockscape ETH Stake NFT
Run test locally
forge test -vv --fork-url $MAINNET_RPC_URL --fork-block-number=16376809 --match-contract BlockscapeValidatorNFT
Git Clone
Please clone the repo with --recursive
flag to clone the submodules.
git clone --recursive https://github.com/BlockscapeNetwork/rocketscape
Contents
Contents
- RocketMinipoolInterface
- RocketNodeDepositInterface
- RocketNodeStakingInterface
- RocketStorageInterface
RocketMinipoolInterface
Functions
initialise
function initialise(address _nodeAddress, MinipoolDeposit _depositType) external;
getStatus
function getStatus() external view returns (MinipoolStatus);
getFinalised
function getFinalised() external view returns (bool);
getStatusBlock
function getStatusBlock() external view returns (uint256);
getStatusTime
function getStatusTime() external view returns (uint256);
getScrubVoted
function getScrubVoted(address _member) external view returns (bool);
getDepositType
function getDepositType() external view returns (MinipoolDeposit);
getNodeAddress
function getNodeAddress() external view returns (address);
getNodeFee
function getNodeFee() external view returns (uint256);
getNodeDepositBalance
function getNodeDepositBalance() external view returns (uint256);
getNodeRefundBalance
function getNodeRefundBalance() external view returns (uint256);
getNodeDepositAssigned
function getNodeDepositAssigned() external view returns (bool);
getUserDepositBalance
function getUserDepositBalance() external view returns (uint256);
getUserDepositAssigned
function getUserDepositAssigned() external view returns (bool);
getUserDepositAssignedTime
function getUserDepositAssignedTime() external view returns (uint256);
getTotalScrubVotes
function getTotalScrubVotes() external view returns (uint256);
calculateNodeShare
function calculateNodeShare(uint256 _balance) external view returns (uint256);
calculateUserShare
function calculateUserShare(uint256 _balance) external view returns (uint256);
nodeDeposit
function nodeDeposit(bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot)
external
payable;
userDeposit
function userDeposit() external payable;
distributeBalance
function distributeBalance() external;
distributeBalanceAndFinalise
function distributeBalanceAndFinalise() external;
refund
function refund() external;
slash
function slash() external;
finalise
function finalise() external;
canStake
function canStake() external view returns (bool);
stake
function stake(bytes calldata _validatorSignature, bytes32 _depositDataRoot) external;
setWithdrawable
function setWithdrawable() external;
dissolve
function dissolve() external;
close
function close() external;
voteScrub
function voteScrub() external;
RocketNodeDepositInterface
Functions
deposit
function deposit(
uint256 _minimumNodeFee,
bytes calldata _validatorPubkey,
bytes calldata _validatorSignature,
bytes32 _depositDataRoot,
uint256 _salt,
address _expectedMinipoolAddress
) external payable;
getDepositType
function getDepositType(uint256 _amount) external view returns (MinipoolDeposit);
RocketNodeStakingInterface
Functions
getTotalRPLStake
function getTotalRPLStake() external view returns (uint256);
getNodeRPLStake
function getNodeRPLStake(address _nodeAddress) external view returns (uint256);
getNodeRPLStakedTime
function getNodeRPLStakedTime(address _nodeAddress) external view returns (uint256);
getTotalEffectiveRPLStake
function getTotalEffectiveRPLStake() external view returns (uint256);
calculateTotalEffectiveRPLStake
function calculateTotalEffectiveRPLStake(uint256 offset, uint256 limit, uint256 rplPrice)
external
view
returns (uint256);
getNodeEffectiveRPLStake
function getNodeEffectiveRPLStake(address _nodeAddress) external view returns (uint256);
getNodeMinimumRPLStake
function getNodeMinimumRPLStake(address _nodeAddress) external view returns (uint256);
getNodeMaximumRPLStake
function getNodeMaximumRPLStake(address _nodeAddress) external view returns (uint256);
getNodeMinipoolLimit
function getNodeMinipoolLimit(address _nodeAddress) external view returns (uint256);
stakeRPL
function stakeRPL(uint256 _amount) external;
stakeRPLFor
function stakeRPLFor(address _nodeAddress, uint256 _amount) external;
withdrawRPL
function withdrawRPL(uint256 _amount) external;
slashRPL
function slashRPL(address _nodeAddress, uint256 _ethSlashAmount) external;
RocketStorageInterface
Functions
getDeployedStatus
function getDeployedStatus() external view returns (bool);
getGuardian
function getGuardian() external view returns (address);
setGuardian
function setGuardian(address _newAddress) external;
confirmGuardian
function confirmGuardian() external;
getAddress
function getAddress(bytes32 _key) external view returns (address);
getUint
function getUint(bytes32 _key) external view returns (uint256);
getString
function getString(bytes32 _key) external view returns (string memory);
getBytes
function getBytes(bytes32 _key) external view returns (bytes memory);
getBool
function getBool(bytes32 _key) external view returns (bool);
getInt
function getInt(bytes32 _key) external view returns (int256);
getBytes32
function getBytes32(bytes32 _key) external view returns (bytes32);
setAddress
function setAddress(bytes32 _key, address _value) external;
setUint
function setUint(bytes32 _key, uint256 _value) external;
setString
function setString(bytes32 _key, string calldata _value) external;
setBytes
function setBytes(bytes32 _key, bytes calldata _value) external;
setBool
function setBool(bytes32 _key, bool _value) external;
setInt
function setInt(bytes32 _key, int256 _value) external;
setBytes32
function setBytes32(bytes32 _key, bytes32 _value) external;
deleteAddress
function deleteAddress(bytes32 _key) external;
deleteUint
function deleteUint(bytes32 _key) external;
deleteString
function deleteString(bytes32 _key) external;
deleteBytes
function deleteBytes(bytes32 _key) external;
deleteBool
function deleteBool(bytes32 _key) external;
deleteInt
function deleteInt(bytes32 _key) external;
deleteBytes32
function deleteBytes32(bytes32 _key) external;
addUint
function addUint(bytes32 _key, uint256 _amount) external;
subUint
function subUint(bytes32 _key, uint256 _amount) external;
getNodeWithdrawalAddress
function getNodeWithdrawalAddress(address _nodeAddress) external view returns (address);
getNodePendingWithdrawalAddress
function getNodePendingWithdrawalAddress(address _nodeAddress) external view returns (address);
setWithdrawalAddress
function setWithdrawalAddress(address _nodeAddress, address _newWithdrawalAddress, bool _confirm) external;
confirmWithdrawalAddress
function confirmWithdrawalAddress(address _nodeAddress) external;
Contents
MinipoolDeposit
enum MinipoolDeposit {
None,
Full,
Half,
Empty
}
MinipoolDetails
struct MinipoolDetails {
bool exists;
address minipoolAddress;
bytes pubkey;
MinipoolStatus status;
uint256 statusBlock;
uint256 statusTime;
bool finalised;
MinipoolDeposit depositType;
uint256 nodeFee;
uint256 nodeDepositBalance;
bool nodeDepositAssigned;
uint256 userDepositBalance;
bool userDepositAssigned;
uint256 userDepositAssignedTime;
bool useLatestDelegate;
address delegate;
address previousDelegate;
address effectiveDelegate;
uint256 penaltyCount;
uint256 penaltyRate;
}
MinipoolStatus
enum MinipoolStatus {
Initialised,
Prelaunch,
Staking,
Withdrawable,
Dissolved
}
BlockscapeAccess
Inherits: AccessControl
State Variables
ADJ_CONFIG_ROLE
role to adjust the config of the smart contract parameters
bytes32 internal constant ADJ_CONFIG_ROLE = keccak256("ADJ_CONFIG_ROLE");
RP_BACKEND_ROLE
role for the backendController executer
bytes32 internal constant RP_BACKEND_ROLE = keccak256("RP_BACKEND_ROLE");
EMERGENCY_ROLE
role to open / close vault in cases of emergencies
bytes32 internal constant EMERGENCY_ROLE = keccak256("EMERGENCY_ROLE");
Functions
constructor
constructor(address adj_config_role, address rp_backend_role, address emergency_role);
BlockscapeErrors
Errors
ErrorVaultState
The vault is in the wrong state
error ErrorVaultState(bool _isOpen);
NotEnoughRPLStake
more RPL stake has to be done in order to open vault
error NotEnoughRPLStake();
IncorrectDepositValueSent
Deposit value needs to align with RP poolsizes as specified in curETHlimit
error IncorrectDepositValueSent();
AlreadyPreparingForWithdrawal
The vault is already preparing for withdrawal
error AlreadyPreparingForWithdrawal();
WithdrawalTimelockNotReached
The withdrawal has a timelock which is not yet reached
error WithdrawalTimelockNotReached(uint256 unlockTimestamp);
YouDontOwnThisNft
user does not own the NFT
error YouDontOwnThisNft(uint256 _tokenID);
BlockscapeEvents
Events
StakeUpdated
event for when the NFT stake is updated
event StakeUpdated(uint256 indexed _tokenID, address indexed _owner, uint256 _newStake);
ETHLimitChanged
event for when the ETH limit is changed
event ETHLimitChanged(uint256 _newLimit);
UserRequestedWithdrawalVali
event for when a user requests a withdrawal for a Validator NFT
event UserRequestedWithdrawalVali(
uint256 indexed _tokenID, address indexed _user, uint256 _fee, uint256 _stakedETH, uint256 _rewards
);
UserRequestedWithdrawalStake
event for when a user requests a withdrawal for a Stake ETH NFT
event UserRequestedWithdrawalStake(
uint256 indexed _tokenID, address indexed _user, uint256 _stakedETH, uint256 _rewards
);
RocketPoolNodeAddressChanged
event for when the RocketPool Node Address is changed
event RocketPoolNodeAddressChanged(address _newAddress);
WithdrawFeeChanged
event for when the withdraw fee is changed
event WithdrawFeeChanged(uint256 _newFee);
TimelockWithdrawChanged
event for when the timelock for a withdrawal is changed
event TimelockWithdrawChanged(uint256 _newTimelock);
EmergencyVaultStateChanged
event for when the vault is opened / closed in case of emergency
event EmergencyVaultStateChanged(bool _isOpen);
BlockscapeShared
Inherits: BlockscapeAccess, BlockscapeErrors, BlockscapeEvents
State Variables
vaultOpen
using OZs sendValue implementation
the initial vault state is open
bool internal vaultOpen = true;
rpComm8
current initial RP commission for 8 ETH minipools, public for transparency
uint256 public rpComm8 = 14;
blockscapeRocketPoolNode
Blockscape Rocket Pool Node Address, public for transparency
address payable public blockscapeRocketPoolNode = payable(0xF6132f532ABc3902EA2DcaE7f8D7FCCdF7Ba4982);
tokenID
initial tokenID
the tokenID is used to identify the NFTs
uint256 internal tokenID = 1;
timelockWithdraw
the current timelock for a withdrawal request, public for transparency
uint256 public timelockWithdraw = 7 days;
initWithdrawFee
current initial withdraw fee, public for transparency
uint256 public initWithdrawFee = 20 * 1e18;
senderToTimestamp
Mapping withdrawal requester to timestamp of request to keep record, public for use in UI
mapping(address => uint256) public senderToTimestamp;
tokenIDtoMetadata
Mappings of tokenID to Metadata
mapping(uint256 => Metadata) internal tokenIDtoMetadata;
tokenIDToExitReward
Mappings of tokenID to the final exit reward for the staker
mapping(uint256 => uint256) public tokenIDToExitReward;
ROCKET_STORAGE
RocketStorageInterface of rocketpool
RocketStorageInterface internal constant ROCKET_STORAGE =
RocketStorageInterface(0x1d8f8f00cfa6758d7bE78336684788Fb0ee0Fa46);
Functions
getAvailableRPLStake
show the currently available RPL stake which is needed to create a pool on rocketscape
function getAvailableRPLStake() public view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | the current available RPL stake with already deducted minimum stake |
getLatestRocketNodeStaking
rocketpool contract interface for interactions with the rocketNodeStaking contract
function getLatestRocketNodeStaking() internal view returns (RocketNodeStakingInterface);
Returns
Name | Type | Description |
---|---|---|
<none> | RocketNodeStakingInterface | the rocketNodeStaking contract interface |
getReqRPLStake
calculates the required RPL needed to stake according to poolsize
if the minipoollimit is 0
then the required stake is also 0
!
function getReqRPLStake() public view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | the RPLs needed |
hasNodeEnoughRPLStake
has the node enough RPL to stake another minipool
function hasNodeEnoughRPLStake() public view returns (bool);
Returns
Name | Type | Description |
---|---|---|
<none> | bool | true if the node has enough RPL to stake another minipool |
setBlockscapeRocketPoolNode
gets used if blockscape changes the address of their rp node
function setBlockscapeRocketPoolNode(address _newBlockscapeRocketPoolNode) external onlyRole(ADJ_CONFIG_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_newBlockscapeRocketPoolNode | address | the new address of the rocketpool node |
_setMetadataForStakeInternal
sets the stakedETH and stakedTimestamp for a given tokenID inm the Metadata struct
function _setMetadataForStakeInternal(uint256 _stakedETH, uint256 _tokenID) internal;
Parameters
Name | Type | Description |
---|---|---|
_stakedETH | uint256 | the amount of ETH staked |
_tokenID | uint256 | the tokenID of the NFT |
getTokenID
the tokenID is incremented with every pool
function getTokenID() public view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | the current tokenID |
getBalance
how much balance does this contract current have
function getBalance() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | amount in wei |
getMetadata
gets the metadata of a given pool
function getMetadata(uint256 _tokenID) external view returns (Metadata memory);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | identifies the pool |
Returns
Name | Type | Description |
---|---|---|
<none> | Metadata | BlockscapeStaking.Metadata of the pool |
openVault
makes the vault stakable again after it has been closed
is triggered when the vault can be staked at rocketpool
function openVault() external onlyRole(EMERGENCY_ROLE);
_openVaultInternal
opens the vault after the recent Validator data has been updated and is associated with the recent _tokenID
function _openVaultInternal() internal;
closeVault
is triggered when the vault can be staked at rocketpool
future staking interactions are prevented afterwards
function closeVault() external onlyRole(EMERGENCY_ROLE);
_closeVaultInternal
closes the vault to temporarily prevent further depositing
function _closeVaultInternal() internal;
isVaultOpen
does the vault currently allow depositing
the backend controller will reopen then vault after the stake have been transferred
function isVaultOpen() public view returns (bool);
Returns
Name | Type | Description |
---|---|---|
<none> | bool | is depositing enabled |
changeWithdrawFee
the withdraw fee might be changed in the future, but cannot be higher than 20%
only the user with the ADJ_CONFIG_ROLE can call this function
function changeWithdrawFee(uint256 _amount) external onlyRole(ADJ_CONFIG_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_amount | uint256 | the new fee in wei |
changeTimelockWithdraw
the timelock for withdraw might be changed in the future, but cannot be higher than 7 days
only the user with the ADJ_CONFIG_ROLE can call this function
function changeTimelockWithdraw(uint256 _newTimelock) external onlyRole(ADJ_CONFIG_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_newTimelock | uint256 | the new timelock period in days |
receive
allow contract to receive ETH without making a delegated call
receive() external payable;
prepareWithdrawalProcess
allow user to request a withdrawal
function prepareWithdrawalProcess(uint256 _tokenID) external virtual;
withdrawFunds
enable the user to withdraw his/her funds
function withdrawFunds(uint256 _tokenID) external virtual;
calcWithdrawFee
calculates the withdraw fee for a given user and tokenID
function calcWithdrawFee(uint256 _tokenID, address _user) public view virtual returns (uint256 _amount);
Structs
Metadata
Metadata struct
struct Metadata {
uint256 stakedETH;
uint256 stakedTimestamp;
}
BlockscapeETHStakeNFT
Inherits: ERC1155Supply, ReentrancyGuard, BlockscapeAccess, BlockscapeShared
Author: Blockscape Finance AG info@blockscape.network
collects ETH, mints NFT in return for stake, which can be any amount of ETH. The ETH is staked in the blockscape rocketpool infrastructure.
State Variables
poolSupply
tracks the ETH pool supply
uint256 private poolSupply;
name
constant used for blockexplorers to display the name of the token (as to be lower case as per blockexplorer standards)
string public constant name = "Blockscape ETH Stake NFTs";
symbol
constant used for blockexplorers to display the symbol of the token (as to be lower case as per blockexplorer standards)
string public constant symbol = "BSS";
Functions
constructor
each pool related vault gets its separate tokenID which depicts the nft for each staker
the IPNS makes sure the nfts stay reachable via this link while new nfts get added to the underlying ipfs folder
constructor()
ERC1155("https://ipfs.blockscape.network/ipns/" "TBD/" "{id}.json")
BlockscapeAccess(msg.sender, BlockscapeShared.blockscapeRocketPoolNode, msg.sender);
supportsInterface
needed as the OZ ERC1155 && AccessControl does both implement the supportsInterface function
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, AccessControl) returns (bool);
depositStakeNFT
used by stakers to deposit ETH into the contract
the vault must be open and enough RPL must be staked in the rocketpool by the node
the msg.value must be greater than 0
the msg.value is added to the poolSupply
if contract balance is greater than 8 ETH, the ETH is sent to the rocketpool node
function depositStakeNFT() external payable nonReentrant;
updateStake
update the stake of the given tokenID, if the NFT owner decides to stake more ETH
emits the StakeUpdated event & increases the poolSupply based on the msg.value
function updateStake(uint256 _tokenID) external payable;
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | Identifier of the vault |
prepareWithdrawalProcess
Withdraw is a two step process, first the staker has to call prepareWithdrawalProcess()
first step used by the staker when he or she wants to unstake
function prepareWithdrawalProcess(uint256 _tokenID) external override;
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | which ETH Stake NFT the staker wants to unstake the backend will listen on the event and will unstake the validator. The ETH value with rewards is transparantly available via beacon chain explorers and will be reduced by the withdraw fee, which is fixed to 0.5% after one year. |
withdrawFunds
used by the staker after prepareWithdrawalProcess() & the timelock has passed to withdraw the funds
the rewards are calculated by the backend controller and are then stored in the contract, this is needed to be able to calculate the rewards correctly including MEV rewards. There off-chain calculated rewards cannot be lower than the on-chain esimated rewards.
function withdrawFunds(uint256 _tokenID) external override nonReentrant;
getPoolSupply
returns the current ETH supply of the pool
function getPoolSupply() public view returns (uint256);
calcWithdrawFee
how much fees would the user have to pay if he or she would to unstake now within the first year of staking the fee is starting at 20% & decreasing linearly, afterwards 0.5%
function calcWithdrawFee(uint256 _tokenID, address _user) public view override returns (uint256 _amount);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | which NFT the staker wants to unstake |
_user | address |
Returns
Name | Type | Description |
---|---|---|
_amount | uint256 | how much the user would pay on fees in percent*1e18 |
calcApr
this function is a on-chain calculation of the rocketpool ETH rewards.
It does take MEV (estimated) into account.
exp(((31556926 / 384) * 64) / 31622 / sqrt(balanceStaked)) - 1) * 100 - 0.5
31556926 = seconds per year
384 = seconds per epoch
31556926 / 384 = epochs per year
64 = BASE_REWARD_FACTOR
31622 = sqrt(gwei per ETH)
166.32368815e18 = ((31556926 / 384) * 64) / 31622
0x00000000219ab540356cBB839Cbe05303d7705Fa = deposit contract address
function calcApr() internal view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | rewards annual procentage rate * 1e18 |
calcRewards
calculates the rewards for the staker based on the current APR and the time staked
function calcRewards(uint256 _tokenID) internal view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | which the rewards are calculated for |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | ETH rewards in wei minus the withdraw fee |
totalSupply
how many NFTs are there totally
function totalSupply() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | total amount of NFTs minted |
contractURI
stake nft metdata location
this path will never change as the contract defines a collection
function contractURI() external pure returns (string memory);
Returns
Name | Type | Description |
---|---|---|
<none> | string | the fixed collection metadata path |
uri
gets the url to the metadata of a given NFT tokenID
function uri(uint256 _tokenID) public pure override returns (string memory);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | the pool |
Returns
Name | Type | Description |
---|---|---|
<none> | string | the NFT metadata url |
ValidatorAlreadySet
Author: Blockscape Finance AG info@blockscape.network
collects staking, mints NFT in return for staker and let's backend controller transfer the stake when the pool is full (currently 16 ETH) and enough RPL are available
this implementation relies on a backend controller which is a core component of the implementation.
error message if a validator is already set
error ValidatorAlreadySet(address _vali);
BlockscapeValidatorNFT
Inherits: ERC1155Supply, ReentrancyGuard, BlockscapeAccess, BlockscapeShared
State Variables
name
name constant used for blockexplorers (as to be lower case as per blockexplorer standards)
string public constant name = "Blockscape Validator NFTs";
symbol
symbol constant used for blockexplorers (as to be lower case as per blockexplorer standards)
string public constant symbol = "BSV";
curETHlimit
Current Rocketpool Minipool Limit
uint256 private curETHlimit = 16 ether;
tokenIDtoValidator
mapping of tokenID to validator minipool address
mapping(uint256 => address) private tokenIDtoValidator;
Functions
constructor
each validator related vault gets its separate tokenID which depicts the nft for each staker
the IPNS makes sure the nfts stay reachable via this link while new nfts get added to the underlying ipfs folder
constructor()
ERC1155(
"https://ipfs.blockscape.network/ipns/" "k51qzi5uqu5di5eo5fzr1zypdsz0zct39zpct9s4wesjustul1caeofak3zoej/"
"{id}.json"
)
BlockscapeAccess(msg.sender, BlockscapeShared.blockscapeRocketPoolNode, msg.sender);
supportsInterface
needed as the OZ ERC1155 && AccessControl does both implement the supportsInterface function
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC1155, AccessControl) returns (bool);
depositValidatorNFT
used by stakers to deposit ETH into the contract
the vault must be open and equal the depositing amount
enought RPL must be staked in the rocketpool by the node
function depositValidatorNFT() external payable;
withdrawBatch
this gets triggered by the backend controller when a new token is minted
the backend controller is only able to withdraw the current ETH limit
function withdrawBatch() external onlyRole(RP_BACKEND_ROLE) nonReentrant;
updateValidator
update validator address for given token id only once after the NFT has been issued and the validator was created by the backend this function will only be called by the backend
works only once for a tokenID; it will reopen the vault
emits no event by design to reduce maintenance costs
function updateValidator(uint256 _tokenID, address _vali) external onlyRole(RP_BACKEND_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | Identifier of the NFT |
_vali | address | the current address of the validator |
prepareWithdrawalProcess
Withdraw is a two step process, first the staker has to call prepareWithdrawalProcess()
fist step used by the staker when he or she wants to unstake
function prepareWithdrawalProcess(uint256 _tokenID) external override;
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | which validator NFT the staker wants to unstake; the backend will listen on the event and will unstake the validator. The ETH value with rewards is transparantly available via beacon chain explorers and will be reduced by the withdraw fee, which is fixed to 0.5% after one year. |
withdrawFunds
used by the staker after prepareWithdrawalProcess() & the timelock has passed to withdraw the funds
the rewards are calculated by the backend controller and are then stored in the contract, this is needed to be able to calculate the rewards correctly including MEV rewards.
There off-chain calculated rewards cannot be lower than the on-chain estimated rewards.
function withdrawFunds(uint256 _tokenID) external override;
calcRewards
this function is called by the backend controller when the UserRequestedWithdrawal is emited
the rewards are calculated by the backend controller and are then stored in the contract, this is needed to be able to calculate the rewards correctly including MEV rewards. There off-chain calculated rewards cannot be lower than the on-chain estimated rewards.
function calcRewards(uint256 _tokenID, uint256 _calcReward) public onlyRole(RP_BACKEND_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | the tokenID of the validator |
_calcReward | uint256 | the calculated rewards in wei |
changeETHLimit8
the limit might change in the future if rocketpool supports smaller pool sizes (RPIP-8)
this function is only callable by our multisig wallet with ADJ_CONFIG_ROLE
it will only allow to set the limit to 8 ETH
function changeETHLimit8() external onlyRole(ADJ_CONFIG_ROLE);
lowerRPCommFee8
this function is only callable by our multisig wallet with ADJ_CONFIG_ROLE
this will set the comission fee for 8 ETH minipools
function lowerRPCommFee8(uint256 _amount) external onlyRole(ADJ_CONFIG_ROLE);
Parameters
Name | Type | Description |
---|---|---|
_amount | uint256 | the new comission |
getCurrentEthLimit
the current depositing threshold
function getCurrentEthLimit() public view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | the current ETH limit in wei |
calcWithdrawFee
how much fees would the user has to pay if he or she would unstake now within the first year of staking the fee is starting at 20% & decreasing linearly, afterwards 0.5%
function calcWithdrawFee(uint256 _tokenID, address _user) public view override returns (uint256 _amount);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | which NFT the staker wants to unstake |
_user | address |
Returns
Name | Type | Description |
---|---|---|
_amount | uint256 | how much the user would pay on fees in percent*1e18 |
getValidatorAddress
this function is used to get the validator address from the tokenID
function getValidatorAddress(uint256 _tokenID) public view returns (address);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | the tokenID of the NFT |
Returns
Name | Type | Description |
---|---|---|
<none> | address | the minipool address of the validator |
estRewardsNoMEV
this function is a on-chain calculation of the rocketpool ETH rewards. It does not take MEV into account & will only work correctly after the Shapella/Shanghai upgrade
function estRewardsNoMEV(uint256 _tokenID) internal view returns (uint256);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | tokenID of the NFT, the user wants to unstake |
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | rewards in wei minus the withdraw fee |
totalSupply
total amount of supply
function totalSupply() external view returns (uint256);
Returns
Name | Type | Description |
---|---|---|
<none> | uint256 | total amount of ERC-1155 tokens of the contract |
contractURI
stake nft metdata location
this path will never change as the contract defines a collection
function contractURI() external pure returns (string memory);
Returns
Name | Type | Description |
---|---|---|
<none> | string | the fixed collection metadata path |
uri
gets the url to the metadata of a given pool
function uri(uint256 _tokenID) public pure override returns (string memory);
Parameters
Name | Type | Description |
---|---|---|
_tokenID | uint256 | the pool |
Returns
Name | Type | Description |
---|---|---|
<none> | string | the url |