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
use crate::{utils::deserializer::deserialize_maybe_empty, TestAuthorization};
use cfx_rpc_primitives::Bytes;
use cfx_types::{Address, H256, U256, U64};
use primitives::transaction::AccessList;
use serde::Deserialize;

#[derive(Debug, PartialEq, Eq, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Transaction {
    #[serde(default, rename = "type")]
    pub tx_type: U64,
    pub chain_id: Option<U256>,
    pub nonce: U256,
    pub gas_price: Option<U256>,
    pub max_priority_fee_per_gas: Option<U256>,
    pub max_fee_per_gas: Option<U256>,
    pub gas_limit: U256,
    #[serde(default, deserialize_with = "deserialize_maybe_empty")]
    pub to: Option<Address>,
    pub value: U256,
    pub data: Bytes,
    pub v: U64,
    pub r: U256,
    pub s: U256,
    pub sender: Option<Address>,
    pub secret_key: Option<H256>,
    pub access_list: Option<AccessList>,
    pub max_fee_per_blob_gas: Option<U256>,
    pub blob_versioned_hashes: Option<Vec<H256>>,
    pub authorization_list: Option<Vec<TestAuthorization>>,
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn recover_basic() {
        let json_str = r#"{
            "type": "0x00",
            "chainId": "0x01",
            "nonce": "0x00",
            "gasPrice": "0x0a",
            "gasLimit": "0x07a120",
            "to": "0x0000000000000000000000000000000000001000",
            "value": "0x00",
            "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
            "v": "0x26",
            "r": "0xb71d8dd5ac327ec1b822930c066a9d0931a26f8529cbd0dca51a6a1f3fc508c9",
            "s": "0x63698823fb964779539d8fd4d016e7326cbd9dab987233458980d422776167b5",
            "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        }"#;

        let tx: Transaction = serde_json::from_str(json_str).unwrap();
        assert_eq!(tx.tx_type, U64::from(0));
        assert_eq!(tx.chain_id, Some(U256::from(1)));
        assert_eq!(tx.nonce, U256::from(0));
        assert_eq!(tx.v, U64::from(38));
        assert_eq!(tx.access_list, None);
    }

    #[test]
    fn recover_access_list_tx() {
        let json_str = r#"{
            "type": "0x01",
            "chainId": "0x01",
            "nonce": "0x00",
            "gasPrice": "0x07",
            "gasLimit": "0x04ef00",
            "to": "0x0000000000000000000000000000000000001000",
            "value": "0x01",
            "data": "0x",
            "accessList": [
                {
                    "address": "0x0000000000000000000000000000000000000000",
                    "storageKeys": [
                        "0x0000000000000000000000000000000000000000000000000000000000000000"
                    ]
                }
            ],
            "v": "0x00",
            "r": "0x81a25ffdb3797e6428f854c642e1884ee7b7be0c4ccbb7e989b70039b87e4450",
            "s": "0x2d25e40f45271d5f77735d06550dff43bf328190de034157cefec446855513d6",
            "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        }"#;

        let tx: Transaction = serde_json::from_str(json_str).unwrap();
        assert_eq!(tx.tx_type, U64::from(1));
        assert!(tx.access_list.is_some());
        assert_eq!(tx.access_list.unwrap().len(), 1);
    }

    #[test]
    fn recover_1559_tx() {
        let json_str = r#"{
            "type": "0x02",
            "chainId": "0x01",
            "nonce": "0x00",
            "maxPriorityFeePerGas": "0x00",
            "maxFeePerGas": "0x07",
            "gasLimit": "0x0f4240",
            "to": "0x0000000000000000000000000000000000001000",
            "value": "0x00",
            "data": "0x000000000000000000000000000000000000000000000000000000000000000c",
            "accessList": [],
            "v": "0x00",
            "r": "0x0250e37fb1094dca850d5e9930a67cfcbdfb10dd4e93d576c1add47ebcaa9087",
            "s": "0x77e2484f633730a17870768524826e03dbb3a1856b5b07b850631453167b42c5",
            "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        }"#;

        let tx: Transaction = serde_json::from_str(json_str).unwrap();
        assert_eq!(tx.tx_type, U64::from(2));
        assert_eq!(tx.max_fee_per_gas, Some(U256::from(7)));
    }

    #[test]
    fn recover_7702_tx() {
        let json_str = r#"{
            "type": "0x04",
            "chainId": "0x01",
            "nonce": "0x00",
            "maxPriorityFeePerGas": "0x00",
            "maxFeePerGas": "0x07",
            "gasLimit": "0x023a5a",
            "to": "0x0000000000000000000000000000000000001000",
            "value": "0x00",
            "data": "0x010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100",
            "accessList": [],
            "v": "0x01",
            "r": "0x3f1b651968d0fb5693206b5f7ece4b4194828417e03abc35f99657e3a39bf485",
            "s": "0x69b6b8c3bc51916a47bffe07298daf32177f39cc14e1d043c55d46ebca4e67b8",
            "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
            "authorizationList": [
                {
                    "chainId": "0x00",
                    "address": "0x0000000000000000000000000000000000000001",
                    "nonce": "0x00",
                    "v": "0x00",
                    "r": "0x33a629f82b5aaff5b4bfe6b9ab53bb3646b92cda403d7c834f72c9a5073aec20",
                    "s": "0x16902e4a3c089e05d649cab6bd74b6f424fae0eefad3a4944fa452ff7413b5d3",
                    "signer": "0x8a0a19589531694250d570040a0c4b74576919b8",
                    "yParity": "0x00"
                }
            ]
        }"#;

        let tx: Transaction = serde_json::from_str(json_str).unwrap();
        assert_eq!(tx.tx_type, U64::from(4));
        assert!(tx.authorization_list.is_some());
        assert_eq!(tx.authorization_list.unwrap().len(), 1);
    }

    #[test]
    fn recover_4844_tx() {
        let json_str = r#"{
            "type": "0x03",
            "chainId": "0x01",
            "nonce": "0x00",
            "maxPriorityFeePerGas": "0x00",
            "maxFeePerGas": "0x07",
            "gasLimit": "0x0f4240",
            "to": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
            "value": "0x00",
            "data": "0x000000000000000000000000000000000000000000000000000000000000000c",
            "accessList": [],
            "maxFeePerBlobGas": "0x01",
            "blobVersionedHashes": [
                "0x0100000000000000000000000000000000000000000000000000000000000000"
            ],
            "v": "0x01",
            "r": "0x53116c986dc393633b36cacf6e2c5cf896531ffed002ba696a1bab16db1ef4f4",
            "s": "0x45d8f72ef3b93897c58143b6b4368c56947344b2770695dccc26aa6d2f35b248",
            "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
        }"#;

        let tx: Transaction = serde_json::from_str(json_str).unwrap();
        assert_eq!(tx.tx_type, U64::from(3));
        assert!(tx.blob_versioned_hashes.is_some());
        assert_eq!(tx.blob_versioned_hashes.unwrap().len(), 1);
        assert_eq!(tx.max_fee_per_blob_gas, Some(U256::from(1)));
    }
}