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: 9/189
Findings: 8
Award: $1,735.84
π Selected for report: 0
π Solo Findings: 0
π Selected for report: LokiThe5th
Also found by: Nikki, __141345__, mahdikarimi, peakbolt, rvierdiiev, wintermute
1263.2349 USDC - $1,263.23
PerpetualAtlanticVaultLP depositor can avoid losses by redeeminf before settle is called
PerpetualAtlanticVaultLP
users deposit into the contract in order to receive funding payment as yield.
When optin is exercised, that means that PerpetualAtlanticVaultLP
lost funds. Then vault pays option and receives rdpx.
In order to exercise ITM options, PerpetualAtlanticVault.settle
is called. This function processes several options a time. During the process it notifies PerpetualAtlanticVaultLP
about loss and sends rdpx from option buyer. In this moment it means that exchange rate of PerpetualAtlanticVaultLP
has decreased and vault has lost some amount of funds.
In case if arbitrum has frontrunning ability, i would simply say, that attacker can frontrun settle
call and withdraw funds. But even without frontrunning it's possible to detect correct time to withdraw.
Anyone can detect strike prices and amount of options for them. This allows depositor to withdraw from vault, when market price has reached strike price with big amount of options. This will allow him to get better exchange rate. After options will be settled(repaid), then he can deposit again. Such strategy can be used to earn yields, but avoid losses.
VsCode
You can think about mechanism that doesn't allow to withdraw at same epoch.
Error
#0 - c4-pre-sort
2023-09-12T08:32:37Z
bytes032 marked the issue as duplicate of #1781
#1 - c4-judge
2023-10-20T08:06:42Z
GalloDaSballo marked the issue as duplicate of #2130
#2 - c4-judge
2023-10-20T20:05:48Z
GalloDaSballo marked the issue as not a duplicate
#3 - c4-judge
2023-10-20T20:05:56Z
GalloDaSballo marked the issue as duplicate of #1584
#4 - c4-judge
2023-10-21T07:20:52Z
GalloDaSballo marked the issue as satisfactory
#5 - c4-judge
2023-10-21T07:51:11Z
GalloDaSballo changed the severity to 3 (High Risk)
π 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
Attacker can break settling of options by sending funds to the PerpetualAtlanticVaultLP contract
When users deposits to the PerpetualAtlanticVaultLP
, then _totalCollateral
variable is updated, to track amount of deposited assets.
In case if option is ITM, then PerpetualAtlanticVault.settle
is called. This function executes option and notifies PerpetualAtlanticVaultLP
about losses.
function subtractLoss(uint256 loss) public onlyPerpVault { require( collateral.balanceOf(address(this)) == _totalCollateral - loss, "Not enough collateral was sent out" ); _totalCollateral -= loss; }
So this function should decrease _totalCollateral
variable with loss
amount.
Also it checks, that balance of contract is exactly equal to _totalCollateral - loss
.
This condition is super easy to break. It's enough to send smal amount of collateral
and it will revert then.
Once this is done, then subtractLoss
function will always revert and it will be not possible to execute options and backing of DpxEthToken will fail.
Do not use equal comparison.
Error
#0 - c4-pre-sort
2023-09-09T06:26:57Z
bytes032 marked the issue as duplicate of #619
#1 - c4-pre-sort
2023-09-11T16:14:06Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T19:37:40Z
GalloDaSballo marked the issue as satisfactory
π Selected for report: bart1e
Also found by: 0x3b, 0xCiphky, Aymen0909, HHK, Inspex, bin2chen, chaduke, gkrastenov, jasonxiale, josephdara, kodyvim, peakbolt, pep7siup, rokinot, rvierdiiev, tapir
181.367 USDC - $181.37
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV3LiquidityAmo.sol#L324-L336
UniV3LiquidityAmo.recoverERC721 sends tokens to RdpxV2Core, which can't handle them.
UniV3LiquidityAmo.recoverERC721 function will send token from UniV3LiquidityAmo contract to the RdpxV2Core contract.
The problem is that RdpxV2Core is not designed to handle such tokens and there is no ability to send them out and as result they will be stucked there.
VsCode
Add ability to use tokens in RdpxV2Core contract.
Error
#0 - c4-pre-sort
2023-09-12T06:12:07Z
bytes032 marked the issue as duplicate of #935
#1 - c4-judge
2023-10-20T18:05:28Z
GalloDaSballo changed the severity to 3 (High Risk)
#2 - c4-judge
2023-10-20T18:06:01Z
GalloDaSballo marked the issue as satisfactory
π 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
LPs share their earned yields with new depositor.
PerpetualAtlanticVaultLP
depositors provide liquidity, which is used buy PerpetualAtlanticVault
. As reward they receive interests, which is accrued by calling perpetualAtlanticVault.updateFunding
function.
PerpetualAtlanticVaultLP.deposit
function calculates shares, they user will receive at the top of function, before all earned interests were accrued.
As result, exchange rate is incorrect, because it's actually smaller than it is in real, which makes it cheaper for depositor to receive specific amount of shares. Because of that, LPs loss some part of yields to the new depositor.
This makes it's possible for attacker to do flashloan attack in order to grab big part of rewards, when it's profitable(after repaying flash loan fees).
VsCode
Accrue interests before calculating shares.
Error
#0 - c4-pre-sort
2023-09-07T13:46:20Z
bytes032 marked the issue as duplicate of #867
#1 - c4-pre-sort
2023-09-07T13:46:24Z
bytes032 marked the issue as low quality report
#2 - c4-pre-sort
2023-09-11T09:06:28Z
bytes032 marked the issue as sufficient quality report
#3 - c4-judge
2023-10-20T19:56:35Z
GalloDaSballo changed the severity to 3 (High Risk)
#4 - c4-judge
2023-10-20T19:57:09Z
GalloDaSballo marked the issue as satisfactory
π 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
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1192-L1198
RdpxV2Core.calculateBondCost
function doesn't call PerpetualAtlanticVault.updateFundingPaymentPointer
, which can be used by users to pay less amount of premium for the bond.
When user wants to create new bond, then he calls bond
function. First, what this function will do is to calculate needed amount of rdpx and weth that user should provide. This includes premium to create option. Then required weth amount is fetched from user.
Let's check how calculateBondCost
works. This function calculates amount of rdpx and weth that user needs to pay and then it calculates premium that should be paid to hedge required rdpx amount. This is how premium payment is calculated.
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1192-L1198
uint256 timeToExpiry = IPerpetualAtlanticVault( addresses.perpetualAtlanticVault ).nextFundingPaymentTimestamp() - block.timestamp; if (putOptionsRequired) { wethRequired += IPerpetualAtlanticVault(addresses.perpetualAtlanticVault) .calculatePremium(strike, rdpxRequired, timeToExpiry, 0); }
The problem is that IPerpetualAtlanticVault.updateFundingPaymentPointer
is not called in this case, which means that stale latestFundingPaymentPointer
can be used when calling nextFundingPaymentTimestamp()
.
One problem with it is that in case if block.timestamp > nextFundingPaymentTimestamp()
, then call will revert and will not allow user to create bond, until updateFundingPaymentPointer()
will be called.
Another problem is that users can call this function exactly when block.timestamp == nextFundingPaymentTimestamp()
in order to calculate lower premium.
Next important thing that bond
function does is purchasing of option. In this case, latestFundingPaymentPointer
will be updated and premium will be calculated correctly, so core contract will pay bigger amount of premium than user has paid.
In summary, if users will purchase bond when block.timestamp == nextFundingPaymentTimestamp()
, then they will have ability to use RdpxV2Core contract's weth to cover their premium.
VsCode
Call updateFundingPaymentPointer
function before calculating premium to calculate expiration for option
correctly.
Error
#0 - c4-pre-sort
2023-09-09T06:18:36Z
bytes032 marked the issue as primary issue
#1 - c4-pre-sort
2023-09-14T09:35:08Z
bytes032 marked the issue as duplicate of #761
#2 - c4-judge
2023-10-20T12:04:35Z
GalloDaSballo marked the issue as not a duplicate
#3 - c4-judge
2023-10-20T19:14:58Z
GalloDaSballo marked the issue as duplicate of #867
#4 - c4-judge
2023-10-20T19:15:21Z
GalloDaSballo marked the issue as not a duplicate
#5 - c4-judge
2023-10-21T07:11:40Z
GalloDaSballo marked the issue as duplicate of #867
#6 - c4-judge
2023-10-21T07:11:49Z
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
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L975-L990
RdpxV2Core.withdraw doesn't decrease totalWethDelegated, which can be used by attacker to to block using of weth
In case if someone has eth, but doesn't have rdpx, then he can deposit those funds into RdpxV2Core contract, so another person with rdpx can use it to create bond.
Amount of provided funds is accumulated into totalWethDelegated
variable.
When someone uses those funds, then this variable is decreased. However, when delegator withdraws his funds, then totalWethDelegated
is not decreased with withdrawn amount.
Also RdpxV2Core
contract has sync
function which can be called by anyone. It will update balance of each asset and in case of weth, it will not count totalWethDelegated
.
Attacker add one or several delegations and then withdraw, in order to decrease weth balance or make it to be 0. As result, contract will think, that all weth amount belongs to delegators and will not be able to use it, for example to provide funding.
VsCode
Decrease totalWethDelegated
, when delegator withdraws.
Error
#0 - c4-pre-sort
2023-09-07T08:14:29Z
bytes032 marked the issue as duplicate of #2186
#1 - c4-judge
2023-10-20T17:55:32Z
GalloDaSballo changed the severity to 2 (Med Risk)
#2 - c4-judge
2023-10-20T18:01:07Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-21T07:38:54Z
GalloDaSballo changed the severity to 3 (High Risk)
#4 - c4-judge
2023-10-21T07:47:56Z
GalloDaSballo marked the issue as partial-50
π Selected for report: 0xTheC0der
Also found by: 0Kage, 0xDING99YA, 0xHelium, 0xbranded, 836541, ABA, Kow, QiuhaoLi, SpicyMeatball, T1MOH, __141345__, alexfilippov314, ayden, bart1e, bin2chen, chaduke, degensec, jasonxiale, joaovwfreire, nirlin, peakbolt, pep7siup, rvierdiiev, tnquanghuy0512
15.9268 USDC - $15.93
PerpetualAtlanticVault.updateFundingDuration function will break funding.
PerpetualAtlanticVault
works with epoch and each of them lasts for the fundingDuration
amount of time.
This variable is very important in the contract, because it is used to determine when period is finished.
LPs of the PerpetualAtlanticVaultLP
vault receive funding from PerpetualAtlanticVault
. This funding is calculated as amount per second and it depends on fundingDuration
.
So when someone will call updateFunding
function, then funding will be sent to the PerpetualAtlanticVaultLP
contract, according to the rate in second for the amount of seconds that have passed since last update.
Admin can call updateFundingDuration
in order to change epoch duration. Once it will be changed, then rewards er second rate will be corrupted, which will make contract to sent less or more rewards to the LPs, which depends if fundingDuration
is bigger or smaller than previous one.
VsCode
The best solution is to pay funding for the current timestamp, according to the old rate, then recalculate funding per second, using new fundingDuration
and amount that is left for previous fundingDuration
.
Error
#0 - c4-pre-sort
2023-09-08T06:29:15Z
bytes032 marked the issue as duplicate of #980
#1 - c4-pre-sort
2023-09-11T08:22:42Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T11:11:22Z
GalloDaSballo marked the issue as satisfactory
238.7514 USDC - $238.75
PerpetualAtlanticVaultLP depositors don't have ability to signal withdrawing
PerpetualAtlanticVaultLP depositors provide funds that will be used to sell options. They receive yields from premium paid for options.
When user wants to withdraw, then he can call redeem
function. The call will succeed only if there is enough funds in the contract.
So in case if epxEth will have success, then utilization ratio will be about 100%, which means that all funds will be used to write options. In this case users will not have ability to redeem if they want to quit. This will make people wait, when someone new deposits in order to withdraw. This creates some bad user experience.
VsCode
As it is not possible to quit sold options, that means that protocol can't withdraw funds that are locked in options in any way. But protocol can have some percentage of funds(for example 5%) that are never used to write options, but serve as withdraw pool.
Error
#0 - c4-pre-sort
2023-09-13T07:08:10Z
bytes032 marked the issue as duplicate of #2088
#1 - c4-pre-sort
2023-09-13T07:08:16Z
bytes032 marked the issue as sufficient quality report
#2 - c4-pre-sort
2023-09-15T06:55:42Z
bytes032 marked the issue as duplicate of #750
#3 - c4-judge
2023-10-15T18:03:55Z
GalloDaSballo marked the issue as satisfactory
π Selected for report: juancito
Also found by: 0xDING99YA, 0xTiwa, 0xkazim, 0xnev, ABA, ArmedGoose, Aymen0909, Bauchibred, Evo, IceBear, KrisApostolov, MohammedRizwan, Nikki, QiuhaoLi, T1MOH, Toshii, WoolCentaur, Yanchuan, __141345__, asui, bart1e, carrotsmuggler, catellatech, chaduke, codegpt, deadrxsezzz, degensec, dethera, dirk_y, erebus, ether_sky, gjaldon, glcanvas, jasonxiale, josephdara, klau5, kodyvim, ladboy233, lsaudit, minhquanym, parsely, peakbolt, pep7siup, rvierdiiev, said, savi0ur, sces60107, tapir, ubermensch, volodya, zzebra83
19.1724 USDC - $19.17
Rdpx from settled options doesn't earn yields
Stakers of PerpetualAtlanticVaultLP provide weth that is used to write options. In case if option is settled, then weth is sent to the RdpxV2Core and rdpx is sent to the PerpetualAtlanticVaultLP.
Then users can redeem their shares to receive both weth and rdpx.
I believe that most of stakers in PerpetualAtlanticVaultLP would not like to manage their positions often. Because when rdpx is sent, then it can't be used to write options. User should redeem it, then swap to eth and stake eth back. Only then he will continue earn on his locked funds. But this is not convenient for users to do every time. I believe that PerpetualAtlanticVaultLP should have ability to swap all rdpx together to use funds for options again and earn premium.
VsCode
Add ability to swap rdpx to weth to use it.
Error
#0 - c4-pre-sort
2023-09-15T08:41:37Z
bytes032 marked the issue as sufficient quality report
#1 - bytes032
2023-09-15T08:41:45Z
Looks like a recommendation, leaving for judge review.
#2 - c4-sponsor
2023-09-25T17:27:03Z
witherblock marked the issue as disagree with severity
#3 - witherblock
2023-09-25T17:27:07Z
Recommendation not issue
#4 - c4-judge
2023-10-12T08:52:56Z
GalloDaSballo changed the severity to QA (Quality Assurance)
#5 - GalloDaSballo
2023-10-12T08:54:12Z
I like the recommendation, from my experience these come from working in DeFi long enough as the cost of re-investing tends to make it so that a more efficient implementation is always preferred
However
The claimer can re-invest The funds are unlocked
giving them yield is a suggestion but I don't think it's correct to claim that this is a vulnerability
#6 - c4-judge
2023-10-20T18:18:55Z
GalloDaSballo marked the issue as grade-b