Skip to content

Commit

Permalink
Fix to prevent overassigning minipools
Browse files Browse the repository at this point in the history
  • Loading branch information
kanewallmann committed Feb 10, 2025
1 parent 159ce57 commit db3a15e
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 56 deletions.
12 changes: 10 additions & 2 deletions contracts/contract/deposit/RocketDepositPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -304,11 +304,19 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul
function _assignMinipools(uint256 _count, RocketDAOProtocolSettingsDepositInterface _rocketDAOProtocolSettingsDeposit) internal {
// Get contracts
RocketMinipoolQueueInterface rocketMinipoolQueue = RocketMinipoolQueueInterface(getContractAddress("rocketMinipoolQueue"));
RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
// Calculate max possible assignments based on current balance
uint256 variableDepositAmount = rocketDAOProtocolSettingsMinipool.getVariableDepositAmount();
uint256 maxPossible = getBalance() / variableDepositAmount;
if (maxPossible == 0) {
return;
}
if (_count > maxPossible) {
_count = maxPossible;
}
// Dequeue minipools
address[] memory minipools = rocketMinipoolQueue.dequeueMinipools(_count);
if (minipools.length > 0) {
RocketDAOProtocolSettingsMinipoolInterface rocketDAOProtocolSettingsMinipool = RocketDAOProtocolSettingsMinipoolInterface(getContractAddress("rocketDAOProtocolSettingsMinipool"));
uint256 variableDepositAmount = rocketDAOProtocolSettingsMinipool.getVariableDepositAmount();
// Withdraw ETH from vault
uint256 totalEther = minipools.length * variableDepositAmount;
rocketVault.withdrawEther(totalEther);
Expand Down
48 changes: 0 additions & 48 deletions contracts/contract/megapool/RocketMegapoolDelegate.sol
Original file line number Diff line number Diff line change
Expand Up @@ -211,54 +211,6 @@ contract RocketMegapoolDelegate is RocketMegapoolDelegateBase, RocketMegapoolDel
}
}

/// @notice Stakes RPL on the megapool
/// @param _amount the RPL amount to be staked on this megapool
// TODO: Move to new RPL staking contract
function stakeRPL(uint256 _amount) external {
revert("Not implemented");
// require(_amount > 0, "Invalid amount");
// // Transfer RPL tokens
// address rplTokenAddress = rocketStorage.getAddress(rocketTokenRPLKey);
// IERC20 rplToken = IERC20(rplTokenAddress);
// require(rplToken.transferFrom(msg.sender, address(this), _amount), "Could not transfer RPL to staking contract");
// stakedRPL += _amount;
}

/// @notice Requests RPL previously staked on this megapool to be unstaked
// @param _amount the RPL amount to be unstaked
// TODO: Move to new RPL staking contract
function requestUnstakeRPL(uint256 _amount) external onlyRPLWithdrawalAddressOrNode() {
revert("Not implemented");
// require(_amount > 0 && _amount >= stakedRPL, "Invalid amount");
// stakedRPL -= _amount;
// unstakedRPL += _amount;
// lastUnstakeRequest = block.timestamp;
}

/// @notice Unstakes RPL after waiting the 'unstaking period' after the last unstake request
// TODO: Move to new RPL staking contract
function unstakeRPL() external onlyRPLWithdrawalAddressOrNode() {
revert("Not implemented");
// uint256 unstakingPeriod = 28 days; // Change to unstaking_period parameter (RPIP-30)
// require(lastUnstakeRequest + unstakingPeriod >= block.timestamp, "Not enough time passed since last unstake RPL request");
// address rplWithdrawalAddress;
//
// RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
// if (rocketNodeManager.getNodeRPLWithdrawalAddressIsSet(nodeAddress)) {
// rplWithdrawalAddress = rocketNodeManager.getNodeRPLWithdrawalAddress(nodeAddress);
// } else {
// rplWithdrawalAddress = nodeAddress;
// }
//
// address rplAddress = rocketStorage.getAddress(rocketTokenRPLKey);
//
// uint256 unstakedAmount = unstakedRPL;
// unstakedRPL = 0;
//
// RocketVaultInterface rocketVault = RocketVaultInterface(rocketStorage.getAddress(rocketVaultKey));
// rocketVault.withdrawToken(rplWithdrawalAddress, IERC20(rplAddress), unstakedAmount);
}

/// @notice Distributes any accrued execution layer rewards sent to this address
function distribute() override public {
_distribute();
Expand Down
32 changes: 30 additions & 2 deletions test-upgrade/rocket-upgrade-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@ import { afterEach, before, beforeEach, describe, it } from 'mocha';
import {
artifacts,
RocketDAOProtocolSettingsDeposit, RocketDAOProtocolSettingsMegapool, RocketNetworkRevenues,
RocketStorage,
RocketStorage, RocketTokenDummyRPL,
RocketUpgradeOneDotFour,
} from '../test/_utils/artifacts';
import { assertBN, injectBNHelpers } from '../test/_helpers/bn';
import { endSnapShot, globalSnapShot, startSnapShot } from '../test/_utils/snapshotting';
import { registerNode } from '../test/_helpers/node';
import { nodeStakeRPL, registerNode } from '../test/_helpers/node';
import { printTitle } from '../test/_utils/formatting';
import { setDefaultParameters } from '../test/_helpers/defaults';
import { deployMegapool, getMegapoolForNode, getValidatorInfo, nodeDeposit } from '../test/_helpers/megapool';
import { deployUpgrade } from './_helpers/upgrade';
import { setDaoNodeTrustedBootstrapUpgrade } from '../test/dao/scenario-dao-node-trusted-bootstrap';
import { userDeposit } from '../test/_helpers/deposit';
import assert from 'assert';
import { createMinipool, getMinipoolMinimumRPLStake } from '../test/_helpers/minipool';
import { mintRPL } from '../test/_helpers/tokens';

const helpers = require('@nomicfoundation/hardhat-network-helpers');
const hre = require('hardhat');
Expand Down Expand Up @@ -106,4 +108,30 @@ describe('Test Upgrade', () => {
assert.equal(validatorInfoAfter.inPrestake, true);
assert.equal(validatorInfoAfter.inQueue, false);
});

it(printTitle('node', 'can assign a minipool after upgrade'), async () => {
// Register node and create a 16 ETH minipool
await registerNode({ from: node });
const minipoolRplStake = await getMinipoolMinimumRPLStake();
await mintRPL(owner, node, minipoolRplStake);
await nodeStakeRPL(minipoolRplStake, { from: node });
const minipool = await createMinipool({ from: node, value: '16'.ether });
assertBN.equal(await minipool.getStatus(), 0n); // Initialised
// Execute upgrade
await executeUpgrade();
// Queue up a megapool validator
await nodeDeposit(node);
// Perform a user deposit that will assign 1 validator (the minipool)
await userDeposit({ from: random, value: '32'.ether });
// Check minipool was assigned
assertBN.equal(await minipool.getStatus(), 1n); // Prestake status
// Perform a user deposit that will assign 1 validator (the megapool)
await userDeposit({ from: random, value: '32'.ether });
// Check megapool validator status
const megapool = await getMegapoolForNode(node);
const validatorInfoAfter = await getValidatorInfo(megapool, 0);
assert.equal(validatorInfoAfter.staked, false);
assert.equal(validatorInfoAfter.inPrestake, true);
assert.equal(validatorInfoAfter.inQueue, false);
});
});
17 changes: 13 additions & 4 deletions test/_utils/artifacts.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ class Artifact {
return new ethers.Contract(address, this.abi, hre.ethers.provider);
}

async fromDeployment(rocketStorage) {
let contractName = this.name.charAt(0).toLowerCase() + this.name.slice(1);
async fromDeployment(rocketStorage, contractName = null) {
if (contractName === null) {
contractName = this.name.charAt(0).toLowerCase() + this.name.slice(1);
}

const addressKey = ethers.solidityPackedKeccak256(['string', 'string'], ['contract.address', contractName]);
const abiKey = ethers.solidityPackedKeccak256(['string', 'string'], ['contract.abi', contractName]);
Expand Down Expand Up @@ -67,13 +69,20 @@ export class Artifacts {

async loadFromDeployment(rocketStorageAddress) {
RocketStorage.instance = this.artifacts['RocketStorage'].at(rocketStorageAddress);

// Map between network contract name and actual contract name
const mapping = {
'RocketTokenDummyRPL': 'rocketTokenRPLFixedSupply'
}
for (const name in this.artifacts) {
switch (name) {
case 'RocketStorage':
break;
default:
await this.artifacts[name].fromDeployment(RocketStorage.instance);
if (mapping.hasOwnProperty(name)) {
await this.artifacts[name].fromDeployment(RocketStorage.instance, mapping[name]);
} else {
await this.artifacts[name].fromDeployment(RocketStorage.instance);
}
}
}
}
Expand Down

0 comments on commit db3a15e

Please sign in to comment.