ccnext-abi-encoding 0.5.0

ABI encoding library intended for use with the ccnext project.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
use crate::common::{
    compute_v, compute_y_parity, encode_blob_hashes, AbiEncodeResult, EncodingVersion,
};
use alloy::{
    consensus::{
        Signed, Transaction as ConsensusTransaction, TxEip1559, TxEip2930, TxEip4844Variant,
        TxEip7702, TxEnvelope, TxLegacy,
    },
    dyn_abi::DynSolValue,
    eips::eip7702::SignedAuthorization,
    primitives::{Address, B256, U256},
    rpc::types::{AccessListItem, Transaction, TransactionReceipt},
};

fn encode_common_fields(tx: &Transaction) -> DynSolValue {
    let (is_to_null, to) = match tx.to() {
        Some(address) => (false, address),
        None => (true, Address::ZERO),
    };

    DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(tx.nonce()), 64), // Nonce
        DynSolValue::Uint(U256::from(tx.gas_limit()), 64), // Gas limit
        DynSolValue::Address(tx.from),                 // From address
        DynSolValue::Bool(is_to_null),                 // Is null (true if contract creation)
        DynSolValue::Address(to),                      // To address
        DynSolValue::Uint(tx.value(), 256),            // Value
        DynSolValue::Bytes(tx.input().to_vec()),       // Input data (true = dynamic encoding)
    ])
}

fn encode_receipt_fields(rx: TransactionReceipt) -> DynSolValue {
    let log_blooms = rx.inner.logs_bloom().0.to_vec();
    DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(rx.status()), 8),
        DynSolValue::Uint(U256::from(rx.gas_used), 64),
        DynSolValue::Array(
            rx.inner
                .logs()
                .iter()
                .map(|log| {
                    let topics = DynSolValue::Array(
                        log.topics()
                            .iter()
                            .map(|topic| DynSolValue::FixedBytes(*topic, 32))
                            .collect(),
                    );

                    DynSolValue::Tuple(vec![
                        DynSolValue::Address(log.address()),
                        topics,
                        DynSolValue::Bytes(log.data().data.to_vec()),
                    ])
                })
                .collect(),
        ),
        DynSolValue::Bytes(log_blooms),
    ])
}

fn encode_transaction_type_0(
    tx: Transaction,
    signed_tx: Signed<TxLegacy>,
    rx: TransactionReceipt,
) -> Vec<DynSolValue> {
    // Encoding transaction in 3 chunks
    let chunk_1 = encode_common_fields(&tx);

    let chunk_2 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(signed_tx.tx().gas_price), 128), // Gas price
        DynSolValue::Uint(
            U256::from(compute_v(signed_tx.signature(), tx.chain_id())),
            256,
        ), // v (legacy is uint8)
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().r()), 32), // r
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().s()), 32), // s
    ]);

    let chunk_3 = encode_receipt_fields(rx);

    vec![chunk_1, chunk_2, chunk_3]
}

fn encode_transaction_type_1(
    tx: Transaction,
    signed_tx: Signed<TxEip2930>,
    rx: TransactionReceipt,
) -> Vec<DynSolValue> {
    // Encoding transaction in 3 chunks
    let chunk_1 = encode_common_fields(&tx);

    let chunk_2 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(signed_tx.tx().chain_id), 64),
        DynSolValue::Uint(U256::from(signed_tx.tx().gas_price), 128), // Gas price
        encode_access_list(&signed_tx.tx().access_list),
        DynSolValue::Uint(U256::from(compute_y_parity(signed_tx.signature())), 8), // y parity
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().r()), 32),        // r
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().s()), 32),        // s
    ]);

    let chunk_3 = encode_receipt_fields(rx);

    vec![chunk_1, chunk_2, chunk_3]
}

fn encode_transaction_type_2(
    tx: Transaction,
    signed_tx: Signed<TxEip1559>,
    rx: TransactionReceipt,
) -> Vec<DynSolValue> {
    // Encoding transaction in 3 chunks
    let chunk_1 = encode_common_fields(&tx);

    let chunk_2 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(signed_tx.tx().chain_id), 64),
        DynSolValue::Uint(U256::from(signed_tx.tx().max_priority_fee_per_gas), 128),
        DynSolValue::Uint(U256::from(tx.max_fee_per_gas()), 128),
        encode_access_list(&signed_tx.tx().access_list),
        DynSolValue::Uint(U256::from(compute_y_parity(signed_tx.signature())), 8), // y parity
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().r()), 32),        // r
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().s()), 32),        // s
    ]);

    let chunk_3 = encode_receipt_fields(rx);

    vec![chunk_1, chunk_2, chunk_3]
}

fn encode_transaction_type_3(
    tx: Transaction,
    signed_tx: Signed<TxEip4844Variant>,
    rx: TransactionReceipt,
) -> Vec<DynSolValue> {
    let access_list = match tx.access_list() {
        Some(access_list) => encode_access_list(access_list),
        None => encode_access_list(&[]),
    };

    let (
        chain_id,
        max_priority_fee_per_gas,
        max_fee_per_gas,
        max_fee_per_blob_gas,
        blob_version_hashes,
    ) = match signed_tx.tx() {
        TxEip4844Variant::TxEip4844(tx_ref) => (
            tx_ref.chain_id,
            tx_ref.max_priority_fee_per_gas,
            tx_ref.max_fee_per_gas,
            tx_ref.max_fee_per_blob_gas,
            &tx_ref.blob_versioned_hashes,
        ),
        TxEip4844Variant::TxEip4844WithSidecar(tx_ref) => (
            tx_ref.tx.chain_id,
            tx_ref.tx.max_priority_fee_per_gas,
            tx_ref.tx.max_fee_per_gas,
            tx_ref.tx.max_fee_per_blob_gas,
            &tx_ref.tx.blob_versioned_hashes,
        ),
    };
    let blob_hashes = encode_blob_hashes(blob_version_hashes);

    // Encoding transaction in 4 chunks
    let chunk_1 = encode_common_fields(&tx);

    let chunk_2 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(chain_id), 64),
        DynSolValue::Uint(U256::from(max_priority_fee_per_gas), 128),
        DynSolValue::Uint(U256::from(max_fee_per_gas), 128),
        access_list,
    ]);

    let chunk_3 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(max_fee_per_blob_gas), 128),
        blob_hashes,
        DynSolValue::Uint(U256::from(compute_y_parity(signed_tx.signature())), 8),
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().r()), 32),
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().s()), 32),
    ]);

    let chunk_4 = encode_receipt_fields(rx);

    vec![chunk_1, chunk_2, chunk_3, chunk_4]
}

fn encode_transaction_type_4(
    tx: Transaction,
    signed_tx: Signed<TxEip7702>,
    rx: TransactionReceipt,
) -> Vec<DynSolValue> {
    // Encoding transaction in 4 chunks
    let chunk_1 = encode_common_fields(&tx);

    let chunk_2 = DynSolValue::Tuple(vec![
        DynSolValue::Uint(U256::from(signed_tx.tx().chain_id), 64),
        DynSolValue::Uint(U256::from(signed_tx.tx().max_priority_fee_per_gas), 128),
        DynSolValue::Uint(U256::from(signed_tx.tx().max_fee_per_gas), 128),
        encode_access_list(&signed_tx.tx().access_list),
    ]);

    let chunk_3 = DynSolValue::Tuple(vec![
        encode_authorization_list(&signed_tx.tx().authorization_list),
        DynSolValue::Uint(U256::from(compute_y_parity(signed_tx.signature())), 8),
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().r()), 32),
        DynSolValue::FixedBytes(B256::from(signed_tx.signature().s()), 32),
    ]);

    let chunk_4 = encode_receipt_fields(rx);

    vec![chunk_1, chunk_2, chunk_3, chunk_4]
}

fn encode_transaction_with_receipt(
    tx: Transaction,
    rx: TransactionReceipt,
) -> Option<(DynSolValue, Vec<DynSolValue>)> {
    let (type_id, chunks) = match tx.inner.clone() {
        TxEnvelope::Legacy(signed_tx) => (
            DynSolValue::Uint(U256::from(0), 8),
            encode_transaction_type_0(tx, signed_tx, rx),
        ),
        TxEnvelope::Eip2930(signed_tx) => (
            DynSolValue::Uint(U256::from(1), 8),
            encode_transaction_type_1(tx, signed_tx, rx),
        ),
        TxEnvelope::Eip1559(signed_tx) => (
            DynSolValue::Uint(U256::from(2), 8),
            encode_transaction_type_2(tx, signed_tx, rx),
        ),
        TxEnvelope::Eip4844(signed_tx) => (
            DynSolValue::Uint(U256::from(3), 8),
            encode_transaction_type_3(tx, signed_tx, rx),
        ),
        TxEnvelope::Eip7702(signed_tx) => (
            DynSolValue::Uint(U256::from(4), 8),
            encode_transaction_type_4(tx, signed_tx, rx),
        ),
    };

    // If for some reason we fail to encode any chunk, we return None
    let encoded_chunks = chunks
        .into_iter()
        .map(|c| c.abi_encode_sequence().map(DynSolValue::Bytes))
        .collect::<Option<Vec<_>>>()?;

    Some((type_id, encoded_chunks))
}

fn encode_authorization_list(signed_authorizations: &[SignedAuthorization]) -> DynSolValue {
    let mut result = Vec::with_capacity(signed_authorizations.len());
    for signed_authorization in signed_authorizations {
        let signed_authorization_tuple = DynSolValue::Tuple(vec![
            DynSolValue::Uint(U256::from(*signed_authorization.chain_id()), 256),
            DynSolValue::Address(*signed_authorization.address()),
            DynSolValue::Uint(U256::from(signed_authorization.nonce()), 64),
            DynSolValue::Uint(U256::from(signed_authorization.y_parity()), 8),
            DynSolValue::Uint(U256::from(signed_authorization.r()), 256),
            DynSolValue::Uint(U256::from(signed_authorization.s()), 256),
        ]);

        result.push(signed_authorization_tuple);
    }

    DynSolValue::Array(result)
}

fn encode_access_list(access_list: &[AccessListItem]) -> DynSolValue {
    let mut list = Vec::with_capacity(access_list.len());
    for access_list_item in access_list {
        let mut storage_keys = Vec::with_capacity(access_list_item.storage_keys.len());
        for storage_item in &access_list_item.storage_keys {
            storage_keys.push(DynSolValue::FixedBytes(*storage_item, 32));
        }

        // Create the `DynSolValue::Tuple` (address, storage_keys)
        let access_list_tuple = DynSolValue::Tuple(vec![
            DynSolValue::Address(access_list_item.address), // Address
            DynSolValue::Array(storage_keys),
        ]);

        list.push(access_list_tuple);
    }

    DynSolValue::Array(list)
}

pub(super) fn abi_encode(tx: Transaction, rx: TransactionReceipt) -> Option<AbiEncodeResult> {
    if let Some((type_id, encoded_chunks)) = encode_transaction_with_receipt(tx, rx) {
        let tuple = DynSolValue::Tuple(vec![type_id, DynSolValue::Array(encoded_chunks.clone())]);
        let final_bytes = tuple.abi_encode_sequence()?;

        Some(AbiEncodeResult::new(final_bytes, EncodingVersion::V1))
    } else {
        None
    }
}

// These tests are used to ensure that the encoding abi is stable and does not change unexpectedly.
#[cfg(test)]
mod test {
    use super::*;

    use serde_json::json;

    #[test]
    fn type_0_transaction_integrity() {
        let transaction = json!({
            "type": "0x0",
            "nonce": "0x43eb",
            "gasPrice": "0xdf8475800",
            "gas": "0xc350",
            "to": "0xdf190dc7190dfba737d7777a163445b7fff16133",
            "value": "0x6113a84987be800",
            "input": "0x",
            "r": "0x3b08715b4403c792b8c7567edea634088bedcd7f60d9352b1f16c69830f3afd5",
            "s": "0x10b9afb67d2ec8b956f0e1dbc07eb79152904f3a7bf789fc869db56320adfe09",
            "v": "0x1c",
            "hash": "0xe9e91f1ee4b56c0df2e9f06c2b8c27c6076195a88a7b8537ba8313d80e6f124e",
            "blockHash": "0x8e38b4dbf6b11fcc3b9dee84fb7986e29ca0a02cecd8977c161ff7333329681e",
            "blockNumber": "0xf4240",
            "transactionIndex": "0x1",
            "from": "0x32be343b94f860124dc4fee278fdcbd38c102d88"
        });
        let receipt = json!({
            "blockHash": "0x8e38b4dbf6b11fcc3b9dee84fb7986e29ca0a02cecd8977c161ff7333329681e",
            "blockNumber": "0xf4240",
            "contractAddress": null,
            "cumulativeGasUsed": "0xc444",
            "effectiveGasPrice": "0xdf8475800",
            "from": "0x32be343b94f860124dc4fee278fdcbd38c102d88",
            "gasUsed": "0x5208",
            "logs": [],
            "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "root": "0xfa28ef92787192b577a8628e520b546ab58b72102572e08191ddecd51d0851e5",
            "to": "0xdf190dc7190dfba737d7777a163445b7fff16133",
            "transactionHash": "0xe9e91f1ee4b56c0df2e9f06c2b8c27c6076195a88a7b8537ba8313d80e6f124e",
            "transactionIndex": "0x1",
            "type": "0x0"
        });
        let transaction: Transaction =
            serde_json::from_value(transaction).expect("valid transaction");
        let receipt: TransactionReceipt = serde_json::from_value(receipt).expect("valid receipt");

        let result = abi_encode(transaction, receipt).expect("encoding should succeed");

        let abi = format!("0x{}", hex::encode(result.abi()));
        let expected_abi = String::from("0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000220000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000043eb000000000000000000000000000000000000000000000000000000000000c35000000000000000000000000032be343b94f860124dc4fee278fdcbd38c102d880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000df190dc7190dfba737d7777a163445b7fff1613300000000000000000000000000000000000000000000000006113a84987be80000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000df8475800000000000000000000000000000000000000000000000000000000000000001c3b08715b4403c792b8c7567edea634088bedcd7f60d9352b1f16c69830f3afd510b9afb67d2ec8b956f0e1dbc07eb79152904f3a7bf789fc869db56320adfe0900000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000005208000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");

        assert_eq!(abi, expected_abi);
    }

    #[test]
    fn type_1_transaction_integrity() {
        let transaction = json!({
            "type": "0x1",
            "chainId": "0x1",
            "nonce": "0x3",
            "gasPrice": "0x4bbe66a6b",
            "gas": "0x2dc6c0",
            "to": "0xac1d3d7a8878e655cbb063d58e453540641f4117",
            "value": "0x0",
            "accessList": [],
            "input": "0xc9567bf9",
            "r": "0xe8b501902f80aa4e595c33b0ea633ff42f05fbaafaa81bce322dc12ed63aadc",
            "s": "0x461898ba0f164b032f98a06f4a3fb8f3d7fc5e738ce2925c62c91c450f476d2e",
            "yParity": "0x1",
            "v": "0x1",
            "hash": "0xf725a062432b1e0405abcf69de62d0d2cbf2a15a17f56b77b8444e5aabf3e3de",
            "blockHash": "0xc6b6d85da551576ef3408cff2304d33162fd6260f34e83cdc42dcec4a70687ff",
            "blockNumber": "0x142723b",
            "transactionIndex": "0x0",
            "from": "0x1f1e9426d6b7d100746b09956ad90a0796e19aa3"
        });
        let receipt = json!({
            "blockHash": "0xc6b6d85da551576ef3408cff2304d33162fd6260f34e83cdc42dcec4a70687ff",
            "blockNumber": "0x142723b",
            "contractAddress": null,
            "cumulativeGasUsed": "0x7f9b",
            "effectiveGasPrice": "0x4bbe66a6b",
            "from": "0x1f1e9426d6b7d100746b09956ad90a0796e19aa3",
            "gasUsed": "0x7f9b",
            "logs": [
                {
                "address": "0xac1d3d7a8878e655cbb063d58e453540641f4117",
                "topics": [
                    "0xb3da2db3dfc3778f99852546c6e9ab39ec253f9de7b0847afec61bd27878e923",
                    "0x00000000000000000000000000000000000000000000000000000000672bf8d3"
                ],
                "data": "0x",
                "blockNumber": "0x142723b",
                "transactionHash": "0xf725a062432b1e0405abcf69de62d0d2cbf2a15a17f56b77b8444e5aabf3e3de",
                "transactionIndex": "0x0",
                "blockHash": "0xc6b6d85da551576ef3408cff2304d33162fd6260f34e83cdc42dcec4a70687ff",
                "logIndex": "0x0",
                "removed": false
                }
            ],
            "logsBloom": "0xc0000000000000000000000000000000000000080000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000010000000000000000080000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000",
            "status": "0x1",
            "to": "0xac1d3d7a8878e655cbb063d58e453540641f4117",
            "transactionHash": "0xf725a062432b1e0405abcf69de62d0d2cbf2a15a17f56b77b8444e5aabf3e3de",
            "transactionIndex": "0x0",
            "type": "0x1"
        });
        let transaction: Transaction =
            serde_json::from_value(transaction).expect("valid transaction");
        let receipt: TransactionReceipt = serde_json::from_value(receipt).expect("valid receipt");

        let result = abi_encode(transaction, receipt).expect("encoding should succeed");

        let abi = format!("0x{}", hex::encode(result.abi()));
        let expected_abi = String::from("0x000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000002dc6c00000000000000000000000001f1e9426d6b7d100746b09956ad90a0796e19aa30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ac1d3d7a8878e655cbb063d58e453540641f4117000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000004c9567bf90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000004bbe66a6b00000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010e8b501902f80aa4e595c33b0ea633ff42f05fbaafaa81bce322dc12ed63aadc461898ba0f164b032f98a06f4a3fb8f3d7fc5e738ce2925c62c91c450f476d2e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000007f9b000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000ac1d3d7a8878e655cbb063d58e453540641f4117000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002b3da2db3dfc3778f99852546c6e9ab39ec253f9de7b0847afec61bd27878e92300000000000000000000000000000000000000000000000000000000672bf8d300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100c0000000000000000000000000000000000000080000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000010000000000000000080000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000");

        assert_eq!(abi, expected_abi);
    }

    #[test]
    fn type_2_transaction_integrity() {
        let transaction = json!({
            "blockHash": "0xf11da6e3bbcea68e3240e095c385a9782ae19fe2420ca69fd297ecbefb2760aa",
            "blockNumber": "0x168d87f",
            "from": "0xdadb0d80178819f2319190d340ce9a924f783711",
            "gas": "0x6af2",
            "gasPrice": "0x179e331a",
            "maxFeePerGas": "0x179e331a",
            "maxPriorityFeePerGas": "0x0",
            "hash": "0xd4be304337067e55c08bcffde2f2825da04da33535f119b422441990cd31bd97",
            "input": "0x",
            "nonce": "0x1914bc",
            "to": "0x73f7b1184b5cd361cc0f7654998953e2a251dd58",
            "transactionIndex": "0xec",
            "value": "0x78b3da703b6a70",
            "type": "0x2",
            "accessList": [],
            "chainId": "0x1",
            "v": "0x1",
            "r": "0x6de9aa950d074830a2339250e6b353d0a8afc886aa3e1649cd0080435a9ac9a4",
            "s": "0x6fb1de15d8511a73808ea299b37ffc66802b142405465937d6b76c36b142d880",
            "yParity": "0x1"
        });
        let receipt = json!({
            "blockHash": "0xf11da6e3bbcea68e3240e095c385a9782ae19fe2420ca69fd297ecbefb2760aa",
            "blockNumber": "0x168d87f",
            "contractAddress": null,
            "cumulativeGasUsed": "0x12668ef",
            "effectiveGasPrice": "0x179e331a",
            "from": "0xdadb0d80178819f2319190d340ce9a924f783711",
            "gasUsed": "0x6af2",
            "logs": [
                {
                "address": "0x73f7b1184b5cd361cc0f7654998953e2a251dd58",
                "topics": [
                    "0x85177f287940f2f05425a4029951af0e047a7f9c4eaa9a6e6917bcd869f86695",
                    "0x000000000000000000000000dadb0d80178819f2319190d340ce9a924f783711"
                ],
                "data": "0x0000000000000000000000000000000000000000000000000078b3da703b6a70",
                "blockNumber": "0x168d87f",
                "transactionHash": "0xd4be304337067e55c08bcffde2f2825da04da33535f119b422441990cd31bd97",
                "transactionIndex": "0xec",
                "blockHash": "0xf11da6e3bbcea68e3240e095c385a9782ae19fe2420ca69fd297ecbefb2760aa",
                "logIndex": "0x1e1",
                "removed": false
                }
            ],
            "logsBloom": "0x00000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000080000000000000001000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000080000000002000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
            "status": "0x1",
            "to": "0x73f7b1184b5cd361cc0f7654998953e2a251dd58",
            "transactionHash": "0xd4be304337067e55c08bcffde2f2825da04da33535f119b422441990cd31bd97",
            "transactionIndex": "0xec",
            "type": "0x2"
        });
        let transaction: Transaction =
            serde_json::from_value(transaction).expect("valid transaction");
        let receipt: TransactionReceipt = serde_json::from_value(receipt).expect("valid receipt");

        let result = abi_encode(transaction, receipt).expect("encoding should succeed");

        let abi = format!("0x{}", hex::encode(result.abi()));
        let expected_abi = String::from("0x0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000001914bc0000000000000000000000000000000000000000000000000000000000006af2000000000000000000000000dadb0d80178819f2319190d340ce9a924f783711000000000000000000000000000000000000000000000000000000000000000000000000000000000000000073f7b1184b5cd361cc0f7654998953e2a251dd580000000000000000000000000000000000000000000000000078b3da703b6a7000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000179e331a00000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000016de9aa950d074830a2339250e6b353d0a8afc886aa3e1649cd0080435a9ac9a46fb1de15d8511a73808ea299b37ffc66802b142405465937d6b76c36b142d880000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000006af2000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000073f7b1184b5cd361cc0f7654998953e2a251dd58000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000285177f287940f2f05425a4029951af0e047a7f9c4eaa9a6e6917bcd869f86695000000000000000000000000dadb0d80178819f2319190d340ce9a924f78371100000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000078b3da703b6a70000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000080000000000000001000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000080000000002000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");

        assert_eq!(abi, expected_abi);
    }

    #[test]
    fn type_3_transaction_integrity() {
        let transaction = json!({
            "type": "0x3",
            "chainId": "0x1",
            "nonce": "0x837e4",
            "gas": "0x36a2b",
            "maxFeePerGas": "0x213f9eed72",
            "maxPriorityFeePerGas": "0x3b9aca00",
            "to": "0x1c479675ad559dc151f6ec7ed3fbf8cee79582b6",
            "value": "0x0",
            "accessList": [
                {
                    "address": "0x1c479675ad559dc151f6ec7ed3fbf8cee79582b6",
                    "storageKeys": [
                        "0x0000000000000000000000000000000000000000000000000000000000000000",
                        "0x0000000000000000000000000000000000000000000000000000000000000001",
                        "0x000000000000000000000000000000000000000000000000000000000000000a",
                        "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103",
                        "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
                        "0xa10aa54071443520884ed767b0684edf43acec528b7da83ab38ce60126562660"
                    ]
                },
                {
                    "address": "0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a",
                    "storageKeys": [
                        "0x0000000000000000000000000000000000000000000000000000000000000006",
                        "0x0000000000000000000000000000000000000000000000000000000000000007",
                        "0x0000000000000000000000000000000000000000000000000000000000000009",
                        "0x000000000000000000000000000000000000000000000000000000000000000a",
                        "0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103",
                        "0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
                        "0xa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873fc679",
                        "0xa66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873fc67a",
                        "0xf652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f3792b181"
                    ]
                },
                {
                    "address": "0xe64a54e2533fd126c2e452c5fab544d80e2e4eb5",
                    "storageKeys": [
                        "0x0000000000000000000000000000000000000000000000000000000000000004",
                        "0x0000000000000000000000000000000000000000000000000000000000000005",
                        "0xe85fd79f89ff278fc57d40aecb7947873df9f0beac531c8f71a98f630e1eab62",
                        "0x7686888b19bb7b75e46bb1aa328b65150743f4899443d722f0adf8e252ccda41"
                    ]
                }
            ],
            "blobVersionedHashes": [
                "0x014527d555d949b3afcfa246e16eb0e0aef9e9da60b7a0266f1da43b3fd8e8cf",
                "0x016d80efa350ab1fc156b505ab619bee3f6245b8f7d4d60bf11c9d8b0105b02f",
                "0x0176b14180ebfaa132142ff163eb2aaf2985af7da011d195e39fe8b0faf1e960",
                "0x0134da09304a6a66b691bc48d351b976203cd419778d142f19e68e904f07a5ae",
                "0x0181b4581a9fc316eadc58e4d6d362e316e259643913339a3e46b7c9d742ac30",
                "0x0112fa6c9dfaceaff1868ef19d01c4a1da99e6e02162fe7dacf94ec441da6977"
            ],
            "maxFeePerBlobGas": "0xa",
            "input": "0x3e5aa082000000000000000000000000000000000000000000000000000000000008fff2000000000000000000000000000000000000000000000000000000000016a443000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000aafdc87000000000000000000000000000000000000000000000000000000000aafde27",
            "r": "0x4dfd139f20fdefc834fbdce2e120ca8ed1a4688d8843df8fc2de1df8c6d0a0f3",
            "s": "0x6ec282ea1c2c55e467425c380c17f0f8ef664d8e2de8a39b18d6c83b8d6a9afa",
            "yParity": "0x1",
            "v": "0x1",
            "hash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
            "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
            "blockNumber": "0x12c135c",
            "transactionIndex": "0x53",
            "from": "0xc1b634853cb333d3ad8663715b08f41a3aec47cc",
            "gasPrice": "0x38367e339"
        });
        let receipt = json!({
            "blobGasPrice": "0x1",
            "blobGasUsed": "0xc0000",
            "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
            "blockNumber": "0x12c135c",
            "contractAddress": null,
            "cumulativeGasUsed": "0x765f8c",
            "effectiveGasPrice": "0x38367e339",
            "from": "0xc1b634853cb333d3ad8663715b08f41a3aec47cc",
            "gasUsed": "0x29d5f",
            "logs": [
                {
                "address": "0x1c479675ad559dc151f6ec7ed3fbf8cee79582b6",
                "topics": [
                    "0x7394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7",
                    "0x000000000000000000000000000000000000000000000000000000000008fff2",
                    "0x10a6a070fc96f51a7f92541aa7fd47cb481cade711489bc1d37fb42273929f95",
                    "0xb4c9f1185b38503ab4b0fcd2f4aff24d39475e5f1df61bb58aa48e7f6d09f709"
                ],
                "data": "0x8d4eaf080d90bc8d1c6bf254f597300e3a04cbc0b17f6f0cc8cb5edd74eefa1b000000000000000000000000000000000000000000000000000000000016a44300000000000000000000000000000000000000000000000000000000661cb14f00000000000000000000000000000000000000000000000000000000661e05cf00000000000000000000000000000000000000000000000000000000012bfcdc00000000000000000000000000000000000000000000000000000000012c139c0000000000000000000000000000000000000000000000000000000000000003",
                "blockNumber": "0x12c135c",
                "transactionHash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
                "transactionIndex": "0x53",
                "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
                "logIndex": "0xc9",
                "removed": false
                },
                {
                "address": "0x8315177ab297ba92a06054ce80a67ed4dbd7ed3a",
                "topics": [
                    "0x5e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1",
                    "0x000000000000000000000000000000000000000000000000000000000016a449",
                    "0x7a9be4783a8a7f47297c0edaea411e7bb2e21f7c6b4a83826c5467e1b095ae6a"
                ],
                "data": "0x0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47ccdb32956884f3752604ba67b6ba9ec6827e03e2cfa750f14de667e291564ccc610000000000000000000000000000000000000000000000000000000347cd193900000000000000000000000000000000000000000000000000000000661e02cf",
                "blockNumber": "0x12c135c",
                "transactionHash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
                "transactionIndex": "0x53",
                "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
                "logIndex": "0xca",
                "removed": false
                },
                {
                "address": "0x1c479675ad559dc151f6ec7ed3fbf8cee79582b6",
                "topics": [
                    "0xff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b",
                    "0x000000000000000000000000000000000000000000000000000000000016a449"
                ],
                "data": "0x0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000661e02cfc1b634853cb333d3ad8663715b08f41a3aec47cc0160b2ad9e7e658fe60b7898ce1f34ed816ad9ebfd9f19b085e84af59c974ee8000000000000000000000000000000000000000000000000000000000008fff20000000000000000000000000000000000000000000000000000000347cd1939000000000000000000000000",
                "blockNumber": "0x12c135c",
                "transactionHash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
                "transactionIndex": "0x53",
                "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
                "logIndex": "0xcb",
                "removed": false
                },
                {
                "address": "0xe64a54e2533fd126c2e452c5fab544d80e2e4eb5",
                "topics": [
                    "0xd0224505f828ccfcbc56ca0590d97442e239a7aa770f712948fd6388356b20de",
                    "0x000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc",
                    "0x0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6",
                    "0x0000000000000000000000000000000000000000000000000000000000000001"
                ],
                "data": "0x0000000000000000000000000000000000000000000000000000000000034710000000000000000000000000000000000000000000000000000000038367e33900000000000000000000000000000000000000000000000000097f51a8b059e2",
                "blockNumber": "0x12c135c",
                "transactionHash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
                "transactionIndex": "0x53",
                "blockHash": "0x885dbb7ca37d235e2a211e04668cd382f54872292e2adf50d61d65785fa2b713",
                "logIndex": "0xcc",
                "removed": false
                }
            ],
            "logsBloom": "0x0400000008000000000000000000000040000080000000000000000040000000000000000000000000000000000000000100000012100000100000001004000000001000000000000000080000000000000000000004001000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000100000000000400000000000000080000002000000000000000001000002006000100400008000000000000000000000000000000000000000000000000000000400000000018400100008004000000000000000800000000000000000000000000000208000000021000000c040",
            "status": "0x1",
            "to": "0x1c479675ad559dc151f6ec7ed3fbf8cee79582b6",
            "transactionHash": "0x2ea19986a6866b6efd2ac292fa8132b0bbf1fcc478560525ce43d6c300323652",
            "transactionIndex": "0x53",
            "type": "0x3"
        });
        let transaction: Transaction =
            serde_json::from_value(transaction).expect("valid transaction");
        let receipt: TransactionReceipt = serde_json::from_value(receipt).expect("valid receipt");

        let result = abi_encode(transaction, receipt).expect("encoding should succeed");

        let abi = format!("0x{}", hex::encode(result.abi()));
        let expected_abi = String::from("0x00000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000260000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000008a000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000837e40000000000000000000000000000000000000000000000000000000000036a2b000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000a43e5aa082000000000000000000000000000000000000000000000000000000000008fff2000000000000000000000000000000000000000000000000000000000016a443000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000aafdc87000000000000000000000000000000000000000000000000000000000aafde270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004800000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000003b9aca00000000000000000000000000000000000000000000000000000000213f9eed72000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000003000000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b60000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca10aa54071443520884ed767b0684edf43acec528b7da83ab38ce601265626600000000000000000000000008315177ab297ba92a06054ce80a67ed4dbd7ed3a00000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009000000000000000000000000000000000000000000000000000000000000000ab53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbca66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873fc679a66cc928b5edb82af9bd49922954155ab7b0942694bea4ce44661d9a873fc67af652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f3792b181000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb50000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000005e85fd79f89ff278fc57d40aecb7947873df9f0beac531c8f71a98f630e1eab627686888b19bb7b75e46bb1aa328b65150743f4899443d722f0adf8e252ccda410000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000014dfd139f20fdefc834fbdce2e120ca8ed1a4688d8843df8fc2de1df8c6d0a0f36ec282ea1c2c55e467425c380c17f0f8ef664d8e2de8a39b18d6c83b8d6a9afa0000000000000000000000000000000000000000000000000000000000000006014527d555d949b3afcfa246e16eb0e0aef9e9da60b7a0266f1da43b3fd8e8cf016d80efa350ab1fc156b505ab619bee3f6245b8f7d4d60bf11c9d8b0105b02f0176b14180ebfaa132142ff163eb2aaf2985af7da011d195e39fe8b0faf1e9600134da09304a6a66b691bc48d351b976203cd419778d142f19e68e904f07a5ae0181b4581a9fc316eadc58e4d6d362e316e259643913339a3e46b7c9d742ac300112fa6c9dfaceaff1868ef19d01c4a1da99e6e02162fe7dacf94ec441da6977000000000000000000000000000000000000000000000000000000000000094000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000029d5f00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000820000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000006000000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b60000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000047394f4a19a13c7b92b5bb71033245305946ef78452f7b4986ac1390b5df4ebd7000000000000000000000000000000000000000000000000000000000008fff210a6a070fc96f51a7f92541aa7fd47cb481cade711489bc1d37fb42273929f95b4c9f1185b38503ab4b0fcd2f4aff24d39475e5f1df61bb58aa48e7f6d09f70900000000000000000000000000000000000000000000000000000000000000e08d4eaf080d90bc8d1c6bf254f597300e3a04cbc0b17f6f0cc8cb5edd74eefa1b000000000000000000000000000000000000000000000000000000000016a44300000000000000000000000000000000000000000000000000000000661cb14f00000000000000000000000000000000000000000000000000000000661e05cf00000000000000000000000000000000000000000000000000000000012bfcdc00000000000000000000000000000000000000000000000000000000012c139c00000000000000000000000000000000000000000000000000000000000000030000000000000000000000008315177ab297ba92a06054ce80a67ed4dbd7ed3a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000000035e3c1311ea442664e8b1611bfabef659120ea7a0a2cfc0667700bebc69cbffe1000000000000000000000000000000000000000000000000000000000016a4497a9be4783a8a7f47297c0edaea411e7bb2e21f7c6b4a83826c5467e1b095ae6a00000000000000000000000000000000000000000000000000000000000000c00000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6000000000000000000000000000000000000000000000000000000000000000d000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47ccdb32956884f3752604ba67b6ba9ec6827e03e2cfa750f14de667e291564ccc610000000000000000000000000000000000000000000000000000000347cd193900000000000000000000000000000000000000000000000000000000661e02cf0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000002ff64905f73a67fb594e0f940a8075a860db489ad991e032f48c81123eb52d60b000000000000000000000000000000000000000000000000000000000016a44900000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000009c00000000000000000000000000000000000000000000000000000000661e02cfc1b634853cb333d3ad8663715b08f41a3aec47cc0160b2ad9e7e658fe60b7898ce1f34ed816ad9ebfd9f19b085e84af59c974ee8000000000000000000000000000000000000000000000000000000000008fff20000000000000000000000000000000000000000000000000000000347cd1939000000000000000000000000000000000000000000000000e64a54e2533fd126c2e452c5fab544d80e2e4eb5000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000004d0224505f828ccfcbc56ca0590d97442e239a7aa770f712948fd6388356b20de000000000000000000000000c1b634853cb333d3ad8663715b08f41a3aec47cc0000000000000000000000001c479675ad559dc151f6ec7ed3fbf8cee79582b6000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000034710000000000000000000000000000000000000000000000000000000038367e33900000000000000000000000000000000000000000000000000097f51a8b059e200000000000000000000000000000000000000000000000000000000000001000400000008000000000000000000000040000080000000000000000040000000000000000000000000000000000000000100000012100000100000001004000000001000000000000000080000000000000000000004001000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000000002000000000000000000100000000000400000000000000080000002000000000000000001000002006000100400008000000000000000000000000000000000000000000000000000000400000000018400100008004000000000000000800000000000000000000000000000208000000021000000c040");

        assert_eq!(abi, expected_abi);
    }

    #[test]
    fn type_4_transaction_integrity() {
        let transaction = json!({
            "type": "0x4",
            "chainId": "0x1",
            "nonce": "0xddf",
            "gas": "0x142aec",
            "maxFeePerGas": "0xb8511c2",
            "maxPriorityFeePerGas": "0x2faf080",
            "to": "0x0000000071727de22e5e9d8baf0edac6f37da032",
            "value": "0x0",
            "accessList": [],
            "authorizationList": [
                {
                    "chainId": "0x1",
                    "address": "0xd2e28229f6f2c235e57de2ebc727025a1d0530fb",
                    "nonce": "0x52",
                    "yParity": "0x1",
                    "r": "0xdbee6cb8128fe31de9c9a2dd20e4fe4a70f20ee64428a3c09d9a9d25a0c6e1c7",
                    "s": "0x7314d0c97d81179a461f2e236510026953553155935ede0fba3645567fb175d8"
                }
            ],
            "input": "0x765e827f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000048c16a1dc402a1e463474f40202497beb9a11deb000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000124f800000000000000000000000000077c60000000000000000000000000000000000000000000000000000000000001b544000000000000000000000000039387000000000000000000000000000e0d0a290000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000088426da7d880000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000007d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac00000000000000000000000000000000000000000000000000000000000dea59000000000000000000000000000000000000000000000000000000000000000000000000000000003c11f6265ddec22f4d049dde480615735f451646000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000684049639fb0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000000000000000000000000000000000000112dcac000000000000000000000000000000000000000000000000000f5b0557048d4000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000058812aa3caf0000000000000000000000005141b82f5ffda4c6fe1e372978f1c5427640a190000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005141b82f5ffda4c6fe1e372978f1c5427640a190000000000000000000000000a7ca2c8673bcfa5a26d8ceec2887f2cc2b0db22a000000000000000000000000000000000000000000000000000000000112dcac000000000000000000000000000000000000000000000000000f5b0557048d40000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ee0000000000000000000000000000000000000000000000000000000003d05120111111125421ca6dc452d289314280a0f8842a65dac17f958d2ee523a2206206994597c13d831ec7012456a75868f1fa3d165d765dca08fc1df1889d6b89d53ac5bf210c7d50612c24bc68ca5b5100000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f00000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f0000000000000000000000008b543dff08ed4ba13ee96f533638ef54591aee71000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000f8f1862c313dd000000000000000000000000000000000000000000000000000000000112dcac02000000000000000000000000c74bb8020068ef4829372978f1c5427640a19000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000280001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041ee1566ef57bc0730d826a0d8009c9f76e16d9208ab35045bc6527775ee37a2c679a9c7fff265764ed3be9b1b16d4cf83a85686c13f7539f7f170be22d24969961c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001741111111254eeb25477b68fb85ed929f73a9605820000014000000140000001400000014000000140000001400000014000000140000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000f8f1862c313dd00000000000000000000000000000000000000000000000000000000c74bb8020000000000000000000000000000000000000000000000000000000068ef48296c68df299ed9d19722811dfcb0a18a058845e20f88bc98d5156c6f700b7ebad90000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000004174ddf31a490ba2d579b6e8a91d2683a889f344702e90843f0121ef0a65f52d11684755d830c2fddcf5afbfbd46e1b793cccaca2321a94b0abc1c3ca9b22729c31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4e3736f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b57d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac000000000000000000000000000061a800000000000000000000000000005daa000068ef493a000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000089ba50f051a985ce8f84587f99cbbd0d951ff1186d097109771073b3a260a7c8ef2790227c8dd9fd61ad61f863ede2bc7b5e809b253b9949509f92274d961760dd6101c000000000000000000000000000000000000000000000000000000000000000000000000000000000000417080bcb677d9195f0a53a1c89bd0c5bac797bd96445315c3675382b956b0a1ee246b351f3493e0a16a0468437ff491adb01e2c3a28f88fe47df36b78c71ff20f1c00000000000000000000000000000000000000000000000000000000000000",
            "r": "0x60bf6ed8d222cd3422d7331c1684e7a6827c40f6e68a21a7d69fd87bd2dce6b6",
            "s": "0x6be34d4773afde685b19086963e06af351da89c0796f4f14acdc941b547ad9e4",
            "yParity": "0x1",
            "v": "0x1",
            "hash": "0x32a7f4b178110a2f0f2ff1d611b081b5659f34546b647714d0d76adea3c32da0",
            "blockHash": "0x63029255b1ffdf8eeb04a60c482a20f2294fc3d7ac4d4138817fe0c7bcfc1a72",
            "blockNumber": "0x167d337",
            "transactionIndex": "0xe1",
            "from": "0x48c16a1dc402a1e463474f40202497beb9a11deb",
            "gasPrice": "0x92efa54"
        });
        let receipt = json!({
            "blockHash": "0x63029255b1ffdf8eeb04a60c482a20f2294fc3d7ac4d4138817fe0c7bcfc1a72",
            "blockNumber": "0x167d337",
            "contractAddress": null,
            "cumulativeGasUsed": "0x12d059d",
            "effectiveGasPrice": "0x92efa54",
            "from": "0x48c16a1dc402a1e463474f40202497beb9a11deb",
            "gasUsed": "0x62a37",
            "logs": [
                {
                "address": "0x0000000071727de22e5e9d8baf0edac6f37da032",
                "topics": [
                    "0xbb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f972"
                ],
                "data": "0x",
                "blockNumber": "0x167d337",
                "transactionHash": "0x32a7f4b178110a2f0f2ff1d611b081b5659f34546b647714d0d76adea3c32da0",
                "transactionIndex": "0xe1",
                "blockHash": "0x63029255b1ffdf8eeb04a60c482a20f2294fc3d7ac4d4138817fe0c7bcfc1a72",
                "logIndex": "0x1ff",
                "removed": false
                },
                {
                "address": "0x0000000071727de22e5e9d8baf0edac6f37da032",
                "topics": [
                    "0xf62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f4792",
                    "0x24a2f504d977eb9364fb9ab406675744e37df5d939547f3f72604b46023b964c",
                    "0x0000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb"
                ],
                "data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064ad7954bc000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047939f4240000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
                "blockNumber": "0x167d337",
                "transactionHash": "0x32a7f4b178110a2f0f2ff1d611b081b5659f34546b647714d0d76adea3c32da0",
                "transactionIndex": "0xe1",
                "blockHash": "0x63029255b1ffdf8eeb04a60c482a20f2294fc3d7ac4d4138817fe0c7bcfc1a72",
                "logIndex": "0x200",
                "removed": false
                },
                {
                "address": "0x0000000071727de22e5e9d8baf0edac6f37da032",
                "topics": [
                    "0x49628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f",
                    "0x24a2f504d977eb9364fb9ab406675744e37df5d939547f3f72604b46023b964c",
                    "0x0000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb",
                    "0x0000000000000000000000007d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac"
                ],
                "data": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045ade7e680000000000000000000000000000000000000000000000000000000000000072000",
                "blockNumber": "0x167d337",
                "transactionHash": "0x32a7f4b178110a2f0f2ff1d611b081b5659f34546b647714d0d76adea3c32da0",
                "transactionIndex": "0xe1",
                "blockHash": "0x63029255b1ffdf8eeb04a60c482a20f2294fc3d7ac4d4138817fe0c7bcfc1a72",
                "logIndex": "0x201",
                "removed": false
                }
            ],
            "logsBloom": "0x00000100000000000000000000000000000000000000000000000000000000000008200000000000000000010000000100000000000000000000020000000000000000000000000000000000000000000040000000200000000000000000000000000000000800000000000000000000000000000000000000800000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000100002000000000000000000400000400001000000000000000000000400000000000000000000000000000000000000000000000000000000080000000800000000000000000080",
            "status": "0x1",
            "to": "0x0000000071727de22e5e9d8baf0edac6f37da032",
            "transactionHash": "0x32a7f4b178110a2f0f2ff1d611b081b5659f34546b647714d0d76adea3c32da0",
            "transactionIndex": "0xe1",
            "type": "0x4"
        });
        let transaction: Transaction =
            serde_json::from_value(transaction).expect("valid transaction");
        let receipt: TransactionReceipt = serde_json::from_value(receipt).expect("valid receipt");

        let result = abi_encode(transaction, receipt).expect("encoding should succeed");

        let abi = format!("0x{}", hex::encode(result.abi()));
        let expected_abi = String::from("0x00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000da00000000000000000000000000000000000000000000000000000000000000e600000000000000000000000000000000000000000000000000000000000000fe00000000000000000000000000000000000000000000000000000000000000d000000000000000000000000000000000000000000000000000000000000000ddf0000000000000000000000000000000000000000000000000000000000142aec00000000000000000000000048c16a1dc402a1e463474f40202497beb9a11deb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000be4765e827f000000000000000000000000000000000000000000000000000000000000004000000000000000000000000048c16a1dc402a1e463474f40202497beb9a11deb000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000124f800000000000000000000000000077c60000000000000000000000000000000000000000000000000000000000001b544000000000000000000000000039387000000000000000000000000000e0d0a290000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000ae00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000088426da7d880000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000120000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044095ea7b30000000000000000000000007d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac00000000000000000000000000000000000000000000000000000000000dea59000000000000000000000000000000000000000000000000000000000000000000000000000000003c11f6265ddec22f4d049dde480615735f451646000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000684049639fb0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee000000000000000000000000000000000000000000000000000000000112dcac000000000000000000000000000000000000000000000000000f5b0557048d4000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000058812aa3caf0000000000000000000000005141b82f5ffda4c6fe1e372978f1c5427640a190000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc20000000000000000000000005141b82f5ffda4c6fe1e372978f1c5427640a190000000000000000000000000a7ca2c8673bcfa5a26d8ceec2887f2cc2b0db22a000000000000000000000000000000000000000000000000000000000112dcac000000000000000000000000000000000000000000000000000f5b0557048d40000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003ee0000000000000000000000000000000000000000000000000000000003d05120111111125421ca6dc452d289314280a0f8842a65dac17f958d2ee523a2206206994597c13d831ec7012456a75868f1fa3d165d765dca08fc1df1889d6b89d53ac5bf210c7d50612c24bc68ca5b5100000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f00000000000000000000000051c72848c68a965f66fa7a88855f9f7784502a7f0000000000000000000000008b543dff08ed4ba13ee96f533638ef54591aee71000000000000000000000000dac17f958d2ee523a2206206994597c13d831ec7000000000000000000000000000000000000000000000000000f8f1862c313dd000000000000000000000000000000000000000000000000000000000112dcac02000000000000000000000000c74bb8020068ef4829372978f1c5427640a19000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000280001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000041ee1566ef57bc0730d826a0d8009c9f76e16d9208ab35045bc6527775ee37a2c679a9c7fff265764ed3be9b1b16d4cf83a85686c13f7539f7f170be22d24969961c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001741111111254eeb25477b68fb85ed929f73a9605820000014000000140000001400000014000000140000001400000014000000140000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2000000000000000000000000000000000000000000000000000f8f1862c313dd00000000000000000000000000000000000000000000000000000000c74bb8020000000000000000000000000000000000000000000000000000000068ef48296c68df299ed9d19722811dfcb0a18a058845e20f88bc98d5156c6f700b7ebad90000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000004174ddf31a490ba2d579b6e8a91d2683a889f344702e90843f0121ef0a65f52d11684755d830c2fddcf5afbfbd46e1b793cccaca2321a94b0abc1c3ca9b22729c31c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c4e3736f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b57d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac000000000000000000000000000061a800000000000000000000000000005daa000068ef493a000000000000dac17f958d2ee523a2206206994597c13d831ec70000000000000000000000000000000000000000000000000000000000089ba50f051a985ce8f84587f99cbbd0d951ff1186d097109771073b3a260a7c8ef2790227c8dd9fd61ad61f863ede2bc7b5e809b253b9949509f92274d961760dd6101c000000000000000000000000000000000000000000000000000000000000000000000000000000000000417080bcb677d9195f0a53a1c89bd0c5bac797bd96445315c3675382b956b0a1ee246b351f3493e0a16a0468437ff491adb01e2c3a28f88fe47df36b78c71ff20f1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000002faf080000000000000000000000000000000000000000000000000000000000b8511c20000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000160bf6ed8d222cd3422d7331c1684e7a6827c40f6e68a21a7d69fd87bd2dce6b66be34d4773afde685b19086963e06af351da89c0796f4f14acdc941b547ad9e400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000d2e28229f6f2c235e57de2ebc727025a1d0530fb00000000000000000000000000000000000000000000000000000000000000520000000000000000000000000000000000000000000000000000000000000001dbee6cb8128fe31de9c9a2dd20e4fe4a70f20ee64428a3c09d9a9d25a0c6e1c77314d0c97d81179a461f2e236510026953553155935ede0fba3645567fb175d8000000000000000000000000000000000000000000000000000000000000066000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000062a370000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000054000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000001bb47ee3e183a558b1a2ff0874b079f3fc5478b7454eacf2bfc5af2ff5878f97200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071727de22e5e9d8baf0edac6f37da032000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000003f62676f440ff169a3a9afdbf812e89e7f95975ee8e5c31214ffdef631c5f479224a2f504d977eb9364fb9ab406675744e37df5d939547f3f72604b46023b964c0000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000064ad7954bc000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000047939f42400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000071727de22e5e9d8baf0edac6f37da03200000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000449628fd1471006c1482da88028e9ce4dbb080b815c9b0344d39e5a8e6ec1419f24a2f504d977eb9364fb9ab406675744e37df5d939547f3f72604b46023b964c0000000000000000000000004cd27786173e00743114202f1455c54e3536cdfb0000000000000000000000007d3201fa7a85c0a5f9fa1c0c6b9d0b784368d2ac000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045ade7e680000000000000000000000000000000000000000000000000000000000000072000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000008200000000000000000010000000100000000000000000000020000000000000000000000000000000000000000000040000000200000000000000000000000000000000800000000000000000000000000000000000000800000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000100002000000000000000000400000400001000000000000000000000400000000000000000000000000000000000000000000000000000000080000000800000000000000000080");

        assert_eq!(abi, expected_abi);
    }
}