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: 107/189
Findings: 3
Award: $58.67
🌟 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
One user add delegate by calling addToDelegate()
function with some weth.
After some time, that user withdraw the remaining weth by calling withdraw()
function.
The problem here is that totalWethDelegated
variable is updated only in addToDelegate()
function not in withdraw()
.
And call sync()
function.
Then reserveAsset[reservesIndex["WETH"]].tokenBalance
is updated incorrectly and once it has done, it is not revertable.
please add below function to 'tests/rdpxV2-core/Unit.t.sol' and run 'forge test'.
function testTotalWethDelegated() public { rdpxV2Core.bond(10 * 1e18, 0, address(this)); uint256 userBalanceBeforeDelegate = weth.balanceOf(address(rdpxV2Core)); (, uint256 wethReserveBeforeDelegate, ) = rdpxV2Core .getReserveTokenInfo("WETH"); // reserveAsset[reservesIndex["WETH"]].tokenBalance > 1e18 assertGt(wethReserveBeforeDelegate, 1e18); rdpxV2Core.addToDelegate(1 * 1e18, 10e8); uint256 userBalanceAfterDelegate = weth.balanceOf(address(rdpxV2Core)); (, uint256 wethReserveAfterDelegate, ) = rdpxV2Core.getReserveTokenInfo( "WETH" ); // real balance changes, but reserveAsset[reservesIndex["WETH"]].tokenBalance doesn't change assertEq(userBalanceAfterDelegate, userBalanceBeforeDelegate + 1e18); assertEq(wethReserveBeforeDelegate, wethReserveAfterDelegate); rdpxV2Core.withdraw(0); (, uint256 wethReserveAfterWithdraw, ) = rdpxV2Core.getReserveTokenInfo( "WETH" ); // reserveAsset[reservesIndex["WETH"]].tokenBalance doesn't change assertEq(wethReserveBeforeDelegate, wethReserveAfterWithdraw); rdpxV2Core.sync(); (, uint256 wethReserveAfterSync, ) = rdpxV2Core.getReserveTokenInfo( "WETH" ); /** 1e18 was removed from 'reserveAsset[reservesIndex["WETH"]].tokenBalance' because 'totalWethDelegated' didn't change when 'withdraw' delegate. This is obviously error. */ assertEq(wethReserveAfterSync, wethReserveAfterWithdraw - 1e18); }
Manual audit
Should add below code to withdraw()
function.
totalWethDelegated -= amountWithdrawn;
Error
#0 - c4-pre-sort
2023-09-07T08:19:20Z
bytes032 marked the issue as duplicate of #2186
#1 - c4-judge
2023-10-20T17:52:57Z
GalloDaSballo marked the issue as satisfactory
#2 - c4-judge
2023-10-20T17:55:32Z
GalloDaSballo changed the severity to 2 (Med Risk)
#3 - c4-judge
2023-10-21T07:38:54Z
GalloDaSballo changed the severity to 3 (High Risk)
#4 - c4-judge
2023-10-21T07:41:25Z
GalloDaSballo marked the issue as partial-50
🌟 Selected for report: bin2chen
Also found by: 0Kage, 0xDING99YA, QiuhaoLi, Toshii, Yanchuan, carrotsmuggler, deadrxsezzz, ether_sky, flacko, gjaldon, kutugu, mert_eren, pep7siup, qpzm, said, sces60107, tapir, ubermensch
39.433 USDC - $39.43
If the rDPX price is higher than EDH (if possible), the expected amount of token A cannot be exchanged because this incorrect value is higher than the correct value. This means it violates the reLP logic.
Since rDPX prices are usually much lower than EDH, this incorrect value is less than the correct value, so you can swap less than you expect.
tokenBAmount = tokenAAmount * tokenAPrice / 1e8
tokenAAmount = tokenBAmount * 1e8 / tokenAPrice
For example:
tokenAPrice = 1e6
(i.e. 1 tokenB = 100 tokenA
)
And we want to swap 1e18 tokenB for tokenA. (We are gonna ignore slippage.)
The calculated value in code : tokenA = tokenB * tokenAPrice / 1e8 = 1e18 * 1e6 / 1e8 = 1e16
This means that token A is more valuable than tokenB.
Actual value will be tokenB * 1e8 / tokenAPrice = 1e20
Manual audit
mintokenAAmount = (((amountB / 2) * 1e8) / tokenAInfo.tokenAPrice) - (((amountB / 2) * 1e8) / tokenAInfo.tokenAPrice) * slippageTolerance / 1e8;
Error
#0 - c4-pre-sort
2023-09-10T10:41:37Z
bytes032 marked the issue as duplicate of #1805
#1 - c4-pre-sort
2023-09-11T07:04:44Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-20T09:23:53Z
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
When the 'nextFundingPaymentTimestamp()' is less than 'block.timestamp', we can't bond due to we get 'Arithmetic over/underflow'. As far as I understood, the 'latestFundingPaymentPointer' doesn't be updated automatically. In order to bond, the 'latestFundingPaymentPointer' should be updated in Vault.
Please add below function to 'tests/rdpxV2-core/Unit.t.sol' and run 'forge test'.
function testBondInNextEpoch() public { vault.updateFundingPaymentPointer(); // move to future epoch, 'latestFundingPaymentPointer' didn't be updated yet. skip(2 * vault.fundingDuration()); // failed with 'Arithmetic over/underflow' error. rdpxV2Core.bond(1 * 1e18, 0, address(this)); }
Manual audit
Add below line to 'IPerpetualAtlanticVault'.
function updateFundingPaymentPointer() external;
And add below lines before calling calculateBondCost()
function in the core.
IPerpetualAtlanticVault(addresses.perpetualAtlanticVault) .updateFundingPaymentPointer();
Under/Overflow
#0 - c4-pre-sort
2023-09-10T12:06:07Z
bytes032 marked the issue as duplicate of #1793
#1 - c4-pre-sort
2023-09-11T07:22:44Z
bytes032 marked the issue as sufficient quality report
#2 - c4-judge
2023-10-15T18:24:18Z
GalloDaSballo marked the issue as satisfactory
#3 - c4-judge
2023-10-26T11:19:31Z
GalloDaSballo changed the severity to QA (Quality Assurance)