-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathEtherDelta.etiml
339 lines (274 loc) · 14.9 KB
/
EtherDelta.etiml
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
pragma etiml ^0.1
structure Pervasive = struct
fun addBy b a = a + b
fun subBy b a = a - b
fun orBy b a = a || b
(* fun waste_time () = 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 *)
fun require b = if b then (* waste_time (); *)() else (throw using _) end
val ether = 1000000000000000000
val minute = 60
end
structure SafeMath = struct
internal fun safeMul (a : uint, b : uint) return uint =
let c : uint = a * b;
require(a == 0 || c / a == b);
c
internal fun safeSub (a : uint, b : uint) return uint =
require(b <= a);
a - b
internal fun safeAdd (a : uint, b : uint) return uint =
let c : uint = a + b;
require(c>=a && c>=b);
c
end
interface Token = sig
(* @param _owner The address from which the balance will be retrieved *)
(* @return The balance *)
fun balanceOf (_owner : address) constant return uint256
(*
/// @notice send `_value` token to `_to` from `msg.sender`
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
*)
fun transfer (_to : address, _value : uint256) return bool
(*
/// @notice send `_value` token to `_to` from `_from` on the condition it is approved by `_from`
/// @param _from The address of the sender
/// @param _to The address of the recipient
/// @param _value The amount of token to be transferred
/// @return Whether the transfer was successful or not
*)
fun transferFrom (_from : address, _to : address, _value : uint256) return bool
(*
/// @notice `msg.sender` approves `_addr` to spend `_value` tokens
/// @param _spender The address of the account able to transfer the tokens
/// @param _value The amount of wei to be approved for transfer
/// @return Whether the approval was successful or not
*)
fun approve (_spender : address, _value : uint256) return bool
(*
/// @param _owner The address of the account owning tokens
/// @param _spender The address of the account able to transfer the tokens
/// @return Amount of remaining tokens allowed to spent
*)
fun allowance (_owner : address, _spender : address) constant return uint256
event Transfer(indexed _from : address, indexed _to : address, _value : uint256)
event Approval(indexed _owner : address, indexed _spender : address, _value : uint256)
(* public state decimals : cell uint *)
(* public state name : cell string *)
end
contract StandardToken = struct
open Pervasive
state balances : map address uint256
state allowed : map address (map address uint256)
public state totalSupply : cell uint256
fun transfer (_to : address, _value : uint256) return bool =
(*
//Default assumes totalSupply can't be over max (2^256 - 1).
//If your token leaves out totalSupply and can issue more tokens as time goes on, you need to check if it doesn't wrap.
//Replace the if with this one instead.
*)
if balances[msg.sender] >= _value && balances[_to] + _value > balances[_to] then
(* //if (balances[msg.sender] >= _value && _value > 0) { *)
modify balances[msg.sender] -= _value;
modify balances[_to] += _value;
(* emit Transfer(msg.sender, _to, _value); *)
true
else
false
end
fun transferFrom (_from : address, _to : address, _value : uint256) return bool =
(* same as above. Replace this line with the following if you want to protect against wrapping uints. *)
if balances[_from] >= _value && allowed[_from][msg.sender] >= _value && balances[_to] + _value > balances[_to] then
(* //if (balances[_from] >= _value && allowed[_from][msg.sender] >= _value && _value > 0) { *)
modify balances[_to] += _value;
modify balances[_from] -= _value;
modify allowed[_from][msg.sender] -= _value;
(* emit Transfer(_from, _to, _value); *)
true
else
false
end
fun balanceOf (_owner : address) constant return uint256 =
balances[_owner]
fun approve (_spender : address, _value : uint256) return bool =
set allowed[msg.sender][_spender] _value;
(* emit Approval(msg.sender, _spender, _value); *)
true
fun allowance (_owner : address, _spender : address) constant return uint256 =
allowed[_owner][_spender]
end
contract ReserveToken = struct
open SafeMath
open StandardToken
public state minter : cell address
fun constructor () =
minter ::= msg.sender
fun create (account : address, amount : uint) =
if msg.sender != !!minter then throw end;
set balances[account] safeAdd(balances[account], amount);
totalSupply ::= safeAdd(!!totalSupply, amount)
fun destroy (account : address, amount : uint) =
if msg.sender != !!minter then throw end;
if balances[account] < amount then throw end;
set balances[account] safeSub(balances[account], amount);
totalSupply ::= safeSub(!!totalSupply, amount)
end
interface AccountLevels = sig
(*
//given a user, return an account level
//0 = regular user (pays take fee and make fee)
//1 = market maker silver (pays take fee, no make fee, gets rebate)
//2 = market maker gold (pays take fee, no make fee, gets entire counterparty's take fee as rebate)
*)
fun accountLevel (user : address) constant return uint
end
contract AccountLevelsTest = struct
public state accountLevels : map address uint
fun setAccountLevel (user : address, level : uint) =
set accountLevels[user] level
fun accountLevel (user : address) constant return uint =
accountLevels[user]
end
contract EtherDelta = struct
open SafeMath
public state admin : cell address (* the admin address *)
public state feeAccount : cell address (* the account that will receive fees *)
public state accountLevelsAddr : cell address (* the address of the AccountLevels contract *)
public state feeMake : cell uint (* percentage times (1 ether) *)
public state feeTake : cell uint (* percentage times (1 ether) *)
public state feeRebate : cell uint (* percentage times (1 ether) *)
public state tokens : map address (map address uint) (* mapping of token addresses to mapping of account balances (token=0 means Ether) *)
public state orders : map address (map bytes32 bool) (* mapping of user accounts to mapping of order hashes to booleans (true = submitted by user, equivalent to offchain signature) *)
public state orderFills : map address (map bytes32 uint) (* mapping of user accounts to mapping of order hashes to uints (amount of order that has been filled) *)
event Order(tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address)
event Cancel(tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address, v : uint8, r : bytes32, s : bytes32)
event Trade(tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, get : address, give : address)
event Deposit(token : address, user : address, amount : uint, balance : uint)
event Withdraw(token : address, user : address, amount : uint, balance : uint)
fun constructor (admin_ : address, feeAccount_ : address, accountLevelsAddr_ : address, feeMake_ : uint, feeTake_ : uint, feeRebate_ : uint) =
admin ::= admin_;
feeAccount ::= feeAccount_;
accountLevelsAddr ::= accountLevelsAddr_;
feeMake ::= feeMake_;
feeTake ::= feeTake_;
feeRebate ::= feeRebate_
fun default () =
throw
fun changeAdmin (admin_ : address) =
if msg.sender != !!admin then throw end;
admin ::= admin_
fun changeAccountLevelsAddr (accountLevelsAddr_ : address) =
if (msg.sender != !!admin) then throw end;
accountLevelsAddr ::= accountLevelsAddr_
fun changeFeeAccount (feeAccount_ : address) =
if (msg.sender != !!admin) then throw end;
feeAccount ::= feeAccount_
fun changeFeeMake (feeMake_ : uint) =
if (msg.sender != !!admin) then throw end;
if (feeMake_ > !!feeMake) then throw end;
feeMake ::= feeMake_
fun changeFeeTake (feeTake_ : uint) =
if (msg.sender != !!admin) then throw end;
if (feeTake_ > !!feeTake || feeTake_ < !!feeRebate) then throw end;
feeTake ::= feeTake_
fun changeFeeRebate (feeRebate_ : uint) =
if (msg.sender != !!admin) then throw end;
if (feeRebate_ < !!feeRebate || feeRebate_ > !!feeTake) then throw end;
feeRebate ::= feeRebate_
fun deposit () payable =
set tokens[0][msg.sender] safeAdd(tokens[0][msg.sender], msg.value)
(* emit Deposit(0, msg.sender, msg.value, tokens[0][msg.sender]) *)
fun withdraw (amount : uint) =
if (tokens[0][msg.sender] < amount) then throw end;
set tokens[0][msg.sender] safeSub(tokens[0][msg.sender], amount)
(* if not (send msg.sender amount) then throw end; *)
(* emit Withdraw(0, msg.sender, amount, tokens[0][msg.sender]) *)
fun depositToken (token : address, amount : uint) =
(*remember to call Token(address).approve(this, amount) or this contract will not be able to do the transfer on your behalf.*)
if (token==0) then throw end;
(* if not (call false (attach token Token) transferFrom(msg.sender, this, amount)) then throw end; *)
set tokens[token][msg.sender] safeAdd(tokens[token][msg.sender], amount)
(* emit Deposit(token, msg.sender, amount, tokens[token][msg.sender]) *)
fun withdrawToken (token : address, amount : uint) =
if (token==0) then throw end;
if (tokens[token][msg.sender] < amount) then throw end;
set tokens[token][msg.sender] safeSub(tokens[token][msg.sender], amount)
(* if not (call false (attach token Token) transfer(msg.sender, amount)) then throw end; *)
(* emit Withdraw(token, msg.sender, amount, tokens[token][msg.sender]) *)
fun balanceOf (token : address, user : address) constant return uint =
tokens[token][user]
fun order (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint) =
let hash : bytes32 = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
set orders[msg.sender][hash] true
(* emit Order(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender) *)
private fun tradeBalances (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, user : address, amount : uint) =
let feeMakeXfer : uint = safeMul(amount, !!feeMake) / ether;
let feeTakeXfer : uint = safeMul(amount, !!feeTake) / ether;
let feeRebateXfer = ref 0;
if (!!accountLevelsAddr != 0) then
let accountLevel : uint = (* call 0 (attach accountLevelsAddr AccountLevels) accountLevel(user) *)1;
if (accountLevel==1) then feeRebateXfer := safeMul(amount, !!feeRebate) / ether end;
if (accountLevel==2) then feeRebateXfer := feeTakeXfer end
end;
set tokens[tokenGet][msg.sender] safeSub(tokens[tokenGet][msg.sender], safeAdd(amount, feeTakeXfer));
set tokens[tokenGet][user] safeAdd(tokens[tokenGet][user], safeSub(safeAdd(amount, !feeRebateXfer), feeMakeXfer));
set tokens[tokenGet][!!feeAccount] safeAdd(tokens[tokenGet][!!feeAccount], safeSub(safeAdd(feeMakeXfer, feeTakeXfer), !feeRebateXfer));
set tokens[tokenGive][user] safeSub(tokens[tokenGive][user], safeMul(amountGive, amount) / amountGet);
set tokens[tokenGive][msg.sender] safeAdd(tokens[tokenGive][msg.sender], safeMul(amountGive, amount) / amountGet)
fun trade (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address, v : uint8, r : bytes32, s : bytes32, amount : uint) =
(*amount is in amountGet terms*)
let hash : bytes32 = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
if (not (
(orders[user][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) &&
block.number <= expires &&
safeAdd(orderFills[user][hash], amount) <= amountGet
)) then throw end;
tradeBalances(tokenGet, amountGet, tokenGive, amountGive, user, amount);
set orderFills[user][hash] safeAdd(orderFills[user][hash], amount)
(* emit Trade(tokenGet, amount, tokenGive, amountGive * amount / amountGet, user, msg.sender) *)
(* ;(orderFills[user][hash], tokens[tokenGet][msg.sender], tokens[tokenGet][user], tokens[tokenGive][msg.sender], tokens[tokenGive][user]) *)
fun availableVolume (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address, v : uint8, r : bytes32, s : bytes32) constant =
let hash : bytes32 = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
if (not (
(orders[user][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == user) &&
block.number <= expires
))
then
0
else
let available1 : uint = safeSub(amountGet, orderFills[user][hash]);
let available2 : uint = safeMul(tokens[tokenGive][user], amountGet) / amountGive;
if (available1<available2) then
available1
else
available2
end
end
fun testTrade (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address, v : uint8, r : bytes32, s : bytes32, amount : uint, sender : address) constant return bool =
if (not (
tokens[tokenGet][sender] >= amount &&
availableVolume(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, user, v, r, s) >= amount
)) then false
else true
end
fun amountFilled (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, user : address, v : uint8, r : bytes32, s : bytes32) constant return uint =
let hash : bytes32 = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
orderFills[user][hash]
fun cancelOrder (tokenGet : address, amountGet : uint, tokenGive : address, amountGive : uint, expires : uint, nonce : uint, v : uint8, r : bytes32, s : bytes32) =
let hash : bytes32 = sha256(this, tokenGet, amountGet, tokenGive, amountGive, expires, nonce);
if (not (orders[msg.sender][hash] || ecrecover(sha3("\x19Ethereum Signed Message:\n32", hash),v,r,s) == msg.sender)) then throw end;
set orderFills[msg.sender][hash] amountGet
(* emit Cancel(tokenGet, amountGet, tokenGive, amountGive, expires, nonce, msg.sender, v, r, s) *)
val _ = constructor (0x8888, 0x8888, 0x8888, 1, 1, 1)
(* val _ = set tokens[0x1111][0x8888] 0x20 *)
(* val _ = set tokens[0x2222][0x4444] 0x20 *)
(* val _ = set orders[0x4444][0] true *)
(* val _ = trade (0x1111, 0x10, 0x2222, 0x10, 0xffffffffffff, 0, 0x4444, 0, 0, 0, 5) *)
(* (* val _ = availableVolume(0x1111, 0x10, 0x2222, 0x10, 0xffffffffffff, 0, 0x4444, 0, 0, 0) *) *)
(* (* val () = halt 0x555 *) *)
(* (* val _ = dispatch {trade = trade, *) *)
(* (* availableVolume = availableVolume, *) *)
(* (* } *) *)
end