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: 31/110
Findings: 3
Award: $214.71
🌟 Selected for report: 0
🚀 Solo Findings: 0
125.2594 USDC - $125.26
For Hedge users even if they win (depeg happens) they loose all the money they put in the Vault if no one has put any money in the counterparty Risk Vault.
Hedge users have the worst favors compared with Risk users. Even if they make a correct prediction they can loose all their money.
At the end of an epoch the controler swaps the Hedge and Risk Vault.
If we are a Hedge users and have made the right prediction.
By the calculation made in Vault#beforeWithdraw
we can only claim 0 if the risk Vault has no value.
forge of foundery
In the controller when we (anyone/kepper) call triggerDepeg
function before swapping we should check if we have any token to swap with
function triggerDepeg(uint256 marketIndex, uint256 epochEnd) { ... insrVault.endEpoch(epochEnd, true); riskVault.endEpoch(epochEnd, true); insrVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd)); riskVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd)); insrVault.sendTokens(epochEnd, address(riskVault)); riskVault.sendTokens(epochEnd, address(insrVault)); ...
with:
if (riskVault.idFinalTVL(epochEnd) != 0) { // Do we have anyting to swap with ? insrVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd)); riskVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd)); insrVault.sendTokens(epochEnd, address(riskVault)); riskVault.sendTokens(epochEnd, address(insrVault)); } else { // set the right claim values ..do not swap insrVault.setClaimTVL(epochEnd, insrVault.idFinalTVL(epochEnd)); riskVault.setClaimTVL(epochEnd, riskVault.idFinalTVL(epochEnd)); }
#0 - zobront
2022-09-19T20:39:42Z
This seems to be the intentional behavior of the system, with an assumption that the Risk Vault should have more assets than the Hedge Vault in proportion to their expected probabilities.
#1 - MiguelBits
2022-09-20T21:42:39Z
The Description you provide describes that our protocol is working as intended.
However the code implementation you suggest matches what I need to do to fix these issues:
https://github.com/code-423n4/2022-09-y2k-finance-findings/issues/259
https://github.com/code-423n4/2022-09-y2k-finance-findings/issues/312
https://github.com/code-423n4/2022-09-y2k-finance-findings/issues/196
Submitted for review
#2 - HickupHH3
2022-10-18T04:17:12Z
weak dup of #312 because it doesn't cover the aspect of hedge users' monies being lost from div by zero that other dups have covered.
🌟 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
testOwnerAuthorize()
from AssertTest.t.sol
fileis failing because is not enough to vm.warp but we still need to call a controller function before withdrawing. Signaling depegging or ending of an epoch.
After the line vm.warp(endEpoch + 1 days);
we can call controller.triggerEndEpoch(SINGLE_MARKET_INDEX, endEpoch);
.
More correctly we should call the function that signals depegging because we are simulating a depeg situation with the FakeOracle.
In this case before the line vm.warp(endEpoch + 1);
we can call two functions like this :
vm.warp(endEpoch - 100); controller.triggerDepeg(SINGLE_MARKET_INDEX, endEpoch);
In both situations now the test passes because withdrawal is succesfully executed.
testFuzzDeposit
from FuzzTest.t.sol
fileis failing because 2 small mistakes :
The default amount of ether that the test contract is given is 2**96 wei (as in DappTools), so we have to restrict the type of amount to uint96 to make sure we don't try to send more than we have to change the function parameter signature from uint256 ethValue
to uint96 ethValue
function testFuzzDeposit(uint96 ethValue) public { vm.assume(ethValue > 0); ...
testFuzzWithdraw()
from FuzzTest.t.sol
fileSame mistake as in testFuzzDeposit
.
We need to change from:
function testFuzzWithdraw(uint256 ethValue) public {
to
function testFuzzWithdraw(uint96 ethValue) public {
In line :
https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/VaultFactory.sol#L171 the true type for strikePrice parameter is not uint256 but int256 because AggregatorV3Interface
is using int256 type for the nowPrice.
epochHasEnded
Insted of epochHasEnded
mybe call it for what it trully does epochTimeStampHasEnded
maybe.
Considering the implementation:
modifier epochHasEnded(uint256 id) { if((block.timestamp < id) && idDepegged[id] == false) revert EpochNotFinished(); _; }
The function is really checking the epoch window timestamp is ended plus if we are not in a depegged situation.
I found this problematic when testOwnerAuthorize()
was failing because the call to witdraw (which is using this modifier). In my opinion it should revert with EpochNotFinshed
because the kepper/controller did not call triggerEndEpoch
(you see here End Epoch) or triggerDepeg. Instead it reverts without this reason and failing the test.
The main problem is that we should have a signal that we are missing a call for "ending" an epoch.
Vault::getNextEpoch
can failThis function is not tested. It doesn`t seem to be used anywhere in codebase.
If the Vault has many epochs the for loop can consume all the transaction gas.
If ever needed a possible mitigation is to add next/previous mapping in relation to the current epoch instead of looping.
SafeMath
in StakingReward
contractBecause you are using solidity version 8 you do not need to use SafeMath library.
🌟 Selected for report: pfapostol
Also found by: 0x040, 0x1f8b, 0x4non, 0xNazgul, 0xSmartContract, 0xc0ffEE, 0xkatana, Aymen0909, Bnke0x0, Deivitto, Diana, JAGADESH, KIntern_NA, Lambda, MiloTruck, R2, RaymondFam, Respx, ReyAdmirado, Rohan16, RoiEvenHaim, Rolezn, Ruhum, Saintcode_, Samatak, Sm4rty, SnowMan, Tomio, Tomo, WilliamAmbrozic, _Adam, __141345__, ajtra, ak1, async, c3phas, ch0bu, cryptostellar5, d3e4, delfin454000, dharma09, djxploit, durianSausage, eierina, erictee, fatherOfBlocks, gianganhnguyen, gogo, ignacio, imare, jag, jonatascm, leosathya, lukris02, malinariy, oyc_109, pashov, pauliax, peanuts, peiw, prasantgupta52, robee, rokinot, rotcivegaf, rvierdiiev, seyni, simon135, slowmoses, sryysryy, tnevler, zishansami
52.8286 USDC - $52.83