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: 6/246
Findings: 4
Award: $988.40
🌟 Selected for report: 0
🚀 Solo Findings: 0
236.4864 USDC - $236.49
Inflates or lowers the price of SfrxEth / ETH depending on the oracle price
/** @notice - Get price of derivative in terms of ETH */ function ethPerDerivative(uint256 _amount) public view returns (uint256) { uint256 frxAmount = IsFrxEth(SFRX_ETH_ADDRESS).convertToAssets( 10 ** 18 ); return ((10 ** 18 * frxAmount) / IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS).price_oracle()); }
To get price SfrxEth / ETH we should calculate (SfrxEth / FrxEth) * (FrxEth / ETH). But in return formula we divide instead of multiply. For easy understanding suppose 1 SfrxEth costs 5 FrxEth and 1 FrxEth costs 0.2 ETH. It results in price SfrxEth / ETH = 5 / 0.2. Which means 25 instead of 1
Manual review
Refactor the formula
function ethPerDerivative(uint256 _amount) public view returns (uint256) { uint256 frxAmount = IsFrxEth(SFRX_ETH_ADDRESS).convertToAssets( 10 ** 18 ); return (frxAmount * IFrxEthEthPool(FRX_ETH_CRV_POOL_ADDRESS).price_oracle() / 10 ** 18); }
#0 - c4-pre-sort
2023-04-03T14:13:08Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T16:50:38Z
0xSorryNotSorry marked the issue as duplicate of #698
#2 - c4-judge
2023-04-21T16:01:44Z
Picodes marked the issue as not a duplicate
#3 - c4-judge
2023-04-21T16:01:58Z
Picodes marked the issue as satisfactory
#4 - c4-judge
2023-04-21T16:02:08Z
Picodes marked the issue as duplicate of #641
#5 - c4-judge
2023-04-24T21:38:22Z
Picodes changed the severity to 3 (High Risk)
🌟 Selected for report: adriro
Also found by: 0x52, T1MOH, anodaram, cloudjunky, hassan-truscova
734.235 USDC - $734.24
Overflow in poolPrice()
leads to revert and blocking of stake and unstake
IUniswapV3Pool pool = IUniswapV3Pool( factory.getPool(rocketTokenRETHAddress, W_ETH_ADDRESS, 500) ); (uint160 sqrtPriceX96, , , , , , ) = pool.slot0(); return (sqrtPriceX96 * (uint(sqrtPriceX96)) * (1e18)) >> (96 * 2);
_sqrtPriceX96ToUint will only work when the non-fractional component of sqrtPriceX96 takes up to 2 bits. This represents a price ratio of 16. Market conditions are different, and can happen
Manual Review
Perform multiplication after converting numbers to 60x18
#0 - c4-pre-sort
2023-04-03T14:13:47Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T14:44:19Z
0xSorryNotSorry marked the issue as duplicate of #693
#2 - c4-judge
2023-04-21T16:39:24Z
Picodes marked the issue as satisfactory
#3 - c4-judge
2023-04-24T21:39:48Z
Picodes changed the severity to 3 (High Risk)
🌟 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
Function returns price of WstEth in terms of stEth. But must be in terms of ETH.
function ethPerDerivative(uint256 _amount) public view returns (uint256) { return IWStETH(WST_ETH).getStETHByWstETH(10 ** 18); }
Manual review
Convert amount of stEth into ETH via price_oracle in LIDO_CRV_POOL
#0 - c4-pre-sort
2023-04-03T14:11:44Z
0xSorryNotSorry marked the issue as low quality report
#1 - c4-pre-sort
2023-04-04T17:19:10Z
0xSorryNotSorry marked the issue as duplicate of #588
#2 - c4-judge
2023-04-21T17:09:53Z
Picodes marked the issue as satisfactory
#3 - c4-judge
2023-04-23T11:07:04Z
Picodes changed the severity to 3 (High Risk)
🌟 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
This contract is dependent on SafEth.sol and provides read-only functionality, there is know sense in deploying it
See this link for a description of this storage variable. While some contracts may not currently be sub-classed, adding the variable now protects against forgetting to add it in the future. 1 instance: SafEthStorage
There is another Openzeppelin Ownable contract (Ownable2StepUpgradeable.sol) has transferOwnership function, use is more secure due to 2-stage ownership transfer.
In WstEth.sol send balanceAfter - balanceBefore, but not all balance
uint256 minOut = (stEthBal * (10 ** 18 - maxSlippage)) / 10 ** 18; uint256 balanceBefore = address(this).balance; IStEthEthPool(LIDO_CRV_POOL).exchange(1, 0, stEthBal, minOut); uint256 balanceAfter = address(this).balance; // solhint-disable-next-line (bool sent, ) = address(msg.sender).call{value: balanceAfter - balanceBefore}( "" );
For resque ERC-20 add
uint256 balancePre = IERC20(STETH_TOKEN).balanceOf(address(this)); IWStETH(WST_ETH).unwrap(_amount); uint256 balancePost = IERC20(STETH_TOKEN).balanceOf(address(this)); uint256 stEthBal = balancePost - balancePre IERC20(STETH_TOKEN).approve(LIDO_CRV_POOL, stEthBal);
And by analogy provide resque for all derivatives
else return (poolPrice() * 10 ** 18) / (10 ** 18);
Return poolPrice() without unnecessary mul and div
#0 - c4-sponsor
2023-04-07T23:33:51Z
elmutt marked the issue as sponsor confirmed
#1 - c4-judge
2023-04-24T18:48:04Z
Picodes marked the issue as grade-b