Platform: Code4rena
Start Date: 25/01/2023
Pot Size: $36,500 USDC
Total HM: 11
Participants: 173
Period: 5 days
Judge: kirk-baird
Total Solo HM: 1
Id: 208
League: ETH
Rank: 91/173
Findings: 2
Award: $19.45
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: adriro
Also found by: 0xRobocop, 0xmrhoodie, 0xngndev, AkshaySrivastav, ArmedGoose, Atarpara, Bauer, CodingNameKiki, ElKu, Garrett, HollaDieWaldfee, IllIllI, Iurii3, KIntern_NA, KmanOfficial, Lotus, M4TZ1P, MiniGlome, Ruhum, SovaSlava, bin2chen, bytes032, carrotsmuggler, cccz, chaduke, codeislight, cryptonue, doublesharp, evan, fs0c, glcanvas, gzeon, hansfriese, hihen, hl_, holme, horsefacts, ladboy233, lukris02, mahdikarimi, manikantanynala97, martin, mert_eren, mrpathfindr, omis, peakbolt, peanuts, prestoncodes, rbserver, rvierdiiev, sashik_eth, timongty, tnevler, trustindistrust, usmannk, wait, yixxas, zadaru13, zaskoh
0.7512 USDC - $0.75
Owner can steal reward from the unclaimed receipt after the end quest and unclaimed receipt should not be able to claim their rewards
As per natspec docs on withdrawRemainingTokens()
every receipt minted still able to claim their rewards and cann't be withdrawn owner but he can run withdrawFee() multiple times steal rewards from unclaimed receipt
/// @notice Function that allows the owner to withdraw the remaining tokens in the contract /// @dev Every receipt minted should still be able to claim rewards (and cannot be withdrawn). This function can only be called after the quest end time /// @param to_ The address to send the remaining tokens to function withdrawRemainingTokens(address to_) public override onlyOwner { ...}
There are multiple scenario to leading this issue. I am explaining one of them.
For Example:
totalParticipants_ = 10
, rewardAmountOrTokenId_ = 10e18
, questFee=2000
.120e18
reward token for starting quest (maxTotalRewards = 100e18, maxProtocolReward = 20e18) receiptRedeemers() = 7
and protocolFee = 14e18 ( 7 *10e18*2000/10000)
now contract balance is 120e18 - 50e18 = 70e18
36e18
Calculation :
unclaimedTokens = 20e18 nonClaimableTokens = 70e18(balance) - 14e18(protocol fee) - 20e18(unclaimedTokens) = 36e18
contract balance is 34e18 (70e18 - 36e18)
contract balance is 20e18 (34e18-14e18) this balance only can be claim by unclaimed Receipt
withdrawFee()
and transfer protocolfee(14e18)Now contract balance is 6e18
Manual Review
withdrawFee()
and withdrawRemainingTokens()
can call only once
#0 - c4-judge
2023-02-05T04:27:34Z
kirk-baird marked the issue as duplicate of #23
#1 - c4-judge
2023-02-05T04:27:42Z
kirk-baird marked the issue as satisfactory
🌟 Selected for report: carlitox477
Also found by: 0xRobocop, 0xbepresent, ArmedGoose, Atarpara, IllIllI, Tointer, UdarTeam, adriro, betweenETHlines, cryptojedi88, evan, glcanvas, gzeon, horsefacts, ladboy233, libratus, lukris02, luxartvinsec, manikantanynala97, minhquanym, mookimgo, p4st13r4, simon135, thekmj, trustindistrust
18.6976 USDC - $18.70
https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/Quest.sol#L99 https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/RabbitHoleReceipt.sol#L117-L133
Quest.sol#Claim()
can be lead into out of gas error due to unbounded array and user can't unable to claim reward token.
User can claim reward token via Receipt NFT contract. After claiming the reward token he still hold claimed mintReceipt and increase his balance. Also user can buy mint Receipt from other marketplace. getOwnedTokenIdsOfQuest()
use 2 SLOAD
opration and this gas cost is 2100*2 = 4200
for (uint i = 0; i < msgSenderBalance; i++) { uint tokenId = tokenOfOwnerByIndex(claimingAddress_, i); // 1st SLOAD (2100 gas) if (keccak256(bytes(questIdForTokenId[tokenId])) == keccak256(bytes(questId_))) { // 2nd SLOAD (2100 gas) tokenIdsForQuest[i] = tokenId; foundTokens++; } }
ethereum block gas limit is : 30_00_000
any user can lead into out of gas error after minting ~ 700
( = 3000000/(2100*2) receipt lead into out of gas error and not able to claim reward token.
this limit is can be easily achievable.
Manual Review
When user claim reward token Mint Receipt should be burn.
#0 - waynehoover
2023-02-07T20:41:08Z
Intended use case has ~1-5, not 700+.
#1 - c4-sponsor
2023-02-07T20:41:14Z
waynehoover marked the issue as sponsor disputed
#2 - c4-judge
2023-02-16T06:48:04Z
kirk-baird marked the issue as satisfactory
#3 - c4-judge
2023-02-16T06:48:49Z
kirk-baird marked the issue as duplicate of #552
#4 - kirk-baird
2023-02-16T06:49:52Z
Although the intended use case is ~5 quests this loop may be reach by numerous participants sending claimed tokens to one user.
It is an unlikely case but I consider this to be a valid medium.