Skip to content

Commit

Permalink
fix tests for complete queued withdrawal with shares
Browse files Browse the repository at this point in the history
  • Loading branch information
danoctavian committed Nov 1, 2024
1 parent ccf6075 commit a516b97
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 20 deletions.
4 changes: 2 additions & 2 deletions src/StakingNode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -257,15 +257,15 @@ contract StakingNode is IStakingNode, StakingNodeEvents, ReentrancyGuardUpgradea
* @dev This function revokes the delegation by calling the `undelegate` method on the `DelegationManager`.
* It emits an `Undelegated` event with the address of the operator from whom the delegation is being removed.
*/
function undelegate() public onlyDelegator {
function undelegate() public onlyDelegator returns (bytes32[] memory withdrawalRoots) {

IDelegationManager delegationManager = IDelegationManager(address(stakingNodesManager.delegationManager()));

address operator = delegationManager.delegatedTo(address(this));

// Get current shares before undelegating
int256 shares = stakingNodesManager.eigenPodManager().podOwnerShares(address(this));
delegationManager.undelegate(address(this));
withdrawalRoots = delegationManager.undelegate(address(this));

if (shares > 0) {
// Adjust queuedSharesAmount by sharesBefore
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/IStakingNode.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ interface IStakingNode {
ISignatureUtils.SignatureWithExpiry memory approverSignatureAndExpiry,
bytes32 approverSalt
) external;
function undelegate() external;
function undelegate() external returns (bytes32[] memory withdrawalRoots);

function implementation() external view returns (address);

Expand Down
85 changes: 71 additions & 14 deletions test/integration/StakingNode.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ contract StakingNodeDelegation is StakingNodeTestBase {

address operator1 = address(0x9999);
address operator2 = address(0x8888);
uint256 nodeId;
IStakingNode stakingNodeInstance;

function setUp() public override {
super.setUp();
Expand All @@ -129,18 +131,18 @@ contract StakingNodeDelegation is StakingNodeTestBase {
"ipfs://some-ipfs-hash"
);
}


nodeId = createStakingNodes(1)[0];
stakingNodeInstance = stakingNodesManager.nodes(nodeId);
}

function testDelegateFailWhenNotAdmin() public {
vm.prank(actors.ops.STAKING_NODE_CREATOR);
IStakingNode stakingNodeInstance = stakingNodesManager.createStakingNode();
vm.expectRevert();
stakingNodeInstance.delegate(address(this), ISignatureUtils.SignatureWithExpiry({signature: "", expiry: 0}), bytes32(0));
}

function testStakingNodeDelegate() public {
vm.prank(actors.ops.STAKING_NODE_CREATOR);
IStakingNode stakingNodeInstance = stakingNodesManager.createStakingNode();
IDelegationManager delegationManager = stakingNodesManager.delegationManager();
IPausable pauseDelegationManager = IPausable(address(delegationManager));
vm.prank(chainAddresses.eigenlayer.DELEGATION_PAUSER_ADDRESS);
Expand All @@ -154,8 +156,7 @@ contract StakingNodeDelegation is StakingNodeTestBase {
}

function testStakingNodeUndelegate() public {
vm.prank(actors.ops.STAKING_NODE_CREATOR);
IStakingNode stakingNodeInstance = stakingNodesManager.createStakingNode();

IDelegationManager delegationManager = stakingNodesManager.delegationManager();
IPausable pauseDelegationManager = IPausable(address(delegationManager));

Expand Down Expand Up @@ -185,8 +186,6 @@ contract StakingNodeDelegation is StakingNodeTestBase {

function testDelegateUndelegateAndDelegateAgain() public {

vm.prank(actors.ops.STAKING_NODE_CREATOR);
IStakingNode stakingNodeInstance = stakingNodesManager.createStakingNode();
IDelegationManager delegationManager = stakingNodesManager.delegationManager();

// Delegate to operator1
Expand All @@ -211,9 +210,7 @@ contract StakingNodeDelegation is StakingNodeTestBase {
assertEq(delegatedOperator2, operator2, "Delegation is not set to operator2.");
}

function testDelegateUndelegateAndDelegateAgainWithExistingStake() public {

uint256 nodeId = createStakingNodes(1)[0];
function testDelegateUndelegateWithExistingStake() public {
{
vm.deal(user, 1000 ether);
yneth.depositETH{value: 1000 ether}(user);
Expand All @@ -225,7 +222,6 @@ contract StakingNodeDelegation is StakingNodeTestBase {
_verifyWithdrawalCredentials(nodeId, validatorIndices[0]);
}

IStakingNode stakingNodeInstance = stakingNodesManager.nodes(nodeId);
IDelegationManager delegationManager = stakingNodesManager.delegationManager();

// Delegate to operator1
Expand All @@ -248,7 +244,8 @@ contract StakingNodeDelegation is StakingNodeTestBase {
uint256 initialQueuedShares = stakingNodeInstance.getQueuedSharesAmount();
// Undelegate
vm.prank(actors.admin.STAKING_NODES_DELEGATOR);
stakingNodeInstance.undelegate();
bytes32[] memory withdrawalRoots = stakingNodeInstance.undelegate();
assertEq(withdrawalRoots.length, 1, "Should have exactly one withdrawal root");

// Get final queued shares and verify increase
uint256 finalQueuedShares = stakingNodeInstance.getQueuedSharesAmount();
Expand All @@ -260,13 +257,24 @@ contract StakingNodeDelegation is StakingNodeTestBase {

address undelegatedAddress = delegationManager.delegatedTo(address(stakingNodeInstance));
assertEq(undelegatedAddress, address(0), "Delegation should be cleared after undelegation.");
}

function testDelegateUndelegateAndDelegateAgainWithExistingStake() public {

address initialOperator = operator1;
testDelegateUndelegateWithExistingStake();

uint256 initialTotalAssets = yneth.totalAssets();

// Complete queued withdrawals as shares
QueuedWithdrawalInfo[] memory queuedWithdrawals = new QueuedWithdrawalInfo[](1);
queuedWithdrawals[0] = QueuedWithdrawalInfo({
withdrawnAmount: 32 ether * validatorIndices.length
});
_completeQueuedWithdrawalsAsShares(queuedWithdrawals, nodeId);
_completeQueuedWithdrawalsAsShares(queuedWithdrawals, nodeId, initialOperator);

// Verify total assets stayed the same after _completeQueuedWithdrawalsAsShares
assertEq(yneth.totalAssets(), initialTotalAssets, "Total assets should not change after completing queued withdrawals");

// Delegate to operator2
vm.prank(actors.admin.STAKING_NODES_DELEGATOR);
Expand All @@ -284,6 +292,55 @@ contract StakingNodeDelegation is StakingNodeTestBase {
);
}


function testDelegateUndelegateAndDelegateAgainWithoutStake() public {

address initialOperator = operator1;
testDelegateUndelegateWithExistingStake();

uint256 initialTotalAssets = yneth.totalAssets();

// Complete queued withdrawals as shares
QueuedWithdrawalInfo[] memory queuedWithdrawals = new QueuedWithdrawalInfo[](1);
queuedWithdrawals[0] = QueuedWithdrawalInfo({
withdrawnAmount: 32 ether * validatorIndices.length
});

// Delegate to operator2
vm.prank(actors.admin.STAKING_NODES_DELEGATOR);
stakingNodeInstance.delegate(operator2, ISignatureUtils.SignatureWithExpiry({signature: "", expiry: 0}), bytes32(0));

address delegatedOperator2 = delegationManager.delegatedTo(address(stakingNodeInstance));
assertEq(delegatedOperator2, operator2, "Delegation is not set to operator2.");

// Verify total assets stayed the same after delegation to operator2
assertEq(yneth.totalAssets(), initialTotalAssets, "Total assets should not change after delegation to operator2");

assertEq(
eigenPodManager.podOwnerShares(address(stakingNodeInstance)),
0,
"Pod owner shares should be 0"
);

_completeQueuedWithdrawalsAsShares(queuedWithdrawals, nodeId, initialOperator);

// Verify total assets stayed the same after _completeQueuedWithdrawalsAsShares
assertEq(yneth.totalAssets(), initialTotalAssets, "Total assets should not change after completing queued withdrawals");

assertEq(
delegationManager.operatorShares(operator2, stakingNodeInstance.beaconChainETHStrategy()),
32 ether * validatorIndices.length,
"Operator shares should be 32 ETH per validator"
);

assertEq(
eigenPodManager.podOwnerShares(address(stakingNodeInstance)),
int256(32 ether * validatorIndices.length),
"Pod owner shares should be 32 ETH per validator"
);

}

function testImplementViewFunction() public {
vm.prank(actors.ops.STAKING_NODE_CREATOR);
IStakingNode stakingNodeInstance = stakingNodesManager.createStakingNode();
Expand Down
23 changes: 20 additions & 3 deletions test/integration/StakingNodeTestBase.sol
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,13 @@ contract StakingNodeTestBase is IntegrationBaseTest {
}
}

function _completeQueuedWithdrawalsAsShares(QueuedWithdrawalInfo[] memory queuedWithdrawals, uint256 nodeId) internal {
function _completeQueuedWithdrawalsAsShares(
QueuedWithdrawalInfo[] memory queuedWithdrawals,
uint256 nodeId,
address operator
) internal {

IDelegationManager.Withdrawal[] memory _withdrawals = _getWithdrawals(queuedWithdrawals, nodeId);
IDelegationManager.Withdrawal[] memory _withdrawals = _getWithdrawals(queuedWithdrawals, nodeId, operator);

{
IStrategy[] memory _strategies = new IStrategy[](1);
Expand All @@ -138,8 +142,21 @@ contract StakingNodeTestBase is IntegrationBaseTest {
function _getWithdrawals(
QueuedWithdrawalInfo[] memory queuedWithdrawals,
uint256 nodeId
) internal returns (IDelegationManager.Withdrawal[] memory) {
return _getWithdrawals(
queuedWithdrawals,
nodeId,
delegationManager.delegatedTo(address(stakingNodesManager.nodes(nodeId)))
);
}

function _getWithdrawals(
QueuedWithdrawalInfo[] memory queuedWithdrawals,
uint256 nodeId,
address operator
) internal returns (IDelegationManager.Withdrawal[] memory _withdrawals) {


_withdrawals = new IDelegationManager.Withdrawal[](queuedWithdrawals.length);

for (uint256 i = 0; i < queuedWithdrawals.length; i++) {
Expand All @@ -150,7 +167,7 @@ contract StakingNodeTestBase is IntegrationBaseTest {
address _stakingNode = address(stakingNodesManager.nodes(nodeId));
_withdrawals[i] = IDelegationManager.Withdrawal({
staker: _stakingNode,
delegatedTo: delegationManager.delegatedTo(_stakingNode),
delegatedTo: operator,
withdrawer: _stakingNode,
nonce: delegationManager.cumulativeWithdrawalsQueued(_stakingNode) - 1,
startBlock: uint32(block.number),
Expand Down

0 comments on commit a516b97

Please sign in to comment.