Skip to content

Commit 2c1d767

Browse files
committed
fix audit issues audit-6.3 audit-6.5 by removing exchangeAdjustmentRate
1 parent d8a5c6e commit 2c1d767

File tree

10 files changed

+22
-148
lines changed

10 files changed

+22
-148
lines changed

scripts/forge/BaseScript.s.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ abstract contract BaseScript is Script, Utils {
103103
PAUSE_ADMIN: vm.envAddress("PAUSER_ADDRESS"),
104104
LSD_RESTAKING_MANAGER: vm.envAddress("LSD_RESTAKING_MANAGER_ADDRESS"),
105105
STAKING_NODE_CREATOR: vm.envAddress("LSD_STAKING_NODE_CREATOR_ADDRESS"),
106-
ORACLE_MANAGER: vm.envAddress("YIELDNEST_ORACLE_MANAGER_ADDRESS")
106+
ORACLE_MANAGER: vm.envAddress("YIELDNEST_ORACLE_MANAGER_ADDRESS"),
107+
DEPOSIT_BOOTSTRAPER: vm.envAddress("DEPOSIT_BOOTSTRAPER_ADDRESS")
107108
});
108109
}
109110

scripts/forge/DeployYieldNest.s.sol

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ contract DeployYieldNest is BaseScript {
4444
IDepositContract public depositContract;
4545
IWETH public weth;
4646

47-
uint startingExchangeAdjustmentRate;
48-
4947
bytes ZERO_PUBLIC_KEY = hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
5048
bytes ONE_PUBLIC_KEY = hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001";
5149
bytes TWO_PUBLIC_KEY = hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002";
@@ -72,9 +70,6 @@ contract DeployYieldNest is BaseScript {
7270

7371
feeReceiver = payable(_broadcaster); // Casting the default signer address to payable
7472

75-
76-
startingExchangeAdjustmentRate = 4;
77-
7873
ContractAddresses contractAddresses = new ContractAddresses();
7974
ContractAddresses.ChainAddresses memory chainAddresses = contractAddresses.getChainAddresses(block.chainid);
8075
eigenPodManager = IEigenPodManager(chainAddresses.eigenlayer.EIGENPOD_MANAGER_ADDRESS);
@@ -120,7 +115,6 @@ contract DeployYieldNest is BaseScript {
120115
pauser: actors.PAUSE_ADMIN,
121116
stakingNodesManager: IStakingNodesManager(address(stakingNodesManager)),
122117
rewardsDistributor: IRewardsDistributor(address(rewardsDistributor)),
123-
exchangeAdjustmentRate: startingExchangeAdjustmentRate,
124118
pauseWhitelist: pauseWhitelist
125119
});
126120
yneth.initialize(ynethInit);

scripts/forge/DeployYnLSD.s.sol

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@ contract DeployYnLSD is BaseScript {
3838
// solhint-disable-next-line no-console
3939
console.log("Current Chain ID:", block.chainid);
4040

41-
uint256 startingExchangeAdjustmentRate = 0;
42-
4341
ContractAddresses contractAddresses = new ContractAddresses();
4442
ContractAddresses.ChainAddresses memory chainAddresses = contractAddresses.getChainAddresses(block.chainid);
4543
eigenPodManager = IEigenPodManager(chainAddresses.eigenlayer.EIGENPOD_MANAGER_ADDRESS);
@@ -80,7 +78,6 @@ contract DeployYnLSD is BaseScript {
8078
strategyManager: strategyManager,
8179
delegationManager: delegationManager,
8280
oracle: yieldNestOracle,
83-
exchangeAdjustmentRate: startingExchangeAdjustmentRate,
8481
maxNodeCount: 10,
8582
admin: actors.ADMIN,
8683
pauser: actors.PAUSE_ADMIN,

src/interfaces/IStakingNode.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ interface IStakingEvents {
2323
event Staked(address indexed staker, uint256 ethAmount, uint256 ynETHAmount);
2424
event DepositETHPausedUpdated(bool isPaused);
2525
event Deposit(address indexed sender, address indexed receiver, uint256 assets, uint256 shares);
26-
event ExchangeAdjustmentRateUpdated(uint256 newRate);
2726
}
2827

2928
interface IStakingNode {

src/ynETH.sol

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
2323
error Paused();
2424
error ValueOutOfBounds(uint256 value);
2525
error ZeroAddress();
26-
error ExchangeAdjustmentRateOutOfBounds(uint256 exchangeAdjustmentRate);
2726
error ZeroETH();
2827
error NoDirectETHDeposit();
2928
error CallerNotStakingNodeManager(address expected, address provided);
@@ -38,9 +37,6 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
3837
IRewardsDistributor public rewardsDistributor;
3938
bool public depositsPaused;
4039

41-
/// @dev The value is in basis points (1/10000).
42-
uint256 public exchangeAdjustmentRate;
43-
4440
uint256 public totalDepositedInPool;
4541

4642
//--------------------------------------------------------------------------------------
@@ -53,7 +49,6 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
5349
address pauser;
5450
IStakingNodesManager stakingNodesManager;
5551
IRewardsDistributor rewardsDistributor;
56-
uint256 exchangeAdjustmentRate;
5752
address[] pauseWhitelist;
5853
}
5954

@@ -80,11 +75,6 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
8075
stakingNodesManager = init.stakingNodesManager;
8176
rewardsDistributor = init.rewardsDistributor;
8277

83-
if (init.exchangeAdjustmentRate > BASIS_POINTS_DENOMINATOR) {
84-
revert ExchangeAdjustmentRateOutOfBounds(init.exchangeAdjustmentRate);
85-
}
86-
exchangeAdjustmentRate = init.exchangeAdjustmentRate;
87-
8878
_setTransfersPaused(true); // transfers are initially paused
8979
_updatePauseWhitelist(init.pauseWhitelist, true);
9080
}
@@ -130,16 +120,13 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
130120
if (totalSupply() == 0) {
131121
return ethAmount;
132122
}
133-
134-
// deltaynETH = (1 - exchangeAdjustmentRate) * (ynETHSupply / totalControlled) * ethAmount
135-
// If `(1 - exchangeAdjustmentRate) * ethAmount * ynETHSupply < totalControlled` this will be 0.
136123

137-
// Can only happen in bootstrap phase if `totalControlled` and `ynETHSupply` could be manipulated
138-
// independently. That should not be possible.
124+
125+
// deltaynETH = (ynETHSupply / totalControlled) * ethAmount
139126
return Math.mulDiv(
140127
ethAmount,
141-
totalSupply() * uint256(BASIS_POINTS_DENOMINATOR - exchangeAdjustmentRate),
142-
totalAssets() * uint256(BASIS_POINTS_DENOMINATOR),
128+
totalSupply(),
129+
totalAssets(),
143130
rounding
144131
);
145132
}
@@ -220,18 +207,6 @@ contract ynETH is IynETH, ynBase, IStakingEvents {
220207
emit DepositETHPausedUpdated(depositsPaused);
221208
}
222209

223-
/// @notice Sets the exchange adjustment rate.
224-
/// @dev Can only be called by the admin..
225-
/// Reverts if the new rate exceeds the basis points denominator.
226-
/// @param newRate The new exchange adjustment rate to be set.
227-
function setExchangeAdjustmentRate(uint256 newRate) external onlyRole(DEFAULT_ADMIN_ROLE) {
228-
if (newRate > BASIS_POINTS_DENOMINATOR) {
229-
revert ValueOutOfBounds(newRate);
230-
}
231-
exchangeAdjustmentRate = newRate;
232-
emit ExchangeAdjustmentRateUpdated(newRate);
233-
}
234-
235210
//--------------------------------------------------------------------------------------
236211
//---------------------------------- MODIFIERS ---------------------------------------
237212
//--------------------------------------------------------------------------------------

src/ynLSD.sol

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
3232

3333
error UnsupportedAsset(IERC20 asset);
3434
error ZeroAmount();
35-
error ExchangeAdjustmentRateOutOfBounds(uint256 exchangeAdjustmentRate);
3635
error ZeroAddress();
3736
error BeaconImplementationAlreadyExists();
3837
error NoBeaconImplementationExists();
@@ -64,8 +63,6 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
6463

6564
/// @notice List of supported ERC20 asset contracts.
6665
IERC20[] public assets;
67-
68-
uint256 public exchangeAdjustmentRate;
6966

7067
/**
7168
* @notice Array of LSD Staking Node contracts.
@@ -89,7 +86,6 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
8986
IStrategyManager strategyManager;
9087
IDelegationManager delegationManager;
9188
YieldNestOracle oracle;
92-
uint256 exchangeAdjustmentRate;
9389
uint256 maxNodeCount;
9490
address admin;
9591
address pauser;
@@ -130,11 +126,6 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
130126
strategyManager = init.strategyManager;
131127
delegationManager = init.delegationManager;
132128
oracle = init.oracle;
133-
134-
if (init.exchangeAdjustmentRate > BASIS_POINTS_DENOMINATOR) {
135-
revert ExchangeAdjustmentRateOutOfBounds(init.exchangeAdjustmentRate);
136-
}
137-
exchangeAdjustmentRate = init.exchangeAdjustmentRate;
138129
maxNodeCount = init.maxNodeCount;
139130

140131
_setTransfersPaused(true); // transfers are initially paused
@@ -199,7 +190,7 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
199190
/**
200191
* @dev Converts an ETH amount to shares based on the current exchange rate and specified rounding method.
201192
* If it's the first stake (bootstrap phase), uses a 1:1 exchange rate. Otherwise, calculates shares based on
202-
* the formula: deltaynETH = (1 - exchangeAdjustmentRate) * (ynETHSupply / totalControlled) * ethAmount.
193+
* the formula: deltaynETH = (ynETHSupply / totalControlled) * ethAmount.
203194
* This calculation can result in 0 during the bootstrap phase if `totalControlled` and `ynETHSupply` could be
204195
* manipulated independently, which should not be possible.
205196
* @param ethAmount The amount of ETH to convert to shares.
@@ -213,15 +204,14 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
213204
return ethAmount;
214205
}
215206

216-
// deltaynETH = (1 - exchangeAdjustmentRate) * (ynETHSupply / totalControlled) * ethAmount
217-
// If `(1 - exchangeAdjustmentRate) * ethAmount * ynETHSupply < totalControlled` this will be 0.
207+
// deltaynETH = (ynETHSupply / totalControlled) * ethAmount
218208

219209
// Can only happen in bootstrap phase if `totalControlled` and `ynETHSupply` could be manipulated
220210
// independently. That should not be possible.
221211
return Math.mulDiv(
222212
ethAmount,
223-
totalSupply() * uint256(BASIS_POINTS_DENOMINATOR - exchangeAdjustmentRate),
224-
totalAssets() * uint256(BASIS_POINTS_DENOMINATOR),
213+
totalSupply(),
214+
totalAssets(),
225215
rounding
226216
);
227217
}
@@ -465,3 +455,4 @@ contract ynLSD is IynLSD, ynBase, ReentrancyGuardUpgradeable, IynLSDEvents {
465455
_;
466456
}
467457
}
458+

test/foundry/integration/IntegrationBaseTest.sol

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ contract IntegrationBaseTest is Test, Utils {
4141
bytes constant ZERO_SIGNATURE = hex"000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
4242
bytes32 constant ZERO_DEPOSIT_ROOT = bytes32(0);
4343

44-
uint256 startingExchangeAdjustmentRate = 4;
45-
4644
// Utils
4745
ContractAddresses public contractAddresses;
4846
ContractAddresses.ChainAddresses public chainAddresses;
@@ -165,7 +163,6 @@ contract IntegrationBaseTest is Test, Utils {
165163
pauser: actors.PAUSE_ADMIN,
166164
stakingNodesManager: IStakingNodesManager(address(stakingNodesManager)),
167165
rewardsDistributor: IRewardsDistributor(address(rewardsDistributor)),
168-
exchangeAdjustmentRate: startingExchangeAdjustmentRate,
169166
pauseWhitelist: pauseWhitelist
170167
});
171168

@@ -251,16 +248,13 @@ contract IntegrationBaseTest is Test, Utils {
251248
});
252249
yieldNestOracle.initialize(oracleInit);
253250

254-
uint startingExchangeAdjustmentRateForYnLSD = 0;
255-
256251
LSDStakingNode lsdStakingNodeImplementation = new LSDStakingNode();
257252
ynLSD.Init memory init = ynLSD.Init({
258253
assets: assets,
259254
strategies: strategies,
260255
strategyManager: strategyManager,
261256
delegationManager: delegationManager,
262257
oracle: yieldNestOracle,
263-
exchangeAdjustmentRate: startingExchangeAdjustmentRateForYnLSD,
264258
maxNodeCount: 10,
265259
admin: actors.ADMIN,
266260
stakingAdmin: actors.STAKING_ADMIN,

test/foundry/integration/Upgrades.t.sol

Lines changed: 2 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ contract UpgradesTest is IntegrationBaseTest {
9999
IRewardsDistributor originalRewardsDistributor = yneth.rewardsDistributor();
100100
uint originalAllocatedETHForDeposits = yneth.totalDepositedInPool();
101101
bool originalIsDepositETHPaused = yneth.depositsPaused();
102-
uint originalExchangeAdjustmentRate = yneth.exchangeAdjustmentRate();
103102
uint originalTotalDepositedInPool = yneth.totalDepositedInPool();
104103

105104
MockERC20 nETH = new MockERC20("Nest ETH", "nETH");
@@ -122,7 +121,6 @@ contract UpgradesTest is IntegrationBaseTest {
122121
assertEq(address(upgradedYnETH.rewardsDistributor()), address(originalRewardsDistributor), "RewardsDistributor mismatch");
123122
assertEq(upgradedYnETH.totalDepositedInPool(), originalAllocatedETHForDeposits, "AllocatedETHForDeposits mismatch");
124123
assertEq(upgradedYnETH.depositsPaused(), originalIsDepositETHPaused, "IsDepositETHPaused mismatch");
125-
assertEq(upgradedYnETH.exchangeAdjustmentRate(), originalExchangeAdjustmentRate, "ExchangeAdjustmentRate mismatch");
126124
assertEq(upgradedYnETH.totalDepositedInPool(), originalTotalDepositedInPool, "TotalDepositedInPool mismatch");
127125

128126
assertEq(finalTotalAssets, yneth.totalAssets(), "Total assets mismatch after upgrade");
@@ -134,38 +132,7 @@ contract UpgradesTest is IntegrationBaseTest {
134132
upgradedYnETH.deposit(nETHDepositAmount, address(this));
135133
}
136134

137-
function testUpgradeYnETHRevertswithInvalidAdjustmentRate() public {
138-
139-
TransparentUpgradeableProxy ynethProxy;
140-
yneth = ynETH(payable(ynethProxy));
141-
142-
// Re-deploying ynETH and creating its proxy again
143-
yneth = new ynETH();
144-
ynethProxy = new TransparentUpgradeableProxy(address(yneth), actors.PROXY_ADMIN_OWNER, "");
145-
yneth = ynETH(payable(ynethProxy));
146-
147-
148-
address[] memory pauseWhitelist = new address[](1);
149-
pauseWhitelist[0] = actors.TRANSFER_ENABLED_EOA;
150-
151-
uint256 invalidRate = 100000000000000000000;
152-
153-
ynETH.Init memory ynethInit = ynETH.Init({
154-
admin: actors.ADMIN,
155-
pauser: actors.PAUSE_ADMIN,
156-
stakingNodesManager: IStakingNodesManager(address(stakingNodesManager)),
157-
rewardsDistributor: IRewardsDistributor(address(rewardsDistributor)),
158-
exchangeAdjustmentRate: invalidRate,
159-
pauseWhitelist: pauseWhitelist
160-
});
161-
162-
bytes memory encodedError = abi.encodeWithSelector(ynETH.ExchangeAdjustmentRateOutOfBounds.selector, invalidRate);
163-
164-
vm.expectRevert(encodedError);
165-
yneth.initialize(ynethInit);
166-
}
167-
168-
function setupInitializeYnLSD(uint256 adjustmentRate, address assetAddress) internal returns (ynLSD.Init memory, ynLSD ynlsd) {
135+
function setupInitializeYnLSD(address assetAddress) internal returns (ynLSD.Init memory, ynLSD ynlsd) {
169136
TransparentUpgradeableProxy ynlsdProxy;
170137
ynlsd = ynLSD(payable(ynlsdProxy));
171138

@@ -203,7 +170,6 @@ contract UpgradesTest is IntegrationBaseTest {
203170
strategyManager: strategyManager,
204171
delegationManager: delegationManager,
205172
oracle: yieldNestOracle,
206-
exchangeAdjustmentRate: adjustmentRate,
207173
maxNodeCount: 10,
208174
admin: actors.ADMIN,
209175
stakingAdmin: actors.STAKING_ADMIN,
@@ -218,16 +184,9 @@ contract UpgradesTest is IntegrationBaseTest {
218184
}
219185

220186
function testYnLSDInitializeRevertsAssetAddressZero() public {
221-
(ynLSD.Init memory init, ynLSD ynlsd) = setupInitializeYnLSD(1000, address(0));
187+
(ynLSD.Init memory init, ynLSD ynlsd) = setupInitializeYnLSD(address(0));
222188
bytes memory encodedError = abi.encodeWithSelector(ynLSD.ZeroAddress.selector);
223189
vm.expectRevert(encodedError);
224190
ynlsd.initialize(init);
225191
}
226-
227-
function testYnLSDInitializeRevertsInvalidAdjustmentRate() public {
228-
(ynLSD.Init memory init, ynLSD ynlsd) = setupInitializeYnLSD(1 ether, chainAddresses.lsd.STETH_ADDRESS);
229-
bytes memory encodedError = abi.encodeWithSelector(ynLSD.ExchangeAdjustmentRateOutOfBounds.selector, 1 ether);
230-
vm.expectRevert(encodedError);
231-
ynlsd.initialize(init);
232-
}
233192
}

test/foundry/integration/ynETH.t.sol

Lines changed: 7 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ contract ynETHIntegrationTest is IntegrationBaseTest {
108108
// Act
109109
uint256 sharesAfterFirstDeposit = yneth.previewDeposit(secondDepositAmount);
110110

111-
uint256 expectedShares = Math.mulDiv(secondDepositAmount, 10000 - startingExchangeAdjustmentRate, 10000, Math.Rounding.Floor);
111+
uint256 expectedShares = secondDepositAmount;
112112

113113
// Assert
114114
assertEq(sharesAfterFirstDeposit, expectedShares, "Fuzz: Shares should match expected shares");
@@ -136,7 +136,7 @@ contract ynETHIntegrationTest is IntegrationBaseTest {
136136
assertEq(totalAssetsAfterSecondDeposit, expectedTotalAssets, "Total assets should match expected total after second deposit");
137137

138138
// Assuming initial total supply equals shares after first deposit
139-
uint256 expectedTotalSupply = firstDepositAmount + secondDepositAmount - startingExchangeAdjustmentRate * secondDepositAmount / 10000;
139+
uint256 expectedTotalSupply = firstDepositAmount + secondDepositAmount;
140140
uint256 totalSupplyAfterSecondDeposit = yneth.totalSupply();
141141
// TODO: figure out this precision issue
142142
assertTrue(compareWithThreshold(totalSupplyAfterSecondDeposit, expectedTotalSupply, 1), "Total supply should match expected total supply after second deposit");
@@ -146,11 +146,10 @@ contract ynETHIntegrationTest is IntegrationBaseTest {
146146
uint256 sharesAfterSecondDeposit = yneth.previewDeposit(thirdDepositAmount);
147147

148148
// Using the formula from ynETH to calculate expectedShares
149-
// Assuming exchangeAdjustmentRate is applied as in the _convertToShares function of ynETH
150149
uint256 expectedShares = Math.mulDiv(
151150
thirdDepositAmount,
152-
expectedTotalSupply * uint256(10000 - startingExchangeAdjustmentRate),
153-
expectedTotalAssets * uint256(10000),
151+
expectedTotalSupply,
152+
expectedTotalAssets,
154153
Math.Rounding.Floor
155154
);
156155

@@ -178,11 +177,10 @@ contract ynETHIntegrationTest is IntegrationBaseTest {
178177
uint256 expectedTotalAssets = ethAmount + expectedNetRewardAmount; // Assuming initial total assets were equal to ethAmount before rewards
179178
uint256 expectedTotalSupply = ethAmount; // Assuming initial total supply equals shares after first deposit
180179
// Using the formula from ynETH to calculate expectedShares
181-
// Assuming exchangeAdjustmentRate is applied as in the _convertToShares function of ynETH
182180
uint256 expectedShares = Math.mulDiv(
183181
ethAmount,
184-
expectedTotalSupply * uint256(10000 - startingExchangeAdjustmentRate),
185-
expectedTotalAssets * uint256(10000),
182+
expectedTotalSupply,
183+
expectedTotalAssets,
186184
Math.Rounding.Floor
187185
);
188186

@@ -358,21 +356,5 @@ contract ynETHIntegrationTest is IntegrationBaseTest {
358356
vm.expectRevert(encodedError);
359357
yneth.withdrawETH(1);
360358
vm.stopPrank();
361-
}
362-
363-
function testSetExchangeAdjustmentRate() public {
364-
uint256 newRate = 1000;
365-
vm.prank(address(actors.ADMIN));
366-
yneth.setExchangeAdjustmentRate(newRate);
367-
assertEq(yneth.exchangeAdjustmentRate(), newRate);
368-
}
369-
370-
function testSetExchangeAdjustmentRateWithInvalidRate() public {
371-
uint256 invalidRate = 100000000000000000000;
372-
bytes memory encodedError = abi.encodeWithSelector(ynETH.ValueOutOfBounds.selector, invalidRate);
373-
vm.prank(address(actors.ADMIN));
374-
vm.expectRevert(encodedError);
375-
yneth.setExchangeAdjustmentRate(invalidRate);
376-
vm.stopPrank();
377-
}
359+
}
378360
}

0 commit comments

Comments
 (0)