Skip to content

Commit af27485

Browse files
committed
Adds ynLSD scneario test with invariants for rebasing balance transfer bug
1 parent a95197c commit af27485

File tree

4 files changed

+571
-0
lines changed

4 files changed

+571
-0
lines changed

test/foundry/scenarios/Invariants.sol

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: BSD 3-Clause License
2+
pragma solidity ^0.8.24;
3+
4+
library Invariants {
5+
6+
/// Share and Assets Invariants
7+
function shareMintIntegrity (uint256 totalSupply, uint256 previousTotal, uint256 newShares) public pure {
8+
require(totalSupply == previousTotal + newShares,
9+
"Invariant: Total supply should be equal to previous total plus new shares"
10+
);
11+
}
12+
13+
function totalDepositIntegrity (uint256 totalDeposited, uint256 previousTotal, uint256 newDeposited) public pure {
14+
require(totalDeposited == previousTotal + newDeposited,
15+
"Invariant: Total deposited should be equal to previous total plus new deposited"
16+
);
17+
}
18+
19+
function userSharesIntegrity (uint256 userShares, uint256 previousShares, uint256 newShares) public pure {
20+
require(userShares == previousShares + newShares,
21+
"Invariant: User shares should be equal to previous shares plus new shares"
22+
);
23+
}
24+
25+
function totalAssetsIntegrity (uint256 totalAssets, uint256 previousAssets, uint256 newAssets) public pure {
26+
require(totalAssets == previousAssets + newAssets,
27+
"Invariant: Total assets should be equal to previous assets plus new assets"
28+
);
29+
}
30+
31+
function totalBalanceIntegrity (uint256 balance, uint256 previousBalance, uint256 newBalance) public pure {
32+
require(balance == previousBalance + newBalance,
33+
"Invariant: Total balance should be equal to previous balance plus new balance"
34+
);
35+
}
36+
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
2+
## Usage Scenario Tests
3+
4+
These tests are designed to verify the correct behavior of the ynETH contract in various usage scenarios.
5+
6+
**Scenario 1:** Successful ETH Deposit and Share Minting
7+
8+
Objective: Test that a user can deposit ETH and receive the correct amount of shares in return.
9+
10+
**Scenario 2:** Deposit Paused
11+
12+
Objective: Ensure that deposits are correctly paused and resumed, preventing or allowing ETH deposits accordingly.
13+
14+
**Scenario 3:** Deposit and Withdraw ETH to Staking Nodes Manager
15+
16+
Objective: Test the end-to-end flow of depositing ETH to an eigenpod, and withdrawing ETH to the staking nodes manager.
17+
18+
**Scenario 4:** Share Accouting and Yield Accrual
19+
20+
Objective: Verify that the share price correctly increases after the contract earns yield from consensus and execution rewards.
21+
22+
**Scenario 5:** Emergency Withdrawal of ETH
23+
24+
Objective: Test ability to withdraw all assets from eigenpods.
25+
26+
**Scenario 6:** Validator and Staking Node Administration
27+
28+
Objective: Test the ynETH's ability to update the address of the Staking Nodes Manager.
29+
30+
**Scenario 7:** Accrual and Distribution of Fees
31+
32+
Objective: Ensure that ynETH correctly accrues and distributes fees from yield earnings from execution and consensus rewards.
33+
34+
**Scenario 8:** Staking Rewards Distribution
35+
36+
Objective: Test the distribution of staking rewards to a multisig.
37+
38+
**Scenario 9:** EigenLayer Accounting and Distribution
39+
40+
Objective: Verify that ynETH correctly accounts for fund balances and withdrawals from EigenLayer.
41+
42+
## Invariant Scenarios
43+
44+
The following invariant scenarios are designed to verify the correct behavior of the ynETH contract in various usage scenarios. These scenarios should never fail, and if they do, it indicates there is an implementation issue somewhere in the protocol.
45+
46+
**Total Assets Consistency**
47+
48+
```solidity
49+
assert(totalDepositedInPool + totalDepositedInValidators() == totalAssets());
50+
```
51+
52+
**Exchange Rate Integrity**
53+
54+
```solidity
55+
assert(exchangeAdjustmentRate >= 0 && exchangeAdjustmentRate <= BASIS_POINTS_DENOMINATOR);
56+
```
57+
**Share Minting Consistency**
58+
59+
```solidity
60+
assert(totalSupply() == previousTotalSupply + mintedShares)
61+
```
62+
63+
**User Shares Integrity**
64+
65+
```solidity
66+
assert(balanceOf(user) == previousUserSharesBalance + newUserSharesBalance);
67+
```
68+
69+
**Total Deposited Integrity**
70+
71+
```solidity
72+
assert(totalDepositedInValidators() == previousTotalDeposited + newDeposit);
73+
```
74+
75+
**Total Assets Integrity**
76+
77+
```solidity
78+
assert(totalAssets() == previousTotalAssets + newDeposit);
79+
```
80+
81+
**Total Balance Integrity**
82+
83+
```solidity
84+
assert(address(yneth).balance() == previousBalance + newBalance);
85+
```
86+
87+
**Deposit and Withdrawal Symmetry**
88+
89+
```solidity
90+
uint256 sharesMinted = depositETH(amount);
91+
assert(sharesMinted == previewDeposit(amount));
92+
```
93+
94+
**Rewards Increase Total Assets**
95+
96+
```solidity
97+
uint256 previousTotalAssets = totalAssets();
98+
// Simulate receiving rewards
99+
receiveRewards{value: rewardAmount}();
100+
assert(totalAssets() == previousTotalAssets + rewardAmount);
101+
```
102+
103+
**Authorized Access Control**
104+
105+
```solidity
106+
// For any role-restricted operation
107+
assert(msg.sender == authorizedRoleAddress);
108+
```

0 commit comments

Comments
 (0)