Platform: Code4rena
Start Date: 21/08/2023
Pot Size: $125,000 USDC
Total HM: 26
Participants: 189
Period: 16 days
Judge: GalloDaSballo
Total Solo HM: 3
Id: 278
League: ETH
Rank: 64/189
Findings: 4
Award: $187.04
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: klau5
Also found by: 0x3b, 0xCiphky, 0xDING99YA, 0xWaitress, 0xbranded, 0xc0ffEE, 0xklh, 0xsurena, 0xvj, ABA, AkshaySrivastav, Anirruth, Aymen0909, Baki, Blockian, BugzyVonBuggernaut, DanielArmstrong, Evo, GangsOfBrahmin, HChang26, Inspex, Jiamin, Juntao, Kow, Krace, KrisApostolov, LFGSecurity, LokiThe5th, Mike_Bello90, Norah, Nyx, QiuhaoLi, RED-LOTUS-REACH, SBSecurity, Snow24, SpicyMeatball, T1MOH, Tendency, Toshii, Udsen, Yanchuan, __141345__, ak1, asui, auditsea, ayden, bart1e, bin2chen, blutorque, carrotsmuggler, chaduke, chainsnake, circlelooper, clash, codegpt, crunch, degensec, dirk_y, ge6a, gjaldon, grearlake, jasonxiale, juancito, ke1caM, kodyvim, kutugu, ladboy233, lanrebayode77, mahdikarimi, max10afternoon, mert_eren, nirlin, nobody2018, oakcobalt, parsely, peakbolt, pks_, pontifex, ravikiranweb3, rokinot, rvierdiiev, said, savi0ur, sces60107, sh1v, sl1, spidy730, tapir, tnquanghuy0512, ubermensch, visualbits, volodya, wintermute
0.0098 USDC - $0.01
An attacker can brick the subtractLoss
function, which is called in the settle
function of the PerpetualAtlanticVault
contract, so settle
will also be bricked.
1 Wei
to the PerpetualAtlanticVaultLP
contract directly.subtractLoss
function will always fail
require( collateral.balanceOf(address(this)) == _totalCollateral - loss);
subtractLoss
function will always revert.function subtractLoss(uint256 loss) public onlyPerpVault { require( // @audit strict equality will break this require if an attacker makes direct transfer collateral.balanceOf(address(this)) == _totalCollateral - loss, "Not enough collateral was sent out" ); _totalCollateral -= loss; }
Manual Review
function subtractLoss(uint256 loss) public onlyPerpVault { require( + collateral.balanceOf(address(this)) >= _totalCollateral - loss, - collateral.balanceOf(address(this)) == _totalCollateral - loss, "Not enough collateral was sent out" ); _totalCollateral -= loss; }
DoS
#0 - c4-pre-sort
2023-09-09T09:54:04Z
bytes032 marked the issue as duplicate of #619
#1 - c4-pre-sort
2023-09-11T16:14:18Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-21T07:15:55Z
GalloDaSballo marked the issue as satisfactory
🌟 Selected for report: LokiThe5th
Also found by: 0xPsuedoPandit, 0xTiwa, 0xnev, 0xvj, Evo, Jiamin, Juntao, QiuhaoLi, T1MOH, Udsen, circlelooper, crunch, eeshenggoh, gjaldon, hals, josephdara, kutugu, minhtrng, niki, umarkhatab_465
96.3292 USDC - $96.33
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L382 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L373
getLpTokenBalanceInWeth()
will return incorrect value.
Because if precision of getLpPrice()
is 1e18
then (lpTokenBalance * getLpPrice())
in getLpTokenBalanceInWeth()
should be divided by 1e18 as the number of decimals in a LP token are 1e18
.
function getLpPrice() public view returns (uint256) { // @audit here getLpPriceInEth's precision is not 1e8 its 1e18 return IRdpxEthOracle(addresses.rdpxOracle).getLpPriceInEth(); }
In UniV2LiquidityAmo.sol
contract's getLpPrice()
function it is assumed that the precision getLpPriceInEth()
function of RdpxEthOracle
is 1e8
but the actual precision of that function is 1e18
.
Due to this false assumption instead of dividing (lpTokenBalance * getLpPrice())
by 1e18
they are dividing it by 1e8
in getLpTokenBalanceInWeth()
function.
Due to this getLpTokenBalanceInWeth()
precision will 1e28
but the precision of actual WETH
token is 1e18
function getLpTokenBalanceInWeth() external view returns (uint256) { return (lpTokenBalance * getLpPrice()) / 1e8; }
Manual Review
If the return value of getLpPrice()
needs to be in 1e8
precision divide the return value by 1e10
before returning.
Decimal
#0 - c4-pre-sort
2023-09-09T05:07:34Z
bytes032 marked the issue as duplicate of #549
#1 - c4-pre-sort
2023-09-12T05:17:16Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T18:28:00Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-20T18:28:12Z
GalloDaSballo changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-10-20T18:28:21Z
GalloDaSballo changed the severity to 3 (High Risk)
🌟 Selected for report: LokiThe5th
Also found by: 0xPsuedoPandit, 0xTiwa, 0xnev, 0xvj, Evo, Jiamin, Juntao, QiuhaoLi, T1MOH, Udsen, circlelooper, crunch, eeshenggoh, gjaldon, hals, josephdara, kutugu, minhtrng, niki, umarkhatab_465
96.3292 USDC - $96.33
calls to settle function will fail even though underlying price is less than the strike price.
function getUnderlyingPrice() public view returns (uint256) { // @audit returns price in 1e18 precision return IRdpxEthOracle(addresses.assetPriceOracle).getRdpxPriceInEth(); }
RdpxOracle.sol
/// @notice Returns the price of rDPX in ETH /// @return price price of rDPX in ETH in 1e18 decimals function getRdpxPriceInEth() external view override returns (uint price) { require( blockTimestampLast + timePeriod + nonUpdateTolerance > block.timestamp, "RdpxEthOracle: UPDATE_TOLERANCE_EXCEEDED" ); price = consult(token0, 1e18); require(price > 0, "RdpxEthOracle: PRICE_ZERO"); }
getUnderlyingPrice()
function in PerpetualAtlanticVault
contract returns the price of Rdpx
(underlying) in 1e18
precision.
The precision of strike prices is 1e8 but the precision of underlying price 1e18 as we can see it in the above code.
Because of this calls to settle function will fail even though the underlying price is less than strike price as the below validation will fail because of inconsistent precisions.
_validate(strike >= getUnderlyingPrice(), 7)
Due this precision inconsistency calculations many places will go wrong.
Manual Review
Divide the return value of getUnderlyingPrice()
by 1e10
to scale it down from 1e18
precision to 1e8
precision.
Decimal
#0 - c4-pre-sort
2023-09-09T05:07:38Z
bytes032 marked the issue as duplicate of #549
#1 - c4-pre-sort
2023-09-12T05:17:29Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T18:28:03Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-20T18:28:12Z
GalloDaSballo changed the severity to 2 (Med Risk)
#4 - c4-judge
2023-10-20T18:28:21Z
GalloDaSballo changed the severity to 3 (High Risk)
🌟 Selected for report: 0xrafaelnicolau
Also found by: 0x111, 0xCiphky, 0xMosh, 0xWaitress, 0xc0ffEE, 0xkazim, 0xnev, 0xvj, ABAIKUNANBAEV, Aymen0909, Baki, ElCid, HChang26, HHK, Inspex, Jorgect, Kow, Krace, KrisApostolov, LFGSecurity, MiniGlome, Nyx, QiuhaoLi, RED-LOTUS-REACH, Talfao, Toshii, Vagner, Viktor_Cortess, Yanchuan, _eperezok, asui, atrixs6, bart1e, bin2chen, carrotsmuggler, chaduke, chainsnake, deadrxsezzz, degensec, dethera, dimulski, dirk_y, ether_sky, gizzy, glcanvas, grearlake, gumgumzum, halden, hals, kodyvim, koo, ladboy233, lanrebayode77, max10afternoon, minhtrng, mussucal, nobody2018, peakbolt, pontifex, qbs, ravikiranweb3, rvierdiiev, said, tapir, ubermensch, volodya, wintermute, yashar, zaevlad, zzebra83
0.0734 USDC - $0.07
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L964 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L975-L990 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/reLP/ReLPContract.sol#L306 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L873
reLP
function of ReLp
contract , which calls the sync
function, will also be bricked.bond
and bondWithDelegate
functions, which call the reLP
function, will also be bricked.addToDelegate
method.totalWethDelegated
will be incremented by that amount because of this line
totalWethDelegated += _amount;
.withdraw
function.totalWethDelegated
will not be decreased as it is not being decremented in withdraw function.sync
function will always revert because of underflow in this line.Manual Review
function withdraw( uint256 delegateId ) external returns (uint256 amountWithdrawn) { _whenNotPaused(); _validate(delegateId < delegates.length, 14); Delegate storage delegate = delegates[delegateId]; _validate(delegate.owner == msg.sender, 9); amountWithdrawn = delegate.amount - delegate.activeCollateral; _validate(amountWithdrawn > 0, 15); delegate.amount = delegate.activeCollateral; IERC20WithBurn(weth).safeTransfer(msg.sender, amountWithdrawn); + totalWethDelegated -= amountWithdrawn emit LogDelegateWithdraw(delegateId, amountWithdrawn); }
DoS
#0 - bytes032
2023-09-07T07:44:59Z
Tries to explain #2186, but differently. Poor explanation. No runnable POC. Partial IMO.
#1 - c4-pre-sort
2023-09-07T07:45:07Z
bytes032 marked the issue as low quality report
#2 - c4-pre-sort
2023-09-07T07:46:12Z
bytes032 marked the issue as duplicate of #2186
#3 - c4-judge
2023-10-20T17:53:09Z
GalloDaSballo marked the issue as satisfactory
#4 - c4-judge
2023-10-20T17:55:32Z
GalloDaSballo changed the severity to 2 (Med Risk)
#5 - c4-judge
2023-10-21T07:38:54Z
GalloDaSballo changed the severity to 3 (High Risk)
#6 - c4-judge
2023-10-21T07:42:36Z
GalloDaSballo marked the issue as partial-50
🌟 Selected for report: QiuhaoLi
Also found by: 0xDING99YA, 0xvj, SBSecurity, T1MOH, Toshii, Udsen, bart1e, bin2chen, carrotsmuggler, pep7siup, said, sces60107, wintermute
90.6302 USDC - $90.63
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L545-L550
swaps will fail or execute with higher slippage than intended.
In _curveSwap()
function of RdpxV2Core
contract , getEthPrice()
should be used in place of getDpxEthPrice()
, and getDpxEthPrice()
should be used in place of getEthPrice()
.
/** * @notice Returns the price of dpxETH against ETH * @dev Price is in 1e8 Precision * @return dpxEthPrice dpxETH price **/ function getDpxEthPrice() public view returns (uint256 dpxEthPrice) { return IDpxEthOracle(pricingOracleAddresses.dpxEthPriceOracle) .getDpxEthPriceInEth(); }
getDpxEthPrice
function returns the price of 1 dpxETH in ETH.
/** * @notice Returns the price of ETH token against the DpxEth * @dev Price is in 1e8 Precision * @return ethPrice ethToken price **/ function getEthPrice() public view returns (uint256 ethPrice) { return IDpxEthOracle(pricingOracleAddresses.dpxEthPriceOracle) .getEthPriceInDpxEth(); }
getEthPrice
returns the price of 1 ETH in dpxETH.
lets say 1 ETH
= 2 dpxETH
so 1 dpxETH
= 0.5 ETH
So getEthPrice
function returns 2 because 1 ETH
= 2 dpxETH
.
And getDpxEthPrice
function returns 0.5 because 1 dpxETH
= 0.5 ETH
.
If we try to swap 1 ETH
into dpxETH
the minAmount should represent how much dpxETH
we should get so it should be around 2 with a slippage of 0.5 percent.
// calculate minimum amount out uint256 minOut = _ethToDpxEth ? (((_amount * getDpxEthPrice()) / 1e8) - (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16)) : (((_amount * getEthPrice()) / 1e8) - (((_amount * getEthPrice()) * slippageTolerance) / 1e16));
But if we calculate minOut
according above code
minOut = 1 * getDpxEthPrice - 1 * getDpxEthPrice * (0.5/100) = (1 * 0.5) - (1 * 0.5 * 0.5/100) = 0.4975
avoiding all the decimals hell and considering slippage as 0.5
Here we are getting minOut
as 0.4975
instead of getting a value around 2. If the slippage calculation is correct we should get a value around 2 because current market value of 1 ETH
is 2 dpxETH
.So if we are swapping from 1 ETH to dpxETH minOut should be around 2 with 0.5% slippage.
Manual Review
// calculate minimum amount out uint256 minOut = _ethToDpxEth - ? (((_amount * getDpxEthPrice()) / 1e8) - - (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16)) - : (((_amount * getEthPrice()) / 1e8) - - (((_amount * getEthPrice()) * slippageTolerance) / 1e16)); + ? (((_amount * getEthPrice()) / 1e8) - + (((_amount * getEthPrice()) * slippageTolerance) / 1e16)) + : (((_amount * getDpxEthPrice()) / 1e8) - + (((_amount * getDpxEthPrice()) * slippageTolerance) / 1e16));
Math
#0 - c4-pre-sort
2023-09-10T10:03:14Z
bytes032 marked the issue as duplicate of #2172
#1 - c4-pre-sort
2023-09-12T04:28:08Z
bytes032 marked the issue as sufficient quality report
#2 - c4-pre-sort
2023-09-12T04:38:09Z
bytes032 marked the issue as duplicate of #970
#3 - c4-judge
2023-10-18T12:33:41Z
GalloDaSballo marked the issue as satisfactory