forked from Zilliqa/zilliqa-contracts
-
Notifications
You must be signed in to change notification settings - Fork 1
/
LockProxy.scilla
389 lines (350 loc) · 12.5 KB
/
LockProxy.scilla
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
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
scilla_version 0
import Polynetwork IntUtils Conversions
library LockProxy
(* toAssetHash, toAddress, amount *)
type TxArgs =
| TxArgs of ByStr ByStr Uint256
type Error =
| AdminValidationFailed
| AmountCannotBeZero
| LockAmountMismatch
| IllegalToAssetHash
| IllegalToAmount
| IllegalTargetProxy
| ManagerValidationFailed
| IllegalFromProxy
| ParseToAssetAddressFailed
| ParseToAddressFailed
| IllegalAmount
| EmptyFromProxy
| FromProxyNotExist
let make_error =
fun (result: Error) =>
let result_code =
match result with
| AdminValidationFailed => Int32 -1
| AmountCannotBeZero => Int32 -2
| LockAmountMismatch => Int32 -3
| IllegalToAssetHash => Int32 -4
| IllegalToAmount => Int32 -5
| IllegalTargetProxy => Int32 -6
| ManagerValidationFailed => Int32 -7
| IllegalFromProxy => Int32 -8
| ParseToAssetAddressFailed => Int32 -9
| ParseToAddressFailed => Int32 -10
| IllegalAmount => Int32 -11
| EmptyFromProxy => Int32 -12
| FromProxyNotExist => Int32 -13
end
in
{ _exception: "Error"; code: result_code }
let one_msg =
fun (m : Message) =>
let e = Nil {Message} in
Cons {Message} m e
let serialize_tx_args =
fun (args: TxArgs) =>
match args with
| TxArgs toAssetHash toAddress amount =>
let empty_str_0x = 0x in
let empty_str = builtin to_bystr empty_str_0x in
let to_asset_hash_str = append_varbytes empty_str toAssetHash in
let to_address = append_varbytes to_asset_hash_str toAddress in
let amount = append_uint256_le to_address amount in
amount
end
let deserialize_tx_args =
fun (value: ByStr) =>
fun (nextpos: Uint32) =>
let to_asset_hash_o = extract_bystr value nextpos in
match to_asset_hash_o with
| Some (Pair to_asset_hash nextpos) =>
let to_address_o = extract_bystr value nextpos in
match to_address_o with
| Some (Pair to_address nextpos) =>
let amount_o = extract_uint256_le value nextpos in
match amount_o with
| Some (Pair amount nextpos) =>
let tx_args = TxArgs to_asset_hash to_address amount in
Some { TxArgs } tx_args
| None => None { TxArgs }
end
| None => None { TxArgs }
end
| None => None { TxArgs }
end
let uint128_zero = Uint128 0
let uint32_zero = Uint32 0
let zero_address = 0x0000000000000000000000000000000000000000
let zero_bystr = let a = 0x in builtin to_bystr a
(* it is unlock *)
let unlock = let a = 0x756e6c6f636b in builtin to_bystr a
let uint128_max = Uint256 340282366920938463463374607431768211455
(***************************************************)
(* The contract definition *)
(***************************************************)
contract LockProxy(
init_admin: ByStr20,
init_manager_proxy: ByStr20,
init_manager: ByStr20
)
field contractadmin: ByStr20 = init_admin
field asset_map: Map ByStr20 (Map Uint64 ByStr) = Emp ByStr20 (Map Uint64 ByStr)
(* The LockProxy in other blockchains *)
field proxy_hash_map: Map Uint64 ByStr = Emp Uint64 ByStr
field manager: ByStr20 = init_manager
field manager_proxy: ByStr20 = init_manager_proxy
(* Procedures *)
procedure ThrowError(err: Error)
e = make_error err;
throw e
end
procedure IsAdmin(initiator: ByStr20)
contractadmin_tmp <- contractadmin;
is_admin = builtin eq initiator contractadmin_tmp;
match is_admin with
| True =>
| False =>
e = AdminValidationFailed;
ThrowError e
end
end
procedure IsManagerContract(initiator: ByStr20)
manager_l <- manager;
is_manager = builtin eq manager_l initiator;
match is_manager with
| True =>
| False =>
e = ManagerValidationFailed;
ThrowError e
end
end
(* lock amount should not be zero *)
procedure ValidateAmount(amount: Uint128)
is_zero = builtin eq amount uint128_zero;
match is_zero with
| True =>
e = AmountCannotBeZero;
ThrowError e
| False =>
end
end
procedure validateFromProxy(fromContractAddr: ByStr)
is_equal = builtin eq zero_bystr fromContractAddr;
match is_equal with
| True =>
e = EmptyFromProxy;
ThrowError e
| False =>
end
end
procedure ValidateToAssetHash(toAssetHash: ByStr)
is_equal = builtin eq zero_bystr toAssetHash;
match is_equal with
| True =>
e = IllegalToAssetHash;
ThrowError e
| False =>
end
end
procedure ValidateFromProxy(fromContractAddr: ByStr, fromChainId: Uint64)
e = { _eventname: "ValidateFromProxy"; fromContractAddr: fromContractAddr; fromChainId: fromChainId };
event e;
validateFromProxy fromContractAddr;
targetAddr_o <- proxy_hash_map[fromChainId];
match targetAddr_o with
| Some targetAddr =>
is_equal = builtin eq targetAddr fromContractAddr;
match is_equal with
| True =>
| False =>
e = IllegalFromProxy;
ThrowError e
end
| None =>
e = FromProxyNotExist;
ThrowError e
end
end
(* @param fromAssetHash: The asset address in current chain, uniformly named as fromAssetHash *)
(* @param fromAddress: obtained by _sender *)
(* @param toAddress: address is this contract: _this_address *)
(* @param amount: The amount of tokens to be crossed from ethereum to the chain with chainId *)
procedure transferZRC2ToContract(fromAssetHash: ByStr20, fromAddress: ByStr20, toAddress: ByStr20, amount: Uint128)
msg_to_zrc2 = {_tag: "TransferFrom"; _recipient: fromAssetHash; _amount: uint128_zero;
from: fromAddress; to: toAddress; amount: amount};
msgs = one_msg msg_to_zrc2;
send msgs
end
procedure transferZRC2FromContract(toAssetHash: ByStr20, address: ByStr20, amount: Uint128)
msg_to_zrc2 = {_tag: "Transfer"; _recipient: toAssetHash; _amount: uint128_zero;
to: address; amount: amount};
msgs = one_msg msg_to_zrc2;
send msgs
end
procedure transferNativeZILFromContract(address: ByStr20, amount: Uint128)
msg = {_tag: "AddFunds"; _recipient: address; _amount: amount };
msgs = one_msg msg;
send msgs
end
(* transfer asset from LockProxy contract to address *)
procedure TransferFromContract(toAssetHash: ByStr20, address: ByStr20, amount: Uint256)
(* convert Uint256 amount to Uint128 amount, so it cannot be greater than uint128_max *)
is_greater = uint256_gt amount uint128_max;
match is_greater with
| True =>
e = IllegalAmount;
ThrowError e
| False =>
uint128_amount_o = builtin to_uint128 amount;
match uint128_amount_o with
| Some uint128_amount =>
(* if toAssetHash is zero address, then transfer native zil, otherwise, transfer zrc2 *)
is_native_transfer = builtin eq toAssetHash zero_address;
match is_native_transfer with
| True =>
transferNativeZILFromContract address uint128_amount;
e = { _eventname: "TransferFromContract"; toAssetHash: toAssetHash; address: address; amount: amount };
event e
| False =>
transferZRC2FromContract toAssetHash address uint128_amount;
e = { _eventname: "TransferFromContract"; toAssetHash: toAssetHash; address: address; amount: amount };
event e
end
| None =>
e = IllegalAmount;
ThrowError e
end
end
end
(* transfer asset from fromAddress to LockProxy contract *)
procedure TransferToContract(fromAssetHash: ByStr20, amount: Uint128)
(* if people choose to lock native zil, then fromAssetHash should be 0x0000000000000000000000000000000000000000 *)
is_asset_zil = builtin eq fromAssetHash zero_address;
match is_asset_zil with
| True =>
accept;
is_amount_correct = builtin eq _amount amount;
match is_amount_correct with
| True =>
e = { _eventname: "TransferToContract"; fromAssetHash: fromAssetHash; amount: amount };
event e
| False =>
e = LockAmountMismatch;
ThrowError e
end
| False =>
(* no accept here, so even some zils is transfered, there is no harm *)
(* see IncreaseAllowance in ZRC2 *)
transferZRC2ToContract fromAssetHash _sender _this_address amount;
e = { _eventname: "TransferToContract"; fromAssetHash: fromAssetHash; amount: amount };
event e
end
end
procedure CrossChain(toChainId: Uint64, toContract: ByStr, method: ByStr, txData: ByStr)
manager_proxy_l <- manager_proxy;
msg = {_tag: "CrossChain"; _recipient: manager_proxy_l; _amount: uint128_zero;
toChainId: toChainId; toContract: toContract; method: method; txData: txData };
msgs = one_msg msg;
send msgs
end
(* This function is meant to be invoked by the user *)
(* a certin amount teokens will be locked in the proxy contract the invoker/msg.sender immediately.*)
(* Then the same amount of tokens will be unloked from target chain proxy contract at the target chain with chainId later. *)
(* @param fromAssetHash: The asset address in current chain, uniformly named as `fromAssetHash` *)
(* @param toChainId: The target chain id *)
(* @param toAddress: The address in bytes format to receive same amount of tokens in target chain *)
(* @param amount: The amount of tokens to be crossed from ethereum to the chain with chainId *)
transition lock(fromAssetHash: ByStr20, toChainId: Uint64, toAddress: ByStr, amount: Uint128)
ValidateAmount amount;
TransferToContract fromAssetHash amount;
toAssetHash_o <- asset_map[fromAssetHash][toChainId];
match toAssetHash_o with
| Some toAssetHash =>
amount_256_o = builtin to_uint256 amount;
match amount_256_o with
| Some amount_256 =>
txArgs = TxArgs toAssetHash toAddress amount_256;
tx_data = serialize_tx_args txArgs;
target_proxy_o <- proxy_hash_map[toChainId];
match target_proxy_o with
| Some target_proxy =>
CrossChain toChainId target_proxy unlock tx_data;
e = { _eventname: "Lock"; fromAssetHash: fromAssetHash; fromAddress: _sender; toChainId: toChainId;
toAssetHash: toAssetHash; toAddress: toAddress; amount: amount; tx_data: tx_data};
event e
| None =>
e = IllegalTargetProxy;
ThrowError e
end
| None =>
e = IllegalToAmount;
ThrowError e
end
| None =>
e = IllegalToAssetHash;
ThrowError e
end
end
(* This function is meant to be invoked by the Zilliqa crosschain management contract *)
(* then mint a certin amount of tokens to the designated address since a certain amount *)
(* was burnt from the source chain invoker. *)
(* @param args: The argument bytes recevied by the zilliqa lock proxy contract, need to be deserialized. *)
(* based on the way of serialization in the source chain proxy contract. *)
(* @param fromContractAddr: The source chain contract address. *)
(* @param fromChainId: The source chain id. *)
transition unlock(args: ByStr, fromContractAddr: ByStr, fromChainId: Uint64)
IsManagerContract _sender;
ValidateFromProxy fromContractAddr fromChainId;
tx_args_o = deserialize_tx_args args uint32_zero;
match tx_args_o with
| Some (TxArgs toAssetHash toAddressHash amount) =>
(* ValidateToAssetHash toAssetHash; *)
toAssetAddress_o = builtin to_bystr20 toAssetHash;
toAddress_o = builtin to_bystr20 toAddressHash;
match toAssetAddress_o with
| Some toAssetAddress =>
match toAddress_o with
| Some toAddress =>
e = { _eventname: "Unlock"; toAssetHash: toAssetAddress; toAddressHash: toAddress; amount: amount };
event e;
TransferFromContract toAssetAddress toAddress amount
| None =>
e = ParseToAddressFailed;
ThrowError e
end
| None =>
e = ParseToAssetAddressFailed;
ThrowError e
end
| None =>
end
end
transition BindAssetHash(fromAssetHash: ByStr20, toChainId: Uint64, toAssetHash: ByStr)
IsAdmin _sender;
asset_map[fromAssetHash][toChainId] := toAssetHash;
e = { _eventname: "BindAssetHash" };
event e
end
transition BindProxyHash(toChainId: Uint64, targetProxyHash: ByStr)
IsAdmin _sender;
proxy_hash_map[toChainId] := targetProxyHash;
e = { _eventname: "BindProxyHash" };
event e
end
transition SetManager(new_manager: ByStr20)
IsAdmin _sender;
manager := new_manager
end
transition SetManagerProxy(new_manager_proxy: ByStr20)
IsAdmin _sender;
manager_proxy := new_manager_proxy
end
transition TransferSuccessCallBack(sender: ByStr20, recipient: ByStr20, amount: Uint128)
end
transition RecipientAcceptTransfer(sender: ByStr20, recipient: ByStr20, amount: Uint128)
end
transition RecipientAcceptTransferFrom(initiator: ByStr20, sender: ByStr20, recipient: ByStr20, amount: Uint128)
end
transition TransferFromSuccessCallBack(initiator: ByStr20, sender: ByStr20, recipient: ByStr20, amount: Uint128)
end