anychain_ethereum/transaction/
legacy.rs1use super::EthereumTransactionId;
2use crate::util::{adapt2, pad_zeros, restore_sender, trim_leading_zeros};
3use crate::{EthereumAddress, EthereumFormat, EthereumNetwork, EthereumPublicKey};
4use anychain_core::{hex, utilities::crypto::keccak256, Transaction, TransactionError};
5use core::{fmt, marker::PhantomData, str::FromStr};
6use ethereum_types::U256;
7use rlp::{Rlp, RlpStream};
8
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10pub struct EthereumTransactionParameters {
11 pub nonce: U256,
12 pub gas_price: U256,
13 pub gas_limit: U256,
14 pub to: EthereumAddress,
15 pub amount: U256,
16 pub data: Vec<u8>,
17}
18
19impl EthereumTransactionParameters {
20 pub fn to_rlp(&self) -> Result<RlpStream, TransactionError> {
21 let to = self
22 .to
23 .to_bytes()
24 .map_err(|e| TransactionError::Message(format!("{}", e)))?;
25
26 let mut rlp = RlpStream::new();
27 rlp.begin_list(9);
28
29 rlp.append(&self.nonce);
30 rlp.append(&self.gas_price);
31 rlp.append(&self.gas_limit);
32 rlp.append(&to);
33 rlp.append(&self.amount);
34 rlp.append(&self.data);
35
36 Ok(rlp)
37 }
38}
39
40#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
41pub struct EthereumTransactionSignature {
42 pub v: u32,
43 pub r: Vec<u8>,
44 pub s: Vec<u8>,
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash)]
48pub struct EthereumTransaction<N: EthereumNetwork> {
49 pub sender: Option<EthereumAddress>,
51 pub params: EthereumTransactionParameters,
53 pub signature: Option<EthereumTransactionSignature>,
55 _network: PhantomData<N>,
56}
57
58impl<N: EthereumNetwork> EthereumTransaction<N> {
59 pub fn restore_sender(&mut self) -> Result<(), TransactionError> {
60 if self.signature.is_none() {
61 return Err(TransactionError::Message(
62 "Signature is missing".to_string(),
63 ));
64 }
65
66 let sig = self.signature.clone().unwrap();
67 self.signature = None;
68
69 let r = sig.r.clone();
70 let s = sig.s.clone();
71
72 let recid = (sig.v - 2 * N::CHAIN_ID - 35) as u8;
73
74 let _sig = [r, s].concat();
75 let msg = self.to_transaction_id()?.txid;
76
77 let sender = restore_sender(msg, _sig, recid)?;
78
79 self.sender = Some(sender);
80 self.signature = Some(sig);
81
82 Ok(())
83 }
84}
85
86impl<N: EthereumNetwork> Transaction for EthereumTransaction<N> {
87 type Address = EthereumAddress;
88 type Format = EthereumFormat;
89 type PublicKey = EthereumPublicKey;
90 type TransactionId = EthereumTransactionId;
91 type TransactionParameters = EthereumTransactionParameters;
92
93 fn new(params: &Self::TransactionParameters) -> Result<Self, TransactionError> {
94 Ok(Self {
95 sender: None,
96 params: params.clone(),
97 signature: None,
98 _network: PhantomData,
99 })
100 }
101
102 fn sign(&mut self, rs: Vec<u8>, recid: u8) -> Result<Vec<u8>, TransactionError> {
103 if rs.len() != 64 {
104 return Err(TransactionError::Message(format!(
105 "Invalid signature length: {}",
106 rs.len()
107 )));
108 }
109 let v = 2 * N::CHAIN_ID + 35 + (recid as u32);
110 let r = rs[..32].to_vec();
111 let s = rs[32..].to_vec();
112 self.signature = Some(EthereumTransactionSignature { v, r, s });
113 self.to_bytes()
114 }
115
116 fn to_bytes(&self) -> Result<Vec<u8>, TransactionError> {
117 match &self.signature {
118 Some(sig) => {
119 let mut rlp = self.params.to_rlp()?;
120 let r = trim_leading_zeros(&sig.r);
121 let s = trim_leading_zeros(&sig.s);
122 rlp.append(&sig.v);
123 rlp.append(&r);
124 rlp.append(&s);
125 Ok(rlp.out().to_vec())
126 }
127 None => {
128 let mut rlp = self.params.to_rlp()?;
129 rlp.append(&N::CHAIN_ID);
130 rlp.append(&0u8);
131 rlp.append(&0u8);
132 Ok(rlp.out().to_vec())
133 }
134 }
135 }
136
137 fn from_bytes(tx: &[u8]) -> Result<Self, TransactionError> {
138 let rlp = Rlp::new(tx);
139
140 let to = adapt2(rlp.val_at::<Vec<u8>>(3))?;
141 let to = hex::encode(to);
142
143 let nonce = adapt2(rlp.val_at::<U256>(0))?;
144 let gas_price = adapt2(rlp.val_at::<U256>(1))?;
145 let gas_limit = adapt2(rlp.val_at::<U256>(2))?;
146 let to = EthereumAddress::from_str(&to)?;
147 let amount = adapt2(rlp.val_at::<U256>(4))?;
148 let data = adapt2(rlp.val_at::<Vec<u8>>(5))?;
149
150 let v = adapt2(rlp.val_at::<u32>(6))?;
151 let mut r = adapt2(rlp.val_at::<Vec<u8>>(7))?;
152 let mut s = adapt2(rlp.val_at::<Vec<u8>>(8))?;
153
154 let params = EthereumTransactionParameters {
155 nonce,
156 gas_price,
157 gas_limit,
158 to,
159 amount,
160 data,
161 };
162
163 let mut tx = EthereumTransaction::<N>::new(¶ms)?;
164
165 if !r.is_empty() && !s.is_empty() {
166 pad_zeros(&mut r, 32);
167 pad_zeros(&mut s, 32);
168 let sig = EthereumTransactionSignature { v, r, s };
169 tx.signature = Some(sig);
170 tx.restore_sender()?;
171 }
172
173 Ok(tx)
174 }
175
176 fn to_transaction_id(&self) -> Result<Self::TransactionId, TransactionError> {
177 Ok(Self::TransactionId {
178 txid: keccak256(&self.to_bytes()?).to_vec(),
179 })
180 }
181}
182
183impl<N: EthereumNetwork> FromStr for EthereumTransaction<N> {
184 type Err = TransactionError;
185
186 fn from_str(tx: &str) -> Result<Self, Self::Err> {
187 let tx = match &tx[..2] {
188 "0x" => &tx[2..],
189 _ => tx,
190 };
191 Self::from_bytes(&hex::decode(tx)?)
192 }
193}
194
195impl<N: EthereumNetwork> fmt::Display for EthereumTransaction<N> {
196 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197 write!(
198 f,
199 "0x{}",
200 &hex::encode(match self.to_bytes() {
201 Ok(transaction) => transaction,
202 _ => return Err(fmt::Error),
203 })
204 )
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use crate::{EthereumAddress, EthereumTransaction, EthereumTransactionParameters, Sepolia};
211 use anychain_core::{hex, Transaction};
212 use core::str::FromStr;
213 use ethereum_types::U256;
214
215 #[test]
216 fn test_legacy_tx() {
217 let params = EthereumTransactionParameters {
218 nonce: U256::from_dec_str("6").unwrap(),
219 gas_price: U256::from_dec_str("20000000000").unwrap(),
220 gas_limit: U256::from_dec_str("21000").unwrap(),
221 to: EthereumAddress::from_str("0xf7a63003b8ef116939804b4c2dd49290a39c4d97").unwrap(),
222 amount: U256::from_dec_str("10000000000000000").unwrap(),
223 data: vec![],
224 };
225
226 let mut tx = EthereumTransaction::<Sepolia>::new(¶ms).unwrap();
227 let msg = tx.to_transaction_id().unwrap().txid;
228 let msg = libsecp256k1::Message::parse_slice(&msg).unwrap();
229
230 let sk = "08d586ed207046d6476f92fd4852be3830a9d651fc148d6fa5a6f15b77ba5df0";
231 let sk = hex::decode(sk).unwrap();
232 let sk = libsecp256k1::SecretKey::parse_slice(&sk).unwrap();
233
234 let (sig, recid) = libsecp256k1::sign(&msg, &sk);
235
236 let sig = sig.serialize().to_vec();
237 let recid = recid.serialize();
238
239 let _ = tx.sign(sig, recid);
240
241 println!("{}", tx);
242 }
243}