Platform: Code4rena
Start Date: 13/03/2023
Pot Size: $72,500 USDC
Total HM: 33
Participants: 35
Period: 7 days
Judge: Dravee
Total Solo HM: 16
Id: 222
League: ETH
Rank: 21/35
Findings: 2
Award: $254.10
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: peakbolt
Also found by: 0xRobocop, 0xbepresent, auditor0517, kaden
175.2447 USDC - $175.24
https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L494 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L511
The protocol does not adequately increase the calculated fees to the totalFunds
storage variable in the open short operations consequently the liquidity providers receive less yields and the protocol receive less funds. Those calculated fees are lost.
The fees are calculated in the 511 code line but those are not increased to the totalFunds
storage variable:
File: LiquidityPool.sol 491: /// @notice Called by exchange when a new short position is created 492: /// @param amount Amount of square perp being shorted 493: /// @param user Address of the user 494: function openShort(uint256 amount, address user, bytes32 referralCode) 495: external 496: override 497: onlyExchange 498: nonReentrant 499: returns (uint256 totalCost) 500: { 501: (uint256 markPrice, bool isInvalid) = getMarkPrice(); 502: require(!isInvalid); 503: 504: uint256 tradeCost = amount.mulWadDown(markPrice); 505: uint256 fees = orderFee(-int256(amount)); 506: totalCost = tradeCost - fees; 507: 508: SUSD.safeTransfer(user, totalCost); 509: 510: uint256 hedgingFees = _hedge(-int256(amount), false); 511: uint256 feesCollected = fees - hedgingFees; 512: uint256 externalFee = feesCollected.mulWadDown(devFee); 513: 514: SUSD.safeTransfer(feeReceipient, externalFee); 515: 516: usedFunds += int256(totalCost + hedgingFees + externalFee); 517: require(usedFunds <= 0 || totalFunds >= uint256(usedFunds)); 518: 519: emit RegisterTrade(referralCode, feesCollected, externalFee); 520: emit OpenShort(markPrice, amount, fees); 521: }
VScode
Increment the feesCollected
to the totalFunds
storage variable in the openShort()
function.
#0 - c4-judge
2023-03-21T13:41:51Z
JustDravee marked the issue as duplicate of #153
#1 - JustDravee
2023-05-02T22:44:53Z
Partial for lack of coded POC on a high
#2 - c4-judge
2023-05-02T22:45:20Z
JustDravee marked the issue as partial-50
🌟 Selected for report: bytes032
Also found by: 0xbepresent, PaludoX0, juancito, peanuts, sorrynotsorry
78.8601 USDC - $78.86
https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L200 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L219
The LiquidityPool.sol::queueDeposit() function helps to queue the user deposit and then the deposit will be processed by the LiquidityPool.sol::processDeposits() function after the delay is completed. The deposits are used to cover the margin required in every operation.
The problem is that an attacker can create many deposits with zero amounts
, so it is possible to flood the depositQueue with zero amount deposits and the processDeposits()
function will cost more work/gas to process.
Please see the next scenario:
sUSD
in the LiquidityPool.sUSD
in the LiquidityPool.queueDeposit()
function because the function doesn't have fees.attacker
frontruns the liquidity providers and he floods the depositQueue
with zero amounts causing the processing of the processDeposits()
function to cost more work/gas.At the end, the attacker can cause the processDeposits()
function to take more work/gas to process, causing valid deposits to be unavailable.
I created a basic test where you can see that it is possible to queue deposits with amount zero:
function testZeroQueueDeposit() public { // It is possible to flood the depositQueue with zero amounts in the queueDeposit() // causing a DOS in the processDeposits() // 1. Call the queueDeposit() with zero amounts // 2. Assert queuedDepositHead and nextQueuedDepositId // 3. Call the processDeposits() // 4. Assert the incremention of queuedDepositHead // // 1. Call the queueDeposit() with zero amounts // pool.queueDeposit(0, user_1); pool.queueDeposit(0, user_2); pool.queueDeposit(0, user_3); // // 2. Assert queuedDepositHead and nextQueuedDepositId // assertEq(pool.queuedDepositHead(), 1); assertEq(pool.nextQueuedDepositId(), 4); // // 3. Call the processDeposits() // vm.warp(block.timestamp + pool.minDepositDelay()); pool.processDeposits(1); // // 4. Assert the incremention of queuedDepositHead // assertEq(pool.queuedDepositHead(), 2); }
VScode
Checks that the deposited amount
is not zero in the queueDeposit()
function.
#0 - c4-judge
2023-03-24T01:30:01Z
JustDravee marked the issue as duplicate of #122
#1 - JustDravee
2023-05-03T01:37:39Z
Considered as a duplicate of https://github.com/code-423n4/2023-03-polynomial-findings/issues/122 from the same wardens as others submitted both in the same finding Also, front-running isn't an issue on Optimism https://help.optimism.io/hc/en-us/articles/4444375174299-Is-transaction-front-running-possible-on-Optimism-
#2 - c4-judge
2023-05-05T12:47:27Z
JustDravee marked the issue as satisfactory
#3 - c4-judge
2023-05-16T00:04:37Z
JustDravee changed the severity to 2 (Med Risk)
🌟 Selected for report: bytes032
Also found by: 0xbepresent, PaludoX0, juancito, peanuts, sorrynotsorry
78.8601 USDC - $78.86
https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L264 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/LiquidityPool.sol#L284 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/KangarooVault.sol#L227 https://github.com/code-423n4/2023-03-polynomial/blob/aeecafc8aaceab1ebeb94117459946032ccdff1e/src/KangarooVault.sol#L269
The queueWithdraw() function helps to the user to queue his withdrawals and the processWithdraws() function helps to process all the users withdrawals.
The problem here is that the attacker can flood the withdrawalQueue with zero amounts, causing the processWithdraws()
cost more gas to process the user withdrawals. The same behaivour is happening in the KangarooVault.sol::initiateWithdrawal().
The withdrawals can be delayed by the attacker which generates mistrust in the protocol to the users.
I created a test in LiquidityPool.Deposits.t.sol
where it is possible to flood the withdrawalQueue
with zero amount via the queueWithdraw()
function.
function testZeroQueueWithdraw() public { // It is possible to flood the withdrawalQueue with zero amounts in the queueWithdraw() // causing a DOS in the processWithdraws() // // 1. Deposit some money in order to have totalFunds // susd.mint(user_2, 1e20); vm.startPrank(user_2); susd.approve(address(pool), 1e20); pool.deposit(69e18, user_2); vm.stopPrank(); // // 2. Call queueWithdraw with zero withdraw amount // pool.queueWithdraw(0, user_1); pool.queueWithdraw(0, user_2); pool.queueWithdraw(0, user_3); pool.queueWithdraw(0, address(1337)); // // 3. Assert queuedWithdrawalHead() and nextQueuedWithdrawalId() // assertEq(pool.queuedWithdrawalHead(), 1); assertEq(pool.nextQueuedWithdrawalId(), 5); // // 4. Call processWithdraws() // vm.warp(block.timestamp + pool.minWithdrawDelay()); pool.processWithdraws(1); // // 5. Assert the increase of queuedWithdrawalHead() // assertEq(pool.queuedWithdrawalHead(), 2); }
VScode
Check the zero amount value in the LiquidityPool.sol::queueWithdraw()
and KangarooVault.sol::initiateWithdrawal()
functions.
#0 - JustDravee
2023-03-22T17:32:28Z
Seems valid. It's more of a Grief attack than a DOS one but both are still very similar and considered as Medium severity findings.
The POC is easy to understand and runs well. Would've loved lines with vm.expectRevert
to showcase a scenario/story of multiple griefing attacks over multiple minWithdrawDelay
but this is already excellent.
#1 - c4-judge
2023-03-22T17:32:36Z
JustDravee marked the issue as satisfactory
#2 - c4-judge
2023-03-22T17:40:48Z
JustDravee marked the issue as primary issue
#3 - c4-sponsor
2023-04-04T10:58:10Z
mubaris marked the issue as sponsor confirmed
#4 - c4-judge
2023-05-03T01:28:21Z
JustDravee marked issue #123 as primary and marked this issue as a duplicate of 123