cma_rust_parser/
parser.rs

1use crate::helpers::{hex_to_string, PortalMatcher, Portals, CARTESI_ADDRESSES};
2use ethers::abi::{encode, Token};
3use ethers::types::{Address, Bytes, U256};
4use ethers::utils::{id, to_checksum};
5use hex;
6use json::JsonValue;
7
8#[repr(u32)]
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum TxHexCodes {
11    // Bytecode for solidity WithdrawEther(uint256,bytes) = 8cf70f0b
12    WithdrawEther = 0x8cf70f0b,
13    // Bytecode for solidity WithdrawErc20(address,uint256,bytes) = 4f94d342
14    WithdrawErc20 = 0x4f94d342,
15    // Bytecode for solidity WithdrawErc721(address,uint256,bytes) = 33acf293
16    WithdrawErc721 = 0x33acf293,
17    // Bytecode for solidity WithdrawErc1155Single(address,uint256,uint256,bytes) = 8bb0a811
18    WithdrawErc1155Single = 0x8bb0a811,
19    // Bytecode for solidity WithdrawErc1155Batch(address,uint256[],uint256[],bytes) = 50c80019
20    WithdrawErc1155Batch = 0x50c80019,
21
22    // Bytecode for solidity TransferEther(uint256,bytes32,bytes) = 428c9c4d
23    TransferEther = 0x428c9c4d,
24    // Bytecode for solidity TransferErc20(address,bytes32,uint256,bytes) = 03d61dcd
25    TransferErc20 = 0x03d61dcd,
26    // Bytecode for solidity TransferErc721(address,bytes32,uint256,bytes) = af615a5a
27    TransferErc721 = 0xaf615a5a,
28    // Bytecode for solidity TransferErc1155Single(address,bytes32,uint256,uint256,bytes) = e1c913ed
29    TransferErc1155Single = 0xe1c913ed,
30    // Bytecode for solidity TransferErc1155Batch(address,bytes32,uint256[],uint256[],bytes) = 638ac6f9
31    TransferErc1155Batch = 0x638ac6f9,
32
33    // Bytecode for solidity transfer(address,uint256) = a9059cbb
34    Erc20TransferFunctionSelectorFunsel = 0xa9059cbb,
35    // Bytecode for solidity safeTransferFrom(address,address,uint256) = 42842e0e
36    Erc721TransferFunctionSelectorFunsel = 0x42842e0e,
37    // Bytecode for solidity safeTransferFrom(address,address,uint256,uint256,bytes) = f242432a
38    Erc1155SingleTransferFunctionSelectorFunsel = 0xf242432a,
39    // Bytecode for solidity safeBatchTransferFrom(address,address,uint256[],uint256[],bytes) = 2eb2c2d6
40    Erc1155BatchTransferFunctionSelectorFunsel = 0x2eb2c2d6,
41}
42
43pub enum CmaVoucherFieldType {
44    EtherVoucherFields(CmaParserEtherVoucherFields),
45    Erc20VoucherFields(CmaParserErc20VoucherFields),
46    Erc721VoucherFields(CmaParserErc721VoucherFields),
47    Erc1155SingleVoucherFields(CmaParserErc1155SingleVoucherFields),
48    Erc1155BatchVoucherFields(CmaParserErc1155BatchVoucherFields),
49}
50
51enum TokenType {
52    Erc20,
53    Erc721,
54}
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq)]
57pub enum CmaParserInputType {
58    CmaParserInputTypeNone,
59    CmaParserInputTypeAuto,
60    CmaParserInputTypeEtherDeposit,
61    CmaParserInputTypeErc20Deposit,
62    CmaParserInputTypeErc721Deposit,
63    CmaParserInputTypeErc1155SingleDeposit,
64    CmaParserInputTypeErc1155BatchDeposit,
65    CmaParserInputTypeEtherWithdrawal,
66    CmaParserInputTypeErc20Withdrawal,
67    CmaParserInputTypeErc721Withdrawal,
68    CmaParserInputTypeErc1155SingleWithdrawal,
69    CmaParserInputTypeErc1155BatchWithdrawal,
70    CmaParserInputTypeEtherTransfer,
71    CmaParserInputTypeErc20Transfer,
72    CmaParserInputTypeErc721Transfer,
73    CmaParserInputTypeErc1155SingleTransfer,
74    CmaParserInputTypeErc1155BatchTransfer,
75    CmaParserInputTypeBalance,
76    CmaParserInputTypeSupply,
77}
78
79impl CmaParserInputType {
80    pub fn from_string(s: &str) -> Self {
81        match s {
82            "EtherDeposit" => CmaParserInputType::CmaParserInputTypeEtherDeposit,
83            "Erc20Deposit" => CmaParserInputType::CmaParserInputTypeErc20Deposit,
84            "Erc721Deposit" => CmaParserInputType::CmaParserInputTypeErc721Deposit,
85            "Erc1155SingleDeposit" => CmaParserInputType::CmaParserInputTypeErc1155SingleDeposit,
86            "Erc1155BatchDeposit" => CmaParserInputType::CmaParserInputTypeErc1155BatchDeposit,
87            "EtherWithdrawal" => CmaParserInputType::CmaParserInputTypeEtherWithdrawal,
88            "Erc20Withdrawal" => CmaParserInputType::CmaParserInputTypeErc20Withdrawal,
89            "Erc721Withdrawal" => CmaParserInputType::CmaParserInputTypeErc721Withdrawal,
90            "Erc1155SingleWithdrawal" => {
91                CmaParserInputType::CmaParserInputTypeErc1155SingleWithdrawal
92            }
93            "Erc1155BatchWithdrawal" => {
94                CmaParserInputType::CmaParserInputTypeErc1155BatchWithdrawal
95            }
96            "EtherTransfer" => CmaParserInputType::CmaParserInputTypeEtherTransfer,
97            "Erc20Transfer" => CmaParserInputType::CmaParserInputTypeErc20Transfer,
98            "Erc721Transfer" => CmaParserInputType::CmaParserInputTypeErc721Transfer,
99            "Erc1155SingleTransfer" => CmaParserInputType::CmaParserInputTypeErc1155SingleTransfer,
100            "Erc1155BatchTransfer" => CmaParserInputType::CmaParserInputTypeErc1155BatchTransfer,
101            "ledgerGetBalance" => CmaParserInputType::CmaParserInputTypeBalance,
102            "ledgerGetTotalSupply" => CmaParserInputType::CmaParserInputTypeSupply,
103            _ => CmaParserInputType::CmaParserInputTypeNone,
104        }
105    }
106}
107
108pub enum CmaParserVoucherType {
109    CmaParserVoucherTypeNone,
110    CmaParserVoucherTypeEther,
111    CmaParserVoucherTypeErc20,
112    CmaParserVoucherTypeErc721,
113    CmaParserVoucherTypeErc1155Single,
114    CmaParserVoucherTypeErc1155Batch,
115}
116
117#[derive(Debug, Clone, PartialEq, Eq)]
118pub enum CmaParserError {
119    Success,
120    IncompatibleInput,
121    MalformedInput,
122    Unknown,
123    Message(String),
124}
125
126impl CmaParserError {
127    pub fn from_code(code: i32) -> Self {
128        match code {
129            0 => Self::Success,
130            -2001 => Self::IncompatibleInput,
131            -2002 => Self::MalformedInput,
132            -2003 => Self::Unknown,
133            -2004 => Self::Message("Unknown error".to_string()),
134            _ => Self::Unknown,
135        }
136    }
137
138    pub fn to_code(self) -> i32 {
139        match self {
140            Self::Success => 0,
141            Self::IncompatibleInput => -2001,
142            Self::MalformedInput => -2002,
143            Self::Unknown => -2003,
144            Self::Message(_) => -2004,
145        }
146    }
147}
148
149#[derive(Debug, Clone, PartialEq, Eq)]
150pub struct CmaVoucher {
151    pub destination: String,
152    pub value: String,
153    pub payload: String,
154}
155
156pub struct CmaParserVoucherData {
157    pub voucher_fields: CmaVoucherFieldType,
158}
159
160pub struct CmaParserEtherVoucherFields {
161    pub amount: U256,
162    pub receiver: Address,
163}
164pub struct CmaParserErc20VoucherFields {
165    pub token: Address,
166    pub receiver: Address,
167    pub value: U256,
168    pub amount: U256,
169}
170pub struct CmaParserErc721VoucherFields {
171    pub token: Address,
172    pub token_id: U256,
173    pub receiver: Address,
174    pub value: U256,
175    pub application_address: Address,
176}
177pub struct CmaParserErc1155SingleVoucherFields {
178    pub token: Address,
179    pub token_id: U256,
180    pub receiver: Address,
181    pub value: U256,
182    pub amount: U256,
183}
184pub struct CmaParserErc1155BatchVoucherFields {
185    pub token: Address,
186    pub receiver: Address,
187    pub count: usize,
188    pub token_ids: Vec<U256>,
189    pub value: U256,
190    pub amounts: Vec<U256>,
191}
192
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub struct CmaParserEtherDeposit {
195    pub sender: Address,
196    pub amount: U256,
197    pub exec_layer_data: Bytes,
198}
199
200pub struct CmaParserErc20Deposit {
201    pub sender: Address,
202    pub token: Address,
203    pub amount: U256,
204    pub exec_layer_data: Bytes,
205}
206
207pub struct CmaParserErc721Deposit {
208    pub sender: Address,
209    pub token: Address,
210    pub token_id: U256,
211    pub exec_layer_data: Bytes,
212}
213
214pub struct CmaParserErc1155SingleDeposit {
215    pub sender: Address,
216    pub token: Address,
217    pub token_id: U256,
218    pub amount: U256,
219    pub exec_layer_data: Bytes,
220}
221
222pub struct CmaParserErc1155BatchDeposit {
223    pub sender: Address,
224    pub token: Address,
225    pub count: usize,
226    pub token_ids: Vec<U256>,
227    pub amounts: Vec<U256>,
228    pub base_layer_data: Bytes,
229    pub exec_layer_data: Bytes,
230}
231
232pub struct CmaParserEtherWithdrawal {
233    pub receiver: Address,
234    pub amount: U256,
235    pub exec_layer_data: String,
236}
237
238pub struct CmaParserErc20Withdrawal {
239    pub receiver: Address,
240    pub token: Address,
241    pub amount: U256,
242    pub exec_layer_data: String,
243}
244
245pub struct CmaParserErc721Withdrawal {
246    pub receiver: Address,
247    pub token: Address,
248    pub token_id: U256,
249    pub exec_layer_data: String,
250}
251
252pub struct CmaParserErc1155SingleWithdrawal {
253    pub receiver: Address,
254    pub token: Address,
255    pub token_id: U256,
256    pub amount: U256,
257    pub exec_layer_data: String,
258}
259
260pub struct CmaParserErc1155BatchWithdrawal {
261    pub receiver: Address,
262    pub token: Address,
263    pub count: usize,
264    pub token_ids: Vec<U256>,
265    pub amounts: Vec<U256>,
266    pub base_layer_data: String,
267    pub exec_layer_data: String,
268}
269
270pub struct CmaParserEtherTransfer {
271    pub sender: Address,
272    pub receiver: Address,
273    pub amount: U256,
274    pub exec_layer_data: String,
275}
276
277pub struct CmaParserErc20Transfer {
278    pub sender: Address,
279    pub receiver: Address,
280    pub token: Address,
281    pub amount: U256,
282    pub exec_layer_data: String,
283}
284
285pub struct CmaParserErc721Transfer {
286    pub sender: Address,
287    pub receiver: Address,
288    pub token: Address,
289    pub token_id: U256,
290    pub exec_layer_data: String,
291}
292
293pub struct CmaParserErc1155SingleTransfer {
294    pub sender: Address,
295    pub receiver: Address,
296    pub token: Address,
297    pub token_id: U256,
298    pub amount: U256,
299    pub exec_layer_data: String,
300}
301
302pub struct CmaParserErc1155BatchTransfer {
303    pub sender: Address,
304    pub receiver: Address,
305    pub token: Address,
306    pub count: usize,
307    pub token_ids: Vec<U256>,
308    pub amounts: Vec<U256>,
309    pub base_layer_data: String,
310    pub exec_layer_data: String,
311}
312
313pub struct CmaParserBalance {
314    pub account: Address,
315    pub token: Address,
316    pub token_ids: Option<Vec<U256>>,
317}
318
319pub struct CmaParserSupply {
320    pub token: Address,
321    pub token_ids: Vec<U256>,
322}
323
324pub enum CmaParserInputData {
325    EtherDeposit(CmaParserEtherDeposit),
326    Erc20Deposit(CmaParserErc20Deposit),
327    Erc721Deposit(CmaParserErc721Deposit),
328    Erc1155SingleDeposit(CmaParserErc1155SingleDeposit),
329    Erc1155BatchDeposit(CmaParserErc1155BatchDeposit),
330    EtherWithdrawal(CmaParserEtherWithdrawal),
331    Erc20Withdrawal(CmaParserErc20Withdrawal),
332    Erc721Withdrawal(CmaParserErc721Withdrawal),
333    Erc1155SingleWithdrawal(CmaParserErc1155SingleWithdrawal),
334    Erc1155BatchWithdrawal(CmaParserErc1155BatchWithdrawal),
335    EtherTransfer(CmaParserEtherTransfer),
336    Erc20Transfer(CmaParserErc20Transfer),
337    Erc721Transfer(CmaParserErc721Transfer),
338    Erc1155SingleTransfer(CmaParserErc1155SingleTransfer),
339    Erc1155BatchTransfer(CmaParserErc1155BatchTransfer),
340    Balance(CmaParserBalance),
341    Supply(CmaParserSupply),
342}
343
344pub struct CmaParserInput {
345    pub req_type: CmaParserInputType,
346    pub input: CmaParserInputData,
347}
348
349fn handle_parse_ether_deposit(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
350    let payload_hex = input["data"]["payload"]
351        .as_str()
352        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
353    let payload = payload_hex.trim_start_matches("0x");
354
355    let bytes = hex::decode(payload)
356        .map_err(|e| CmaParserError::Message(format!("hex decode error: {}", e)))?;
357
358    if bytes.len() < 20 + 32 {
359        return Err(CmaParserError::Message(
360            "Invalid payload length".to_string(),
361        ));
362    }
363
364    let sender_bytes = &bytes[0..20];
365    let sender = Address::from_slice(sender_bytes);
366
367    let value_bytes = &bytes[20..52];
368    let value = U256::from_big_endian(value_bytes);
369
370    let exec_layer_data = Bytes::from(bytes[52..].to_vec());
371
372    Ok(CmaParserInputData::EtherDeposit(CmaParserEtherDeposit {
373        sender,
374        amount: value,
375        exec_layer_data,
376    }))
377}
378
379fn handle_parse_erc20_and_erc721_deposit(
380    input: JsonValue,
381    t_type: TokenType,
382) -> Result<CmaParserInputData, CmaParserError> {
383    let payload_hex = input["data"]["payload"]
384        .as_str()
385        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
386    let payload = payload_hex.trim_start_matches("0x");
387
388    let bytes = hex::decode(payload)
389        .map_err(|e| CmaParserError::Message(format!("hex decode error: {}", e)))?;
390
391    if bytes.len() < 20 + 20 + 32 {
392        return Err(CmaParserError::Message(
393            "Invalid payload length".to_string(),
394        ));
395    }
396
397    let token = &bytes[0..20];
398    let sender = &bytes[20..40];
399    let amount_bytes = &bytes[40..72];
400    let amount = U256::from_big_endian(amount_bytes);
401    let exec_layer_data = Bytes::from(bytes[72..].to_vec());
402
403    match t_type {
404        TokenType::Erc20 => Ok(CmaParserInputData::Erc20Deposit(CmaParserErc20Deposit {
405            sender: Address::from_slice(sender),
406            token: Address::from_slice(token),
407            amount,
408            exec_layer_data,
409        })),
410        TokenType::Erc721 => Ok(CmaParserInputData::Erc721Deposit(CmaParserErc721Deposit {
411            sender: Address::from_slice(sender),
412            token: Address::from_slice(token),
413            token_id: amount,
414            exec_layer_data,
415        })),
416    }
417}
418
419fn handle_parse_erc1155_single_deposit(
420    input: JsonValue,
421) -> Result<CmaParserInputData, CmaParserError> {
422    let payload_hex = input["data"]["payload"]
423        .as_str()
424        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
425    let payload = payload_hex.trim_start_matches("0x");
426
427    let bytes = hex::decode(payload)
428        .map_err(|e| CmaParserError::Message(format!("hex decode error: {}", e)))?;
429
430    if bytes.len() < 20 + 20 + 32 + 32 {
431        return Err(CmaParserError::Message(
432            "Invalid payload length".to_string(),
433        ));
434    }
435
436    let token = &bytes[0..20];
437    let sender = &bytes[20..40];
438    let token_id_bytes = &bytes[40..72];
439    let token_id = U256::from_big_endian(token_id_bytes);
440    let amount_bytes = &bytes[72..104];
441    let amount = U256::from_big_endian(amount_bytes);
442    let _base_layer_data = Bytes::from(bytes[104..136].to_vec());
443    let exec_layer_data = Bytes::from(bytes[136..].to_vec());
444
445    Ok(CmaParserInputData::Erc1155SingleDeposit(
446        CmaParserErc1155SingleDeposit {
447            sender: Address::from_slice(sender),
448            token: Address::from_slice(token),
449            token_id,
450            amount,
451            exec_layer_data,
452        },
453    ))
454}
455
456fn handle_parse_erc1155_batch_deposit(
457    input: JsonValue,
458) -> Result<CmaParserInputData, CmaParserError> {
459    let payload_hex = input["data"]["payload"]
460        .as_str()
461        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
462    let payload = payload_hex.trim_start_matches("0x");
463
464    let bytes = hex::decode(payload)
465        .map_err(|e| CmaParserError::Message(format!("hex decode error: {}", e)))?;
466
467    if bytes.len() < 20 + 20 + 32 + 32 + 32 {
468        return Err(CmaParserError::Message(
469            "Invalid payload length".to_string(),
470        ));
471    }
472
473    let u256_from = |b: &[u8]| U256::from_big_endian(b);
474    let as_addr = |b: &[u8]| Address::from_slice(&b[12..32]);
475
476    let token = as_addr(&bytes[0..32]);
477    let sender = as_addr(&bytes[32..64]);
478
479    let token_ids_offset = u256_from(&bytes[64..96]).as_usize();
480    let values_offset = u256_from(&bytes[96..128]).as_usize();
481    let base_offset = u256_from(&bytes[128..160]).as_usize();
482    let exec_offset = u256_from(&bytes[160..192]).as_usize();
483
484    let token_ids_len = u256_from(&bytes[token_ids_offset..token_ids_offset + 32]).as_usize();
485    let mut token_ids = Vec::with_capacity(token_ids_len);
486
487    let mut cursor = token_ids_offset + 32;
488    for _ in 0..token_ids_len {
489        token_ids.push(u256_from(&bytes[cursor..cursor + 32]));
490        cursor += 32;
491    }
492
493    let values_len = u256_from(&bytes[values_offset..values_offset + 32]).as_usize();
494    let mut values = Vec::with_capacity(values_len);
495
496    let mut cursor2 = values_offset + 32;
497    for _ in 0..values_len {
498        values.push(u256_from(&bytes[cursor2..cursor2 + 32]));
499        cursor2 += 32;
500    }
501
502    let base_len = u256_from(&bytes[base_offset..base_offset + 32]).as_usize();
503    let base_start = base_offset + 32;
504    let base_end = base_start + base_len;
505    let base_layer_data = Bytes::from(bytes[base_start..base_end].to_vec());
506
507    let exec_len = u256_from(&bytes[exec_offset..exec_offset + 32]).as_usize();
508    let exec_start = exec_offset + 32;
509    let exec_end = exec_start + exec_len;
510    let exec_layer_data = Bytes::from(bytes[exec_start..exec_end].to_vec());
511
512    if token_ids_len == 0 || values_len == 0 || token_ids_len != values_len {
513        return Err(CmaParserError::Message("Invalid payload data".to_string()));
514    }
515
516    Ok(CmaParserInputData::Erc1155BatchDeposit(
517        CmaParserErc1155BatchDeposit {
518            sender,
519            token,
520            count: token_ids_len,
521            token_ids,
522            amounts: values,
523            base_layer_data,
524            exec_layer_data,
525        },
526    ))
527}
528
529fn handle_ether_withdrawal(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
530    let payload_hex = input["data"]["payload"]
531        .as_str()
532        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
533    let payload_str = hex_to_string(payload_hex)
534        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
535    let msg_sender =
536        input["data"]["metadata"]["msg_sender"]
537            .as_str()
538            .ok_or(CmaParserError::Message(String::from(
539                "Invalid msg_sender address",
540            )))?;
541
542    match json::parse(&payload_str) {
543        Ok(parsed_json) => {
544            let receiver = msg_sender
545                .parse::<Address>()
546                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
547            let amount_str = parsed_json["amount"]
548                .as_str()
549                .ok_or(CmaParserError::Message(String::from("Invalid amount")))?;
550            let amount = U256::from_dec_str(amount_str)
551                .map_err(|e| CmaParserError::Message(format!("amount parse error: {}", e)))?;
552            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
553
554            Ok(CmaParserInputData::EtherWithdrawal(
555                CmaParserEtherWithdrawal {
556                    receiver,
557                    amount,
558                    exec_layer_data,
559                },
560            ))
561        }
562        Err(_) => Err(CmaParserError::Message(String::from(
563            "Failed to parse JSON payload",
564        ))),
565    }
566}
567
568fn handle_erc20_withdrawal(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
569    let payload_hex = input["data"]["payload"]
570        .as_str()
571        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
572    let payload_str = hex_to_string(payload_hex)
573        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
574    let msg_sender =
575        input["data"]["metadata"]["msg_sender"]
576            .as_str()
577            .ok_or(CmaParserError::Message(String::from(
578                "Invalid msg_sender address",
579            )))?;
580
581    match json::parse(&payload_str) {
582        Ok(parsed_json) => {
583            let receiver = msg_sender
584                .parse::<Address>()
585                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
586            let token_str = parsed_json["token"]
587                .as_str()
588                .ok_or(CmaParserError::Message(String::from(
589                    "Invalid token address",
590                )))?;
591            let token = token_str
592                .parse::<Address>()
593                .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
594            let amount_str = parsed_json["amount"]
595                .as_str()
596                .ok_or(CmaParserError::Message(String::from("Invalid amount")))?;
597            let amount = U256::from_dec_str(amount_str)
598                .map_err(|e| CmaParserError::Message(format!("amount parse error: {}", e)))?;
599            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
600
601            Ok(CmaParserInputData::Erc20Withdrawal(
602                CmaParserErc20Withdrawal {
603                    receiver,
604                    token,
605                    amount,
606                    exec_layer_data,
607                },
608            ))
609        }
610        Err(_) => Err(CmaParserError::Message(String::from(
611            "Failed to parse JSON payload",
612        ))),
613    }
614}
615
616fn handle_erc721_withdrawal(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
617    let payload_hex = input["data"]["payload"]
618        .as_str()
619        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
620    let payload_str = hex_to_string(payload_hex)
621        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
622    let msg_sender =
623        input["data"]["metadata"]["msg_sender"]
624            .as_str()
625            .ok_or(CmaParserError::Message(String::from(
626                "Invalid msg_sender address",
627            )))?;
628
629    match json::parse(&payload_str) {
630        Ok(parsed_json) => {
631            let receiver = msg_sender
632                .parse::<Address>()
633                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
634            let token_str = parsed_json["token"]
635                .as_str()
636                .ok_or(CmaParserError::Message(String::from(
637                    "Invalid token address",
638                )))?;
639            let token = token_str
640                .parse::<Address>()
641                .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
642            let token_id_str = parsed_json["id"]
643                .as_str()
644                .ok_or(CmaParserError::Message(String::from("Invalid token id")))?;
645            let token_id = U256::from_dec_str(token_id_str)
646                .map_err(|e| CmaParserError::Message(format!("token id parse error: {}", e)))?;
647            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
648
649            Ok(CmaParserInputData::Erc721Withdrawal(
650                CmaParserErc721Withdrawal {
651                    receiver,
652                    token,
653                    token_id,
654                    exec_layer_data,
655                },
656            ))
657        }
658        Err(_) => Err(CmaParserError::Message(String::from(
659            "Failed to parse JSON payload",
660        ))),
661    }
662}
663
664fn handle_ether_transfer(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
665    let payload_hex = input["data"]["payload"]
666        .as_str()
667        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
668    let payload_str = hex_to_string(payload_hex)
669        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
670    let msg_sender =
671        input["data"]["metadata"]["msg_sender"]
672            .as_str()
673            .ok_or(CmaParserError::Message(String::from(
674                "Invalid msg_sender address",
675            )))?;
676
677    match json::parse(&payload_str) {
678        Ok(parsed_json) => {
679            let sender = msg_sender
680                .parse::<Address>()
681                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
682            let receiver_str = parsed_json["receiver"]
683                .as_str()
684                .ok_or(CmaParserError::Message(String::from(
685                    "Invalid receiver address",
686                )))?;
687            let receiver = receiver_str
688                .parse::<Address>()
689                .map_err(|e| CmaParserError::Message(format!("receiver address error: {}", e)))?;
690            let amount_str = parsed_json["amount"]
691                .as_str()
692                .ok_or(CmaParserError::Message(String::from("Invalid amount")))?;
693            let amount = U256::from_dec_str(amount_str)
694                .map_err(|e| CmaParserError::Message(format!("amount parse error: {}", e)))?;
695            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
696
697            Ok(CmaParserInputData::EtherTransfer(CmaParserEtherTransfer {
698                sender,
699                receiver,
700                amount,
701                exec_layer_data,
702            }))
703        }
704        Err(_) => Err(CmaParserError::Message(String::from(
705            "Failed to parse JSON payload",
706        ))),
707    }
708}
709
710fn handle_erc20_transfer(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
711    let payload_hex = input["data"]["payload"]
712        .as_str()
713        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
714    let payload_str = hex_to_string(payload_hex)
715        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
716    let msg_sender =
717        input["data"]["metadata"]["msg_sender"]
718            .as_str()
719            .ok_or(CmaParserError::Message(String::from(
720                "Invalid msg_sender address",
721            )))?;
722
723    match json::parse(&payload_str) {
724        Ok(parsed_json) => {
725            let sender = msg_sender
726                .parse::<Address>()
727                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
728            let receiver_str = parsed_json["receiver"]
729                .as_str()
730                .ok_or(CmaParserError::Message(String::from(
731                    "Invalid receiver address",
732                )))?;
733            let receiver = receiver_str
734                .parse::<Address>()
735                .map_err(|e| CmaParserError::Message(format!("receiver address error: {}", e)))?;
736            let token_str = parsed_json["token"]
737                .as_str()
738                .ok_or(CmaParserError::Message(String::from(
739                    "Invalid token address",
740                )))?;
741            let token = token_str
742                .parse::<Address>()
743                .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
744            let amount_str = parsed_json["amount"]
745                .as_str()
746                .ok_or(CmaParserError::Message(String::from("Invalid amount")))?;
747            let amount = U256::from_dec_str(amount_str)
748                .map_err(|e| CmaParserError::Message(format!("amount parse error: {}", e)))?;
749            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
750
751            Ok(CmaParserInputData::Erc20Transfer(CmaParserErc20Transfer {
752                sender,
753                receiver,
754                token,
755                amount,
756                exec_layer_data,
757            }))
758        }
759        Err(_) => Err(CmaParserError::Message(String::from(
760            "Failed to parse JSON payload",
761        ))),
762    }
763}
764
765fn handle_erc721_transfer(input: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
766    let payload_hex = input["data"]["payload"]
767        .as_str()
768        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
769    let payload_str = hex_to_string(payload_hex)
770        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
771    let msg_sender =
772        input["data"]["metadata"]["msg_sender"]
773            .as_str()
774            .ok_or(CmaParserError::Message(String::from(
775                "Invalid msg_sender address",
776            )))?;
777
778    match json::parse(&payload_str) {
779        Ok(parsed_json) => {
780            let sender = msg_sender
781                .parse::<Address>()
782                .map_err(|e| CmaParserError::Message(format!("msg_sender address error: {}", e)))?;
783            let receiver_str = parsed_json["receiver"]
784                .as_str()
785                .ok_or(CmaParserError::Message(String::from(
786                    "Invalid receiver address",
787                )))?;
788            let receiver = receiver_str
789                .parse::<Address>()
790                .map_err(|e| CmaParserError::Message(format!("receiver address error: {}", e)))?;
791            let token_str = parsed_json["token"]
792                .as_str()
793                .ok_or(CmaParserError::Message(String::from(
794                    "Invalid token address",
795                )))?;
796            let token = token_str
797                .parse::<Address>()
798                .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
799            let token_id_str = parsed_json["id"]
800                .as_str()
801                .ok_or(CmaParserError::Message(String::from("Invalid token id")))?;
802            let token_id = U256::from_dec_str(token_id_str)
803                .map_err(|e| CmaParserError::Message(format!("token id parse error: {}", e)))?;
804            let exec_layer_data = parsed_json["exec_layer_data"].to_string();
805
806            Ok(CmaParserInputData::Erc721Transfer(
807                CmaParserErc721Transfer {
808                    sender,
809                    receiver,
810                    token,
811                    token_id,
812                    exec_layer_data,
813                },
814            ))
815        }
816        Err(_) => Err(CmaParserError::Message(String::from(
817            "Failed to parse JSON payload",
818        ))),
819    }
820}
821
822pub fn cma_decode_advance(input: JsonValue) -> Result<CmaParserInput, CmaParserError> {
823    let msg_sender =
824        input["data"]["metadata"]["msg_sender"]
825            .as_str()
826            .ok_or(CmaParserError::Message(String::from(
827                "Invalid msg_sender address",
828            )))?;
829    let req_type: CmaParserInputType;
830
831    // Determine the portal type based on msg_sender
832    match CARTESI_ADDRESSES.match_portal(msg_sender) {
833        Portals::ERC1155BatchPortal => {
834            req_type = CmaParserInputType::CmaParserInputTypeErc1155BatchDeposit;
835            return handle_parse_erc1155_batch_deposit(input).map(|data| CmaParserInput {
836                req_type,
837                input: data,
838            });
839        }
840        Portals::ERC1155SinglePortal => {
841            req_type = CmaParserInputType::CmaParserInputTypeErc1155SingleDeposit;
842            return handle_parse_erc1155_single_deposit(input).map(|data| CmaParserInput {
843                req_type,
844                input: data,
845            });
846        }
847        Portals::ERC721Portal => {
848            req_type = CmaParserInputType::CmaParserInputTypeErc721Deposit;
849            return handle_parse_erc20_and_erc721_deposit(input, TokenType::Erc721).map(|data| {
850                CmaParserInput {
851                    req_type,
852                    input: data,
853                }
854            });
855        }
856        Portals::ERC20Portal => {
857            req_type = CmaParserInputType::CmaParserInputTypeErc20Deposit;
858            return handle_parse_erc20_and_erc721_deposit(input, TokenType::Erc20).map(|data| {
859                CmaParserInput {
860                    req_type,
861                    input: data,
862                }
863            });
864        }
865        Portals::EtherPortal => {
866            req_type = CmaParserInputType::CmaParserInputTypeEtherDeposit;
867            return handle_parse_ether_deposit(input).map(|data| CmaParserInput {
868                req_type,
869                input: data,
870            });
871        }
872        // IF CALLER IS NOT ANY OF THE ABOVE PORTALS, WE TRY TO PARSE THE PAYLOAD FOR WITHDRAWALS/TRANSFERS
873        Portals::None => {
874            let payload_hex = input["data"]["payload"]
875                .as_str()
876                .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
877            let payload_str = hex_to_string(payload_hex).map_err(|e| {
878                CmaParserError::Message(format!("hex to string conversion error: {}", e))
879            })?;
880
881            match json::parse(&payload_str) {
882                Ok(parsed_json) => {
883                    let function_type =
884                        parsed_json["function_type"]
885                            .as_str()
886                            .ok_or(CmaParserError::Message(String::from(
887                                "Invalid function type",
888                            )))?;
889
890                    // Determine the request type based on function_type
891                    req_type = CmaParserInputType::from_string(function_type);
892
893                    // Handle the request based on the determined type
894                    match req_type {
895                        CmaParserInputType::CmaParserInputTypeEtherWithdrawal => {
896                            return handle_ether_withdrawal(input).map(|data| CmaParserInput {
897                                req_type,
898                                input: data,
899                            });
900                        }
901
902                        CmaParserInputType::CmaParserInputTypeErc20Withdrawal => {
903                            return handle_erc20_withdrawal(input).map(|data| CmaParserInput {
904                                req_type,
905                                input: data,
906                            });
907                        }
908                        CmaParserInputType::CmaParserInputTypeErc721Withdrawal => {
909                            return handle_erc721_withdrawal(input).map(|data| CmaParserInput {
910                                req_type,
911                                input: data,
912                            });
913                        }
914                        CmaParserInputType::CmaParserInputTypeEtherTransfer => {
915                            return handle_ether_transfer(input).map(|data| CmaParserInput {
916                                req_type,
917                                input: data,
918                            });
919                        }
920                        CmaParserInputType::CmaParserInputTypeErc20Transfer => {
921                            return handle_erc20_transfer(input).map(|data| CmaParserInput {
922                                req_type,
923                                input: data,
924                            });
925                        }
926                        CmaParserInputType::CmaParserInputTypeErc721Transfer => {
927                            return handle_erc721_transfer(input).map(|data| CmaParserInput {
928                                req_type,
929                                input: data,
930                            });
931                        }
932                        _ => Err(CmaParserError::IncompatibleInput),
933                    }
934                }
935                Err(_) => {
936                    return Err(CmaParserError::Message(String::from(
937                        "Failed to parse JSON payload",
938                    )))
939                }
940            }
941        }
942    }
943}
944
945fn handle_ledger_get_balance(parsed_json: JsonValue) -> Result<CmaParserBalance, CmaParserError> {
946    // Extract params array
947    let params_val = &parsed_json["params"];
948    if !params_val.is_array() {
949        return Err(CmaParserError::Message(
950            "Invalid params: not an array".into(),
951        ));
952    }
953
954    // params[0] = account
955    let account_str = params_val[0]
956        .as_str()
957        .ok_or_else(|| CmaParserError::Message("Invalid account param".into()))?;
958
959    let account = account_str
960        .parse::<Address>()
961        .map_err(|e| CmaParserError::Message(format!("account address error: {}", e)))?;
962
963    // params[1] = token
964    let token_str = params_val[1]
965        .as_str()
966        .ok_or_else(|| CmaParserError::Message("Invalid token param".into()))?;
967
968    let token = token_str
969        .parse::<Address>()
970        .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
971
972    // params[2] = optional array containing token id's
973    let mut token_id: Vec<U256> = Vec::new();
974    if params_val.len() > 2 && params_val[2].is_array() {
975        // params_val[2][0] might itself be an array of ids or params_val[2] might be the array
976        if params_val[2][0].is_array() {
977            for v in params_val[2][0].members() {
978                let s = v
979                    .as_str()
980                    .ok_or_else(|| CmaParserError::Message("Invalid token id".into()))?;
981                let id = U256::from_dec_str(s)
982                    .map_err(|e| CmaParserError::Message(format!("token id parse error: {}", e)))?;
983                token_id.push(id);
984            }
985        } else {
986            // handle array of strings/numbers or comma-separated string(s)
987            for v in params_val[2].members() {
988                if let Some(s) = v.as_str() {
989                    if s.contains(',') {
990                        for part in s.split(',').map(str::trim).filter(|p| !p.is_empty()) {
991                            let id = U256::from_dec_str(part).map_err(|e| {
992                                CmaParserError::Message(format!("token id parse error: {}", e))
993                            })?;
994                            token_id.push(id);
995                        }
996                    } else {
997                        let id = U256::from_dec_str(s).map_err(|e| {
998                            CmaParserError::Message(format!("token id parse error: {}", e))
999                        })?;
1000                        token_id.push(id);
1001                    }
1002                } else if v.is_number() {
1003                    let id = U256::from_dec_str(&v.to_string()).map_err(|e| {
1004                        CmaParserError::Message(format!("token id parse error: {}", e))
1005                    })?;
1006                    token_id.push(id);
1007                } else {
1008                    return Err(CmaParserError::Message("Invalid token id format".into()));
1009                }
1010            }
1011        }
1012    }
1013
1014    Ok(CmaParserBalance {
1015        account,
1016        token,
1017        token_ids: Some(token_id),
1018    })
1019}
1020
1021fn handle_ledger_get_supply(parsed_json: JsonValue) -> Result<CmaParserInputData, CmaParserError> {
1022    // Ensure params is an array
1023    let params_val = &parsed_json["params"];
1024    if !params_val.is_array() {
1025        return Err(CmaParserError::Message(
1026            "Invalid params: not an array".into(),
1027        ));
1028    }
1029
1030    // params[0] = token address string
1031    let token_str = params_val[0]
1032        .as_str()
1033        .ok_or_else(|| CmaParserError::Message("Invalid token param".into()))?;
1034
1035    let token = token_str
1036        .parse::<Address>()
1037        .map_err(|e| CmaParserError::Message(format!("token address error: {}", e)))?;
1038
1039    // params[1] = optional array containing token id's
1040    let mut token_id: Vec<U256> = Vec::new();
1041    if params_val.len() > 1 && params_val[1].is_array() {
1042        // params_val[1][0] might itself be an array of ids or params_val[1] might be the array
1043        if params_val[1][0].is_array() {
1044            for v in params_val[1][0].members() {
1045                let s = v
1046                    .as_str()
1047                    .ok_or_else(|| CmaParserError::Message("Invalid token id".into()))?;
1048                let id = U256::from_dec_str(s)
1049                    .map_err(|e| CmaParserError::Message(format!("token id parse error: {}", e)))?;
1050                token_id.push(id);
1051            }
1052        } else {
1053            // handle array of strings/numbers or comma-separated string(s)
1054            for v in params_val[1].members() {
1055                if let Some(s) = v.as_str() {
1056                    if s.contains(',') {
1057                        for part in s.split(',').map(str::trim).filter(|p| !p.is_empty()) {
1058                            let id = U256::from_dec_str(part).map_err(|e| {
1059                                CmaParserError::Message(format!("token id parse error: {}", e))
1060                            })?;
1061                            token_id.push(id);
1062                        }
1063                    } else {
1064                        let id = U256::from_dec_str(s).map_err(|e| {
1065                            CmaParserError::Message(format!("token id parse error: {}", e))
1066                        })?;
1067                        token_id.push(id);
1068                    }
1069                } else if v.is_number() {
1070                    let id = U256::from_dec_str(&v.to_string()).map_err(|e| {
1071                        CmaParserError::Message(format!("token id parse error: {}", e))
1072                    })?;
1073                    token_id.push(id);
1074                } else {
1075                    return Err(CmaParserError::Message("Invalid token id format".into()));
1076                }
1077            }
1078        }
1079    }
1080
1081    Ok(CmaParserInputData::Supply(CmaParserSupply {
1082        token,
1083        token_ids: token_id,
1084    }))
1085}
1086
1087pub fn cma_decode_inspect(input: JsonValue) -> Result<CmaParserInput, CmaParserError> {
1088    let payload_hex = input["data"]["payload"]
1089        .as_str()
1090        .ok_or(CmaParserError::Message(String::from("Invalid payload hex")))?;
1091    let payload_str = hex_to_string(payload_hex)
1092        .map_err(|e| CmaParserError::Message(format!("hex to string conversion error: {}", e)))?;
1093    let payload_json = json::parse(&payload_str)
1094        .map_err(|e| CmaParserError::Message(format!("Error parsing string to JSON: {}", e)))?;
1095
1096    let req_type: CmaParserInputType =
1097        CmaParserInputType::from_string(payload_json["method"].as_str().ok_or(
1098            CmaParserError::Message(String::from("Invalid inspection type")),
1099        )?);
1100
1101    match req_type {
1102        CmaParserInputType::CmaParserInputTypeBalance => {
1103            return handle_ledger_get_balance(payload_json).map(|data| CmaParserInput {
1104                req_type,
1105                input: CmaParserInputData::Balance(data),
1106            });
1107        }
1108        CmaParserInputType::CmaParserInputTypeSupply => {
1109            return handle_ledger_get_supply(payload_json).map(|data| CmaParserInput {
1110                req_type,
1111                input: data,
1112            });
1113        }
1114        _ => {
1115            // Unsupported inspection type
1116            return Err(CmaParserError::IncompatibleInput);
1117        }
1118    }
1119}
1120
1121fn handle_ether_voucher_encoding(
1122    voucher_request: &CmaParserVoucherData,
1123) -> Result<CmaVoucher, CmaParserError> {
1124    if let CmaVoucherFieldType::EtherVoucherFields(fields) = &voucher_request.voucher_fields {
1125        let payload = "0x".to_string();
1126
1127        let mut value_bytes = [0u8; 32];
1128        fields.amount.to_big_endian(&mut value_bytes);
1129
1130        let voucher = CmaVoucher {
1131            destination: to_checksum(&fields.receiver, None),
1132            value: format!("0x{}", hex::encode(value_bytes)),
1133            payload,
1134        };
1135
1136        Ok(voucher)
1137    } else {
1138        Err(CmaParserError::Message(String::from(
1139            "Invalid voucher fields for Ether",
1140        )))
1141    }
1142}
1143
1144fn handle_erc20_voucher_encoding(
1145    voucher_request: &CmaParserVoucherData,
1146) -> Result<CmaVoucher, CmaParserError> {
1147    if let CmaVoucherFieldType::Erc20VoucherFields(fields) = &voucher_request.voucher_fields {
1148        let token = fields.token;
1149
1150        let args: Vec<Token> = vec![Token::Address(fields.receiver), Token::Uint(fields.amount)];
1151
1152        let function_sig = "transfer(address,uint256)";
1153        let selector = &id(function_sig)[..4];
1154
1155        let encoded_args = encode(&args);
1156        let value = fields.value;
1157        let mut payload_bytes = Vec::new();
1158        payload_bytes.extend_from_slice(selector);
1159        payload_bytes.extend_from_slice(&encoded_args);
1160        let payload = format!("0x{}", hex::encode(payload_bytes));
1161
1162        let mut value_bytes = [0u8; 32];
1163        value.to_big_endian(&mut value_bytes);
1164
1165        let voucher = CmaVoucher {
1166            destination: format!("{:?}", token),
1167            value: format!("0x{}", hex::encode(value_bytes)),
1168            payload: format!("{}", payload),
1169        };
1170        return Ok(voucher);
1171    } else {
1172        Err(CmaParserError::Message(String::from(
1173            "Invalid voucher fields for ERC20",
1174        )))
1175    }
1176}
1177
1178fn handle_erc721_voucher_encoding(
1179    voucher_request: &CmaParserVoucherData,
1180) -> Result<CmaVoucher, CmaParserError> {
1181    if let CmaVoucherFieldType::Erc721VoucherFields(fields) = &voucher_request.voucher_fields {
1182        let token = fields.token;
1183
1184        let args: Vec<Token> = vec![
1185            Token::Address(fields.application_address),
1186            Token::Address(fields.receiver),
1187            Token::Uint(fields.token_id.into()),
1188        ];
1189        let function_sig = "transferFrom(address,address,uint256)";
1190        let selector = &id(function_sig)[..4];
1191        let encoded_args = encode(&args);
1192        let value = fields.value;
1193        let mut payload_bytes = Vec::new();
1194        payload_bytes.extend_from_slice(selector);
1195        payload_bytes.extend_from_slice(&encoded_args);
1196        let payload = format!("0x{}", hex::encode(payload_bytes));
1197
1198        let mut value_bytes = [0u8; 32];
1199        value.to_big_endian(&mut value_bytes);
1200
1201        let voucher = CmaVoucher {
1202            destination: format!("{:?}", token),
1203            value: format!("0x{}", hex::encode(value_bytes)),
1204            payload: format!("{}", payload),
1205        };
1206
1207        return Ok(voucher);
1208    } else {
1209        Err(CmaParserError::Message(String::from(
1210            "Invalid voucher fields for ERC721",
1211        )))
1212    }
1213}
1214
1215pub fn cma_encode_voucher(
1216    req_type: CmaParserVoucherType,
1217    voucher_request: CmaParserVoucherData,
1218) -> Result<CmaVoucher, CmaParserError> {
1219    match req_type {
1220        CmaParserVoucherType::CmaParserVoucherTypeEther => {
1221            return handle_ether_voucher_encoding(&voucher_request);
1222        }
1223        CmaParserVoucherType::CmaParserVoucherTypeErc20 => {
1224            return handle_erc20_voucher_encoding(&voucher_request);
1225        }
1226        CmaParserVoucherType::CmaParserVoucherTypeErc721 => {
1227            return handle_erc721_voucher_encoding(&voucher_request);
1228        }
1229        CmaParserVoucherType::CmaParserVoucherTypeErc1155Single => {
1230            // TODO Implement encoding logic for ERC1155 Single voucher
1231            return Err(CmaParserError::Message(String::from("Not Implemented yet")));
1232        }
1233        CmaParserVoucherType::CmaParserVoucherTypeErc1155Batch => {
1234            // TODO Implement encoding logic for ERC1155 Batch voucher
1235            return Err(CmaParserError::Message(String::from("Not Implemented yet")));
1236        }
1237        CmaParserVoucherType::CmaParserVoucherTypeNone => {
1238            return Err(CmaParserError::Message(String::from("Not Implemented yet")))
1239        }
1240    }
1241}