Platform: Code4rena
Start Date: 14/09/2022
Pot Size: $50,000 USDC
Total HM: 25
Participants: 110
Period: 5 days
Judge: hickuphh3
Total Solo HM: 9
Id: 162
League: ETH
Rank: 38/110
Findings: 2
Award: $161.88
🌟 Selected for report: 0
🚀 Solo Findings: 0
125.2594 USDC - $125.26
In each Vault epoch, idFinalTVL[]
and idClaimTVL[]
values is only set when someone call triggerDepeg()
or triggerEndEpoch()
from Controller. In case of depeg, we will swap assets of hedge and risk Vault.
But if one Vault has noone deposited, idFinalTVL[]
will be zero and it makes beforeWithdraw()
always reverted because of divide by zero error. The result is funds cannot withdraw()
their assets.
Also if only one Vault has be deposited, users will receive nothing. (Depeg: they lost deposited funds, End Epoch: nothing since other Vault is empty)
Consider the scenario
vHedge
and vRisk
. Alice deposited 10 WETH
to vHedge
and vRisk
has nothing.10 WETH
from vHedge
to vRisk
. And since no one deposited to vRisk
, these WETH is locked forever.vHedge
Vault will receive nothing too since only vHedge
vault has assets.Manual Review
Consider add a mechanism in case noone deposit in 1 Vault after epoch start, consider that epoch is cancelled and users can withdraw their funds.
#0 - 3xHarry
2022-09-21T12:25:38Z
@MiguelBits seems valid, we should add if condition in beforeWithdraw
to check if claimTVL is 0
#1 - HickupHH3
2022-10-18T02:50:01Z
Selecting #312 for the report as it provides more technical details + foundry POC.
🌟 Selected for report: Respx
Also found by: 0x1f8b, 0xDecorativePineapple, 0xNazgul, 0xPanas, 0xSmartContract, 0xc0ffEE, 0xmuxyz, Aymen0909, Bahurum, Bnke0x0, CodingNameKiki, Deivitto, Jeiwan, Lambda, Picodes, PwnPatrol, R2, RaymondFam, Rolezn, Ruhum, Saintcode_, SooYa, Tointer, V_B, ajtra, ak1, async, auditor0517, brgltd, c3phas, carrotsmuggler, cccz, csanuragjain, datapunk, djxploit, durianSausage, eierina, erictee, gogo, imare, joestakey, jonatascm, kv, ladboy233, leosathya, lukris02, oyc_109, pashov, pauliax, rbserver, robee, rokinot, rvierdiiev, scaraven, simon135, unforgiven, wagmi, zzzitron
36.6223 USDC - $36.62
In Tests section, sponsors said they would like to assess if testFuzzDeposit()
and testFuzzWithdraw()
are failed due to a logic fault in the contracts or in testing.
For both tests, we only assume that
vm.assume(ethValue >= 1);
So in when fuzzing, if ethValue
is too large, for example ethValue = 2**255
, it may make some calculation overflow (even it’s just a simple sumation because ethValue
is already large).
In case ethValue = 2**256 - 1
, some calculations will be overflow. For example
When deposit()
, it will call to ​​previewDeposit()
=> convertToShares()
with assets = 2**256 - 1
.
function convertToShares(uint256 id, uint256 assets) public view virtual returns (uint256) { uint256 supply = totalSupply(id); // Saves an extra SLOAD if totalSupply is non-zero. return supply == 0 ? assets : assets.mulDivDown(supply, totalAssets(id)); }
It will be overflowed in mulDivDown
and test failed
Should add a condition on ethValue
to be reasonable like
vm.assume(ethValue < (2 << 127));
#0 - 0xnexusflip
2022-09-21T16:26:50Z
When using the recommended fix the fuzzer does even less runs than before. Will try and use the same recommended logic pre-condition by limiting the maximum number of fuzz runs but I highly doubt the problem lies just in the test itself, as proven by other contestants on other issues (refer to #213 and #263 )
#1 - 0xnexusflip
2022-09-21T16:31:56Z
Tested logic by limiting fuzz runs as well and the results are similar. As such, I will mark this issue as closed and the solution to it as not valid.
#2 - HickupHH3
2022-11-01T13:23:38Z
Aren't test files out of scope? Would be a non-crit finding at most.
#3 - HickupHH3
2022-11-01T13:24:19Z
warden's QA.