rosetta_tx_ethereum/
lib.rs1use anyhow::Result;
2use ethabi::token::{LenientTokenizer, Tokenizer};
3use ethers_core::abi::HumanReadableParser;
4use ethers_core::types::{Eip1559TransactionRequest, NameOrAddress, Signature, H160};
5use rosetta_config_ethereum::{EthereumMetadata, EthereumMetadataParams};
6use rosetta_core::crypto::address::Address;
7use rosetta_core::crypto::SecretKey;
8use rosetta_core::{BlockchainConfig, TransactionBuilder};
9use sha3::{Digest, Keccak256};
10
11pub use ethers_core::types::U256;
12
13#[derive(Default)]
14pub struct EthereumTransactionBuilder;
15
16impl TransactionBuilder for EthereumTransactionBuilder {
17 type MetadataParams = EthereumMetadataParams;
18 type Metadata = EthereumMetadata;
19
20 fn transfer(&self, address: &Address, amount: u128) -> Result<Self::MetadataParams> {
21 let destination: H160 = address.address().parse()?;
22 let amount: U256 = amount.into();
23 Ok(EthereumMetadataParams {
24 destination: destination.0.to_vec(),
25 amount: amount.0,
26 data: vec![],
27 })
28 }
29
30 fn method_call(
31 &self,
32 contract: &str,
33 method: &str,
34 params: &[String],
35 amount: u128,
36 ) -> Result<Self::MetadataParams> {
37 let destination: H160 = contract.parse()?;
38 let amount: U256 = amount.into();
39 let function = HumanReadableParser::parse_function(method)?;
40 let mut tokens = Vec::with_capacity(params.len());
41 for (ty, arg) in function.inputs.iter().zip(params) {
42 tokens.push(LenientTokenizer::tokenize(&ty.kind, arg)?);
43 }
44 let bytes = function.encode_input(&tokens)?;
45 Ok(EthereumMetadataParams {
46 destination: destination.0.to_vec(),
47 amount: amount.0,
48 data: bytes,
49 })
50 }
51
52 fn deploy_contract(&self, contract_binary: Vec<u8>) -> Result<Self::MetadataParams> {
53 Ok(EthereumMetadataParams {
54 destination: vec![],
55 amount: [0, 0, 0, 0],
56 data: contract_binary,
57 })
58 }
59
60 fn create_and_sign(
61 &self,
62 config: &BlockchainConfig,
63 metadata_params: &Self::MetadataParams,
64 metadata: &Self::Metadata,
65 secret_key: &SecretKey,
66 ) -> Vec<u8> {
67 let from = secret_key
68 .public_key()
69 .to_address(config.address_format)
70 .address()
71 .parse()
72 .unwrap();
73 let to: Option<NameOrAddress> = if metadata_params.destination.len() >= 20 {
74 Some(H160::from_slice(&metadata_params.destination).into())
75 } else {
76 None
77 };
78 let tx = Eip1559TransactionRequest {
79 from: Some(from),
80 to,
81 gas: Some(U256(metadata.gas_limit)),
82 value: Some(U256(metadata_params.amount)),
83 data: Some(metadata_params.data.clone().into()),
84 nonce: Some(metadata.nonce.into()),
85 access_list: Default::default(),
86 max_priority_fee_per_gas: Some(U256(metadata.max_priority_fee_per_gas)),
87 max_fee_per_gas: Some(U256(metadata.max_fee_per_gas)),
88 chain_id: Some(metadata.chain_id.into()),
89 };
90 let mut hasher = Keccak256::new();
91 hasher.update([0x02]);
92 hasher.update(tx.rlp());
93 let hash = hasher.finalize();
94 let signature = secret_key.sign_prehashed(&hash).unwrap().to_bytes();
95 let rlp = tx.rlp_signed(&Signature {
96 r: U256::from_big_endian(&signature[..32]),
97 s: U256::from_big_endian(&signature[32..64]),
98 v: signature[64] as _,
99 });
100 let mut tx = Vec::with_capacity(rlp.len() + 1);
101 tx.push(0x02);
102 tx.extend(rlp);
103 tx
104 }
105}