pod_sdk/network/
mod.rs

1use alloy_consensus::{TxEnvelope, TxType, TypedTransaction};
2use alloy_eips::eip2930::AccessList;
3use alloy_network::{
4    BuildResult, Network, NetworkWallet, TransactionBuilder, TransactionBuilderError,
5};
6use alloy_primitives::{Address, Bytes, ChainId, Signature, TxKind, U256};
7use alloy_provider::fillers::{
8    ChainIdFiller, GasFiller, JoinFill, NonceFiller, RecommendedFillers,
9};
10
11pub use pod_types::rpc::receipt::PodReceiptResponse;
12
13use alloy_rpc_types::TransactionRequest;
14use pod_types::Timestamp;
15use serde::{Deserialize, Serialize};
16use std::ops::{Deref, DerefMut};
17
18#[derive(Debug, Clone, Copy)]
19pub struct PodNetwork;
20
21#[derive(Debug, Serialize, Deserialize, Clone)]
22pub struct PodTransactionRequest {
23    #[serde(flatten)]
24    pub inner: TransactionRequest,
25}
26
27impl Default for PodTransactionRequest {
28    fn default() -> Self {
29        let mut inner = TransactionRequest::default();
30        inner.set_max_fee_per_gas(1_000_000_000);
31        inner.set_max_priority_fee_per_gas(0);
32        Self { inner }
33    }
34}
35
36impl Deref for PodTransactionRequest {
37    type Target = TransactionRequest;
38
39    fn deref(&self) -> &Self::Target {
40        &self.inner
41    }
42}
43
44impl DerefMut for PodTransactionRequest {
45    fn deref_mut(&mut self) -> &mut Self::Target {
46        &mut self.inner
47    }
48}
49
50impl From<PodTransactionRequest> for TransactionRequest {
51    fn from(value: PodTransactionRequest) -> Self {
52        value.inner
53    }
54}
55
56impl From<TypedTransaction> for PodTransactionRequest {
57    fn from(value: TypedTransaction) -> Self {
58        Self {
59            inner: value.into(),
60        }
61    }
62}
63
64impl From<TxEnvelope> for PodTransactionRequest {
65    fn from(value: TxEnvelope) -> Self {
66        Self {
67            inner: value.into(),
68        }
69    }
70}
71
72impl TransactionBuilder<PodNetwork> for PodTransactionRequest {
73    fn chain_id(&self) -> Option<ChainId> {
74        self.chain_id
75    }
76
77    fn set_chain_id(&mut self, chain_id: ChainId) {
78        self.chain_id = Some(chain_id);
79    }
80
81    fn nonce(&self) -> Option<u64> {
82        self.nonce
83    }
84
85    fn set_nonce(&mut self, nonce: u64) {
86        self.nonce = Some(nonce);
87    }
88
89    fn take_nonce(&mut self) -> Option<u64> {
90        self.nonce.take()
91    }
92
93    fn input(&self) -> Option<&Bytes> {
94        self.input.input()
95    }
96
97    fn set_input<T: Into<Bytes>>(&mut self, input: T) {
98        self.input.input = Some(input.into());
99    }
100
101    fn from(&self) -> Option<Address> {
102        self.from
103    }
104
105    fn set_from(&mut self, from: Address) {
106        self.from = Some(from);
107    }
108
109    fn kind(&self) -> Option<TxKind> {
110        self.to
111    }
112
113    fn clear_kind(&mut self) {
114        self.to = None;
115    }
116
117    fn set_kind(&mut self, kind: TxKind) {
118        self.to = Some(kind);
119    }
120
121    fn value(&self) -> Option<U256> {
122        self.value
123    }
124
125    fn set_value(&mut self, value: U256) {
126        self.value = Some(value)
127    }
128
129    fn gas_price(&self) -> Option<u128> {
130        self.gas_price
131    }
132
133    fn set_gas_price(&mut self, gas_price: u128) {
134        self.gas_price = Some(gas_price);
135    }
136
137    fn max_fee_per_gas(&self) -> Option<u128> {
138        self.max_fee_per_gas
139    }
140
141    fn set_max_fee_per_gas(&mut self, max_fee_per_gas: u128) {
142        self.max_fee_per_gas = Some(max_fee_per_gas);
143    }
144
145    fn max_priority_fee_per_gas(&self) -> Option<u128> {
146        self.max_priority_fee_per_gas
147    }
148
149    fn set_max_priority_fee_per_gas(&mut self, max_priority_fee_per_gas: u128) {
150        self.max_priority_fee_per_gas = Some(max_priority_fee_per_gas);
151    }
152
153    fn gas_limit(&self) -> Option<u64> {
154        self.gas
155    }
156
157    fn set_gas_limit(&mut self, gas_limit: u64) {
158        self.gas = Some(gas_limit);
159    }
160
161    fn access_list(&self) -> Option<&AccessList> {
162        self.access_list.as_ref()
163    }
164
165    fn set_access_list(&mut self, access_list: AccessList) {
166        self.access_list = Some(access_list);
167    }
168
169    fn complete_type(&self, ty: TxType) -> Result<(), Vec<&'static str>> {
170        match ty {
171            TxType::Eip1559 => self.complete_1559(),
172            _ => unimplemented!(), // Preventing usage of any other except EIP-1559 Tx
173        }
174    }
175
176    fn can_submit(&self) -> bool {
177        // value and data may be None. If they are, they will be set to default.
178        // gas fields and nonce may be None, if they are, they will be populated
179        // with default values by the RPC server
180        self.from.is_some()
181    }
182
183    fn can_build(&self) -> bool {
184        // Only supporting EIP-1559 Transactions
185        self.max_fee_per_gas.is_some() && self.max_priority_fee_per_gas.is_some()
186    }
187
188    #[doc(alias = "output_transaction_type")]
189    fn output_tx_type(&self) -> TxType {
190        TxType::Eip1559
191    }
192
193    #[doc(alias = "output_transaction_type_checked")]
194    fn output_tx_type_checked(&self) -> Option<TxType> {
195        self.buildable_type()
196    }
197
198    fn prep_for_submission(&mut self) {
199        self.transaction_type = Some(self.preferred_type() as u8);
200        self.trim_conflicting_keys();
201        self.populate_blob_hashes();
202    }
203
204    fn build_unsigned(self) -> BuildResult<TypedTransaction, PodNetwork> {
205        if let Err((tx_type, missing)) = self.missing_keys() {
206            return Err(
207                TransactionBuilderError::InvalidTransactionRequest(tx_type, missing)
208                    .into_unbuilt(self),
209            );
210        }
211        Ok(self
212            .inner
213            .build_typed_tx()
214            .expect("checked by missing_keys"))
215    }
216
217    async fn build<W: NetworkWallet<PodNetwork>>(
218        self,
219        wallet: &W,
220    ) -> Result<<PodNetwork as Network>::TxEnvelope, TransactionBuilderError<PodNetwork>> {
221        Ok(wallet.sign_request(self).await?)
222    }
223}
224
225#[derive(Debug, Serialize, Deserialize, Clone)]
226pub struct AttestationData {
227    pub public_key: Address,
228    pub signature: Signature,
229    pub timestamp: Timestamp,
230}
231
232impl Network for PodNetwork {
233    type TxType = TxType;
234    type TxEnvelope = alloy_consensus::TxEnvelope;
235    type UnsignedTx = TypedTransaction;
236    type ReceiptEnvelope = alloy_consensus::ReceiptEnvelope;
237    type Header = alloy_consensus::Header;
238    type TransactionRequest = PodTransactionRequest;
239    type TransactionResponse = alloy_rpc_types::Transaction;
240    type ReceiptResponse = PodReceiptResponse;
241    type HeaderResponse = alloy_rpc_types::Header;
242    type BlockResponse = alloy_rpc_types::Block;
243}
244
245impl RecommendedFillers for PodNetwork {
246    type RecommendedFillers = JoinFill<GasFiller, JoinFill<NonceFiller, ChainIdFiller>>;
247
248    fn recommended_fillers() -> Self::RecommendedFillers {
249        JoinFill::new(
250            GasFiller,
251            JoinFill::new(NonceFiller::default(), ChainIdFiller::default()),
252        )
253    }
254}