From 594256847d6abc92efc2ef73238fce17a7e692d9 Mon Sep 17 00:00:00 2001 From: Will Cory Date: Fri, 13 Sep 2024 09:58:10 -0700 Subject: [PATCH] :bug: Fix: eth_estimateGas (#1430) ## Description 1. Typescript type for estimateGas json request wrong 2. State overrides and block tag handled wrong ## Testing Explain the quality checks that have been done on the code changes ## Additional Information - [ ] I read the [contributing docs](../docs/contributing.md) (if this is your first contribution) Your ENS/address: ## Summary by CodeRabbit - **New Features** - Enhanced gas estimation accuracy for Ethereum transactions by fixing a bug related to the `eth_estimateGas` method. - Introduced optional parameters for gas estimation requests, allowing for greater flexibility in specifying block tags and state overrides. - **Bug Fixes** - Resolved issues with handling block tags and state overrides in gas estimation. - **Tests** - Added new test cases to improve coverage for gas estimation functionality, including scenarios for handling block tags and specific contract interactions. Co-authored-by: William Cory --- .changeset/forty-mugs-exist.md | 5 ++++ .../src/test/viem/estimateGas.spec.ts | 7 ++++++ .../procedures/src/eth/EthJsonRpcRequest.ts | 10 +++++++- .../ethEstimateGasProcedure.spec.ts.snap | 2 ++ .../src/eth/ethEstimateGasProcedure.js | 23 +++++++++++++++++- .../src/eth/ethEstimateGasProcedure.spec.ts | 24 +++++++++++++++++++ 6 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 .changeset/forty-mugs-exist.md diff --git a/.changeset/forty-mugs-exist.md b/.changeset/forty-mugs-exist.md new file mode 100644 index 000000000..0ca31ddf2 --- /dev/null +++ b/.changeset/forty-mugs-exist.md @@ -0,0 +1,5 @@ +--- +"@tevm/procedures": patch +--- + +Fixed bug with eth_estimateGas json-rpc not handling block tag and state overrides correctly diff --git a/packages/memory-client/src/test/viem/estimateGas.spec.ts b/packages/memory-client/src/test/viem/estimateGas.spec.ts index 2dad107c8..94e739bfd 100644 --- a/packages/memory-client/src/test/viem/estimateGas.spec.ts +++ b/packages/memory-client/src/test/viem/estimateGas.spec.ts @@ -31,6 +31,13 @@ beforeEach(async () => { describe('estimateGas', () => { it('should work', async () => { + expect( + await mc.estimateGas({ + to: c.simpleContract.address, + data: encodeFunctionData(c.simpleContract.write.set(69n)), + blockTag: 'latest', + }), + ).toBe(27_784n) expect( await mc.estimateGas({ to: c.simpleContract.address, diff --git a/packages/procedures/src/eth/EthJsonRpcRequest.ts b/packages/procedures/src/eth/EthJsonRpcRequest.ts index ecf65336e..15ff23175 100644 --- a/packages/procedures/src/eth/EthJsonRpcRequest.ts +++ b/packages/procedures/src/eth/EthJsonRpcRequest.ts @@ -70,7 +70,15 @@ export type EthCoinbaseJsonRpcRequest = JsonRpcRequest<'eth_coinbase', readonly /** * JSON-RPC request for `eth_estimateGas` procedure */ -export type EthEstimateGasJsonRpcRequest = JsonRpcRequest<'eth_estimateGas', readonly [tx: JsonRpcTransaction]> +export type EthEstimateGasJsonRpcRequest = JsonRpcRequest< + 'eth_estimateGas', + readonly [ + tx: JsonRpcTransaction, + tag?: BlockTag | Hex, + stateOverrideSet?: SerializeToJson, + blockOverrideSet?: SerializeToJson, + ] +> // eth_hashrate /** * JSON-RPC request for `eth_hashrate` procedure diff --git a/packages/procedures/src/eth/__snapshots__/ethEstimateGasProcedure.spec.ts.snap b/packages/procedures/src/eth/__snapshots__/ethEstimateGasProcedure.spec.ts.snap index 05e781fa6..cc0104ff4 100644 --- a/packages/procedures/src/eth/__snapshots__/ethEstimateGasProcedure.spec.ts.snap +++ b/packages/procedures/src/eth/__snapshots__/ethEstimateGasProcedure.spec.ts.snap @@ -2,6 +2,8 @@ exports[`ethEstimateGasJsonRpcProcedure > should estimate gas successfully 1`] = `"0x5208"`; +exports[`ethEstimateGasJsonRpcProcedure > should handle block tag 1`] = `"0x5208"`; + exports[`ethEstimateGasJsonRpcProcedure > should handle errors from callProcedure 1`] = ` { "code": -32602, diff --git a/packages/procedures/src/eth/ethEstimateGasProcedure.js b/packages/procedures/src/eth/ethEstimateGasProcedure.js index 6fecc0189..166dcff41 100644 --- a/packages/procedures/src/eth/ethEstimateGasProcedure.js +++ b/packages/procedures/src/eth/ethEstimateGasProcedure.js @@ -8,9 +8,30 @@ import { callProcedure } from '../call/callProcedure.js' export const ethEstimateGasJsonRpcProcedure = (client) => { return async (request) => { const estimateGasRequest = /** @type {import('./EthJsonRpcRequest.js').EthEstimateGasJsonRpcRequest}*/ (request) + const [_params, blockTag, stateOverrides, blockOverrides] = estimateGasRequest.params + + const getParams = () => { + /** + * @type {import('../call/CallJsonRpcRequest.js').CallJsonRpcRequest['params']} + */ + const params = [ + { + ..._params, + ...(blockTag !== undefined ? { blockTag } : {}), + }, + ] + if (blockOverrides !== undefined) { + params.push(stateOverrides ?? {}, blockOverrides) + } + if (stateOverrides !== undefined) { + params.push(...params, stateOverrides) + } + return params + } + const callResult = await callProcedure(client)({ ...estimateGasRequest, - params: [...estimateGasRequest.params], + params: getParams(), method: 'tevm_call', }) if (callResult.error || !callResult.result) { diff --git a/packages/procedures/src/eth/ethEstimateGasProcedure.spec.ts b/packages/procedures/src/eth/ethEstimateGasProcedure.spec.ts index b796b9f43..ba0b57246 100644 --- a/packages/procedures/src/eth/ethEstimateGasProcedure.spec.ts +++ b/packages/procedures/src/eth/ethEstimateGasProcedure.spec.ts @@ -1,4 +1,5 @@ import { type TevmNode, createTevmNode } from '@tevm/node' +import { numberToHex } from '@tevm/utils' import { beforeEach, describe, expect, it } from 'vitest' import type { EthEstimateGasJsonRpcRequest } from './EthJsonRpcRequest.js' import { ethEstimateGasJsonRpcProcedure } from './ethEstimateGasProcedure.js' @@ -31,6 +32,29 @@ describe('ethEstimateGasJsonRpcProcedure', () => { expect(response.id).toBe(request.id as any) expect(response.result).toMatchSnapshot() }) + it('should handle block tag', async () => { + const latestBlock = await client.getVm().then((vm) => vm.blockchain.getCanonicalHeadBlock()) + const request: EthEstimateGasJsonRpcRequest = { + jsonrpc: '2.0', + method: 'eth_estimateGas', + id: 1, + params: [ + { + from: '0x0000000000000000000000000000000000000000', + to: '0x0000000000000000000000000000000000000000', + data: '0x', + }, + numberToHex(latestBlock.header.number), + ], + } + + const response = await ethEstimateGasJsonRpcProcedure(client)(request) + expect(response.error).toBeUndefined() + expect(response.result).toBeDefined() + expect(response.method).toBe('eth_estimateGas') + expect(response.id).toBe(request.id as any) + expect(response.result).toMatchSnapshot() + }) it('should handle errors from callProcedure', async () => { const request: EthEstimateGasJsonRpcRequest = {