anychain_ethereum/transaction/
legacy.rs

1use 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    /// The address of the sender
50    pub sender: Option<EthereumAddress>,
51    /// The transaction parameters (gas, gas_price, nonce, data)
52    pub params: EthereumTransactionParameters,
53    /// The transaction signature
54    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(&params)?;
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(&params).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}