decode_starknet_calldata/
lib.rs

1use bigdecimal::ToPrimitive;
2use starknet::{accounts::Call, core::types::FieldElement};
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum DecodeCalldataError {
7    #[error("field '{0}' at index {1} was not found in calldata")]
8    FieldNotFound(String, usize),
9    #[error("failed to convert field '{0}' to u64 at index {1}")]
10    Conversion(String, usize),
11    #[error("actual calldata length {0} does not match the expected length of {1}")]
12    UnexpectedLength(u64, u64),
13}
14
15struct CallBuilder {
16    to: FieldElement,
17    selector: FieldElement,
18    data_offset: u64,
19    data_len: u64,
20}
21
22pub fn decode(calls: &[FieldElement]) -> Result<Vec<Call>, DecodeCalldataError> {
23    decode_legacy(calls).or_else(|_| decode_new(calls))
24}
25
26pub fn decode_legacy(calldata: &[FieldElement]) -> Result<Vec<Call>, DecodeCalldataError> {
27    let mut calls = vec![];
28
29    let calls_length = calldata
30        .first()
31        .ok_or(DecodeCalldataError::FieldNotFound(
32            String::from("calls_length"),
33            0,
34        ))?
35        .to_big_decimal(0);
36
37    let calls_length = calls_length
38        .to_u64()
39        .ok_or(DecodeCalldataError::Conversion(
40            String::from("calls_length"),
41            0,
42        ))?;
43
44    let mut offset = 1;
45    let mut call_builders: Vec<CallBuilder> = vec![];
46    for _ in 0..calls_length {
47        let to = *calldata
48            .get(offset)
49            .ok_or(DecodeCalldataError::FieldNotFound(
50                String::from("to"),
51                offset,
52            ))?;
53
54        let selector = *calldata
55            .get(offset + 1)
56            .ok_or(DecodeCalldataError::FieldNotFound(
57                String::from("selector"),
58                offset + 1,
59            ))?;
60
61        let data_offset = calldata
62            .get(offset + 2)
63            .ok_or(DecodeCalldataError::FieldNotFound(
64                String::from("data_offset"),
65                offset + 2,
66            ))?;
67        let data_offset = data_offset.to_big_decimal(0);
68        let data_offset = data_offset.to_u64().ok_or(DecodeCalldataError::Conversion(
69            String::from("data_offset"),
70            offset + 2,
71        ))?;
72
73        let data_len = calldata
74            .get(offset + 3)
75            .ok_or(DecodeCalldataError::FieldNotFound(
76                String::from("data_len"),
77                offset + 3,
78            ))?;
79        let data_len = data_len.to_big_decimal(0);
80        let data_len = data_len.to_u64().ok_or(DecodeCalldataError::Conversion(
81            String::from("data_len"),
82            offset + 3,
83        ))?;
84
85        call_builders.push(CallBuilder::new(to, selector, data_offset, data_len));
86
87        offset += 4;
88    }
89
90    let calldata_len = calldata
91        .get(offset)
92        .ok_or(DecodeCalldataError::FieldNotFound(
93            String::from("calldata_len"),
94            offset,
95        ))?;
96    let calldata_len = calldata_len.to_big_decimal(0);
97    let calldata_len = calldata_len
98        .to_u64()
99        .ok_or(DecodeCalldataError::Conversion(
100            String::from("calldata_len"),
101            0,
102        ))?;
103
104    let expected_calldata_len = call_builders
105        .iter()
106        .fold(0, |acc, call_builder| acc + call_builder.data_len);
107    if calldata_len != expected_calldata_len {
108        return Err(DecodeCalldataError::UnexpectedLength(
109            calldata_len,
110            expected_calldata_len,
111        ));
112    }
113
114    offset += 1;
115
116    for call_builder in call_builders.into_iter() {
117        let calldata = calldata
118            .get(
119                offset + call_builder.data_offset as usize
120                    ..offset + call_builder.data_offset as usize + call_builder.data_len as usize,
121            )
122            .ok_or(DecodeCalldataError::FieldNotFound(
123                String::from("calldata"),
124                offset + call_builder.data_offset as usize,
125            ))?
126            .to_vec();
127
128        calls.push(call_builder.build(calldata));
129    }
130
131    Ok(calls)
132}
133
134pub fn decode_new(calldata: &[FieldElement]) -> Result<Vec<Call>, DecodeCalldataError> {
135    let mut calls = vec![];
136
137    let calls_length = calldata
138        .first()
139        .ok_or(DecodeCalldataError::FieldNotFound(
140            String::from("calls_length"),
141            0,
142        ))?
143        .to_big_decimal(0);
144    let calls_length = calls_length
145        .to_u64()
146        .ok_or(DecodeCalldataError::Conversion(
147            String::from("calls_length"),
148            0,
149        ))?;
150
151    let mut offset = 1;
152    for _ in 0..calls_length {
153        let to = *calldata
154            .get(offset)
155            .ok_or(DecodeCalldataError::FieldNotFound(
156                String::from("to"),
157                offset,
158            ))?;
159
160        let selector = *calldata
161            .get(offset + 1)
162            .ok_or(DecodeCalldataError::FieldNotFound(
163                String::from("selector"),
164                offset + 1,
165            ))?;
166
167        let calldata_len = calldata
168            .get(offset + 2)
169            .ok_or(DecodeCalldataError::FieldNotFound(
170                String::from("calldata_len"),
171                offset + 2,
172            ))?;
173        let calldata_len = calldata_len.to_big_decimal(0);
174        let calldata_len = calldata_len
175            .to_u64()
176            .ok_or(DecodeCalldataError::Conversion(
177                String::from("calldata_len"),
178                offset + 2,
179            ))?;
180
181        let calldata = calldata
182            .get(offset + 3..offset + 3 + calldata_len as usize)
183            .ok_or(DecodeCalldataError::FieldNotFound(
184                String::from("calldata"),
185                offset + 3,
186            ))?
187            .to_vec();
188
189        println!("calldata: {:?}", calldata);
190        println!("calldata_len: {:?}", calldata_len);
191
192        if calldata.len() != calldata_len as usize {
193            return Err(DecodeCalldataError::UnexpectedLength(
194                calldata_len,
195                calldata.len() as u64,
196            ));
197        }
198
199        offset += 3 + calldata_len as usize;
200
201        calls.push(Call {
202            to,
203            selector,
204            calldata,
205        });
206    }
207
208    Ok(calls)
209}
210
211impl CallBuilder {
212    fn new(to: FieldElement, selector: FieldElement, data_offset: u64, data_len: u64) -> Self {
213        CallBuilder {
214            to,
215            selector,
216            data_offset,
217            data_len,
218        }
219    }
220
221    fn build(&self, calldata: Vec<FieldElement>) -> Call {
222        Call {
223            to: self.to,
224            selector: self.selector,
225            calldata,
226        }
227    }
228}
229
230#[cfg(test)]
231mod tests {
232    use starknet::macros::felt;
233
234    use super::*;
235
236    #[test]
237    fn test_decode_new_approve_repay_calldata() {
238        let calldata = vec![
239            // calls len
240            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
241            // to
242            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
243            // selector (approve)
244            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c"),
245            // calldata len
246            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
247            // d0
248            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
249            // d1
250            felt!("0x000000000000000000000000000000000000000000000000000c35f7d2acc9ec"),
251            // d2
252            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
253            // to
254            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
255            // selector (repay)
256            felt!("0x00ad257770e86a03742ebe0a615fb19503d9c891d118daa82163867444c08680"),
257            // calldata len
258            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
259            // token (d0)
260            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
261            // amount (d1)
262            felt!("0x000000000000000000000000000000000000000000000000000c35f7d2acc9ec"),
263        ];
264
265        let calls = decode(&calldata).unwrap();
266        assert_eq!(calls.len(), 2);
267
268        assert_eq!(
269            calls[0].to,
270            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
271        );
272        assert_eq!(
273            calls[0].selector,
274            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c")
275        );
276
277        assert_eq!(calls[0].calldata.len(), 3);
278
279        assert_eq!(
280            calls[1].to,
281            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
282        );
283        assert_eq!(
284            calls[1].selector,
285            felt!("0x00ad257770e86a03742ebe0a615fb19503d9c891d118daa82163867444c08680")
286        );
287        assert_eq!(calls[1].calldata.len(), 2);
288    }
289
290    #[test]
291    fn test_decode_new_withdraw_all_calldata() {
292        let calldata = vec![
293            // calls len
294            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
295            // to
296            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
297            // selector (withdraw_all)
298            felt!("0x0275dc81fcd5c700205ff6dc320e9d54ed3f0ace21177d591d6d5d259ee1d7c2"),
299            // calldata len
300            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
301            // token (d0)
302            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
303        ];
304
305        let calls = decode(&calldata).unwrap();
306
307        assert_eq!(calls.len(), 1);
308
309        assert_eq!(
310            calls[0].to,
311            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
312        );
313        assert_eq!(
314            calls[0].selector,
315            felt!("0x0275dc81fcd5c700205ff6dc320e9d54ed3f0ace21177d591d6d5d259ee1d7c2")
316        );
317    }
318
319    #[test]
320    fn test_decode_new_approve_deposit_enable_collateral_calldata() {
321        let calldata = vec![
322            // calls len
323            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
324            // to
325            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
326            // selector (approve)
327            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c"),
328            // calldata len
329            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
330            // d0
331            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
332            // d1
333            felt!("0x00000000000000000000000000000000000000000000000000c60349dcfe6c7d"),
334            // d2
335            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
336            // to
337            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
338            // selector (deposit)
339            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01"),
340            // calldata len
341            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
342            // token (d0)
343            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
344            // amount (d1)
345            felt!("0x00000000000000000000000000000000000000000000000000c60349dcfe6c7d"),
346            // to
347            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
348            // selector (enable_collateral)
349            felt!("0x0271680756697a04d1447ad4c21d53bdf15966bdc5b78bd52d4fc2153aa76bda"),
350            // calldata len
351            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
352            // token (d0)
353            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
354        ];
355
356        let calls = decode(&calldata).unwrap();
357
358        assert_eq!(calls.len(), 3);
359
360        assert_eq!(
361            calls[0].to,
362            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
363        );
364        assert_eq!(
365            calls[0].selector,
366            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c")
367        );
368        assert_eq!(calls[0].calldata.len(), 3);
369
370        assert_eq!(
371            calls[1].to,
372            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
373        );
374        assert_eq!(
375            calls[1].selector,
376            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01")
377        );
378        assert_eq!(calls[1].calldata.len(), 2);
379
380        assert_eq!(
381            calls[2].to,
382            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
383        );
384        assert_eq!(
385            calls[2].selector,
386            felt!("0x0271680756697a04d1447ad4c21d53bdf15966bdc5b78bd52d4fc2153aa76bda")
387        );
388        assert_eq!(calls[2].calldata.len(), 1);
389    }
390
391    #[test]
392    fn test_decode_new_approve_deposit_calldata() {
393        let calldata = vec![
394            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
395            // to
396            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
397            // selector (approve)
398            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c"),
399            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
400            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
401            felt!("0x000000000000000000000000000000000000000000000000255c9da2d84e8000"),
402            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
403            // to
404            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
405            // selector (deposit)
406            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01"),
407            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
408            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
409            felt!("0x000000000000000000000000000000000000000000000000255c9da2d84e8000"),
410        ];
411
412        let calls = decode(&calldata).unwrap();
413
414        assert_eq!(calls.len(), 2);
415
416        assert_eq!(
417            calls[0].to,
418            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
419        );
420        assert_eq!(
421            calls[0].selector,
422            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c")
423        );
424        assert_eq!(calls[0].calldata.len(), 3);
425
426        assert_eq!(
427            calls[1].to,
428            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
429        );
430        assert_eq!(
431            calls[1].selector,
432            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01")
433        );
434        assert_eq!(calls[1].calldata.len(), 2);
435    }
436
437    #[test]
438    fn test_decode_legacy_withdraw_all_calldata() {
439        let calldata = vec![
440            // calls len
441            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
442            // to
443            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
444            // selector (withdraw_all)
445            felt!("0x0275dc81fcd5c700205ff6dc320e9d54ed3f0ace21177d591d6d5d259ee1d7c2"),
446            // data_offset
447            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
448            // data_len
449            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
450            // calldata array starts
451
452            // calldata len
453            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
454            // d0 (token)
455            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
456        ];
457
458        let calls = decode(&calldata).unwrap();
459
460        assert_eq!(calls.len(), 1);
461        assert_eq!(
462            calls[0].to,
463            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
464        );
465        assert_eq!(
466            calls[0].selector,
467            felt!("0x0275dc81fcd5c700205ff6dc320e9d54ed3f0ace21177d591d6d5d259ee1d7c2")
468        );
469        assert_eq!(calls[0].calldata.len(), 1);
470        assert_eq!(
471            calls[0].calldata[0],
472            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
473        )
474    }
475
476    #[test]
477    fn test_decode_legacy_withdraw_calldata() {
478        let calldata = vec![
479            // calls len
480            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
481            // call array starts
482
483            // to
484            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
485            // selector (withdraw)
486            felt!("0x015511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77"),
487            // data_offset
488            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
489            // data_len
490            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
491            // calldata array starts
492
493            // calldata len
494            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
495            // d0 (token)
496            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
497            // d1 (amount)
498            felt!("0x000000000000000000000000000000000000000000000000057664a5e4444d40"),
499        ];
500
501        let calls = decode(&calldata).unwrap();
502
503        assert_eq!(calls.len(), 1);
504        assert_eq!(
505            calls[0].to,
506            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
507        );
508        assert_eq!(
509            calls[0].selector,
510            felt!("0x015511cc3694f64379908437d6d64458dc76d02482052bfb8a5b33a72c054c77")
511        );
512        assert_eq!(calls[0].calldata.len(), 2);
513        assert_eq!(
514            calls[0].calldata[0],
515            felt!("0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
516        );
517        assert_eq!(
518            calls[0].calldata[1],
519            felt!("0x000000000000000000000000000000000000000000000000057664a5e4444d40")
520        );
521    }
522
523    #[test]
524    fn test_decode_legacy_approve_deposit_enable_collateral() {
525        let calldata = vec![
526            // call array len
527            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
528            // call array starts
529
530            // to
531            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"),
532            // selector (approve)
533            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c"),
534            // data_offset
535            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
536            // data_len
537            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
538            // to
539            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
540            // selector
541            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01"),
542            // data_offset
543            felt!("0x0000000000000000000000000000000000000000000000000000000000000003"),
544            // data_len
545            felt!("0x0000000000000000000000000000000000000000000000000000000000000002"),
546            // to
547            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
548            // selector
549            felt!("0x0271680756697a04d1447ad4c21d53bdf15966bdc5b78bd52d4fc2153aa76bda"),
550            // data_offset
551            felt!("0x0000000000000000000000000000000000000000000000000000000000000005"),
552            // data_len
553            felt!("0x0000000000000000000000000000000000000000000000000000000000000001"),
554            // calldata len
555            felt!("0x0000000000000000000000000000000000000000000000000000000000000006"),
556            // calldata array starts
557
558            // approve d0 (spender)
559            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05"),
560            // approve d1 (amount)
561            felt!("0x000000000000000000000000000000000000000000000000000000000020bde4"),
562            // approve d2
563            felt!("0x0000000000000000000000000000000000000000000000000000000000000000"),
564            // deposit d0 (token)
565            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"),
566            // deposit d1 (amount)
567            felt!("0x000000000000000000000000000000000000000000000000000000000020bde4"),
568            // enable_collateral d0 (token)
569            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8"),
570        ];
571
572        let calls = decode(&calldata).unwrap();
573        assert_eq!(calls.len(), 3);
574
575        assert_eq!(
576            calls[0].to,
577            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8")
578        );
579        assert_eq!(
580            calls[0].selector,
581            felt!("0x0219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c")
582        );
583        assert_eq!(calls[0].calldata.len(), 3);
584        assert_eq!(
585            calls[0].calldata[0],
586            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
587        );
588        assert_eq!(
589            calls[0].calldata[1],
590            felt!("0x000000000000000000000000000000000000000000000000000000000020bde4")
591        );
592        assert_eq!(
593            calls[0].calldata[2], // approve d2
594            felt!("0x0000000000000000000000000000000000000000000000000000000000000000")
595        );
596
597        assert_eq!(
598            calls[1].to,
599            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
600        );
601        assert_eq!(
602            calls[1].selector,
603            felt!("0x00c73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01")
604        );
605        assert_eq!(calls[1].calldata.len(), 2);
606        assert_eq!(
607            calls[1].calldata[0],
608            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8")
609        );
610        assert_eq!(
611            calls[1].calldata[1],
612            felt!("0x000000000000000000000000000000000000000000000000000000000020bde4")
613        );
614
615        assert_eq!(
616            calls[2].to,
617            felt!("0x04c0a5193d58f74fbace4b74dcf65481e734ed1714121bdc571da345540efa05")
618        );
619        assert_eq!(
620            calls[2].selector,
621            felt!("0x0271680756697a04d1447ad4c21d53bdf15966bdc5b78bd52d4fc2153aa76bda")
622        );
623        assert_eq!(calls[2].calldata.len(), 1);
624        assert_eq!(
625            calls[2].calldata[0],
626            felt!("0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8")
627        );
628    }
629
630    #[test]
631    fn test_decode_legacy_transfer() {
632        let calldata = vec![
633            felt!("0x1"),
634            felt!("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7"),
635            felt!("0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e"),
636            felt!("0x0"),
637            felt!("0x3"),
638            felt!("0x3"),
639            felt!("0x7521c84e175b5b36c3a59f8a737cbd4a4dd372d5570989770f4b99dd1a49dd"),
640            felt!("0x71afd498d0011"),
641            felt!("0x0"),
642        ];
643
644        let decoded = decode(&calldata).unwrap();
645
646        assert_eq!(decoded.len(), 1);
647
648        assert_eq!(
649            decoded[0].to,
650            felt!("0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7")
651        );
652        assert_eq!(
653            decoded[0].selector,
654            felt!("0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e")
655        );
656        assert_eq!(decoded[0].calldata.len(), 3);
657        assert_eq!(
658            decoded[0].calldata[0],
659            felt!("0x7521c84e175b5b36c3a59f8a737cbd4a4dd372d5570989770f4b99dd1a49dd")
660        );
661        assert_eq!(decoded[0].calldata[1], felt!("0x71afd498d0011"));
662        assert_eq!(decoded[0].calldata[2], felt!("0x0"));
663    }
664}