1#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(unused_crate_dependencies)]
20
21extern crate alloc;
22
23use alloc::vec::Vec;
24pub use ethereum::{
25 AccessListItem, AuthorizationList, AuthorizationListItem, BlockV3 as Block,
26 LegacyTransactionMessage, Log, ReceiptV4 as Receipt, TransactionAction,
27 TransactionV3 as Transaction,
28};
29use ethereum_types::{H160, H256, U256};
30use fp_evm::{CallOrCreateInfo, CheckEvmTransactionInput};
31use frame_support::dispatch::{DispatchErrorWithPostInfo, PostDispatchInfo};
32use scale_codec::{Decode, Encode};
33
34pub trait ValidatedTransaction {
35 fn apply(
36 source: H160,
37 transaction: Transaction,
38 ) -> Result<(PostDispatchInfo, CallOrCreateInfo), DispatchErrorWithPostInfo>;
39}
40
41#[derive(Clone, Debug, Eq, PartialEq, Encode, Decode)]
42pub struct TransactionData {
43 pub action: TransactionAction,
44 pub input: Vec<u8>,
45 pub nonce: U256,
46 pub gas_limit: U256,
47 pub gas_price: Option<U256>,
48 pub max_fee_per_gas: Option<U256>,
49 pub max_priority_fee_per_gas: Option<U256>,
50 pub value: U256,
51 pub chain_id: Option<u64>,
52 pub access_list: Vec<(H160, Vec<H256>)>,
53 pub authorization_list: AuthorizationList,
54}
55
56impl TransactionData {
57 #[allow(clippy::too_many_arguments)]
58 pub fn new(
59 action: TransactionAction,
60 input: Vec<u8>,
61 nonce: U256,
62 gas_limit: U256,
63 gas_price: Option<U256>,
64 max_fee_per_gas: Option<U256>,
65 max_priority_fee_per_gas: Option<U256>,
66 value: U256,
67 chain_id: Option<u64>,
68 access_list: Vec<(H160, Vec<H256>)>,
69 authorization_list: AuthorizationList,
70 ) -> Self {
71 Self {
72 action,
73 input,
74 nonce,
75 gas_limit,
76 gas_price,
77 max_fee_per_gas,
78 max_priority_fee_per_gas,
79 value,
80 chain_id,
81 access_list,
82 authorization_list,
83 }
84 }
85
86 pub fn proof_size_base_cost(&self) -> u64 {
88 self.encode()
89 .len()
90 .saturating_add(65)
92 .saturating_add(1)
94 .saturating_add(1) as u64
96 }
97}
98
99impl From<TransactionData> for CheckEvmTransactionInput {
100 fn from(t: TransactionData) -> Self {
101 CheckEvmTransactionInput {
102 to: if let TransactionAction::Call(to) = t.action {
103 Some(to)
104 } else {
105 None
106 },
107 chain_id: t.chain_id,
108 input: t.input,
109 nonce: t.nonce,
110 gas_limit: t.gas_limit,
111 gas_price: t.gas_price,
112 max_fee_per_gas: t.max_fee_per_gas,
113 max_priority_fee_per_gas: t.max_priority_fee_per_gas,
114 value: t.value,
115 access_list: t.access_list,
116 authorization_list: t
117 .authorization_list
118 .iter()
119 .map(|d| {
120 (
121 d.chain_id.into(),
122 d.address,
123 d.nonce,
124 d.authorizing_address().ok(),
125 )
126 })
127 .collect(),
128 }
129 }
130}
131
132impl From<&Transaction> for TransactionData {
133 fn from(t: &Transaction) -> Self {
134 match t {
135 Transaction::Legacy(t) => TransactionData {
136 action: t.action,
137 input: t.input.clone(),
138 nonce: t.nonce,
139 gas_limit: t.gas_limit,
140 gas_price: Some(t.gas_price),
141 max_fee_per_gas: None,
142 max_priority_fee_per_gas: None,
143 value: t.value,
144 chain_id: t.signature.chain_id(),
145 access_list: Vec::new(),
146 authorization_list: Vec::new(),
147 },
148 Transaction::EIP2930(t) => TransactionData {
149 action: t.action,
150 input: t.input.clone(),
151 nonce: t.nonce,
152 gas_limit: t.gas_limit,
153 gas_price: Some(t.gas_price),
154 max_fee_per_gas: None,
155 max_priority_fee_per_gas: None,
156 value: t.value,
157 chain_id: Some(t.chain_id),
158 access_list: t
159 .access_list
160 .iter()
161 .map(|d| (d.address, d.storage_keys.clone()))
162 .collect(),
163 authorization_list: Vec::new(),
164 },
165 Transaction::EIP1559(t) => TransactionData {
166 action: t.action,
167 input: t.input.clone(),
168 nonce: t.nonce,
169 gas_limit: t.gas_limit,
170 gas_price: None,
171 max_fee_per_gas: Some(t.max_fee_per_gas),
172 max_priority_fee_per_gas: Some(t.max_priority_fee_per_gas),
173 value: t.value,
174 chain_id: Some(t.chain_id),
175 access_list: t
176 .access_list
177 .iter()
178 .map(|d| (d.address, d.storage_keys.clone()))
179 .collect(),
180 authorization_list: Vec::new(),
181 },
182 Transaction::EIP7702(t) => TransactionData {
183 action: t.destination,
184 input: t.data.clone(),
185 nonce: t.nonce,
186 gas_limit: t.gas_limit,
187 gas_price: None,
188 max_fee_per_gas: Some(t.max_fee_per_gas),
189 max_priority_fee_per_gas: Some(t.max_priority_fee_per_gas),
190 value: t.value,
191 chain_id: Some(t.chain_id),
192 access_list: t
193 .access_list
194 .iter()
195 .map(|d| (d.address, d.storage_keys.clone()))
196 .collect(),
197 authorization_list: t.authorization_list.clone(),
198 },
199 }
200 }
201}