diff --git a/Lottery.sol b/Lottery.sol index 58e7da1..62a4032 100644 --- a/Lottery.sol +++ b/Lottery.sol @@ -21,6 +21,8 @@ contract Lottery { bool public open; + mapping(uint => mapping(address => bool)) private entered; + constructor () { owner = msg.sender; } @@ -61,11 +63,10 @@ contract Lottery { require(msg.value == entryAmount, "Insufficient Funds"); //Check if user is already a player - for(uint i=0; i < players.length; i++){ - if (msg.sender == players[i]){ - revert reEntry(); - } + if(entered[lotteryId][msg.sender]){ + revert reEntry(); } + entered[lotteryId][msg.sender] = true; players.push(msg.sender); } diff --git a/README.md b/README.md index 506cdc2..4cb5db7 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,46 @@ -# Introduction +# How to generate and work with randomness in Solidity using Witnet + +## Introduction - Randomness is a core functionality for many applications - Games, trait-based NFTs, and luck-based financial applications rely heavily on randomness -- Welcome! In this tutorial, we are going to learn about random number generation and Working with it +- Welcome! In this tutorial, we are going to learn about random number generation and working with it --- -# Pre requisites -- To understand and utilize this tutorial you need to have the understanding of: - - Basic knowledge of developing smart contracts in Solidity - - Basic experience with Remix IDE - - Working with Celo Alfajores testnet +## Pre requisites +- To get the most out of this tutorial you need to have a basic understanding of: + - Developing smart contracts in Solidity + - Working with the Remix IDE + - Working with the Celo Alfajores testnet --- -# Requirements +## Requirements - Metamask - Celo Alfajores testnet --- -# Let's Get started! -## What we are going to build -- A lottery contract where users can join the lottery by paying an entry amount (just like buying a lottery in real life) -- A random winner will be chosen from the players and will be rewarded the entire lottery amount -- The Lottery will be conducted by an owner who would have access to start and end the lottery -- The owner will not have access to the funds +## Let's Get started! + +### What we are going to build +- A lottery smart contract where users can join the lottery by paying an entry fee +- A random winner will be chosen amongst the participants and will be rewarded the entire lottery amount +- The Lottery will be conducted by the lottery's owner who would have access to start and end the lottery +- The lottery's owner will not have access to the funds - The winner will be picked randomly based on the random number generated by an oracle -- Before starting to code, we must understand some basics first +- Before starting to code, we must first understand some basics - We will be covering - - Randomness and its requirement in blockchain - - Problem with generating on-chain randomness - - About oracles and Random Number Generation - - About Witnet Oracle - - Random number generation contract from Witnet -## Requirement of Randomness + - Use cases of randomness in blockchain applications + - Problems with generating randomness on-chain + - Achieving randomness through oracles + - An Introduction to the WitnetRandomness contract provided by Witnet +### Requirement of Randomness - Most applications require randomness in some sort - Let's take for example a gambling contract(like our own), these contracts award people based on luck, and luck is random - For these luck-based applications to work, the randomness must be tamper-proof so that no one can exploit -- While in the field of blockchain and smart contracts, there are some problems -## Problem with On-Chain Randomness +- However, in the field of blockchain and smart contracts, there are some problems +### Problem with On-Chain Randomness - When people get started they use randomness by using the block number or the block timestamp - But everything in the blockchain is deterministic - This leads to big security concerns where a party can gain an unfair advantage - The only bypass to this situation is to generate a number through a trusted source that is outside of the blockchain - Enter Oracles!! -## Oracles and Random Number generation +### Oracles and Random Number generation - Oracles act as a bridge between smart contracts and the outer world - Oracles are a reliable source of information - They allow the blockchain to interact with external data @@ -49,14 +51,14 @@ - Through oracles, smart contracts can obtain tamper-proof random numbers - Every oracle has a different way of generating the randomness - We are going to learn how to generate a random number using Witnet -## Witnet Oracle +### Witnet Oracle - Witnet is a multichain oracle that gives smart contract access to real-world information - It is one of the oracles that are available in the cell network - Witnet provides us with a contract using which we can call and obtain randomness - How this work is, nodes from the witnet are randomly selected to generate a random byte that is cryptographically committed - It is called crowd-witnessing -- To learn more about randomness in witnet - https://docs.witnet.io/smart-contracts/witnet-randomness-oracle -## Using Randomness from witnet +- To learn more about randomness in Witnet - https://docs.witnet.io/smart-contracts/witnet-randomness-oracle +### Using Randomness from Witnet - Before starting to code our lottery contract, let's understand the randomness functions provided by Witnet - You can find their code and the explanation here - https://docs.witnet.io/smart-contracts/witnet-randomness-oracle/code-examples @@ -96,14 +98,14 @@ contract Witnet { - It takes around 5 to 10 minutes to generate the random number - After 5 - 10 minutes, we can call the fetch function to obtain the random number - This number is generated earlier and it is fetched into the contract whenever you call the fetch function -## Setup -- To make this tutorial as simple as possible, we are going to use only remix to write and test the contract +### Setup +- To make this tutorial as simple as possible, we are going to use only Remix to write and test the contract - You can also use local development by using your favorite code editor - You can download the package for the interface of the randomness contract through this command: npm I witnet-solidity-bridge -- For the rest of us, we are going to use remix IDE +- For the rest of us, we are going to use Remix IDE - Open up remix IDE and create a new file -> Lottery.sol -## Building the contract +### Building the contract - If you're curious, the entire code for the contract can be viewed by [CLICKING HERE!](https://github.com/KishoreVB70/Lottery-Tutorial/blob/main/Lottery.sol) - Before starting to code a project, we must have an outline of all the functionality that will be in the contract - This contract will behave like a traditional lottery where there is an owner who will start and end the lottery @@ -130,7 +132,7 @@ contract Lottery { ``` - As usual, we write the license and the pragma solidity version - We import the interface for the randomness contract -- We set the address of the randomness contract in Celo alfajores and create the instance of the interface. +- We set the address of the randomness contract hosted on the Celo Alfajores testnet and create the instance of the interface. --- ``` uint256 entryAmount; @@ -143,6 +145,8 @@ contract Lottery { address owner; bool open; + + mapping(uint => mapping(address => bool)) private entered; ``` - Let's look at all the variables we will be going through - Firstly we have the `entryAmount` so that the players can know the amount @@ -210,20 +214,19 @@ contract Lottery { require(msg.value == entryAmount, "Insufficient Funds"); //Check if user is already a player - for(uint i=0; i < players.length; i++){ - if (msg.sender == players[i]){ - revert reEntry(); - } + if(entered[lotteryId][msg.sender]){ + revert reEntry(); } + entered[lotteryId][msg.sender] = true; players.push(msg.sender); } ``` - Then we have the join function which is payable and can only be accessed if there is an active lottery(`onlyIfOpen`) - First, we have a require statement to check if the user has sent the right amount -- Then we perform a check to see if the user is already entered in the lottery -- We have employed a simple for loop which iterated over the `players` array and checks if the caller is already a part of it -- If the caller is already in the array, then the function call is reverted by the custom error -- If not, the player is added to the array +- Then we perform a check to see if the user has already entered in the lottery +- We use a mapping to store a boolean value about whether a user is already participating in the current lottery +- If the caller is already participating in the lottery, then the function call is reverted with a custom error +- If not, the player is added to the array and the entered value of the caller is set to true for the current lottery --- ``` function requestRandomness() external onlyOwner onlyIfOpen{ @@ -278,22 +281,22 @@ contract Lottery { - Finally, we emit the `Ended` event to log the information of the lottery Id, winner amount, and the winner's address - As our contract is handling funds, we implement a receive function --- -## Testing the contract +### Testing the contract - Finally, we are done coding the contract - You can find the entire code of the contract by [CLICKING HERE!](https://github.com/KishoreVB70/Lottery-Tutorial/blob/main/Lottery.sol) - Now we are going to use remix IDE and metamask to deploy the contract to the Celo alfajores network - I have made a simple video to show you guys the functionality [![Testing Video](https://i.postimg.cc/ZYFzPrvF/tutorial-yt.jpg)](https://www.youtube.com/watch?v=DPsizPEkZZk "Testing Video") --- -# Conclusion +## Conclusion - Congratulations!, you have learned another new implementation in the Web3 world - In this tutorial, we have learned a reliable way to generate random numbers and built a practical contract --- -# What's next +## What's next - You can use this random number generator to make complex contracts for games - Explore other oracles and use randomness generator from them - You can learn more about oracles and access other forms of data they provide --- -# References +## References - Witnet - https://witnet.io/ - Witnet Randomness - https://docs.witnet.io/intro/tutorials/randomness