QuestFactory.sol: receipts can be minted after endTime of a quest is reached which can lead to loss of rewards for users #96
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
duplicate-601
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/Erc20Quest.sol#L81-L87
https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/QuestFactory.sol#L219-L229
Vulnerability details
Impact
When the
endTime
is reached, any unclaimed tokens can be withdrawn from theErc20Quest
contract via thewithdrawRemainingTokens
function (https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/Erc20Quest.sol#L81-L87).The
endTime
is checked in theonlyAdminWithdrawAfterEnd
modifier in the parent function (https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/Quest.sol#L150).This is the calculation to determine the amount to withdraw:
You can see that the rewards for any minted receipts that are not yet redeemed will stay in the contract.
The issue with this is that there is no check in the
QuestFactory.mintReceipt
function that makes sure that receipts cannot be minted after theendTime
of a quest is reached (https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/QuestFactory.sol#L219-L229).Therefore when
Erc20Quest.withdrawRemainingTokens
is called and then a new receipt is minted, there won't be enough rewards in theErc20Quest
contract for everyone to redeem.The sponsor provided the information that the
claimSigner
will signmintReceipt
requests only when theendTime
is not yet reached.I think however that this is not sufficient and the
endTime
check must occur on-chain in theQuestFactory.mintReceipt
function.This is because a
mintReceipt
request might be signed off-chain in time (i.e. before theendTime
) but is only processed on-chain after theendTime
.Proof of Concept
Think of the following scenario:
claimSigner
signs amintReceipt
request for User A before theendTime
is reachedendTime
is reached and all remaining funds are withdrawn from theErc20Quest
contract. Say there is funds for one receipt left in the contract which can be redeemed by User BmintReceipt
request is processed on-chain and User A redeems his rewardErc20Quest
contractYou can see from this scenario how - when a
mintReceipt
request is processed on-chain after theendTime
- users can miss out on their rewards.Tools Used
VSCode
Recommended Mitigation Steps
The
QuestFactory
contract should have access to theendTime
of each Quest and not mint receipts after theendTime
has been reached.This can be achieved by extending the
Quest
struct to include theendTime
:The
endTime
can then be checked in theQuestFactory.mintReceipt
function:The text was updated successfully, but these errors were encountered: