From bc1e04966b7cac168836cb2fa4ac509c1931ea24 Mon Sep 17 00:00:00 2001 From: Akosh Farkash Date: Wed, 12 Jul 2023 14:00:08 +0100 Subject: [PATCH] FM-141: Parse logs into events. Return actor ID after deploy. (#143) --- fendermint/eth/api/examples/ethers.rs | 27 +++++++++++++++++++++++--- fendermint/eth/api/src/conv/from_tm.rs | 7 ++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/fendermint/eth/api/examples/ethers.rs b/fendermint/eth/api/examples/ethers.rs index 3cef1920..e5768675 100644 --- a/fendermint/eth/api/examples/ethers.rs +++ b/fendermint/eth/api/examples/ethers.rs @@ -24,6 +24,7 @@ // See https://coinsbench.com/ethereum-with-rust-tutorial-part-1-create-simple-transactions-with-rust-26d365a7ea93 // and https://coinsbench.com/ethereum-with-rust-tutorial-part-2-compile-and-deploy-solidity-contract-with-rust-c3cd16fce8ee +// and https://coinsbench.com/ethers-rust-power-or-ethers-abigen-rundown-89ab5e47875d use std::{ fmt::{Debug, Display}, @@ -537,7 +538,8 @@ async fn run(provider: Provider, opts: Options) -> anyhow::Result<()> { // Send a SimpleCoin transaction to get an event emitted. // Not using `prepare_call` here because `send_transaction` will fill the missing fields. - let coin_send: TestContractCall = contract.send_coin(to.eth_addr, U256::from(100)); + let coin_send_value = U256::from(100); + let coin_send: TestContractCall = contract.send_coin(to.eth_addr, coin_send_value); // Using `send_transaction` instead of `coin_send.send()` so it gets the receipt. // Unfortunately the returned `bool` is not available through the Ethereum API. let receipt = request( @@ -574,13 +576,32 @@ async fn run(provider: Provider, opts: Options) -> anyhow::Result<()> { }, )?; - // TODO: Parse logs with the contract. - request( + let logs = request( "eth_getFilterChanges (logs)", mw.get_filter_changes(logs_filter_id).await, |logs: &Vec| !logs.is_empty(), )?; + // eprintln!("LOGS = {logs:?}"); + + // Parse `Transfer` events from the logs with the SimpleCoin contract. + // Based on https://github.com/filecoin-project/ref-fvm/blob/evm-integration-tests/testing/integration/tests/fevm_features/common.rs#L616 + // and https://github.com/filecoin-project/ref-fvm/blob/evm-integration-tests/testing/integration/tests/fevm_features/simple_coin.rs#L26 + // and https://github.com/filecoin-project/ref-fvm/blob/evm-integration-tests/testing/integration/tests/evm/src/simple_coin/simple_coin.rs#L103 + + // The contract has methods like `.transfer_filter()` which allows querying logs, but here we just test parsing to make sure the data is correct. + let transfer_events = logs + .into_iter() + .filter(|log| log.address == contract.address()) + .map(|log| contract.decode_event::("Transfer", log.topics, log.data)) + .collect::, _>>() + .context("failed to parse logs to transfer events")?; + + assert!(!transfer_events.is_empty()); + assert_eq!(transfer_events[0].from, from.eth_addr); + assert_eq!(transfer_events[0].to, to.eth_addr); + assert_eq!(transfer_events[0].value, coin_send_value); + // Uninstall all filters. for id in filter_ids { request("eth_uninstallFilter", mw.uninstall_filter(id).await, |ok| { diff --git a/fendermint/eth/api/src/conv/from_tm.rs b/fendermint/eth/api/src/conv/from_tm.rs index 78757af6..a7ba19e9 100644 --- a/fendermint/eth/api/src/conv/from_tm.rs +++ b/fendermint/eth/api/src/conv/from_tm.rs @@ -341,7 +341,12 @@ fn app_hash_to_root(app_hash: &tendermint::AppHash) -> anyhow::Result fn maybe_contract_address(deliver_tx: &DeliverTx) -> Option { fendermint_rpc::response::decode_fevm_create(deliver_tx) .ok() - .map(|cr| cr.eth_address) + .map(|cr| { + // We can return `cr.eth_address` here and that's an address usable for calling the contract. + // However, the events are reported using the actor ID, so unless we want to translate those + // to ETH addresses on the fly, we can return a masked address here and see if that works. + EthAddress::from_id(cr.actor_id) + }) } pub fn to_logs(