Solidity: Using mapping and code design for lottery contract address

Viewed 67

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);
          _;
        }
    }   
1 Answers

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;       
        }         
Related