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: 161/246
Findings: 1
Award: $13.13
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: brgltd
Also found by: 0x3b, 0xAgro, 0xGusMcCrae, 0xNorman, 0xRajkumar, 0xSmartContract, 0xTraub, 0xWagmi, 0xWaitress, 0xffchain, 0xhacksmithh, 0xkazim, 0xnev, 3dgeville, ArbitraryExecution, Aymen0909, BRONZEDISC, Bason, Bloqarl, BlueAlder, Brenzee, CodeFoxInc, CodingNameKiki, Cryptor, DadeKuma, DevABDee, Diana, Dug, Englave, Gde, Haipls, HollaDieWaldfee, Ignite, Infect3d, Jerry0x, Josiah, Kaysoft, Koko1912, KrisApostolov, Lavishq, LeoGold, Madalad, PNS, Rappie, RaymondFam, RedTiger, Rickard, Rolezn, Sathish9098, SunSec, T1MOH, UdarTeam, Udsen, Viktor_Cortess, Wander, adriro, ak1, alejandrocovrr, alexzoid, arialblack14, ayden, bin2chen, brevis, btk, c3phas, carlitox477, catellatech, ch0bu, chaduke, ck, climber2002, codeslide, descharre, dingo2077, ernestognw, fatherOfBlocks, favelanky, georgits, helios, hl_, inmarelibero, juancito, ks__xxxxx, lopotras, lukris02, m_Rassska, mahdirostami, maxper, nadin, navinavu, nemveer, p_crypt0, peanuts, pipoca, pixpi, qpzm, rbserver, reassor, roelio, rotcivegaf, scokaf, siddhpurakaran, slvDev, smaul, tnevler, tsvetanovv, turvy_fuzz, vagrant, wen, yac, zzzitron
13.1298 USDC - $13.13
If an admin calls the SafEth.setMaxSlippage()
function by mistakenly inputing 0 as _slippage
parameter value, this might lead to DoS in the affected derivatives functions until the admin has updated the max slippage storage value of the affected derivative.
SafEth.sol:setMaxSlippage()
The minimum swap amount is calculated as follow:
uint256 minOut = ((((rethPerEth * msg.value) / 10 ** 18) * ((10 ** 18 - maxSlippage))) / 10 ** 18);
If maxSlippage
is set to 0, this will lead to minOut
being equal to rethPerEth * msg.value / 10 ** 18
which is equivalent to a swap without slippage that might revert the whole staking operation during the sub call to ISwapRouter(UNISWAP_ROUTER).exactInputSingle(params);
as it can be seen at line 128
of the Uniswap v3 SwapRouter contract (https://github.com/Uniswap/v3-periphery/blob/main/contracts/SwapRouter.sol#L128).
The minimum swap amount is calculated as follow:
uint256 minOut = (stEthBal * (10 ** 18 - maxSlippage)) / 10 ** 18;
If maxSlippage
is set to 0, this will lead to minOut
being equal to stEthBal / 10 ** 18
which is equivalent to a swap without slippage that might revert the whole unstaking operation during the sub call to IStEthEthPool(LIDO_CRV_POOL).exchange(1, 0, stEthBal, minOut);
as it can be seen at line 453
of the deployed IStEthEthPool(LIDO_CRV_POOL)
external contract: (https://etherscan.io/address/0xDC24316b9AE028F1497c275EB9192a3Ea0f67022#code).
The minimum swap amount is calculated as follow:
uint256 minOut = (((ethPerDerivative(_amount) * _amount) / 10 ** 18) * (10 ** 18 - maxSlippage)) / 10 ** 18;
If maxSlippage
is set to 0, this will lead to minOut
being equal to (ethPerDerivative(_amount) * _amount) / 10 ** 18
which is equivalent to a swap without slippage that might revert the whole unstaking operation during the sub call to IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS).exchange(1,0,frxEthBalance,minOut);
as it can be seen at line 534
of the deployed IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS)
external contract: (https://etherscan.io/address/0xa1F8A6807c402E4A15ef4EBa36528A3FED24E577#code).
Assert that the _maxSlippage
parameter value of the SafEth.sol:setMaxSlippage()
function is non-zero.
Comment @notice - Adds new derivative to the index fund
is misleading, this function is used to update the weight of a specific derivative.
SafEth.sol:adjustWeight() - NATSPEC
Describe the valid role of the function: updating the weight of a specific derivative.
Manual review
There is no event emitted on the success of implementations' initialize()
functions that might lead to a lack of transparency and difficult off-chain upgrades tracking.
Reth.sol:initialize() WstEth.sol:initialize() SfrxEth.sol:initialize() SafEth.sol:initialize()
Emit an event on initialization.
Manual review
In respect to the check-effect-interaction pattern, the events should be emitted before any external calls to uncontrolled addresses to avoid issues for off-chain third-parties in the scenario of an eventual reentering call.
Global
Example in SafEth.unstake()
:
function unstake(uint256 _safEthAmount) external { // ... (code removed for clarity) (bool sent, ) = address(msg.sender).call{value: ethAmountToWithdraw}( "" ); require(sent, "Failed to send Ether"); // Emits after the external call to an uncontrolled address that might reenter emit Unstaked(msg.sender, ethAmountToWithdraw, _safEthAmount); }
Emit events before external calls on uncontrolled addresses when possible.
Example in SafEth.unstake()
:
function unstake(uint256 _safEthAmount) external { // ... (code removed for clarity) // Emits before the external call to uncontrolled address emit Unstaked(msg.sender, ethAmountToWithdraw, _safEthAmount); (bool sent, ) = address(msg.sender).call{value: ethAmountToWithdraw}( "" ); require(sent, "Failed to send Ether"); //emit Unstaked(msg.sender, ethAmountToWithdraw, _safEthAmount); }
Manual review
The totalSupply
local value of the stake()
function shadows the inherited totalSupply()
function name.
In this particular context, it does not represent a threat to the security of the contract but could potentially introduce vulnerabilities as the protocol/contract grows (upgrades).
This also leads to less readability and potential developer errors.
SafEth.sol:stake()
function stake() external payable { // ... (code removed for clarity) // totalSupply shadows inherited totalSupply() function name uint256 totalSupply = totalSupply(); uint256 preDepositPrice; if (totalSupply == 0) preDepositPrice = 10 ** 18; else preDepositPrice = (10 ** 18 * underlyingValue) / totalSupply; // ... (code removed for clarity) }
Use a different local variable name.
Manual review
#0 - c4-sponsor
2023-04-10T21:01:09Z
toshiSat marked the issue as sponsor acknowledged
#1 - c4-judge
2023-04-24T18:39:05Z
Picodes marked the issue as grade-b