Platform: Code4rena
Start Date: 13/12/2022
End Date: 16/12/2022
Period: 3 days
Status: Completed
Pot Size: $36,500 USDC
Participants: 77
Reporter: itsmetechjay
Judge: gzeon
Id: 191
League: ETH
Auditor per page
The C4audit output for the contest can be found here within an hour of contest opening.
Note for C4 wardens: Anything included in the C4udit output is considered a publicly known issue and is ineligible for awards.
We rely on @chainlink/contracts
to supply VRF
numbers and this contract clearly documents chain.link
as a dependency for this project. Any issues directly related to the chainlink infastructure contracts other than incorrect configuration of their libraries within this project are not in scope for this audit.
We want to raffle away a single NFT (token) based off of another NFT collection (or drawingToken) in a fair and trustless manner.
For instance, we could raffle off a single high value NFT to any cryptopunk holder, the punk that wins can choose to claim the NFT. If they do not claim, a re-roll or redraw can be done to select a new holder that would be able to claim the NFT.
The contract follows the hyperstructure concept (https://jacob.energy/hyperstructures.html) except for the dependency on chain.link (https://chain.link/).
We are utilizing the chain.link
Verifiable Random Function (VRF
) contract tools to fairly raffle off the NFT. Their VRF
docs can be found at: https://docs.chain.link/vrf/v2/introduction/.
The main functions are VRFNFTRandomDrawFactory.makeNewDraw()
to create a new non-upgradeable minimal clones proxy draw contract with your desired configuration. Each contract is separate to allow for easier UX and more security with interactions. After the drawing is created, it needs to be started which will pull the NFT from the creator/owner's wallet up for raffle when they call VRFNFTRandomDraw.startDraw()
.
After the drawing is started, we will request a random entropy from chain.link using the internal _requestRoll()
function. Once chain.link
returns the data in the fulfillRandomWords()
callback the raffle NFT will be chosen and saved. If the raffle NFT is burned or removed this will still complete and a redraw will need to happen to find an NFT that is active/accessible to draw the winning NFT. Most raffles will use a specific contract that users will have a high incentive to withdraw their winning NFT.
The winning user can determine if they have won by calling hasUserWon(address)
that checks the owner of the winning NFT to return the winning user. They also can look at request().currentChosenTokenId
to see the currently chosen winning NFT token id. Once they have won, they can call winnerClaimNFT()
from the account that won to have the raffled NFT transferred to the winner.
If the winning user does not claim the winning NFT within a specific deadline, the owner can call redraw()
to redraw the NFT raffle. This is an ownerOnly
function that will call into chain.link
.
If no users ultimately claim the NFT, the admin specifies a timelock period after which they can retrieve the raffled NFT.
File | SLOC | Description and Coverage | Libraries |
---|---|---|---|
Contracts (4) | |||
src/utils/Version.sol | 10 | 100.00% | |
src/VRFNFTRandomDrawFactoryProxy.sol | 15 | Proxy Contract linking to the Factory, - | @openzeppelin/contracts-upgradeable |
src/VRFNFTRandomDrawFactory.sol | 41 | Factory for VRF NFT Raffle, UUPS Upgradable by owner., 100.00% | @openzeppelin/contracts-upgradeable |
src/VRFNFTRandomDraw.sol ♻️ | 196 | This contract is the main escrow and VRF-integrated raffle contract, 86.67% | @openzeppelin/contracts-upgradeable @chainlink/contracts |
Abstracts (1) | |||
src/ownable/OwnableUpgradeable.sol | 73 | This contract is the main escrow and VRF-integrated raffle contract, 94.12% | @openzeppelin/contracts-upgradeable |
Interfaces (3) | |||
src/interfaces/IVRFNFTRandomDrawFactory.sol | 11 | Interface to the main VRFNFTRandomDraw contract, - | |
src/ownable/IOwnableUpgradeable.sol | 15 | The interface to an owner safe-transferrable upgradeable openzeppelin fork, - | |
src/interfaces/IVRFNFTRandomDraw.sol | 62 | Interface to the factory VRFNFTRandomDrawFactory contract, - | |
Total (over 8 files): | 423 | 89.41% |
- If you have a public code repo, please share it here: https://github.com/0xigami/vrf-nft-raffle - How many contracts are in scope?: 3 - Total SLoC for these contracts?: 320 - How many external imports are there?: 6 - How many separate interfaces and struct definitions are there for the contracts within scope?: 2 structs, 2 interfaces - Does most of your code generally use composition or inheritance?: Code typically uses composition - How many external calls?: 4 - What is the overall line coverage percentage provided by your tests?: 94 - Is there a need to understand a separate part of the codebase / get context in order to audit this part of the protocol?: false - Please describe required context: - Does it use an oracle?: true - Does the token conform to the ERC20 standard?: N/A - Are there any novel or unique curve logic or mathematical models?: N/A - Does it use a timelock function?: Yes - Is it an NFT?: No (but NFTs get locked inside) - Does it have an AMM?: No - Is it a fork of a popular project?: false - Does it use rollups?: false - Is it multi-chain?: false - Does it use a side-chain?: false
rm -Rf 2022-12-forgeries || true && git clone https://github.com/code-423n4/2022-12-forgeries.git -j8 && cd 2022-12-forgeries && yarn && foundryup && yarn test-gas
yarn
: https://yarnpkg.com/getting-started/installforge
: https://book.getfoundry.sh/getting-started/installationyarn
yarn test
chain.link
have issues that are out of scope in the repo for Slither.