1use super::AuthorizationListItem;
2use crate::{
3 bytes::Bytes, transaction::AccessList, AccessListItem, Action,
4 AuthorizationList, SignedTransaction, Transaction,
5 TransactionWithSignature, TransactionWithSignatureSerializePart,
6};
7use cfx_types::{AddressWithSpace, H256, U256};
8use cfxkey::Address;
9use rlp::{Encodable, RlpStream};
10use rlp_derive::{RlpDecodable, RlpEncodable};
11use serde_derive::{Deserialize, Serialize};
12
13impl Eip155Transaction {
14 pub fn fake_sign_phantom(
19 self, from: AddressWithSpace,
20 ) -> SignedTransaction {
21 SignedTransaction {
22 transaction: TransactionWithSignature {
23 transaction: TransactionWithSignatureSerializePart {
24 unsigned: Transaction::Ethereum(
25 EthereumTransaction::Eip155(self),
26 ),
27 r: U256::from(from.address.as_ref()),
32 s: U256::from(from.address.as_ref()),
33 v: 0,
34 },
35 hash: H256::zero(),
36 rlp_size: None,
37 }
38 .compute_hash(),
39 sender: from.address,
40 public: None,
41 }
42 }
43
44 pub fn fake_sign_rpc(self, from: AddressWithSpace) -> SignedTransaction {
48 SignedTransaction {
49 transaction: TransactionWithSignature {
50 transaction: TransactionWithSignatureSerializePart {
51 unsigned: Transaction::Ethereum(
52 EthereumTransaction::Eip155(self),
53 ),
54 r: U256::one(),
55 s: U256::one(),
56 v: 0,
57 },
58 hash: H256::zero(),
59 rlp_size: None,
60 }
61 .compute_hash(),
62 sender: from.address,
63 public: None,
64 }
65 }
66}
67
68#[derive(Default, Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
69pub struct Eip155Transaction {
70 pub nonce: U256,
72 pub gas_price: U256,
74 pub gas: U256,
76 pub action: Action,
78 pub value: U256,
80 pub chain_id: Option<u32>,
82 pub data: Bytes,
84}
85
86impl Encodable for Eip155Transaction {
87 fn rlp_append(&self, s: &mut RlpStream) {
88 match self.chain_id {
89 Some(chain_id) => {
90 s.begin_list(9);
91 s.append(&self.nonce);
92 s.append(&self.gas_price);
93 s.append(&self.gas);
94 s.append(&self.action);
95 s.append(&self.value);
96 s.append(&self.data);
97 s.append(&chain_id);
98 s.append(&0u8);
99 s.append(&0u8);
100 }
101 None => {
102 s.begin_list(6);
103 s.append(&self.nonce);
104 s.append(&self.gas_price);
105 s.append(&self.gas);
106 s.append(&self.action);
107 s.append(&self.value);
108 s.append(&self.data);
109 }
110 }
111 }
112}
113
114#[derive(
115 Default,
116 Debug,
117 Clone,
118 PartialEq,
119 Eq,
120 Serialize,
121 Deserialize,
122 RlpEncodable,
123 RlpDecodable,
124)]
125pub struct Eip2930Transaction {
126 pub chain_id: u32,
127 pub nonce: U256,
128 pub gas_price: U256,
129 pub gas: U256,
130 pub action: Action,
131 pub value: U256,
132 pub data: Bytes,
133 pub access_list: Vec<AccessListItem>,
134}
135
136#[derive(
137 Default,
138 Debug,
139 Clone,
140 PartialEq,
141 Eq,
142 Serialize,
143 Deserialize,
144 RlpEncodable,
145 RlpDecodable,
146)]
147pub struct Eip1559Transaction {
148 pub chain_id: u32,
149 pub nonce: U256,
150 pub max_priority_fee_per_gas: U256,
151 pub max_fee_per_gas: U256,
152 pub gas: U256,
153 pub action: Action,
154 pub value: U256,
155 pub data: Bytes,
156 pub access_list: Vec<AccessListItem>,
157}
158
159#[derive(
160 Default,
161 Debug,
162 Clone,
163 PartialEq,
164 Eq,
165 Serialize,
166 Deserialize,
167 RlpEncodable,
168 RlpDecodable,
169)]
170pub struct Eip7702Transaction {
171 pub chain_id: u32,
172 pub nonce: U256,
173 pub max_priority_fee_per_gas: U256,
174 pub max_fee_per_gas: U256,
175 pub gas: U256,
176 pub destination: Address,
177 pub value: U256,
178 pub data: Bytes,
179 pub access_list: Vec<AccessListItem>,
180 pub authorization_list: Vec<AuthorizationListItem>,
181}
182
183#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
184pub enum EthereumTransaction {
185 Eip155(Eip155Transaction),
186 Eip1559(Eip1559Transaction),
187 Eip2930(Eip2930Transaction),
188 Eip7702(Eip7702Transaction),
189}
190use EthereumTransaction::*;
191
192impl EthereumTransaction {
193 pub fn fake_sign_rpc(self, from: AddressWithSpace) -> SignedTransaction {
194 SignedTransaction {
195 transaction: TransactionWithSignature {
196 transaction: TransactionWithSignatureSerializePart {
197 unsigned: Transaction::Ethereum(self),
198 r: U256::one(),
199 s: U256::one(),
200 v: 0,
201 },
202 hash: H256::zero(),
203 rlp_size: None,
204 }
205 .compute_hash(),
206 sender: from.address,
207 public: None,
208 }
209 }
210}
211
212macro_rules! eth_access_common_ref {
213 ($field:ident, $ty:ty) => {
214 pub fn $field(&self) -> &$ty {
215 match self {
216 EthereumTransaction::Eip155(tx) => &tx.$field,
217 EthereumTransaction::Eip2930(tx) => &tx.$field,
218 EthereumTransaction::Eip1559(tx) => &tx.$field,
219 EthereumTransaction::Eip7702(tx) => &tx.$field,
220 }
221 }
222 };
223}
224
225impl EthereumTransaction {
226 eth_access_common_ref!(gas, U256);
227
228 eth_access_common_ref!(data, Bytes);
229
230 eth_access_common_ref!(nonce, U256);
231
232 eth_access_common_ref!(value, U256);
233
234 pub fn action(&self) -> Action {
235 match self {
236 Eip155(tx) => tx.action,
237 Eip1559(tx) => tx.action,
238 Eip2930(tx) => tx.action,
239 Eip7702(tx) => Action::Call(tx.destination),
240 }
241 }
242
243 pub fn gas_price(&self) -> &U256 {
244 match self {
245 Eip155(tx) => &tx.gas_price,
246 Eip1559(tx) => &tx.max_fee_per_gas,
247 Eip2930(tx) => &tx.gas_price,
248 Eip7702(tx) => &tx.max_fee_per_gas,
249 }
250 }
251
252 pub fn max_priority_gas_price(&self) -> &U256 {
253 match self {
254 Eip155(tx) => &tx.gas_price,
255 Eip1559(tx) => &tx.max_priority_fee_per_gas,
256 Eip2930(tx) => &tx.gas_price,
257 Eip7702(tx) => &tx.max_priority_fee_per_gas,
258 }
259 }
260
261 pub fn chain_id(&self) -> Option<u32> {
262 match self {
263 Eip155(tx) => tx.chain_id,
264 Eip1559(tx) => Some(tx.chain_id),
265 Eip2930(tx) => Some(tx.chain_id),
266 Eip7702(tx) => Some(tx.chain_id),
267 }
268 }
269
270 pub fn nonce_mut(&mut self) -> &mut U256 {
271 match self {
272 Eip155(tx) => &mut tx.nonce,
273 Eip2930(tx) => &mut tx.nonce,
274 Eip1559(tx) => &mut tx.nonce,
275 Eip7702(tx) => &mut tx.nonce,
276 }
277 }
278
279 pub fn data_mut(&mut self) -> &mut Vec<u8> {
280 match self {
281 Eip155(tx) => &mut tx.data,
282 Eip2930(tx) => &mut tx.data,
283 Eip1559(tx) => &mut tx.data,
284 Eip7702(tx) => &mut tx.data,
285 }
286 }
287
288 pub fn access_list(&self) -> Option<&AccessList> {
289 match self {
290 Eip155(_tx) => None,
291 Eip2930(tx) => Some(&tx.access_list),
292 Eip1559(tx) => Some(&tx.access_list),
293 Eip7702(tx) => Some(&tx.access_list),
294 }
295 }
296
297 pub fn authorization_list(&self) -> Option<&AuthorizationList> {
298 if let Eip7702(tx) = self {
299 Some(&tx.authorization_list)
300 } else {
301 None
302 }
303 }
304}
305
306pub mod eip155_signature {
308 pub fn add_chain_replay_protection(v: u8, chain_id: Option<u64>) -> u64 {
310 v as u64
311 + if let Some(n) = chain_id {
312 35 + n * 2
313 } else {
314 27
315 }
316 }
317
318 pub fn extract_standard_v(v: u64) -> u8 {
322 match v {
323 v if v == 27 => 0,
324 v if v == 28 => 1,
325 v if v >= 35 => ((v - 1) % 2) as u8,
326 _ => 4,
327 }
328 }
329
330 pub fn extract_chain_id_from_legacy_v(v: u64) -> Option<u64> {
331 if v >= 35 {
332 Some((v - 35) / 2 as u64)
333 } else {
334 None
335 }
336 }
337}