forked from PAY-IT-FORWARD/contracts
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDutchAuction.sol
205 lines (158 loc) · 6.17 KB
/
DutchAuction.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
//! Copyright Parity Technologies, 2017.
//! Released under the Apache Licence 2.
pragma solidity ^0.4.7;
/// Stripped down ERC20 standard token interface.
contract Token {
function transfer(address _to, uint256 _value) returns (bool success);
}
/// Simple Dutch Auction contract. Price starts high and monotonically decreases
/// until all tokens are sold at the current price with currently received
/// funds.
contract DutchAuction {
/// Someone bought in at a particular max-price.
event Buyin(address indexed who, uint price, uint spent, uint refund);
/// The sale just ended with the current price.
event Ended(uint price);
/// Finalised the purchase for `who`, who has been given `tokens` tokens and
/// refunded `refund` (which is the remainder since only a whole number of
/// tokens may be purchased).
event Finalised(address indexed who, uint tokens);
/// Auction is over. All accounts finalised.
event Retired();
/// Simple constructor.
function DutchAuction(address _tokenContract, address _treasury, address _admin, uint _beginTime, uint _beginPrice, uint _saleSpeed, uint _tokenCap) {
tokenContract = Token(_tokenContract);
treasury = _treasury;
admin = _admin;
beginTime = _beginTime;
beginPrice = _beginPrice;
saleSpeed = _saleSpeed;
tokenCap = _tokenCap;
endTime = beginTime + beginPrice / saleSpeed;
}
/// Buyin function. Throws if the sale is not active. May refund some of the
/// funds if they would end the sale.
function()
payable
when_not_halted
when_active
avoid_dust
{
uint price = currentPrice();
uint tokens = msg.value / price;
uint refund = 0;
uint accepted = msg.value;
// if we've asked for too many, send back the extra.
if (tokens > tokensAvailable()) {
refund = (tokens - tokensAvailable()) * price;
if (!msg.sender.send(refund)) throw;
tokens = tokensAvailable();
accepted -= refund;
}
// send rest to treasury
if (!treasury.send(accepted)) throw;
// record the acceptance.
participants[msg.sender] += accepted;
totalReceived += accepted;
uint targetPrice = totalReceived / tokenCap;
uint salePriceDrop = beginPrice - targetPrice;
uint saleDuration = salePriceDrop / saleSpeed;
endTime = beginTime + saleDuration;
Buyin(msg.sender, price, accepted, refund);
}
/// Mint tokens for a particular participant.
function finalise(address _who)
when_not_halted
when_ended
only_participants(_who)
{
// end the auction if we're the first one to finalise.
if (endPrice == 0) {
endPrice = totalReceived / tokenCap;
Ended(endPrice);
}
// enact the purchase.
uint tokens = participants[_who] / endPrice;
uint refund = participants[_who] - endPrice * tokens;
totalFinalised += participants[_who];
participants[_who] = 0;
if (!tokenContract.transfer(_who, tokens)) throw;
Finalised(_who, tokens);
if (totalFinalised == totalReceived) {
Retired();
}
}
/// Emergency function to pause buy-in and finalisation.
function setHalted(bool _halted) only_admin { halted = _halted; }
/// Emergency function to drain the contract of any funds.
function drain() only_admin { if (!treasury.send(this.balance)) throw; }
/// Kill this contract once the sale is finished.
function kill() when_all_finalised { suicide(admin); }
/// The current price for a single token. If a buyin happens now, this is
/// the highest price per token that the buyer will pay.
function currentPrice() constant returns (uint weiPerToken) {
if (!isActive()) return 0;
return beginPrice - (now - beginTime) * saleSpeed;
}
/// Returns the tokens available for purchase right now.
function tokensAvailable() constant returns (uint tokens) {
if (!isActive()) return 0;
return tokenCap - totalReceived / currentPrice();
}
/// The largest purchase than can be made at present.
function maxPurchase() constant returns (uint spend) {
if (!isActive()) return 0;
return tokenCap * currentPrice() - totalReceived;
}
/// True if the sale is ongoing.
function isActive() constant returns (bool) { return now >= beginTime && now < endTime; }
/// True if all participants have finalised.
function allFinalised() constant returns (bool) { return now >= endTime && totalReceived == totalFinalised; }
/// Ensure the sale is ongoing.
modifier when_active { if (isActive()) _; else throw; }
/// Ensure the sale is ended.
modifier when_ended { if (now >= endTime) _; else throw; }
/// Ensure we're not halted.
modifier when_not_halted { if (!halted) _; else throw; }
/// Ensure all participants have finalised.
modifier when_all_finalised { if (allFinalised()) _; else throw; }
/// Ensure the sender sent a sensible amount of ether.
modifier avoid_dust { if (msg.value >= DUST_LIMIT) _; else throw; }
/// Ensure `_who` is a participant.
modifier only_participants(address _who) { if (participants[_who] != 0) _; else throw; }
/// Ensure sender is admin.
modifier only_admin { if (msg.sender == admin) _; else throw; }
// State:
/// The auction participants.
mapping (address => uint) public participants;
/// Total amount of ether received.
uint public totalReceived = 0;
/// Total amount of ether which has been finalised.
uint public totalFinalised = 0;
/// The current end time. Gets updated when new funds are received.
uint public endTime;
/// The price per token; only valid once the sale has ended and at least one
/// participant has finalised.
uint public endPrice;
/// Must be false for any public function to be called.
bool public halted;
// Constants after constructor:
/// The tokens contract.
Token public tokenContract;
/// The treasury address; where all the Ether goes.
address public treasury;
/// The admin address; auction can be paused or halted at any time by this.
address public admin;
/// The time at which the sale begins.
uint public beginTime;
/// Price at which the sale begins.
uint public beginPrice;
/// The speed at which the price reduces, in Wei per second.
uint public saleSpeed;
/// Maximum amount of tokens to mint. Once totalSale / currentPrice is
/// greater than this, the sale ends.
uint public tokenCap;
// Static constants:
/// Anything less than this is considered dust and cannot be used to buy in.
uint constant public DUST_LIMIT = 10 finney;
}