我正在写彩票合同。由于气体成本很高,我想使用映射而不是数组,并且我在struct中定义了id。然而,我无法摆脱代码结构。如何确定获胜者以及如何清空获胜者之后的通讯簿。
// 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);
_;
}
}
您不需要Players
结构。在lotteryHistory
中,您已经在跟踪获胜者地址。这样定义players
映射:
// this will take care of storing in mapping instead of array
mapping (uint => address) players;
uint playersCount=0;
则在enter
函数中:
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);
}
则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 ;
}
我们可以使用lotteryId
作为键,将players
映射定义为嵌套映射,而不是执行for循环删除播放器。我们的地图将像这个
lotteryId => playersCount => address
所以在第一次彩票中,你会有
1 => playersCount => address
在pickWinner
中,您已经增加了lotteryId++
。第一次抽奖后,您将开始一个新的映射
2 => playersCount => address
另外,在pickWinner中,选择获胜者后,您应该重置playersCount=0
,您的enter
功能将如下所示:
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;
}