UNPKG

@nodeset/contracts

Version:

Protocol for accessing NodeSet's Constellation Ethereum staking network

284 lines (220 loc) 9.7 kB
import { RocketMinipoolDelegate, RocketMinipoolManager, RocketMinipoolFactory, RocketDAOProtocolSettingsMinipool, RocketNetworkPrices, RocketNodeDeposit, RocketDAOProtocolSettingsNode, RocketStorage, RocketNodeStaking, RocketNodeDepositNew, RocketNodeStakingNew, } from '../_utils/artifacts'; import { getValidatorPubkey, getValidatorSignature, getDepositDataRoot } from '../_utils/beacon'; import { assertBN } from './bn'; // Possible states that a proposal may be in export const minipoolStates = { Initialised: 0, Prelaunch: 1, Staking: 2, Withdrawable: 3, Dissolved: 4 }; // Get the number of minipools a node has export async function getNodeMinipoolCount(nodeAddress) { const rocketMinipoolManager = await RocketMinipoolManager.deployed(); let count = await rocketMinipoolManager.getNodeMinipoolCount.call(nodeAddress); return count; } // Get the number of minipools a node has in Staking status export async function getNodeStakingMinipoolCount(nodeAddress) { const rocketMinipoolManager = await RocketMinipoolManager.deployed(); let count = await rocketMinipoolManager.getNodeStakingMinipoolCount.call(nodeAddress); return count; } // Get the number of minipools a node has in that are active export async function getNodeActiveMinipoolCount(nodeAddress) { const rocketMinipoolManager = await RocketMinipoolManager.deployed(); let count = await rocketMinipoolManager.getNodeActiveMinipoolCount.call(nodeAddress); return count; } // Get the minimum required RPL stake for a minipool export async function getMinipoolMinimumRPLStake() { // Load contracts const [ rocketDAOProtocolSettingsMinipool, rocketNetworkPrices, rocketDAOProtocolSettingsNode, ] = await Promise.all([ RocketDAOProtocolSettingsMinipool.deployed(), RocketNetworkPrices.deployed(), RocketDAOProtocolSettingsNode.deployed(), ]); // Load data let [depositUserAmount, minMinipoolStake, rplPrice] = await Promise.all([ rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount(), rocketDAOProtocolSettingsNode.getMinimumPerMinipoolStake(), rocketNetworkPrices.getRPLPrice(), ]); // Calculate & return return depositUserAmount.mul(minMinipoolStake).div(rplPrice); } let minipoolSalt = 1 // Create a minipool export async function createMinipool(txOptions, salt = null) { return createMinipoolWithBondAmount(txOptions.value, txOptions, salt); } // Function to generate deposit data for creating a minipool export async function generateDepositData(sender, salt) { const rocketMinipoolFactory = await RocketMinipoolFactory.deployed(); let minipoolAddress = (await rocketMinipoolFactory.getExpectedAddress(sender, salt)).substr(2); let withdrawalCredentials = '0x010000000000000000000000' + minipoolAddress; // Get validator deposit data let depositData = { pubkey: getValidatorPubkey(), withdrawalCredentials: Buffer.from(withdrawalCredentials.substr(2), 'hex'), amount: BigInt(1000000000), // gwei signature: getValidatorSignature(), }; // Calculate the deposit data root - this might involve hashing the deposit data // depending on your implementation specifics. let depositDataRoot = getDepositDataRoot(depositData); // Return the deposit data and its root return { depositData, depositDataRoot, minipoolAddress }; } export async function generateDepositDataForStake(minipoolAddress) { // Get contracts const rocketMinipoolManager = await RocketMinipoolManager.deployed(); // Get minipool validator pubkey const validatorPubkey = await rocketMinipoolManager.getMinipoolPubkey(minipoolAddress); // Get minipool withdrawal credentials let withdrawalCredentials = await rocketMinipoolManager.getMinipoolWithdrawalCredentials.call(minipoolAddress); // Get validator deposit data const depositData = { pubkey: Buffer.from(validatorPubkey.substr(2), 'hex'), withdrawalCredentials: Buffer.from(withdrawalCredentials.substr(2), 'hex'), amount: BigInt(31000000000), // gwei signature: getValidatorSignature(), }; // Calculate the deposit data root - this might involve hashing the deposit data // depending on your implementation specifics. let depositDataRoot = getDepositDataRoot(depositData); // Return the deposit data and its root return { depositData, depositDataRoot }; } export async function createMinipoolWithBondAmount(bondAmount, txOptions, salt = null) { // Load contracts const [ rocketMinipoolFactory, rocketNodeDeposit, rocketNodeStaking, rocketStorage, ] = await Promise.all([ RocketMinipoolFactory.deployed(), RocketNodeDepositNew.deployed(), RocketNodeStakingNew.deployed(), RocketStorage.deployed() ]); // Get minipool contract bytecode let contractBytecode; if (salt === null) { salt = minipoolSalt++; } let minipoolAddress = (await rocketMinipoolFactory.getExpectedAddress(txOptions.from, salt)).substr(2); let withdrawalCredentials = '0x010000000000000000000000' + minipoolAddress; // Make node deposit const ethMatched1 = await rocketNodeStaking.getNodeETHMatched(txOptions.from); // Get validator deposit data let depositData = { pubkey: getValidatorPubkey(), withdrawalCredentials: Buffer.from(withdrawalCredentials.substr(2), 'hex'), amount: BigInt(1000000000), // gwei signature: getValidatorSignature(), }; let depositDataRoot = getDepositDataRoot(depositData); if (txOptions.value.eq(bondAmount)) { await rocketNodeDeposit.deposit(bondAmount, 0, depositData.pubkey, depositData.signature, depositDataRoot, salt, '0x' + minipoolAddress, txOptions); } else { await rocketNodeDeposit.depositWithCredit(bondAmount, 0, depositData.pubkey, depositData.signature, depositDataRoot, salt, '0x' + minipoolAddress, txOptions); } const ethMatched2 = await rocketNodeStaking.getNodeETHMatched(txOptions.from); // Expect node's ETH matched to be increased by (32 - bondAmount) assertBN.equal(ethMatched2.sub(ethMatched1), ethers.utils.parseEther("32").sub(bondAmount), 'Incorrect ETH matched'); return RocketMinipoolDelegate.at('0x' + minipoolAddress); } // Create a vacant minipool export async function createVacantMinipool(bondAmount, txOptions, salt = null, currentBalance = '32'.ether, pubkey = null) { // Load contracts const [ rocketMinipoolFactory, rocketNodeDeposit, rocketNodeStaking, rocketStorage, ] = await Promise.all([ RocketMinipoolFactory.deployed(), RocketNodeDeposit.deployed(), RocketNodeStaking.deployed(), RocketStorage.deployed() ]); if (salt === null) { salt = minipoolSalt++; } if (pubkey === null) { pubkey = getValidatorPubkey(); } const minipoolAddress = (await rocketMinipoolFactory.getExpectedAddress(txOptions.from, salt)).substr(2); const ethMatched1 = await rocketNodeStaking.getNodeETHMatched(txOptions.from); await rocketNodeDeposit.createVacantMinipool(bondAmount, '0'.ether, pubkey, salt, '0x' + minipoolAddress, currentBalance, txOptions); const ethMatched2 = await rocketNodeStaking.getNodeETHMatched(txOptions.from); // Expect node's ETH matched to be increased by (32 - bondAmount) assertBN.equal(ethMatched2.sub(ethMatched1), '32'.ether.sub(bondAmount), 'Incorrect ETH matched'); return RocketMinipoolDelegate.at('0x' + minipoolAddress); } // Refund node ETH from a minipool export async function refundMinipoolNodeETH(minipool, txOptions) { await minipool.refund(txOptions); } // Progress a minipool to staking export async function stakeMinipool(minipool, txOptions) { // Get contracts const rocketMinipoolManager = await RocketMinipoolManager.deployed(); // Get minipool validator pubkey const validatorPubkey = await rocketMinipoolManager.getMinipoolPubkey(minipool.address); // Get minipool withdrawal credentials let withdrawalCredentials = await rocketMinipoolManager.getMinipoolWithdrawalCredentials.call(minipool.address); // Check if legacy or new minipool let legacy = !(await minipool.getDepositType()).eq('4'.BN); // Get validator deposit data let depositData; if (legacy) { depositData = { pubkey: Buffer.from(validatorPubkey.substr(2), 'hex'), withdrawalCredentials: Buffer.from(withdrawalCredentials.substr(2), 'hex'), amount: BigInt(16000000000), // gwei signature: getValidatorSignature(), }; } else { depositData = { pubkey: Buffer.from(validatorPubkey.substr(2), 'hex'), withdrawalCredentials: Buffer.from(withdrawalCredentials.substr(2), 'hex'), amount: BigInt(31000000000), // gwei signature: getValidatorSignature(), }; } let depositDataRoot = getDepositDataRoot(depositData); // Stake await minipool.stake(depositData.signature, depositDataRoot, txOptions); } // Promote a minipool to staking export async function promoteMinipool(minipool, txOptions) { await minipool.promote(txOptions); } // Dissolve a minipool export async function dissolveMinipool(minipool, txOptions) { await minipool.dissolve(txOptions); } // Close a dissolved minipool and destroy it export async function closeMinipool(minipool, txOptions) { await minipool.close(txOptions); }