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: 22/110
Findings: 4
Award: $529.56
🌟 Selected for report: 1
🚀 Solo Findings: 0
🌟 Selected for report: carrotsmuggler
Also found by: 0x52, 0xDecorativePineapple, 0xPanas, Bahurum, Jeiwan, Lambda, PwnPatrol, R2, Respx, auditor0517, durianSausage, hyh, ladboy233, pauliax, scaraven, teawaterwire, zzzitron
47.5961 USDC - $47.60
https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/oracles/PegOracle.sol#L46-L83 https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/Controller.sol#L299-L300
Wrong maths for handling pricefeed decimals. This code will only work for pricefeeds of 8 decimals, any others give wrong/incorrect data. The maths used can be shown in three lines:
nowPrice = (price1 * 10000) / price2; nowPrice = nowPrice * int256(10**(18 - priceFeed1.decimals())); return nowPrice / 1000000;
Line1: adds 4 decimals Line2: adds (18 - d) decimals, (where d = pricefeed.decimals()) Line3: removes 6 decimals
Total: adds (16 - d) decimals
when d=8, the contract correctly returns an 8 decimal number. However, when d = 6, the function will return a 10 decimal number. This is further raised by (18-d = 12) decimals when checking for depeg event, leading to a 22 decimal number which is 4 orders of magnitude incorrect.
if d=18, (like usd-eth pricefeeds) contract fails / returns 0.
All chainlink contracts which give price in eth, operate with 18 decimals. So this can cripple the system if added later.
Running the test AssertTest.t.sol:testPegOracleMarketCreation and changing the line on
to
PegOracle pegOracle3 = new PegOracle( 0xB1552C5e96B312d0Bf8b554186F846C40614a540, //usd-eth contract address btcEthOracle );
gives this output
oracle3price1: 1085903802394919427 oracle3price2: 13753840915281064000 oracle3price1 / oracle3price2: 0
returning an oracle value of 0. Simulating with a mock price feed of 6 decimals gives results 4 orders of magnitude off.
Foundry, vs-code
Since only the price ratio is calculated, there is no point in increasing the decimal by (18-d) in the second line. Proposed solution:
nowPrice = (price1 * 10000) / price2; nowPrice = nowPrice * int256(10**(priceFeed1.decimals())) * 100; return nowPrice / 1000000;
This returns results in d decimals, no matter the value of d.
#0 - HickupHH3
2022-10-17T10:12:42Z
Prefer this over #300 for its simpler explanation.
125.2594 USDC - $125.26
https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/Controller.sol#L148-L192 https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/Controller.sol#L198-L248
Controller functions do not check for empty vaults. If either hedge or risk vault is empty for any market / id, the premium / risk value can be irretrievably lost. When a vault value is 0 and the counterparty vault's funds are moved in, the idFinalTVL is set to 0, making any withdrawal/recovery impossible essentially permanently burning those tokens. Such burn functions should be avoided.
Also, if either vault is empty, it implies that either hedgers are hedging against nothing, or riskers are risking with no premium. Since the protocol does not allow the users to withdraw their funds before the start of the hedging period, it highly discourages people from adding money to either vault if the counterparty vault is empty.
Run the test in
but with hedge vault 0 (no deposit from ALICE & BOB). The Premium amount will be locked forever. Similarly, test testControllerDepeg with risk vault 0 (no deposit from CHAD & DEGEN).
Vs-code, Foundry
Check if either vault (hedge/risk) is empty before triggering depeg/ endepoch. If any vault is 0, allow withdrawal of funds without triggering the inter-vault token transfers (basically a refund).
#0 - 3xHarry
2022-09-22T10:29:22Z
dup #409
🌟 Selected for report: unforgiven
Also found by: carrotsmuggler, cccz
320.0832 USDC - $320.08
Judge has assessed an item in Issue #207 as Medium risk. The relevant finding follows:
#0 - HickupHH3
2022-11-05T02:36:51Z
- Withdrawal before epoch begins Maybe allow the withdrawal of funds before the epoch begins to fix mistakes etc regarding deposit amounts. Current implementation only allows withdrawal after depeg event, or epochEnd. Can be ignored if this is the intended method of operation.
dup #447
🌟 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
When creating a new vault, epochBegin time should be checked against the block.timestamp. Otherwise can lead to the creation of unusable vaults. https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/Vault.sol#L307-L325
Maybe allow the withdrawal of funds before the epoch begins to fix mistakes etc regarding deposit amounts. Current implementation only allows withdrawal after depeg event, or epochEnd. Can be ignored if this is the intended method of operation.
Some places address the vault as insr, some places address it as hedge. Advised to have consistent naming to prevent confusion.
https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/VaultFactory.sol#L314 https://github.com/code-423n4/2022-09-y2k-finance/blob/2175c044af98509261e4147edeb48e1036773771/src/VaultFactory.sol#L199
Incorrect expression in comments. Should be // 0.5% = multiply by 5 then divide by 1000
The test in
fails since the controller is never called to end the epoch. Insert the line controller.triggerEndEpoch(1, endEpoch);
before starting the withdrawal process.
2 Fuzz tests fail in FuzzTest.t.sol, both due to the same reason: an issue in the test function testFuzzDeposit().
The reason for failure is that the FixedPointMathLib.sol library can only handle uint128 numbers. It multiplies two numbers and stores them in z
This only works if the product fits in uint256, which can be guaranteed with uint128 numbers. The fuzz test sends a number larger than uint128 since it expects to test uint256, making the test revert. A simple fix is to put in an assume statement at the top, only accepting uint96. uint96 as an example, because we want the result of the number * MULTIPLIER to fit within a uint128. Add the assume as below
vm.assume(ethValue < type(uint96).max && ethValue > 1);
The second condition is needed otherwise it reverts if sent 0 ETH by design. The other failing fuzz test fails because it calls this function. So adding this one line will fix all tests in FuzzTest.t.sol.