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: 160/189
Findings: 1
Award: $0.07
🌟 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/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L975-L990 https://github.com/code-423n4/2023-08-dopex/blob/eb4d4a201b3a75dd4bddc74a34e9c42c71d0d12f/contracts/core/RdpxV2Core.sol#L995-L1008
Calling 'rdpxV2Core.bondWithDelegate()' with extra WETH and then calling 'rdpxV2Core.withdraw()' to withdraw the unused WETH. After which 'rdpxV2Core.bond()' or 'rdpxV2Core.bondWithDelegate()' is called. The WETH backing reserve value is not correct.
In 'rdpxV2Core.withdraw()', the public variable totalWethDelegated is not reduced. Calling 'rdpxV2Core.sync()' after 'rdpxV2Core.withdraw()' causes arithmetic overflow in line 1002.
A modified test case from tests/rdpxV2-core/Unit.t.sol/testBondWithDelegate()
function testBondWithDelegateWithExtraWeth() public { // assert token reserves (, uint256 rdpxBalance, ) = rdpxV2Core.getReserveTokenInfo("RDPX"); (, uint256 wethBalance, ) = rdpxV2Core.getReserveTokenInfo("WETH"); /// add to delegate with different fees uint256 delegateId = rdpxV2Core.addToDelegate(50 * 1e18, 10 * 1e8); // test bond with delegate uint256[] memory _amounts = new uint256[](1); uint256[] memory _delegateIds = new uint256[](1); _delegateIds[0] = 0; _amounts[0] = 1 * 1e18; // address 1 bonds /// check user balance uint256 userRdpxBalance = rdpx.balanceOf(address(1)); uint256 userWethBalance = weth.balanceOf(address(1)); (uint256 rdpxRequired, uint256 wethRequired) = rdpxV2Core.calculateBondCost( 1 * 1e18, 0 ); vm.prank(address(1)); rdpx.approve(address(rdpxV2Core), 2 * 1e18); vm.prank(address(1), address(1)); (uint256 userAmount, uint256[] memory delegateAmounts) = rdpxV2Core .bondWithDelegate(address(1), _amounts, _delegateIds, 0); // check the correct amounts have been transferred assertEq(rdpx.balanceOf(address(1)), userRdpxBalance - rdpxRequired); assertEq(weth.balanceOf(address(1)), userWethBalance); uint256 amount; uint256 activeCollateral; (, amount, , activeCollateral) = rdpxV2Core.delegates(delegateId); assertEq(amount, 50 * 1e18); assertEq(activeCollateral, wethRequired); rdpxV2Core.withdraw(_delegateIds[0]); //Comment these two lines for the rdpxV2Core.sync(); //test to pass assertEq( rdpxV2ReceiptToken.balanceOf(address(rdpxV2Core)), userAmount + delegateAmounts[0] ); // assert token reserves (, rdpxBalance, ) = rdpxV2Core.getReserveTokenInfo("RDPX"); (, wethBalance, ) = rdpxV2Core.getReserveTokenInfo("WETH"); assertEq(rdpxBalance, 1275 * 1e15); assertGt(wethBalance, 245 * 1e15); }
Manual review and foundry.
'totalWethDelegated' needs to be decremented by the amount of unused WETH withdrawn in 'rdpxV2Core.withdraw()'.
Error
#0 - c4-pre-sort
2023-09-07T07:59:10Z
bytes032 marked the issue as duplicate of #2186
#1 - c4-judge
2023-10-20T17:52:53Z
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:00Z
GalloDaSballo marked the issue as partial-50