Smart contracts allow conducting transparent raffles on the blockchain by enforcing rules in code. We will build a decentralized Ethereum raffle that takes Ether entries, picks a random winner, and sends the prize money automatically.
This article will guide you through building and understanding a Raffle smart contract step-by-step.
Prerequisites
Before we start coding, you need a basic understanding of Solidity and working with Remix IDE. No prior experience building smart contracts is required, as we will explore all the concepts along the way.
For this tutorial, we will be using Foundry, and to set that up on Vscode, I wrote a guide to help you get started.
The full code blocks can be found here; fork it and follow along.
Setting Your Environment
Open your Vscode and create a folder, run a forge init to set up dependencies for foundry, and then delete all the counter.sol
files in src, script, and test, we will not need them going forward.
Setting up the Raffle Contract
Create a file in src. I will call mine raffle.sol
next. We will define the version of Solidity and add NatSpec comments to document our contract properly.
The SPDX license identifier ensures the open-source licensing of our code. We target Solidity version 0.8.18
to use the latest features. The NatSpec comments provide a title, description, author, and usage notice for our Raffle contract.
Defining State Variables
Next, we define state variables to store essential contract data.
The i_ticketPrice will store the ticket price set at deployment. We make it immutable
so it can never change.
An error Raffle__InsufficientETH()
will be thrown when the Ether sent is less than the ticket price. Finally, we use a dynamic array s_participants
to store the addresses of all players.
Setting the Ticket Price
The contract needs to know the ticket price, so we add a constructor that sets it.
Anyone deploying the contract must pass ticketPrice
, which gets stored in the immutable state variable. i_ticketPrice
Adding the Enter Function
We now need a way for players to enter the raffle by paying the entrance fee.
We first use an if statement to check that the Ether sent is greater than the ticket price. If not, we revert with a custom error that gets caught on the front end.
note we could have used the required require(msg.value >= i_ticketPrice, "Raffle: Insufficient amount");
I discovered it would cost more gas using require
when we tested it on remix.
To understand these two lines of code properly, we must first understand Event
Events on the Blockchain
Blockchain-based applications generate data that we sometimes want external services to be aware of. For example, our Raffle contract must be able to perform randomness to pick a winner, but as we are aware, blockchain is deterministic.
We must rely on a decentralized oracle leveraging Verifiable Random Function, and we would use the Chainlink VRF to connect our smart contracts to verifiable randomness.
Defining Events
Events are a way for smart contracts to emit messages to interested external listeners. Here is an event definition in our contract:
event RafflesEntered(address indexed player);
This RafflesEntered event contains one parameter named player of type address. The indexed keyword allows efficient filtering for that address later.
Emitting Events
We can trigger events from within functions. For example, when a player enters the raffle:
The emit keyword triggers the event, passing the player's address captured from the global msg.sender
.
Listening for Events Using Chainlink VRF
Chainlink nodes listen for our event via the Chainlink VRF oracle. When detected, the oracle uses the key to track the request and provide a verifiable random number corresponding to that key.
We can access the random number by implementing a fulfillRandomness
callback in our contract. Chainlink VRF triggers it automatically once randomness generation is complete.
Events are powerful for decoupling smart contract logic from notifications. Defining, emitting, and listening for events unlocks reactive application possibilities on Ethereum.
Conclusion
That concludes our tutorial on building a transparent Raffle contract on Ethereum! We learned about storing state, accepting payments, generating randomness and sending funds,
In our follow-up series, we will dive into how randomness works using Chainlink VRF and how to get the withdrew function to work.
If you find this article thrilling, discover extra thrilling posts like this on Learnhub Blog; we write a lot of tech-related topics from Cloud computing to Frontend Dev, Cybersecurity, AI, and Blockchain. Take a look at How to Build Offline Web Applications.