From a4517c3397116dcc3c31281df2be1536823903af Mon Sep 17 00:00:00 2001 From: Kane Wallmann Date: Wed, 29 Jan 2025 11:56:11 +1000 Subject: [PATCH] Add global validator set, calc deposit data root on-chain, tweak interfaces --- .../megapool/RocketMegapoolDelegate.sol | 125 +++++++++++++++--- .../megapool/RocketMegapoolManager.sol | 43 ++++++ .../megapool/RocketMegapoolStorageLayout.sol | 5 +- contracts/contract/node/RocketNodeDeposit.sol | 3 + .../upgrade/RocketUpgradeOneDotFour.sol | 61 +++++---- .../RocketMegapoolDelegateInterface.sol | 2 +- .../RocketMegapoolManagerInterface.sol | 10 ++ test-upgrade/_helpers/upgrade.js | 3 + test/_helpers/deployment.js | 1 + test/_helpers/megapool.js | 15 ++- test/_utils/artifacts.js | 1 + test/megapool/scenario-exit-queue.js | 2 +- 12 files changed, 213 insertions(+), 58 deletions(-) create mode 100644 contracts/contract/megapool/RocketMegapoolManager.sol create mode 100644 contracts/interface/megapool/RocketMegapoolManagerInterface.sol diff --git a/contracts/contract/megapool/RocketMegapoolDelegate.sol b/contracts/contract/megapool/RocketMegapoolDelegate.sol index 6864d3fc..54c92739 100644 --- a/contracts/contract/megapool/RocketMegapoolDelegate.sol +++ b/contracts/contract/megapool/RocketMegapoolDelegate.sol @@ -1,21 +1,20 @@ // SPDX-License-Identifier: GPL-3.0-only pragma solidity 0.8.18; -pragma abicoder v2; -import "../RocketBase.sol"; -import "../../interface/RocketVaultInterface.sol"; -import "../../interface/deposit/RocketDepositPoolInterface.sol"; -import "../../interface/casper/DepositInterface.sol"; -import "../../interface/megapool/RocketMegapoolDelegateInterface.sol"; -import "../../interface/node/RocketNodeManagerInterface.sol"; -import "../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol"; -import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMegapoolInterface.sol"; -import "../../interface/token/RocketTokenRETHInterface.sol"; -import {RocketMegapoolProxy} from "./RocketMegapoolProxy.sol"; -import "./RocketMegapoolDelegateBase.sol"; - -import {BeaconStateVerifier} from "../util/BeaconStateVerifier.sol"; +import {RocketStorageInterface} from "../../interface/RocketStorageInterface.sol"; +import {RocketVaultInterface} from "../../interface/RocketVaultInterface.sol"; +import {DepositInterface} from "../../interface/casper/DepositInterface.sol"; +import {RocketDAONodeTrustedSettingsMinipoolInterface} from "../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol"; +import {RocketDAOProtocolSettingsMegapoolInterface} from "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMegapoolInterface.sol"; +import {RocketDepositPoolInterface} from "../../interface/deposit/RocketDepositPoolInterface.sol"; +import {RocketMegapoolDelegateInterface} from "../../interface/megapool/RocketMegapoolDelegateInterface.sol"; import {RocketNetworkRevenuesInterface} from "../../interface/network/RocketNetworkRevenuesInterface.sol"; +import {RocketNodeManagerInterface} from "../../interface/node/RocketNodeManagerInterface.sol"; +import {ValidatorProof, BeaconStateVerifierInterface} from "../../interface/util/BeaconStateVerifierInterface.sol"; +import {IERC20} from "../../interface/util/IERC20.sol"; +import {RocketMegapoolDelegateBase} from "./RocketMegapoolDelegateBase.sol"; +import {RocketMegapoolStorageLayout} from "./RocketMegapoolStorageLayout.sol"; +pragma abicoder v2; /// @title RocketMegapool /// @notice This contract manages multiple validators. It serves as the target of Beacon Chain withdrawal credentials. @@ -23,7 +22,7 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel // Constants uint256 constant internal prestakeValue = 1 ether; uint256 constant internal fullDepositValue = 32 ether; - uint256 constant internal milliToWei = 10**15; + uint256 constant internal milliToWei = 10 ** 15; uint256 constant internal calcBase = 1 ether; // Events @@ -69,10 +68,12 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel // Store prestake data { PrestakeData memory prestake; - prestake._depositDataRoot = _depositDataRoot; prestake._signature = _validatorSignature; prestakeData[validatorId] = prestake; } + // Compute and verify supplied deposit data root is correct + bytes32 depositDataRoot = computeDepositDataRoot(_validatorPubkey, _validatorSignature, uint64(prestakeValue / 1 gwei)); + require(depositDataRoot == _depositDataRoot, "Invalid deposit data root"); // Increase total bond used for bond requirement calculations nodeBond += _bondAmount; // Request full deposit amount from deposit pool @@ -81,6 +82,89 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel emit MegapoolValidatorEnqueued(address(this), validatorId, block.timestamp); } + function computeDepositDataRoot(bytes memory pubkey, bytes memory signature, uint64 amount) public view returns (bytes32 ret) { + bytes32 withdrawalCredentials = getWithdrawalCredentials(); + assembly { + let result + let temp := mload(0x40) + + // [0x00] = pubkey[0x00:0x20] + // [0x20] = pubkey[0x20:0x30] . bytes16(0) + mstore(0x00, mload(add(pubkey, 0x20))) + mstore(0x20, and(mload(add(pubkey, 0x40)), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000)) + + // temp[0x00] = sha256([0x00:0x40]) + result := staticcall(84, 0x02, 0x00, 0x40, temp, 0x20) + if iszero(result) { + revert(0, 0) + } + + // temp[0x20] = withdrawal_credentials + mstore(add(temp, 0x20), withdrawalCredentials) + + // temp[0x00] = sha256(temp[0x00:0x40]) + result := staticcall(84, 0x02, temp, 0x40, temp, 0x20) + if iszero(result) { + revert(0, 0) + } + + // temp[0x20] = sha256(signature[0x00:0x40]) + result := staticcall(84, 0x02, add(signature, 0x20), 0x40, add(temp, 0x20), 0x20) + if iszero(result) { + revert(0,0) + } + + // [0x00] = signature[0x40] + // [0x20] = bytes32(0) + mstore(0x00, mload(add(signature, 0x60))) + mstore(0x20, 0) + + // [0x20] = sha256([0x00:0x40]) + result := staticcall(84, 0x02, 0x00, 0x40, 0x20, 0x20) + if iszero(result) { + revert(0, 0) + } + + // [0x00] = temp[0x20] + mstore(0x00, mload(add(temp, 0x20))) + + // [0x20] = sha256([0x00:0x40]) + result := staticcall(84, 0x02, 0x00, 0x40, 0x20, 0x20) + if iszero(result) { + revert(0, 0) + } + + // [0x00] = to_little_endian(amount) . bytes24(0) + mstore(0x00, 0) + mstore8(0x00, shr(0x00, amount)) + mstore8(0x01, shr(0x08, amount)) + mstore8(0x02, shr(0x10, amount)) + mstore8(0x03, shr(0x18, amount)) + mstore8(0x04, shr(0x20, amount)) + mstore8(0x05, shr(0x28, amount)) + mstore8(0x06, shr(0x30, amount)) + mstore8(0x07, shr(0x38, amount)) + + // [0x20] = sha256([0x00:0x40]) + result := staticcall(84, 0x02, 0x00, 0x40, 0x20, 0x20) + if iszero(result) { + revert(0, 0) + } + + // [0x00] = temp[0x00] + mstore(0x00, mload(temp)) + + // [0x00] = sha256([0x00:0x40]) + result := staticcall(84, 0x02, 0x00, 0x40, 0x00, 0x20) + if iszero(result) { + revert(0, 0) + } + + // Return [0x00:0x20] + ret := mload(0x00) + } + } + /// @notice Removes a validator from the deposit queue /// @param _validatorId the validator ID function dequeue(uint32 _validatorId) external onlyMegapoolOwner { @@ -116,7 +200,8 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel // Execute prestake operation PrestakeData memory validatorPrestakeData = prestakeData[_validatorId]; DepositInterface casperDeposit = DepositInterface(getContractAddress("casperDeposit")); - casperDeposit.deposit{value: prestakeValue}(validator.pubKey, abi.encodePacked(getWithdrawalCredentials()), validatorPrestakeData._signature, validatorPrestakeData._depositDataRoot); + bytes32 depositDataRoot = computeDepositDataRoot(validator.pubKey, validatorPrestakeData._signature, uint64(prestakeValue / 1 gwei)); + casperDeposit.deposit{value: prestakeValue}(validator.pubKey, abi.encodePacked(getWithdrawalCredentials()), validatorPrestakeData._signature, depositDataRoot); // Clean up prestake data delete prestakeData[_validatorId]; // Emit event @@ -147,7 +232,7 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel userCapital += uint256(lastRequestedValue - validator.lastRequestedBond) * milliToWei; nodeCapital += uint256(validator.lastRequestedBond) * milliToWei; // Update validator status - validator.active = true; + validator.staked = true; validator.inPrestake = false; validator.lastAssignmentTime = 0; validator.lastRequestedBond = 0; @@ -181,7 +266,7 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel refundValue += uint256(validator.lastRequestedBond) * milliToWei - prestakeValue; // Recycle the ETH RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool")); - rocketDepositPool.recycleDissolvedDeposit{value : validator.lastRequestedValue - validator.lastRequestedBond}(); + rocketDepositPool.recycleDissolvedDeposit{value: validator.lastRequestedValue - validator.lastRequestedBond}(); // TODO: Handle recovery of prestakeValue as part of capital distribution process } @@ -297,7 +382,7 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel } /// @notice Returns the number of validators created for this megapool - function getValidatorCount() override external view returns (uint256) { + function getValidatorCount() override external view returns (uint32) { return numValidators; } diff --git a/contracts/contract/megapool/RocketMegapoolManager.sol b/contracts/contract/megapool/RocketMegapoolManager.sol new file mode 100644 index 00000000..43c92d53 --- /dev/null +++ b/contracts/contract/megapool/RocketMegapoolManager.sol @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity 0.8.18; + +import "./RocketMegapoolStorageLayout.sol"; +import "./RocketMegapoolStorageLayout.sol"; +import {RocketBase} from "../RocketBase.sol"; +import {RocketMegapoolInterface} from "../../interface/megapool/RocketMegapoolInterface.sol"; +import {RocketStorageInterface} from "../../interface/RocketStorageInterface.sol"; +import {RocketMegapoolManagerInterface} from "../../interface/megapool/RocketMegapoolManagerInterface.sol"; + +/// @notice Manages the global list of validators across all megapools +contract RocketMegapoolManager is RocketBase, RocketMegapoolManagerInterface { + + constructor(RocketStorageInterface _rocketStorageAddress) RocketBase(_rocketStorageAddress) { + version = 1; + } + + /// @notice Returns the total number validators across all megapools + function getValidatorCount() override external view returns (uint256) { + return getUint(keccak256("megapool.validator.count")); + } + + /// @notice Adds a validator record to the global megapool validator set + /// @param _megapoolAddress Address of the megapool which manages this validator + /// @param _validatorId Internal validator ID of the new validator + function addValidator(address _megapoolAddress, uint32 _validatorId) override external onlyLatestContract("rocketMegapoolManager", address(this)) onlyLatestContract("rocketNodeDeposit", msg.sender) { + uint256 index = getUint(keccak256("megapool.validator.count")); + setUint(keccak256("megapool.validator.count"), index + 1); + uint256 encoded = (uint160(_megapoolAddress) << 96) | uint32(_validatorId); + setUint(keccak256(abi.encodePacked("megapool.validator.set", index)), encoded); + } + + /// @notice Returns validator info for the given global megapool validator index + /// @param _index The index of the validator to query + function getValidatorInfo(uint256 _index) override external view returns (RocketMegapoolStorageLayout.ValidatorInfo memory) { + uint256 encoded = getUint(keccak256(abi.encodePacked("megapool.validator.set", _index))); + address megapoolAddress = address(uint160(encoded) >> 96); + uint32 validatorId = uint32(encoded); + + RocketMegapoolInterface rocketMegapool = RocketMegapoolInterface(megapoolAddress); + return rocketMegapool.getValidatorInfo(validatorId); + } +} diff --git a/contracts/contract/megapool/RocketMegapoolStorageLayout.sol b/contracts/contract/megapool/RocketMegapoolStorageLayout.sol index 03a170fe..4ecbbc6a 100644 --- a/contracts/contract/megapool/RocketMegapoolStorageLayout.sol +++ b/contracts/contract/megapool/RocketMegapoolStorageLayout.sol @@ -28,7 +28,7 @@ abstract contract RocketMegapoolStorageLayout { uint32 lastRequestedValue; // Value in milliether last requested uint32 lastRequestedBond; // Value in milliether of the bond supplied for last request for funds - bool active; // Whether the validator is actively validating on the beacon chain + bool staked; // Whether the validator has staked the minimum required to begin validating (32 ETH) bool exited; // Whether the validator has exited the beacon chain bool inQueue; // Whether the validator is currently awaiting funds from the deposit pool bool inPrestake; // Whether the validator is currently awaiting the stake operation @@ -39,7 +39,6 @@ abstract contract RocketMegapoolStorageLayout { // Extra data temporarily stored for prestake operation struct PrestakeData { bytes _signature; - bytes32 _depositDataRoot; } // @@ -61,7 +60,7 @@ abstract contract RocketMegapoolStorageLayout { // address internal nodeAddress; // Megapool owner - uint256 internal numValidators; // Number of individual validators handled by this megapool + uint32 internal numValidators; // Number of individual validators handled by this megapool uint256 internal assignedValue; // ETH assigned from DP pending prestake/stake uint256 internal refundValue; // ETH refunded to the owner after a dissolution diff --git a/contracts/contract/node/RocketNodeDeposit.sol b/contracts/contract/node/RocketNodeDeposit.sol index 838bf653..a4bce877 100644 --- a/contracts/contract/node/RocketNodeDeposit.sol +++ b/contracts/contract/node/RocketNodeDeposit.sol @@ -18,6 +18,7 @@ import "../../interface/node/RocketNodeDepositInterface.sol"; import "../../interface/node/RocketNodeManagerInterface.sol"; import "../../interface/node/RocketNodeStakingInterface.sol"; import "../RocketBase.sol"; +import {RocketMegapoolManagerInterface} from "../../interface/megapool/RocketMegapoolManagerInterface.sol"; /// @notice Entry point for node operators to perform deposits for the creation of new validators on the network contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { @@ -188,11 +189,13 @@ contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { // Get or deploy a megapool for the caller RocketMegapoolFactoryInterface rocketMegapoolFactory = RocketMegapoolFactoryInterface(getContractAddress("rocketMegapoolFactory")); RocketMegapoolInterface megapool = RocketMegapoolInterface(rocketMegapoolFactory.getOrDeployContract(msg.sender)); + RocketMegapoolManagerInterface rocketMegapoolManager = RocketMegapoolManagerInterface(getContractAddress("rocketMegapoolManager")); // Check bond requirements checkBondRequirement(megapool, _bondAmount); checkDebtRequirement(megapool); // Request a new validator from the megapool megapool.newValidator(_bondAmount, _useExpressTicket, _validatorPubkey, _validatorSignature, _depositDataRoot); + rocketMegapoolManager.addValidator(address(megapool), megapool.getValidatorCount()); // Send node operator's bond to the deposit pool RocketDepositPoolInterface rocketDepositPool = RocketDepositPoolInterface(getContractAddress("rocketDepositPool")); rocketDepositPool.nodeDeposit{value: msg.value}(_bondAmount); diff --git a/contracts/contract/upgrade/RocketUpgradeOneDotFour.sol b/contracts/contract/upgrade/RocketUpgradeOneDotFour.sol index 8a3bd393..65e0adba 100644 --- a/contracts/contract/upgrade/RocketUpgradeOneDotFour.sol +++ b/contracts/contract/upgrade/RocketUpgradeOneDotFour.sol @@ -22,6 +22,7 @@ contract RocketUpgradeOneDotFour is RocketBase { address public rocketMegapoolDelegate; address public rocketMegapoolFactory; address public rocketMegapoolProxy; + address public rocketMegapoolManager; address public rocketNodeManager; address public rocketNodeDeposit; address public rocketNodeStaking; @@ -41,6 +42,7 @@ contract RocketUpgradeOneDotFour is RocketBase { string public rocketMegapoolDelegateAbi; string public rocketMegapoolFactoryAbi; string public rocketMegapoolProxyAbi; + string public rocketMegapoolManagerAbi; string public rocketNodeManagerAbi; string public rocketNodeDepositAbi; string public rocketNodeStakingAbi; @@ -81,39 +83,41 @@ contract RocketUpgradeOneDotFour is RocketBase { rocketMegapoolDelegate = _addresses[0]; rocketMegapoolFactory = _addresses[1]; rocketMegapoolProxy = _addresses[2]; - rocketNodeManager = _addresses[3]; - rocketNodeDeposit = _addresses[4]; - rocketNodeStaking = _addresses[5]; - rocketDepositPool = _addresses[6]; - linkedListStorage = _addresses[7]; - rocketDAOProtocolSettingsNode = _addresses[8]; - rocketDAOProtocolSettingsDeposit = _addresses[9]; - rocketDAOProtocolSettingsNetwork = _addresses[10]; - rocketDAOProtocolSettingsSecurity = _addresses[11]; - rocketDAOSecurityProposals = _addresses[12]; - rocketNetworkRevenues = _addresses[13]; - rocketNetworkSnapshots = _addresses[14]; - blockRoots = _addresses[15]; - beaconStateVerifier = _addresses[16]; + rocketMegapoolManager = _addresses[3]; + rocketNodeManager = _addresses[4]; + rocketNodeDeposit = _addresses[5]; + rocketNodeStaking = _addresses[6]; + rocketDepositPool = _addresses[7]; + linkedListStorage = _addresses[8]; + rocketDAOProtocolSettingsNode = _addresses[9]; + rocketDAOProtocolSettingsDeposit = _addresses[10]; + rocketDAOProtocolSettingsNetwork = _addresses[11]; + rocketDAOProtocolSettingsSecurity = _addresses[12]; + rocketDAOSecurityProposals = _addresses[13]; + rocketNetworkRevenues = _addresses[14]; + rocketNetworkSnapshots = _addresses[15]; + blockRoots = _addresses[16]; + beaconStateVerifier = _addresses[17]; // Set ABIs rocketMegapoolDelegateAbi = _abis[0]; rocketMegapoolFactoryAbi = _abis[1]; rocketMegapoolProxyAbi = _abis[2]; - rocketNodeManagerAbi = _abis[3]; - rocketNodeDepositAbi = _abis[4]; - rocketNodeStakingAbi = _abis[5]; - rocketDepositPoolAbi = _abis[6]; - linkedListStorageAbi = _abis[7]; - rocketDAOProtocolSettingsNodeAbi = _abis[8]; - rocketDAOProtocolSettingsDepositAbi = _abis[9]; - rocketDAOProtocolSettingsNetworkAbi = _abis[10]; - rocketDAOProtocolSettingsSecurityAbi = _abis[11]; - rocketDAOSecurityProposalsAbi = _abis[12]; - rocketNetworkRevenuesAbi = _abis[13]; - rocketNetworkSnapshotsAbi = _abis[14]; - blockRootsAbi = _abis[15]; - beaconStateVerifierAbi = _abis[16]; + rocketMegapoolManagerAbi = _abis[3]; + rocketNodeManagerAbi = _abis[4]; + rocketNodeDepositAbi = _abis[5]; + rocketNodeStakingAbi = _abis[6]; + rocketDepositPoolAbi = _abis[7]; + linkedListStorageAbi = _abis[8]; + rocketDAOProtocolSettingsNodeAbi = _abis[9]; + rocketDAOProtocolSettingsDepositAbi = _abis[10]; + rocketDAOProtocolSettingsNetworkAbi = _abis[11]; + rocketDAOProtocolSettingsSecurityAbi = _abis[12]; + rocketDAOSecurityProposalsAbi = _abis[13]; + rocketNetworkRevenuesAbi = _abis[14]; + rocketNetworkSnapshotsAbi = _abis[15]; + blockRootsAbi = _abis[16]; + beaconStateVerifierAbi = _abis[17]; } /// @notice Prevents further changes from being applied @@ -131,6 +135,7 @@ contract RocketUpgradeOneDotFour is RocketBase { _addContract("rocketMegapoolDelegate", rocketMegapoolDelegate, rocketMegapoolDelegateAbi); _addContract("rocketMegapoolFactory", rocketMegapoolFactory, rocketMegapoolFactoryAbi); _addContract("rocketMegapoolProxy", rocketMegapoolProxy, rocketMegapoolProxyAbi); + _addContract("rocketMegapoolManager", rocketMegapoolManager, rocketMegapoolManagerAbi); _addContract("linkedListStorage", linkedListStorage, linkedListStorageAbi); _addContract("rocketNetworkRevenues", rocketNetworkRevenues, rocketNetworkRevenuesAbi); _addContract("blockRoots", blockRoots, blockRootsAbi); diff --git a/contracts/interface/megapool/RocketMegapoolDelegateInterface.sol b/contracts/interface/megapool/RocketMegapoolDelegateInterface.sol index c6726134..13dcc969 100644 --- a/contracts/interface/megapool/RocketMegapoolDelegateInterface.sol +++ b/contracts/interface/megapool/RocketMegapoolDelegateInterface.sol @@ -17,7 +17,7 @@ interface RocketMegapoolDelegateInterface is RocketMegapoolDelegateBaseInterface function dissolveValidator(uint32 _validatorId) external; function getNodeAddress() external returns (address); - function getValidatorCount() external view returns (uint256); + function getValidatorCount() external view returns (uint32); function getValidatorInfo(uint32 _validatorId) external view returns (RocketMegapoolStorageLayout.ValidatorInfo memory); function getAssignedValue() external view returns (uint256); function getDebt() external view returns (uint256); diff --git a/contracts/interface/megapool/RocketMegapoolManagerInterface.sol b/contracts/interface/megapool/RocketMegapoolManagerInterface.sol new file mode 100644 index 00000000..ebf6088e --- /dev/null +++ b/contracts/interface/megapool/RocketMegapoolManagerInterface.sol @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: GPL-3.0-only +pragma solidity >0.5.0 <0.9.0; + +import "../../contract/megapool/RocketMegapoolStorageLayout.sol"; + +interface RocketMegapoolManagerInterface { + function getValidatorCount() external view returns (uint256); + function addValidator(address _megapoolAddress, uint32 _validatorId) external; + function getValidatorInfo(uint256 _index) external view returns (RocketMegapoolStorageLayout.ValidatorInfo memory); +} \ No newline at end of file diff --git a/test-upgrade/_helpers/upgrade.js b/test-upgrade/_helpers/upgrade.js index 08d7b83e..215930c3 100644 --- a/test-upgrade/_helpers/upgrade.js +++ b/test-upgrade/_helpers/upgrade.js @@ -9,6 +9,7 @@ const networkContracts = { rocketMegapoolDelegate: artifacts.require('RocketMegapoolDelegate'), rocketMegapoolFactory: artifacts.require('RocketMegapoolFactory'), rocketMegapoolProxy: artifacts.require('RocketMegapoolProxy'), + rocketMegapoolManager: artifacts.require('RocketMegapoolManager'), rocketNodeManager: artifacts.require('RocketNodeManager'), rocketNodeDeposit: artifacts.require('RocketNodeDeposit'), rocketNodeStaking: artifacts.require('RocketNodeStaking'), @@ -76,6 +77,7 @@ export async function deployUpgrade(rocketStorageAddress) { addresses.rocketMegapoolDelegate, addresses.rocketMegapoolFactory, addresses.rocketMegapoolProxy, + addresses.rocketMegapoolManager, addresses.rocketNodeManager, addresses.rocketNodeDeposit, addresses.rocketNodeStaking, @@ -95,6 +97,7 @@ export async function deployUpgrade(rocketStorageAddress) { compressABI(networkContracts.rocketMegapoolDelegate.abi), compressABI(networkContracts.rocketMegapoolFactory.abi), compressABI(networkContracts.rocketMegapoolProxy.abi), + compressABI(networkContracts.rocketMegapoolManager.abi), compressABI(networkContracts.rocketNodeManager.abi), compressABI(networkContracts.rocketNodeDeposit.abi), compressABI(networkContracts.rocketNodeStaking.abi), diff --git a/test/_helpers/deployment.js b/test/_helpers/deployment.js index 992ef3f6..8b8e71dd 100644 --- a/test/_helpers/deployment.js +++ b/test/_helpers/deployment.js @@ -105,6 +105,7 @@ const networkContracts = { // v1.4 rocketMegapoolFactory: artifacts.require('RocketMegapoolFactory'), rocketMegapoolProxy: artifacts.require('RocketMegapoolProxy'), + rocketMegapoolManager: artifacts.require('RocketMegapoolManager'), rocketMegapoolDelegate: artifacts.require('RocketMegapoolDelegate'), rocketNetworkRevenues: artifacts.require('RocketNetworkRevenues'), // Utils diff --git a/test/_helpers/megapool.js b/test/_helpers/megapool.js index 2fe4eacd..81b0364e 100644 --- a/test/_helpers/megapool.js +++ b/test/_helpers/megapool.js @@ -3,7 +3,7 @@ import * as assert from 'assert'; import { artifacts, RocketDAOProtocolSettingsDeposit, RocketDepositPool, RocketMegapoolDelegate, - RocketMegapoolFactory, + RocketMegapoolFactory, RocketMegapoolManager, RocketNodeDeposit, RocketNodeManager, RocketNodeStaking, } from '../_utils/artifacts'; @@ -23,7 +23,7 @@ export async function getValidatorInfo(megapool, index) { lastRequestedValue: validatorInfo[2], lastRequestedBond: validatorInfo[3], - active: validatorInfo[4], + staked: validatorInfo[4], exited: validatorInfo[5], inQueue: validatorInfo[6], inPrestake: validatorInfo[7], @@ -51,12 +51,14 @@ export async function nodeDeposit(useExpressTicket, useCredit, txOptions) { rocketMegapoolFactory, rocketDepositPool, rocketDAOProtocolSettingsDeposit, + rocketMegapoolManager, ] = await Promise.all([ RocketNodeDeposit.deployed(), RocketNodeManager.deployed(), RocketMegapoolFactory.deployed(), RocketDepositPool.deployed(), RocketDAOProtocolSettingsDeposit.deployed(), + RocketMegapoolManager.deployed(), ]); // Construct deposit data for prestake @@ -73,9 +75,10 @@ export async function nodeDeposit(useExpressTicket, useCredit, txOptions) { let data = await Promise.all([ rocketMegapoolFactory.getMegapoolDeployed(txOptions.from.address), rocketNodeManager.getExpressTicketCount(txOptions.from.address), + rocketMegapoolManager.getValidatorCount(), ]).then( - ([ deployed, numExpressTickets]) => - ({ deployed, numExpressTickets, numValidators: 0n, assignedValue: 0n, nodeCapital: 0n, userCapital: 0n }), + ([ deployed, numExpressTickets, numGlobalValidators]) => + ({ deployed, numExpressTickets, numGlobalValidators, numValidators: 0n, assignedValue: 0n, nodeCapital: 0n, userCapital: 0n }), ); if (data.deployed) { @@ -107,12 +110,14 @@ export async function nodeDeposit(useExpressTicket, useCredit, txOptions) { // Confirm state changes to node const numValidatorsDelta = data2.numValidators - data1.numValidators; + const numGlobalValidatorsDelta = data2.numGlobalValidators - data1.numGlobalValidators; const numExpressTicketsDelta = data2.numExpressTickets - data1.numExpressTickets; const assignedValueDelta = data2.assignedValue - data1.assignedValue; const nodeCapitalDelta = data2.nodeCapital - data1.nodeCapital; const userCapitalDelta = data2.userCapital - data1.userCapital; assertBN.equal(numValidatorsDelta, 1n, "Number of validators did not increase by 1"); + assertBN.equal(numGlobalValidatorsDelta, 1n, "Number of global validators did not increase by 1"); if (useExpressTicket) { assertBN.equal(numExpressTicketsDelta, -1n, "Did not consume express ticket"); @@ -141,7 +146,7 @@ export async function nodeDeposit(useExpressTicket, useCredit, txOptions) { assertBN.equal(validatorInfo.lastRequestedValue, '32'.ether / milliToWei, "Incorrect validator lastRequestedValue"); assertBN.equal(validatorInfo.lastRequestedBond, txOptions.value / milliToWei, "Incorrect validator lastRequestedBond"); - assert.equal(validatorInfo.active, false, "Incorrect validator status"); + assert.equal(validatorInfo.staked, false, "Incorrect validator status"); assert.equal(validatorInfo.dissolved, false, "Incorrect validator status"); assert.equal(validatorInfo.exited, false, "Incorrect validator status"); assert.equal(validatorInfo.expressUsed, useExpressTicket, "Incorrect validator express ticket usage"); diff --git a/test/_utils/artifacts.js b/test/_utils/artifacts.js index a9bf5060..846bbf98 100644 --- a/test/_utils/artifacts.js +++ b/test/_utils/artifacts.js @@ -130,6 +130,7 @@ export const SnapshotTest = artifacts.require('SnapshotTest'); export const RocketMegapoolFactory = artifacts.require('RocketMegapoolFactory'); export const RocketMegapoolDelegate = artifacts.require('RocketMegapoolDelegate'); export const RocketMegapoolProxy = artifacts.require('RocketMegapoolProxy'); +export const RocketMegapoolManager = artifacts.require('RocketMegapoolManager'); export const RocketMinipoolFactory = artifacts.require('RocketMinipoolFactory'); export const RocketMinipoolBase = artifacts.require('RocketMinipoolBase'); export const RocketMinipoolQueue = artifacts.require('RocketMinipoolQueue'); diff --git a/test/megapool/scenario-exit-queue.js b/test/megapool/scenario-exit-queue.js index ed7c3212..26ec20d0 100644 --- a/test/megapool/scenario-exit-queue.js +++ b/test/megapool/scenario-exit-queue.js @@ -16,7 +16,7 @@ export async function exitQueue(node, validatorIndex) { // Check the validator status const validatorInfoAfter = await megapool.getValidatorInfo(validatorIndex); - assert.equal(validatorInfoAfter.active, false); + assert.equal(validatorInfoAfter.staked, false); assert.equal(validatorInfoAfter.inQueue, false); // Check an ETH credit was applied