CCIP is now live for all developers. See what's new.

Back to QuickStarts

VRF-Enabled Mystery Box

Build a mystery box smart contract using VRF.


This is a template for NFT collection with a mystery box mechanic powered by Chainlink VRF V2.5.

Smart contracts are based on the gas efficient ERC721Psi. It's super easy to deploy and configure with most of the steps automated in the deploy script.

The key features of this template include:

  • a private minting stage with a merkle tree
  • rate limited batch minting
  • delayed reveal with randomization technique to save gas
  • provenance hash to verify the authenticity of the metadata
  • royalties for secondary sales
  • configurable parameters


You will use a Hardhat project to deploy an existing MysteryBox application on Ethereum Sepolia.

Before you begin

Before you start this tutorial, complete the following items:

  • Set up a cryptocurrency wallet such as MetaMask.
  • Fund your wallet with testnet ETH and LINK from
  • Install git. Run git --version to check the installation.
  • Install Nodejs version 16 or later.
  • Optionally, you can install Yarn and use it to run this example instead of using npm.
  • Create an Etherscan API key if you do not already have one. This is used to verify your contracts onchain.
  • Create an account with Infura or Alchemy to obtain an RPC endpoint if you do not already have one.

Steps to implement

1 Clone the example repo and install dependencies

Clone the repo and install all dependencies.

If you want to use npm, run:

git clone && \
cd quickstarts-mysterybox && \
npm install

Alternatively, you can use yarn to install dependencies:

git clone [email protected]:smartcontractkit/quickstarts-mysterybox.git && \
cd quickstarts-mysterybox && \
yarn install
2 Configure your project

Copy the .env.example file to .env and fill in the values.

cp .env.example .env

Set the parameters for the NFT contract. If you don't have a VRF subscription, delete the VRF_SUBSCRIPTION_ID parameter.

NFT_NAMEThe name of the NFT collectionMysteryBox
NFT_SYMBOLThe symbol of the NFT collectionBOX
NFT_UNREVEALED_URIThe metadata URI for all tokens before reveal
NFT_MAX_SUPPLYThe maximum number of tokens that can be minted100
NFT_MAX_MINT_PER_USERThe maximum number of tokens that can be minted per user address10
NFT_FEEThe fee for minting a token in ETH0.01
NFT_ROYALTY_BPSThe royalty fee for selling a token in basis points500
VRF_SUBSCRIPTION_IDA funded Chainlink VRF V2.5 subscription ID. If you leave this blank, a new subscription will be created and funded on deploy.79850349243438349975305816782035019118399435445660033947721688676378382535454
3 Configure the Hardhat project

Hardhat is an Ethereum development environment that is used here to configure and deploy the mystery box contract. You need the following information:

SEPOLIA_RPC_URLThe RPC URL for the Ethereum Sepolia network.
PRIVATE_KEYThe private key of the account you want to deploy from.abc123abc123abc123abc123abc123...
SCANNER_API_KEYThe API key for Etherscan used for contract verification.ABC123ABC123ABC123ABC123ABC123ABC1
4 Test the contracts locally

To run the unit tests, run the following command:

npm run test

If you want to see gas usage, run the following command:

REPORT_GAS=true npm run test

For coverage reports, run the following command:

npm run coverage
5 Deploy the example contract

Run the npx hardhat run command and replace <network> with the network that you want to deploy to. The network must be configured in hardhat.config.ts.

npx hardhat run scripts/deploy.ts --network <network>

In addition to deploying the contract, the deploy script also completes the following steps automatically:

  1. Create and fund a VRF V2.5 subscription if one is not provided. Make sure the deployer account has enough LINK to fund the subscription. The initial funding amount is configured in network-config.ts. For testnets, you can use the LINK faucet to get LINK. If your subscription is underfunded, your VRF request will be pending for 24 hours. If this happens, check the Subscription Manager to see the additional balance needed.

  2. Add the deployed contract address as a consumer to the VRF subscription. If you provided a subscription ID, make sure the deployer account is the owner of the subscription. Otherwise, comment out the addConsumerToSubscription function in the deploy script and add the contract address manually.

  3. Generate a Merkle tree for the allowlist. The merkle tree is generated from the address list in scripts/data/whitelist.json file.

  4. Verify the contract on Etherscan. This is important to show users the source code for the contract so they can confirm how it works. It's also required to run the example yourself.

After the deployment is complete, the terminal prints the link to view your contract on Etherscan.

6 Run the example

After the contract is deployed, run the example using contract functions on Etherscan.

  1. Open the Etherscan link from your terminal to view your contract.
  2. On the Contract tab, click the Write Contract tab to view your contract's write functions.
  3. Click Connect to Web3 to connect your wallet to Etherscan so you can run the functions.
  4. Enable public minting:
  5. Open the setPublicMint function.
  6. Enter a value of true.
  7. Click Write to run the function. Approve the transaction in MetaMask.
  8. Mint an NFT to test the contract:
  9. Open the publicMint function.
  10. Enter a publicMint value of 0.01 ETH and an amount of 1.
  11. Click Write to run the function. Approve the transaction in MetaMask.
  12. Reveal the box:
  13. Open the reveal function.
  14. Click reveal to reveal the mystery box.
  15. After the reveal, you can find the NFT in the token list for your externally owned account (EOA).

Explore the code

After you complete the example, see the Mystery Box repository to learn about more capabilities of this example and how to configure them. For example, you can learn more about the various Configuration Options for this example and modify it to meet the needs of your application.

Stay updated on the latest Chainlink news