-
Notifications
You must be signed in to change notification settings - Fork 50
/
Copy pathTokenSellerFactory.sol
279 lines (254 loc) · 10.4 KB
/
TokenSellerFactory.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
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
pragma solidity ^0.4.4;
// ------------------------------------------------------------------------
// TokenSellerFactory
//
// Decentralised trustless ERC20-partially-compliant token to ETH exchange
// contract on the Ethereum blockchain.
//
// This caters for the Golem Network Token which does not implement the
// ERC20 transferFrom(...), approve(...) and allowance(...) methods
//
// Enjoy. (c) JonnyLatte, Cintix & BokkyPooBah 2016. The MIT licence.
// ------------------------------------------------------------------------
// https://github.com/ethereum/EIPs/issues/20
contract ERC20Partial {
function totalSupply() constant returns (uint totalSupply);
function balanceOf(address _owner) constant returns (uint balance);
function transfer(address _to, uint _value) returns (bool success);
// function transferFrom(address _from, address _to, uint _value) returns (bool success);
// function approve(address _spender, uint _value) returns (bool success);
// function allowance(address _owner, address _spender) constant returns (uint remaining);
event Transfer(address indexed _from, address indexed _to, uint _value);
// event Approval(address indexed _owner, address indexed _spender, uint _value);
}
contract Owned {
address public owner;
event OwnershipTransferred(address indexed _from, address indexed _to);
function Owned() {
owner = msg.sender;
}
modifier onlyOwner {
if (msg.sender != owner) throw;
_;
}
function transferOwnership(address newOwner) onlyOwner {
OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
// contract can sell tokens for ETH
// prices are in amount of wei per batch of token units
contract TokenSeller is Owned {
address public asset; // address of token
uint256 public sellPrice; // contract sells lots of tokens at this price
uint256 public units; // lot size (token-wei)
bool public sellsTokens; // is contract selling
event ActivatedEvent(bool sells);
event MakerWithdrewAsset(uint256 tokens);
event MakerWithdrewERC20Token(address tokenAddress, uint256 tokens);
event MakerWithdrewEther(uint256 ethers);
event TakerBoughtAsset(address indexed buyer, uint256 ethersSent,
uint256 ethersReturned, uint256 tokensBought);
// Constructor - only to be called by the TokenSellerFactory contract
function TokenSeller (
address _asset,
uint256 _sellPrice,
uint256 _units,
bool _sellsTokens
) internal {
asset = _asset;
sellPrice = _sellPrice;
units = _units;
sellsTokens = _sellsTokens;
ActivatedEvent(sellsTokens);
}
// Maker can activate or deactivate this contract's
// selling status
//
// The ActivatedEvent() event is logged with the following
// parameter:
// sellsTokens this contract can sell asset tokens
function activate (
bool _sellsTokens
) onlyOwner {
sellsTokens = _sellsTokens;
ActivatedEvent(sellsTokens);
}
// Maker can withdraw asset tokens from this contract, with the
// following parameter:
// tokens is the number of asset tokens to be withdrawn
//
// The MakerWithdrewAsset() event is logged with the following
// parameter:
// tokens is the number of tokens withdrawn by the maker
//
// This method was called withdrawAsset() in the old version
function makerWithdrawAsset(uint256 tokens) onlyOwner returns (bool ok) {
MakerWithdrewAsset(tokens);
return ERC20Partial(asset).transfer(owner, tokens);
}
// Maker can withdraw any ERC20 asset tokens from this contract
//
// This method is included in the case where this contract receives
// the wrong tokens
//
// The MakerWithdrewERC20Token() event is logged with the following
// parameter:
// tokenAddress is the address of the tokens withdrawn by the maker
// tokens is the number of tokens withdrawn by the maker
//
// This method was called withdrawToken() in the old version
function makerWithdrawERC20Token(
address tokenAddress,
uint256 tokens
) onlyOwner returns (bool ok) {
MakerWithdrewERC20Token(tokenAddress, tokens);
return ERC20Partial(tokenAddress).transfer(owner, tokens);
}
// Maker withdraws ethers from this contract
//
// The MakerWithdrewEther() event is logged with the following parameter
// ethers is the number of ethers withdrawn by the maker
//
// This method was called withdraw() in the old version
function makerWithdrawEther(uint256 ethers) onlyOwner returns (bool ok) {
if (this.balance >= ethers) {
MakerWithdrewEther(ethers);
return owner.send(ethers);
}
}
// Taker buys asset tokens by sending ethers
//
// The TakerBoughtAsset() event is logged with the following parameters
// buyer is the buyer's address
// ethersSent is the number of ethers sent by the buyer
// ethersReturned is the number of ethers sent back to the buyer as
// change
// tokensBought is the number of asset tokens sent to the buyer
//
// This method was called buy() in the old version
function takerBuyAsset() payable {
if (sellsTokens || msg.sender == owner) {
uint order = msg.value / sellPrice;
uint can_sell = ERC20Partial(asset).balanceOf(address(this)) / units;
uint256 change = 0;
if (order > can_sell) {
change = msg.value - (can_sell * sellPrice);
order = can_sell;
if (!msg.sender.send(change)) throw;
}
if (order > 0) {
if(!ERC20Partial(asset).transfer(msg.sender, order * units)) throw;
}
TakerBoughtAsset(msg.sender, msg.value, order * units, change);
}
// Return user funds if the contract is not selling
else if (!msg.sender.send(msg.value)) throw;
}
// Taker buys tokens by sending ethers
function () payable {
takerBuyAsset();
}
}
// This contract deploys TokenSeller contracts and logs the event
contract TokenSellerFactory is Owned {
event TradeListing(address indexed ownerAddress, address indexed tokenSellerAddress,
address indexed asset, uint256 sellPrice, uint256 units, bool sellsTokens);
event OwnerWithdrewERC20Token(address indexed tokenAddress, uint256 tokens);
mapping(address => bool) _verify;
// Anyone can call this method to verify the settings of a
// TokenSeller contract. The parameters are:
// tradeContract is the address of a TokenSeller contract
//
// Return values:
// valid did this TokenTraderFactory create the TokenTrader contract?
// owner is the owner of the TokenTrader contract
// asset is the ERC20 asset address
// sellPrice is the sell price in ethers per `units` of asset tokens
// units is the number of units of asset tokens
// sellsTokens is the TokenTrader contract selling tokens?
//
function verify(address tradeContract) constant returns (
bool valid,
address owner,
address asset,
uint256 sellPrice,
uint256 units,
bool sellsTokens
) {
valid = _verify[tradeContract];
if (valid) {
TokenSeller t = TokenSeller(tradeContract);
owner = t.owner();
asset = t.asset();
sellPrice = t.sellPrice();
units = t.units();
sellsTokens = t.sellsTokens();
}
}
// Maker can call this method to create a new TokenSeller contract
// with the maker being the owner of this new contract
//
// Parameters:
// asset is the ERC20 asset address
// sellPrice is the sell price in ethers per `units` of asset tokens
// units is the number of units of asset tokens
// sellsTokens is the TokenSeller contract selling tokens?
//
// For example, listing a TokenSeller contract on the GNT Golem Network Token
// where the contract will sell GNT tokens at a rate of 170/100000 = 0.0017 ETH
// per GNT token:
// asset 0xa74476443119a942de498590fe1f2454d7d4ac0d
// sellPrice 170
// units 100000
// sellsTokens true
//
// The TradeListing() event is logged with the following parameters
// ownerAddress is the Maker's address
// tokenSellerAddress is the address of the newly created TokenSeller contract
// asset is the ERC20 asset address
// sellPrice is the sell price in ethers per `units` of asset tokens
// unit is the number of units of asset tokens
// sellsTokens is the TokenSeller contract selling tokens?
//
// This method was called createTradeContract() in the old version
//
function createSaleContract(
address asset,
uint256 sellPrice,
uint256 units,
bool sellsTokens
) returns (address seller) {
// Cannot set zero or negative price
if (sellPrice <= 0) throw;
// Cannot sell zero or negative units
if (units <= 0) throw;
seller = new TokenSeller(
asset,
sellPrice,
units,
sellsTokens);
// Record that this factory created the trader
_verify[seller] = true;
// Set the owner to whoever called the function
TokenSeller(seller).transferOwnership(msg.sender);
TradeListing(msg.sender, seller, asset, sellPrice, units, sellsTokens);
}
// Factory owner can withdraw any ERC20 asset tokens from this contract
//
// This method is included in the case where this contract receives
// the wrong tokens
//
// The OwnerWithdrewERC20Token() event is logged with the following
// parameter:
// tokenAddress is the address of the tokens withdrawn by the maker
// tokens is the number of tokens withdrawn by the maker
function ownerWithdrawERC20Token(address tokenAddress, uint256 tokens) onlyOwner returns (bool ok) {
OwnerWithdrewERC20Token(tokenAddress, tokens);
return ERC20Partial(tokenAddress).transfer(owner, tokens);
}
// Prevents accidental sending of ether to the factory
function () {
throw;
}
}