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: 155/246
Findings: 2
Award: $13.27
π Selected for report: 0
π Solo Findings: 0
π Selected for report: HHK
Also found by: 019EC6E2, 0Kage, 0x52, 0xRobocop, 0xTraub, 0xbepresent, 0xepley, 0xfusion, 0xl51, 4lulz, Bahurum, BanPaleo, Bauer, CodeFoxInc, Dug, HollaDieWaldfee, IgorZuk, Lirios, MadWookie, MiloTruck, RedTiger, Ruhum, SaeedAlipoor01988, Shogoki, SunSec, ToonVH, Toshii, UdarTeam, Viktor_Cortess, a3yip6, auditor0517, aviggiano, bearonbike, bytes032, carlitox477, carrotsmuggler, chalex, deliriusz, ernestognw, fs0c, handsomegiraffe, igingu, jasonxiale, kaden, koxuan, latt1ce, m_Rassska, n1punp, nemveer, nowonder92, peanuts, pontifex, roelio, rvierdiiev, shalaamum, shuklaayush, skidog, tank, teddav, top1st, ulqiorra, wait, wen, yac
0.1353 USDC - $0.14
https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L241 https://github.com/code-423n4/2023-03-asymmetry/blob/44b5cd94ebedc187a08884a7f685e950e987261c/contracts/SafEth/derivatives/Reth.sol#L91-L101
I want to demonstrate how frontrunning with the flash loan can affect stake function causing errors and reverting transactions.
I chose WETH/rETH pool on Uniswap V3 because I'm more familiar with this exchange. But I think similar operations are possible with the other 2 derivatives.
First I tried to manipulate the price in the pool to see if it was possible to mint more shares during staking, but the result wasn't very significant. Staking 0.5 ETH with a flashloan of 1460 WETH (almost all WETH in the pool) could bring only about 0.006 WETH in profit (without expenses for gas and assuming the flashloan is free and could be borrowed without fees from Balancer).
During these attempts, I noticed 2 possible errors:
1)Error: VM Exception while processing transaction: reverted with panic code 0x11 (Arithmetic operation underflowed or overflowed outside of an unchecked block) in Reth.sol contract in this line :
241: return (sqrtPriceX96 * (uint(sqrtPriceX96)) * (1e18)) >> (96 * 2);
This error happens if the stake amount is 1 ETH and the size of flashloan is 1470 eth in my test. The sqrtPriceX96 = 1461446703485210103287273052203988822378723970341
it.only("WST Flash", async () => { let wethWhale = "0x0C4809bE72F9E117D75381438c5dAeC8AbE75BaD" let WETH = "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2"; let rETH = "0xae78736Cd615f374D3085123A210448E74Fc6393"; const ethDepositAmount = "1"; const weiDepositAmount = ethers.utils.parseEther(ethDepositAmount); const weiDepositAmount2 = ethers.utils.parseEther("1470"); await network.provider.request({ method: "hardhat_impersonateAccount", params: [wethWhale], }); const whaleSigner = await ethers.getSigner(wethWhale); const erc20 = new ethers.Contract("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", ERC20.abi, whaleSigner); await erc20.transfer(derivatives[0].address, weiDepositAmount2); //I used swapExactInputSingleHop from Reth.sol to imitate trade with flashloan on Uniswap V3 to make the process faster. let amountOut = await derivatives[0].swapExactInputSingleHop(WETH,rETH,500,weiDepositAmount2,0) const tx1 = await safEthProxy.stake({ value: weiDepositAmount }); })
2) Error: VM Exception while processing transaction: reverted with reason string 'Too little received happens if I change amounts of stake and flashloan:
const ethDepositAmount = "100"; const weiDepositAmount = ethers.utils.parseEther(ethDepositAmount); const weiDepositAmount2 = ethers.utils.parseEther("1450");
Protection from slippage works, but the transaction reverts.
VC
In one case we see that slippage protection works, but in the case of overflow, some changes should be made to the formula in the return statement of the poolPrice() function.
#0 - c4-pre-sort
2023-04-04T11:46:48Z
0xSorryNotSorry marked the issue as duplicate of #601
#1 - c4-judge
2023-04-21T16:13:55Z
Picodes marked the issue as satisfactory
#2 - c4-judge
2023-04-21T16:15:25Z
Picodes marked the issue as duplicate of #1125
#3 - c4-judge
2023-04-24T21:41:08Z
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
There is no checking of 0 address, so this code from the Test showing deployment of derivative contracts works:
describe("Derivatives", async () => { let derivatives = [] as any; beforeEach(async () => { await resetToBlock(initialHardhatBlock); derivatives = []; const factory0 = await ethers.getContractFactory("Reth"); const factory1 = await ethers.getContractFactory("SfrxEth"); const factory2 = await ethers.getContractFactory("WstEth"); const derivative0 = await upgrades.deployProxy(factory0, [ "0x0000000000000000000000000000000000000000", ]); await derivative0.deployed();
This could lead to redeployment and reinitialization.
Recommend considering implementing a two-step process where the owner or admin nominates an account and the nominated account needs to call an acceptOwnership() function for the transfer of ownership to fully succeed. This ensures the nominated EOA account is a valid and active account.
Avoid floating pragmas for non-library contracts.
While floating pragmas make sense for libraries to allow them to be included with multiple different versions of applications, it may be a security risk for application implementations.
A known vulnerable compiler version may accidentally be selected or security tools might fall back to an older compiler version ending up checking a different EVM compilation that is ultimately deployed on the blockchain.
It is recommended to pin to a concrete compiler version.
All files: pragma solidity ^0.8.13;
All files.
Itβs possible to name the imports to improve code readability
#0 - c4-sponsor
2023-04-07T21:47:38Z
toshiSat marked the issue as sponsor acknowledged
#1 - c4-judge
2023-04-24T17:14:38Z
Picodes marked the issue as grade-b