-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpycma.pyx
More file actions
587 lines (553 loc) · 36.1 KB
/
Copy pathpycma.pyx
File metadata and controls
587 lines (553 loc) · 36.1 KB
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
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
from libc.stdint cimport uint64_t, uint8_t
from libc.stdlib cimport free, malloc
cimport libcmt
cimport libcma
import pycmt
cdef class RollupCma:
"""Rollup extended with libcma voucher encoding helpers.
Captures the application contract address on read_advance_state so that
cma_parser_encode_voucher can be invoked from emit_*_voucher methods.
"""
cdef bytes _app_contract
cdef object _rollup
def __cinit__(self):
self._app_contract = None
self._rollup = pycmt.Rollup()
cpdef str finish(self, bint last_request_status):
return self._rollup.finish(last_request_status)
cpdef object read_inspect_state(self):
return self._rollup.read_inspect_state()
cpdef int emit_voucher(self, str address, object value, bytes payload):
return self._rollup.emit_voucher(address,value,payload)
cpdef int emit_delegate_call_voucher(self, str address, bytes payload):
return self._rollup.emit_delegate_call_voucher(address,payload)
cpdef int emit_notice(self, bytes payload):
return self._rollup.emit_notice(payload)
cpdef emit_report(self, bytes payload):
return self._rollup.emit_report(payload)
cpdef emit_exception(self, bytes payload):
return self._rollup.emit_exception(payload)
cpdef load_merkle(self, str merkle_path):
self._rollup.load_merkle(merkle_path)
cpdef save_merkle(self, str merkle_path):
self._rollup.save_merkle(merkle_path)
cpdef reset_merkle(self):
self._rollup.reset_merkle()
cpdef object gio_request(self, int domain, bytes id):
return self._rollup.gio_request(domain,id)
cpdef object read_advance_state(self):
ret = self._rollup.read_advance_state()
self._app_contract = bytes(ret['app_contract'])
return ret
cdef libcma.cma_abi_address_t _get_app_address(self):
cdef libcma.cma_abi_address_t app_addr
if self._app_contract is None:
raise Exception("app_contract not set; call read_advance_state first")
app_addr.data = self._app_contract[:libcmt.CMT_ABI_ADDRESS_LENGTH]
return app_addr
cpdef emit_ether_voucher(self, str receiver, object amount):
if receiver.startswith("0x"):
receiver = receiver[2:]
cdef libcma.cma_parser_voucher_data_t voucher_req[1]
voucher_req[0].receiver.data = bytes.fromhex(receiver[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].ether.amount.data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
cdef libcma.cma_voucher_t voucher[1]
voucher[0].payload.data = NULL
voucher[0].payload.length = 0
cdef libcma.cma_abi_address_t app_addr = self._get_app_address()
err = libcma.cma_parser_encode_voucher(libcma.CMA_PARSER_VOUCHER_TYPE_ETHER, &app_addr, voucher_req, voucher)
if err != 0:
raise Exception(f"Failed to encode ether voucher ({err} - {libcma.cma_parser_get_last_error_message()})")
self.emit_voucher("0x" + voucher[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
int.from_bytes(voucher[0].value.data[:libcmt.CMT_ABI_U256_LENGTH]),
b'')
cpdef emit_erc20_voucher(self, str token, str receiver, object amount):
if receiver.startswith("0x"):
receiver = receiver[2:]
if token.startswith("0x"):
token = token[2:]
cdef libcma.cma_parser_voucher_data_t voucher_req[1]
voucher_req[0].receiver.data = bytes.fromhex(receiver[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc20.token.data = bytes.fromhex(token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc20.amount.data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
cdef uint8_t voucher_payload_buffer[libcma.CMA_PARSER_ERC20_VOUCHER_PAYLOAD_SIZE]
cdef libcma.cma_voucher_t voucher[1]
voucher[0].payload.data = voucher_payload_buffer
voucher[0].payload.length = sizeof(voucher_payload_buffer)
cdef libcma.cma_abi_address_t app_addr = self._get_app_address()
err = libcma.cma_parser_encode_voucher(libcma.CMA_PARSER_VOUCHER_TYPE_ERC20, &app_addr, voucher_req, voucher)
if err != 0:
raise Exception(f"Failed to encode erc20 voucher ({err} - {libcma.cma_parser_get_last_error_message()})")
self._rollup.emit_voucher("0x" + voucher[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
int.from_bytes(voucher[0].value.data[:libcmt.CMT_ABI_U256_LENGTH]),
voucher[0].payload.data[:voucher[0].payload.length])
cpdef emit_erc721_voucher(self, str token, str receiver, object token_id):
if receiver.startswith("0x"):
receiver = receiver[2:]
if token.startswith("0x"):
token = token[2:]
cdef libcma.cma_parser_voucher_data_t voucher_req[1]
voucher_req[0].receiver.data = bytes.fromhex(receiver[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc721.token.data = bytes.fromhex(token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc721.token_id.data = bytes.fromhex(f"{token_id:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
cdef uint8_t voucher_payload_buffer[libcma.CMA_PARSER_ERC721_VOUCHER_PAYLOAD_SIZE]
cdef libcma.cma_voucher_t voucher[1]
voucher[0].payload.data = voucher_payload_buffer
voucher[0].payload.length = sizeof(voucher_payload_buffer)
cdef libcma.cma_abi_address_t app_addr = self._get_app_address()
err = libcma.cma_parser_encode_voucher(libcma.CMA_PARSER_VOUCHER_TYPE_ERC721, &app_addr, voucher_req, voucher)
if err != 0:
raise Exception(f"Failed to encode erc721 voucher ({err} - {libcma.cma_parser_get_last_error_message()})")
self._rollup.emit_voucher("0x" + voucher[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
int.from_bytes(voucher[0].value.data[:libcmt.CMT_ABI_U256_LENGTH]),
voucher[0].payload.data[:voucher[0].payload.length])
cpdef emit_erc1155_single_voucher(self, str token, str receiver, object token_id, object amount):
if receiver.startswith("0x"):
receiver = receiver[2:]
if token.startswith("0x"):
token = token[2:]
cdef libcma.cma_parser_voucher_data_t voucher_req[1]
voucher_req[0].receiver.data = bytes.fromhex(receiver[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc1155_single.token.data = bytes.fromhex(token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc1155_single.token_id.data = bytes.fromhex(f"{token_id:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
voucher_req[0].erc1155_single.amount.data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
voucher_req[0].erc1155_single.exec_layer_data.length = 0
voucher_req[0].erc1155_single.exec_layer_data.data = NULL
cdef uint8_t voucher_payload_buffer[libcma.CMA_PARSER_ERC1155_SINGLE_VOUCHER_PAYLOAD_MIN_SIZE]
cdef libcma.cma_voucher_t voucher[1]
voucher[0].payload.data = voucher_payload_buffer
voucher[0].payload.length = sizeof(voucher_payload_buffer)
cdef libcma.cma_abi_address_t app_addr = self._get_app_address()
err = libcma.cma_parser_encode_voucher(libcma.CMA_PARSER_VOUCHER_TYPE_ERC1155_SINGLE, &app_addr, voucher_req, voucher)
if err != 0:
raise Exception(f"Failed to encode erc1155_single voucher ({err} - {libcma.cma_parser_get_last_error_message()})")
self._rollup.emit_voucher("0x" + voucher[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
int.from_bytes(voucher[0].value.data[:libcmt.CMT_ABI_U256_LENGTH]),
voucher[0].payload.data[:voucher[0].payload.length])
cpdef emit_erc1155_batch_voucher(self, str token, str receiver, object token_ids, object amounts):
if receiver.startswith("0x"):
receiver = receiver[2:]
if token.startswith("0x"):
token = token[2:]
cdef libcma.cma_parser_voucher_data_t voucher_req[1]
voucher_req[0].receiver.data = bytes.fromhex(receiver[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
voucher_req[0].erc1155_batch.token.data = bytes.fromhex(token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
token_ids_p = b"".join([bytes.fromhex(f"{token_id:064x}")[:libcmt.CMT_ABI_U256_LENGTH] for token_id in token_ids])
cdef const uint8_t *token_ids_bytes = token_ids_p
cdef libcma.cma_abi_u256_data *token_ids_ptr = <libcma.cma_abi_u256_data *>token_ids_bytes
amounts_p = b"".join([bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH] for amount in amounts])
cdef const uint8_t *amounts_bytes = amounts_p
cdef libcma.cma_abi_u256_data *amounts_ptr = <libcma.cma_abi_u256_data *>amounts_bytes
voucher_req[0].erc1155_batch.token_ids.length = len(token_ids)
voucher_req[0].erc1155_batch.token_ids.data = token_ids_ptr
voucher_req[0].erc1155_batch.amounts.length = len(amounts)
voucher_req[0].erc1155_batch.amounts.data = amounts_ptr
voucher_req[0].erc1155_batch.exec_layer_data.length = 0
voucher_req[0].erc1155_batch.exec_layer_data.data = NULL
payload_size = libcma.CMA_PARSER_ERC1155_BATCH_VOUCHER_PAYLOAD_MIN_SIZE + 2 * len(token_ids) * libcmt.CMT_ABI_U256_LENGTH
cdef uint8_t *voucher_payload_buffer = <uint8_t *>malloc(payload_size * sizeof(uint8_t))
if not voucher_payload_buffer:
raise Exception("Error allocating voucher payload buffer")
cdef libcma.cma_voucher_t voucher[1]
voucher[0].payload.data = voucher_payload_buffer
voucher[0].payload.length = payload_size
cdef libcma.cma_abi_address_t app_addr = self._get_app_address()
try:
err = libcma.cma_parser_encode_voucher(libcma.CMA_PARSER_VOUCHER_TYPE_ERC1155_BATCH, &app_addr, voucher_req, voucher)
if err != 0:
raise Exception(f"Failed to encode erc1155_batch voucher ({err} - {libcma.cma_parser_get_last_error_message()})")
self._rollup.emit_voucher("0x" + voucher[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
int.from_bytes(voucher[0].value.data[:libcmt.CMT_ABI_U256_LENGTH]),
voucher[0].payload.data[:voucher[0].payload.length])
finally:
free(voucher_payload_buffer)
cpdef object decode_ether_deposit(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_ETHER_DEPOSIT, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode ether deposit ({err} - {libcma.cma_parser_get_last_error_message()})")
return {
"sender": "0x" + parser_input[0].ether_deposit.sender.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"amount": int.from_bytes(parser_input[0].ether_deposit.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].ether_deposit.exec_layer_data.data[:parser_input[0].ether_deposit.exec_layer_data.length]
}
cpdef object decode_erc20_deposit(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_ERC20_DEPOSIT, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode erc20 deposit ({err} - {libcma.cma_parser_get_last_error_message()})")
return {
"sender": "0x" + parser_input[0].erc20_deposit.sender.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token": "0x" + parser_input[0].erc20_deposit.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"amount": int.from_bytes(parser_input[0].erc20_deposit.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc20_deposit.exec_layer_data.data[:parser_input[0].erc20_deposit.exec_layer_data.length]
}
cpdef object decode_erc721_deposit(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_ERC721_DEPOSIT, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode erc721 deposit ({err} - {libcma.cma_parser_get_last_error_message()})")
return {
"sender": "0x" + parser_input[0].erc721_deposit.sender.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token": "0x" + parser_input[0].erc721_deposit.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc721_deposit.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc721_deposit.exec_layer_data.data[:parser_input[0].erc721_deposit.exec_layer_data.length]
}
cpdef object decode_erc1155_single_deposit(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_ERC1155_SINGLE_DEPOSIT, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode erc1155_single deposit ({err} - {libcma.cma_parser_get_last_error_message()})")
return {
"sender": "0x" + parser_input[0].erc1155_single_deposit.sender.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token": "0x" + parser_input[0].erc1155_single_deposit.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc1155_single_deposit.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"amount": int.from_bytes(parser_input[0].erc1155_single_deposit.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc1155_single_deposit.exec_layer_data.data[:parser_input[0].erc1155_single_deposit.exec_layer_data.length]
}
cpdef object decode_erc1155_batch_deposit(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_ERC1155_BATCH_DEPOSIT, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode erc1155_batch deposit ({err} - {libcma.cma_parser_get_last_error_message()})")
token_ids = []
for i in range(parser_input[0].erc1155_batch_deposit.token_ids.length):
token_ids.append(int.from_bytes(parser_input[0].erc1155_batch_deposit.token_ids.data[i][:libcmt.CMT_ABI_U256_LENGTH]))
amounts = []
for i in range(parser_input[0].erc1155_batch_deposit.amounts.length):
amounts.append(int.from_bytes(parser_input[0].erc1155_batch_deposit.amounts.data[i][:libcmt.CMT_ABI_U256_LENGTH]))
return {
"sender": "0x" + parser_input[0].erc1155_batch_deposit.sender.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token": "0x" + parser_input[0].erc1155_batch_deposit.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_ids": token_ids,
"amounts": amounts,
"exec_layer_data": parser_input[0].erc1155_batch_deposit.exec_layer_data.data[:parser_input[0].erc1155_batch_deposit.exec_layer_data.length]
}
cpdef object decode_advance(dict input):
cdef libcmt.cmt_rollup_advance_t input_ptr[1]
input_ptr[0].msg_sender.data = input['msg_sender']
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_advance(libcma.CMA_PARSER_INPUT_TYPE_AUTO, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode advance ({err} - {libcma.cma_parser_get_last_error_message()})")
if parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ETHER_WITHDRAWAL:
ret = {
"type": "ETHER_WITHDRAWAL",
"amount": int.from_bytes(parser_input[0].ether_withdrawal.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].ether_withdrawal.exec_layer_data.data[:parser_input[0].ether_withdrawal.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC20_WITHDRAWAL:
ret = {
"type": "ERC20_WITHDRAWAL",
"token": "0x" + parser_input[0].erc20_withdrawal.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"amount": int.from_bytes(parser_input[0].erc20_withdrawal.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc20_withdrawal.exec_layer_data.data[:parser_input[0].erc20_withdrawal.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC721_WITHDRAWAL:
ret = {
"type": "ERC721_WITHDRAWAL",
"token": "0x" + parser_input[0].erc721_withdrawal.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc721_withdrawal.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc721_withdrawal.exec_layer_data.data[:parser_input[0].erc721_withdrawal.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC1155_SINGLE_WITHDRAWAL:
ret = {
"type": "ERC1155_SINGLE_WITHDRAWAL",
"token": "0x" + parser_input[0].erc1155_single_withdrawal.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc1155_single_withdrawal.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"amount": int.from_bytes(parser_input[0].erc1155_single_withdrawal.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc1155_single_withdrawal.exec_layer_data.data[:parser_input[0].erc1155_single_withdrawal.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC1155_BATCH_WITHDRAWAL:
ret = {
"type": "ERC1155_BATCH_WITHDRAWAL",
"token": "0x" + parser_input[0].erc1155_batch_withdrawal.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_ids": [int.from_bytes(parser_input[0].erc1155_batch_withdrawal.token_ids.data[i][:libcmt.CMT_ABI_U256_LENGTH]) for i in range(parser_input[0].erc1155_batch_withdrawal.token_ids.length)],
"amounts": [int.from_bytes(parser_input[0].erc1155_batch_withdrawal.amounts.data[i][:libcmt.CMT_ABI_U256_LENGTH]) for i in range(parser_input[0].erc1155_batch_withdrawal.amounts.length)],
"exec_layer_data": parser_input[0].erc1155_batch_withdrawal.exec_layer_data.data[:parser_input[0].erc1155_batch_withdrawal.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ETHER_TRANSFER:
ret = {
"type": "ETHER_TRANSFER",
"receiver": "0x" + parser_input[0].ether_transfer.receiver.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"amount": int.from_bytes(parser_input[0].ether_transfer.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].ether_transfer.exec_layer_data.data[:parser_input[0].ether_transfer.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC20_TRANSFER:
ret = {
"type": "ERC20_TRANSFER",
"receiver": "0x" + parser_input[0].erc20_transfer.receiver.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].erc20_transfer.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"amount": int.from_bytes(parser_input[0].erc20_transfer.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc20_transfer.exec_layer_data.data[:parser_input[0].erc20_transfer.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC721_TRANSFER:
ret = {
"type": "ERC721_TRANSFER",
"receiver": "0x" + parser_input[0].erc721_transfer.receiver.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].erc721_transfer.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc721_transfer.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc721_transfer.exec_layer_data.data[:parser_input[0].erc721_transfer.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC1155_SINGLE_TRANSFER:
ret = {
"type": "ERC1155_SINGLE_TRANSFER",
"receiver": "0x" + parser_input[0].erc1155_single_transfer.receiver.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].erc1155_single_transfer.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].erc1155_single_transfer.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"amount": int.from_bytes(parser_input[0].erc1155_single_transfer.amount.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].erc1155_single_transfer.exec_layer_data.data[:parser_input[0].erc1155_single_transfer.exec_layer_data.length]
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_ERC1155_BATCH_TRANSFER:
ret = {
"type": "ERC1155_BATCH_TRANSFER",
"receiver": "0x" + parser_input[0].erc1155_batch_transfer.receiver.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].erc1155_batch_transfer.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_ids": [int.from_bytes(parser_input[0].erc1155_batch_transfer.token_ids.data[i][:libcmt.CMT_ABI_U256_LENGTH]) for i in range(parser_input[0].erc1155_batch_transfer.token_ids.length)],
"amounts": [int.from_bytes(parser_input[0].erc1155_batch_transfer.amounts.data[i][:libcmt.CMT_ABI_U256_LENGTH]) for i in range(parser_input[0].erc1155_batch_transfer.amounts.length)],
"exec_layer_data": parser_input[0].erc1155_batch_transfer.exec_layer_data.data[:parser_input[0].erc1155_batch_transfer.exec_layer_data.length]
}
else:
raise Exception(f"Unknown input type ({parser_input[0].type})")
return ret
cpdef object decode_inspect(dict input):
cdef libcmt.cmt_rollup_inspect_t input_ptr[1]
input_ptr[0].payload.data = input['payload']['data']
input_ptr[0].payload.length = input['payload']['length']
cdef libcma.cma_parser_input_t parser_input[1]
err = libcma.cma_parser_decode_inspect(libcma.CMA_PARSER_INPUT_TYPE_AUTO, input_ptr, parser_input)
if err != 0:
raise Exception(f"Failed to decode inspect ({err})")
if parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_BALANCE_ACCOUNT:
ret = {
"type": "BALANCE",
"account": "0x" + parser_input[0].balance.account.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": None,
"token_id": None,
"exec_layer_data": None
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_BALANCE_ACCOUNT_TOKEN_ADDRESS:
ret = {
"type": "BALANCE",
"account": "0x" + parser_input[0].balance.account.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].balance.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": None,
"exec_layer_data": None
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_BALANCE_ACCOUNT_TOKEN_ADDRESS_ID:
ret = {
"type": "BALANCE",
"account": "0x" + parser_input[0].balance.account.data[:libcmt.CMT_ABI_U256_LENGTH].hex(),
"token": "0x" + parser_input[0].balance.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].balance.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].balance.exec_layer_data.data[:parser_input[0].balance.exec_layer_data.length] if parser_input[0].balance.exec_layer_data.length > 0 else None
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_SUPPLY:
ret = {
"type": "SUPPLY",
"token": None,
"token_id": None,
"exec_layer_data": None
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_SUPPLY_TOKEN_ADDRESS:
ret = {
"type": "SUPPLY",
"token": "0x" + parser_input[0].supply.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": None,
"exec_layer_data": None
}
elif parser_input[0].type == libcma.CMA_PARSER_INPUT_TYPE_SUPPLY_TOKEN_ADDRESS_ID:
ret = {
"type": "SUPPLY",
"token": "0x" + parser_input[0].supply.token.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex(),
"token_id": int.from_bytes(parser_input[0].supply.token_id.data[:libcmt.CMT_ABI_U256_LENGTH]),
"exec_layer_data": parser_input[0].supply.exec_layer_data.data[:parser_input[0].supply.exec_layer_data.length] if parser_input[0].supply.exec_layer_data.length > 0 else None
}
else:
raise Exception(f"Unknown input type ({parser_input[0].type})")
return ret
cdef class Ledger:
cdef libcma.cma_ledger_t _c_ledger[1]
def __cinit__(self, str memory_filename = None, int offset = 0, int mem_length = 0,
int n_accounts = 0, int n_assets = 0, int n_balances = 0,
bint single_asset_account_drive = 0, str account_drive_token = None):
cdef char *c_memory_filename
cdef libcma.cma_ledger_asset_type_t asset_type[1]
cdef libcma.cma_token_address_t ltok[1]
cdef libcma.cma_token_address_t *ltok_ptr = NULL
if memory_filename is not None:
if mem_length == 0 or n_accounts == 0 or n_assets == 0 or n_balances == 0:
raise Exception("Memory should be initialized with non zero values")
b_memory_filename = memory_filename.encode('UTF-8')
c_memory_filename = b_memory_filename
if single_asset_account_drive:
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_BASE
if account_drive_token is not None:
if account_drive_token.startswith("0x"):
account_drive_token = account_drive_token[2:]
if len(account_drive_token) != 2*libcmt.CMT_ABI_ADDRESS_LENGTH:
raise Exception("Invalid account_drive_token")
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS
ltok[0].data = bytes.fromhex(account_drive_token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
ltok_ptr = ltok
err = libcma.cma_ledger_init_single_file(self._c_ledger, c_memory_filename,
offset, mem_length, n_accounts, asset_type[0], ltok_ptr);
if err != 0:
raise Exception(f"Failed to initialize ledger file single ({err} - {libcma.cma_ledger_get_last_error_message()})")
else:
err = libcma.cma_ledger_init_file(self._c_ledger, c_memory_filename,
offset, mem_length, n_accounts, n_assets, n_balances);
if err != 0:
raise Exception(f"Failed to initialize ledger file ({err} - {libcma.cma_ledger_get_last_error_message()})")
else:
err = libcma.cma_ledger_init(self._c_ledger)
if err != 0:
raise Exception(f"Failed to initialize ledger ({err} - {libcma.cma_ledger_get_last_error_message()})")
def __dealloc__(self):
err = libcma.cma_ledger_fini(self._c_ledger)
if err != 0:
raise Exception(f"Failed to finalize ledger ({err} - {libcma.cma_ledger_get_last_error_message()})")
cpdef reset(self):
err = libcma.cma_ledger_reset(self._c_ledger)
if err != 0:
raise Exception(f"Failed to reset ledger ({err} - {libcma.cma_ledger_get_last_error_message()})")
def retrieve_asset(self, asset_id = None, token = None, token_id = None, token_id_with_amount = None, base_token = None, force_find = None, remove = None):
cdef libcma.cma_ledger_asset_id_t lassid[1]
cdef libcma.cma_token_address_t ltok[1]
cdef libcma.cma_token_id_t ltokid[1]
cdef libcma.cma_amount_t ltotal_supply[1]
cdef libcma.cma_ledger_asset_type_t asset_type[1]
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_ID
if base_token is not None and base_token:
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_BASE
cdef libcma.cma_ledger_retrieve_operation_t operation = libcma.CMA_LEDGER_OP_FIND_OR_CREATE
if asset_id is not None:
lassid[0] = asset_id
elif token is not None:
if token.startswith("0x"):
token = token[2:]
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS
ltok[0].data = bytes.fromhex(token[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
if token_id is not None:
ltokid[0].data = bytes.fromhex(f"{token_id:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
if token_id_with_amount is not None and token_id_with_amount:
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS_ID_AMOUNT
else:
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS_ID
else:
operation = libcma.CMA_LEDGER_OP_CREATE
if force_find is not None and force_find:
operation = libcma.CMA_LEDGER_OP_FIND
if remove is not None and remove:
operation = libcma.CMA_LEDGER_OP_FIND_AND_REMOVE
err = libcma.cma_ledger_retrieve_asset(self._c_ledger, lassid, ltok, ltokid, ltotal_supply, asset_type, operation)
if err != 0:
raise Exception(f"Failed to retrieve asset ({err} - {libcma.cma_ledger_get_last_error_message()})")
token_str = None
token_id_str = None
if asset_type[0] == libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS:
token_str = "0x" + ltok[0].data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex()
elif asset_type[0] == libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS_ID or \
asset_type[0] == libcma.CMA_LEDGER_ASSET_TYPE_TOKEN_ADDRESS_ID_AMOUNT:
token_str = "0x" + ltok[0].data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex()
token_id_str = int.from_bytes(ltokid[0].data[:libcmt.CMT_ABI_U256_LENGTH])
return {
"asset_id": lassid[0],
"token": token_str,
"token_id": token_id_str,
"total_supply": int.from_bytes(ltotal_supply[0].data[:libcmt.CMT_ABI_U256_LENGTH])
}
def retrieve_account(self, account_id = None, account = None, remove = None):
cdef libcma.cma_ledger_account_id_t laccid[1]
cdef libcma.cma_ledger_account_t lacc[1]
cdef libcma.cma_ledger_account_type_t account_type[1]
account_type[0] = libcma.CMA_LEDGER_ACCOUNT_TYPE_ID
cdef libcma.cma_ledger_retrieve_operation_t operation = libcma.CMA_LEDGER_OP_FIND_OR_CREATE
if account_id is not None:
laccid[0] = account_id
elif account is not None:
if account.startswith("0x"):
account = account[2:]
if len(account) == 2*libcmt.CMT_ABI_ADDRESS_LENGTH:
account_type[0] = libcma.CMA_LEDGER_ACCOUNT_TYPE_WALLET_ADDRESS
lacc[0].address.data = bytes.fromhex(account[:(2*libcmt.CMT_ABI_ADDRESS_LENGTH)])[:libcmt.CMT_ABI_ADDRESS_LENGTH]
elif len(account) == 2*libcmt.CMT_ABI_U256_LENGTH:
account_type[0] = libcma.CMA_LEDGER_ACCOUNT_TYPE_ACCOUNT_ID
lacc[0].account_id.data = bytes.fromhex(account[:(2*libcmt.CMT_ABI_U256_LENGTH)])[:libcmt.CMT_ABI_U256_LENGTH]
else:
raise ValueError(f"Invalid account address length: {len(account)}")
else:
account_type[0] = libcma.CMA_LEDGER_ACCOUNT_TYPE_ID
operation = libcma.CMA_LEDGER_OP_CREATE
if remove is not None and remove:
operation = libcma.CMA_LEDGER_OP_FIND_AND_REMOVE
cdef size_t n_balances[1]
err = libcma.cma_ledger_retrieve_account(self._c_ledger, laccid, lacc, NULL, n_balances, account_type, operation)
if err != 0:
raise Exception(f"Failed to retrieve account ({err} - {libcma.cma_ledger_get_last_error_message()})")
account_str = None
if lacc[0].type == libcma.CMA_LEDGER_ACCOUNT_TYPE_WALLET_ADDRESS:
account_str = "0x" + lacc[0].address.data[:libcmt.CMT_ABI_ADDRESS_LENGTH].hex()
elif lacc[0].type == libcma.CMA_LEDGER_ACCOUNT_TYPE_ACCOUNT_ID:
account_str = "0x" + lacc[0].account_id.data[:libcmt.CMT_ABI_U256_LENGTH].hex()
return {
"account_id": laccid[0],
"account": account_str,
"n_balances": n_balances[0],
}
cpdef deposit(self, libcma.cma_ledger_asset_id_t asset_id, libcma.cma_ledger_account_id_t account_id, object amount):
cdef libcma.cma_amount_t lamount[1]
lamount[0].data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
err = libcma.cma_ledger_deposit(self._c_ledger, asset_id, account_id, lamount)
if err != 0:
raise Exception(f"Failed to deposit ({err} - {libcma.cma_ledger_get_last_error_message()})")
cpdef withdraw(self, libcma.cma_ledger_asset_id_t asset_id, libcma.cma_ledger_account_id_t account_id, object amount):
cdef libcma.cma_amount_t lamount[1]
lamount[0].data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
err = libcma.cma_ledger_withdraw(self._c_ledger, asset_id, account_id, lamount)
if err != 0:
raise Exception(f"Failed to withdraw ({err} - {libcma.cma_ledger_get_last_error_message()})")
cpdef transfer(self, libcma.cma_ledger_asset_id_t asset_id, libcma.cma_ledger_account_id_t from_account_id, libcma.cma_ledger_account_id_t to_account_id, object amount):
cdef libcma.cma_amount_t lamount[1]
lamount[0].data = bytes.fromhex(f"{amount:064x}")[:libcmt.CMT_ABI_U256_LENGTH]
err = libcma.cma_ledger_transfer(self._c_ledger, asset_id, from_account_id, to_account_id, lamount)
if err != 0:
raise Exception(f"Failed to transfer ({err} - {libcma.cma_ledger_get_last_error_message()})")
cpdef object balance(self, libcma.cma_ledger_asset_id_t asset_id, libcma.cma_ledger_account_id_t account_id):
cdef libcma.cma_amount_t lamount[1]
err = libcma.cma_ledger_get_balance(self._c_ledger, asset_id, account_id, lamount, NULL)
if err != 0:
raise Exception(f"Failed to get balance ({err} - {libcma.cma_ledger_get_last_error_message()})")
return int.from_bytes(lamount[0].data[:libcmt.CMT_ABI_U256_LENGTH])
cpdef object supply(self, libcma.cma_ledger_asset_id_t asset_id):
# cma_ledger_get_total_supply was removed; the total supply is now
# returned by cma_ledger_retrieve_asset via the out_total_supply param.
cdef libcma.cma_ledger_asset_id_t lassid[1]
cdef libcma.cma_token_address_t ltok[1]
cdef libcma.cma_token_id_t ltokid[1]
cdef libcma.cma_amount_t ltotal_supply[1]
cdef libcma.cma_ledger_asset_type_t asset_type[1]
lassid[0] = asset_id
asset_type[0] = libcma.CMA_LEDGER_ASSET_TYPE_ID
err = libcma.cma_ledger_retrieve_asset(self._c_ledger, lassid, ltok, ltokid, ltotal_supply,
asset_type, libcma.CMA_LEDGER_OP_FIND)
if err != 0:
raise Exception(f"Failed to get total supply ({err} - {libcma.cma_ledger_get_last_error_message()})")
return int.from_bytes(ltotal_supply[0].data[:libcmt.CMT_ABI_U256_LENGTH])