Changing the RabbitHoleReceipt
contract in the QuestFactory
will break rewards for existing quests
#607
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
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-425
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/QuestFactory.sol#L172-L174
Vulnerability details
The
RabbitHoleReceipt
is a ERC721 token that represents a completed task for a specific quest and can be used to claim rewards. This token is minted in theQuestFactory
contract using themintReceipt
function and rewards can be claimed using theclaim
function present in theErc20Quest
andErc1155Quest
contracts.The
QuestFactory
contract contains a reference to theRabbitHoleReceipt
in therabbitholeReceiptContract
variable. This address is forwarded to the quests contracts in thecreateQuest
function, in line 82 for theErc20Quest
contract and line 115 for theErc1155Quest
contract. These contracts hold an immutable reference to theRabbitHoleReceipt
(https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/Quest.sol#L13).The factory contract contains also a function to update the
rabbitholeReceiptContract
variable:https://github.com/rabbitholegg/quest-protocol/blob/8c4c1f71221570b14a0479c216583342bd652d8d/contracts/QuestFactory.sol#L172-L174
Now, if the
rabbitholeReceiptContract
variable is updated in the factory, current ongoing quests will be out of sync with respect to this reference, as these contracts contain an immutable reference to the previousrabbitholeReceiptContract
value that was copied when they were created.Receipt minting will be done using the new contract (
mintReceipt
inQuestFactory
), while claiming will be done using the previous contract (claim
inErc20Quest
orErc1155Quest
). Users that complete tasks after theRabbitHoleReceipt
contract is updated will be minted the new receipt, which will fail to be claimed in the quest as these two are essentially different contracts.Impact
After the
RabbitHoleReceipt
contract is updated in theQuestFactory
contract, users that complete tasks for quests that were created before the receipt contract was updated won't be able to claim their rewards.Given this scenario, users will mint their receipts using the
mintReceipt
function present in theQuestFactory
contract which will use the new updated contract. However, if they attempt to claim their rewards using theclaim
function in the quest contract, the call will be reverted as the receipt contract here is outdated and their receipt will not be recognized.PoC
In the following test, the
RabbitHoleReceipt
contract is updated in the factory after the quest is created. Alice mints her receipt after completing the quest, which fails to be claimed with theNoTokensToClaim()
error, as the receipt she has is a different contract than the one the quest is expecting.Recommendation
The straightforward solution would be to remove the mutation around the
RabbitHoleReceipt
reference in theQuestFactory
contract. TheRabbitHoleReceipt
contract is upgradeable, which means it can be updated while keeping the same address. This will ensure that both the factory and the quests contract maintain the same reference to the receipt contract.A bit more complicated solution would be to move the minting (
mintReceipt
) to the quest contract itself. This way both minting and claiming happens in the quest contract, which will always resolve to the same receipt contract. Note that this will require setting up all quest contracts as minters of the receipt, which could carry other potential risks.The text was updated successfully, but these errors were encountered: