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: 146/189
Findings: 2
Award: $7.91
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 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
There is totalWethDelegated
param that accounts for how much of WETH was provided by the delegators. It first increased in addToDelegate()
function and then it's substracted when somebody calls _bondWithDelegate
to bond with their decaying bond and to use delegator's WETH. However, the variable is not updated anyhow when the delegator withdraws his WETH.
addToDelegate()
and deposits 5 WETH:https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L964
totalWethDelegated += _amount;
The variable is now 10.
Then imagine 5 of his WETH was used inside of _bondWithDelegate
so the variable is now 5.
The delegator wants to withdraw the unused WETH and calls withdraw
:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L975-990
But this time the variable is not updated and totalWethDelegated
still 5. Now if someone wants to use this 5 delegated WETH, his tx may revert due to underflow in _bondWithDelegate
:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L720
Manual review.
Update totalWethDelegated
inside of withdraw()
.
Math
#0 - c4-pre-sort
2023-09-07T07:57:49Z
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-20T17:56:26Z
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:46:19Z
GalloDaSballo marked the issue as partial-50
🌟 Selected for report: Vagner
Also found by: 0Kage, 0xCiphky, 0xnev, ABAIKUNANBAEV, Aymen0909, Evo, KmanOfficial, MohammedRizwan, T1MOH, Viktor_Cortess, Yanchuan, ak1, alexzoid, bin2chen, codegpt, hals, ladboy233, mrudenko, nemveer, oakcobalt, peakbolt, pep7siup, qbs, said, savi0ur, tapir, wintermute, zaevlad, zzebra83
7.8372 USDC - $7.84
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L168 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L172 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L210 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L215 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L321
Inside of UniV2LiquidityAmo.sol
, there are several functions that interact with RdpxV2Core.sol
and transfer tokens between the contracts. The problem is that some functions are missing sync()
to update the reserves correctly. For example, sync
is called when rDPX tokens are transferred from ReLPContract to the core after performing swaps:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/reLP/ReLPContract.sol#L306
First of all, it's _sendTokensToRdpxV2Core()
that is called inside of addLiquidity()
, removeLiquidity
and swap
to send the unused tokens back to the RdpxV2Core.sol:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L160-178 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L238 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L286 https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L346
IERC20WithBurn(addresses.tokenA).safeTransfer( addresses.rdpxV2Core, tokenABalance ); IERC20WithBurn(addresses.tokenB).safeTransfer( addresses.rdpxV2Core, tokenBBalance );
Also there are transfers of tokens from RdpxV2Core
to perform liquidity operations in the amo contract. As they are directly transferred from the amo and not from the core, they will not be synchronized correctly:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L210-214
IERC20WithBurn(addresses.tokenA).safeTransferFrom( addresses.rdpxV2Core, address(this), tokenAAmount ); IERC20WithBurn(addresses.tokenB).safeTransferFrom( addresses.rdpxV2Core, address(this), tokenBAmount );
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/amo/UniV2LiquidityAmo.sol#L321-325
IERC20WithBurn(token1).safeTransferFrom( addresses.rdpxV2Core, address(this), token1Amount );
Manual review.
Call sync()
on these functions.
Other
#0 - c4-pre-sort
2023-09-09T03:48:42Z
bytes032 marked the issue as duplicate of #798
#1 - c4-pre-sort
2023-09-09T04:09:22Z
bytes032 marked the issue as duplicate of #269
#2 - c4-pre-sort
2023-09-11T11:58:26Z
bytes032 marked the issue as sufficient quality report
#3 - c4-judge
2023-10-15T18:12:44Z
GalloDaSballo marked the issue as satisfactory
#4 - c4-judge
2023-10-20T19:39:05Z
GalloDaSballo changed the severity to 2 (Med Risk)
🌟 Selected for report: Vagner
Also found by: 0Kage, 0xCiphky, 0xnev, ABAIKUNANBAEV, Aymen0909, Evo, KmanOfficial, MohammedRizwan, T1MOH, Viktor_Cortess, Yanchuan, ak1, alexzoid, bin2chen, codegpt, hals, ladboy233, mrudenko, nemveer, oakcobalt, peakbolt, pep7siup, qbs, said, savi0ur, tapir, wintermute, zaevlad, zzebra83
7.8372 USDC - $7.84
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L941
This issue may look like my another issue about not calling sync() on several functions. In that case, the internal account of reserves was affected. In this issue, it's different as it may lead to the WETH being used on completely different purposes (and possibly lost). The problem is that, in RpdxV2Core.sol
, the sync() function is not called automatically in addToDelegate(). So if it's not called by somebody, the balances will remain not sync. This is a serious issue as in the sync() function the total balance of WETH is synchronized the following way:
https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1002
balance = balance - totalWethDelegated;
Basically, it decreases the WETH reserve balance by totalWethDelegated making it not accessible to be used for different purposes (for example, liquidity provision or pegging of dpxETH / ETH). If the function is not sync
immediately, it opens up a time window when this delegated collateral can be used not for delegating.
addToDelegate()
and deposits 10 WETH. The tokenBalance
of WETH is 20 WETH:https://github.com/code-423n4/2023-08-dopex/blob/main/contracts/core/RdpxV2Core.sol#L1004
reserveAsset[i].tokenBalance = balance;
Now as the function sync()
is not called, the IERC20weth.balanceOf(address(this))
of WETH token will be 30 WETH.
This can lead to this WETH being withdrawn in emergencyWithdraw()
if it's called before sync()
which is unexpected behavior as the initial intention of the delegator was to just delegate his WETH and not for his WETH to be somehow withdrawn.
Manual review.
Add sync()
at the end of the addToDelegate()
function.
Other
#0 - c4-pre-sort
2023-09-14T04:22:53Z
bytes032 marked the issue as duplicate of #269
#1 - c4-judge
2023-10-15T18:12:38Z
GalloDaSballo marked the issue as satisfactory
#2 - c4-judge
2023-10-20T19:39:05Z
GalloDaSballo changed the severity to 2 (Med Risk)