@@ -15,7 +15,6 @@ import {TestLSDStakingNodeV2} from "test/foundry/mocks/TestLSDStakingNodeV2.sol"
15
15
import {TestYnLSDV2} from "test/foundry/mocks/TestYnLSDV2.sol " ;
16
16
import {ynBase} from "src/ynBase.sol " ;
17
17
18
-
19
18
contract ynLSDAssetTest is IntegrationBaseTest {
20
19
function testDepositSTETHFailingWhenStrategyIsPaused () public {
21
20
IERC20 asset = IERC20 (chainAddresses.lsd.STETH_ADDRESS);
@@ -38,7 +37,7 @@ contract ynLSDAssetTest is IntegrationBaseTest {
38
37
assets[0 ] = asset;
39
38
amounts[0 ] = amount;
40
39
41
- vm.expectRevert (bytes ("BALANCE_EXCEEDED " ));
40
+ vm.expectRevert (bytes ("Pausable: index is paused " ));
42
41
vm.prank (actors.LSD_RESTAKING_MANAGER);
43
42
lsdStakingNode.depositAssetsToEigenlayer (assets, amounts);
44
43
}
@@ -47,6 +46,9 @@ contract ynLSDAssetTest is IntegrationBaseTest {
47
46
IERC20 stETH = IERC20 (chainAddresses.lsd.STETH_ADDRESS);
48
47
uint256 amount = 32 ether ;
49
48
49
+ uint256 initialSupply = ynlsd.totalSupply ();
50
+ uint256 initialTotalAssets = ynlsd.totalAssets ();
51
+
50
52
// Obtain STETH
51
53
(bool success , ) = chainAddresses.lsd.STETH_ADDRESS.call {value: amount + 1 }("" );
52
54
require (success, "ETH transfer failed " );
@@ -58,15 +60,18 @@ contract ynLSDAssetTest is IntegrationBaseTest {
58
60
stETH.approve (address (ynlsd), 32 ether);
59
61
ynlsd.deposit (stETH, depositAmount, address (this ));
60
62
61
- assertEq (ynlsd.balanceOf (address (this )), ynlsd.totalSupply (), "ynlsd balance does not match total supply " );
62
- assertTrue ((depositAmount - ynlsd.totalAssets ()) < 1e18 , "Total assets do not match user deposits " );
63
+ assertEq (ynlsd.balanceOf (address (this )), ynlsd.totalSupply () - initialSupply , "ynlsd balance does not match total supply " );
64
+ assertTrue ((depositAmount - ( ynlsd.totalAssets () - initialTotalAssets )) < 1e18 , "Total assets do not match user deposits " );
63
65
assertTrue ((depositAmount - ynlsd.balanceOf (address (this ))) < 1e18 , "Invalid ynLSD Balance " );
64
66
}
65
67
66
68
function testDepositSTETHSuccessWithMultipleDeposits () public {
67
69
IERC20 stETH = IERC20 (chainAddresses.lsd.STETH_ADDRESS);
68
70
uint256 amount = 32 ether ;
69
71
72
+ uint256 initialSupply = ynlsd.totalSupply ();
73
+ uint256 initialTotalAssets = ynlsd.totalAssets ();
74
+
70
75
// Obtain STETH
71
76
(bool success , ) = chainAddresses.lsd.STETH_ADDRESS.call {value: amount + 1 }("" );
72
77
require (success, "ETH transfer failed " );
@@ -84,8 +89,8 @@ contract ynLSDAssetTest is IntegrationBaseTest {
84
89
85
90
uint256 totalDeposit = depositAmountOne + depositAmountTwo + depositAmountThree;
86
91
87
- assertEq (ynlsd.balanceOf (address (this )), ynlsd.totalSupply (), "ynlsd balance does not match total supply " );
88
- assertTrue ((totalDeposit - ynlsd.totalAssets ()) < 1e18 , "Total assets do not match user deposits " );
92
+ assertEq (ynlsd.balanceOf (address (this )), ynlsd.totalSupply () - initialSupply , "ynlsd balance does not match total supply " );
93
+ assertTrue ((totalDeposit - ( ynlsd.totalAssets () - initialTotalAssets )) < 1e18 , "Total assets do not match user deposits " );
89
94
assertTrue (totalDeposit - ynlsd.balanceOf (address (this )) < 1e18 , "Invalid ynLSD Balance " );
90
95
}
91
96
@@ -114,17 +119,29 @@ contract ynLSDAssetTest is IntegrationBaseTest {
114
119
ynlsd.convertToShares (asset, amount);
115
120
}
116
121
122
+ function testConvertToSharesBootstrapStrategy () public {
123
+ vm.prank (actors.STAKING_NODE_CREATOR);
124
+ ynlsd.createLSDStakingNode ();
125
+ uint256 [] memory totalAssets = ynlsd.getTotalAssets ();
126
+ ynlsd.nodes (0 );
127
+
128
+ uint256 bootstrapAmountUnits = ynlsd.BOOTSTRAP_AMOUNT_UNITS () * 1e18 - 1 ;
129
+ assertTrue (compareWithThreshold (totalAssets[0 ], bootstrapAmountUnits, 1 ), "Total assets should be equal to bootstrap amount " );
130
+ }
131
+
117
132
function testConvertToSharesZeroStrategy () public {
118
133
vm.prank (actors.STAKING_NODE_CREATOR);
119
134
ynlsd.createLSDStakingNode ();
120
135
uint256 [] memory totalAssets = ynlsd.getTotalAssets ();
121
136
ynlsd.nodes (0 );
122
- assertEq (totalAssets[0 ], 0 , "Total assets should be zero " );
137
+
138
+ assertEq (totalAssets[1 ], 0 , "Total assets should be equal to bootstrap 0 " );
123
139
}
124
140
125
141
function testGetTotalAssets () public {
142
+ uint256 totalAssetsInETH = ynlsd.convertToETH (ynlsd.assets (0 ), ynlsd.BOOTSTRAP_AMOUNT_UNITS () * 1e18 - 1 );
126
143
uint256 totalAssets = ynlsd.totalAssets ();
127
- assertEq ( totalAssets, 0 , "Total assets should be zero " );
144
+ assertTrue ( compareWithThreshold ( totalAssets, totalAssetsInETH, 1 ), "Total assets should be equal to bootstrap amount converted to its ETH value " );
128
145
}
129
146
130
147
function testLSDWrongStrategy () public {
@@ -142,8 +159,8 @@ contract ynLSDAssetTest is IntegrationBaseTest {
142
159
uint256 shares = ynlsd.convertToShares (asset, amount);
143
160
(, int256 price , , uint256 timeStamp , ) = assetPriceFeed.latestRoundData ();
144
161
145
- assertEq (ynlsd.totalAssets (), 0 );
146
- assertEq (ynlsd.totalSupply (), 0 );
162
+ // assertEq(ynlsd.totalAssets(), 0);
163
+ // assertEq(ynlsd.totalSupply(), 0);
147
164
148
165
assertEq (timeStamp > 0 , true , "Zero timestamp " );
149
166
assertEq (price > 0 , true , "Zero price " );
@@ -164,6 +181,8 @@ contract ynLSDAssetTest is IntegrationBaseTest {
164
181
vm.startPrank (unpauser);
165
182
pausableStrategyManager.unpause (0 );
166
183
vm.stopPrank ();
184
+
185
+ uint256 totalAssetsBeforeDeposit = ynlsd.totalAssets ();
167
186
168
187
// Obtain STETH
169
188
(bool success , ) = chainAddresses.lsd.STETH_ADDRESS.call {value: amount + 1 }("" );
@@ -173,6 +192,7 @@ contract ynLSDAssetTest is IntegrationBaseTest {
173
192
asset.approve (address (ynlsd), amount);
174
193
ynlsd.deposit (asset, amount, address (this ));
175
194
195
+
176
196
{
177
197
IERC20 [] memory assets = new IERC20 [](1 );
178
198
uint256 [] memory amounts = new uint256 [](1 );
@@ -194,7 +214,7 @@ contract ynLSDAssetTest is IntegrationBaseTest {
194
214
uint256 expectedBalance = balanceInStrategyForNode * oraclePrice / 1e18 ;
195
215
196
216
// Assert that totalAssets reflects the deposit
197
- assertEq (totalAssetsAfterDeposit, expectedBalance, "Total assets do not reflect the deposit " );
217
+ assertEq (totalAssetsAfterDeposit - totalAssetsBeforeDeposit , expectedBalance, "Total assets do not reflect the deposit " );
198
218
}
199
219
200
220
function testPreviewDeposit () public {
@@ -527,4 +547,54 @@ contract ynLSDTransferPauseTest is IntegrationBaseTest {
527
547
assertFalse (isFirstAddressWhitelisted, "First new whitelist address was not removed " );
528
548
assertFalse (isSecondAddressWhitelisted, "Second new whitelist address was not removed " );
529
549
}
550
+ }
551
+
552
+
553
+ contract ynLSDDonationsTest is IntegrationBaseTest {
554
+
555
+ function testYnLSDdonationToZeroShareAttackResistance () public {
556
+
557
+ uint INITIAL_AMOUNT = 10_000 ether ;
558
+
559
+ address _alice = makeAddr ("Alice " );
560
+ address _bob = makeAddr ("Bob " );
561
+
562
+ IERC20 assetToken = IERC20 (chainAddresses.lsd.STETH_ADDRESS);
563
+
564
+ vm.deal (_alice, INITIAL_AMOUNT);
565
+ vm.deal (_bob, INITIAL_AMOUNT);
566
+
567
+
568
+ IERC20 steth = IERC20 (chainAddresses.lsd.STETH_ADDRESS);
569
+
570
+ // get stETH
571
+ vm.startPrank (_alice);
572
+ (bool success , ) = chainAddresses.lsd.STETH_ADDRESS.call {value: INITIAL_AMOUNT}("" );
573
+ require (success, "ETH transfer failed " );
574
+
575
+ steth.approve (address (ynlsd), type (uint256 ).max);
576
+
577
+ vm.startPrank (_bob);
578
+ (success, ) = chainAddresses.lsd.STETH_ADDRESS.call {value: INITIAL_AMOUNT}("" );
579
+ require (success, "ETH transfer failed " );
580
+
581
+ steth.approve (address (ynlsd), type (uint256 ).max);
582
+
583
+ // Front-running part
584
+ uint256 bobDepositAmount = INITIAL_AMOUNT / 2 ;
585
+ // Alice knows that Bob is about to deposit INITIAL_AMOUNT*0.5 ATK to the Vault by observing the mempool
586
+ vm.startPrank (_alice);
587
+ uint256 aliceDepositAmount = 1 ;
588
+ uint256 aliceShares = ynlsd.deposit (assetToken, aliceDepositAmount, _alice);
589
+ assertEq (aliceShares, 0 ); // Since there are boostrap funds, this has no effect
590
+ // Try to inflate shares value
591
+ assetToken.transfer (address (ynlsd), bobDepositAmount);
592
+ vm.stopPrank ();
593
+
594
+ // Check that Bob did not get 0 share when he deposits
595
+ vm.prank (_bob);
596
+ uint256 bobShares = ynlsd.deposit (assetToken, bobDepositAmount, _bob);
597
+
598
+ assertGt (bobShares, 1 wei, "Bob's shares should be greater than 1 wei " );
599
+ }
530
600
}
0 commit comments