1use crate::types::{Address, Bytes, Index, Log, H2048, H256, U256, U64};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Default, Clone, PartialEq, Deserialize, Serialize)]
6pub struct Transaction {
7 pub hash: H256,
9 pub nonce: U256,
11 #[serde(rename = "blockHash")]
13 pub block_hash: Option<H256>,
14 #[serde(rename = "blockNumber")]
16 pub block_number: Option<U64>,
17 #[serde(rename = "transactionIndex")]
19 pub transaction_index: Option<Index>,
20 #[serde(default, skip_serializing_if = "Option::is_none")]
22 pub from: Option<Address>,
23 pub to: Option<Address>,
25 pub value: U256,
27 #[serde(rename = "gasPrice")]
29 pub gas_price: Option<U256>,
30 pub gas: U256,
32 pub input: Bytes,
34 #[serde(default, skip_serializing_if = "Option::is_none")]
36 pub v: Option<U64>,
37 #[serde(default, skip_serializing_if = "Option::is_none")]
39 pub r: Option<U256>,
40 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub s: Option<U256>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub raw: Option<Bytes>,
46 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
48 pub transaction_type: Option<U64>,
49 #[serde(rename = "accessList", default, skip_serializing_if = "Option::is_none")]
51 pub access_list: Option<AccessList>,
52 #[serde(rename = "maxFeePerGas", skip_serializing_if = "Option::is_none")]
54 pub max_fee_per_gas: Option<U256>,
55 #[serde(rename = "maxPriorityFeePerGas", skip_serializing_if = "Option::is_none")]
57 pub max_priority_fee_per_gas: Option<U256>,
58}
59
60#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
62pub struct Receipt {
63 #[serde(rename = "transactionHash")]
65 pub transaction_hash: H256,
66 #[serde(rename = "transactionIndex")]
68 pub transaction_index: Index,
69 #[serde(rename = "blockHash")]
71 pub block_hash: Option<H256>,
72 #[serde(rename = "blockNumber")]
74 pub block_number: Option<U64>,
75 #[serde(default)]
79 pub from: Address,
80 #[serde(default)]
84 pub to: Option<Address>,
85 #[serde(rename = "cumulativeGasUsed")]
87 pub cumulative_gas_used: U256,
88 #[serde(rename = "gasUsed")]
92 pub gas_used: Option<U256>,
93 #[serde(rename = "contractAddress")]
95 pub contract_address: Option<Address>,
96 pub logs: Vec<Log>,
98 pub status: Option<U64>,
100 pub root: Option<H256>,
102 #[serde(rename = "logsBloom")]
104 pub logs_bloom: H2048,
105 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
107 pub transaction_type: Option<U64>,
108 #[serde(rename = "effectiveGasPrice")]
110 pub effective_gas_price: Option<U256>,
111}
112
113#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
115pub struct RawTransaction {
116 pub raw: Bytes,
118 pub tx: Transaction,
120}
121
122pub type AccessList = Vec<AccessListItem>;
124
125#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
127#[serde(rename_all = "camelCase")]
128pub struct AccessListItem {
129 pub address: Address,
131 pub storage_keys: Vec<H256>,
133}
134
135#[cfg(test)]
136mod tests {
137 use super::{RawTransaction, Receipt};
138
139 #[test]
140 fn test_deserialize_receipt() {
141 let receipt_str = "{\"blockHash\":\"0x83eaba432089a0bfe99e9fc9022d1cfcb78f95f407821be81737c84ae0b439c5\",\"blockNumber\":\"0x38\",\"contractAddress\":\"0x03d8c4566478a6e1bf75650248accce16a98509f\",\"from\":\"0x407d73d8a49eeb85d32cf465507dd71d507100c1\",\"to\":\"0x853f43d8a49eeb85d32cf465507dd71d507100c1\",\"cumulativeGasUsed\":\"0x927c0\",\"gasUsed\":\"0x927c0\",\"logs\":[],\"logsBloom\":\"0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\",\"root\":null,\"transactionHash\":\"0x422fb0d5953c0c48cbb42fb58e1c30f5e150441c68374d70ca7d4f191fd56f26\",\"transactionIndex\":\"0x0\",\"effectiveGasPrice\": \"0x100\"}";
142
143 let _receipt: Receipt = serde_json::from_str(receipt_str).unwrap();
144 }
145
146 #[test]
147 fn should_deserialize_receipt_without_from_to() {
148 let receipt_str = r#"{
149 "blockHash": "0x83eaba432089a0bfe99e9fc9022d1cfcb78f95f407821be81737c84ae0b439c5",
150 "blockNumber": "0x38",
151 "contractAddress": "0x03d8c4566478a6e1bf75650248accce16a98509f",
152 "cumulativeGasUsed": "0x927c0",
153 "gasUsed": "0x927c0",
154 "logs": [],
155 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
156 "root": null,
157 "transactionHash": "0x422fb0d5953c0c48cbb42fb58e1c30f5e150441c68374d70ca7d4f191fd56f26",
158 "transactionIndex": "0x0",
159 "status": "0x1",
160 "effectiveGasPrice": "0x100"
161 }"#;
162
163 let _receipt: Receipt = serde_json::from_str(receipt_str).unwrap();
164 }
165
166 #[test]
167 fn should_deserialize_receipt_with_status() {
168 let receipt_str = r#"{
169 "blockHash": "0x83eaba432089a0bfe99e9fc9022d1cfcb78f95f407821be81737c84ae0b439c5",
170 "blockNumber": "0x38",
171 "contractAddress": "0x03d8c4566478a6e1bf75650248accce16a98509f",
172 "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
173 "to": "0x853f43d8a49eeb85d32cf465507dd71d507100c1",
174 "cumulativeGasUsed": "0x927c0",
175 "gasUsed": "0x927c0",
176 "logs": [],
177 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
178 "root": null,
179 "transactionHash": "0x422fb0d5953c0c48cbb42fb58e1c30f5e150441c68374d70ca7d4f191fd56f26",
180 "transactionIndex": "0x0",
181 "status": "0x1",
182 "effectiveGasPrice": "0x100"
183 }"#;
184
185 let _receipt: Receipt = serde_json::from_str(receipt_str).unwrap();
186 }
187
188 #[test]
189 fn should_deserialize_receipt_without_to() {
190 let receipt_str = r#"{
191 "blockHash": "0x83eaba432089a0bfe99e9fc9022d1cfcb78f95f407821be81737c84ae0b439c5",
192 "blockNumber": "0x38",
193 "contractAddress": "0x03d8c4566478a6e1bf75650248accce16a98509f",
194 "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
195 "to": null,
196 "cumulativeGasUsed": "0x927c0",
197 "gasUsed": "0x927c0",
198 "logs": [],
199 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
200 "root": null,
201 "transactionHash": "0x422fb0d5953c0c48cbb42fb58e1c30f5e150441c68374d70ca7d4f191fd56f26",
202 "transactionIndex": "0x0",
203 "status": "0x1",
204 "effectiveGasPrice": "0x100"
205 }"#;
206
207 let _receipt: Receipt = serde_json::from_str(receipt_str).unwrap();
208 }
209
210 #[test]
211 fn should_deserialize_receipt_without_gas() {
212 let receipt_str = r#"{
213 "blockHash": "0x83eaba432089a0bfe99e9fc9022d1cfcb78f95f407821be81737c84ae0b439c5",
214 "blockNumber": "0x38",
215 "contractAddress": "0x03d8c4566478a6e1bf75650248accce16a98509f",
216 "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
217 "to": "0x853f43d8a49eeb85d32cf465507dd71d507100c1",
218 "cumulativeGasUsed": "0x927c0",
219 "gasUsed": null,
220 "logs": [],
221 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
222 "root": null,
223 "transactionHash": "0x422fb0d5953c0c48cbb42fb58e1c30f5e150441c68374d70ca7d4f191fd56f26",
224 "transactionIndex": "0x0",
225 "status": "0x1",
226 "effectiveGasPrice": "0x100"
227 }"#;
228
229 let _receipt: Receipt = serde_json::from_str(receipt_str).unwrap();
230 }
231
232 #[test]
233 fn test_deserialize_signed_tx_parity() {
234 let tx_str = r#"{
236 "raw": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675",
237 "tx": {
238 "hash": "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b",
239 "nonce": "0x0",
240 "blockHash": "0xbeab0aa2411b7ab17f30a99d3cb9c6ef2fc5426d6ad6fd9e2a26a6aed1d1055b",
241 "blockNumber": "0x15df",
242 "transactionIndex": "0x1",
243 "from": "0x407d73d8a49eeb85d32cf465507dd71d507100c1",
244 "to": "0x853f43d8a49eeb85d32cf465507dd71d507100c1",
245 "value": "0x7f110",
246 "gas": "0x7f110",
247 "gasPrice": "0x09184e72a000",
248 "input": "0x603880600c6000396000f300603880600c6000396000f3603880600c6000396000f360",
249 "s": "0x777"
250 }
251 }"#;
252
253 let _tx: RawTransaction = serde_json::from_str(tx_str).unwrap();
254 }
255
256 #[test]
257 fn test_deserialize_signed_tx_geth() {
258 let tx_str = r#"{
259 "raw": "0xf85d01018094f3b3138e5eb1c75b43994d1bb760e2f9f735789680801ca06484d00575e961a7db35ebe5badaaca5cb7ee65d1f2f22f22da87c238b99d30da07a85d65797e4b555c1d3f64beebb2cb6f16a6fbd40c43cc48451eaf85305f66e",
260 "tx": {
261 "gas": "0x0",
262 "gasPrice": "0x1",
263 "hash": "0x0a32fb4e18bc6f7266a164579237b1b5c74271d453c04eab70444ca367d38418",
264 "input": "0x",
265 "nonce": "0x1",
266 "to": "0xf3b3138e5eb1c75b43994d1bb760e2f9f7357896",
267 "r": "0x6484d00575e961a7db35ebe5badaaca5cb7ee65d1f2f22f22da87c238b99d30d",
268 "s": "0x7a85d65797e4b555c1d3f64beebb2cb6f16a6fbd40c43cc48451eaf85305f66e",
269 "v": "0x1c",
270 "value": "0x0"
271 }
272 }"#;
273
274 let _tx: RawTransaction = serde_json::from_str(tx_str).unwrap();
275 }
276}