Chainlink VRF Example ~ Dice Roll

Shows you how to use Chainlink VRF to randomly reveal a dice roll.

๐Ÿ— Scaffold-ETH

is everything you need to get started building decentralized applications powered by smart contracts.

This tutorial is PART 1 of a series on how to integrate Chainlink technology with Scaffold-ETH.

For some more advanced VRF handling, check out PART 2.

To learn about public APIs / Data feeds, check out PART 3.

Verifiable Randomness

In this tutorial you learn how to use Chainlink VRF (verifiable randomness) ๐ŸŽฒ

There are 3 example contracts (simple to advanced) for you to ape into! ๐Ÿฆ

๐Ÿงช Quickly experiment with Solidity using a frontend that adapts to your smart contract:

image

git clone -b chainlink-tutorial-1 https://github.com/scaffold-eth/scaffold-eth-examples.git

# ๐Ÿ„โ€โ™‚๏ธ Quick Start

### Manual setup

Prerequisites: [Node](https://nodejs.org/en/download/) plus [Yarn](https://classic.yarnpkg.com/en/docs/install/) and [Git](https://git-scm.com/downloads)

> clone/fork ๐Ÿ— scaffold-eth-examples:

```bash
git clone https://github.com/scaffold-eth/scaffold-eth-examples.git

We skip local development since it would require mock contracts. Going directly to testnet makes the first steps simpler.

generate your account to deploy to testnet:

cd scaffold-eth-examples
yarn generate

The warnings are normal and you can ignore. image

yarn account

You will need to fund your deployer account with kovan ETH before you can deploy your contracts.

Testnet ETH is available from https://faucets.chain.link/

image

yarn deploy

image

๐Ÿ” Edit your smart contract RandomNumberConsumer.sol in packages/hardhat/contracts ๐Ÿ” Edit your smart contract DiceRolls.sol in packages/hardhat/contracts ๐Ÿ” Edit your smart contract MultiDiceRolls.sol in packages/hardhat/contracts

๐Ÿ“ Edit your frontend App.jsx in packages/react-app/src

๐Ÿ’ผ Edit your deployment script 00_deploy_your_contract.js in packages/hardhat/deploy

๐Ÿ“ฑ Open http://localhost:3000 to see the app

๐Ÿ“š Keep solidity by example handy and check out the Solidity globals and units

With everything up your UI should look something like this:

Screenshot 2021-12-07 at 22 02 29

RandomNumberConsumer

Fund the contract with LINK

** Side Quest - use 00_deploy_your_contract.js to fund the contract with LINK after funding deployer account. **

  • Testnet LINK is available from https://faucets.chain.link/

Copy the contract address and send it some link. You don't need much, average oracle costs .1 LINK. image

To test just go to requestRandomNumber and click send.

Screenshot 2021-12-07 at 22 45 14

Once the transaction is mined you will see the requestId updated:

Screenshot 2021-12-07 at 22 46 01

This value identifies the request that your contract just made to the Chainlink VRF contract.

It takes about 1 minute for the Oracle to call your contract with a response. After waiting for 1 minute you should see the randomResult updated:

Screenshot 2021-12-07 at 22 49 10

In the Example UI you'll find an example of how to manage UI state when making such requests:

Screenshot 2021-12-07 at 22 51 37

Screenshot 2021-12-07 at 22 51 44

** ๐Ÿง™โ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿงžโ€โ™‚๏ธ Side Quest 1- How secure is it to expose our requestId publicly? ** Can we hack ๐Ÿฅท the system and fulfill the request before the Oracle does?

Since you know the latest requestId, call rawFulfillRandomness() on RandomNumberConsumer, just like the Oracle would.

Use the Debug Contracts tab. Make the rawFulfillRandomness() call and provide any random number you want. See if you can make the contract store your bogus random number.

The transaction reverted. Why didn't it work? Check out the actual code and see what the reason might be. You won't find the function directly in RandomNumberConsumer though...

๐Ÿ“ Takeaway: randomness from Chainlink VRF is a two-step process.

  • You trigger the first when you ask for a random number.
  • The VRF contract triggers the second step when it responds with a random number.

When receiving randomness your contract can do something useful with it.

Let's see an example!

DiceRolls

Let's roll some dice...

Make sure your DiceRolls contract is deployed and has some LINK.

Make sure to uncomment the DiceRolls code in App.jsx, in order to see it in the Debug Contracts Tab

You should find it below the RandomNumberConsumer:

Screenshot 2021-12-08 at 20 05 55

Go to the Example UI and click on the Roll Dice! button. After 1 minute or so the Oracle should have responded.

You will see a new entry in the events UI:

Screenshot 2021-12-08 at 20 12 19

You will see the event data in the console:

Screenshot 2021-12-08 at 20 12 11

Check out the code in the Events.jsx component

Screenshot 2021-12-08 at 20 15 05

Here is the solidity code broken down

Screenshot 2021-12-08 at 20 17 39

This solidity code is far from optimal, it will charge a lot of gas. It shows you a generic way to create several random numbers from a single one. Our problem is quite simple though: we have a large random number and we need 6 small random numbers (between 1 and 6 each)

** ๐Ÿง™โ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿงžโ€โ™‚๏ธ Side Quest 2! Find a cheaper solution which doesn't use the expand() function. ** Check out Utilities.sol, it contains some code to get you started. Keep the original solution.

** ๐Ÿง™โ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿงžโ€โ™‚๏ธ Side Quest 3! Compare gas costs ** Find a way to see how much gas was consumed in the transaction which produced the dice roll event (hint: browser console / etherscan) Do this with your cheaper implementation and redeploy with the original one, then compare the results.

** ๐Ÿง™โ€โ™‚๏ธ ๐Ÿงโ€โ™€๏ธ ๐Ÿงžโ€โ™‚๏ธ Side Quest 4! Dice Roll UX ** Try to improve the UX in the Example UI. Replicate what the Request Random Number! button does - a spinner should appear while waiting for the Oracle response.


๐Ÿ” You can yarn deploy --reset any time and get fresh new contracts in the frontend:

Make sure to edit your 00_deploy_your_contract.js if you don't want to redeploy all of your contracts.

Screenshot 2021-12-09 at 23 00 10


Check out PART 2 for a more advanced VRF setup!

Check out PART 3 for a tutorial on how to use public APIs and price feeds in your smart contracts!


๐Ÿ” Global variables like msg.sender and msg.value are cryptographically backed and can be used to make rules

๐Ÿ“ Keep this cheat sheet handy

โณ Maybe we could use block.timestamp or block.number to track time in our contract

๐Ÿ” Or maybe keep track of an address public owner; then make a rule like require( msg.sender == owner ); for an important function

๐Ÿงพ Maybe create a smart contract that keeps track of a mapping ( address => uint256 ) public balance;

๐Ÿฆ It could be like a decentralized bank that you function deposit() public payable {} and withdraw()

๐Ÿ“Ÿ Events are really handy for signaling to the frontend. Read more about events here.

๐Ÿ“ฒ Spend some time in App.jsx in packages/react-app/src and learn about the ๐Ÿ›ฐ Providers

โš ๏ธ Big numbers are stored as objects: formatEther and parseEther (ethers.js) will help with WEI->ETH and ETH->WEI.

๐Ÿงณ The single page (searchable) ethers.js docs are pretty great too.

๐Ÿœ The UI framework Ant Design has a bunch of great components.

๐Ÿ“ƒ Check the console log for your app to see some extra output from hooks like useContractReader and useEventListener.

๐Ÿ— You'll notice the <Contract /> component that displays the dynamic form as scaffolding for interacting with your contract.

๐Ÿ”ฒ Try making a <Button/> that calls writeContracts.YourContract.setPurpose("๐Ÿ‘‹ Hello World") to explore how your UI might work...

๐Ÿ’ฌ Wrap the call to writeContracts with a tx() helper that uses BlockNative's Notify.js.

๐Ÿงฌ Next learn about structs in Solidity.

๐Ÿ—ณ Maybe an make an array YourStructName[] public proposals; that could call be voted on with function vote() public {}

๐Ÿ”ญ Your dev environment is perfect for testing assumptions and learning by prototyping.

๐Ÿ“ Next learn about the fallback function

๐Ÿ’ธ Maybe add a receive() external payable {} so your contract will accept ETH?

๐Ÿš OH! Programming decentralized money! ๐Ÿ˜Ž So rad!

๐Ÿ›ฐ Ready to deploy to a testnet? Change the defaultNetwork in packages/hardhat/hardhat.config.js

๐Ÿ” Generate a deploy account with yarn generate and view it with yarn account

๐Ÿ”‘ Create wallet links to your app with yarn wallet and yarn fundedwallet

โฌ‡๏ธ Installing a new package to your frontend? You need to cd packages/react-app and then yarn add PACKAGE

โฌ‡๏ธ Installing a new package to your backend? You need to cd packages/harthat and then yarn add PACKAGE

( You will probably want to take some of the ๐Ÿ”— hooks, ๐ŸŽ› components with you from ๐Ÿ— scaffold-eth so we started ๐Ÿ–‡ eth-hooks )

๐Ÿš€ Good luck!

Automated with Gitpod

To deploy this project to Gitpod, click this button:

Open in Gitpod

๐Ÿ“š Documentation

Documentation, tutorials, challenges, and many more resources, visit: docs.scaffoldeth.io

๐Ÿ”ญ Learning Solidity

๐Ÿ“• Read the docs: https://docs.soliditylang.org

๐Ÿ“š Go through each topic from solidity by example editing YourContract.sol in ๐Ÿ— scaffold-eth

๐Ÿ“ง Learn the Solidity globals and units

๐Ÿ›  Buidl

Check out all the active branches, open issues, and join/fund the ๐Ÿฐ BuidlGuidl!

๐Ÿ’ฌ Support Chat

Join the telegram support chat ๐Ÿ’ฌ to ask questions and find others building with ๐Ÿ— scaffold-eth!


๐Ÿ™ Please check out our Gitcoin grant too!

๐ŸฐBuidlGuidl is a registered ๐Ÿค  Wyoming DAO LLC
Fork meยท

Built with โค๏ธ at

BuidlGuidl
WalletConnect
WalletConnect
Scan with WalletConnect to connect