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

Blockscape Validator NFT

Workflow Diagram: Blockscape ETH Stake NFT

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

Git Source

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

Git Source

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

Git Source

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

Git Source

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

Git Source

enum MinipoolDeposit {
    None,
    Full,
    Half,
    Empty
}

MinipoolDetails

Git Source

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

Git Source

enum MinipoolStatus {
    Initialised,
    Prelaunch,
    Staking,
    Withdrawable,
    Dissolved
}

BlockscapeAccess

Git Source

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

Git Source

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

Git Source

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

Git Source

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

NameTypeDescription
<none>uint256the 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

NameTypeDescription
<none>RocketNodeStakingInterfacethe 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

NameTypeDescription
<none>uint256the RPLs needed

hasNodeEnoughRPLStake

has the node enough RPL to stake another minipool

function hasNodeEnoughRPLStake() public view returns (bool);

Returns

NameTypeDescription
<none>booltrue 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

NameTypeDescription
_newBlockscapeRocketPoolNodeaddressthe 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

NameTypeDescription
_stakedETHuint256the amount of ETH staked
_tokenIDuint256the tokenID of the NFT

getTokenID

the tokenID is incremented with every pool

function getTokenID() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256the current tokenID

getBalance

how much balance does this contract current have

function getBalance() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256amount in wei

getMetadata

gets the metadata of a given pool

function getMetadata(uint256 _tokenID) external view returns (Metadata memory);

Parameters

NameTypeDescription
_tokenIDuint256identifies the pool

Returns

NameTypeDescription
<none>MetadataBlockscapeStaking.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

NameTypeDescription
<none>boolis 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

NameTypeDescription
_amountuint256the 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

NameTypeDescription
_newTimelockuint256the 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

Git Source

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

NameTypeDescription
_tokenIDuint256Identifier 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

NameTypeDescription
_tokenIDuint256which 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

NameTypeDescription
_tokenIDuint256which NFT the staker wants to unstake
_useraddress

Returns

NameTypeDescription
_amountuint256how 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

NameTypeDescription
<none>uint256rewards 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

NameTypeDescription
_tokenIDuint256which the rewards are calculated for

Returns

NameTypeDescription
<none>uint256ETH rewards in wei minus the withdraw fee

totalSupply

how many NFTs are there totally

function totalSupply() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256total 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

NameTypeDescription
<none>stringthe 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

NameTypeDescription
_tokenIDuint256the pool

Returns

NameTypeDescription
<none>stringthe NFT metadata url

ValidatorAlreadySet

Git Source

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

Git Source

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

NameTypeDescription
_tokenIDuint256Identifier of the NFT
_valiaddressthe 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

NameTypeDescription
_tokenIDuint256which 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

NameTypeDescription
_tokenIDuint256the tokenID of the validator
_calcRewarduint256the 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

NameTypeDescription
_amountuint256the new comission

getCurrentEthLimit

the current depositing threshold

function getCurrentEthLimit() public view returns (uint256);

Returns

NameTypeDescription
<none>uint256the 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

NameTypeDescription
_tokenIDuint256which NFT the staker wants to unstake
_useraddress

Returns

NameTypeDescription
_amountuint256how 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

NameTypeDescription
_tokenIDuint256the tokenID of the NFT

Returns

NameTypeDescription
<none>addressthe 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

NameTypeDescription
_tokenIDuint256tokenID of the NFT, the user wants to unstake

Returns

NameTypeDescription
<none>uint256rewards in wei minus the withdraw fee

totalSupply

total amount of supply

function totalSupply() external view returns (uint256);

Returns

NameTypeDescription
<none>uint256total 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

NameTypeDescription
<none>stringthe 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

NameTypeDescription
_tokenIDuint256the pool

Returns

NameTypeDescription
<none>stringthe url