The documentation for the protocol in scope defines the following rarities for the NFTs that can be minted:
However, the distribution of rarity among minted NFTs follows a continuous uniform distribution, meaning that there is an equal probability of minting a Brown Snek
, a Jungle Snek
or a Cosmic Snek
.
The protocol uses the Chainlink VRF to generate random values, which are used to determine the rarity of the minted NFT.
However, when the VRFCoordinator
performs its callback to fulfillRandomWords
, the random value (represented by random_words[0]
) generated is used in the following line of code:
Assuming the value returned from Chainlink is truly random, there is an equal probability that its modulo will return 0, 1, or 2 as rarity values.
To prove this point, it is possible to write a test that simulates a million raffles, and look at the distribution of rarity among the minted NFTs.
If, as suspected, the rarity follows a continuous uniform distribution, the final share of NFTs should be around 33% for each type of item.
To write such a test, it is necessary to modify the VRFCoordinatorV2Mock.vy
, as it currently returns a static, not random, value. Modify the fulfillRandomWords
function with the following line, using requestId
as a source of randomness:
To create random request IDs, we can use the "random" Python library. Import the "random" library and add the following test to the snek_raffle_test.py
test suite:
According to the law of large numbers, using a thousand raffles should give us results close to the expected distribution. Running the tests, we would expect each category to get about 333 NFTs. As a matter of fact, these are the results when running the test:
The distribution of NFT rarity does not follow the expected one. All NFTs have the same probability of being minted, causing them to average on the same value with each other. No NFT is more valuable, meaning that taking part in more raffles to win a rare prize is not incentivized.
Manual review, VSCode, Pytest
Implement the rarity mechanism described in the documentation. For example, the following modification to the previously shown line of fulfillRandomWords
yields the expected rarity:
Running the test again returns the expected distribution:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.