-
Notifications
You must be signed in to change notification settings - Fork 0
/
simpleDAO.sol
185 lines (139 loc) · 5.56 KB
/
simpleDAO.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
// SPDX-License-Identifier: MIT
pragma solidity >=0.7.0 <0.9.0;
/// @title Simple DAO smart contract.
contract simpleDAO {
// This simple proof of concept DAO smart contract sends ether to the digital vending machine
// only if the majority of the DAO members vote "yes" to buy digital cookies.
// If the majority of the DAO members decide not to send ether, the members who deposited ether
// are able to withdraw the ether they deposited.
// address of vending machine
address payable public VendingMachineAddress;
uint public voteEndTime;
// balance of ether in the smart contract
uint public DAObalance;
// allow withdrawals
mapping(address=>uint) balances;
// proposal decision of voters
uint decision;
// default set as false
// makes sure votes are counted before ending vote
bool ended;
struct Voter {
uint weight; // weight is accumulated by delegation
bool voted; // if true, that person already voted
address delegate; // person delegated to
uint vote; // index of the voted proposal
}
struct Proposal {
string name; // short name (up to 32 bytes)
uint voteCount; // number of accumulated votes
}
// address of the person who set up the vote
address public chairperson;
mapping(address => Voter) public voters;
Proposal[] public proposals;
//error handlers
/// The vote has already ended.
error voteAlreadyEnded();
/// The auction has not ended yet.
error voteNotYetEnded();
// Sample input string: ["buy_cupcakes", "no_cupcakes"]
// First item in string is the one that will execute the purchase
// _VendingMachineAddress is the address where the ether will be sent
constructor(
address payable _VendingMachineAddress,
uint _voteTime,
string[] memory proposalNames
) {
VendingMachineAddress = _VendingMachineAddress;
chairperson = msg.sender;
voteEndTime = block.timestamp + _voteTime;
voters[chairperson].weight = 1;
for (uint i = 0; i < proposalNames.length; i++) {
proposals.push(Proposal({
name: proposalNames[i],
voteCount: 0
}));
}
}
// anyone can deposit ether to the DAO smart contract
// members must deposit at least 1 eth into DAO
// this is to avoid complications during withdrawl if the DAO voted to buy cupcakes
function DepositEth() public payable {
DAObalance = address(this).balance;
if (block.timestamp > voteEndTime)
revert voteAlreadyEnded();
require(DAObalance <= 1 ether, "1 Ether balance has been reached");
DAObalance = address(this).balance;
balances[msg.sender]+=msg.value;
}
// only the chairperson can decide who can vote
function giveRightToVote(address voter) public {
require(
msg.sender == chairperson,
"Only chairperson can give right to vote."
);
require(
!voters[voter].voted,
"The voter already voted."
);
require(voters[voter].weight == 0);
voters[voter].weight = 1;
}
// proposals are in format 0,1,2,...
function vote(uint proposal) public {
Voter storage sender = voters[msg.sender];
require(sender.weight != 0, "Has no right to vote");
require(!sender.voted, "Already voted.");
sender.voted = true;
sender.vote = proposal;
proposals[proposal].voteCount += sender.weight;
}
// winningProposal must be executed before EndVote
function countVote() public
returns (uint winningProposal_)
{
require(
block.timestamp > voteEndTime,
"Vote not yet ended.");
uint winningVoteCount = 0;
for (uint p = 0; p < proposals.length; p++) {
if (proposals[p].voteCount > winningVoteCount) {
winningVoteCount = proposals[p].voteCount;
winningProposal_ = p;
decision = winningProposal_;
ended = true;
}
}
}
// Individuals can only withdraw what they deposited.
// After EndVote function is run and if proposal "buy_cupcakes" won,
// users will not be able to withdraw ether
function withdraw(uint amount) public{
if(balances[msg.sender]>=amount){
balances[msg.sender]-=amount;
payable(msg.sender).transfer(amount);
DAObalance = address(this).balance;
}
}
// ends the vote
// if DAO decided not to buy cupcakes members can withdraw deposited ether
function EndVote() public {
require(
block.timestamp > voteEndTime,
"Vote not yet ended.");
require(
ended == true,
"Must count vote first");
require(
DAObalance >= 1 ether,
"Not enough balance in DAO required to buy cupcake. Members may withdraw deposited ether.");
require(
decision == 0,
"DAO decided to not buy cupcakes. Members may withdraw deposited ether.");
if (DAObalance < 1 ether) revert();
(bool success, ) = address(VendingMachineAddress).call{value: 1 ether}(abi.encodeWithSignature("purchase(uint256)", 1));
require(success);
DAObalance = address(this).balance;
}
}