Platform: Code4rena
Start Date: 13/12/2022
Pot Size: $36,500 USDC
Total HM: 5
Participants: 77
Period: 3 days
Judge: gzeon
Total Solo HM: 1
Id: 191
League: ETH
Rank: 37/77
Findings: 2
Award: $64.93
🌟 Selected for report: 0
🚀 Solo Findings: 0
🌟 Selected for report: Soosh
Also found by: 9svR6w, Apocalypto, Ch_301, HE1M, Koolex, SmartSek, Titi, Trust, Zarf, bin2chen, btk, carrotsmuggler, csanuragjain, dic0de, dipp, gz627, hansfriese, hihen, imare, immeas, indijanc, jadezti, kuldeep, ladboy233, maks, neumo, obront, rvierdiiev, sces60107, sk8erboy
19.2206 USDC - $19.22
In order to guarantee the raffle NFT will not be stuck in the contract, there’s a last resort option which allows the admin the reclaim the NFT from the contract. However, the timestamp as from which this action can take place, is calculated based on when the contract was initialized.
In case an contract is initialized but is not directly used to start the contest, the owner might claim the NFT directly either before the draw even has started or during the draw before the winner is able to claim the NFT.
While users might think the draw process is honest, the owner could actually use a contract which was initialized recoverTimelock
ago. Starting from this timestamp, the owner is always able to claim the NFT, regardless of the state of the contract.
VRFNFTRandomDraw
contract and chooses a recoverTimelock
variable of 1 week (minimum amount is 1 week).startDraw()
)Manual Review
It’s recommended to reset the block timestamp upon which the admin can call the lastResortTimelockOwnerClaimNFT()
function (block.timestamp + recoverTimelock
) in each _requestRoll()
.
#0 - hansfriese
2022-12-17T12:19:53Z
#1 - c4-judge
2022-12-17T12:35:55Z
gzeon-c4 marked the issue as duplicate of #146
#2 - c4-judge
2022-12-17T12:35:58Z
gzeon-c4 marked the issue as satisfactory
#3 - c4-judge
2023-01-23T17:09:20Z
gzeon-c4 changed the severity to 3 (High Risk)
45.7078 USDC - $45.71
redraw()
can be called before startDraw()
.
Whenever startDraw()
has not yet been called, redraw()
could be called to initiate the first draw. However, this bypasses the SetupDraw
event emit, which might confuse users.
It’s recommended to use Solidity time units (minutes
, hours
, days
) to improve readability.
redraw()
doesn’t emit an event.
redraw()
is a fairly important functionality which benefits from an emit event similarly to SetupDraw
in startDraw()
Missing verification in fulfillRandomWords()
to check whether the winning tokenId has an owner.
In case the winning tokenId of the drawingToken has no owner (e.g. is not yet minted/doesn’t exist), the contract has to wait for drawBufferTime
before it can be rerolled. If the winning tokenId has no owner, we can redraw directly and the contract is not ‘stuck’ for a determined time.
The contract does not support the approvers of the winning tokenId to withdraw the raffle tokenId.
In some cases tokens are managed by the approvers (e.g. particular wallets/contracts). In case this particular NFT wins, the approvers will not be able to withdraw the raffle token id as winnerClaimNFT()
checks whether msg.sender
is the owner of the NFT.
The initializer of VRFNFTRandomDrawFactory
does not call __UUPSUpgradeable_init()
#0 - c4-judge
2022-12-17T17:05:59Z
gzeon-c4 marked the issue as grade-b