0

Let's say we can listen for pending transaction using code below. We can simulate transactions using provider.call() function. And we can get result from simulated transaction as a string. There should be a way to get logs of simulated transaction. I'd like to know which contracts it affected. How can I do this?

const init = async () => {
    wsProvider.on("pending", async (tx_hash) => {
        const getTxResponse = await provider.getTransaction(tx_hash)
        if (!getTxResponse) return;

        const transaction = ethers.Transaction.from(getTxResponse);

        try {
            const call = await provider.call(transaction);

            // It's simulated. How to get logs?

            console.log(call);
        } catch (e) {
            console.log(e);
        }


    });
};

I tried to simulate execution of tx using provider.call(transaction). I'm looking for a way to get logs of simulated tx.

TylerH
  • 20,799
  • 66
  • 75
  • 101
graygt
  • 47
  • 3

4 Answers4

1

Is there any way to get receipt or logs of pending transaction?

Receipt is generated after the transaction is executed by a block producer (validator on PoS, miner on PoW), and published as part of the block.

Until a transaction is included in a published block, it's considered pending.

Meaning, transaction receipts (and parts of the receipt such as event logs) are not available for pending transactions.


We can simulate transactions using provider.call() function. And we can get result from simulated transaction as a string. There should be a way to get logs of simulated transaction

This approach executes eth_call RPC method on the node that you're connected to. Logs are not generated for *calls - only for transactions.


To get logs of an emulated transaction, you might need to run an emulator (Hardhat, Geth, EthereumJS, ...) that keeps access to the latest blockchain state (most likely you'll want to fork a public network) and then execute the transaction on this emulator.

Petr Hejda
  • 40,554
  • 8
  • 72
  • 100
0

You can simulate a transaction by

  • Creating a "mainnet fork" from a blockchain e.g. using a test-RPC provider like Anvil from Forge - here is a Python example
  • Doing a simulated transaction broadcast on your forked network
  • Reading the logs in the receipt of the simulated transaction
Mikko Ohtamaa
  • 82,057
  • 50
  • 264
  • 435
0

As far as the pending transactions do not differ from any other transaction objects not included in the blockchain, the more correct question would be:

How to get the receipt for a Transaction Object before including it into the blockchain?

We use this approach to simulate our transactions and to check the expected status and logs before submitting them to the network. You can pick a transaction from the mempool and perform the same simulations.

  1. We use hardhat to simulate the transaction. The simulation is executed instantly and in-process, which means you don't need to launch any local development networks.
  2. You would execute the transaction on the latest block, which means you don't need to have the archive node - a basic RPC node is enough.
  3. Accounts:
    • By picking the transactions from the mempool, they are already signed, so you can execute them immediately.
    • In our case, we simulate transactions for other accounts whose private keys we don't have. But hardhat has a special method called impersonateAccount that allows you to execute transactions for any address.

To get a feeling for how it works, here is an example of how we simulate transactions using the dequanto library

import { ERC20 } from '@dequanto-contracts/openzeppelin/ERC20';
import { HardhatProvider } from '@dequanto/hardhat/HardhatProvider';
import { $address } from '@dequanto/utils/$address';

const provider = new HardhatProvider();
const client = await provider.forked({ url: 'https://eth.public-rpc.com' });

const ownerImpersonated = '0x60faae176336dab62e284fe19b885b095d29fb7f';
const daiAddress = '0x6b175474e89094c44da98b954eedeac495271d0f';

await client.debug.impersonateAccount(ownerImpersonated);

const erc20 = new ERC20(daiAddress, client);
// transfer 100DAI from account to zero address
const writer = await erc20.transfer({ address: ownerImpersonated }, $address.ZERO, 100n ** 18n);
const receipt = await writer.wait();

let transferEvents = erc20.extractLogsTransfer(receipt);
console.log(transferEvents);

With raw hardhat and web3js plugin it would be something like this:

import hardhat from 'hardhat'
import { Transaction  } from '@ethereumjs/tx';

// Transaction from mempool
let tx: TransactionConfig & { v, r, s };

// point the in-process network to target the mainnets latest
await hardhat.reset('https://eth.public-rpc.com');

let hex = '0x' + new Transaction(tx).serialize().toString('hex');
let receipt = await hardhat.web3.eth.sendSignedTransaction(hex);

Hope it helps.

tenbits
  • 7,568
  • 5
  • 34
  • 53
0

Thanks everybody for participating! I actually asked a wrong question. The reason I need logs is to determine which contracts are affected with tx. The way to do it is to call a provider with tracer and get all calls as a result.

graygt
  • 47
  • 3