Platform: Code4rena
Start Date: 09/02/2024
Pot Size: $60,500 USDC
Total HM: 17
Participants: 283
Period: 12 days
Judge:
Id: 328
League: ETH
Rank: 249/283
Findings: 1
Award: $0.23
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: ahmedaghadi
Also found by: 0x13, 0xAleko, 0xDetermination, 0xKowalski, 0xPluto, 0xRiO, 0xvj, AlexCzm, Avci, BARW, BigVeezus, Cryptor, DeFiHackLabs, Draiakoo, Fitro, Giorgio, GoSlang, Greed, Honour, Kalogerone, KmanOfficial, Krace, McToady, MidgarAudits, MrPotatoMagic, Nyxaris, ReadyPlayer2, Ryonen, SovaSlava, SpicyMeatball, VAD37, _eperezok, alexzoid, almurhasan, btk, cu5t0mpeo, deadrxsezzz, djxploit, dvrkzy, emrekocak, erosjohn, evmboi32, fnanni, grearlake, inzinko, jesjupyter, jesusrod15, josephdara, ke1caM, klau5, ktg, ladboy233, merlinboii, nuthan2x, peanuts, pipidu83, pontifex, radev_sw, sl1, sobieski, soliditywala, t0x1c, taner2344, vnavascues, y4y, yovchev_yoan, zaevlad
0.2347 USDC - $0.23
The claimRewards
function in the MergingPool
contract is vulnerable to a Denial of Service (DoS) attack due to unbounded loops. This can lead to a situation where users are unable to claim their rewards, effectively blocking access to the function.
Consider a scenario where a user manages to become a winner in a large number of rounds. When the claimRewards
function is called, it iterates through all unclaimed rounds for the sender (from 0
to currentRountID
). If the number of iterations is large enough, the transaction may exceed the block gas limit, resulting in a failure to claim rewards.
function claimRewards( //@audit DoS attack string[] calldata modelURIs, string[] calldata modelTypes, uint256[2][] calldata customAttributes ) external { uint256 winnersLength; uint32 claimIndex = 0; uint32 lowerBound = numRoundsClaimed[msg.sender]; for (uint32 currentRound = lowerBound; currentRound < roundId; currentRound++) { numRoundsClaimed[msg.sender] += 1; winnersLength = winnerAddresses[currentRound].length; for (uint32 j = 0; j < winnersLength; j++) { if (msg.sender == winnerAddresses[currentRound][j]) { _fighterFarmInstance.mintFromMergingPool( msg.sender, modelURIs[claimIndex], modelTypes[claimIndex], customAttributes[claimIndex] ); claimIndex += 1; } } } if (claimIndex > 0) { emit Claimed(msg.sender, claimIndex); } }
Manual Analysis
Limit the Number of Rounds Processed: Introduce a parameter that limits the number of rounds that can be processed in a single transaction. This will prevent the function from exceeding the gas limit due to too many iterations.
function claimRewards( string[] calldata modelURIs, string[] calldata modelTypes, uint256[2][] calldata customAttributes, uint32 maxRoundsToProcess // New parameter ) external { uint256 winnersLength; uint32 claimIndex = 0; uint32 lowerBound = numRoundsClaimed[msg.sender]; uint32 upperBound = min(roundId, lowerBound + maxRoundsToProcess); for (uint32 currentRound = lowerBound; currentRound < upperBound; currentRound++) { numRoundsClaimed[msg.sender] += 1; winnersLength = winnerAddresses[currentRound].length; for (uint32 j = 0; j < winnersLength; j++) { if (msg.sender == winnerAddresses[currentRound][j]) { _fighterFarmInstance.mintFromMergingPool( msg.sender, modelURIs[claimIndex], modelTypes[claimIndex], customAttributes[claimIndex] ); claimIndex += 1; } } } if (claimIndex > 0) { emit Claimed(msg.sender, claimIndex); } }
DoS
#0 - c4-pre-sort
2024-02-24T00:04:00Z
raymondfam marked the issue as sufficient quality report
#1 - c4-pre-sort
2024-02-24T00:04:43Z
raymondfam marked the issue as duplicate of #1541
#2 - c4-judge
2024-03-11T13:01:31Z
HickupHH3 marked the issue as duplicate of #216
#3 - c4-judge
2024-03-11T13:08:05Z
HickupHH3 changed the severity to 2 (Med Risk)
#4 - c4-judge
2024-03-12T02:36:26Z
HickupHH3 marked the issue as partial-50
#5 - c4-judge
2024-03-21T02:58:14Z
HickupHH3 marked the issue as satisfactory