-
Notifications
You must be signed in to change notification settings - Fork 0
/
DAO.sol
229 lines (179 loc) · 7.66 KB
/
DAO.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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
pragma solidity ^0.4.8;
contract DAO{
uint256 tokenCost;
uint256 tokenSellLength;
uint256 start;
DAOToken daoToken;
uint256 votingLength;
mapping(uint => Proposal) proposalsID;
uint currProp;
struct Proposal{
uint256 startTime;
address recipient;
uint256 amount;
string description;
uint256 amountROI;
mapping (address => VotingInfo) votingInfo;
uint256 numVotesFor;
uint256 numVoted;
}
struct VotingInfo{
bool voted;
bool vote;
}
modifier isTokenHolder{
if (daoToken.balanceOf(msg.sender) == 0) throw;
_;
}
modifier noLiveProposals{
uint256 propStartTime = proposalsID[currProp].startTime;
if( propStartTime != 0 &&
now <= (propStartTime + votingLength)) throw;
_;
}
function DAO (uint256 _tokenCost, uint256 _tokenSellLength, uint256 _votingLength){
start = now;
tokenCost = _tokenCost;
tokenSellLength = _tokenSellLength;
votingLength = _votingLength;
// The totalSupply is 0 until no more tokens can be sold.
daoToken = new DAOToken(0, this);
}
function invest() payable returns (bool success) {
if(now > (start + tokenSellLength)) return false;
uint256 numTokens = msg.value/tokenCost;
uint256 change = msg.value - numTokens*tokenCost;
daoToken.addTokens(msg.sender, numTokens);
msg.sender.transfer(change);
return true;
}
// this function has two modifiers. Together, they make sure only token
// holders can call this function when there are no live proposals. This means
// there cannot be more than 1 live proposal at a time. When this function
// is called, it creates a new proposal, adds the appropriate information
// to the proposals mapping, then sets the liveProposal to the proposal
// that was just created.
function newProposal(address _recipient, uint _amount, string _description, uint _amountROI) isTokenHolder noLiveProposals returns (uint256 _proposalID) {
uint256 proposalID = (uint256)(sha3(_recipient, _amount, _description, _amountROI));
Proposal memory newProp = Proposal(now, _recipient, _amount, _description, _amountROI, 0, 0);
proposalsID[proposalID] = newProp;
currProp = proposalID;
return proposalID;
}
// This function allows token holders to vote.
function vote(uint _proposalID, bool _supportProposal) isTokenHolder {
Proposal proposal = proposalsID[_proposalID];
if(now > (proposal.startTime + votingLength)) throw;
if(proposal.votingInfo[msg.sender].voted){
if(proposal.votingInfo[msg.sender].vote && !_supportProposal){
proposal.numVotesFor -= daoToken.balanceOf(msg.sender);
} else if(proposal.votingInfo[msg.sender].vote && _supportProposal){
proposal.numVotesFor += daoToken.balanceOf(msg.sender);
}
} else {
if (_supportProposal) proposal.numVotesFor += daoToken.balanceOf(msg.sender);
proposal.numVoted++;
proposal.votingInfo[msg.sender].vote = _supportProposal;
proposal.votingInfo[msg.sender].voted = true;
}
}
function executeProposal(uint _proposalId) returns (bool success) {
Proposal currProp = proposalsID[_proposalId];
if(now < (currProp.startTime + votingLength)) return false;
if(currProp.numVotesFor > (currProp.numVoted - currProp.numVotesFor)) {
currProp.recipient.transfer(currProp.amount);
return true;
}
return false;
}
function transfer(address _to, uint _value) noLiveProposals returns (bool){
return daoToken.transfer(_to, _value);
}
function transferFrom(address _from, address _to, uint256 _value) noLiveProposals returns (bool success){
return daoToken.transferFrom(_from, _to, _value);
}
// Can approve while there are live proposals, but cannot actually withdraw.
// In other words, the transaction can be allowed but not carried out.
function approve(address _spender, uint _value) returns (bool){
return daoToken.approve(_spender, _value);
}
function balanceOf(address _owner) constant returns (uint256 balance){
return daoToken.balanceOf(_owner);
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return daoToken.allowance(_owner, _spender);
}
function payBackInvestment(uint _proposalId) payable returns (bool success){
return transferFrom(msg.sender, this, proposalsID[_proposalId].amountROI +
proposalsID[_proposalId].amount);
}
function withdrawEther() noLiveProposals returns (bool){
msg.sender.transfer(daoToken.burnTokens()*this.balance);
return true;
}
}
contract DAOToken {
uint256 public totalSupply;
mapping (address => uint256) public balanceOf;
mapping (address => mapping (address => uint256)) approvals;
address private DAOAddress;
uint256 public numTokenHolders = 0;
event Transfer(address indexed _from, address indexed _to, uint256 _value);
event Approval(address indexed _owner, address indexed _spender, uint256 _value);
function DAOToken(uint256 _totalSupply, address _DAOAddress){
totalSupply = _totalSupply;
DAOAddress = _DAOAddress;
}
modifier isDAO{
if(msg.sender != DAOAddress) throw;
_;
}
function numTokenHolders() constant returns (uint256 numTokenHolders){
return numTokenHolders;
}
function totalSupply() constant returns (uint256 totalSupply){
return totalSupply;
}
function balanceOf(address _owner) constant returns (uint256 balance){
return balanceOf[_owner];
}
function transfer(address _to, uint256 _value) isDAO returns (bool success){
if(balanceOf[msg.sender] < _value) return false;
if(balanceOf[_to] == 0) numTokenHolders++;
balanceOf[_to] += _value;
balanceOf[msg.sender] -= _value;
Transfer(msg.sender, _to, _value);
return true;
}
function transferFrom(address _from, address _to, uint256 _value) isDAO returns (bool success){
if(balanceOf[msg.sender] < _value) return false;
if(approvals[_from][msg.sender] < _value) return false;
if(balanceOf[_to] == 0) numTokenHolders++;
balanceOf[_to] += _value;
balanceOf[_from] -= _value;
approvals[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
return true;
}
function approve(address _spender, uint256 _value) isDAO returns (bool success){
if(balanceOf[msg.sender] < _value) return false;
approvals[msg.sender][_spender] += _value;
Approval(msg.sender, _spender, _value);
return true;
}
function allowance(address _owner, address _spender) constant returns (uint256 remaining) {
return approvals[_owner][msg.sender];
}
function addTokens(address _owner, uint256 _amount) isDAO {
totalSupply += _amount;
if(balanceOf[_owner] == 0) numTokenHolders++;
balanceOf[_owner] += _amount;
}
function burnTokens() isDAO returns (uint256 _etherAmount){
uint256 etherAmount = balanceOf[msg.sender]/totalSupply;//msg.sender.value;
numTokenHolders--;
totalSupply -= balanceOf[msg.sender];
balanceOf[msg.sender] = 0;
return etherAmount;
}
}