1use crate::util::{adapt2, pad_zeros, restore_sender, trim_leading_zeros};
2use crate::{EthereumAddress, EthereumFormat, EthereumNetwork, EthereumPublicKey};
3use anychain_core::{
4 hex, utilities::crypto::keccak256, Transaction, TransactionError, TransactionId,
5};
6use core::{fmt, marker::PhantomData, str::FromStr};
7use ethabi::{ethereum_types::H160, Function, Param, ParamType, StateMutability, Token};
8use ethereum_types::U256;
9use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
10use serde_json::{json, Value};
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13pub struct EthereumTransactionParameters {
14 pub nonce: U256,
15 pub gas_price: U256,
16 pub gas_limit: U256,
17 pub to: EthereumAddress,
18 pub amount: U256,
19 pub data: Vec<u8>,
20}
21
22impl EthereumTransactionParameters {
23 pub fn to_rlp(&self) -> Result<RlpStream, TransactionError> {
24 let to = self
25 .to
26 .to_bytes()
27 .map_err(|e| TransactionError::Message(format!("{}", e)))?;
28
29 let mut rlp = RlpStream::new();
30 rlp.begin_list(9);
31
32 rlp.append(&self.nonce);
33 rlp.append(&self.gas_price);
34 rlp.append(&self.gas_limit);
35 rlp.append(&to);
36 rlp.append(&self.amount);
37 rlp.append(&self.data);
38
39 Ok(rlp)
40 }
41}
42
43#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
44pub struct EthereumTransactionSignature {
45 pub v: u32,
46 pub r: Vec<u8>,
47 pub s: Vec<u8>,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq, Hash)]
51pub struct EthereumTransaction<N: EthereumNetwork> {
52 pub sender: Option<EthereumAddress>,
54 pub params: EthereumTransactionParameters,
56 pub signature: Option<EthereumTransactionSignature>,
58 _network: PhantomData<N>,
59}
60
61impl<N: EthereumNetwork> EthereumTransaction<N> {
62 pub fn restore_sender(&mut self) -> Result<(), TransactionError> {
63 if self.signature.is_none() {
64 return Err(TransactionError::Message(
65 "Signature is missing".to_string(),
66 ));
67 }
68
69 let sig = self.signature.clone().unwrap();
70 self.signature = None;
71
72 let r = sig.r.clone();
73 let s = sig.s.clone();
74
75 let recid = (sig.v - 2 * N::CHAIN_ID - 35) as u8;
76
77 let _sig = [r, s].concat();
78 let msg = self.to_transaction_id()?.txid;
79
80 let sender = restore_sender(msg, _sig, recid)?;
81
82 self.sender = Some(sender);
83 self.signature = Some(sig);
84
85 Ok(())
86 }
87}
88
89impl<N: EthereumNetwork> Transaction for EthereumTransaction<N> {
90 type Address = EthereumAddress;
91 type Format = EthereumFormat;
92 type PublicKey = EthereumPublicKey;
93 type TransactionId = EthereumTransactionId;
94 type TransactionParameters = EthereumTransactionParameters;
95
96 fn new(params: &Self::TransactionParameters) -> Result<Self, TransactionError> {
97 Ok(Self {
98 sender: None,
99 params: params.clone(),
100 signature: None,
101 _network: PhantomData,
102 })
103 }
104
105 fn sign(&mut self, rs: Vec<u8>, recid: u8) -> Result<Vec<u8>, TransactionError> {
106 if rs.len() != 64 {
107 return Err(TransactionError::Message(format!(
108 "Invalid signature length: {}",
109 rs.len()
110 )));
111 }
112 let v = 2 * N::CHAIN_ID + 35 + (recid as u32);
113 let r = rs[..32].to_vec();
114 let s = rs[32..].to_vec();
115 self.signature = Some(EthereumTransactionSignature { v, r, s });
116 self.to_bytes()
117 }
118
119 fn to_bytes(&self) -> Result<Vec<u8>, TransactionError> {
120 match &self.signature {
121 Some(sig) => {
122 let mut rlp = self.params.to_rlp()?;
123 let r = trim_leading_zeros(&sig.r);
124 let s = trim_leading_zeros(&sig.s);
125 rlp.append(&sig.v);
126 rlp.append(&r);
127 rlp.append(&s);
128 Ok(rlp.out().to_vec())
129 }
130 None => {
131 let mut rlp = self.params.to_rlp()?;
132 rlp.append(&N::CHAIN_ID);
133 rlp.append(&0u8);
134 rlp.append(&0u8);
135 Ok(rlp.out().to_vec())
136 }
137 }
138 }
139
140 fn from_bytes(tx: &[u8]) -> Result<Self, TransactionError> {
141 let rlp = Rlp::new(tx);
142
143 let to = adapt2(rlp.val_at::<Vec<u8>>(3))?;
144 let to = hex::encode(to);
145
146 let nonce = adapt2(rlp.val_at::<U256>(0))?;
147 let gas_price = adapt2(rlp.val_at::<U256>(1))?;
148 let gas_limit = adapt2(rlp.val_at::<U256>(2))?;
149 let to = EthereumAddress::from_str(&to)?;
150 let amount = adapt2(rlp.val_at::<U256>(4))?;
151 let data = adapt2(rlp.val_at::<Vec<u8>>(5))?;
152
153 let v = adapt2(rlp.val_at::<u32>(6))?;
154 let mut r = adapt2(rlp.val_at::<Vec<u8>>(7))?;
155 let mut s = adapt2(rlp.val_at::<Vec<u8>>(8))?;
156
157 let params = EthereumTransactionParameters {
158 nonce,
159 gas_price,
160 gas_limit,
161 to,
162 amount,
163 data,
164 };
165
166 let mut tx = EthereumTransaction::<N>::new(¶ms)?;
167
168 if !r.is_empty() && !s.is_empty() {
169 pad_zeros(&mut r, 32);
170 pad_zeros(&mut s, 32);
171 let sig = EthereumTransactionSignature { v, r, s };
172 tx.signature = Some(sig);
173 tx.restore_sender()?;
174 }
175
176 Ok(tx)
177 }
178
179 fn to_transaction_id(&self) -> Result<Self::TransactionId, TransactionError> {
180 Ok(Self::TransactionId {
181 txid: keccak256(&self.to_bytes()?).to_vec(),
182 })
183 }
184}
185
186impl<N: EthereumNetwork> FromStr for EthereumTransaction<N> {
187 type Err = TransactionError;
188
189 fn from_str(tx: &str) -> Result<Self, Self::Err> {
190 let tx = match &tx[..2] {
191 "0x" => &tx[2..],
192 _ => tx,
193 };
194 Self::from_bytes(&hex::decode(tx)?)
195 }
196}
197
198impl<N: EthereumNetwork> fmt::Display for EthereumTransaction<N> {
199 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
200 write!(
201 f,
202 "0x{}",
203 &hex::encode(match self.to_bytes() {
204 Ok(transaction) => transaction,
205 _ => return Err(fmt::Error),
206 })
207 )
208 }
209}
210
211#[derive(Debug, Clone, PartialEq, Eq, Hash)]
212pub struct Eip1559TransactionParameters {
213 pub chain_id: u32,
214 pub nonce: U256,
215 pub max_priority_fee_per_gas: U256,
216 pub max_fee_per_gas: U256,
217 pub gas_limit: U256,
218 pub to: EthereumAddress,
219 pub amount: U256,
220 pub data: Vec<u8>,
221 pub access_list: Vec<AccessItem>,
222}
223
224impl Eip1559TransactionParameters {
225 pub fn to_rlp(&self, array_len: usize) -> Result<RlpStream, TransactionError> {
226 let to = self
227 .to
228 .to_bytes()
229 .map_err(|e| TransactionError::Message(format!("{}", e)))?;
230
231 let mut rlp = RlpStream::new();
232 rlp.begin_list(array_len);
233
234 rlp.append(&self.chain_id);
235 rlp.append(&self.nonce);
236 rlp.append(&self.max_priority_fee_per_gas);
237 rlp.append(&self.max_fee_per_gas);
238 rlp.append(&self.gas_limit);
239 rlp.append(&to);
240 rlp.append(&self.amount);
241 rlp.append(&self.data);
242 rlp.append_list(&self.access_list);
243
244 Ok(rlp)
245 }
246}
247
248#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
249pub struct Eip1559TransactionSignature {
250 pub y_parity: bool,
251 pub r: Vec<u8>,
252 pub s: Vec<u8>,
253}
254
255#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
256pub struct AccessItem {
257 pub address: EthereumAddress,
258 pub storage_keys: Vec<Vec<u8>>,
259}
260
261impl Encodable for AccessItem {
262 fn rlp_append(&self, s: &mut RlpStream) {
263 s.begin_list(2);
264 s.append(&self.address.to_bytes().unwrap());
265 s.append_list::<Vec<u8>, Vec<u8>>(&self.storage_keys);
266 }
267}
268
269impl Decodable for AccessItem {
270 fn decode(rlp: &rlp::Rlp) -> Result<Self, DecoderError> {
271 let address = hex::encode(rlp.val_at::<Vec<u8>>(0)?);
272 let address = EthereumAddress::from_str(&address).unwrap();
273 let storage_keys = rlp.list_at::<Vec<u8>>(1)?;
274 Ok(Self {
275 address,
276 storage_keys,
277 })
278 }
279}
280
281#[derive(Debug, Clone, PartialEq, Eq, Hash)]
282pub struct Eip1559Transaction<N: EthereumNetwork> {
283 pub sender: Option<EthereumAddress>,
284 pub params: Eip1559TransactionParameters,
285 pub signature: Option<Eip1559TransactionSignature>,
286 _network: PhantomData<N>,
287}
288
289impl<N: EthereumNetwork> Eip1559Transaction<N> {
290 pub fn restore_sender(&mut self) -> Result<(), TransactionError> {
291 if self.signature.is_none() {
292 return Err(TransactionError::Message(
293 "Signature is missing".to_string(),
294 ));
295 }
296
297 let sig = self.signature.clone().unwrap();
298 self.signature = None;
299
300 let recid = match sig.y_parity {
301 true => 1,
302 false => 0,
303 } as u8;
304
305 let _sig = [sig.r.clone(), sig.s.clone()].concat();
306 let msg = self.to_transaction_id()?.txid;
307
308 let sender = restore_sender(msg, _sig, recid)?;
309
310 self.sender = Some(sender);
311 self.signature = Some(sig);
312
313 Ok(())
314 }
315}
316
317impl<N: EthereumNetwork> Transaction for Eip1559Transaction<N> {
318 type Address = EthereumAddress;
319 type Format = EthereumFormat;
320 type PublicKey = EthereumPublicKey;
321 type TransactionId = EthereumTransactionId;
322 type TransactionParameters = Eip1559TransactionParameters;
323
324 fn new(params: &Self::TransactionParameters) -> Result<Self, TransactionError> {
325 Ok(Self {
326 sender: None,
327 params: params.clone(),
328 signature: None,
329 _network: PhantomData,
330 })
331 }
332
333 fn sign(&mut self, rs: Vec<u8>, recid: u8) -> Result<Vec<u8>, TransactionError> {
334 if rs.len() != 64 {
335 return Err(TransactionError::Message(format!(
336 "Invalid signature length: {}",
337 rs.len()
338 )));
339 }
340 let y_parity = recid == 1;
341 let r = rs[..32].to_vec();
342 let s = rs[32..].to_vec();
343 self.signature = Some(Eip1559TransactionSignature { y_parity, r, s });
344 self.to_bytes()
345 }
346
347 fn to_bytes(&self) -> Result<Vec<u8>, TransactionError> {
348 let rlp = match &self.signature {
349 Some(sig) => {
350 let mut rlp = self.params.to_rlp(12)?;
351 let r = trim_leading_zeros(&sig.r);
352 let s = trim_leading_zeros(&sig.s);
353 rlp.append(&sig.y_parity);
354 rlp.append(&r);
355 rlp.append(&s);
356 rlp.out().to_vec()
357 }
358 None => self.params.to_rlp(9)?.out().to_vec(),
359 };
360 Ok([vec![2u8], rlp].concat())
361 }
362
363 fn from_bytes(tx: &[u8]) -> Result<Self, TransactionError> {
364 let rlp = Rlp::new(&tx[1..]);
365
366 let to = adapt2(rlp.val_at::<Vec<u8>>(5))?;
367 let to = hex::encode(to);
368
369 let chain_id = adapt2(rlp.val_at::<u32>(0))?;
370 let nonce = adapt2(rlp.val_at::<U256>(1))?;
371 let max_priority_fee_per_gas = adapt2(rlp.val_at::<U256>(2))?;
372 let max_fee_per_gas = adapt2(rlp.val_at::<U256>(3))?;
373 let gas_limit = adapt2(rlp.val_at::<U256>(4))?;
374 let to = EthereumAddress::from_str(&to)?;
375 let amount = adapt2(rlp.val_at::<U256>(6))?;
376 let data = adapt2(rlp.val_at::<Vec<u8>>(7))?;
377 let access_list = adapt2(rlp.list_at::<AccessItem>(8))?;
378
379 let y_parity = adapt2(rlp.val_at::<bool>(9))?;
380 let mut r = adapt2(rlp.val_at::<Vec<u8>>(10))?;
381 let mut s = adapt2(rlp.val_at::<Vec<u8>>(11))?;
382
383 let params = Eip1559TransactionParameters {
384 chain_id,
385 nonce,
386 max_priority_fee_per_gas,
387 max_fee_per_gas,
388 gas_limit,
389 to,
390 amount,
391 data,
392 access_list,
393 };
394
395 let mut tx = Eip1559Transaction::<N>::new(¶ms)?;
396
397 if !r.is_empty() && !s.is_empty() {
398 pad_zeros(&mut r, 32);
399 pad_zeros(&mut s, 32);
400 let sig = Eip1559TransactionSignature { y_parity, r, s };
401 tx.signature = Some(sig);
402 tx.restore_sender()?;
403 }
404
405 Ok(tx)
406 }
407
408 fn to_transaction_id(&self) -> Result<Self::TransactionId, TransactionError> {
409 Ok(Self::TransactionId {
410 txid: keccak256(&self.to_bytes()?).to_vec(),
411 })
412 }
413}
414
415impl<N: EthereumNetwork> FromStr for Eip1559Transaction<N> {
416 type Err = TransactionError;
417
418 fn from_str(tx: &str) -> Result<Self, Self::Err> {
419 let tx = match &tx[..2] {
420 "0x" => &tx[2..],
421 _ => tx,
422 };
423 Self::from_bytes(&hex::decode(tx)?)
424 }
425}
426
427impl<N: EthereumNetwork> fmt::Display for Eip1559Transaction<N> {
428 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
429 write!(
430 f,
431 "0x{}",
432 &hex::encode(match self.to_bytes() {
433 Ok(transaction) => transaction,
434 _ => return Err(fmt::Error),
435 })
436 )
437 }
438}
439
440#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
441pub struct EthereumTransactionId {
442 pub txid: Vec<u8>,
443}
444
445impl TransactionId for EthereumTransactionId {}
446
447impl fmt::Display for EthereumTransactionId {
448 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
449 write!(f, "0x{}", hex::encode(&self.txid))
450 }
451}
452
453pub fn encode_transfer(func_name: &str, address: &EthereumAddress, amount: U256) -> Vec<u8> {
454 #[allow(deprecated)]
455 let func = Function {
456 name: func_name.to_string(),
457 inputs: vec![
458 Param {
459 name: "address".to_string(),
460 kind: ParamType::Address,
461 internal_type: None,
462 },
463 Param {
464 name: "amount".to_string(),
465 kind: ParamType::Uint(256),
466 internal_type: None,
467 },
468 ],
469 outputs: vec![],
470 constant: None,
471 state_mutability: StateMutability::Payable,
472 };
473
474 let tokens = vec![
475 Token::Address(H160::from_slice(&address.to_bytes().unwrap())),
476 Token::Uint(amount),
477 ];
478
479 func.encode_input(&tokens).unwrap()
480}
481
482pub fn decode_transfer(data: Vec<u8>) -> Result<Value, TransactionError> {
483 if data.len() < 4 {
484 return Err(TransactionError::Message("Illegal data".to_string()));
485 }
486
487 let selector = &data[..4];
488
489 match selector {
490 [169, 5, 156, 187] => {
492 #[allow(deprecated)]
493 let func = Function {
494 name: "transfer".to_string(),
495 inputs: vec![
496 Param {
497 name: "to".to_string(),
498 kind: ParamType::Address,
499 internal_type: None,
500 },
501 Param {
502 name: "amount".to_string(),
503 kind: ParamType::Uint(256),
504 internal_type: None,
505 },
506 ],
507 outputs: vec![],
508 constant: None,
509 state_mutability: StateMutability::Payable,
510 };
511 match func.decode_input(&data[4..]) {
512 Ok(tokens) => {
513 let to = hex::encode(tokens[0].clone().into_address().unwrap().as_bytes());
514 let amount = tokens[1].clone().into_uint().unwrap();
515 Ok(json!({
516 "function": "transfer",
517 "params": {
518 "to": to,
519 "amount": amount.to_string(),
520 }
521 }))
522 }
523 Err(e) => Err(TransactionError::Message(e.to_string())),
524 }
525 }
526 _ => Err(TransactionError::Message(
527 "Unsupported contract function".to_string(),
528 )),
529 }
530}
531
532