arb_rpc/
response.rs

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