op_alloy_network/
lib.rs

1#![doc = include_str!("../README.md")]
2#![doc(
3    html_logo_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/alloy.jpg",
4    html_favicon_url = "https://raw.githubusercontent.com/alloy-rs/core/main/assets/favicon.ico"
5)]
6#![cfg_attr(not(test), warn(unused_crate_dependencies))]
7#![cfg_attr(docsrs, feature(doc_cfg))]
8
9pub use alloy_network::*;
10
11use alloy_consensus::{ReceiptWithBloom, TxEnvelope, TxType, TypedTransaction};
12use alloy_primitives::{Address, Bytes, ChainId, TxKind, U256};
13use alloy_rpc_types_eth::AccessList;
14use op_alloy_consensus::{OpReceipt, OpTxEnvelope, OpTxType, OpTypedTransaction};
15use op_alloy_rpc_types::OpTransactionRequest;
16
17/// Types for an Op-stack network.
18#[derive(Clone, Copy, Debug)]
19pub struct Optimism {
20    _private: (),
21}
22
23impl Network for Optimism {
24    type TxType = OpTxType;
25
26    type TxEnvelope = op_alloy_consensus::OpTxEnvelope;
27
28    type UnsignedTx = op_alloy_consensus::OpTypedTransaction;
29
30    type ReceiptEnvelope = ReceiptWithBloom<OpReceipt>;
31
32    type Header = alloy_consensus::Header;
33
34    type TransactionRequest = op_alloy_rpc_types::OpTransactionRequest;
35
36    type TransactionResponse = op_alloy_rpc_types::Transaction;
37
38    type ReceiptResponse = op_alloy_rpc_types::OpTransactionReceipt;
39
40    type HeaderResponse = alloy_rpc_types_eth::Header;
41
42    type BlockResponse =
43        alloy_rpc_types_eth::Block<Self::TransactionResponse, Self::HeaderResponse>;
44}
45
46impl TransactionBuilder<Optimism> for OpTransactionRequest {
47    fn chain_id(&self) -> Option<ChainId> {
48        self.as_ref().chain_id()
49    }
50
51    fn set_chain_id(&mut self, chain_id: ChainId) {
52        self.as_mut().set_chain_id(chain_id);
53    }
54
55    fn nonce(&self) -> Option<u64> {
56        self.as_ref().nonce()
57    }
58
59    fn set_nonce(&mut self, nonce: u64) {
60        self.as_mut().set_nonce(nonce);
61    }
62
63    fn take_nonce(&mut self) -> Option<u64> {
64        self.as_mut().nonce.take()
65    }
66
67    fn input(&self) -> Option<&Bytes> {
68        self.as_ref().input()
69    }
70
71    fn set_input<T: Into<Bytes>>(&mut self, input: T) {
72        self.as_mut().set_input(input);
73    }
74
75    fn from(&self) -> Option<Address> {
76        self.as_ref().from()
77    }
78
79    fn set_from(&mut self, from: Address) {
80        self.as_mut().set_from(from);
81    }
82
83    fn kind(&self) -> Option<TxKind> {
84        self.as_ref().kind()
85    }
86
87    fn clear_kind(&mut self) {
88        self.as_mut().clear_kind();
89    }
90
91    fn set_kind(&mut self, kind: TxKind) {
92        self.as_mut().set_kind(kind);
93    }
94
95    fn value(&self) -> Option<U256> {
96        self.as_ref().value()
97    }
98
99    fn set_value(&mut self, value: U256) {
100        self.as_mut().set_value(value);
101    }
102
103    fn gas_price(&self) -> Option<u128> {
104        self.as_ref().gas_price()
105    }
106
107    fn set_gas_price(&mut self, gas_price: u128) {
108        self.as_mut().set_gas_price(gas_price);
109    }
110
111    fn max_fee_per_gas(&self) -> Option<u128> {
112        self.as_ref().max_fee_per_gas()
113    }
114
115    fn set_max_fee_per_gas(&mut self, max_fee_per_gas: u128) {
116        self.as_mut().set_max_fee_per_gas(max_fee_per_gas);
117    }
118
119    fn max_priority_fee_per_gas(&self) -> Option<u128> {
120        self.as_ref().max_priority_fee_per_gas()
121    }
122
123    fn set_max_priority_fee_per_gas(&mut self, max_priority_fee_per_gas: u128) {
124        self.as_mut().set_max_priority_fee_per_gas(max_priority_fee_per_gas);
125    }
126
127    fn gas_limit(&self) -> Option<u64> {
128        self.as_ref().gas_limit()
129    }
130
131    fn set_gas_limit(&mut self, gas_limit: u64) {
132        self.as_mut().set_gas_limit(gas_limit);
133    }
134
135    fn access_list(&self) -> Option<&AccessList> {
136        self.as_ref().access_list()
137    }
138
139    fn set_access_list(&mut self, access_list: AccessList) {
140        self.as_mut().set_access_list(access_list);
141    }
142
143    fn complete_type(&self, ty: OpTxType) -> Result<(), Vec<&'static str>> {
144        match ty {
145            OpTxType::Deposit => Err(vec!["not implemented for deposit tx"]),
146            _ => {
147                let ty = TxType::try_from(ty as u8).unwrap();
148                self.as_ref().complete_type(ty)
149            }
150        }
151    }
152
153    fn can_submit(&self) -> bool {
154        self.as_ref().can_submit()
155    }
156
157    fn can_build(&self) -> bool {
158        self.as_ref().can_build()
159    }
160
161    #[doc(alias = "output_transaction_type")]
162    fn output_tx_type(&self) -> OpTxType {
163        match self.as_ref().preferred_type() {
164            TxType::Eip1559 | TxType::Eip4844 => OpTxType::Eip1559,
165            TxType::Eip2930 => OpTxType::Eip2930,
166            TxType::Eip7702 => OpTxType::Eip7702,
167            TxType::Legacy => OpTxType::Legacy,
168        }
169    }
170
171    #[doc(alias = "output_transaction_type_checked")]
172    fn output_tx_type_checked(&self) -> Option<OpTxType> {
173        self.as_ref().buildable_type().map(|tx_ty| match tx_ty {
174            TxType::Eip1559 | TxType::Eip4844 => OpTxType::Eip1559,
175            TxType::Eip2930 => OpTxType::Eip2930,
176            TxType::Eip7702 => OpTxType::Eip7702,
177            TxType::Legacy => OpTxType::Legacy,
178        })
179    }
180
181    fn prep_for_submission(&mut self) {
182        self.as_mut().prep_for_submission();
183    }
184
185    fn build_unsigned(self) -> BuildResult<OpTypedTransaction, Optimism> {
186        if let Err((tx_type, missing)) = self.as_ref().missing_keys() {
187            let tx_type = OpTxType::try_from(tx_type as u8).unwrap();
188            return Err(TransactionBuilderError::InvalidTransactionRequest(tx_type, missing)
189                .into_unbuilt(self));
190        }
191        Ok(self.build_typed_tx().expect("checked by missing_keys"))
192    }
193
194    async fn build<W: NetworkWallet<Optimism>>(
195        self,
196        wallet: &W,
197    ) -> Result<<Optimism as Network>::TxEnvelope, TransactionBuilderError<Optimism>> {
198        Ok(wallet.sign_request(self).await?)
199    }
200}
201
202impl NetworkWallet<Optimism> for EthereumWallet {
203    fn default_signer_address(&self) -> Address {
204        NetworkWallet::<Ethereum>::default_signer_address(self)
205    }
206
207    fn has_signer_for(&self, address: &Address) -> bool {
208        NetworkWallet::<Ethereum>::has_signer_for(self, address)
209    }
210
211    fn signer_addresses(&self) -> impl Iterator<Item = Address> {
212        NetworkWallet::<Ethereum>::signer_addresses(self)
213    }
214
215    async fn sign_transaction_from(
216        &self,
217        sender: Address,
218        tx: OpTypedTransaction,
219    ) -> alloy_signer::Result<OpTxEnvelope> {
220        let tx = match tx {
221            OpTypedTransaction::Legacy(tx) => TypedTransaction::Legacy(tx),
222            OpTypedTransaction::Eip2930(tx) => TypedTransaction::Eip2930(tx),
223            OpTypedTransaction::Eip1559(tx) => TypedTransaction::Eip1559(tx),
224            OpTypedTransaction::Eip7702(tx) => TypedTransaction::Eip7702(tx),
225            OpTypedTransaction::Deposit(_) => {
226                return Err(alloy_signer::Error::other("not implemented for deposit tx"));
227            }
228        };
229        let tx = NetworkWallet::<Ethereum>::sign_transaction_from(self, sender, tx).await?;
230
231        Ok(match tx {
232            TxEnvelope::Eip1559(tx) => OpTxEnvelope::Eip1559(tx),
233            TxEnvelope::Eip2930(tx) => OpTxEnvelope::Eip2930(tx),
234            TxEnvelope::Eip7702(tx) => OpTxEnvelope::Eip7702(tx),
235            TxEnvelope::Legacy(tx) => OpTxEnvelope::Legacy(tx),
236            _ => unreachable!(),
237        })
238    }
239}
240
241use alloy_provider::fillers::{
242    ChainIdFiller, GasFiller, JoinFill, NonceFiller, RecommendedFillers,
243};
244
245impl RecommendedFillers for Optimism {
246    type RecommendedFillers = JoinFill<GasFiller, JoinFill<NonceFiller, ChainIdFiller>>;
247
248    fn recommended_fillers() -> Self::RecommendedFillers {
249        Default::default()
250    }
251}