-
Notifications
You must be signed in to change notification settings - Fork 0
/
SpinnerLottery.sol
190 lines (147 loc) · 5.4 KB
/
SpinnerLottery.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
pragma solidity ^0.8.11;
import "./interface/ILottery.sol";
contract SpinnerLottery is ILottery {
address public owner;
address[] public players;
address[] public mWinners;
address mParentAddress;
uint mDeadLineInDays;
uint mDeployedTime;
uint mMinDeposit; //Ether
uint mMaxDeposit; //Ether
uint public lotteryId;
address public generatorAddress; //Parent contract adress for backward compability
uint private mWinningPercentage;
mapping (uint => address[]) lotteryHistory; //Can have list of winners per lottery id
bool public ended;
uint256 internal prize = 0;
constructor(
address _owner,
address parentAddress,
uint256 winningPercentage,
uint deadLineInDays,
uint minDeposit,
uint maxDeposit
){
owner = _owner;
lotteryId = 1;
mWinningPercentage = winningPercentage;
mParentAddress = parentAddress;
mDeadLineInDays = deadLineInDays;
mDeployedTime = block.timestamp;
mMinDeposit = minDeposit;
mMaxDeposit = maxDeposit;
}
function getBalance()
public
view
returns (uint)
{
return address(this).balance;
}
function getPlayers() public view returns (address[] memory){ //out put is tempurary only for function call
return players;
}
function getParticipants(address checkedAddr) external view returns(bool) {
return checkAddressAlreadyExsits(checkedAddr);
}
function enterLottery() external payable enterLotteryRequirement override { //payable cause lead to some payment in blockchain
// require(msg.value > .01 ether);
//Player address
players.push(payable(msg.sender));
}
function getWinnerByLotteryId(uint index) public view returns (address[] memory){
return lotteryHistory[index];
}
function getRandomNumber() public view returns (uint){ //view because change nothing in blockchain
return uint(keccak256(abi.encodePacked(owner, block.timestamp)));
}
function pickWinner() external onlyOwner {
uint256 numWinners = ((players.length * mWinningPercentage) / 100) % 10; //to round winner numer, exaple: when percentage is 30% but only have 2 participants
if(numWinners < 1){
numWinners = 1;
}
uint256[] memory indices = randomIndices(numWinners, players.length);
for (uint256 i = 0; i < numWinners; i++) {
mWinners.push(players[indices[i]]);
}
uint256 balance = address(this).balance;
prize = (balance - (balance /100)) / numWinners ;
lotteryHistory[lotteryId] = mWinners;
lotteryId++;
//reset the state
players = new address payable[](0);
ended = true;
emit LotteryEnded(mWinners, prize);
}
function checkAddressAlreadyExsits(address checkedAddress) private view returns (bool) {
for (uint i = 0; i < players.length; i++) {
if (players[i] == checkedAddress) {
return true;
}
}
return false;
}
modifier onlyOwner(){
require(msg.sender == owner);
_;
}
modifier onlyWinner(){
require(addressIsInWinnerList() == true , "You not in this lottery winners list!");
require(prize != 0 , "Lottery has not finished yet!");
_;
}
function addressIsInWinnerList() private view returns (bool) {
for (uint i = 0; i < mWinners.length; i++) {
if (mWinners[i] == msg.sender) {
return true;
}
}
return false;
}
function getCondition(address participant) external view override returns(bool) {
return checkAddressAlreadyExsits(participant);
}
modifier enterLotteryRequirement(){
require(msg.value >= (mMinDeposit * (1 ether)) && msg.value <= (mMaxDeposit * (1 ether)), "out of deposit min max range");
require(checkAddressAlreadyExsits(msg.sender) == false);
require(lotteryNotPassedDeadline() == true);
_;
}
function lotteryNotPassedDeadline()
private
view
returns (bool) {
uint now = block.timestamp;
uint daysDiff = (now - mDeployedTime) / 60 / 60 / 24 ;
if (daysDiff <= mDeadLineInDays){
return true;
}
return false;
}
function randomIndices(uint256 numWinners, uint256 ticketCount) private view returns (uint256[] memory) {
uint256[] memory indices = new uint256[](ticketCount);
for (uint256 i = 0; i < ticketCount; i++) {
indices[i] = i;
}
for (uint256 i = 0; i < numWinners; i++) {
uint256 j = i + uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, i))) % (ticketCount - i);
(indices[i], indices[j]) = (indices[j], indices[i]);
}
return indices;
}
function getWinners() external view override returns(address[] memory) {
require(ended, "Lottery has not ended yet");
return mWinners;
}
function getLotteryNumber() external view override returns(uint256) {
require(ended, "Lottery has not ended yet");
return lotteryId;
}
function getWinningPercentage() external view override returns(uint256) {
return mWinningPercentage;
}
function claimPrize() external override onlyWinner {
payable(msg.sender).transfer(prize);
}
}