From 36f75b63f35d7bb017bb89aab8d9c0f235e779d4 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Sat, 23 Jul 2022 07:18:46 -0500 Subject: [PATCH 1/8] Allows deposit size to scale with minipool queue space in addition to deposit pool space - Also allows assignment to scale with value of deposit --- .../contract/deposit/RocketDepositPool.sol | 62 +++++++++++++++---- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/contracts/contract/deposit/RocketDepositPool.sol b/contracts/contract/deposit/RocketDepositPool.sol index 22d95b223..5bea89a7f 100644 --- a/contracts/contract/deposit/RocketDepositPool.sol +++ b/contracts/contract/deposit/RocketDepositPool.sol @@ -77,7 +77,19 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled"); require(msg.value >= rocketDAOProtocolSettingsDeposit.getMinimumDeposit(), "The deposited amount is less than the minimum deposit size"); RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault")); - require(rocketVault.balanceOf("rocketDepositPool").add(msg.value) <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize(), "The deposit pool size after depositing exceeds the maximum size"); + uint256 capacityNeeded = rocketVault.balanceOf("rocketDepositPool").add(msg.value); + if (capacityNeeded > rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize()) { + // Doing a conditional require() instead of a single one optimizes for the common + // case where capacityNeeded fits in the deposit pool without looking at the queue + if (rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) { + RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue")); + require(capacity <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize() + rocketMinipoolQueue.getEffectiveCapacity(), + "The deposit pool size after depositing (and matching with minipools) exceeds the maximum size"); + } else { + require(capacity <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize(), + "The deposit pool size after depositing exceeds the maximum size"); + } + } // Calculate deposit fee uint256 depositFee = msg.value.mul(rocketDAOProtocolSettingsDeposit.getDepositFee()).div(calcBase); uint256 depositNet = msg.value.sub(depositFee); @@ -140,6 +152,7 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul } // Assigns deposits to available minipools, returns false if assignment is currently disabled + // Can assign deposits up to the value of the deposit plus getMaximumDepositAssignments() function _assignDeposits(RocketVaultInterface _rocketVault, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) private returns (bool) { // Check if assigning deposits is enabled if (!_rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) { @@ -152,28 +165,51 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul uint256 balance = _rocketVault.balanceOf("rocketDepositPool"); uint256 totalEther = 0; // Calculate minipool assignments - uint256 maxAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments(); - MinipoolAssignment[] memory assignments = new MinipoolAssignment[](maxAssignments); - MinipoolDeposit depositType = MinipoolDeposit.None; + uint256 count = 0; uint256 minipoolCapacity = 0; - for (uint256 i = 0; i < maxAssignments; ++i) { - // Optimised for multiple of the same deposit type - if (count == 0) { - (depositType, count) = rocketMinipoolQueue.getNextDeposit(); - if (depositType == MinipoolDeposit.None) { break; } - minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(depositType); + uint256 depositValueForAssignments = msg.value; + uint256 socializedAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments(); + MinipoolAssignment[] memory assignments = new MinipoolAssignment[](maxAssignments); + + // Prepare half deposit assignments + count = rocketMinipoolQueue.getLength(MinipoolDeposit.Half); + minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(MinipoolDeposit.Half); + for (uint256 i=0; i < count; ++i) { // (see note in full deposit loop) + if (depositValueForAssignments < minipoolCapacity) { + if (socializedAssignments == 0) { break; } + else {socializedAssignments--;} + } else { + depositValueForAssignments.sub(minipoolCapacity); + } + if (balance.sub(totalEther) < minipoolCapacity) { break; } + // Dequeue the minipool + address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(MinipoolDeposit.Half); + // Update running total + totalEther = totalEther.add(minipoolCapacity); + // Add assignment + assignments[i].etherAssigned = minipoolCapacity; + assignments[i].minipoolAddress = minipoolAddress; + } + + // Prepare full deposit assignments + count = rocketMinipoolQueue.getLength(MinipoolDeposit.Full); + minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(MinipoolDeposit.Full); + for (i; i < i + count; ++i) { // NOTE - this is a weird line - we continue the indexing from the half deposit loop + if (depositValueForAssignments < minipoolCapacity) { + if (socializedAssignments == 0) { break; } + else {socializedAssignments--;} } - count--; - if (minipoolCapacity == 0 || balance.sub(totalEther) < minipoolCapacity) { break; } + if (balance.sub(totalEther) < minipoolCapacity) { break; } // Dequeue the minipool - address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(depositType); + address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(MinipoolDeposit.Full); // Update running total totalEther = totalEther.add(minipoolCapacity); // Add assignment assignments[i].etherAssigned = minipoolCapacity; assignments[i].minipoolAddress = minipoolAddress; } + if (totalEther > 0) { // Withdraw ETH from vault _rocketVault.withdrawEther(totalEther); From 06fd9385e81d7f9c2822042ff02456549e9689a6 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Tue, 26 Jul 2022 19:20:59 -0500 Subject: [PATCH 2/8] Remove unused functions --- .../contract/minipool/RocketMinipoolQueue.sol | 36 ++----------------- .../minipool/RocketMinipoolQueueInterface.sol | 3 -- test/deposit/scenario-assign-deposits.js | 6 ++-- 3 files changed, 4 insertions(+), 41 deletions(-) diff --git a/contracts/contract/minipool/RocketMinipoolQueue.sol b/contracts/contract/minipool/RocketMinipoolQueue.sol index 9afcd055b..a558bd86c 100644 --- a/contracts/contract/minipool/RocketMinipoolQueue.sol +++ b/contracts/contract/minipool/RocketMinipoolQueue.sol @@ -57,18 +57,6 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { return addressQueueStorage.getLength(_key); } - // Get the total combined capacity of the queues - function getTotalCapacity() override external view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - return ( - getLength(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount()) - ).add( - getLength(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount()) - ).add( - getLength(queueKeyEmpty).mul(rocketDAOProtocolSettingsMinipool.getEmptyDepositUserAmount()) - ); - } - // Get the total effective capacity of the queues (used in node demand calculation) function getEffectiveCapacity() override external view returns (uint256) { RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); @@ -79,28 +67,6 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { ); } - // Get the capacity of the next available minipool - // Returns 0 if no minipools are available - function getNextCapacity() override external view returns (uint256) { - RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - if (getLength(queueKeyHalf) > 0) { return rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount(); } - if (getLength(queueKeyFull) > 0) { return rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount(); } - if (getLength(queueKeyEmpty) > 0) { return rocketDAOProtocolSettingsMinipool.getEmptyDepositUserAmount(); } - return 0; - } - - // Get the deposit type of the next available minipool and the number of deposits in that queue - // Returns None if no minipools are available - function getNextDeposit() override external view returns (MinipoolDeposit, uint256) { - uint256 length = getLength(queueKeyHalf); - if (length > 0) { return (MinipoolDeposit.Half, length); } - length = getLength(queueKeyFull); - if (length > 0) { return (MinipoolDeposit.Full, length); } - length = getLength(queueKeyEmpty); - if (length > 0) { return (MinipoolDeposit.Empty, length); } - return (MinipoolDeposit.None, 0); - } - // Add a minipool to the end of the appropriate queue // Only accepts calls from the RocketMinipoolManager contract function enqueueMinipool(MinipoolDeposit _depositType, address _minipool) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketMinipoolManager", msg.sender) { @@ -143,6 +109,8 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { // Remove a minipool from a queue // Only accepts calls from registered minipools + // Note: this removal is made computationally efficient by swapping with the last item in the + // queue. This is acceptable because removing minipools should be rare. function removeMinipool(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyRegisteredMinipool(msg.sender) { // Remove minipool from queue if (_depositType == MinipoolDeposit.Half) { return removeMinipool(queueKeyHalf, msg.sender); } diff --git a/contracts/interface/minipool/RocketMinipoolQueueInterface.sol b/contracts/interface/minipool/RocketMinipoolQueueInterface.sol index 326690d86..3781427f6 100644 --- a/contracts/interface/minipool/RocketMinipoolQueueInterface.sol +++ b/contracts/interface/minipool/RocketMinipoolQueueInterface.sol @@ -7,10 +7,7 @@ import "../../types/MinipoolDeposit.sol"; interface RocketMinipoolQueueInterface { function getTotalLength() external view returns (uint256); function getLength(MinipoolDeposit _depositType) external view returns (uint256); - function getTotalCapacity() external view returns (uint256); function getEffectiveCapacity() external view returns (uint256); - function getNextCapacity() external view returns (uint256); - function getNextDeposit() external view returns (MinipoolDeposit, uint256); function enqueueMinipool(MinipoolDeposit _depositType, address _minipool) external; function dequeueMinipool() external returns (address minipoolAddress); function dequeueMinipoolByDeposit(MinipoolDeposit _depositType) external returns (address minipoolAddress); diff --git a/test/deposit/scenario-assign-deposits.js b/test/deposit/scenario-assign-deposits.js index b518c88c3..17bc1e100 100644 --- a/test/deposit/scenario-assign-deposits.js +++ b/test/deposit/scenario-assign-deposits.js @@ -66,10 +66,9 @@ export async function assignDeposits(txOptions) { function getMinipoolQueueDetails() { return Promise.all([ rocketMinipoolQueue.getTotalLength.call(), - rocketMinipoolQueue.getTotalCapacity.call(), ]).then( - ([totalLength, totalCapacity]) => - ({totalLength, totalCapacity}) + ([totalLength]) => + ({totalLength}) ); } @@ -94,7 +93,6 @@ export async function assignDeposits(txOptions) { // Check minipool queues assert(queue2.totalLength.eq(queue1.totalLength.sub(web3.utils.toBN(expectedDepositAssignments))), 'Incorrect updated minipool queue length'); - assert(queue2.totalCapacity.eq(queue1.totalCapacity.sub(expectedEthAssigned)), 'Incorrect updated minipool queue capacity'); } From 5f8d4e539cc16534d43a1daf7e97f97fea8d0b52 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Sat, 13 Aug 2022 13:13:22 -0500 Subject: [PATCH 3/8] Address comments from Kane - 2 comments in PR - Need for a hard max on assignments to ensure there's enough gas in a block - Unrelated; did away with the weird counter-spanning-for-loops trick to be more explicit --- .../RocketDAOProtocolSettingsDeposit.sol | 8 +++- .../contract/deposit/RocketDepositPool.sol | 43 ++++++++++--------- 2 files changed, 30 insertions(+), 21 deletions(-) diff --git a/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsDeposit.sol b/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsDeposit.sol index 973631bab..19e41e8eb 100644 --- a/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsDeposit.sol +++ b/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsDeposit.sol @@ -20,7 +20,8 @@ contract RocketDAOProtocolSettingsDeposit is RocketDAOProtocolSettings, RocketDA setSettingBool("deposit.assign.enabled", true); setSettingUint("deposit.minimum", 0.01 ether); setSettingUint("deposit.pool.maximum", 160 ether); - setSettingUint("deposit.assign.maximum", 2); + setSettingUint("deposit.assign.maximum", 90); + setSettingUint("deposit.assign.socializedmaximum", 2); setSettingUint("deposit.fee", 0.0005 ether); // Set to approx. 1 day of rewards at 18.25% APR // Settings initialised setBool(keccak256(abi.encodePacked(settingNameSpace, "deployed")), true); @@ -52,6 +53,11 @@ contract RocketDAOProtocolSettingsDeposit is RocketDAOProtocolSettings, RocketDA return getSettingUint("deposit.assign.maximum"); } + // The maximum number of socialized (ie, not related to deposit size) assignments to perform + function getMaximumDepositSocializedAssignments() override external view returns (uint256) { + return getSettingUint("deposit.assign.socializedmaximum"); + } + // Get the fee paid on deposits function getDepositFee() override external view returns (uint256) { return getSettingUint("deposit.fee"); diff --git a/contracts/contract/deposit/RocketDepositPool.sol b/contracts/contract/deposit/RocketDepositPool.sol index 5bea89a7f..cc592c247 100644 --- a/contracts/contract/deposit/RocketDepositPool.sol +++ b/contracts/contract/deposit/RocketDepositPool.sol @@ -83,11 +83,10 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul // case where capacityNeeded fits in the deposit pool without looking at the queue if (rocketDAOProtocolSettingsDeposit.getAssignDepositsEnabled()) { RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue")); - require(capacity <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize() + rocketMinipoolQueue.getEffectiveCapacity(), + require(capacityNeeded <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize() + rocketMinipoolQueue.getEffectiveCapacity(), "The deposit pool size after depositing (and matching with minipools) exceeds the maximum size"); } else { - require(capacity <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize(), - "The deposit pool size after depositing exceeds the maximum size"); + revert("The deposit pool size after depositing exceeds the maximum size"); } } // Calculate deposit fee @@ -164,21 +163,23 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul // Setup initial variable values uint256 balance = _rocketVault.balanceOf("rocketDepositPool"); uint256 totalEther = 0; - // Calculate minipool assignments - uint256 count = 0; + // Calculate minipool assignments + uint256 i; + uint256 assignmentIndex = 0; uint256 minipoolCapacity = 0; uint256 depositValueForAssignments = msg.value; - uint256 socializedAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments(); + uint256 socializedAssignmentsLeft = _rocketDAOProtocolSettingsDeposit.getMaximumDepositSocializedAssignments(); + uint256 maxAssignments = _rocketDAOProtocolSettingsDeposit.getMaximumDepositAssignments(); MinipoolAssignment[] memory assignments = new MinipoolAssignment[](maxAssignments); // Prepare half deposit assignments - count = rocketMinipoolQueue.getLength(MinipoolDeposit.Half); minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(MinipoolDeposit.Half); - for (uint256 i=0; i < count; ++i) { // (see note in full deposit loop) + for (i=0; i < rocketMinipoolQueue.getLength(MinipoolDeposit.Half); ++i) { + if (assignmentIndex == maxAssignments) { break; } if (depositValueForAssignments < minipoolCapacity) { - if (socializedAssignments == 0) { break; } - else {socializedAssignments--;} + if (socializedAssignmentsLeft == 0) { break; } + else {socializedAssignmentsLeft--;} } else { depositValueForAssignments.sub(minipoolCapacity); } @@ -187,27 +188,29 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(MinipoolDeposit.Half); // Update running total totalEther = totalEther.add(minipoolCapacity); - // Add assignment - assignments[i].etherAssigned = minipoolCapacity; - assignments[i].minipoolAddress = minipoolAddress; + // Add assignment, increment index + assignments[assignmentIndex].etherAssigned = minipoolCapacity; + assignments[assignmentIndex].minipoolAddress = minipoolAddress; + assignmentIndex++; } // Prepare full deposit assignments - count = rocketMinipoolQueue.getLength(MinipoolDeposit.Full); minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(MinipoolDeposit.Full); - for (i; i < i + count; ++i) { // NOTE - this is a weird line - we continue the indexing from the half deposit loop + for (i=0; i < rocketMinipoolQueue.getLength(MinipoolDeposit.Full); ++i) { + if (assignmentIndex == maxAssignments) { break; } if (depositValueForAssignments < minipoolCapacity) { - if (socializedAssignments == 0) { break; } - else {socializedAssignments--;} + if (socializedAssignmentsLeft == 0) { break; } + else {socializedAssignmentsLeft--;} } if (balance.sub(totalEther) < minipoolCapacity) { break; } // Dequeue the minipool address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(MinipoolDeposit.Full); // Update running total totalEther = totalEther.add(minipoolCapacity); - // Add assignment - assignments[i].etherAssigned = minipoolCapacity; - assignments[i].minipoolAddress = minipoolAddress; + // Add assignment, increment index + assignments[assignmentIndex].etherAssigned = minipoolCapacity; + assignments[assignmentIndex].minipoolAddress = minipoolAddress; + assignmentIndex++; } if (totalEther > 0) { From a81179bac184d7e102f92d8a2f72e063369d7722 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Sat, 13 Aug 2022 13:20:40 -0500 Subject: [PATCH 4/8] Consistency in dissolve() Comments implied it could be used either by anyone when an NO failed to move forward in prelaunch OR by the NO at that same time or while in queue. However, the functionality only allowed the former. Updated code/comments to explicitly only do the former. --- contracts/contract/minipool/RocketMinipoolDelegate.sol | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/contracts/contract/minipool/RocketMinipoolDelegate.sol b/contracts/contract/minipool/RocketMinipoolDelegate.sol index 82341f5ce..6c2cff05b 100644 --- a/contracts/contract/minipool/RocketMinipoolDelegate.sol +++ b/contracts/contract/minipool/RocketMinipoolDelegate.sol @@ -420,15 +420,15 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn } // Dissolve the minipool, returning user deposited ETH to the deposit pool - // Only accepts calls from the minipool owner (node), or from any address if timed out + // Only accepts calls when in Prelaunch for too long without calling stake() + // In other words, this prevents User ETH from getting stuck when an NO fails to move forward function dissolve() override external onlyInitialised { // Check current status - require(status == MinipoolStatus.Initialised || status == MinipoolStatus.Prelaunch, "The minipool can only be dissolved while initialised or in prelaunch"); + require(status == MinipoolStatus.Prelaunch, "The minipool can only be dissolved while in prelaunch"); // Load contracts RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - // Check if being dissolved by minipool owner or minipool is timed out require( - (status == MinipoolStatus.Prelaunch && block.timestamp.sub(statusTime) >= rocketDAOProtocolSettingsMinipool.getLaunchTimeout()), + (block.timestamp.sub(statusTime) >= rocketDAOProtocolSettingsMinipool.getLaunchTimeout()), "The minipool can only be dissolved once it has timed out" ); // Perform the dissolution From 3f1c84170c763877f322b049f18a5f608e3cd5a8 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Fri, 12 Aug 2022 16:26:35 -0500 Subject: [PATCH 5/8] [wip] Deposit side - No longer supports 32E deposits - Will support any deposit size the same way (eg, 16E or 8E) --- .../minipool/RocketMinipoolDelegate.sol | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/contracts/contract/minipool/RocketMinipoolDelegate.sol b/contracts/contract/minipool/RocketMinipoolDelegate.sol index 6c2cff05b..ae69c7272 100644 --- a/contracts/contract/minipool/RocketMinipoolDelegate.sol +++ b/contracts/contract/minipool/RocketMinipoolDelegate.sol @@ -5,6 +5,7 @@ pragma solidity 0.7.6; import "@openzeppelin/contracts/math/SafeMath.sol"; import "./RocketMinipoolStorageLayout.sol"; +import "../../interface/RocketVaultInterface.sol"; import "../../interface/casper/DepositInterface.sol"; import "../../interface/deposit/RocketDepositPoolInterface.sol"; import "../../interface/minipool/RocketMinipoolInterface.sol"; @@ -17,6 +18,7 @@ import "../../interface/node/RocketNodeStakingInterface.sol"; import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol"; import "../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol"; import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsNodeInterface.sol"; +import "../../interface/dao/protocol/settings/RocketDAOProtocolSettingsDepositInterface.sol"; import "../../interface/dao/node/RocketDAONodeTrustedInterface.sol"; import "../../interface/network/RocketNetworkFeesInterface.sol"; import "../../interface/token/RocketTokenRETHInterface.sol"; @@ -31,6 +33,7 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn uint8 public constant version = 2; // Used to identify which delegate contract each minipool is using uint256 constant calcBase = 1 ether; uint256 constant prelaunchAmount = 16 ether; // The amount of ETH initially deposited when minipool is created + uint256 constant efficientprelaunchAmount = 1 ether; // The amount of ETH initially deposited when minipool is created uint256 constant distributionCooldown = 100; // Number of blocks that must pass between calls to distributeBalance // Libs @@ -131,16 +134,20 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn function nodeDeposit(bytes calldata _validatorPubkey, bytes calldata _validatorSignature, bytes32 _depositDataRoot) override external payable onlyLatestContract("rocketNodeDeposit", msg.sender) onlyInitialised { // Check current status & node deposit status require(status == MinipoolStatus.Initialised, "The node deposit can only be assigned while initialised"); - require(!nodeDepositAssigned, "The node deposit has already been assigned"); - // Progress full minipool to prelaunch - if (depositType == MinipoolDeposit.Full) { setStatus(MinipoolStatus.Prelaunch); } - // Update node deposit details - nodeDepositBalance = msg.value; - nodeDepositAssigned = true; + require(nodeDepositBalance == 0, "The minipool already has a previous nodeDeposit"); + // Emit ether deposited event emit EtherDeposited(msg.sender, msg.value, block.timestamp); // Perform the pre-stake to lock in withdrawal credentials on beacon chain preStake(_validatorPubkey, _validatorSignature, _depositDataRoot); + + nodeDepositBalance = msg.value; + nodeDepositAssigned = 0; // should be 0 from initialization anyhow + + // Deposit ETH (except the ETH needed to preStake) without minting rETH + // Transfer to vault directly instead of via processDeposits to avoid assigning twice + RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault")); + rocketVault.depositEther{value: msg.value.sub(efficientprelaunchAmount)}(); } // Assign user deposited ETH to the minipool and mark it as prelaunch @@ -220,7 +227,11 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn DepositInterface casperDeposit = DepositInterface(getContractAddress("casperDeposit")); RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager")); // Get launch amount - uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance().sub(prelaunchAmount); + if (depositType == MinipoolDeposit.Efficient) { + uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance().sub(efficientprelaunchAmount); + } else { + uint256 launchAmount = rocketDAOProtocolSettingsMinipool.getLaunchBalance().sub(prelaunchAmount); + } // Check minipool balance require(address(this).balance >= launchAmount, "Insufficient balance to begin staking"); // Retrieve validator pubkey from storage @@ -237,7 +248,7 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn DepositInterface casperDeposit = DepositInterface(getContractAddress("casperDeposit")); RocketMinipoolManagerInterface rocketMinipoolManager = RocketMinipoolManagerInterface(getContractAddress("rocketMinipoolManager")); // Check minipool balance - require(address(this).balance >= prelaunchAmount, "Insufficient balance to pre-stake"); + require(address(this).balance >= efficientprelaunchAmount, "Insufficient balance to pre-stake"); // Check validator pubkey is not in use require(rocketMinipoolManager.getMinipoolByPubkey(_validatorPubkey) == address(0x0), "Validator pubkey is in use"); // Set minipool pubkey @@ -245,9 +256,9 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn // Get withdrawal credentials bytes memory withdrawalCredentials = rocketMinipoolManager.getMinipoolWithdrawalCredentials(address(this)); // Send staking deposit to casper - casperDeposit.deposit{value : prelaunchAmount}(_validatorPubkey, withdrawalCredentials, _validatorSignature, _depositDataRoot); + casperDeposit.deposit{value : efficientprelaunchAmount}(_validatorPubkey, withdrawalCredentials, _validatorSignature, _depositDataRoot); // Emit event - emit MinipoolPrestaked(_validatorPubkey, _validatorSignature, _depositDataRoot, prelaunchAmount, withdrawalCredentials, block.timestamp); + emit MinipoolPrestaked(_validatorPubkey, _validatorSignature, _depositDataRoot, efficientprelaunchAmount, withdrawalCredentials, block.timestamp); } // Mark the minipool as withdrawable From cc7293f34f3ab4a343ab4063566bbab6e7f9344b Mon Sep 17 00:00:00 2001 From: Valdorff Date: Fri, 12 Aug 2022 16:46:21 -0500 Subject: [PATCH 6/8] [wip] Assignment side --- .../RocketDAOProtocolSettingsMinipool.sol | 15 ++++++--------- .../contract/deposit/RocketDepositPool.sol | 18 ++++++++++++++++++ .../minipool/RocketMinipoolDelegate.sol | 14 +++++++++----- .../contract/minipool/RocketMinipoolQueue.sol | 12 ++++++------ contracts/contract/node/RocketNodeDeposit.sol | 12 +++++++----- ...ketDAOProtocolSettingsMinipoolInterface.sol | 1 - 6 files changed, 46 insertions(+), 26 deletions(-) diff --git a/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsMinipool.sol b/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsMinipool.sol index a6aaa28c4..578deb5e3 100644 --- a/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsMinipool.sol +++ b/contracts/contract/dao/protocol/settings/RocketDAOProtocolSettingsMinipool.sol @@ -8,6 +8,7 @@ import "./RocketDAOProtocolSettings.sol"; import "../../../../interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol"; import "../../../../interface/dao/node/settings/RocketDAONodeTrustedSettingsMinipoolInterface.sol"; import "../../../../types/MinipoolDeposit.sol"; +import "../../../../contracts/contract/minipool/RocketMinipoolDelegate.sol"; // Network minipool settings contract RocketDAOProtocolSettingsMinipool is RocketDAOProtocolSettings, RocketDAOProtocolSettingsMinipoolInterface { @@ -49,29 +50,25 @@ contract RocketDAOProtocolSettingsMinipool is RocketDAOProtocolSettings, RocketD } // Required node deposit amounts - function getDepositNodeAmount(MinipoolDeposit _depositType) override external pure returns (uint256) { - if (_depositType == MinipoolDeposit.Full) { return getFullDepositNodeAmount(); } - if (_depositType == MinipoolDeposit.Half) { return getHalfDepositNodeAmount(); } - if (_depositType == MinipoolDeposit.Empty) { return getEmptyDepositNodeAmount(); } - return 0; - } function getFullDepositNodeAmount() override public pure returns (uint256) { return getLaunchBalance(); } function getHalfDepositNodeAmount() override public pure returns (uint256) { return getLaunchBalance().div(2); } - function getEmptyDepositNodeAmount() override public pure returns (uint256) { - return 0 ether; - } // Required user deposit amounts function getDepositUserAmount(MinipoolDeposit _depositType) override external pure returns (uint256) { + if (_depositType == MinipoolDeposit.Efficient) { return getEfficientDepositUserAmount(); } if (_depositType == MinipoolDeposit.Full) { return getFullDepositUserAmount(); } if (_depositType == MinipoolDeposit.Half) { return getHalfDepositUserAmount(); } if (_depositType == MinipoolDeposit.Empty) { return getEmptyDepositUserAmount(); } return 0; } + function getEfficientDepositUserAmount() override public pure returns (uint256) { + address delegateAddress = getContractAddress("rocketMinipoolDelegate"); + return getLaunchBalance().sub(delegateAddress.efficientprelaunchAmount); + } function getFullDepositUserAmount() override public pure returns (uint256) { return getLaunchBalance().div(2); } diff --git a/contracts/contract/deposit/RocketDepositPool.sol b/contracts/contract/deposit/RocketDepositPool.sol index cc592c247..3ad866823 100644 --- a/contracts/contract/deposit/RocketDepositPool.sol +++ b/contracts/contract/deposit/RocketDepositPool.sol @@ -213,6 +213,24 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul assignmentIndex++; } + // Prepare efficient deposit assignments - will always need 31 ETH + count = rocketMinipoolQueue.getLength(MinipoolDeposit.Efficient); + minipoolCapacity = rocketDAOProtocolSettingsMinipool.getDepositUserAmount(MinipoolDeposit.Efficient); + for (i; i < i + count; ++i) { // NOTE - this is a weird line - we continue the indexing from the full deposit loop + if (depositValueForAssignments < minipoolCapacity) { + if (socializedAssignments == 0) { break; } + else {socializedAssignments--;} + } + if (balance.sub(totalEther) < minipoolCapacity) { break; } + // Dequeue the minipool + address minipoolAddress = rocketMinipoolQueue.dequeueMinipoolByDeposit(MinipoolDeposit.Efficient); + // Update running total + totalEther = totalEther.add(minipoolCapacity); + // Add assignment + assignments[i].etherAssigned = minipoolCapacity; + assignments[i].minipoolAddress = minipoolAddress; + } + if (totalEther > 0) { // Withdraw ETH from vault _rocketVault.withdrawEther(totalEther); diff --git a/contracts/contract/minipool/RocketMinipoolDelegate.sol b/contracts/contract/minipool/RocketMinipoolDelegate.sol index ae69c7272..43159be2c 100644 --- a/contracts/contract/minipool/RocketMinipoolDelegate.sol +++ b/contracts/contract/minipool/RocketMinipoolDelegate.sol @@ -158,15 +158,19 @@ contract RocketMinipoolDelegate is RocketMinipoolStorageLayout, RocketMinipoolIn require(userDepositAssignedTime == 0, "The user deposit has already been assigned"); // Progress initialised minipool to prelaunch if (status == MinipoolStatus.Initialised) { setStatus(MinipoolStatus.Prelaunch); } - // Update user deposit details - userDepositBalance = msg.value; - userDepositAssignedTime = block.timestamp; - // Refinance full minipool + if (depositType == MinipoolDeposit.Full) { - // Update node balances + // Refinance full minipool nodeDepositBalance = nodeDepositBalance.sub(msg.value); nodeRefundBalance = nodeRefundBalance.add(msg.value); } + + + nodeDepositAssigned = true; // indicate that the node deposit was returned for Efficient queue + // Update user deposit details + userDepositBalance = msg.value; + userDepositAssignedTime = block.timestamp; + // Emit ether deposited event emit EtherDeposited(msg.sender, msg.value, block.timestamp); } diff --git a/contracts/contract/minipool/RocketMinipoolQueue.sol b/contracts/contract/minipool/RocketMinipoolQueue.sol index a558bd86c..929f349c0 100644 --- a/contracts/contract/minipool/RocketMinipoolQueue.sol +++ b/contracts/contract/minipool/RocketMinipoolQueue.sol @@ -47,6 +47,7 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { // Get the length of a queue // Returns 0 for invalid queues function getLength(MinipoolDeposit _depositType) override external view returns (uint256) { + if (_depositType == MinipoolDeposit.Efficient) { return getLength(queueKeyEfficient); } if (_depositType == MinipoolDeposit.Full) { return getLength(queueKeyFull); } if (_depositType == MinipoolDeposit.Half) { return getLength(queueKeyHalf); } if (_depositType == MinipoolDeposit.Empty) { return getLength(queueKeyEmpty); } @@ -64,12 +65,15 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { getLength(queueKeyFull).mul(rocketDAOProtocolSettingsMinipool.getFullDepositUserAmount()) ).add( getLength(queueKeyHalf).mul(rocketDAOProtocolSettingsMinipool.getHalfDepositUserAmount()) + ).add( + getLength(queueKeyEfficient).mul(rocketDAOProtocolSettingsMinipool.getEfficientDepositUserAmount()) ); } // Add a minipool to the end of the appropriate queue // Only accepts calls from the RocketMinipoolManager contract function enqueueMinipool(MinipoolDeposit _depositType, address _minipool) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketMinipoolManager", msg.sender) { + if (_depositType == MinipoolDeposit.Efficient) { return enqueueMinipool(queueKeyEfficient, _minipool); } if (_depositType == MinipoolDeposit.Half) { return enqueueMinipool(queueKeyHalf, _minipool); } if (_depositType == MinipoolDeposit.Full) { return enqueueMinipool(queueKeyFull, _minipool); } if (_depositType == MinipoolDeposit.Empty) { return enqueueMinipool(queueKeyEmpty, _minipool); } @@ -83,15 +87,10 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { emit MinipoolEnqueued(_minipool, _key, block.timestamp); } - // Remove the first available minipool from the highest priority queue and return its address // Only accepts calls from the RocketDepositPool contract - function dequeueMinipool() override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address minipoolAddress) { - if (getLength(queueKeyHalf) > 0) { return dequeueMinipool(queueKeyHalf); } - if (getLength(queueKeyFull) > 0) { return dequeueMinipool(queueKeyFull); } - if (getLength(queueKeyEmpty) > 0) { return dequeueMinipool(queueKeyEmpty); } - require(false, "No minipools are available"); } function dequeueMinipoolByDeposit(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyLatestContract("rocketDepositPool", msg.sender) returns (address minipoolAddress) { + if (_depositType == MinipoolDeposit.Efficient) { return dequeueMinipool(queueKeyEfficient); } if (_depositType == MinipoolDeposit.Half) { return dequeueMinipool(queueKeyHalf); } if (_depositType == MinipoolDeposit.Full) { return dequeueMinipool(queueKeyFull); } if (_depositType == MinipoolDeposit.Empty) { return dequeueMinipool(queueKeyEmpty); } @@ -113,6 +112,7 @@ contract RocketMinipoolQueue is RocketBase, RocketMinipoolQueueInterface { // queue. This is acceptable because removing minipools should be rare. function removeMinipool(MinipoolDeposit _depositType) override external onlyLatestContract("rocketMinipoolQueue", address(this)) onlyRegisteredMinipool(msg.sender) { // Remove minipool from queue + if (_depositType == MinipoolDeposit.Efficient) { return removeMinipool(queueKeyEfficient, msg.sender); } if (_depositType == MinipoolDeposit.Half) { return removeMinipool(queueKeyHalf, msg.sender); } if (_depositType == MinipoolDeposit.Full) { return removeMinipool(queueKeyFull, msg.sender); } if (_depositType == MinipoolDeposit.Empty) { return removeMinipool(queueKeyEmpty, msg.sender); } diff --git a/contracts/contract/node/RocketNodeDeposit.sol b/contracts/contract/node/RocketNodeDeposit.sol index 26f79a271..f3daa2c36 100644 --- a/contracts/contract/node/RocketNodeDeposit.sol +++ b/contracts/contract/node/RocketNodeDeposit.sol @@ -70,11 +70,13 @@ contract RocketNodeDeposit is RocketBase, RocketNodeDepositInterface { function getDepositType(uint256 _amount) public override view returns (MinipoolDeposit) { // Get contract RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool")); - // Get deposit type by node deposit amount - if (_amount == rocketDAOProtocolSettingsMinipool.getFullDepositNodeAmount()) { return MinipoolDeposit.Full; } - else if (_amount == rocketDAOProtocolSettingsMinipool.getHalfDepositNodeAmount()) { return MinipoolDeposit.Half; } - // Invalid deposit amount - return MinipoolDeposit.None; + // Ensure valid deposit amount + if (_amount == rocketDAOProtocolSettingsMinipool.getHalfDepositNodeAmount()) { + // invalid deposit amount + return MinipoolDeposit.None; + } + // All deposits going forward have the same type and use the same queue + return MinipoolDeposit.Efficient; } function checkNodeFee(uint256 _minimumNodeFee) private view { diff --git a/contracts/interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol b/contracts/interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol index 4fee3d256..31f9986bf 100644 --- a/contracts/interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol +++ b/contracts/interface/dao/protocol/settings/RocketDAOProtocolSettingsMinipoolInterface.sol @@ -6,7 +6,6 @@ import "../../../../types/MinipoolDeposit.sol"; interface RocketDAOProtocolSettingsMinipoolInterface { function getLaunchBalance() external view returns (uint256); - function getDepositNodeAmount(MinipoolDeposit _depositType) external view returns (uint256); function getFullDepositNodeAmount() external view returns (uint256); function getHalfDepositNodeAmount() external view returns (uint256); function getEmptyDepositNodeAmount() external view returns (uint256); From d64da922983086b4ac404a6197ecc34d834e75de Mon Sep 17 00:00:00 2001 From: Valdorff Date: Fri, 19 Aug 2022 13:46:40 -0500 Subject: [PATCH 7/8] [technically optional] Add stakingQueueETH to balances oDAO tracks --- .../network/RocketNetworkBalances.sol | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/contracts/contract/network/RocketNetworkBalances.sol b/contracts/contract/network/RocketNetworkBalances.sol index 8e855ca4f..4a08aacb3 100644 --- a/contracts/contract/network/RocketNetworkBalances.sol +++ b/contracts/contract/network/RocketNetworkBalances.sol @@ -17,7 +17,7 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { using SafeMath for uint; // Events - event BalancesSubmitted(address indexed from, uint256 block, uint256 totalEth, uint256 stakingEth, uint256 rethSupply, uint256 time); + event BalancesSubmitted(address indexed from, uint256 block, uint256 totalEth, uint256 stakingEth, uint256 stakingQueueEth, uint256 rethSupply, uint256 time); event BalancesUpdated(uint256 block, uint256 totalEth, uint256 stakingEth, uint256 rethSupply, uint256 time); // Construct @@ -33,7 +33,7 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { setUint(keccak256("network.balances.updated.block"), _value); } - // The current RP network total ETH balance + // The current RP network total user ETH balance function getTotalETHBalance() override public view returns (uint256) { return getUint(keccak256("network.balance.total")); } @@ -41,7 +41,7 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { setUint(keccak256("network.balance.total"), _value); } - // The current RP network staking ETH balance + // The current RP network staking ETH balance from users function getStakingETHBalance() override public view returns (uint256) { return getUint(keccak256("network.balance.staking")); } @@ -49,6 +49,15 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { setUint(keccak256("network.balance.staking"), _value); } + // The current RP network total staking ETH balance from the minipool queue + // - Note: this does not contribute to getTotalETHBalance, as it isn't from User deposits + function getStakingQueueETHBalance() override public view returns (uint256) { + return getUint(keccak256("network.balance.queuestaking")); + } + function setStakingQueueETHBalance(uint256 _value) private { + setUint(keccak256("network.balance.queuestaking"), _value); + } + // The current RP network total rETH supply function getTotalRETHSupply() override external view returns (uint256) { return getUint(keccak256("network.balance.reth.supply")); @@ -68,7 +77,7 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { // Submit network balances for a block // Only accepts calls from trusted (oracle) nodes - function submitBalances(uint256 _block, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) onlyTrustedNode(msg.sender) { + function submitBalances(uint256 _block, uint256 _totalEth, uint256 _stakingEth, uint256 _stakingQueueEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) onlyTrustedNode(msg.sender) { // Check settings RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork")); require(rocketDAOProtocolSettingsNetwork.getSubmitBalancesEnabled(), "Submitting balances is currently disabled"); @@ -78,8 +87,8 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { // Check balances require(_stakingEth <= _totalEth, "Invalid network balances"); // Get submission keys - bytes32 nodeSubmissionKey = keccak256(abi.encodePacked("network.balances.submitted.node", msg.sender, _block, _totalEth, _stakingEth, _rethSupply)); - bytes32 submissionCountKey = keccak256(abi.encodePacked("network.balances.submitted.count", _block, _totalEth, _stakingEth, _rethSupply)); + bytes32 nodeSubmissionKey = keccak256(abi.encodePacked("network.balances.submitted.node", msg.sender, _block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply)); + bytes32 submissionCountKey = keccak256(abi.encodePacked("network.balances.submitted.count", _block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply)); // Check & update node submission status require(!getBool(nodeSubmissionKey), "Duplicate submission from node"); setBool(nodeSubmissionKey, true); @@ -88,16 +97,16 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { uint256 submissionCount = getUint(submissionCountKey).add(1); setUint(submissionCountKey, submissionCount); // Emit balances submitted event - emit BalancesSubmitted(msg.sender, _block, _totalEth, _stakingEth, _rethSupply, block.timestamp); + emit BalancesSubmitted(msg.sender, _block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply, block.timestamp); // Check submission count & update network balances RocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted")); if (calcBase.mul(submissionCount).div(rocketDAONodeTrusted.getMemberCount()) >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold()) { - updateBalances(_block, _totalEth, _stakingEth, _rethSupply); + updateBalances(_block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply); } } // Executes updateBalances if consensus threshold is reached - function executeUpdateBalances(uint256 _block, uint256 _totalEth, uint256 _stakingEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) { + function executeUpdateBalances(uint256 _block, uint256 _totalEth, uint256 _stakingEth, uint256, _stakingQueueEth, uint256 _rethSupply) override external onlyLatestContract("rocketNetworkBalances", address(this)) { // Check settings RocketDAOProtocolSettingsNetworkInterface rocketDAOProtocolSettingsNetwork = RocketDAOProtocolSettingsNetworkInterface(getContractAddress("rocketDAOProtocolSettingsNetwork")); require(rocketDAOProtocolSettingsNetwork.getSubmitBalancesEnabled(), "Submitting balances is currently disabled"); @@ -113,7 +122,7 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { // Check submission count & update network balances RocketDAONodeTrustedInterface rocketDAONodeTrusted = RocketDAONodeTrustedInterface(getContractAddress("rocketDAONodeTrusted")); require(calcBase.mul(submissionCount).div(rocketDAONodeTrusted.getMemberCount()) >= rocketDAOProtocolSettingsNetwork.getNodeConsensusThreshold(), "Consensus has not been reached"); - updateBalances(_block, _totalEth, _stakingEth, _rethSupply); + updateBalances(_block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply); } // Update network balances @@ -122,9 +131,10 @@ contract RocketNetworkBalances is RocketBase, RocketNetworkBalancesInterface { setBalancesBlock(_block); setTotalETHBalance(_totalEth); setStakingETHBalance(_stakingEth); + setStakingQueueETHBalance(_stakingQueueEth); setTotalRETHSupply(_rethSupply); // Emit balances updated event - emit BalancesUpdated(_block, _totalEth, _stakingEth, _rethSupply, block.timestamp); + emit BalancesUpdated(_block, _totalEth, _stakingEth, _stakingQueueEth, _rethSupply, block.timestamp); } // Returns the latest block number that oracles should be reporting balances for From 652efb1ebfce7bd1113e40a82fff37914feafc48 Mon Sep 17 00:00:00 2001 From: Valdorff Date: Tue, 30 Aug 2022 22:43:20 -0500 Subject: [PATCH 8/8] Using eth in queue to simplify flexible queue --- design.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 design.md diff --git a/design.md b/design.md new file mode 100644 index 000000000..efec50af0 --- /dev/null +++ b/design.md @@ -0,0 +1,17 @@ +## Top level idea + +- Consistency makes our queue easier to work with + - For example, queue_capacity is currently just queue_length*16 for the half deposit queue + - For example, we need to know the capacity of the next minipool in the queue to decide whether we + have enough ETH to assign it +- We can maintain consistency by implementing the "use eth in the queue" idea + - For this idea, we make the minimum deposit on the beacon chain (1 ETH), and _every_ minipool + will need 31 ETH to launch. This will be true with 16 or 8 ETH node deposits for now, and for + whatever future values we support. + - If we _don't_ maintain consistency like this, finding capacity requires either iterating through + the queue, or adding an extra tracking variable that we update on pop. +- In my "[wip] Deposit side" commit, I've used nodeDepositAssigned=False, and a positive + nodeDepositBalance to indicate this state where I've provided some ETH (eg, 16), but it's not all + in the minipool contract. + +To add LEB8s, we'd need to tweak getDepositType to allow 8 ETH deposits. \ No newline at end of file