Platform: Code4rena
Start Date: 24/03/2023
Pot Size: $49,200 USDC
Total HM: 20
Participants: 246
Period: 6 days
Judge: Picodes
Total Solo HM: 1
Id: 226
League: ETH
Rank: 111/246
Findings: 2
Award: $33.34
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: adriro
Also found by: 0xMirce, 0xRajkumar, 0xepley, BPZ, Bahurum, Bauer, Co0nan, Emmanuel, Franfran, HollaDieWaldfee, IgorZuk, MiloTruck, NoamYakov, RedTiger, Ruhum, T1MOH, Tricko, ad3sh_, auditor0517, bin2chen, carrotsmuggler, eyexploit, handsomegiraffe, igingu, jasonxiale, koxuan, lukris02, monrel, nadin, peanuts, rbserver, rvierdiiev, shaka, sinarette, tnevler, y1cunhui
4.5426 USDC - $4.54
The WstEth
contract incorrectly calculates the price of ETH in terms of WstETH.
The function returns the price of WstETH in terms of stETH. The underlying asset which we desire is ETH.
Since stETH does not have the same value as ETH the output price is incorrect.
The impact is severe as underlyingValue
and totalStakeValueEth
through the stake()
function in the SafEth.sol
contract SafEth.sol#L63 are wrong calculated.
The function IWstETH(token).getStETHByWstETH()
only converts WstETH to stETH. Thus, ethPerDerivative()
returns the value of WstETH in terms of stETH. Also, the @notice
comment in the code says that the derivate's price should be in terms of ETH.
/** @notice - Get price of derivative in terms of ETH */ function ethPerDerivative(uint256 _amount) public view returns (uint256) { return IWStETH(WST_ETH).getStETHByWstETH(10 ** 18); }
Manuel review https://code4rena.com/reports/2022-05-alchemix/#m-15-lido-adapter-incorrectly-calculates-the-price-of-the-underlying-token
Add extra steps to ethPerDerivative()
to approximate the rate for converting stETH to ETH. This can be done using the same curve pool that is used to convert stETH to ETH in withdraw()
.
#0 - c4-pre-sort
2023-04-04T17:14:23Z
0xSorryNotSorry marked the issue as duplicate of #588
#1 - c4-judge
2023-04-23T11:07:05Z
Picodes changed the severity to 3 (High Risk)
#2 - c4-judge
2023-04-24T20:45:28Z
Picodes marked the issue as satisfactory
🌟 Selected for report: silviaxyz
Also found by: 0xMirce, 0xbepresent, CodingNameKiki, Franfran, HollaDieWaldfee, MiloTruck, Tricko, adriro, codeislight, cryptonue, d3e4, ladboy233, rbserver, shaka, volodya
28.8013 USDC - $28.80
The main impact is that if a deposit is disabled in the rocketDepositPool
contract, the deposit()
function Reth.sol#L156 will revert, and not try to deposit through swapExactInputSingleHop
and UniswapV3 contract Reth.sol#L170.
Function deposit()
is called from stake()
function SafEth.sol#L91, so, complete stake process will be reverted.
Function deposit()
in RocketDepositPool.sol
looks like
function deposit() override external payable onlyThisLatestContract { // Check deposit settings RocketDAOProtocolSettingsDepositInterface rocketDAOProtocolSettingsDeposit = RocketDAOProtocolSettingsDepositInterface(getContractAddress("rocketDAOProtocolSettingsDeposit")); require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled"); require(msg.value >= rocketDAOProtocolSettingsDeposit.getMinimumDeposit(), "The deposited amount is less than the minimum deposit size"); RocketVaultInterface rocketVault = RocketVaultInterface(getContractAddress("rocketVault")); require(rocketVault.balanceOf("rocketDepositPool").add(msg.value) <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize(), "The deposit pool size after depositing exceeds the maximum size"); // Calculate deposit fee uint256 depositFee = msg.value.mul(rocketDAOProtocolSettingsDeposit.getDepositFee()).div(calcBase); uint256 depositNet = msg.value.sub(depositFee); // Mint rETH to user account RocketTokenRETHInterface rocketTokenRETH = RocketTokenRETHInterface(getContractAddress("rocketTokenRETH")); rocketTokenRETH.mint(depositNet, msg.sender); // Emit deposit received event emit DepositReceived(msg.sender, msg.value, block.timestamp); // Process deposit processDeposit(rocketVault, rocketDAOProtocolSettingsDeposit); }
As it is seen from the code, it exists check require(rocketDAOProtocolSettingsDeposit.getDepositEnabled(), "Deposits into Rocket Pool are currently disabled");
, so without this check, deposit()
function in Reth.sol#L156 will revert.
Manuel review
In Reth.sol#L120 include check rocketDAOProtocolSettingsDeposit.getDepositEnabled()
. The best place for that is Reth.sol#L146
return rocketDAOProtocolSettingsDeposit.getDepositEnabled() && rocketDepositPool.getBalance() + _amount <= rocketDAOProtocolSettingsDeposit.getMaximumDepositPoolSize() && _amount >= rocketDAOProtocolSettingsDeposit.getMinimumDeposit();
#0 - c4-pre-sort
2023-04-04T18:55:47Z
0xSorryNotSorry marked the issue as duplicate of #812
#1 - c4-judge
2023-04-24T19:42:38Z
Picodes marked the issue as satisfactory