1use serde::{Deserialize, Serialize};
2
3use alloy::consensus::TxReceipt;
4use alloy::primitives::{Address, B256, BlockHash, Bloom, TxHash, U64};
5use alloy::rpc::types::{Log, TransactionReceipt};
6
7use super::receipt_envelope::ReceiptEnvelope;
8use crate::types::*;
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
12#[serde(rename_all = "camelCase")]
13pub struct ReceiptResponse<T = ReceiptEnvelope<Log>> {
14 #[serde(flatten)]
16 inner: TransactionReceipt<T>,
17 l1_batch_number: Option<U64>,
19 l1_batch_tx_index: Option<U64>,
21 l2_to_l1_logs: Vec<L2ToL1Log>,
23}
24
25impl ReceiptResponse {
26 pub fn logs(&self) -> &[Log] {
28 self.inner.inner.logs()
29 }
30 pub fn logs_bloom(&self) -> Bloom {
32 self.inner.inner.bloom()
33 }
34 pub fn l1_batch_number(&self) -> Option<U64> {
36 self.l1_batch_number
37 }
38 pub fn l1_batch_tx_index(&self) -> Option<U64> {
40 self.l1_batch_tx_index
41 }
42 pub fn l2_to_l1_logs(&self) -> &[L2ToL1Log] {
44 &self.l2_to_l1_logs
45 }
46
47 pub fn authorization_list(&self) -> Option<&Vec<Address>> {
49 None
50 }
51}
52
53impl<T: TxReceipt<Log = Log>> alloy::network::ReceiptResponse for ReceiptResponse<T> {
54 fn contract_address(&self) -> Option<Address> {
56 self.inner.contract_address()
57 }
58
59 fn status(&self) -> bool {
61 self.inner.status()
62 }
63
64 fn block_hash(&self) -> Option<BlockHash> {
66 self.inner.block_hash()
67 }
68
69 fn block_number(&self) -> Option<u64> {
71 self.inner.block_number()
72 }
73
74 fn transaction_hash(&self) -> TxHash {
76 self.inner.transaction_hash()
77 }
78
79 fn transaction_index(&self) -> Option<u64> {
81 self.inner.transaction_index()
82 }
83
84 fn gas_used(&self) -> u64 {
86 self.inner.gas_used()
87 }
88
89 fn effective_gas_price(&self) -> u128 {
91 self.inner.effective_gas_price()
92 }
93
94 fn blob_gas_used(&self) -> Option<u64> {
96 self.inner.blob_gas_used()
97 }
98
99 fn blob_gas_price(&self) -> Option<u128> {
101 self.inner.blob_gas_price()
102 }
103
104 fn from(&self) -> Address {
106 self.inner.from()
107 }
108
109 fn to(&self) -> Option<Address> {
111 self.inner.to()
112 }
113
114 fn cumulative_gas_used(&self) -> u64 {
116 self.inner.cumulative_gas_used()
117 }
118
119 fn state_root(&self) -> Option<B256> {
123 self.inner.state_root()
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use std::str::FromStr;
130
131 use super::*;
132 use alloy::network::ReceiptResponse as AlloyReceiptResponse;
133 use alloy::primitives::U256;
134 use alloy::primitives::address;
135
136 #[tokio::test(flavor = "multi_thread")]
137 async fn receipt_test() {
138 let receipt_json = r#"
139 {
140 "blockHash": "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9",
141 "blockNumber": "0x1d1551e",
142 "contractAddress": "0x0000000000000000000000000000000000008006",
143 "cumulativeGasUsed": "0x0",
144 "effectiveGasPrice": "0x17d7840",
145 "from": "0x1bc3366b3664c01b8687b1efcfc6478d9351a8a9",
146 "gasUsed": "0x2b9bcb",
147 "l1BatchNumber": "0x72ae1",
148 "l1BatchTxIndex": "0x469",
149 "l2ToL1Logs": [
150 {
151 "blockHash": "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9",
152 "blockNumber": "30496030",
153 "isService": true,
154 "key": "0x000000000000000000000000000000000000000000000000000000000000800a",
155 "l1BatchNumber": "0x72ae1",
156 "logIndex": "0x0",
157 "sender": "0x0000000000000000000000000000000000008008",
158 "shardId": "0x0",
159 "transactionHash": "0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda",
160 "transactionIndex": "0x0",
161 "transactionLogIndex": "0x0",
162 "txIndexInL1Batch": "0x12d",
163 "value": "0x30c635c6a0084404145f3723046c1c1b21eb5ccbb97893c90747c7a8bd83a641"
164 }
165 ],
166 "logs": [
167 {
168 "address": "0x000000000000000000000000000000000000800a",
169 "blockHash": "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9",
170 "blockNumber": "0x1d1551e",
171 "blockTimestamp": "0x660c1740",
172 "data": "0x0000000000000000000000000000000000000000000000000001011c8f80b6c0",
173 "l1BatchNumber": "0x72ae1",
174 "logIndex": "0x0",
175 "logType": null,
176 "removed": false,
177 "topics": [
178 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
179 "0x0000000000000000000000001bc3366b3664c01b8687b1efcfc6478d9351a8a9",
180 "0x0000000000000000000000000000000000000000000000000000000000008001"
181 ],
182 "transactionHash": "0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda",
183 "transactionIndex": "0x0",
184 "transactionLogIndex": "0x0"
185 },
186 {
187 "address": "0x000000000000000000000000000000000000800a",
188 "blockHash": "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9",
189 "blockNumber": "0x1d1551e",
190 "blockTimestamp": "0x660c1740",
191 "data": "0x000000000000000000000000000000000000000000000000000042a896fb71c0",
192 "l1BatchNumber": "0x72ae1",
193 "logIndex": "0x1",
194 "logType": null,
195 "removed": false,
196 "topics": [
197 "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
198 "0x0000000000000000000000000000000000000000000000000000000000008001",
199 "0x0000000000000000000000001bc3366b3664c01b8687b1efcfc6478d9351a8a9"
200 ],
201 "transactionHash": "0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda",
202 "transactionIndex": "0x0",
203 "transactionLogIndex": "0x1"
204 }
205 ],
206 "logsBloom": "0x00280000000400000000000088000000000000000000008000004000800000100000000000000000002000000010000002000000000040000008000000000080000000002000840000000008000000240000000000000000000080010000080000000000020500000004000000000800000000000000000001000010000000000000000000000000000004000000000000001000000000000000004000000000000000000001100004000000000010000000000000000000000000000000000000000002008002800000080400500110402000000000000000000000000020000000000000000000000000000000000000002041000000020000000000000060",
207 "status": "0x1",
208 "to": "0x9b5def958d0f3b6955cbea4d5b7809b2fb26b059",
209 "transactionHash": "0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda",
210 "transactionIndex": "0x0",
211 "type": "0x2",
212 "blobGasUsed": 111111,
213 "blobGasPrice": 222222
214 }
215 "#;
216
217 let receipt = serde_json::from_str::<ReceiptResponse>(receipt_json).unwrap();
218 assert_eq!(receipt.l1_batch_number(), Some(U64::from(0x72ae1)));
219 assert_eq!(receipt.l1_batch_tx_index(), Some(U64::from(0x469)));
220 assert_eq!(
221 receipt.l2_to_l1_logs(),
222 vec![L2ToL1Log {
223 block_hash: Some(
224 B256::from_str(
225 "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9"
226 )
227 .unwrap()
228 ),
229 block_number: U64::from(30496030),
230 l1_batch_number: Some(U64::from(0x72ae1)),
231 log_index: U256::from(0),
232 transaction_index: U64::from(0),
233 transaction_hash: B256::from_str(
234 "0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda"
235 )
236 .unwrap(),
237 transaction_log_index: U256::from(0),
238 tx_index_in_l1_batch: Some(U64::from(301)),
239 shard_id: U64::from(0),
240 is_service: true,
241 sender: address!("0000000000000000000000000000000000008008"),
242 key: B256::from_str(
243 "0x000000000000000000000000000000000000000000000000000000000000800a"
244 )
245 .unwrap(),
246 value: B256::from_str(
247 "0x30c635c6a0084404145f3723046c1c1b21eb5ccbb97893c90747c7a8bd83a641"
248 )
249 .unwrap()
250 }]
251 );
252 assert_eq!(receipt.logs(), receipt.inner.inner.logs());
253 assert_eq!(receipt.logs_bloom(), receipt.inner.inner.bloom());
254 assert_eq!(
255 receipt.contract_address(),
256 Some(address!("0000000000000000000000000000000000008006"))
257 );
258 assert!(receipt.status());
259 assert_eq!(
260 receipt.block_hash(),
261 Some(
262 B256::from_str(
263 "0x5046bdc714b2a9b40e9fbfdfc5140371c1b03b40335d908de92a7686dcc067e9"
264 )
265 .unwrap()
266 )
267 );
268 assert_eq!(receipt.block_number(), Some(30496030));
269 assert_eq!(
270 receipt.transaction_hash(),
271 B256::from_str("0xb2adc4d2b3203e186001dc37fdf02cc8e772518425d263adc6a17dbddff3bfda")
272 .unwrap()
273 );
274 assert_eq!(receipt.transaction_index(), Some(0));
275 assert_eq!(receipt.gas_used(), 2857931);
276 assert_eq!(receipt.effective_gas_price(), 25000000);
277 assert_eq!(receipt.blob_gas_used(), Some(111111));
278 assert_eq!(receipt.blob_gas_price(), Some(222222));
279 assert_eq!(
280 receipt.from(),
281 address!("1bc3366b3664c01b8687b1efcfc6478d9351a8a9")
282 );
283 assert_eq!(
284 receipt.to(),
285 Some(address!("9b5def958d0f3b6955cbea4d5b7809b2fb26b059"))
286 );
287 assert_eq!(receipt.authorization_list(), None);
288 assert_eq!(receipt.cumulative_gas_used(), 0);
289 assert_eq!(receipt.state_root(), None);
290 }
291}