I am attempting to get the historical state of the chain within a block. That is, it is straightforward to use hardhat to fork at an earlier block but I want to be above to move up an arbitrary number of transactions within that block. For what it's worth, I am working on Python with Web3Py.
What I am attempting to do to solve this is to create a local fork up to the block I want to enter, then fetch the transactions from the next block from Alchemy:
from web3 import Web3
import json
web3_current = Web3(Web3.HTTPProvider('MY_ALCHEMY_API')) # get fork at current block which will contain the block we want to replay
web3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545/')) # connect to local fork of mainnet at the block we want to replay
block_number = 17895275 # where we want to replay from
txs = web3_current.eth.get_block(block_number)['transactions'] # get all transactions in the block we want to replicate
impersonated_tx_hash = txs[0] # get the first transaction in the block
impersonated_tx = web3_current.eth.get_transaction(impersonated_tx_hash) # get the transaction object
Then I impersonate this account and create a dict that contains all the info necessary to replay the transaction:
web3.provider.make_request('hardhat_impersonateAccount', [impersonated_tx['from']])
# Initialize replay_tx as an empty dictionary
replay_tx = {}
# Common fields for both legacy and EIP-1559 transactions
common_fields = ['from', 'to', 'gas', 'value', 'input', 'nonce', 'type', 'chainId', 'accessList', 'data']
for field in common_fields:
if field in impersonated_tx:
replay_tx[field] = impersonated_tx[field]
# For legacy transactions
if 'gasPrice' in impersonated_tx:
replay_tx['gasPrice'] = impersonated_tx['gasPrice']
if 'maxFeePerGas' in impersonated_tx and 'maxPriorityFeePerGas' in impersonated_tx:
replay_tx['maxFeePerGas'] = impersonated_tx['maxFeePerGas']
replay_tx['maxPriorityFeePerGas'] = impersonated_tx['maxPriorityFeePerGas']
if 'input' in replay_tx:
replay_tx['data'] = replay_tx.pop('input')
replay_tx['chainId'] = 31337 # need to hardcode for hardhat
if 'type' in replay_tx and replay_tx['type'] == 2:
if 'gasPrice' in replay_tx:
del replay_tx['gasPrice']
After this I simply send the transaction out:
tx_hash = web3.eth.send_transaction(replay_tx) # replay transaction on local fork impersonating the sender ('from')
The transaction is attempting to swap with the Uniswap Router. This isn't that critical, it's just happens to be the first transaction in the block. However, I get an error returned:
ValueError: {'code': -32603, 'message': "Error: VM Exception while processing transaction: reverted with reason string 'UniswapV2Router: EXPIRED'", 'data': {'message': "Error: VM Exception while processing transaction: reverted with reason string 'UniswapV2Router: EXPIRED'", 'txHash': '0x42a6b46f0e757ddb6994633aa231cfa4818235ce9542e03f54777a993f9c3512', 'data': '0x08c379a000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000018556e69737761705632526f757465723a20455850495245440000000000000000'}}
Am I going about this incorrectly? Again, the fact that it's a Uniswap transaction is tangential; I want to be able to replay UP TO any transaction from an historical block. I have a hunch that it has something to do with timestamps but I'm not sure how that factors into things here and would imagine it would impact other transactions, as well.
The basic question is: assuming it is possible to do so, how does one "replay" transactions from a forked chain?