I'm writing the Lottery Contract. Since gas cost is high, I wanted to use mapping instead of an array and I defined id in struct. However, I could not get out of the code structure. How to determine the winner and how to empty the address book after the winner.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract freeLottery {
address public owner;
uint public lotteryId;
mapping (uint => address payable) public lotteryHistory;
struct Players {
bool isWinner;
uint id;
}
mapping (address => Players) players;
uint playersCount=0;
constructor() {
owner = msg.sender;
lotteryId = 1;
}
function getWinner(uint lottery) public view returns (address payable) {
return lotteryHistory[lottery];
}
function getBalance() public view returns (uint) {
return address(this).balance;
}
function enter() public payable {
players[msg.sender];
playersCount++;
}
function contribute() public payable onlyowner{
require(msg.value>0,"Please send an amount greater than 0");
}
function getRandomNumber() internal view returns (uint) {
return uint(keccak256(abi.encodePacked(owner, block.timestamp)));
}
function pickWinner() public onlyowner {
require(address(this).balance>0,"Please upload balance");
uint index = getRandomNumber() % ???;
???
???
lotteryHistory[lotteryId] = players[id];
lotteryId++;
// reset the state of the contract
???;
}
modifier onlyowner() {
require(msg.sender == owner);
_;
}
}
You do not neet Players
struct. in lotteryHistory
you are already tracking the winner address. define your players
mapping like this:
// this will take care of storing in mapping instead of array
mapping (uint => address) players;
uint playersCount=0;
then in enter
function:
function enter() public payable {
// initially playersCount is 0. so increase it first
playersCount++;
// payable vs normal address has different methods. for storing it wont matter
players[playersCount]=payable(msg.sender);
}
then pickWinner
:
function pickWinner() public onlyowner returns (address payable) {
require(address(this).balance>0,"Please upload balance");
uint index = getRandomNumber() % playersCount;
address payable winner=payable(players[index]);
lotteryHistory[lotteryId] = winner;
// since you inialized lotteryId=1 in constructor
lotteryId++;
// for resetting, you have to do for loop
for (uint i=0; i< playersCount ; i++) {
delete players[i];
}
return winner ;
}
Instead of doing for-loop do delete the players, we can define the players
mapping as a nested mapping, using the lotteryId
as the key. Our mapping will be like this
lotteryId => playersCount => address
So in the first lottery you would have
1 => playersCount => address
Inside pickWinner
you already increase lotteryId++
. After first lottery, you will start a fresh mapping
2 => playersCount => address
Now additionally, in pickWinner after selecting the winner, you should reset the playersCount=0
, Your enter
function will look like this:
function enter() public payable {
// initially playersCount is 0. so increase it first
playersCount++;
// payable vs normal address has different methods. for storing it wont matter
players[lotteryId][playersCount]=msg.sender;
}