diff --git a/fendermint/eth/api/src/conv/from_tm.rs b/fendermint/eth/api/src/conv/from_tm.rs index f31d257a..22b5f5eb 100644 --- a/fendermint/eth/api/src/conv/from_tm.rs +++ b/fendermint/eth/api/src/conv/from_tm.rs @@ -9,6 +9,7 @@ use std::str::FromStr; use anyhow::{anyhow, Context}; use ethers_core::types::{self as et}; use fendermint_vm_actor_interface::eam::EthAddress; +use fendermint_vm_message::conv::from_fvm::to_eth_transaction_request; use fendermint_vm_message::{chain::ChainMessage, signed::SignedMessage}; use fvm_shared::address::Address; use fvm_shared::bigint::Zero; @@ -211,30 +212,36 @@ pub fn to_eth_transaction( // Based on https://github.com/filecoin-project/lotus/blob/6cc506f5cf751215be6badc94a960251c6453202/node/impl/full/eth.go#L2048 let sig = to_eth_signature(msg.signature(), true).context("failed to convert to eth signature")?; - let msg = msg.message; + + // Recover the original request; this method has better tests. + let tx = to_eth_transaction_request(&msg.message, &chain_id) + .context("failed to convert to tx request")?; let tx = et::Transaction { hash, - nonce: et::U256::from(msg.sequence), + nonce: tx.nonce.unwrap_or_default(), block_hash: None, block_number: None, transaction_index: None, - from: to_eth_address(&msg.from).unwrap_or_default(), - to: to_eth_address(&msg.to), - value: to_eth_tokens(&msg.value)?, - gas: et::U256::from(msg.gas_limit), - max_fee_per_gas: Some(to_eth_tokens(&msg.gas_fee_cap)?), - max_priority_fee_per_gas: Some(to_eth_tokens(&msg.gas_premium)?), + from: tx.from.unwrap_or_default(), + to: tx.to.and_then(|to| to.as_address().cloned()), + value: tx.value.unwrap_or_default(), + gas: tx.gas.unwrap_or_default(), + max_fee_per_gas: tx.max_fee_per_gas, + max_priority_fee_per_gas: tx.max_priority_fee_per_gas, // Strictly speaking a "Type 2" transaction should not need to set this, but we do because Blockscout // has a database constraint that if a transaction is included in a block this can't be null. - gas_price: Some(to_eth_tokens(&msg.gas_fee_cap)? + to_eth_tokens(&msg.gas_premium)?), - input: et::Bytes::from(msg.params.bytes().to_vec()), - chain_id: Some(et::U256::from(u64::from(chain_id))), + gas_price: Some( + tx.max_fee_per_gas.unwrap_or_default() + + tx.max_priority_fee_per_gas.unwrap_or_default(), + ), + input: tx.data.unwrap_or_default(), + chain_id: tx.chain_id.map(|x| et::U256::from(x.as_u64())), v: et::U64::from(sig.v), r: sig.r, s: sig.s, transaction_type: Some(2u64.into()), - access_list: None, + access_list: Some(tx.access_list), other: Default::default(), }; diff --git a/fendermint/vm/message/src/conv/from_fvm.rs b/fendermint/vm/message/src/conv/from_fvm.rs index 6283fb88..ee4d9f38 100644 --- a/fendermint/vm/message/src/conv/from_fvm.rs +++ b/fendermint/vm/message/src/conv/from_fvm.rs @@ -7,7 +7,6 @@ use std::str::FromStr; use anyhow::anyhow; use ethers_core::types as et; -use ethers_core::types::transaction::eip2718::TypedTransaction; use fendermint_crypto::{RecoveryId, Signature}; use fendermint_vm_actor_interface::eam::EthAddress; use fendermint_vm_actor_interface::eam::EAM_ACTOR_ID; @@ -94,11 +93,11 @@ pub fn to_eth_signature(sig: &FvmSignature, normalized: bool) -> anyhow::Result< Ok(sig) } -/// Turn an FVM `Message` back into an Ethereum transaction request, mainly for signature checking. -pub fn to_eth_typed_transaction( +/// Turn an FVM `Message` back into an Ethereum transaction request. +pub fn to_eth_transaction_request( msg: &Message, chain_id: &ChainID, -) -> anyhow::Result { +) -> anyhow::Result { let chain_id: u64 = (*chain_id).into(); let Message { @@ -134,7 +133,7 @@ pub fn to_eth_typed_transaction( tx.value = Some(to_eth_tokens(value)?); } - Ok(tx.into()) + Ok(tx) } #[cfg(test)] @@ -158,7 +157,7 @@ pub mod tests { tests::{EthMessage, KeyPair}, }; - use super::{to_eth_signature, to_eth_tokens, to_eth_typed_transaction}; + use super::{to_eth_signature, to_eth_tokens, to_eth_transaction_request}; #[quickcheck] fn prop_to_eth_tokens(tokens: ArbTokenAmount) -> bool { @@ -211,10 +210,9 @@ pub mod tests { fn prop_to_and_from_eth_transaction(msg: EthMessage, chain_id: u64) { let chain_id = ChainID::from(chain_id); let msg0 = msg.0; - let tx = - to_eth_typed_transaction(&msg0, &chain_id).expect("to_eth_typed_transaction failed"); - let tx = tx.as_eip1559_ref().expect("not an eip1559 transaction"); - let msg1 = to_fvm_message(tx).expect("to_fvm_message failed"); + let tx = to_eth_transaction_request(&msg0, &chain_id) + .expect("to_eth_transaction_request failed"); + let msg1 = to_fvm_message(&tx).expect("to_fvm_message failed"); assert_eq!(msg1, msg0) } @@ -227,8 +225,9 @@ pub mod tests { let chain_id = ChainID::from(chain_id); let msg0 = msg.0; - let tx = - to_eth_typed_transaction(&msg0, &chain_id).expect("to_eth_typed_transaction failed"); + let tx: TypedTransaction = to_eth_transaction_request(&msg0, &chain_id) + .expect("to_eth_transaction_request failed") + .into(); let wallet: Wallet = Wallet::from_bytes(key_pair.sk.serialize().as_ref()) .expect("failed to create wallet") diff --git a/fendermint/vm/message/src/signed.rs b/fendermint/vm/message/src/signed.rs index b9d67558..9e2e827d 100644 --- a/fendermint/vm/message/src/signed.rs +++ b/fendermint/vm/message/src/signed.rs @@ -6,6 +6,7 @@ use anyhow::anyhow; use cid::multihash::MultihashDigest; use cid::Cid; use ethers_core::types as et; +use ethers_core::types::transaction::eip2718::TypedTransaction; use fendermint_crypto::SecretKey; use fendermint_vm_actor_interface::{eam, evm}; use fvm_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple}; @@ -41,6 +42,7 @@ pub enum SignedMessageError { /// which use a different algorithm than Ethereum. /// /// We can potentially extend this list to include CID based indexing. +#[derive(Debug, Clone)] pub enum DomainHash { Eth([u8; 32]), } @@ -104,8 +106,9 @@ impl SignedMessage { // work with regular accounts. match maybe_eth_address(&message.from) { Some(addr) => { - let tx = from_fvm::to_eth_typed_transaction(message, chain_id) - .map_err(SignedMessageError::Ethereum)?; + let tx: TypedTransaction = from_fvm::to_eth_transaction_request(message, chain_id) + .map_err(SignedMessageError::Ethereum)? + .into(); Ok(Signable::Ethereum((tx.sighash(), addr))) } @@ -155,7 +158,7 @@ impl SignedMessage { chain_id: &ChainID, ) -> Result, SignedMessageError> { if maybe_eth_address(&self.message.from).is_some() { - let tx = from_fvm::to_eth_typed_transaction(self.message(), chain_id) + let tx = from_fvm::to_eth_transaction_request(self.message(), chain_id) .map_err(SignedMessageError::Ethereum)?; let sig = from_fvm::to_eth_signature(self.signature(), true)