Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Snek-Raffle Does not Properly Implement `VRFConsumerBaseV2`

Summary

The Snek-Raffle project fails to implement the VRFConsumerBaseV2 interface properly, leading to incompatibilities with the Chainlink's VRF service. This finding was rated as high risk because it undermines the correct operation of the raffle.

Vulnerability Details

The implemented rawFulfillRandomWords() function in the Snek-raffle contract is not matching the one expected by the VRFConsumerBaseV2 interface.

@external
@>def rawFulfillRandomWords(requestId: uint256, randomWords: uint256[MAX_ARRAY_SIZE]):
"""The function the VRF Coordinator calls back to to provide the random words."""
assert msg.sender == VRF_COORDINATOR.address, ERROR_NOT_COORDINATOR
self.fulfillRandomWords(requestId, randomWords)
@internal
@>def fulfillRandomWords(request_id: uint256, random_words: uint256[MAX_ARRAY_SIZE]):

Notice the function selectors above use a fixed array (uint256[MAX_ARRAY_SIZE]). However, in order to be able to interact with Chainlink's VRF, the contract must implement VRFConsumerBaseV2 with dynamic arrays (uint256[] memory randomWords in Solidity or DynArray[uint256, 10] in Vyper).

See the following related StackExchange question for more information: https://ethereum.stackexchange.com/questions/132894/match-a-solidity-function-selector-with-a-dynamic-array-to-a-vyper-function-sele

Impact

As indicated in the summary, not being able to properly interact with Chainlink's VRF is undermining the correct operation of the raffle.

Tools Used

Manual analysis.

Recommendations

It is recommended to make the suggested changes below in order to be able to make use of Chainlink's VRF:

@external
-def rawFulfillRandomWords(requestId: uint256, randomWords: uint256[MAX_ARRAY_SIZE]):
+def rawFulfillRandomWords(requestId: uint256, randomWords: DynArray[uint256, 10]):
"""The function the VRF Coordinator calls back to to provide the random words."""
assert msg.sender == VRF_COORDINATOR.address, ERROR_NOT_COORDINATOR
self.fulfillRandomWords(requestId, randomWords)
@internal
-def fulfillRandomWords(request_id: uint256, random_words: uint256[MAX_ARRAY_SIZE]):
+def fulfillRandomWords(request_id: uint256, random_words: DynArray[uint256, 10]):
index_of_winner: uint256 = random_words[0] % len(self.players)
recent_winner: address = self.players[index_of_winner]
self.recent_winner = recent_winner
self.players = []
self.raffle_state = RaffleState.OPEN
self.last_timestamp = block.timestamp
rarity: uint256 = random_words[0] % 3
self.tokenIdToRarity[ERC721._total_supply()] = rarity
log WinnerPicked(recent_winner)
ERC721._mint(recent_winner, ERC721._total_supply())
send(recent_winner, self.balance)
Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Incorrect Function Selector for Chainlink VRF

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.