Creators can create multiple draws with the same prize, but only the first draw to call startDraw will have the prize. This can trick users into entering raffle pools that does not have a prize.
Furthermore, the prize token can also be one of the tokens in the raffle pool. If the prize token gets drawn, then no one can get the prize since the contract is the winner.
Proof of Concept
Run the following test.
Test_PrizeReuse creates 2 draws with the same prize. The second draw fails when calling startDraw.
Test_DrawingPrize creates a draw where the prize is in the drawing pool. It proves that it's possible for the contract itself to win the raffle at the end of the draw.
Create a mapping between prize tokens and VRFNFTRandomDraw contracts in VRFNFTRandomDrawFactory.sol to prevent prize re-use.
Also, add a check in VRFNFTRandomDraw.sol initialize() function to ensure that the prize is not in the raffle pool.
Lines of code
https://github.com/code-423n4/2022-12-forgeries/blob/main/src/VRFNFTRandomDraw.sol#L75-L138 https://github.com/code-423n4/2022-12-forgeries/blob/main/src/interfaces/IVRFNFTRandomDraw.sol#L73-L81
Vulnerability details
Impact
Creators can create multiple draws with the same prize, but only the first draw to call
startDraw
will have the prize. This can trick users into entering raffle pools that does not have a prize.Furthermore, the prize token can also be one of the tokens in the raffle pool. If the prize token gets drawn, then no one can get the prize since the contract is the winner.
Proof of Concept
Run the following test. Test_PrizeReuse creates 2 draws with the same prize. The second draw fails when calling startDraw. Test_DrawingPrize creates a draw where the prize is in the drawing pool. It proves that it's possible for the contract itself to win the raffle at the end of the draw.
Tools Used
VSCode, foundry
Recommended Mitigation Steps
Create a mapping between prize tokens and VRFNFTRandomDraw contracts in
VRFNFTRandomDrawFactory.sol
to prevent prize re-use. Also, add a check in VRFNFTRandomDraw.sol initialize() function to ensure that the prize is not in the raffle pool.