Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test: withdrawSharesAsTokens regression #904

Merged
merged 2 commits into from
Nov 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/test/integration/IntegrationChecks.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,6 @@ contract IntegrationCheckUtils is IntegrationBase {
// Common checks
assert_WithdrawalNotPending(delegationManager.calculateWithdrawalRoot(withdrawal), "staker withdrawal should no longer be pending");

// FIXME: This check is currently broken for native ETH deposits for some reason.
assert_Snap_Added_TokenBalances(staker, tokens, expectedTokens, "staker should have received expected tokens");
assert_Snap_Unchanged_StakerDepositShares(staker, "staker shares should not have changed");
assert_Snap_Removed_StrategyShares(strategies, shares, "strategies should have total shares decremented");
Expand Down
112 changes: 56 additions & 56 deletions src/test/integration/tests/Deposit_Delegate_Queue_Complete.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,62 @@ contract Integration_Deposit_Delegate_Queue_Complete is IntegrationCheckUtils {
/// 2. delegates to an operator
/// 3. queues a withdrawal for a ALL shares
/// 4. completes the queued withdrawal as tokens
// function testFuzz_deposit_delegate_queue_completeAsTokens(uint24 _random) public {
// // When new Users are created, they will choose a random configuration from these params:
// _configRand({
// _randomSeed: _random,
// _assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL,
// _userTypes: DEFAULT | ALT_METHODS
// });

// /// 0. Create an operator and a staker with:
// // - some nonzero underlying token balances
// // - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager)
// //
// // ... check that the staker has no delegatable shares and isn't currently delegated
// (
// User staker,
// IStrategy[] memory strategies,
// uint[] memory tokenBalances
// ) = _newRandomStaker();
// (User operator, ,) = _newRandomOperator();
// // Upgrade contracts if forkType is not local
// _upgradeEigenLayerContracts();

// uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances);

// assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing");
// assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated");

// // 1. Deposit Into Strategies
// staker.depositIntoEigenlayer(strategies, tokenBalances);
// check_Deposit_State(staker, strategies, shares);

// // 2. Delegate to an operator
// staker.delegateTo(operator);
// check_Delegation_State(staker, operator, strategies, shares);

// // 3. Queue Withdrawals
// IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares);
// bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
// check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots);

// // 4. Complete withdrawal
// // Fast forward to when we can complete the withdrawal
// _rollBlocksForCompleteWithdrawals();

// for (uint256 i = 0; i < withdrawals.length; i++) {
// uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares);
// IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]);
// check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens);
// }

// // Check final state:
// assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator");
// assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares");
// assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token balances");
// assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending");
// }
function testFuzz_deposit_delegate_queue_completeAsTokens(uint24 _random) public {
// When new Users are created, they will choose a random configuration from these params:
_configRand({
_randomSeed: _random,
_assetTypes: HOLDS_LST | HOLDS_ETH | HOLDS_ALL,
_userTypes: DEFAULT | ALT_METHODS
});

/// 0. Create an operator and a staker with:
// - some nonzero underlying token balances
// - corresponding to a random subset of valid strategies (StrategyManager and/or EigenPodManager)
//
// ... check that the staker has no delegatable shares and isn't currently delegated
(
User staker,
IStrategy[] memory strategies,
uint[] memory tokenBalances
) = _newRandomStaker();
(User operator, ,) = _newRandomOperator();
// Upgrade contracts if forkType is not local
_upgradeEigenLayerContracts();

uint[] memory shares = _calculateExpectedShares(strategies, tokenBalances);

assert_HasNoDelegatableShares(staker, "staker should not have delegatable shares before depositing");
assertFalse(delegationManager.isDelegated(address(staker)), "staker should not be delegated");

// 1. Deposit Into Strategies
staker.depositIntoEigenlayer(strategies, tokenBalances);
check_Deposit_State(staker, strategies, shares);

// 2. Delegate to an operator
staker.delegateTo(operator);
check_Delegation_State(staker, operator, strategies, shares);

// 3. Queue Withdrawals
IDelegationManagerTypes.Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares);
bytes32[] memory withdrawalRoots = _getWithdrawalHashes(withdrawals);
check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawals, withdrawalRoots);

// 4. Complete withdrawal
// Fast forward to when we can complete the withdrawal
_rollBlocksForCompleteWithdrawals();

for (uint256 i = 0; i < withdrawals.length; i++) {
uint256[] memory expectedTokens = _calculateExpectedTokens(withdrawals[i].strategies, withdrawals[i].scaledShares);
IERC20[] memory tokens = staker.completeWithdrawalAsTokens(withdrawals[i]);
check_Withdrawal_AsTokens_State(staker, operator, withdrawals[i], strategies, shares, tokens, expectedTokens);
}

// Check final state:
assertEq(address(operator), delegationManager.delegatedTo(address(staker)), "staker should still be delegated to operator");
assert_HasNoDelegatableShares(staker, "staker should have withdrawn all shares");
assert_HasUnderlyingTokenBalances(staker, strategies, tokenBalances, "staker should once again have original token balances");
assert_NoWithdrawalsPending(withdrawalRoots, "all withdrawals should be removed from pending");
}

/// Generates a random staker and operator. The staker:
/// 1. deposits all assets into strategies
Expand Down
23 changes: 23 additions & 0 deletions src/test/unit/EigenPodManagerUnit.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,12 @@ contract EigenPodManagerUnitTests_WithdrawSharesAsTokensTests is EigenPodManager
emit PodSharesUpdated(defaultStaker, 100e18);
cheats.expectEmit(true, true, true, true);
emit NewTotalShares(defaultStaker, 0);
// Expect call to EigenPod for the withdrawal
cheats.expectCall(
address(defaultPod),
abi.encodeWithSelector(IEigenPod.withdrawRestakedBeaconChainETH.selector, defaultStaker, 1e18),
1
);
eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw);

// Check storage update
Expand All @@ -370,6 +376,17 @@ contract EigenPodManagerUnitTests_WithdrawSharesAsTokensTests is EigenPodManager

// Withdraw shares
cheats.prank(address(delegationManagerMock));
cheats.expectEmit(true, true, true, true);
emit PodSharesUpdated(defaultStaker, 50e18);
cheats.expectEmit(true, true, true, true);
emit NewTotalShares(defaultStaker, -50e18);
// Assert that no call is made by passing in zero for the count
bytes memory emptyBytes;
cheats.expectCall(
address(defaultPod),
emptyBytes, // Cheatcode checks a partial match starting at the first byte of the calldata
0
);
eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw);

// Check storage update
Expand All @@ -387,6 +404,12 @@ contract EigenPodManagerUnitTests_WithdrawSharesAsTokensTests is EigenPodManager

// Withdraw shares
cheats.prank(address(delegationManagerMock));
// Expect call to EigenPod for the withdrawal
cheats.expectCall(
address(defaultPod),
abi.encodeWithSelector(IEigenPod.withdrawRestakedBeaconChainETH.selector, defaultStaker, sharesToWithdraw),
1
);
eigenPodManager.withdrawSharesAsTokens(defaultStaker, beaconChainETHStrategy, IERC20(address(0)), sharesToWithdraw);

// Check storage remains the same
Expand Down
Loading