Skip to content

Commit

Permalink
feat: yneigen scenario tests
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyonline committed Jul 31, 2024
1 parent b24a256 commit e41c794
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 223 deletions.
1 change: 1 addition & 0 deletions test/integration/ynEIGEN/ynEigenIntegrationBaseTest.sol
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {AssetRegistry} from "src/ynEIGEN/AssetRegistry.sol";
import {EigenStrategyManager} from "src/ynEIGEN/EigenStrategyManager.sol";
import {ynEigen} from "src/ynEIGEN/ynEigen.sol";
import {ITokenStakingNodesManager} from "src/interfaces/ITokenStakingNodesManager.sol";
import {ITokenStakingNode} from "src/interfaces/ITokenStakingNode.sol";
import {ynEigenDepositAdapter} from "src/ynEIGEN/ynEigenDepositAdapter.sol";
import {IwstETH} from "src/external/lido/IwstETH.sol";
import {IERC4626} from "lib/openzeppelin-contracts/contracts/interfaces/IERC4626.sol";
Expand Down
158 changes: 1 addition & 157 deletions test/scenarios/ynETH.spec.sol
Original file line number Diff line number Diff line change
Expand Up @@ -315,160 +315,4 @@ contract YnETHScenarioTest8 is IntegrationBaseTest, YnETHScenarioTest3 {
// until processed rewards should be in the consensusLayerReceiver
assertEq(ynethBalance, 0, "yneth.balance != 0");
}
}

contract YnETHScenarioTest10 is IntegrationBaseTest, YnETHScenarioTest3 {

/**
Scenario 10: Self-Destruct ETH Transfer Attack
Objective: Ensure the system is not vulnerable to a self-destruct attack.
*/

function setUp() public override {
super.setUp();
// Additional setup can be added here if needed
vm.recordLogs();
}

function test_ynETH_Scenario_9_Self_Destruct_Attack() public {

uint256 previousTotalDeposited = yneth.totalDepositedInPool();
uint256 previousTotalShares = yneth.totalSupply();


// Deposit 32 ETH to ynETH and create a Staking Node with a Validator
(IStakingNode stakingNode,) = depositEth_and_createValidator();

// Amount of ether to send via self-destruct
uint256 amountToSendViaSelfDestruct = 1 ether;

// Ensure the test contract has enough ether to send, user1 comes from Test3
vm.deal(user1, amountToSendViaSelfDestruct);

// Address to send ether to - for example, the stakingNode or another address
address payable target = payable(address(stakingNode)); // or any other target address

// Create and send ether via self-destruct
// The SelfDestructSender contract is created with the amountToSend and immediately self-destructs,
// sending its balance to the target address.
address(new SelfDestructSender{value: amountToSendViaSelfDestruct}(target));

log_balances(stakingNode);

assertEq(address(yneth).balance, 0, "yneth.balance != 0");
assertEq(address(stakingNode).balance, 1 ether, "stakingNode.balance != 1 ether");
assertEq(address(consensusLayerReceiver).balance, 0, "consensusLayerReceiver.balance != 0");
assertEq(address(executionLayerReceiver).balance, 0, "executionLayerReceiver.balance != 0");

vm.startPrank(actors.ops.STAKING_NODES_OPERATOR);
uint256 rewardsSentToEigenPod = send_eth_rewards_to_eigenpod(stakingNode);
stakingNode.processDelayedWithdrawals();
vm.stopPrank();

log_balances(stakingNode);

// funds are deposited in the validators
assertEq(address(yneth).balance, 0, "yneth.balance != 0");

// funds have been collected from the StakingNode
assertEq(address(stakingNode).balance, 0, "stakingNode.balance != 0");
assertEq(
address(consensusLayerReceiver).balance,
rewardsSentToEigenPod + amountToSendViaSelfDestruct,
"consensusLayerReceiver.balance != 1 ether + 1 wei"
);
assertEq(address(executionLayerReceiver).balance, 0, "executionLayerReceiver.balance != 0");

uint256 userAmount = 32 ether;
uint256 userShares = yneth.balanceOf(user1);

runInvariants(
user1,
previousTotalDeposited,
previousTotalShares,
userAmount,
userShares
);
}

function send_eth_rewards_to_eigenpod(IStakingNode stakingNode) public returns (uint256) {

// send concensus rewards to eigen pod
uint256 amount = 32 ether + 1 wei;
IEigenPod eigenPod = IEigenPod(stakingNode.eigenPod());
uint256 initialPodBalance = address(eigenPod).balance;

vm.deal(actors.ops.STAKING_NODES_OPERATOR, 40 ether);
(bool success,) = payable(address(eigenPod)).call{value: amount}("");
require(success, "Failed to send rewards to EigenPod");

assertEq(address(eigenPod).balance, initialPodBalance + amount, "eigenPod.balance != initialPodBalance + amount");

// trigger withdraw before restaking succesfully
stakingNode.withdrawNonBeaconChainETHBalanceWei();

// There should be a delayedWithdraw on the DelayedWithdrawalRouter
IDelayedWithdrawalRouter withdrawalRouter = IDelayedWithdrawalRouter(chainAddresses.eigenlayer.DELAYED_WITHDRAWAL_ROUTER_ADDRESS);
IDelayedWithdrawalRouter.DelayedWithdrawal[] memory delayedWithdrawals = withdrawalRouter.getUserDelayedWithdrawals(address(stakingNode));
assertEq(delayedWithdrawals.length, 1);
assertEq(delayedWithdrawals[0].amount, amount);

// Because of the delay, the delayedWithdrawal should not be claimable yet
IDelayedWithdrawalRouter.DelayedWithdrawal[] memory claimableDelayedWithdrawals = withdrawalRouter.getClaimableUserDelayedWithdrawals(address(stakingNode));
assertEq(claimableDelayedWithdrawals.length, 0, "claimableDelayedWithdrawals.length != 0");

// Move ahead in time to make the delayedWithdrawal claimable
vm.roll(block.number + withdrawalRouter.withdrawalDelayBlocks() + 1);
IDelayedWithdrawalRouter.DelayedWithdrawal[] memory claimableDelayedWithdrawalsWarp = withdrawalRouter.getClaimableUserDelayedWithdrawals(address(stakingNode));
assertEq(claimableDelayedWithdrawalsWarp.length, 1, "claimableDelayedWithdrawalsWarp.length != 1");
assertEq(claimableDelayedWithdrawalsWarp[0].amount, amount, "claimableDelayedWithdrawalsWarp[0].amount != 3 ether");

withdrawalRouter.claimDelayedWithdrawals(address(stakingNode), type(uint256).max);

return amount;
}

function log_balances (IStakingNode stakingNode) public {
emit LogUint("yneth.balance", address(yneth).balance);
emit LogUint("stakingNode.balance", address(stakingNode).balance);
emit LogUint("consensusReciever.balance", address(consensusLayerReceiver).balance);
emit LogUint("executionReciever.balance", address(executionLayerReceiver).balance);
emit LogUint("eigenPod.balance", address(IEigenPod(stakingNode.eigenPod())).balance);
}

function runInvariants(address user, uint256 previousTotalDeposited, uint256 previousTotalShares, uint256 userAmount, uint256 userShares) public {

uint256 totalDeposited = 0;
Vm.Log[] memory logs = vm.getRecordedLogs();

for (uint i = 0; i < logs.length; i++) {
Vm.Log memory log = logs[i];
if (log.topics[0] ==
keccak256("Deposit(address,address,uint256,uint256,uint256)")) {
(uint256 assets,) = abi.decode(log.data, (uint256, uint256));
totalDeposited += assets;
}
}
Invariants.totalDepositIntegrity(totalDeposited, previousTotalDeposited, userAmount);

Invariants.totalAssetsIntegrity(yneth.totalAssets(), previousTotalDeposited, userAmount);

Invariants.shareMintIntegrity(yneth.totalSupply(), previousTotalShares, userShares);

Invariants.userSharesIntegrity(yneth.balanceOf(user), 0, userShares);
}

/*
*/
}

// Add this contract definition outside of your existing contract definitions
contract SelfDestructSender {
constructor(address payable _target) payable {
selfdestruct(_target);
}
}



}
Loading

0 comments on commit e41c794

Please sign in to comment.