ethers_types_rs/request/
legacy.rs

1use ethabi::ethereum_types::{H256, U256, U64};
2use ethers_hash_rs::keccak256;
3use rlp::{Encodable, RlpStream};
4use serde::{Deserialize, Serialize};
5
6use super::rlp_opt;
7
8use crate::block::Bytecode;
9use crate::signature::SignatureVRS;
10use crate::Address;
11use crate::Signature;
12
13#[derive(Debug, Serialize, Deserialize, Clone, Default)]
14#[serde(rename_all = "camelCase")]
15pub struct LegacyTransactionRequest {
16    /// Transaction nonce
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub nonce: Option<U256>,
19    /// Gas price
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub gas_price: Option<U256>,
22    /// Supplied gas
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub gas: Option<U256>,
25    /// Recipient address (None for contract creation)
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub to: Option<Address>,
28    /// Transferred value
29    pub value: Option<U256>,
30    /// The compiled code of a contract OR the first 4 bytes of the hash of the
31    /// invoked method signature and encoded parameters. For details see Ethereum Contract ABI
32    #[serde(skip_serializing_if = "Option::is_none")]
33    pub data: Option<Bytecode>,
34    /// Chain id for EIP-155
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub chain_id: Option<U64>,
37}
38
39impl Encodable for LegacyTransactionRequest {
40    fn rlp_append(&self, s: &mut RlpStream) {
41        s.begin_unbounded_list();
42
43        self.rlp_base(s);
44
45        // EIP-155 suggest encoding fields
46        // rlp_opt(s, &self.chain_id);
47        s.append(&self.chain_id.unwrap());
48        s.append(&0u8);
49        s.append(&0u8);
50        s.finalize_unbounded_list();
51    }
52}
53
54impl LegacyTransactionRequest {
55    /// Generate legacy transaction sign hash.
56    pub fn sign_hash(&self) -> H256 {
57        keccak256(self.rlp()).into()
58    }
59
60    pub fn rlp(&self) -> Bytecode {
61        let mut s = rlp::RlpStream::new();
62
63        self.rlp_append(&mut s);
64
65        s.out().freeze().to_vec().into()
66    }
67
68    pub(crate) fn rlp_base(&self, rlp: &mut RlpStream) {
69        rlp_opt(rlp, &self.nonce);
70        rlp_opt(rlp, &self.gas_price);
71        rlp_opt(rlp, &self.gas);
72
73        rlp_opt(rlp, &self.to);
74        rlp_opt(rlp, &self.value);
75        rlp_opt(rlp, &self.data);
76
77        // rlp.append(&self.to);
78        // rlp.append(&self.value);
79        // rlp.append(&self.input);
80    }
81
82    /// Returns signed tx rlp encoding stream.
83    pub fn rlp_signed(&self, signature: Signature) -> Bytecode {
84        let mut rlp = rlp::RlpStream::new();
85
86        rlp.begin_unbounded_list();
87
88        self.rlp_base(&mut rlp);
89
90        // encode v,r,s
91        let chain_id: u64 = self.chain_id.unwrap_or(Default::default()).as_u64();
92
93        let v = signature.v() as u64 + 35 + chain_id * 2;
94
95        rlp.append(&v);
96        rlp.append(&signature.r());
97        rlp.append(&signature.s());
98
99        rlp.finalize_unbounded_list();
100
101        rlp.out().freeze().to_vec().into()
102    }
103}