Platform: Code4rena
Start Date: 14/06/2022
Pot Size: $50,000 USDC
Total HM: 19
Participants: 99
Period: 5 days
Judge: HardlyDifficult
Total Solo HM: 4
Id: 136
League: ETH
Rank: 45/99
Findings: 3
Award: $91.32
π Selected for report: 0
π Solo Findings: 0
π Selected for report: hyh
Also found by: 0x29A, 0xNineDec, 0xf15ers, 0xkowloon, GreyArt, IllIllI, KIntern, Kenshin, Lambda, WatchPug, Wayne, berndartmueller, byterocket, cccz, codexploder, horsefacts, kenzo, obront, obtarian, oyc_109, peritoflores, rajatbeladiya, rfa, saian, unforgiven, zer0dot
11.084 USDC - $11.08
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1230 https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L346
Detailed description of the impact of this finding.
rescueETH() is a function used to rescue the Ether funds present in the InfinityStaker & InfinityExchange contracts, however, it does not work as expected and sends msg.value (Ether sent by the owner) to the destination.
This will result in a lack of timely access to Ether funds in the event of an emergency, further leading to a hack.
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L1230
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/staking/InfinityStaker.sol#L346
function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: msg.value}(''); require(sent, 'failed'); }
Replace the code of the function with
function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: address(this).balance}(''); require(sent, 'failed'); }
done.
function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: msg.value}(''); require(sent, 'failed'); }
Replace the code of the function with
function rescueETH(address destination) external payable onlyOwner { (bool sent, ) = destination.call{value: address(this).balance}(''); require(sent, 'failed'); }
#0 - nneverlander
2022-06-22T11:18:59Z
Duplicate
#1 - HardlyDifficult
2022-07-09T16:41:43Z
π Selected for report: joestakey
Also found by: 0x1f8b, 0x29A, 0x52, 0xDjango, 0xNazgul, 0xNineDec, 0xf15ers, 0xkowloon, 0xmint, 8olidity, BowTiedWardens, Chom, Cityscape, Czar102, ElKu, FSchmoede, Funen, GimelSec, GreyArt, IllIllI, KIntern, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, Ruhum, Sm4rty, StErMi, TerrierLover, TomJ, Treasure-Seeker, VAD37, WatchPug, Wayne, _Adam, a12jmx, abhinavmir, antonttc, apostle0x01, asutorufos, berndartmueller, cccz, cloudjunky, codexploder, cryptphi, csanuragjain, defsec, delfin454000, fatherOfBlocks, georgypetrov, hake, hansfriese, horsefacts, hyh, k, kenta, nxrblsrpr, oyc_109, peritoflores, rajatbeladiya, reassor, rfa, robee, sach1r0, saian, samruna, shenwilly, simon135, sorrynotsorry, sseefried, throttle, unforgiven, wagmi, zzzitron
49.0062 USDC - $49.01
https://github.com/code-423n4/2022-06-infinity/blob/main/contracts/core/InfinityExchange.sol#L379
Detailed description of the impact of this finding.
cancelAllOrders()
is used to cancel all pending orders, however, the value of userMinOrderNonce[caller] is in the range of next + 1000000 which means that userMinOrderNonce can be set arbitrarily, resulting in the cancelMultipleOrders() function not being called successfully.
function cancelAllOrders(uint256 minNonce) external { require(minNonce > userMinOrderNonce[msg.sender], 'nonce too low'); require(minNonce < userMinOrderNonce[msg.sender] + 1000000, 'too many'); userMinOrderNonce[msg.sender] = minNonce; emit CancelAllOrders(msg.sender, minNonce); }
function cancelMultipleOrders(uint256[] calldata orderNonces) external { uint256 numNonces = orderNonces.length; require(numNonces > 0, 'cannot be empty'); for (uint256 i = 0; i < numNonces; ) { require(orderNonces[i] >= userMinOrderNonce[msg.sender], 'nonce too low'); require(!isUserOrderNonceExecutedOrCancelled[msg.sender][orderNonces[i]], 'nonce already executed or cancelled'); isUserOrderNonceExecutedOrCancelled[msg.sender][orderNonces[i]] = true; unchecked { ++i; } } emit CancelMultipleOrders(msg.sender, orderNonces); }
e,g.
Step 1.
minNonce(999999) > userMinOrderNonce[msg.sender]=0
minNonce(999999) < 0 + 1000000
userMinOrderNonce[msg.sender] = 999999
Step 2.
minNonce(1999998) > userMinOrderNonce[msg.sender]=999999
minNonce(1999998) < 999999 + 1000000
userMinOrderNonce[msg.sender] = 1999999
The principle is the current value + 1000000 - 1.
Provide direct links to all referenced code in GitHub. Add screenshots, logs, or any other relevant proof that illustrates the concept.
Set a maximum limit, i.e. the user's current nonce + 1000000 must not exceed the limit
#0 - nneverlander
2022-06-22T18:16:32Z
Not a bug
#1 - HardlyDifficult
2022-07-09T20:06:07Z
This is a fair consideration. Lowering risk and converting this into a QA report for the warden.
#2 - HardlyDifficult
2022-07-09T20:31:59Z
π Selected for report: IllIllI
Also found by: 0v3rf10w, 0x1f8b, 0x29A, 0xAsm0d3us, 0xDjango, 0xKitsune, 0xNazgul, 0xf15ers, 0xkatana, 0xkowloon, BowTiedWardens, Chom, ElKu, FSchmoede, Funen, GimelSec, Kaiziron, Kenshin, Lambda, MadWookie, MiloTruck, PPrieditis, Picodes, PwnedNoMore, StErMi, Tadashi, TerrierLover, TomJ, Tomio, Wayne, Waze, _Adam, antonttc, apostle0x01, asutorufos, c3phas, codexploder, defsec, delfin454000, fatherOfBlocks, hake, hansfriese, hyh, joestakey, k, kenta, oyc_109, peritoflores, reassor, rfa, robee, sach1r0, simon135, slywaters, zer0dot
31.2269 USDC - $31.23
Title:
INFINITY_TOKEN global variable mutability to immutable
Content:
I noticed that other contracts use immutable to optimize gas consumption, and the only global variable in the InfinityStaker.sol contract that will change during the deployment phase and not change later is not set to immutable, so I suggest changing the mutability of INFINITY_TOKEN to immutable.