Skip to content

Commit 46b090d

Browse files
committed
Add function to withdraw credit as rETH from withdrawal address
1 parent 6c31f26 commit 46b090d

File tree

4 files changed

+42
-9
lines changed

4 files changed

+42
-9
lines changed

contracts/contract/deposit/RocketDepositPool.sol

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul
4444
event FundsRequested(address indexed receiver, uint256 validatorId, uint256 amount, bool expressQueue, uint256 time);
4545
event FundsAssigned(address indexed receiver, uint256 amount, uint256 time);
4646
event QueueExited(address indexed nodeAddress, uint256 time);
47-
event CreditWithdrawn(address indexed receiver, uint256 amount, uint256 time);
47+
event CreditWithdrawn(address indexed nodeAddress, uint256 amount, uint256 time);
4848

4949
// Structs
5050
struct MinipoolAssignment {
@@ -563,27 +563,43 @@ contract RocketDepositPool is RocketBase, RocketDepositPoolInterface, RocketVaul
563563
/// @notice Allows node operator to withdraw any ETH credit they have as rETH
564564
/// @param _amount Amount in ETH to withdraw
565565
function withdrawCredit(uint256 _amount) override external onlyRegisteredNode(msg.sender) onlyThisLatestContract {
566+
address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(msg.sender);
567+
_withdrawCreditFor(msg.sender, withdrawalAddress, _amount);
568+
}
569+
570+
/// @notice Allows node operator to withdraw any ETH credit they have as rETH from their withdrawal address
571+
/// @param _nodeAddress Address of the node operator
572+
/// @param _amount Amount in ETH to withdraw
573+
function withdrawCreditFor(address _nodeAddress, uint256 _amount) override public onlyRegisteredNode(_nodeAddress) onlyThisLatestContract {
574+
// Check caller
575+
address withdrawalAddress = rocketStorage.getNodeWithdrawalAddress(_nodeAddress);
576+
require(msg.sender == withdrawalAddress, "Must be called from withdrawal address");
577+
// Withdraw credit
578+
_withdrawCreditFor(_nodeAddress, withdrawalAddress, _amount);
579+
}
580+
581+
/// @dev Withdraws credit from a given node operator as rETH
582+
function _withdrawCreditFor(address _nodeAddress, address _recipient, uint256 _amount) internal {
566583
// Check deposits are enabled
567584
RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit"));
568585
require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled");
569586
// Check node operator has sufficient credit
570-
uint256 credit = getUint(keccak256(abi.encodePacked("node.deposit.credit.balance", msg.sender)));
587+
uint256 credit = getUint(keccak256(abi.encodePacked("node.deposit.credit.balance", _nodeAddress)));
571588
require(credit >= _amount, "Amount exceeds credit available");
572589
// Account for balance changes
573-
subUint(keccak256(abi.encodePacked("node.deposit.credit.balance", msg.sender)), _amount);
590+
subUint(keccak256(abi.encodePacked("node.deposit.credit.balance", _nodeAddress)), _amount);
574591
// Note: The funds are already stored in RocketVault under RocketDepositPool so no ETH transfer is required
575592
// Get the node operator's withdrawal address
576593
RocketNodeManagerInterface rocketNodeManager = RocketNodeManagerInterface(getContractAddress("rocketNodeManager"));
577-
address nodeWithdrawalAddress = rocketNodeManager.getNodeWithdrawalAddress(msg.sender);
578594
// Calculate deposit fee
579595
unchecked { // depositFee < msg.value
580596
uint256 depositFee = _amount * rocketDAOProtocolSettingsDeposit.getDepositFee() / calcBase;
581597
uint256 depositNet = _amount - depositFee;
582-
// Mint rETH to node
583-
rocketTokenRETH.mint(depositNet, nodeWithdrawalAddress);
598+
// Mint rETH to recipient address
599+
rocketTokenRETH.mint(depositNet, _recipient);
584600
}
585601
// Emit event
586-
emit CreditWithdrawn(msg.sender, _amount, block.timestamp);
602+
emit CreditWithdrawn(_nodeAddress, _amount, block.timestamp);
587603
}
588604

589605
/// @notice Gets the receiver next to be assigned and whether it can be assigned immediately

contracts/interface/deposit/RocketDepositPoolInterface.sol

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface RocketDepositPoolInterface {
2323
function reduceBond(address _nodeAddress, uint256 _amount) external;
2424
function fundsReturned(address _nodeAddress, uint256 _nodeAmount, uint256 _userAmount) external;
2525
function withdrawCredit(uint256 _amount) external;
26+
function withdrawCreditFor(address _nodeAddress, uint256 _amount) external;
2627
function getQueueTop() external view returns (address receiver, bool assignmentPossible, uint256 headMovedBlock);
2728
function getQueueIndex() external view returns (uint256);
2829
function getMinipoolQueueLength() external view returns (uint256);

test/megapool/megapool-tests.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,18 @@ export default function() {
860860
await withdrawCredit(node, '2'.ether);
861861
});
862862

863+
it(printTitle('node', 'can reduce bond to new requirement and use credit to mint rETH from their withdrawal address'), async () => {
864+
await reduceBond(megapool, '2'.ether);
865+
// Fail to withdraw credit from random address
866+
await shouldRevert(
867+
withdrawCredit(node, '2'.ether, random),
868+
'Was able to withdraw credit from random address',
869+
'Must be called from withdrawal address'
870+
);
871+
// Withdraw credit from withdrawal address
872+
await withdrawCredit(node, '2'.ether, nodeWithdrawalAddress);
873+
});
874+
863875
it(printTitle('node', 'can reduce bond to new requirement and use some credit for another validator and some for rETH'), async () => {
864876
await reduceBond(megapool, '2'.ether);
865877
await withdrawCredit(node, '1'.ether);

test/megapool/scenario-withdraw-credit.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
} from '../_utils/artifacts';
77
import { assertBN } from '../_helpers/bn';
88

9-
export async function withdrawCredit(node, amount) {
9+
export async function withdrawCredit(node, amount, from = node) {
1010
const rocketDepositPool = await RocketDepositPool.deployed();
1111
const rocketStorage = await RocketStorage.deployed();
1212
const rocketTokenRETH = await RocketTokenRETH.deployed();
@@ -37,7 +37,11 @@ export async function withdrawCredit(node, amount) {
3737

3838
const dataBefore = await getData();
3939

40-
await rocketDepositPool.connect(node).withdrawCredit(amount);
40+
if (from === node) {
41+
await rocketDepositPool.connect(from).withdrawCredit(amount);
42+
} else {
43+
await rocketDepositPool.connect(from).withdrawCreditFor(node.address, amount);
44+
}
4145

4246
const dataAfter = await getData();
4347

0 commit comments

Comments
 (0)