cma_rust_parser/
parser.rs

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