1use crate::{utils::deserializer::deserialize_maybe_empty, TestAuthorization};
2use cfx_rpc_primitives::Bytes;
3use cfx_types::{Address, H256, U256, U64};
4use primitives::transaction::AccessList;
5use serde::Deserialize;
6
7#[derive(Debug, PartialEq, Eq, Deserialize)]
8#[serde(rename_all = "camelCase")]
9pub struct Transaction {
10 #[serde(default, rename = "type")]
11 pub tx_type: U64,
12 pub chain_id: Option<U256>,
13 pub nonce: U256,
14 pub gas_price: Option<U256>,
15 pub max_priority_fee_per_gas: Option<U256>,
16 pub max_fee_per_gas: Option<U256>,
17 pub gas_limit: U256,
18 #[serde(default, deserialize_with = "deserialize_maybe_empty")]
19 pub to: Option<Address>,
20 pub value: U256,
21 pub data: Bytes,
22 pub v: U64,
23 pub r: U256,
24 pub s: U256,
25 pub sender: Option<Address>,
26 pub secret_key: Option<H256>,
27 pub access_list: Option<AccessList>,
28 pub max_fee_per_blob_gas: Option<U256>,
29 pub blob_versioned_hashes: Option<Vec<H256>>,
30 pub authorization_list: Option<Vec<TestAuthorization>>,
31}
32
33#[cfg(test)]
34mod tests {
35 use super::*;
36
37 #[test]
38 fn recover_basic() {
39 let json_str = r#"{
40 "type": "0x00",
41 "chainId": "0x01",
42 "nonce": "0x00",
43 "gasPrice": "0x0a",
44 "gasLimit": "0x07a120",
45 "to": "0x0000000000000000000000000000000000001000",
46 "value": "0x00",
47 "data": "0x00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002003fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2efffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f",
48 "v": "0x26",
49 "r": "0xb71d8dd5ac327ec1b822930c066a9d0931a26f8529cbd0dca51a6a1f3fc508c9",
50 "s": "0x63698823fb964779539d8fd4d016e7326cbd9dab987233458980d422776167b5",
51 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
52 }"#;
53
54 let tx: Transaction = serde_json::from_str(json_str).unwrap();
55 assert_eq!(tx.tx_type, U64::from(0));
56 assert_eq!(tx.chain_id, Some(U256::from(1)));
57 assert_eq!(tx.nonce, U256::from(0));
58 assert_eq!(tx.v, U64::from(38));
59 assert_eq!(tx.access_list, None);
60 }
61
62 #[test]
63 fn recover_access_list_tx() {
64 let json_str = r#"{
65 "type": "0x01",
66 "chainId": "0x01",
67 "nonce": "0x00",
68 "gasPrice": "0x07",
69 "gasLimit": "0x04ef00",
70 "to": "0x0000000000000000000000000000000000001000",
71 "value": "0x01",
72 "data": "0x",
73 "accessList": [
74 {
75 "address": "0x0000000000000000000000000000000000000000",
76 "storageKeys": [
77 "0x0000000000000000000000000000000000000000000000000000000000000000"
78 ]
79 }
80 ],
81 "v": "0x00",
82 "r": "0x81a25ffdb3797e6428f854c642e1884ee7b7be0c4ccbb7e989b70039b87e4450",
83 "s": "0x2d25e40f45271d5f77735d06550dff43bf328190de034157cefec446855513d6",
84 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
85 }"#;
86
87 let tx: Transaction = serde_json::from_str(json_str).unwrap();
88 assert_eq!(tx.tx_type, U64::from(1));
89 assert!(tx.access_list.is_some());
90 assert_eq!(tx.access_list.unwrap().len(), 1);
91 }
92
93 #[test]
94 fn recover_1559_tx() {
95 let json_str = r#"{
96 "type": "0x02",
97 "chainId": "0x01",
98 "nonce": "0x00",
99 "maxPriorityFeePerGas": "0x00",
100 "maxFeePerGas": "0x07",
101 "gasLimit": "0x0f4240",
102 "to": "0x0000000000000000000000000000000000001000",
103 "value": "0x00",
104 "data": "0x000000000000000000000000000000000000000000000000000000000000000c",
105 "accessList": [],
106 "v": "0x00",
107 "r": "0x0250e37fb1094dca850d5e9930a67cfcbdfb10dd4e93d576c1add47ebcaa9087",
108 "s": "0x77e2484f633730a17870768524826e03dbb3a1856b5b07b850631453167b42c5",
109 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
110 }"#;
111
112 let tx: Transaction = serde_json::from_str(json_str).unwrap();
113 assert_eq!(tx.tx_type, U64::from(2));
114 assert_eq!(tx.max_fee_per_gas, Some(U256::from(7)));
115 }
116
117 #[test]
118 fn recover_7702_tx() {
119 let json_str = r#"{
120 "type": "0x04",
121 "chainId": "0x01",
122 "nonce": "0x00",
123 "maxPriorityFeePerGas": "0x00",
124 "maxFeePerGas": "0x07",
125 "gasLimit": "0x023a5a",
126 "to": "0x0000000000000000000000000000000000001000",
127 "value": "0x00",
128 "data": "0x010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010100",
129 "accessList": [],
130 "v": "0x01",
131 "r": "0x3f1b651968d0fb5693206b5f7ece4b4194828417e03abc35f99657e3a39bf485",
132 "s": "0x69b6b8c3bc51916a47bffe07298daf32177f39cc14e1d043c55d46ebca4e67b8",
133 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
134 "authorizationList": [
135 {
136 "chainId": "0x00",
137 "address": "0x0000000000000000000000000000000000000001",
138 "nonce": "0x00",
139 "v": "0x00",
140 "r": "0x33a629f82b5aaff5b4bfe6b9ab53bb3646b92cda403d7c834f72c9a5073aec20",
141 "s": "0x16902e4a3c089e05d649cab6bd74b6f424fae0eefad3a4944fa452ff7413b5d3",
142 "signer": "0x8a0a19589531694250d570040a0c4b74576919b8",
143 "yParity": "0x00"
144 }
145 ]
146 }"#;
147
148 let tx: Transaction = serde_json::from_str(json_str).unwrap();
149 assert_eq!(tx.tx_type, U64::from(4));
150 assert!(tx.authorization_list.is_some());
151 assert_eq!(tx.authorization_list.unwrap().len(), 1);
152 }
153
154 #[test]
155 fn recover_4844_tx() {
156 let json_str = r#"{
157 "type": "0x03",
158 "chainId": "0x01",
159 "nonce": "0x00",
160 "maxPriorityFeePerGas": "0x00",
161 "maxFeePerGas": "0x07",
162 "gasLimit": "0x0f4240",
163 "to": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02",
164 "value": "0x00",
165 "data": "0x000000000000000000000000000000000000000000000000000000000000000c",
166 "accessList": [],
167 "maxFeePerBlobGas": "0x01",
168 "blobVersionedHashes": [
169 "0x0100000000000000000000000000000000000000000000000000000000000000"
170 ],
171 "v": "0x01",
172 "r": "0x53116c986dc393633b36cacf6e2c5cf896531ffed002ba696a1bab16db1ef4f4",
173 "s": "0x45d8f72ef3b93897c58143b6b4368c56947344b2770695dccc26aa6d2f35b248",
174 "sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
175 }"#;
176
177 let tx: Transaction = serde_json::from_str(json_str).unwrap();
178 assert_eq!(tx.tx_type, U64::from(3));
179 assert!(tx.blob_versioned_hashes.is_some());
180 assert_eq!(tx.blob_versioned_hashes.unwrap().len(), 1);
181 assert_eq!(tx.max_fee_per_blob_gas, Some(U256::from(1)));
182 }
183}