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: 134/189
Findings: 3
Award: $17.39
🌟 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
PerpetualAtlanticVault.settle()
is susceptible to frontrunning which could cause the function to revert due to a call made to PerpetualAtlanticVaultLP.subtractLoss()
.
After transferring WETH from PerpetualAtlanticVaultLP
to the RdpxV2Core
, and RDPX is transferred from RdpxV2Core
to the PerpetualAtlanticVaultLP
, PerpetualAtlanticVaultLP.subtractLoss()
is triggered to deduct the transferred WETH from _totalCollateral
.
The problem with PerpetualAtlanticVaultLP.subtractLoss()
function is the check that requires collateral.balanceOf(address(this)) == _totalCollateral - loss
, this check can be easily made to fail by sending dust(little) amount of WETH to the PerpetualAtlanticVaultLP contract address directly which will not be accounted for in _totalCollateral
.
require( collateral.balanceOf(address(this)) == _totalCollateral - loss, "Not enough collateral was sent out" );
Manual review.
Consider changing the equality sign to less or equal.
require( collateral.balanceOf(address(this)) <= _totalCollateral - loss, "Not enough collateral was sent out" );
DoS
#0 - c4-pre-sort
2023-09-09T06:49:42Z
bytes032 marked the issue as duplicate of #619
#1 - c4-pre-sort
2023-09-11T16:14:11Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T20:02:06Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-21T07:26:28Z
GalloDaSballo changed the severity to 3 (High Risk)
#4 - c4-judge
2023-10-21T07:26:28Z
GalloDaSballo changed the severity to 3 (High Risk)
#5 - c4-judge
2023-10-21T07:26:28Z
GalloDaSballo changed the severity to 3 (High Risk)
#6 - c4-judge
2023-10-21T07:26:28Z
GalloDaSballo changed the severity to 3 (High Risk)
#7 - c4-judge
2023-10-21T07:26:29Z
GalloDaSballo changed the severity to 3 (High Risk)
🌟 Selected for report: said
Also found by: 0Kage, 0xCiphky, 0xkazim, 836541, AkshaySrivastav, Evo, HChang26, HHK, KrisApostolov, Neon2835, QiuhaoLi, Tendency, Toshii, bart1e, bin2chen, carrotsmuggler, chaduke, etherhood, gjaldon, glcanvas, josephdara, lanrebayode77, mahdikarimi, max10afternoon, nobody2018, peakbolt, qpzm, rvierdiiev, sces60107, tapir, ubermensch, volodya
17.313 USDC - $17.31
Whenever shares are redeemed in PerpetualAtlanticVaultLP, there's an accounting deficit that causes a revert in PerpetualAtlanticVaultLP.addProceeds()
, leading to a denial of service in multiple functions that makes calls to PerpetualAtlanticVaultLP.addProceeds()
through PerpetualAtlanticVault.updateFunding()
like; PerpetualAtlanticVault.purchase()
, PerpetualAtlanticVault.settle()
, PerpetualAtlanticVaultLP.deposit()
, and PerpetualAtlanticVaultLP.redeem()
PerpetualAtlanticVaultLP.deposit()
where funds is transferred from user to the contract and _totalCollatera
is updated(increamented). https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L128-L132// Need to transfer before minting or ERC777s could reenter. collateral.transferFrom(msg.sender, address(this), assets); _mint(receiver, shares); _totalCollateral += assets;
_rdpxCollateral
is updated(decremented) but _totalCollateral
is not. https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L162-L175_rdpxCollateral -= rdpxAmount; beforeWithdraw(assets, shares); _burn(owner, shares); collateral.transfer(receiver, assets); IERC20WithBurn(rdpx).safeTransfer(receiver, rdpxAmount); emit Withdraw(msg.sender, receiver, owner, assets, shares);
PerpetualAtlanticVaultLP.addProceeds()
a check is done to assert that balanceOf Collateral is equal or greater than _totalCollateral + proceeds
, this will NEVER hold if shares have been redeemed. https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/perp-vault/PerpetualAtlanticVaultLP.sol#L191-L194require( collateral.balanceOf(address(this)) >= _totalCollateral + proceeds, "Not enough collateral token was sent" );
--Alice makes a deposit of 100 collateral token to get equivalent shares, this increases _totalCollateral
by 100.
--Alice redeems 50% of her shares to get 50 collateral token transferred back to her by the contract, reducing the contract balance by 50 but no corresponding decrease in _totalCollateral
.
--So whenever collateral.balanceOf(address(this)) >= _totalCollateral + proceeds
is checked, _totalCollateral will still hold 100+, so the check always fails.
--The ripple effect is that all function that relies on the check fails.
Manual review.
Update _totalCollateral after transferring collateral to the redeemer.
_totalCollateral -= assets;
Token-Transfer
#0 - c4-pre-sort
2023-09-13T12:44:03Z
bytes032 marked the issue as duplicate of #867
#1 - c4-judge
2023-10-20T19:26:19Z
GalloDaSballo marked the issue as satisfactory
🌟 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
RdpxV2Core.sync()
will fail if a whale delegate withdraws a large amount of WETH or WETH reserve balance gets updated with a wrong value when a smaller withdrawal is made due to un-updated totalWethDelegated in the withdraw() function.
Another problem this will cause is that RdpxV2Core.bond()
and RdpxV2Core.bondWithDelegate()
will revert because they both make a call to ReLPContrac.reLp()
function which calls the RdpxV2Core.sync()
, this will also cause both functions to fail if isReLPActive is true.
addDelegate()
and deposits WETH, totalWethDelegated
is incremented with the deposited amount.
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L963-L964// add amount to total weth delegated totalWethDelegated += _amount;
bondWithDelegate()
, a call is made to _bondWithDelegate()
that decrements the totalWethDelegated
by the amount of WETH required for the bonding.
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L719-L720// update total weth delegated totalWethDelegated -= wethRequired;
withdraw()
, available WETH is sent to the delegate without updating(decrement) the totalWethDelegated
by the withdrawn amount.The problem is that, when syn()
is called, it checks for WETH and decrements the balance by totalWethDelegated
. If a withdrawal was made, the contract WETH balance will reduce by the withdrawn amount and the calculated balance will give wrong value, in a case where a whale delegate makes a huge withdrawal the function will fail due to an overflow exception error.
--Alice calls addDelegate()
to deposit 1000WETH, totalWethDelegated
increased by 1000
--10WETH was used for bonding so totalWethDelegated
reduces to 990WETH
--She withdrew 990WETH but totalWethDelegated
remains the same
--syn()
is called and WETH balance was 300WETH, but balance = balance - totalWethDelegated
is 300 - 990(instead of 300 - 0 = 300) which will cause the entire function to revert due to solidity prevention of overflow.
-- If the withdrawn amount is lower(let's say 200), WETH balance will be updated with a wrong value of 1100 - 200 = 900 instead of 1100 - 0 = 1100
https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L1001-L1004
if (weth == reserveAsset[i].tokenAddress) { balance = balance - totalWethDelegated; } reserveAsset[i].tokenBalance = balance; }
Manual review.
Update totalWethDelegated
during withdrawals
totalWethDelegated -= wethRequired;
Math
#0 - c4-pre-sort
2023-09-08T13:28:03Z
bytes032 marked the issue as duplicate of #2186
#1 - c4-judge
2023-10-20T17:55:50Z
GalloDaSballo marked the issue as satisfactory
#2 - c4-judge
2023-10-21T07:38:54Z
GalloDaSballo changed the severity to 3 (High Risk)
#3 - c4-judge
2023-10-21T07:45:55Z
GalloDaSballo marked the issue as partial-50