-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvoting.sol
204 lines (163 loc) · 8.11 KB
/
voting.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
191
192
193
194
195
196
197
198
199
200
201
202
203
204
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.18;
/*
Задача:
- Контракт должен создавать объект голосования, принимая на вход массив адресов кандидатов.
- Голосований может быть много, по всем нужно иметь возможность посмотреть информацию.
- Голосование длится некоторое время.
- Пользователи могут голосовать за кандидата, переводя на контракт эфир.
- По завершении голосования победитель может снять средства, которые были внесены в это голосование, за исключением комиссии площадки.
- Владелец площадки должен иметь возможность выводить комиссию.
*/
/** @title Основной контракт голосования **/
contract VotingContract {
// Администратор контракта ( владелец )
address public ownerContract;
// Максимальное количество кандидатов
uint256 public maxCandidatesNum;
// Переменаня, хранящая номер голосования
uint256 public counterVotings;
/** @title Структура кандидата **/
struct Candidate {
// Существует ли канидидат?
bool valid;
// Баланс кандидата
uint256 votingBalance;
}
/** @title Структура голосования **/
struct Voting {
// Активно ли сейчас данное голосование
bool isActive;
// Победитель текущего голосования
address winner;
// Время начала голосования
uint256 startTimeStamp;
// Длительность голосования
uint256 period;
// Баланс победителя на начало конец
uint256 winnerBalanceAtVotingClose;
// Баланс контракта на момент голосования
uint256 bankBalance;
// Список кандидатов на победу
mapping(address => Candidate) candidates;
}
// Список голосований
mapping(uint256 => Voting) private votings;
// Комиссия сервиса. Устанавливается один раз в конструкторе смарт-контракта ( в процентах )
uint8 public immutable commision;
constructor(uint8 _commision) {
commision = _commision;
ownerContract = msg.sender;
maxCandidatesNum = 5;
}
// Проголосовать за кандидата
function iAmVote(uint256 _votingId, address _to) public payable {
require(votings[_votingId].isActive == true, "Voting is not started or not exist.");
require(votings[_votingId].startTimeStamp + votings[_votingId].period > block.timestamp, "Voting is ended.");
require(checkCandidate(_votingId, _to), "Candidate does not exist on this voting");
votings[_votingId].candidates[_to].votingBalance += msg.value;
if(votings[_votingId].candidates[_to].votingBalance > votings[_votingId].winnerBalanceAtVotingClose)
{
votings[_votingId].winner = _to;
votings[_votingId].winnerBalanceAtVotingClose = votings[_votingId].candidates[_to].votingBalance;
}
}
// Начать процедуру голсования
function StartVoting(uint256 _votingId) public onlyOwner
{
votings[_votingId].isActive = true;
votings[_votingId].startTimeStamp = block.timestamp;
emit votingStarted(_votingId, block.timestamp);
}
// Проверить, существует ли кандидат в определённых голосованиях
function checkCandidate(uint256 _votingId, address _candidate)
public
view
returns (bool)
{
return (votings[_votingId].candidates[_candidate].valid);
}
// Получить информацию по голосованию
function getVotingInfo(uint256 _votingId) public view returns (
bool isActive,
address winner,
uint256 startTimeStamp,
uint256 winnerBalanceAtVotingClose,
uint256 bankBalance
)
{
return (
votings[_votingId].isActive,
votings[_votingId].winner,
votings[_votingId].startTimeStamp,
votings[_votingId].winnerBalanceAtVotingClose,
votings[_votingId].bankBalance
);
}
// Добавить кандидата на голосование
function addCandidate(uint256 _votingId, address _candidate) public onlyOwner {
require(votings[_votingId].isActive == false, "Voting has already begun!");
votings[_votingId].candidates[_candidate].valid = true;
emit candidateInfo(_votingId, _candidate, true);
}
// Создать голосование
function addVoting(uint256 _period, address[] calldata _candidates) public onlyOwner
{
require(_candidates.length < maxCandidatesNum, "Too many candidates!");
votings[counterVotings].period = _period;
for (uint256 i = 0; i < _candidates.length; i++) {
addCandidate(counterVotings, _candidates[i]);
}
emit votingCreated(counterVotings);
counterVotings++;
}
// Начать голосовние
function startVoting(uint256 _votingId) public onlyOwner {
votings[_votingId].isActive = true;
votings[_votingId].startTimeStamp = block.timestamp;
emit votingStarted(_votingId, block.timestamp);
}
// Изменить период голосования
function editVotingPeriod(uint256 _votingId, uint256 _newPeriod) public onlyOwner
{
require(votings[_votingId].isActive == false, "Voting has already begun!");
votings[_votingId].period = _newPeriod;
}
// Удалить кандидата из голосования
function deleteCandidate(uint256 _votingId, address _candidate) public onlyOwner
{
require(votings[_votingId].isActive == false, "Voting has already begun!");
votings[_votingId].candidates[_candidate].valid = false;
emit candidateInfo(_votingId, _candidate, false);
}
// Установить максимальное число кандидатов
function setMaxCandidatesNum(uint256 _maxCandidatesNum) public onlyOwner {
maxCandidatesNum = _maxCandidatesNum;
}
// Получить приз
function WithdrowMyPrize(uint256 _votingId) public {
require(votings[_votingId].isActive == true, "Voting not started yet");
require(votings[_votingId].startTimeStamp + votings[_votingId].period < block.timestamp, "Voting is not over yet!");
require(msg.sender == votings[_votingId].winner, "You are not a winner!");
require(votings[_votingId].bankBalance > 0, "You have already received your prize!");
uint256 amount = votings[_votingId].bankBalance;
uint256 ownersComission = (commision * amount) / 100;
uint256 clearAmount = amount - ownersComission;
votings[_votingId].bankBalance = 0;
// отправить комиссию создателю
payable(ownerContract).transfer(ownersComission);
// отправить приз победителю
payable(msg.sender).transfer(clearAmount);
}
// Только для владельца контракта
modifier onlyOwner() {
require(
msg.sender == ownerContract,
"Error! You're not the smart contract owner!"
);
_;
}
event votingStarted(uint256 indexed votingId, uint256 startTimeStamp);
event candidateInfo(uint256 indexed votingId, address indexed candidate, bool valid);
event votingCreated(uint256 indexed votingId);
}