visit
If you enjoy working on Web3 projects, subscribe to my channel for all sorts of videos for learning web3 development. You can if you want to connect with me.
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract RaffleDraw {
address public owner;
mapping(address => bool) public players;
mapping(uint256 => address) public playerNumber;
mapping(address => bool) erasePlayers;
mapping(uint256 => address) eraseNo;
uint256 public ticketPrice;
uint256 public totalPlayers;
uint256 public totalPot;
address[] winners;
constructor() {
owner = msg.sender;
ticketPrice = 1 ether;
}
function enter() public payable {
require(msg.value == ticketPrice, "Not upto the ticket price");
require(!players[msg.sender], "Player already entered");
players[msg.sender] = true;
playerNumber[totalPlayers] = msg.sender;
totalPlayers++;
totalPot += msg.value;
}
function draw() public {
require(msg.sender == owner, "Caller must be the owner");
require(totalPlayers > 0, "Total players must be more than zero");
address\[] memory eligible = new address[\](totalPlayers);
for (uint256 i = 0; i < totalPlayers; i++) {
address player = playerNumber[i];
eligible[i] = player;
}
uint256 winnerCount = thirtyPercent(totalPlayers) > 0
? thirtyPercent(totalPlayers)
: 1;
for (uint256 i = 0; i < winnerCount; i++) {
uint256 randIndex = uint256(
keccak256(abi.encodePacked(block.timestamp, block.difficulty))
) % totalPlayers;
winners.push(eligible[randIndex]);
players[winners[i]] = true;
eligible = removeAddress(eligible, eligible[randIndex]);
}
}
function shareMoney() public {
require(msg.sender == owner, "Caller must be the owner");
for (uint256 i = 0; i < winners.length; i++) {
payable(winners[i]).transfer(ticketPrice * 2);
}
}
function getWinners() public view returns (address[] memory) {
return winners;
}
function resetRaffle() public returns (bool) {
require(msg.sender == owner, "Caller must be the owner");
for (uint256 i = 0; i < winners.length; i++) {
delete winners[i];
}
for (uint256 i = 0; i < totalPlayers; i++) {
delete players[playerNumber[i]];
delete playerNumber[i];
}
totalPlayers = 0;
totalPot = 0;
return true;
}
function thirtyPercent(uint256 x) public pure returns (uint256) {
return (x * 3) / 10;
}
function removeAddress(address[] memory addresses, address toRemove)
public
pure
returns (address[] memory)
{
address\[] memory newAddresses = new address[\](addresses.length - 1);
uint256 index = 0;
for (uint256 i = 0; i < addresses.length; i++) {
if (addresses[i] != toRemove) {
newAddresses[index] = addresses[i];
index++;
}
}
return newAddresses;
}
}
address public owner;
mapping(address => bool) public players;
mapping(uint256 => address) public playerNumber;
mapping(address => bool) erasePlayers;
mapping(uint256 => address) eraseNo;
uint256 public ticketPrice;
uint256 public totalPlayers;
uint256 public totalPot;
address[] winners;
constructor() {
owner = msg.sender;
ticketPrice = 1 ether;
}
The first function we'll look at is the enter() function. Players use this function to enter the raffle by sending a certain amount of ether to the smart contract. The function checks that the amount of ether sent is equal to the ticket price and that the player has not already entered the raffle. If the checks pass, the player is added to the players mapping and the totalPlayers and totalPot variables are incremented. See the snippet below:
function enter() public payable {
require(msg.value == ticketPrice, "Not upto the ticket price");
require(!players[msg.sender], "Player already entered");
players[msg.sender] = true;
playerNumber[totalPlayers] = msg.sender;
totalPlayers++;
totalPot += msg.value;
}
The next function is the draw() function. This function is used by the contract owner to conduct the raffle draw. It first checks that the caller is the owner of the contract and that there are more than zero players. It then creates a new address array called eligible that is the same size as the totalPlayers variable. This array is used to store all the eligible players for the draw. The draw is then conducted by selecting a random index from the eligible array and adding the player at that index to the winners array. The selected player is also removed from the eligible array using the removeAddress() function to prevent repeat winners. Observe the code below:
function draw() public {
require(msg.sender == owner, "Caller must be the owner");
require(totalPlayers > 0, "Total players must be more than zero");
address\[] memory eligible = new address[\](totalPlayers);
for (uint256 i = 0; i < totalPlayers; i++) {
address player = playerNumber[i];
eligible[i] = player;
}
uint256 winnerCount = thirtyPercent(totalPlayers) > 0
? thirtyPercent(totalPlayers)
: 1;
for (uint256 i = 0; i < winnerCount; i++) {
uint256 randIndex = uint256(
keccak256(abi.encodePacked(block.timestamp, block.difficulty))
) % totalPlayers;
winners.push(eligible[randIndex]);
players[winners[i]] = true;
eligible = removeAddress(eligible, eligible[randIndex]);
}
}
The shareMoney() function is used by the owner of the contract to distribute the winnings to the winners. This function iterates through the winners array and sends each winner 2 times the ticket price in ether. See the code below:
function shareMoney() public {
require(msg.sender == owner, "Caller must be the owner");
for (uint256 i = 0; i < winners.length; i++) {
payable(winners[i]).transfer(ticketPrice * 2);
}
}
The getWinners() function is a view function that returns the winners array. This function is useful for displaying the winners to users after the raffle has been conducted. See the snippet below:
function getWinners() public view returns (address[] memory) {
return winners;
}
The resetRaffle() function is used by the contract owner to reset the raffle. This function deletes all the players, winners, and resets the totalPlayers and totalPot variables to zero.
function resetRaffle() public returns (bool) {
require(msg.sender == owner, "Caller must be the owner");
for (uint256 i = 0; i < winners.length; i++) {
delete winners[i];
}
for (uint256 i = 0; i < totalPlayers; i++) {
delete players[playerNumber[i]];
delete playerNumber[i];
}
totalPlayers = 0;
totalPot = 0;
return true;
}
I
f you want to understand the nitty-gritty of smart contract development, check out the book below to become an in-demand smart contract developer.
Grab a copy of my book titled, ” to become an in-demand smart contract developer.
The last two functions are helper functions. The thirtyPercent() function is a pure function that takes in an argument and returns 30% of that argument. The removeAddress() function is used to remove an address from an address array. See the code below:
function thirtyPercent(uint256 x) public pure returns (uint256) {
return (x * 3) / 10;
}
function removeAddress(address[] memory addresses, address toRemove)
public
pure
returns (address[] memory)
{
address\[] memory newAddresses = new address[\](addresses.length - 1);
uint256 index = 0;
for (uint256 i = 0; i < addresses.length; i++) {
if (addresses[i] != toRemove) {
newAddresses[index] = addresses[i];
index++;
}
}
return newAddresses;
}
Don’t forget to for all sorts of web3 development videos. Till next time, all the best.
Gospel Darlington is a full-stack blockchain developer with 6+
years of experience in the software development industry.