arb_rpc/
response.rs

1//! Arbitrum transaction response conversion.
2
3use std::convert::Infallible;
4
5use alloy_primitives::Address;
6use alloy_rpc_types_eth::{Transaction, TransactionInfo};
7use alloy_serde::WithOtherFields;
8use arb_primitives::{ArbTransactionSigned, ArbTypedTransaction};
9use reth_rpc_convert::transaction::RpcTxConverter;
10
11/// Converts consensus transactions to RPC transaction responses.
12#[derive(Debug, Clone)]
13pub struct ArbRpcTxConverter;
14
15impl
16    RpcTxConverter<
17        ArbTransactionSigned,
18        WithOtherFields<Transaction<ArbTransactionSigned>>,
19        TransactionInfo,
20    > for ArbRpcTxConverter
21{
22    type Err = Infallible;
23
24    fn convert_rpc_tx(
25        &self,
26        tx: ArbTransactionSigned,
27        signer: Address,
28        tx_info: TransactionInfo,
29    ) -> Result<WithOtherFields<Transaction<ArbTransactionSigned>>, Infallible> {
30        use alloy_consensus::transaction::Recovered;
31
32        let other = arb_tx_fields(tx.inner());
33
34        let base = Transaction::from_transaction(Recovered::new_unchecked(tx, signer), tx_info);
35
36        Ok(WithOtherFields {
37            inner: base,
38            other: alloy_serde::OtherFields::new(other),
39        })
40    }
41}
42
43/// Extract Arbitrum-specific extension fields from a transaction.
44pub fn arb_tx_fields(
45    tx: &ArbTypedTransaction,
46) -> std::collections::BTreeMap<String, serde_json::Value> {
47    let mut fields = std::collections::BTreeMap::new();
48
49    match tx {
50        ArbTypedTransaction::Deposit(d) => {
51            fields.insert(
52                "requestId".to_string(),
53                serde_json::to_value(d.l1_request_id).unwrap_or_default(),
54            );
55        }
56        ArbTypedTransaction::Contract(c) => {
57            fields.insert(
58                "requestId".to_string(),
59                serde_json::to_value(c.request_id).unwrap_or_default(),
60            );
61        }
62        ArbTypedTransaction::Retry(r) => {
63            fields.insert(
64                "ticketId".to_string(),
65                serde_json::to_value(r.ticket_id).unwrap_or_default(),
66            );
67            fields.insert(
68                "refundTo".to_string(),
69                serde_json::to_value(r.refund_to).unwrap_or_default(),
70            );
71            fields.insert(
72                "maxRefund".to_string(),
73                serde_json::to_value(r.max_refund).unwrap_or_default(),
74            );
75            fields.insert(
76                "submissionFeeRefund".to_string(),
77                serde_json::to_value(r.submission_fee_refund).unwrap_or_default(),
78            );
79        }
80        ArbTypedTransaction::SubmitRetryable(s) => {
81            fields.insert(
82                "requestId".to_string(),
83                serde_json::to_value(s.request_id).unwrap_or_default(),
84            );
85            fields.insert(
86                "l1BaseFee".to_string(),
87                serde_json::to_value(s.l1_base_fee).unwrap_or_default(),
88            );
89            fields.insert(
90                "depositValue".to_string(),
91                serde_json::to_value(s.deposit_value).unwrap_or_default(),
92            );
93            if let Some(retry_to) = s.retry_to {
94                fields.insert(
95                    "retryTo".to_string(),
96                    serde_json::to_value(retry_to).unwrap_or_default(),
97                );
98            }
99            fields.insert(
100                "retryValue".to_string(),
101                serde_json::to_value(s.retry_value).unwrap_or_default(),
102            );
103            fields.insert(
104                "beneficiary".to_string(),
105                serde_json::to_value(s.beneficiary).unwrap_or_default(),
106            );
107            fields.insert(
108                "maxSubmissionFee".to_string(),
109                serde_json::to_value(s.max_submission_fee).unwrap_or_default(),
110            );
111            fields.insert(
112                "refundTo".to_string(),
113                serde_json::to_value(s.fee_refund_addr).unwrap_or_default(),
114            );
115            fields.insert(
116                "retryData".to_string(),
117                serde_json::to_value(s.retry_data.clone()).unwrap_or_default(),
118            );
119        }
120        // Standard Ethereum types and internal/unsigned: no extra fields.
121        _ => {}
122    }
123
124    fields
125}