forked from lacala/5-Role-Base-Learn
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path13. Own a(n) ERC20 Pin NFT
More file actions
157 lines (138 loc) · 4.43 KB
/
Copy path13. Own a(n) ERC20 Pin NFT
File metadata and controls
157 lines (138 loc) · 4.43 KB
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
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
contract WeightedVoting is ERC20 {
using EnumerableSet for EnumerableSet.AddressSet;
error TokensClaimed();
error AllTokensClaimed();
error NoTokensHeld();
error QuorumTooHigh(uint quorum);
error AlreadyVoted();
error VotingClosed();
uint private constant MAX_SUPPLY = 1_000_000;
uint private claimedTokens = 0;
struct Issue {
EnumerableSet.AddressSet voters; // Lưu trữ tập hợp địa chỉ
string issueDesc;
uint quorum;
uint totalVotes;
uint votesFor;
uint votesAgainst;
uint votesAbstain;
bool passed;
bool closed;
}
struct FormattedIssue {
address[] voters;
string issueDesc;
uint quorum;
uint totalVotes;
uint votesFor;
uint votesAgainst;
uint votesAbstain;
bool passed;
bool closed;
}
Issue[] private issues;
enum Vote {
AGAINST,
FOR,
ABSTAIN
}
mapping(address => bool) private claimed;
constructor(
string memory name_,
string memory symbol_
) ERC20(name_, symbol_) {
issues.push(); // Thêm một Issue rỗng vào mảng
Issue storage burntIssue = issues[0]; // Lấy tham chiếu đến Issue vừa thêm
burntIssue.issueDesc = "burnt";
burntIssue.quorum = 0;
burntIssue.totalVotes = 0;
burntIssue.votesFor = 0;
burntIssue.votesAgainst = 0;
burntIssue.votesAbstain = 0;
burntIssue.passed = false;
burntIssue.closed = true;
// Lưu ý: voters được khởi tạo tự động trống, không cần gán
}
function claim() external {
if (claimed[msg.sender]) {
revert TokensClaimed();
}
if (claimedTokens >= MAX_SUPPLY) {
revert AllTokensClaimed();
}
claimed[msg.sender] = true;
_mint(msg.sender, 100);
claimedTokens += 100;
}
function createIssue(
string calldata _issueDesc,
uint _quorum
) external returns (uint) {
if (balanceOf(msg.sender) == 0) {
revert NoTokensHeld();
}
if (_quorum > totalSupply()) {
revert QuorumTooHigh(_quorum);
}
issues.push(); // Thêm một Issue rỗng
uint issueId = issues.length - 1; // Lấy ID của Issue mới
Issue storage newIssue = issues[issueId]; // Lấy tham chiếu đến Issue
newIssue.issueDesc = _issueDesc;
newIssue.quorum = _quorum;
newIssue.totalVotes = 0;
newIssue.votesFor = 0;
newIssue.votesAgainst = 0;
newIssue.votesAbstain = 0;
newIssue.passed = false;
newIssue.closed = false;
// voters được khởi tạo tự động trống
return issueId;
}
function getIssue(uint _id) external view returns (FormattedIssue memory) {
Issue storage issue = issues[_id];
return
FormattedIssue({
voters: issue.voters.values(),
issueDesc: issue.issueDesc,
quorum: issue.quorum,
totalVotes: issue.totalVotes,
votesFor: issue.votesFor,
votesAgainst: issue.votesAgainst,
votesAbstain: issue.votesAbstain,
passed: issue.passed,
closed: issue.closed
});
}
function vote(uint _issueId, Vote _vote) external {
Issue storage issue = issues[_issueId];
if (issue.closed) {
revert VotingClosed();
}
if (issue.voters.contains(msg.sender)) {
revert AlreadyVoted();
}
uint balance = balanceOf(msg.sender);
if (balance == 0) {
revert NoTokensHeld();
}
issue.voters.add(msg.sender);
if (_vote == Vote.AGAINST) {
issue.votesAgainst += balance;
} else if (_vote == Vote.FOR) {
issue.votesFor += balance;
} else {
issue.votesAbstain += balance;
}
issue.totalVotes += balance;
if (issue.totalVotes >= issue.quorum) {
issue.closed = true;
if (issue.votesFor > issue.votesAgainst) {
issue.passed = true;
}
}
}
}