From 43d93de3bb29921d6105687ef398b7ed93971637 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 21 Feb 2023 17:16:18 -1000 Subject: [PATCH 01/67] Add payload as optional argument for InvalidResponseError --- .../web3-core/src/web3_request_manager.ts | 2 +- .../web3-errors/src/errors/response_errors.ts | 34 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/packages/web3-core/src/web3_request_manager.ts b/packages/web3-core/src/web3_request_manager.ts index 327d9f24edf..15975825e78 100644 --- a/packages/web3-core/src/web3_request_manager.ts +++ b/packages/web3-core/src/web3_request_manager.ts @@ -369,7 +369,7 @@ export class Web3RequestManager< throw new RpcError(rpcErrorResponse); } } else if (!Web3RequestManager._isReverted(response)) { - throw new InvalidResponseError(response); + throw new InvalidResponseError(response, payload); } } diff --git a/packages/web3-errors/src/errors/response_errors.ts b/packages/web3-errors/src/errors/response_errors.ts index fd0afb45128..7efd4240ceb 100644 --- a/packages/web3-errors/src/errors/response_errors.ts +++ b/packages/web3-errors/src/errors/response_errors.ts @@ -16,7 +16,12 @@ along with web3.js. If not, see . */ // eslint-disable-next-line max-classes-per-file -import { JsonRpcError, JsonRpcResponse, JsonRpcResponseWithError } from 'web3-types'; +import { + JsonRpcError, + JsonRpcPayload, + JsonRpcResponse, + JsonRpcResponseWithError, +} from 'web3-types'; import { BaseWeb3Error } from '../web3_error_base'; import { ERR_INVALID_RESPONSE, ERR_RESPONSE } from '../error_codes'; @@ -36,14 +41,19 @@ const isResponseWithError = ( const buildErrorMessage = (response: JsonRpcResponse): string => isResponseWithError(response) ? response.error.message : ''; -export class ResponseError extends BaseWeb3Error { +export class ResponseError extends BaseWeb3Error { public code = ERR_RESPONSE; public data?: ErrorType | ErrorType[]; + public request?: JsonRpcPayload; - public constructor(response: JsonRpcResponse, message?: string) { + public constructor( + response: JsonRpcResponse, + message?: string, + request?: JsonRpcPayload, + ) { super( message ?? - `Returned error: ${ + `${ Array.isArray(response) ? response.map(r => buildErrorMessage(r)).join(',') : buildErrorMessage(response) @@ -55,16 +65,24 @@ export class ResponseError extends BaseWeb3Error { ? response.map(r => r.error?.data as ErrorType) : response?.error?.data; } + + this.request = request; } public toJSON() { - return { ...super.toJSON(), data: this.data }; + return { ...super.toJSON(), data: this.data, request: this.request }; } } -export class InvalidResponseError extends ResponseError { - public constructor(result: JsonRpcResponse) { - super(result); +export class InvalidResponseError extends ResponseError< + ErrorType, + RequestType +> { + public constructor( + result: JsonRpcResponse, + request?: JsonRpcPayload, + ) { + super(result, undefined, request); this.code = ERR_INVALID_RESPONSE; let errorOrErrors: JsonRpcError | JsonRpcError[] | undefined; From db9cb5002470cb3768c13928c1ffb5ff2f2104b7 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 21 Feb 2023 17:19:58 -1000 Subject: [PATCH 02/67] Init Transaction Error Scenarios tests --- .../web3_eth/send_transaction.test.ts | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index c5d8d339ddd..2d687fa6ce4 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -355,4 +355,94 @@ describe('Web3Eth.sendTransaction', () => { // expect.assertions(1); }); }); + + describe('Transaction Error Scenarios', () => { + it('Should throw because gas too low', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: BigInt(1), + gas: 1, + }; + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'InvalidResponseError', + code: 101, + message: expect.any(String), + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: tempAcc.address, + gas: '0x1', + gasPrice: expect.any(String), + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + to: '0x0000000000000000000000000000000000000000', + value: '0x1', + }, + ], + }, + }); + }); + + it('Should throw because insufficient funds', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: BigInt('999999999999999999999999999999999999999999999999999999999'), + }; + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'InvalidResponseError', + code: 101, + message: expect.any(String), + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: tempAcc.address, + gasPrice: expect.any(String), + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + to: '0x0000000000000000000000000000000000000000', + value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', + }, + ], + }, + }); + }); + + it('Should throw because of unknown account', async () => { + const transaction: Transaction = { + from: '0x0000000000000000000000000000000000000000', + to: '0x0000000000000000000000000000000000000000', + }; + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'InvalidResponseError', + code: 101, + message: expect.any(String), + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: '0x0000000000000000000000000000000000000000', + to: '0x0000000000000000000000000000000000000000', + gasPrice: expect.any(String), + }, + ], + }, + }); + }); + }); }); From 8eb82ba7fb9db56a58399cf24ab48b42d0461a81 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 21 Feb 2023 21:40:17 -1000 Subject: [PATCH 03/67] Init ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR --- packages/web3-errors/src/error_codes.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/web3-errors/src/error_codes.ts b/packages/web3-errors/src/error_codes.ts index 81c50434454..5efc073bbfe 100644 --- a/packages/web3-errors/src/error_codes.ts +++ b/packages/web3-errors/src/error_codes.ts @@ -86,6 +86,7 @@ export const ERR_TX_GAS_MISMATCH = 434; export const ERR_TX_CHAIN_MISMATCH = 435; export const ERR_TX_HARDFORK_MISMATCH = 436; export const ERR_TX_INVALID_RECEIVER = 437; +export const ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR = 438; // Connection error codes export const ERR_CONN = 500; From e4a289137e27957746715430d129b5de754eda22 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 21 Feb 2023 21:40:36 -1000 Subject: [PATCH 04/67] WIP --- .../src/errors/transaction_errors.ts | 46 +++++++-- packages/web3-eth/src/rpc_method_wrappers.ts | 51 +++++----- packages/web3-eth/src/types.ts | 15 ++- .../web3-eth/src/utils/get_revert_reason.ts | 76 +++++++------- .../src/utils/get_transaction_error.ts | 87 ++++++++++++++++ .../web3_eth/send_transaction.test.ts | 99 ++++++++++++++----- 6 files changed, 276 insertions(+), 98 deletions(-) create mode 100644 packages/web3-eth/src/utils/get_transaction_error.ts diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index 74d1318feda..4f4f216347f 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -57,6 +57,7 @@ import { ERR_TX_UNABLE_TO_POPULATE_NONCE, ERR_TX_UNSUPPORTED_EIP_1559, ERR_TX_UNSUPPORTED_TYPE, + ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR, } from '../error_codes'; import { InvalidValueError, BaseWeb3Error } from '../web3_error_base'; @@ -84,25 +85,54 @@ export class RevertInstructionError extends BaseWeb3Error { } } -export class TransactionRevertError extends BaseWeb3Error { +export class TransactionRevertError extends BaseWeb3Error { public code = ERR_TX_REVERT_TRANSACTION; public constructor( public reason: string, public signature?: string, - public receipt?: TransactionReceipt, + public receipt?: ReceiptType, + public data?: string, ) { - super( - `Transaction has been reverted by the EVM:\n ${JSON.stringify(receipt, undefined, 2)}`, - ); + super(reason); + } + + public toJSON() { + return { + ...super.toJSON(), + reason: this.reason, + signature: this.signature, + receipt: this.receipt, + data: this.data + }; + } +} + +export class TransactionRevertWithCustomError extends TransactionRevertError { + public code = ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR; + + public constructor( + public reason: string, + public customErrorName: string, + public customErrorDecodedSignature: string, + public customErrorArguments: Record, + public signature?: string, + public receipt?: ReceiptType, + public data?: string, + ) { + super(reason); } public toJSON() { return { ...super.toJSON(), reason: this.reason, + customErrorName: this.customErrorName, + customErrorDecodedSignature: this.customErrorDecodedSignature, + customErrorArguments: this.customErrorArguments, signature: this.signature, receipt: this.receipt, + data: this.data }; } } @@ -125,10 +155,10 @@ export class ContractCodeNotStoredError extends TransactionError { } } -export class TransactionRevertedWithoutReasonError extends TransactionError { - public constructor(receipt: TransactionReceipt) { +export class TransactionRevertedWithoutReasonError extends TransactionError { + public constructor(receipt?: ReceiptType) { super( - `Transaction has been reverted by the EVM:\n ${JSON.stringify(receipt, undefined, 2)}`, + `Transaction has been reverted by the EVM${receipt === undefined ? '' : `:\n ${JSON.stringify(receipt, undefined, 2)}`}`, receipt, ); this.code = ERR_TX_REVERT_WITHOUT_REASON; diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 410eaf10471..1a250c49329 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -48,7 +48,10 @@ import { import { Web3Context, Web3PromiEvent } from 'web3-core'; import { ETH_DATA_FORMAT, FormatType, DataFormat, DEFAULT_RETURN_FORMAT, format } from 'web3-utils'; import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator'; -import { SignatureError, TransactionError, ContractExecutionError } from 'web3-errors'; +import { + SignatureError, + TransactionError, +} from 'web3-errors'; import { ethRpcMethods } from 'web3-rpc-methods'; import { decodeSignedTransaction } from './utils/decode_signed_transaction'; import { @@ -77,8 +80,7 @@ import { trySendTransaction } from './utils/try_send_transaction'; import { waitForTransactionReceipt } from './utils/wait_for_transaction_receipt'; import { watchTransactionForConfirmations } from './utils/watch_transaction_for_confirmations'; import { NUMBER_DATA_FORMAT } from './constants'; -// eslint-disable-next-line import/no-cycle -import { getRevertReason } from './utils/get_revert_reason'; +import { getTransactionError } from './utils/get_transaction_error'; /** * @@ -1078,14 +1080,6 @@ export function sendTransaction< ETH_DATA_FORMAT, ); - if (web3Context.handleRevert) { - // eslint-disable-next-line no-use-before-define - await getRevertReason( - web3Context, - transactionFormatted as TransactionCall, - ); - } - if ( !options?.ignoreGasPricing && isNullish(transactionFormatted.gasPrice) && @@ -1177,17 +1171,17 @@ export function sendTransaction< ) as unknown as ResolveType, ); } else if (transactionReceipt.status === BigInt(0)) { + const error = await getTransactionError( + web3Context, + transactionFormatted as TransactionCall, + transactionReceiptFormatted, + ); + if (promiEvent.listenerCount('error') > 0) { - promiEvent.emit( - 'error', - new TransactionError( - 'Transaction failed', - transactionReceiptFormatted, - ), - ); + promiEvent.emit('error', error); } - reject(transactionReceiptFormatted as unknown as ResolveType); - return; + + reject(error); } else { resolve(transactionReceiptFormatted as unknown as ResolveType); } @@ -1206,17 +1200,18 @@ export function sendTransaction< ); } } catch (error) { - if (error instanceof ContractExecutionError) { - promiEvent.emit('contractExecutionError', error); - } + const _error = await getTransactionError( + web3Context, + undefined, + undefined, + error + ); + if (promiEvent.listenerCount('error') > 0) { - promiEvent.emit( - 'error', - new TransactionError((error as Error).message), - ); + promiEvent.emit('error', _error); } - reject(error); + reject(_error); } })() as unknown; }); diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index bae3f0a9e2a..74dc54d4cb8 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -15,7 +15,14 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { TransactionError, ContractExecutionError, ResponseError } from 'web3-errors'; +import { + TransactionError, + ContractExecutionError, + ResponseError, + TransactionRevertedWithoutReasonError, + TransactionRevertError, + TransactionRevertWithCustomError, +} from 'web3-errors'; import { Bytes, HexString, Numbers, Transaction, TransactionReceipt } from 'web3-types'; import { DataFormat, ETH_DATA_FORMAT, FormatType } from 'web3-utils'; @@ -31,8 +38,10 @@ export type SendTransactionEvents = { receipt: FormatType; latestBlockHash: FormatType; }; - error: TransactionError>; - contractExecutionError: ContractExecutionError | ResponseError; + error: + | TransactionRevertedWithoutReasonError> + | TransactionRevertError> + | TransactionRevertWithCustomError>; }; export type SendSignedTransactionEvents = { diff --git a/packages/web3-eth/src/utils/get_revert_reason.ts b/packages/web3-eth/src/utils/get_revert_reason.ts index 40ca1d71617..095a7e0fc31 100644 --- a/packages/web3-eth/src/utils/get_revert_reason.ts +++ b/packages/web3-eth/src/utils/get_revert_reason.ts @@ -25,6 +25,45 @@ import { DataFormat, DEFAULT_RETURN_FORMAT } from 'web3-utils'; import { call } from '../rpc_method_wrappers'; import { RevertReason, RevertReasonWithCustomError } from '../types'; +export const parseTransactionError = (error: unknown, contractAbi?: ContractAbi) => { + if ( + error instanceof ContractExecutionError && + error.innerError instanceof Eip838ExecutionError + ) { + if (contractAbi !== undefined) { + const errorsAbi = contractAbi.filter(abi => + isAbiErrorFragment(abi), + ) as unknown as AbiErrorFragment[]; + decodeContractErrorData(errorsAbi, error.innerError); + + return { + reason: error.innerError.message, + signature: error.innerError.data?.slice(0, 10), + data: error.innerError.data?.substring(10), + customErrorName: error.innerError.errorName, + customErrorDecodedSignature: error.innerError.errorSignature, + customErrorArguments: error.innerError.errorArgs, + } as RevertReasonWithCustomError; + } + + return { + reason: error.innerError.message, + signature: error.innerError.data?.slice(0, 10), + data: error.innerError.data?.substring(10), + } as RevertReason; + } + + if ( + error instanceof InvalidResponseError && + !Array.isArray(error.innerError) && + error.innerError !== undefined + ) { + return error.innerError.message; + } + + throw error; +}; + /** * Returns the revert reason generated by the EVM if the transaction were to be executed. * @@ -44,41 +83,6 @@ export async function getRevertReason< await call(web3Context, transaction, web3Context.defaultBlock, returnFormat); return undefined; } catch (error) { - if ( - error instanceof ContractExecutionError && - error.innerError instanceof Eip838ExecutionError - ) { - if (contractAbi !== undefined) { - const errorsAbi = contractAbi.filter(abi => - isAbiErrorFragment(abi), - ) as unknown as AbiErrorFragment[]; - decodeContractErrorData(errorsAbi, error.innerError); - - return { - reason: error.innerError.message, - signature: error.innerError.data?.slice(0, 10), - data: error.innerError.data?.substring(10), - customErrorName: error.innerError.errorName, - customErrorDecodedSignature: error.innerError.errorSignature, - customErrorArguments: error.innerError.errorArgs, - } as RevertReasonWithCustomError; - } - - return { - reason: error.innerError.message, - signature: error.innerError.data?.slice(0, 10), - data: error.innerError.data?.substring(10), - } as RevertReason; - } - - if ( - error instanceof InvalidResponseError && - !Array.isArray(error.innerError) && - error.innerError !== undefined - ) { - return error.innerError.message; - } - - throw error; + return parseTransactionError(error, contractAbi); } } diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts new file mode 100644 index 00000000000..f6e160bf25e --- /dev/null +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -0,0 +1,87 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { Web3Context } from 'web3-core'; +import { + TransactionRevertedWithoutReasonError, + TransactionRevertError, + TransactionRevertWithCustomError, +} from 'web3-errors'; +import { TransactionCall, TransactionReceipt } from 'web3-types'; +import { DataFormat, FormatType } from 'web3-utils'; +import { RevertReason, RevertReasonWithCustomError } from '../types'; +import { getRevertReason, parseTransactionError } from './get_revert_reason'; + +// TODO Add support for passing contract ABI to getRevertReason? +export async function getTransactionError( + web3Context: Web3Context, + transactionFormatted?: TransactionCall, + transactionReceiptFormatted?: FormatType, + receivedError?: unknown +) { + let reason: string | RevertReason | RevertReasonWithCustomError | undefined; + + if (receivedError !== undefined) { + reason = parseTransactionError(receivedError); + } else if (web3Context.handleRevert && transactionFormatted !== undefined) { + reason = await getRevertReason(web3Context, transactionFormatted); + } + + let error: + | TransactionRevertedWithoutReasonError> + | TransactionRevertError> + | TransactionRevertWithCustomError>; + if (reason === undefined) { + error = new TransactionRevertedWithoutReasonError< + FormatType + >(transactionReceiptFormatted); + } else { + if (typeof reason === 'string') { + error = new TransactionRevertError>( + reason, + undefined, + transactionReceiptFormatted, + ); + } else if ( + (reason as RevertReasonWithCustomError).customErrorName !== undefined && + (reason as RevertReasonWithCustomError).customErrorDecodedSignature !== undefined && + (reason as RevertReasonWithCustomError).customErrorArguments !== undefined + ) { + const _reason: RevertReasonWithCustomError = reason as RevertReasonWithCustomError; + error = new TransactionRevertWithCustomError< + FormatType + >( + _reason.reason, + _reason.customErrorName, + _reason.customErrorDecodedSignature, + _reason.customErrorArguments, + _reason.signature, + transactionReceiptFormatted, + _reason.data, + ); + } else { + error = new TransactionRevertError>( + reason.reason, + reason.signature, + transactionReceiptFormatted, + reason.data, + ); + } + } + + return error; +} diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 2d687fa6ce4..a71f9f06909 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -20,6 +20,7 @@ import { TransactionWithFromLocalWalletIndex, TransactionWithToLocalWalletIndex, TransactionWithFromAndToLocalWalletIndex, + Address, } from 'web3-types'; import { Wallet } from 'web3-eth-accounts'; import { isHexStrict } from 'web3-validator'; @@ -31,6 +32,7 @@ import { createTempAccount, getSystemTestProvider, } from '../../fixtures/system_test_utils'; +import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; describe('Web3Eth.sendTransaction', () => { let web3Eth: Web3Eth; @@ -389,34 +391,40 @@ describe('Web3Eth.sendTransaction', () => { }); }); - it('Should throw because insufficient funds', async () => { + it.only('Should throw because insufficient funds', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ - name: 'InvalidResponseError', - code: 101, - message: expect.any(String), - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: tempAcc.address, - gasPrice: expect.any(String), - maxFeePerGas: undefined, - maxPriorityFeePerGas: undefined, - to: '0x0000000000000000000000000000000000000000', - value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', - }, - ], - }, - }); + try { + await web3Eth.sendTransaction(transaction).on('error', error => console.log(error)); + } catch (error) { + // @ts-ignore + console.log(error); + } + // await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + // name: 'InvalidResponseError', + // code: 101, + // message: expect.any(String), + // innerError: expect.any(Object), + // data: undefined, + // request: { + // jsonrpc: '2.0', + // id: expect.any(String), + // method: 'eth_sendTransaction', + // params: [ + // { + // from: tempAcc.address, + // gasPrice: expect.any(String), + // maxFeePerGas: undefined, + // maxPriorityFeePerGas: undefined, + // to: '0x0000000000000000000000000000000000000000', + // value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', + // }, + // ], + // }, + // }); }); it('Should throw because of unknown account', async () => { @@ -444,5 +452,50 @@ describe('Web3Eth.sendTransaction', () => { }, }); }); + + it('Should throw because of contract revert', async () => { + const simpleRevertDeployTransaction: Transaction = { + from: tempAcc.address, + data: SimpleRevertDeploymentData, + }; + simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( + simpleRevertDeployTransaction, + ); + const simpleRevertContractAddress = ( + await web3Eth.sendTransaction(simpleRevertDeployTransaction) + ).contractAddress as Address; + + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', + }; + web3Eth.handleRevert = true; + try { + await web3Eth.sendTransaction(transaction).on('error', error => console.log(error)); + } catch (error) { + // @ts-ignore + console.log(error); + } + // await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + // name: 'InvalidResponseError', + // code: 101, + // message: expect.any(String), + // innerError: expect.any(Object), + // data: undefined, + // request: { + // jsonrpc: '2.0', + // id: expect.any(String), + // method: 'eth_sendTransaction', + // params: [ + // { + // from: '0x0000000000000000000000000000000000000000', + // to: '0x0000000000000000000000000000000000000000', + // gasPrice: expect.any(String), + // }, + // ], + // }, + // }); + }); }); }); From 36c9b0d950f1b882dcbb28839bda5cd83a9ae5bb Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 22 Feb 2023 21:33:45 -1000 Subject: [PATCH 05/67] WIP --- packages/web3-eth/src/rpc_method_wrappers.ts | 16 ++++++---------- packages/web3-eth/src/types.ts | 4 +++- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 1a250c49329..3a7557dd40f 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -49,6 +49,7 @@ import { Web3Context, Web3PromiEvent } from 'web3-core'; import { ETH_DATA_FORMAT, FormatType, DataFormat, DEFAULT_RETURN_FORMAT, format } from 'web3-utils'; import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator'; import { + InvalidResponseError, SignatureError, TransactionError, } from 'web3-errors'; @@ -1200,18 +1201,13 @@ export function sendTransaction< ); } } catch (error) { - const _error = await getTransactionError( - web3Context, - undefined, - undefined, - error - ); - - if (promiEvent.listenerCount('error') > 0) { - promiEvent.emit('error', _error); + if (error instanceof InvalidResponseError && + promiEvent.listenerCount('error') > 0 + ) { + promiEvent.emit('error', error); } - reject(_error); + reject(error); } })() as unknown; }); diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index 74dc54d4cb8..f5ddedd05b5 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -22,6 +22,7 @@ import { TransactionRevertedWithoutReasonError, TransactionRevertError, TransactionRevertWithCustomError, + InvalidResponseError, } from 'web3-errors'; import { Bytes, HexString, Numbers, Transaction, TransactionReceipt } from 'web3-types'; import { DataFormat, ETH_DATA_FORMAT, FormatType } from 'web3-utils'; @@ -41,7 +42,8 @@ export type SendTransactionEvents = { error: | TransactionRevertedWithoutReasonError> | TransactionRevertError> - | TransactionRevertWithCustomError>; + | TransactionRevertWithCustomError> + | InvalidResponseError; }; export type SendSignedTransactionEvents = { From 2378e6a589c0b1835f19e0b172600452d6045cf7 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 15:10:26 -1000 Subject: [PATCH 06/67] Update TransactionRevertedWithoutReasonError to handle receipts objects with BigInts --- .../web3-errors/src/errors/transaction_errors.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index 4f4f216347f..10fc84c78bb 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -103,12 +103,14 @@ export class TransactionRevertError extends Ba reason: this.reason, signature: this.signature, receipt: this.receipt, - data: this.data + data: this.data, }; } } -export class TransactionRevertWithCustomError extends TransactionRevertError { +export class TransactionRevertWithCustomError< + ReceiptType = TransactionReceipt, +> extends TransactionRevertError { public code = ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR; public constructor( @@ -132,7 +134,7 @@ export class TransactionRevertWithCustomError customErrorArguments: this.customErrorArguments, signature: this.signature, receipt: this.receipt, - data: this.data + data: this.data, }; } } @@ -155,10 +157,14 @@ export class ContractCodeNotStoredError extends TransactionError { } } -export class TransactionRevertedWithoutReasonError extends TransactionError { +export class TransactionRevertedWithoutReasonError< + ReceiptType = TransactionReceipt, +> extends TransactionError { public constructor(receipt?: ReceiptType) { super( - `Transaction has been reverted by the EVM${receipt === undefined ? '' : `:\n ${JSON.stringify(receipt, undefined, 2)}`}`, + `Transaction has been reverted by the EVM${ + receipt === undefined ? '' : `:\n ${BaseWeb3Error.convertToString(receipt)}` + }`, receipt, ); this.code = ERR_TX_REVERT_WITHOUT_REASON; From 044fea2f196d05edded97268705b3705ccf3e439 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 15:10:44 -1000 Subject: [PATCH 07/67] Update sendTransaction revert tests --- .../web3_eth/send_transaction.test.ts | 150 +++++++++++------- 1 file changed, 93 insertions(+), 57 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index a71f9f06909..427867fd778 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -359,7 +359,7 @@ describe('Web3Eth.sendTransaction', () => { }); describe('Transaction Error Scenarios', () => { - it('Should throw because gas too low', async () => { + it('Should throw InvalidResponseError because gas too low', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', @@ -391,43 +391,37 @@ describe('Web3Eth.sendTransaction', () => { }); }); - it.only('Should throw because insufficient funds', async () => { + it('Should throw InvalidResponseError because insufficient funds', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - try { - await web3Eth.sendTransaction(transaction).on('error', error => console.log(error)); - } catch (error) { - // @ts-ignore - console.log(error); - } - // await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ - // name: 'InvalidResponseError', - // code: 101, - // message: expect.any(String), - // innerError: expect.any(Object), - // data: undefined, - // request: { - // jsonrpc: '2.0', - // id: expect.any(String), - // method: 'eth_sendTransaction', - // params: [ - // { - // from: tempAcc.address, - // gasPrice: expect.any(String), - // maxFeePerGas: undefined, - // maxPriorityFeePerGas: undefined, - // to: '0x0000000000000000000000000000000000000000', - // value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', - // }, - // ], - // }, - // }); + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'InvalidResponseError', + code: 101, + message: expect.any(String), + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: tempAcc.address, + gasPrice: expect.any(String), + maxFeePerGas: undefined, + maxPriorityFeePerGas: undefined, + to: '0x0000000000000000000000000000000000000000', + value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', + }, + ], + }, + }); }); - it('Should throw because of unknown account', async () => { + it('Should throw InvalidResponseError because of unknown account', async () => { const transaction: Transaction = { from: '0x0000000000000000000000000000000000000000', to: '0x0000000000000000000000000000000000000000', @@ -453,7 +447,7 @@ describe('Web3Eth.sendTransaction', () => { }); }); - it('Should throw because of contract revert', async () => { + it('Should throw TransactionRevertError because of contract revert and return revert reason', async () => { const simpleRevertDeployTransaction: Transaction = { from: tempAcc.address, data: SimpleRevertDeploymentData, @@ -470,32 +464,74 @@ describe('Web3Eth.sendTransaction', () => { to: simpleRevertContractAddress, data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', }; + web3Eth.handleRevert = true; - try { - await web3Eth.sendTransaction(transaction).on('error', error => console.log(error)); - } catch (error) { - // @ts-ignore - console.log(error); - } - // await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ - // name: 'InvalidResponseError', - // code: 101, - // message: expect.any(String), - // innerError: expect.any(Object), - // data: undefined, - // request: { - // jsonrpc: '2.0', - // id: expect.any(String), - // method: 'eth_sendTransaction', - // params: [ - // { - // from: '0x0000000000000000000000000000000000000000', - // to: '0x0000000000000000000000000000000000000000', - // gasPrice: expect.any(String), - // }, - // ], - // }, - // }); + + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'TransactionRevertError', + code: 402, + reason: 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + receipt: { + transactionHash: expect.any(String), + transactionIndex: BigInt(0), + blockNumber: expect.any(BigInt), + blockHash: expect.any(String), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }); + }); + + it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { + const simpleRevertDeployTransaction: Transaction = { + from: tempAcc.address, + data: SimpleRevertDeploymentData, + }; + simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( + simpleRevertDeployTransaction, + ); + const simpleRevertContractAddress = ( + await web3Eth.sendTransaction(simpleRevertDeployTransaction) + ).contractAddress as Address; + + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', + }; + + web3Eth.handleRevert = false; + + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + name: 'TransactionRevertedWithoutReasonError', + code: 405, + receipt: { + transactionHash: expect.any(String), + transactionIndex: BigInt(0), + blockNumber: expect.any(BigInt), + blockHash: expect.any(String), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }); }); }); }); From 3a12870e7e54b341401e1c133d8f233163572899 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:17:21 -1000 Subject: [PATCH 08/67] Add contractAbi argument to getTransactionError --- .../src/utils/get_transaction_error.ts | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts index f6e160bf25e..e97fc29b166 100644 --- a/packages/web3-eth/src/utils/get_transaction_error.ts +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -21,9 +21,10 @@ import { TransactionRevertError, TransactionRevertWithCustomError, } from 'web3-errors'; -import { TransactionCall, TransactionReceipt } from 'web3-types'; +import { ContractAbi, TransactionCall, TransactionReceipt } from 'web3-types'; import { DataFormat, FormatType } from 'web3-utils'; import { RevertReason, RevertReasonWithCustomError } from '../types'; +// eslint-disable-next-line import/no-cycle import { getRevertReason, parseTransactionError } from './get_revert_reason'; // TODO Add support for passing contract ABI to getRevertReason? @@ -31,14 +32,15 @@ export async function getTransactionError( web3Context: Web3Context, transactionFormatted?: TransactionCall, transactionReceiptFormatted?: FormatType, - receivedError?: unknown + receivedError?: unknown, + contractAbi?: ContractAbi, ) { let reason: string | RevertReason | RevertReasonWithCustomError | undefined; if (receivedError !== undefined) { reason = parseTransactionError(receivedError); } else if (web3Context.handleRevert && transactionFormatted !== undefined) { - reason = await getRevertReason(web3Context, transactionFormatted); + reason = await getRevertReason(web3Context, transactionFormatted, contractAbi); } let error: @@ -49,38 +51,34 @@ export async function getTransactionError( error = new TransactionRevertedWithoutReasonError< FormatType >(transactionReceiptFormatted); + } else if (typeof reason === 'string') { + error = new TransactionRevertError>( + reason, + undefined, + transactionReceiptFormatted, + ); + } else if ( + (reason as RevertReasonWithCustomError).customErrorName !== undefined && + (reason as RevertReasonWithCustomError).customErrorDecodedSignature !== undefined && + (reason as RevertReasonWithCustomError).customErrorArguments !== undefined + ) { + const _reason: RevertReasonWithCustomError = reason as RevertReasonWithCustomError; + error = new TransactionRevertWithCustomError>( + _reason.reason, + _reason.customErrorName, + _reason.customErrorDecodedSignature, + _reason.customErrorArguments, + _reason.signature, + transactionReceiptFormatted, + _reason.data, + ); } else { - if (typeof reason === 'string') { - error = new TransactionRevertError>( - reason, - undefined, - transactionReceiptFormatted, - ); - } else if ( - (reason as RevertReasonWithCustomError).customErrorName !== undefined && - (reason as RevertReasonWithCustomError).customErrorDecodedSignature !== undefined && - (reason as RevertReasonWithCustomError).customErrorArguments !== undefined - ) { - const _reason: RevertReasonWithCustomError = reason as RevertReasonWithCustomError; - error = new TransactionRevertWithCustomError< - FormatType - >( - _reason.reason, - _reason.customErrorName, - _reason.customErrorDecodedSignature, - _reason.customErrorArguments, - _reason.signature, - transactionReceiptFormatted, - _reason.data, - ); - } else { - error = new TransactionRevertError>( - reason.reason, - reason.signature, - transactionReceiptFormatted, - reason.data, - ); - } + error = new TransactionRevertError>( + reason.reason, + reason.signature, + transactionReceiptFormatted, + reason.data, + ); } return error; From 63554f282f93e974fcf90a9e2bb05d58a278621d Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:18:27 -1000 Subject: [PATCH 09/67] sendTransation emits error for ContractExecutionError --- packages/web3-eth/src/rpc_method_wrappers.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 3a7557dd40f..e3e102cd8a1 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -49,6 +49,7 @@ import { Web3Context, Web3PromiEvent } from 'web3-core'; import { ETH_DATA_FORMAT, FormatType, DataFormat, DEFAULT_RETURN_FORMAT, format } from 'web3-utils'; import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator'; import { + ContractExecutionError, InvalidResponseError, SignatureError, TransactionError, @@ -81,6 +82,7 @@ import { trySendTransaction } from './utils/try_send_transaction'; import { waitForTransactionReceipt } from './utils/wait_for_transaction_receipt'; import { watchTransactionForConfirmations } from './utils/watch_transaction_for_confirmations'; import { NUMBER_DATA_FORMAT } from './constants'; +// eslint-disable-next-line import/no-cycle import { getTransactionError } from './utils/get_transaction_error'; /** @@ -1176,6 +1178,8 @@ export function sendTransaction< web3Context, transactionFormatted as TransactionCall, transactionReceiptFormatted, + undefined, + options?.contractAbi, ); if (promiEvent.listenerCount('error') > 0) { @@ -1201,7 +1205,9 @@ export function sendTransaction< ); } } catch (error) { - if (error instanceof InvalidResponseError && + if ( + (error instanceof InvalidResponseError || + error instanceof ContractExecutionError) && promiEvent.listenerCount('error') > 0 ) { promiEvent.emit('error', error); From 8c33881cfef6c8628b299bb3a78a2e61232499e3 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:18:59 -1000 Subject: [PATCH 10/67] Add ContractExecutionError to SendTransactionEvents. Add contractAbi to SendTransactionOptions --- packages/web3-eth/src/types.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index f5ddedd05b5..d1819d76c46 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -24,7 +24,14 @@ import { TransactionRevertWithCustomError, InvalidResponseError, } from 'web3-errors'; -import { Bytes, HexString, Numbers, Transaction, TransactionReceipt } from 'web3-types'; +import { + Bytes, + ContractAbi, + HexString, + Numbers, + Transaction, + TransactionReceipt, +} from 'web3-types'; import { DataFormat, ETH_DATA_FORMAT, FormatType } from 'web3-utils'; export type InternalTransaction = FormatType; @@ -43,7 +50,8 @@ export type SendTransactionEvents = { | TransactionRevertedWithoutReasonError> | TransactionRevertError> | TransactionRevertWithCustomError> - | InvalidResponseError; + | InvalidResponseError + | ContractExecutionError; }; export type SendSignedTransactionEvents = { @@ -63,6 +71,7 @@ export type SendSignedTransactionEvents = { export interface SendTransactionOptions { ignoreGasPricing?: boolean; transactionResolver?: (receipt: TransactionReceipt) => ResolveType; + contractAbi?: ContractAbi; } export interface SendSignedTransactionOptions { From 853d0b2618ac6f95c23c743e8fa540fcd3f70ac8 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:20:31 -1000 Subject: [PATCH 11/67] Replace use of contractExecutionError sendTransaction event with error --- packages/web3-eth-contract/src/contract.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 666df4ecb8d..098575137e4 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -1053,7 +1053,7 @@ export class Contract const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT); // eslint-disable-next-line no-void - void transactionToSend.on('contractExecutionError', (error: unknown) => { + void transactionToSend.on('error', (error: unknown) => { if (error instanceof ContractExecutionError) { // this will parse the error data by trying to decode the ABI error inputs according to EIP-838 decodeContractErrorData(errorsAbi, error.innerError); From bd4ff704adb3d9078dd3c0c4aefe9c7c7b73654d Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:20:53 -1000 Subject: [PATCH 12/67] Update contract_methods reverts test --- .../test/integration/contract_methods.test.ts | 41 ++++++++++--------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts index 7cfed117bdc..e48d296eca3 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts @@ -146,27 +146,28 @@ describe('contract', () => { expect(await deployedTempContract.methods.getStringValue().call()).toBe('TEST'); }); - // TODO: Get and match the revert error message it('should returns errors on reverts', async () => { - try { - await contractDeployed.methods.reverts().send(sendOptions); - } catch (receipt: any) { - // eslint-disable-next-line jest/no-conditional-expect - expect(receipt).toEqual( - // eslint-disable-next-line jest/no-conditional-expect - expect.objectContaining({ - // eslint-disable-next-line jest/no-conditional-expect - transactionHash: expect.any(String), - }), - ); - - // To avoid issue with the `objectContaining` and `cypress` had to add - // these expectations explicitly on each attribute - // eslint-disable-next-line jest/no-conditional-expect - expect(receipt.status).toEqual(BigInt(0)); - } - - expect.assertions(2); + await expect( + contractDeployed.methods.reverts().send(sendOptions), + ).rejects.toMatchObject({ + name: 'TransactionRevertedWithoutReasonError', + receipt: { + blockHash: expect.any(String), + blockNumber: expect.any(BigInt), + cumulativeGasUsed: BigInt(21543), + effectiveGasPrice: expect.any(BigInt), + from: acc.address, + gasUsed: BigInt(21543), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + to: expect.any(String), + transactionHash: expect.any(String), + transactionIndex: BigInt(0), + type: BigInt(0), + }, + }); }); }); }); From d075a86105b45436646ce97cf2ec56112cf81c70 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 16:30:22 -1000 Subject: [PATCH 13/67] Update web3-errors test --- packages/web3-errors/test/unit/errors.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-errors/test/unit/errors.test.ts b/packages/web3-errors/test/unit/errors.test.ts index a267ad5dd7c..1ca30c26bb1 100644 --- a/packages/web3-errors/test/unit/errors.test.ts +++ b/packages/web3-errors/test/unit/errors.test.ts @@ -53,7 +53,7 @@ describe('errors', () => { // To disable error for the abstract class // eslint-disable-next-line @typescript-eslint/ban-ts-comment - const err = new ErrorClass({} as never, {} as never, {} as never); + const err = new ErrorClass({} as never, {} as never, {} as never, {} as never); errorCodes.push(err.code); } From 2b59dc660251bae60bfca941bea0e2f20e76537d Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 17:05:30 -1000 Subject: [PATCH 14/67] Update expected error mesage for contract_deploy_test --- .../web3-eth-contract/test/integration/contract_deploy.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts index f89008d7b95..c97ad326171 100644 --- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts @@ -225,7 +225,7 @@ describe('contract', () => { it('should fail with errors on "intrinsic gas too low" OOG', async () => { await expect( contract.deploy(deployOptions).send({ ...sendOptions, gas: '100' }), - ).rejects.toThrow('Returned error: intrinsic gas too low'); + ).rejects.toThrow('intrinsic gas too low'); }); it('should fail with errors deploying a zero length bytecode', () => { From 7e830d21fbbff0a176f62530e053e61fb35dfa17 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 17:09:53 -1000 Subject: [PATCH 15/67] Add expectedErrorObject based on test backend --- .../web3_eth/send_transaction.test.ts | 121 +++++++++++------- 1 file changed, 78 insertions(+), 43 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 427867fd778..e6705555bc6 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -15,6 +15,10 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +// TODO Seems to be an issue with linter falsely reporting this +// error for Transaction Error Scenarios tests +/* eslint-disable jest/no-conditional-expect */ + import { Transaction, TransactionWithFromLocalWalletIndex, @@ -30,6 +34,7 @@ import { closeOpenConnection, createAccountProvider, createTempAccount, + getSystemTestBackend, getSystemTestProvider, } from '../../fixtures/system_test_utils'; import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; @@ -467,29 +472,44 @@ describe('Web3Eth.sendTransaction', () => { web3Eth.handleRevert = true; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ - name: 'TransactionRevertError', - code: 402, - reason: 'VM Exception while processing transaction: revert This is a send revert', - signature: '0x08c379a0', - data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - receipt: { - transactionHash: expect.any(String), - transactionIndex: BigInt(0), - blockNumber: expect.any(BigInt), - blockHash: expect.any(String), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, - }); + const expectedErrorObject = + getSystemTestBackend() === 'geth' + ? { + name: 'ContractExecutionError', + code: 310, + innerError: { + name: 'Eip838ExecutionError', + code: 3, + data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }, + } + : { + name: 'TransactionRevertError', + code: 402, + reason: 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + receipt: { + transactionHash: expect.any(String), + transactionIndex: BigInt(0), + blockNumber: expect.any(BigInt), + blockHash: expect.any(String), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( + expectedErrorObject, + ); }); it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { @@ -512,26 +532,41 @@ describe('Web3Eth.sendTransaction', () => { web3Eth.handleRevert = false; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ - name: 'TransactionRevertedWithoutReasonError', - code: 405, - receipt: { - transactionHash: expect.any(String), - transactionIndex: BigInt(0), - blockNumber: expect.any(BigInt), - blockHash: expect.any(String), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, - }); + const expectedErrorObject = + getSystemTestBackend() === 'geth' + ? { + name: 'ContractExecutionError', + code: 310, + innerError: { + name: 'Eip838ExecutionError', + code: 3, + data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }, + } + : { + name: 'TransactionRevertedWithoutReasonError', + code: 405, + receipt: { + transactionHash: expect.any(String), + transactionIndex: BigInt(0), + blockNumber: expect.any(BigInt), + blockHash: expect.any(String), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( + expectedErrorObject, + ); }); }); }); From 91a4e6fead0a59ff0e7c7be242b35a5da0c92a7f Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 18:04:27 -1000 Subject: [PATCH 16/67] Correct web3-errors test snapshots --- .../unit/__snapshots__/errors.test.ts.snap | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap index 9e6705c7e85..2bc868b11eb 100644 --- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap @@ -170,8 +170,9 @@ Object { }, "message": "error message", }, - "message": "Returned error: error message", + "message": "error message", "name": "InvalidResponseError", + "request": undefined, } `; @@ -227,8 +228,9 @@ Object { "b": "20", }, "innerError": undefined, - "message": "Returned error: error message", + "message": "error message", "name": "ResponseError", + "request": undefined, } `; @@ -237,8 +239,9 @@ Object { "code": 100, "data": undefined, "innerError": undefined, - "message": "Returned error: error message", + "message": "error message", "name": "ResponseError", + "request": undefined, } `; @@ -283,11 +286,9 @@ Object { exports[`errors TransactionRevertError should have valid json structure 1`] = ` Object { "code": 402, + "data": undefined, "innerError": undefined, - "message": "Transaction has been reverted by the EVM: - { - \\"attr1\\": \\"attr1\\" -}", + "message": "message", "name": "TransactionRevertError", "reason": "message", "receipt": Object { @@ -302,9 +303,7 @@ Object { "code": 405, "innerError": undefined, "message": "Transaction has been reverted by the EVM: - { - \\"attr1\\": \\"attr1\\" -}", + {\\"attr1\\":\\"attr1\\"}", "name": "TransactionRevertedWithoutReasonError", "receipt": Object { "attr1": "attr1", From ff142e06a95447d681e2858b685fe0681a0bec41 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Fri, 24 Feb 2023 18:25:55 -0500 Subject: [PATCH 17/67] fix (#5869) --- packages/web3-providers-ws/test/fixtures/proxy.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/web3-providers-ws/test/fixtures/proxy.ts b/packages/web3-providers-ws/test/fixtures/proxy.ts index db883eeb6d9..37747506647 100644 --- a/packages/web3-providers-ws/test/fixtures/proxy.ts +++ b/packages/web3-providers-ws/test/fixtures/proxy.ts @@ -48,14 +48,22 @@ export const createProxy = async ( }); closeFunc = async () => { await new Promise(resolve => { + const timeOut = setTimeout(() => { + resolve(true); + }, 2000); ws.on('close', () => { ws.removeAllListeners(); + clearTimeout(timeOut); resolve(true); }); ws.terminate(); }); await new Promise(resolve => { + const timeOut = setTimeout(() => { + resolve(true); + }, 2000); originWs.on('close', () => { + clearTimeout(timeOut); originWs.removeAllListeners(); resolve(true); }); From 89489732eb2c9a6e20217d9ee51bd99a1ce2a57f Mon Sep 17 00:00:00 2001 From: Junaid <86780488+jdevcs@users.noreply.github.com> Date: Tue, 28 Feb 2023 13:43:10 +0100 Subject: [PATCH 18/67] 5747 codecov (#5843) * code cov integration for unit tests * removed cov threshold * code cov token * by default collect coverage * codecov with existing unittests * jest config * only analyze coverage for n v16 unit test runs * node ver * codecov paths config * added layout * common config * flag names in ci * flags under proj * min CI for test * build and test for u14 and 16 * validated yml * components usage * comment moved at end * updated comments * testing 90% cov target * component cov target * patch cov * enable actions + remove old coverage check actions * codecov config change * remove unused scripts --- .github/workflows/build.yml | 65 ++-------------- codecov.yml | 78 +++++++++++++++++++ package.json | 5 -- packages/web3-core/test/unit/jest.config.js | 11 ++- packages/web3-errors/test/unit/jest.config.js | 11 ++- .../web3-eth-abi/test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- .../web3-eth-ens/test/unit/jest.config.js | 11 ++- .../web3-eth-iban/test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- packages/web3-eth/test/unit/jest.config.js | 11 ++- packages/web3-net/test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- .../test/unit/jest.config.js | 11 ++- .../web3-rpc-methods/test/unit/jest.config.js | 11 ++- packages/web3-utils/test/unit/jest.config.js | 11 ++- .../web3-validator/test/unit/jest.config.js | 11 ++- packages/web3/test/unit/jest.config.js | 11 ++- templates/jest.config.js.tmpl | 6 +- 21 files changed, 255 insertions(+), 86 deletions(-) create mode 100644 codecov.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ab02246dea3..d1141df254d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -83,6 +83,12 @@ jobs: path: /tmp - run: tar -xf /tmp/web3-${{ matrix.node }}.js.tar.gz -C ./ - run: yarn test:unit + - name: Upload coverage to Codecov + uses: codecov/codecov-action@v3 + with: + flags: UnitTests + token: ${{ secrets.CODECOV_TOKEN }} + if: ${{ matrix.node == 16 }} integration: name: Integration @@ -186,62 +192,3 @@ jobs: path: /tmp - run: tar -xf /tmp/web3-${{ matrix.node }}.js.tar.gz -C ./ - run: yarn build:docs - - coverage-tests-unit: - name: Coverage Tests - Unit - needs: build - runs-on: ubuntu-latest - strategy: - matrix: - node: [16] - steps: - - uses: actions/download-artifact@v3 - with: - name: web3-${{ matrix.node }}.js.tar.gz - path: /tmp - - run: tar -xf /tmp/web3-${{ matrix.node }}.js.tar.gz -C ./ - - run: yarn test:coverage:unit - - coverage-tests-integration: - name: Coverage Tests - Integration - needs: build - runs-on: ubuntu-latest - env: - INFURA_GOERLI_HTTP: ${{ secrets.INFURA_GOERLI_HTTP }} - INFURA_GOERLI_WS: ${{ secrets.INFURA_GOERLI_WS }} - strategy: - fail-fast: false - matrix: - node: [16] - backend: ['geth', 'ganache'] - mode: ['http', 'ws'] - steps: - - uses: actions/download-artifact@v3 - with: - name: web3-${{ matrix.node }}.js.tar.gz - path: /tmp - - run: tar -xf /tmp/web3-${{ matrix.node }}.js.tar.gz -C ./ - - run: yarn test:coverage:e2e:${{ matrix.backend }}:${{ matrix.mode }} - shell: bash - - coverage-tests-ipc: - name: Coverage Tests - Integration IPC - needs: build - runs-on: ubuntu-latest - env: - INFURA_GOERLI_HTTP: ${{ secrets.INFURA_GOERLI_HTTP }} - INFURA_GOERLI_WS: ${{ secrets.INFURA_GOERLI_WS }} - strategy: - fail-fast: false - matrix: - node: [ 16 ] - backend: [ 'geth' ] - mode: [ 'ipc' ] - steps: - - uses: actions/download-artifact@v3 - with: - name: web3-${{ matrix.node }}.js.tar.gz - path: /tmp - - run: tar -xf /tmp/web3-${{ matrix.node }}.js.tar.gz -C ./ - - run: yarn test:coverage:e2e:${{ matrix.backend }}:${{ matrix.mode }} - shell: bash diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..c80b88db171 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,78 @@ +coverage: + status: + project: + default: + target: 80% + threshold: 1% + patch: + default: + target: auto + threshold: 5% + +component_management: + default_rules: # default rules that will be inherited by all components + statuses: + - type: project + target: 80% + - type: patch + target: 80% + + individual_components: + - component_id: "web3" + paths: + - /packages/web3/src/ + - component_id: "web3-core" + paths: + - /packages/web3-core/src/ + - component_id: "web3-errors" + paths: + - /packages/web3-errors/src/ + - component_id: "web3-eth" + paths: + - /packages/web3-eth/src/ + - component_id: "web3-eth-abi" + paths: + - /packages/web3-eth-abi/src/ + - component_id: "web3-eth-accounts" + paths: + - /packages/web3-eth-accounts/src/ + - component_id: "web3-eth-contract" + paths: + - /packages/web3-eth-contract/src/ + - component_id: "web3-eth-ens" + paths: + - /packages/web3-eth-ens/src/ + - component_id: "web3-eth-iban" + paths: + - /packages/web3-eth-iban/src/ + - component_id: "web3-eth-personal" + paths: + - /packages/web3-eth-personal/src/ + - component_id: "web3-net" + paths: + - /packages/web3-net/src/ + - component_id: "web3-providers-http" + paths: + - /packages/web3-providers-http/src/ + - component_id: "web3-providers-ipc" + paths: + - /packages/web3-providers-ipc/src/ + - component_id: "web3-providers-ws" + paths: + - /packages/web3-providers-ws/src/ + - component_id: "web3-rpc-methods" + paths: + - /packages/web3-rpc-methods/src/ + - component_id: "web3-utils" + paths: + - /packages/web3-utils/src/ + - component_id: "web3-validator" + paths: + - /packages/web3-validator/src/ + +comment: + layout: 'header, diff, flags, components' + behavior: 'default' + require_changes: false + require_base: no + require_head: no \ No newline at end of file diff --git a/package.json b/package.json index f6cfced21d6..0e9af4f1bcb 100644 --- a/package.json +++ b/package.json @@ -67,11 +67,6 @@ "test:e2e:geth:ipc": "./scripts/test-runner.sh geth ipc", "test:sync:e2e:geth:ws": "./scripts/test-runner.sh geth ws node sync", "test:sync:e2e:geth:ipc": "./scripts/test-runner.sh geth ipc node sync", - "test:coverage:e2e:ganache:http": "./scripts/test-runner.sh ganache http node coverage", - "test:coverage:e2e:ganache:ws": "./scripts/test-runner.sh ganache ws node coverage", - "test:coverage:e2e:geth:http": "./scripts/test-runner.sh geth http node coverage", - "test:coverage:e2e:geth:ws": "./scripts/test-runner.sh geth ws node coverage", - "test:coverage:e2e:geth:ipc": "./scripts/test-runner.sh geth ipc node coverage", "test:e2e:ganache:ws:electron": "./scripts/test-runner.sh ganache ws electron", "test:e2e:ganache:ws:chrome": "./scripts/test-runner.sh ganache ws chrome", "test:e2e:ganache:ws:firefox": "./scripts/test-runner.sh ganache ws firefox", diff --git a/packages/web3-core/test/unit/jest.config.js b/packages/web3-core/test/unit/jest.config.js index ceac341e332..0d8c33a998a 100644 --- a/packages/web3-core/test/unit/jest.config.js +++ b/packages/web3-core/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-core-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-errors/test/unit/jest.config.js b/packages/web3-errors/test/unit/jest.config.js index ceac341e332..ba9d5b9b33c 100644 --- a/packages/web3-errors/test/unit/jest.config.js +++ b/packages/web3-errors/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-errors-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-abi/test/unit/jest.config.js b/packages/web3-eth-abi/test/unit/jest.config.js index ceac341e332..6acd2aba2ee 100644 --- a/packages/web3-eth-abi/test/unit/jest.config.js +++ b/packages/web3-eth-abi/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-abi-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-accounts/test/unit/jest.config.js b/packages/web3-eth-accounts/test/unit/jest.config.js index ceac341e332..de9992fdf10 100644 --- a/packages/web3-eth-accounts/test/unit/jest.config.js +++ b/packages/web3-eth-accounts/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-accounts-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-contract/test/unit/jest.config.js b/packages/web3-eth-contract/test/unit/jest.config.js index ceac341e332..06b5f59117a 100644 --- a/packages/web3-eth-contract/test/unit/jest.config.js +++ b/packages/web3-eth-contract/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-contract-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-ens/test/unit/jest.config.js b/packages/web3-eth-ens/test/unit/jest.config.js index ceac341e332..c88b5aeb17d 100644 --- a/packages/web3-eth-ens/test/unit/jest.config.js +++ b/packages/web3-eth-ens/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-ens-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-iban/test/unit/jest.config.js b/packages/web3-eth-iban/test/unit/jest.config.js index ceac341e332..7e869778053 100644 --- a/packages/web3-eth-iban/test/unit/jest.config.js +++ b/packages/web3-eth-iban/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-iban-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth-personal/test/unit/jest.config.js b/packages/web3-eth-personal/test/unit/jest.config.js index ceac341e332..3815ba858d7 100644 --- a/packages/web3-eth-personal/test/unit/jest.config.js +++ b/packages/web3-eth-personal/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-personal-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-eth/test/unit/jest.config.js b/packages/web3-eth/test/unit/jest.config.js index ceac341e332..2ec33b0110d 100644 --- a/packages/web3-eth/test/unit/jest.config.js +++ b/packages/web3-eth/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-eth-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-net/test/unit/jest.config.js b/packages/web3-net/test/unit/jest.config.js index ceac341e332..6730195e8b5 100644 --- a/packages/web3-net/test/unit/jest.config.js +++ b/packages/web3-net/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-net-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-providers-http/test/unit/jest.config.js b/packages/web3-providers-http/test/unit/jest.config.js index ceac341e332..6e44877cd60 100644 --- a/packages/web3-providers-http/test/unit/jest.config.js +++ b/packages/web3-providers-http/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-providers-http-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-providers-ipc/test/unit/jest.config.js b/packages/web3-providers-ipc/test/unit/jest.config.js index ceac341e332..bd20de1a9bf 100644 --- a/packages/web3-providers-ipc/test/unit/jest.config.js +++ b/packages/web3-providers-ipc/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-providers-ipc-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-providers-ws/test/unit/jest.config.js b/packages/web3-providers-ws/test/unit/jest.config.js index ceac341e332..0fb5407df6a 100644 --- a/packages/web3-providers-ws/test/unit/jest.config.js +++ b/packages/web3-providers-ws/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-providers-ws-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-rpc-methods/test/unit/jest.config.js b/packages/web3-rpc-methods/test/unit/jest.config.js index ceac341e332..35542a2b387 100644 --- a/packages/web3-rpc-methods/test/unit/jest.config.js +++ b/packages/web3-rpc-methods/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-rpc-methods-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-utils/test/unit/jest.config.js b/packages/web3-utils/test/unit/jest.config.js index ceac341e332..fc28d37c499 100644 --- a/packages/web3-utils/test/unit/jest.config.js +++ b/packages/web3-utils/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-utils-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3-validator/test/unit/jest.config.js b/packages/web3-validator/test/unit/jest.config.js index ceac341e332..c524db4732b 100644 --- a/packages/web3-validator/test/unit/jest.config.js +++ b/packages/web3-validator/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-validator-unit-coverage.json', + }, + ], + ], }; diff --git a/packages/web3/test/unit/jest.config.js b/packages/web3/test/unit/jest.config.js index ceac341e332..36386477f13 100644 --- a/packages/web3/test/unit/jest.config.js +++ b/packages/web3/test/unit/jest.config.js @@ -4,6 +4,15 @@ module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - coverageDirectory: '.coverage/unit', + coverageDirectory: '../../.coverage/unit', collectCoverageFrom: ['src/**'], + collectCoverage: true, + coverageReporters: [ + [ + 'json', + { + file: 'web3-unit-coverage.json', + }, + ], + ], }; diff --git a/templates/jest.config.js.tmpl b/templates/jest.config.js.tmpl index 62ff0707018..ee2c5b18998 100644 --- a/templates/jest.config.js.tmpl +++ b/templates/jest.config.js.tmpl @@ -30,11 +30,7 @@ module.exports = { collectCoverage: false, coverageReporters: ['json'], coverageDirectory: '.coverage', - coverageThreshold: { - global: { - lines: 80, - }, - }, + /** * restoreMocks [boolean] * From c39aab25afea450a3830622d9d918899de2725fa Mon Sep 17 00:00:00 2001 From: Nikos Iliakis Date: Tue, 28 Feb 2023 16:37:31 +0200 Subject: [PATCH 19/67] ens system tests (#5849) * Expose registry events in ens class * Add tests for events * Check for socket * Skip test * Try to unskip test * skip test again * Update packages/web3-eth-ens/test/integration/ens.events.test.ts Co-authored-by: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> * feedback --------- Co-authored-by: Junaid <86780488+jdevcs@users.noreply.github.com> Co-authored-by: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> --- packages/web3-eth-ens/src/ens.ts | 4 + packages/web3-eth-ens/src/registry.ts | 3 + .../test/integration/ens.events.test.ts | 201 ++++++++++++++++++ .../test/integration/resolver.test.ts | 15 ++ .../test/integration/reconnection.test.ts | 4 +- 5 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 packages/web3-eth-ens/test/integration/ens.events.test.ts diff --git a/packages/web3-eth-ens/src/ens.ts b/packages/web3-eth-ens/src/ens.ts index 264f1e31331..5359e885f79 100644 --- a/packages/web3-eth-ens/src/ens.ts +++ b/packages/web3-eth-ens/src/ens.ts @@ -293,4 +293,8 @@ export class ENS extends Web3Context { public async supportsInterface(ENSName: string, interfaceId: string) { return this._resolver.supportsInterface(ENSName, interfaceId); } + + public get events() { + return this._registry.events; + } } diff --git a/packages/web3-eth-ens/src/registry.ts b/packages/web3-eth-ens/src/registry.ts index 89a875f7fcb..88b91378862 100644 --- a/packages/web3-eth-ens/src/registry.ts +++ b/packages/web3-eth-ens/src/registry.ts @@ -234,4 +234,7 @@ export class Registry { throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented } } + public get events() { + return this.contract.events; + } } diff --git a/packages/web3-eth-ens/test/integration/ens.events.test.ts b/packages/web3-eth-ens/test/integration/ens.events.test.ts new file mode 100644 index 00000000000..5b859600b69 --- /dev/null +++ b/packages/web3-eth-ens/test/integration/ens.events.test.ts @@ -0,0 +1,201 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Contract, PayableTxOptions } from 'web3-eth-contract'; +import { sha3, DEFAULT_RETURN_FORMAT } from 'web3-utils'; +import { getBlock } from 'web3-eth'; + +import { Address, Bytes } from 'web3-types'; +import { ENS } from '../../src'; +import { namehash } from '../../src/utils'; + +import { + getSystemTestAccounts, + getSystemTestProvider, + isWs, + isIpc, + closeOpenConnection, + isSocket, + describeIf, +} from '../fixtures/system_tests_utils'; + +import { ENSRegistryAbi } from '../../src/abi/ens/ENSRegistry'; +import { ENSRegistryBytecode } from '../fixtures/ens/bytecode/ENSRegistryBytecode'; +import { NameWrapperAbi } from '../fixtures/ens/abi/NameWrapper'; +import { NameWrapperBytecode } from '../fixtures/ens/bytecode/NameWrapperBytecode'; +import { PublicResolverAbi } from '../../src/abi/ens/PublicResolver'; +import { PublicResolverBytecode } from '../fixtures/ens/bytecode/PublicResolverBytecode'; + +describeIf(isSocket)('ens events', () => { + let registry: Contract; + let resolver: Contract; + let nameWrapper: Contract; + + type ResolverContract = Contract; + + let Resolver: ResolverContract; + let setEnsResolver: ResolverContract; + let getEnsResolver: ResolverContract; + + let sendOptions: PayableTxOptions; + + const domain = 'test'; + const node = namehash('resolver'); + const label = sha3('resolver') as string; + + const web3jsName = 'web3js.test'; + + const ttl = 3600; + + let accounts: string[]; + let ens: ENS; + let defaultAccount: string; + let accountOne: string; + + const ZERO_NODE: Bytes = '0x0000000000000000000000000000000000000000000000000000000000000000'; + const addressOne: Address = '0x0000000000000000000000000000000000000001'; + + beforeAll(async () => { + accounts = await getSystemTestAccounts(); + + [defaultAccount, accountOne] = accounts; + + sendOptions = { from: defaultAccount, gas: '10000000' }; + + const Registry = new Contract(ENSRegistryAbi, undefined, { + provider: getSystemTestProvider(), + }); + + const NameWrapper = new Contract(NameWrapperAbi, undefined, { + provider: getSystemTestProvider(), + }); + + Resolver = new Contract(PublicResolverAbi, undefined, { + provider: getSystemTestProvider(), + }); + + registry = await Registry.deploy({ data: ENSRegistryBytecode }).send(sendOptions); + + nameWrapper = await NameWrapper.deploy({ data: NameWrapperBytecode }).send(sendOptions); + + resolver = await Resolver.deploy({ + data: PublicResolverBytecode, + arguments: [ + registry.options.address as string, + nameWrapper.options.address as string, + accountOne, + defaultAccount, + ], + }).send(sendOptions); + + await registry.methods.setSubnodeOwner(ZERO_NODE, label, defaultAccount).send(sendOptions); + await registry.methods + .setResolver(node, resolver.options.address as string) + .send(sendOptions); + await resolver.methods.setAddr(node, addressOne).send(sendOptions); + + await registry.methods + .setSubnodeOwner(ZERO_NODE, sha3(domain) as string, defaultAccount) + .send(sendOptions); + + const clientUrl = getSystemTestProvider(); + let provider; + if (isIpc) provider = new ENS.providers.IpcProvider(clientUrl); + else if (isWs) provider = new ENS.providers.WebsocketProvider(clientUrl); + else provider = new ENS.providers.HttpProvider(clientUrl); + + ens = new ENS(registry.options.address, provider); + + const block = await getBlock(ens, 'latest', false, DEFAULT_RETURN_FORMAT); + const gas = block.gasLimit.toString(); + + // Increase gas for contract calls + sendOptions = { + ...sendOptions, + gas, + }; + }); + + afterAll(async () => { + await closeOpenConnection(ens); + // @ts-expect-error @typescript-eslint/ban-ts-comment + await closeOpenConnection(ens?._registry?.contract); + await closeOpenConnection(getEnsResolver); + await closeOpenConnection(setEnsResolver); + await closeOpenConnection(registry); + await closeOpenConnection(resolver); + await closeOpenConnection(nameWrapper); + }); + + beforeEach(async () => { + // set up subnode + await registry.methods + .setSubnodeOwner(namehash(domain), sha3('web3js') as string, defaultAccount) + .send(sendOptions); + }); + + // eslint-disable-next-line jest/expect-expect, jest/no-done-callback, jest/consistent-test-it + it('ApprovalForAll event', async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor + await new Promise(async resolve => { + const event = ens.events.ApprovalForAll(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + event.on('data', () => { + resolve(); + }); + + await ens.setApprovalForAll(accountOne, true, sendOptions); + }); + }); + + // eslint-disable-next-line jest/expect-expect, jest/no-done-callback + test('NewTTL event', async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor + await new Promise(async resolve => { + const event = ens.events.NewTTL(); + + event.on('data', () => { + resolve(); + }); + + event.on('error', () => { + resolve(); + }); + + await ens.setTTL(web3jsName, ttl, sendOptions); + }); + }); + + // eslint-disable-next-line jest/expect-expect, jest/no-done-callback, jest/consistent-test-it + it('NewResolver event', async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor + await new Promise(async resolve => { + const mockAddress = '0x0000000000000000000000000000000000000000'; + const ENS_NAME = 'web3js.eth'; + const event = ens.events.NewResolver(); + + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + event.on('data', () => { + resolve(); + }); + + await ens.setResolver(ENS_NAME, mockAddress, sendOptions); + }); + }); +}); diff --git a/packages/web3-eth-ens/test/integration/resolver.test.ts b/packages/web3-eth-ens/test/integration/resolver.test.ts index 096df74ac6c..8b50fd89e2c 100644 --- a/packages/web3-eth-ens/test/integration/resolver.test.ts +++ b/packages/web3-eth-ens/test/integration/resolver.test.ts @@ -31,6 +31,7 @@ import { isIpc, closeOpenConnection, isSocket, + itIf, } from '../fixtures/system_tests_utils'; import { ENSRegistryAbi } from '../../src/abi/ens/ENSRegistry'; @@ -197,6 +198,20 @@ describe('ens', () => { expect(res).toBe(contentHash); }); + // eslint-disable-next-line jest/expect-expect + itIf(isSocket)('ContenthashChanged event', async () => { + // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor + await new Promise(async resolve => { + const resolver2 = await ens.getResolver('resolver'); + const event = resolver2.events.ContenthashChanged(); + + event.on('data', () => { + resolve(); + }); + await ens.setContenthash(domain, contentHash, sendOptions); + }); + }); + it('fetches contenthash', async () => { await resolver.methods.setContenthash(domainNode, contentHash).call(sendOptions); diff --git a/packages/web3-providers-ws/test/integration/reconnection.test.ts b/packages/web3-providers-ws/test/integration/reconnection.test.ts index 34fd0749039..aaf3acdb533 100644 --- a/packages/web3-providers-ws/test/integration/reconnection.test.ts +++ b/packages/web3-providers-ws/test/integration/reconnection.test.ts @@ -84,7 +84,9 @@ describeIf(isWs && !isBrowser)('WebSocketProvider - reconnection', () => { expect(!!(await disconnectPromise)).toBe(true); }); - it('should connect, disconnect and reconnect', async () => { + + // eslint-disable-next-line jest/no-disabled-tests + it.skip('should connect, disconnect and reconnect', async () => { const server = await createProxy(18546, getSystemTestProvider()); const web3Provider = new WebSocketProvider(server.path, {}, reconnectionOptions); From 3cb0a27c6d821e84d7949d069310cc03b82ecbf7 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Tue, 28 Feb 2023 10:30:40 -0500 Subject: [PATCH 20/67] Disconnect function doesn't exists in types of currentProvider (#5865) * fix disconnect function * add link * test types * add disconnect function test * fix eth tests * test stuck * trace * fix * check * fix test * add empty disconnect function * add test for provider instances * fix http unit test * remove logs * revert to throw error http provider --------- Co-authored-by: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> --- packages/web3-core/src/web3_context.ts | 9 ++-- .../test/integration/defaults.test.ts | 5 +- .../test/integration/reconnection.test.ts | 25 ++-------- packages/web3-utils/src/socket_provider.ts | 7 ++- packages/web3/test/integration/web3.test.ts | 46 ++++++++++++++++++- 5 files changed, 59 insertions(+), 33 deletions(-) diff --git a/packages/web3-core/src/web3_context.ts b/packages/web3-core/src/web3_context.ts index 1c749c06845..1bde6a502bb 100644 --- a/packages/web3-core/src/web3_context.ts +++ b/packages/web3-core/src/web3_context.ts @@ -23,6 +23,7 @@ import { SupportedProviders, HexString, EthExecutionAPI, + Web3BaseProvider, } from 'web3-types'; import { isNullish } from 'web3-utils'; import { ExistingPluginNamespaceError } from 'web3-errors'; @@ -268,8 +269,8 @@ export class Web3Context< * ``` */ - public get provider(): SupportedProviders | string | undefined { - return this.requestManager.provider; + public get provider(): Web3BaseProvider | undefined { + return this.currentProvider; } /** @@ -310,8 +311,8 @@ export class Web3Context< * } * ``` */ - public get currentProvider(): SupportedProviders | string | undefined { - return this.requestManager.provider; + public get currentProvider(): Web3BaseProvider | undefined { + return this.requestManager.provider as Web3BaseProvider; } /** diff --git a/packages/web3-eth/test/integration/defaults.test.ts b/packages/web3-eth/test/integration/defaults.test.ts index 089729c40c8..11fdbc8011b 100644 --- a/packages/web3-eth/test/integration/defaults.test.ts +++ b/packages/web3-eth/test/integration/defaults.test.ts @@ -543,8 +543,7 @@ describe('defaults', () => { // It will cause providers that does not support subscriptions (like http) to throw exception when subscribing. // This case is tested to ensure that even if an error happen at subscription, // polling will still get the data from next blocks. - (tempEth.provider as Web3BaseProvider>).supportsSubscriptions = - () => true; + (tempEth.provider as Web3BaseProvider).supportsSubscriptions = () => true; // Cause the events to take a long time (more than blockHeaderTimeout), // to ensure that polling of new blocks works in such cases. @@ -552,7 +551,7 @@ describe('defaults', () => { // to never return data through listening to new events // eslint-disable-next-line @typescript-eslint/no-misused-promises - (tempEth.provider as Web3BaseProvider>).on = async () => { + (tempEth.provider as Web3BaseProvider).on = async () => { await new Promise(res => { setTimeout(res, 1000000); }); diff --git a/packages/web3-providers-ws/test/integration/reconnection.test.ts b/packages/web3-providers-ws/test/integration/reconnection.test.ts index aaf3acdb533..f0b9e735903 100644 --- a/packages/web3-providers-ws/test/integration/reconnection.test.ts +++ b/packages/web3-providers-ws/test/integration/reconnection.test.ts @@ -89,33 +89,14 @@ describeIf(isWs && !isBrowser)('WebSocketProvider - reconnection', () => { it.skip('should connect, disconnect and reconnect', async () => { const server = await createProxy(18546, getSystemTestProvider()); const web3Provider = new WebSocketProvider(server.path, {}, reconnectionOptions); - expect(!!(await waitForEvent(web3Provider, 'connect'))).toBe(true); - - // @ts-expect-error-next-line - // eslint-disable-next-line @typescript-eslint/no-unused-vars - web3Provider._onCloseHandler = (_: CloseEvent) => { - // @ts-expect-error-next-line - web3Provider._onCloseEvent({ code: 1002 }); - }; - // @ts-expect-error-next-line - web3Provider._removeSocketListeners(); - // @ts-expect-error-next-line - web3Provider._addSocketListeners(); + web3Provider.disconnect(1002); await server.close(); const connectEvent = waitForEvent(web3Provider, 'connect'); const server2 = await createProxy(18546, getSystemTestProvider()); expect(!!(await connectEvent)).toBe(true); - // @ts-expect-error-next-line - web3Provider._onCloseHandler = (event: CloseEvent) => { - // @ts-expect-error-next-line - web3Provider._onCloseEvent(event); - }; - // @ts-expect-error-next-line - web3Provider._removeSocketListeners(); - // @ts-expect-error-next-line - web3Provider._addSocketListeners(); - web3Provider.disconnect(1000, 'test'); + + web3Provider.disconnect(); await waitForEvent(web3Provider, 'disconnect'); await server2.close(); }); diff --git a/packages/web3-utils/src/socket_provider.ts b/packages/web3-utils/src/socket_provider.ts index 9e94b7f20ef..7c5fcda3287 100644 --- a/packages/web3-utils/src/socket_provider.ts +++ b/packages/web3-utils/src/socket_provider.ts @@ -55,6 +55,8 @@ type ReconnectOptions = { type EventType = 'message' | 'connect' | 'disconnect' | 'chainChanged' | 'accountsChanged' | string; +const NORMAL_CLOSE_CODE = 1000; // https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close + export abstract class SocketProvider< MessageEvent, CloseEvent, @@ -216,11 +218,12 @@ export abstract class SocketProvider< * @param data - The data to be sent to the server */ public disconnect(code?: number, data?: string): void { + const disconnectCode = code ?? NORMAL_CLOSE_CODE; this._removeSocketListeners(); if (this.getStatus() !== 'disconnected') { - this._closeSocketConnection(code, data); + this._closeSocketConnection(disconnectCode, data); } - this._onDisconnect(code, data); + this._onDisconnect(disconnectCode, data); } /** diff --git a/packages/web3/test/integration/web3.test.ts b/packages/web3/test/integration/web3.test.ts index c831cbd164a..918444bdc0a 100644 --- a/packages/web3/test/integration/web3.test.ts +++ b/packages/web3/test/integration/web3.test.ts @@ -19,7 +19,7 @@ import { JsonRpcOptionalRequest, Web3BaseProvider, SupportedProviders } from 'we import Contract from 'web3-eth-contract'; import HttpProvider from 'web3-providers-http'; import IpcProvider from 'web3-providers-ipc'; -import WebsocketProvider from 'web3-providers-ws'; +import WebSocketProvider from 'web3-providers-ws'; import Web3 from '../../src/index'; import { BasicAbi } from '../shared_fixtures/Basic'; import { validEncodeParametersData } from '../shared_fixtures/data'; @@ -32,9 +32,13 @@ import { isIpc, isWs, waitForOpenConnection, + itIf, + isSocket, } from '../shared_fixtures/system_tests_utils'; import { GreeterAbi, GreeterBytecode } from '../shared_fixtures/build/Greeter'; +/* eslint-disable jest/no-standalone-expect */ + describe('Web3 instance', () => { let clientUrl: string; let accounts: string[]; @@ -75,6 +79,44 @@ describe('Web3 instance', () => { expect(() => new Web3()).not.toThrow(); }); + it('check disconnect function', async () => { + const web3Instance = new Web3(clientUrl); + await web3Instance.eth.getBlockNumber(); + expect(typeof web3Instance.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.currentProvider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.currentProvider?.disconnect).toBe('function'); + if (isSocket) { + web3Instance.currentProvider?.disconnect(); + } + }); + itIf(isWs)('check disconnect function for WebSocket provider', async () => { + const web3Instance = new Web3(new WebSocketProvider(clientUrl)); + await web3Instance.eth.getBlockNumber(); + expect(typeof web3Instance.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.currentProvider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.currentProvider?.disconnect).toBe('function'); + web3Instance.currentProvider?.disconnect(); + }); + itIf(isIpc)('check disconnect function for ipc provider', async () => { + const web3Instance = new Web3(new IpcProvider(clientUrl)); + await web3Instance.eth.getBlockNumber(); + expect(typeof web3Instance.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.currentProvider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.currentProvider?.disconnect).toBe('function'); + web3Instance.currentProvider?.disconnect(); + }); + itIf(isHttp)('check disconnect function for http provider', async () => { + const web3Instance = new Web3(new HttpProvider(clientUrl)); + await web3Instance.eth.getBlockNumber(); + expect(typeof web3Instance.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.provider?.disconnect).toBe('function'); + expect(typeof web3Instance.currentProvider?.disconnect).toBe('function'); + expect(typeof web3Instance.eth.currentProvider?.disconnect).toBe('function'); + }); + it('should be able use "utils" without provider', () => { web3 = new Web3(); @@ -179,7 +221,7 @@ describe('Web3 instance', () => { const res = Web3.providers; expect(Web3.providers.HttpProvider).toBe(HttpProvider); - expect(res.WebsocketProvider).toBe(WebsocketProvider); + expect(res.WebsocketProvider).toBe(WebSocketProvider); expect(res.IpcProvider).toBe(IpcProvider); }); From c951bb7897c2a832a60956826fb0e85762777930 Mon Sep 17 00:00:00 2001 From: Nikos Iliakis Date: Wed, 1 Mar 2023 09:44:36 +0200 Subject: [PATCH 21/67] Nikos/fix ens event test (#5880) * Expose registry events in ens class * Add tests for events * Check for socket * Skip test * Try to unskip test * skip test again * Update packages/web3-eth-ens/test/integration/ens.events.test.ts Co-authored-by: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> * feedback * Try fix * Merge branch '4.x' * Revert conf files * Remove error for event --------- Co-authored-by: Junaid <86780488+jdevcs@users.noreply.github.com> Co-authored-by: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> --- .../test/integration/ens.events.test.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/web3-eth-ens/test/integration/ens.events.test.ts b/packages/web3-eth-ens/test/integration/ens.events.test.ts index 5b859600b69..94333047dd3 100644 --- a/packages/web3-eth-ens/test/integration/ens.events.test.ts +++ b/packages/web3-eth-ens/test/integration/ens.events.test.ts @@ -164,8 +164,8 @@ describeIf(isSocket)('ens events', () => { }); }); - // eslint-disable-next-line jest/expect-expect, jest/no-done-callback - test('NewTTL event', async () => { + // eslint-disable-next-line jest/expect-expect, jest/no-done-callback, jest/consistent-test-it + it('NewTTL event', async () => { // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor await new Promise(async resolve => { const event = ens.events.NewTTL(); @@ -186,8 +186,6 @@ describeIf(isSocket)('ens events', () => { it('NewResolver event', async () => { // eslint-disable-next-line @typescript-eslint/no-misused-promises, no-async-promise-executor await new Promise(async resolve => { - const mockAddress = '0x0000000000000000000000000000000000000000'; - const ENS_NAME = 'web3js.eth'; const event = ens.events.NewResolver(); // eslint-disable-next-line @typescript-eslint/no-unsafe-call @@ -195,7 +193,12 @@ describeIf(isSocket)('ens events', () => { resolve(); }); - await ens.setResolver(ENS_NAME, mockAddress, sendOptions); + await ens.setResolver( + domain, + resolver.options.address as string, + sendOptions, + DEFAULT_RETURN_FORMAT, + ); }); }); }); From b2c21b2c9395c89a19cb86a4ebaece471430bf61 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 1 Mar 2023 10:42:48 -0500 Subject: [PATCH 22/67] update event emitter geth ipc tests (#5874) * update geth binary tests * update helper and changelog * adding await * update helper * add await * add await * add await * fix typings * update tests * update * debug * remove debugging --- packages/web3-eth-contract/CHANGELOG.md | 1 + scripts/geth_binary.sh | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/web3-eth-contract/CHANGELOG.md b/packages/web3-eth-contract/CHANGELOG.md index 57fa111129a..7556002795b 100644 --- a/packages/web3-eth-contract/CHANGELOG.md +++ b/packages/web3-eth-contract/CHANGELOG.md @@ -219,6 +219,7 @@ const transactionHash = receipt.transactionHash; ### Fixed - Fix contract defaults (#5756) +- Fixed getPastEventsError (#5819) ### Changed diff --git a/scripts/geth_binary.sh b/scripts/geth_binary.sh index 6eeb7237e04..ca4270ff838 100755 --- a/scripts/geth_binary.sh +++ b/scripts/geth_binary.sh @@ -59,12 +59,12 @@ start() { download if [ -z "${ORIGARGS[1]}" ]; then echo "Starting geth..." - echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --dev.period=0 " - ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --dev.period=0 + echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 " + ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 else echo "Starting geth..." - echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --dev.period=0 &>/dev/null &" - ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --dev.period=0 &>/dev/null & + echo "geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 &>/dev/null &" + ${TMP_FOLDER}/geth --ipcpath $IPC_PATH --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev --mine --dev.period=0 &>/dev/null & echo "Waiting for geth..." npx wait-port -t 10000 "$WEB3_SYSTEM_TEST_PORT" fi From af788586bbb0da6131f2bacdd2d947e205c9ac9d Mon Sep 17 00:00:00 2001 From: Junaid <86780488+jdevcs@users.noreply.github.com> Date: Thu, 2 Mar 2023 17:31:24 +0100 Subject: [PATCH 23/67] 4.x issue stale conf (#5878) --- .github/workflows/stale.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index e3e5f19f9ec..80e37cfbbcd 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -11,9 +11,9 @@ jobs: with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions. If you believe this was a mistake, please comment.' - stale-pr-message: 'This PR has been automatically marked as stale beacause it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions. If you believe this was a mistake, please comment.' + stale-pr-message: 'This PR has been automatically marked as stale because it has not had recent activity. It will be closed in 7 days if no further activity occurs. Thank you for your contributions. If you believe this was a mistake, please comment.' days-before-stale: 60 days-before-close: 14 operations-per-run: 100 - exempt-pr-labels: 'work-in-progress' - exempt-issue-labels: 'work-in-progress' + exempt-pr-labels: 'work-in-progress','4.x' + exempt-issue-labels: 'work-in-progress','4.x' From 77d6fa0e24dbe38fe59a5c531f0f400cf5f8c0ff Mon Sep 17 00:00:00 2001 From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Mon, 6 Mar 2023 10:14:01 +0100 Subject: [PATCH 24/67] Add documentation for catching provider events (#5886) * show Ipc and WebSocket providers in the documentation * add guides for providers and their events * move the generic section of the providers guide from the migration guide * edit some texts in the guides --- .../providers_migration_guide.md | 124 ++++------- docs/docs/guides/web3_plugin_guide/index.md | 2 +- .../web3_providers_guide/events_listening.md | 68 ++++++ .../docs/guides/web3_providers_guide/index.md | 206 ++++++++++++++++++ .../web3_tree_shaking_support_guide/index.md | 2 +- packages/web3-providers-ipc/src/index.ts | 4 +- packages/web3-providers-ws/src/index.ts | 5 +- packages/web3-utils/src/socket_provider.ts | 2 +- 8 files changed, 319 insertions(+), 94 deletions(-) create mode 100644 docs/docs/guides/web3_providers_guide/events_listening.md create mode 100644 docs/docs/guides/web3_providers_guide/index.md diff --git a/docs/docs/guides/web3_migration_guide/providers_migration_guide.md b/docs/docs/guides/web3_migration_guide/providers_migration_guide.md index 7d58b9f6f85..7cc50878c15 100644 --- a/docs/docs/guides/web3_migration_guide/providers_migration_guide.md +++ b/docs/docs/guides/web3_migration_guide/providers_migration_guide.md @@ -4,85 +4,18 @@ sidebar_position: 2 sidebar_label: web3.providers --- -There are multiple ways to set the provider. +For full description about the providers, their priorities and their types, you can check [web3.js Providers Guide](/docs/guides/web3_providers_guide/). -```ts title='Setting a provider' -web3.setProvider(myProvider); -web3.eth.setProvider(myProvider); -web3.Contract.setProvider(myProvider); -contractInstance.setProvider(myProvider); -``` - -The key rule for setting provider is as follows: - -1. Any provider set on the higher level will be applied to all lower levels. e.g. Any provider set using `web3.setProvider` will also be applied to `web3.eth` object. -2. For contracts `web3.Contract.setProvider` can be used to set provider for **all instances** of contracts created by `web3.eth.Contract`. - -:::tip -A provider can be either type `string` or [`SupportedProviders`](/api/web3-core#SupportedProviders). -::: - -## Examples - -### Local Geth Node - -```ts -const Web3 = require('web3'); -const web3 = new Web3('http://localhost:8545'); -// or -const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); - -// change provider -web3.setProvider('ws://localhost:8546'); -// or -web3.setProvider(new Web3.providers.WebsocketProvider('ws://localhost:8546')); - -// Using the IPC provider in node.js -const net = require('net'); -const web3 = new Web3('/Users/myuser/Library/Ethereum/geth.ipc', net); // mac os path -// or -const web3 = new Web3( - new Web3.providers.IpcProvider('/Users/myuser/Library/Ethereum/geth.ipc', net), -); // mac os path -// on windows the path is: "\\\\.\\pipe\\geth.ipc" -// on linux the path is: "/users/myuser/.ethereum/geth.ipc" -``` +### Provider Options Changes -### Remote Node Provider - -```ts -// Using a remote node provider, like Alchemy (https://www.alchemyapi.io/supernode), is simple. -const Web3 = require('web3'); -const web3 = new Web3('https://eth-mainnet.alchemyapi.io/v2/your-api-key'); -``` - -### Injected providers - -The Injected provider should be in compliance with [EIP1193](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md). - -The web3.js 4.x Provider specifications are defined in [web3 base provider](https://github.com/ChainSafe/web3.js/blob/4.x/packages/web3-types/src/web3_base_provider.ts) for Injected Providers. - -```ts -const Web3 = require('web3'); -// Using an EIP1193 provider like MetaMask can be injected - -if (window.ethereum) { - // Check if ethereum object exists - await window.ethereum.request(); - window.web3 = new Web3(window.ethereum); // inject provider -} -``` - -### Provider Options - -There are differences in the objects that could be passed in the Provider constructors. +There are differences in the objects that could be passed in the Provider constructors between version 1.x and 4.x. Below, you will find the difference for every Provider object type. #### HttpProvider In 1.x, options passed in the constructor should be of type [`HttpProviderOptions`](https://github.com/web3/web3.js/blob/1.x/packages/web3-core-helpers/types/index.d.ts#L173). The `HttpProviderOptions` interface consists of: ```ts -export interface HttpProviderOptions { +interface HttpProviderOptions { keepAlive?: boolean; timeout?: number; headers?: HttpHeader[]; @@ -90,13 +23,13 @@ export interface HttpProviderOptions { agent?: HttpAgent; } -export interface HttpAgent { +interface HttpAgent { http?: http.Agent; https?: https.Agent; baseUrl?: string; } -export interface HttpHeader { +interface HttpHeader { name: string; value: string; } @@ -147,12 +80,12 @@ let httpOptions = { }; ``` -#### WebsocketProvider +#### WebSocketProvider In 1.x, options passed in the constructor should be of type [`WebsocketProviderOptions`](https://github.com/web3/web3.js/blob/1.x/packages/web3-core-helpers/types/index.d.ts#L192). The `WebsocketProviderOptions` interface consists of: ```ts -export interface WebsocketProviderOptions { +interface WebsocketProviderOptions { host?: string; timeout?: number; reconnectDelay?: number; @@ -164,7 +97,7 @@ export interface WebsocketProviderOptions { reconnect?: ReconnectOptions; } -export interface ReconnectOptions { +interface ReconnectOptions { auto?: boolean; delay?: number; maxAttempts?: number; @@ -172,22 +105,21 @@ export interface ReconnectOptions { } ``` -In 4.x, the options object is of type `ClientRequestArgs` or of `ClientOptions`. See -Regarding `RequestInit` see [here](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) for `ClientRequestArgs` and [here](https://github.com/websockets/ws) for `ClientOptions`. - -In 4.x a second option parameter can be given regarding reconnecting. +In 4.x, the options object is of type `ClientRequestArgs` or of `ClientOptions`. See [here](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) for `ClientRequestArgs` and [here](https://github.com/websockets/ws) for `ClientOptions`. -The interface: +In 4.x a second option parameter can be given regarding auto-reconnecting, delay and max tries attempts. And here is its type: ```ts -export type ReconnectOptions = { - autoReconnect: boolean; - delay: number; - maxAttempts: number; +type ReconnectOptions = { + autoReconnect: boolean; // default: `true` + delay: number; // default: `5000` + maxAttempts: number; // default: `5` }; ``` -For example: +##### Options examples + +Below is an example for the passed options for each version: ```ts // in 1.x @@ -232,3 +164,23 @@ const reconnectOptions: ReconnectOptions = { maxAttempts: 5, }; ``` + +##### Error message for reconnect attempts + +The error in, version 1.x, was an Error object that contains the message: +`'Maximum number of reconnect attempts reached!'` + +However, the error, in version 4.x, is just an error message (not wrapped in an Error object). And the error message will contain the value of the variable `maxAttempts` as follows: + +`` `Max connection attempts exceeded (${maxAttempts})` `` + +And here is how to catch the error, in version 4.x, if max attempts reached when there is auto reconnecting: + +```ts +provider.on('error', errorMessage => { + if (errorMessage.startsWith('Max connection attempts exceeded')) { + // the `errorMessage` will be `Max connection attempts exceeded (${maxAttempts})` + // the `maxAttempts` is equal to the provided value by the user, or the default value `5`. + } +}); +``` diff --git a/docs/docs/guides/web3_plugin_guide/index.md b/docs/docs/guides/web3_plugin_guide/index.md index c85745adbf3..32d0f8c15b4 100644 --- a/docs/docs/guides/web3_plugin_guide/index.md +++ b/docs/docs/guides/web3_plugin_guide/index.md @@ -1,5 +1,5 @@ --- -sidebar_position: 1 +sidebar_position: 2 sidebar_label: 'web3 Plugins' --- diff --git a/docs/docs/guides/web3_providers_guide/events_listening.md b/docs/docs/guides/web3_providers_guide/events_listening.md new file mode 100644 index 00000000000..8c85bb00e2f --- /dev/null +++ b/docs/docs/guides/web3_providers_guide/events_listening.md @@ -0,0 +1,68 @@ +--- +sidebar_position: 0 +sidebar_label: 'Providers Events Listening' +--- + +# Providers Events Listening + +Some providers are, by design, always connected. Therefor, they can communicate changes with the user through events. Actually, among the 3 providers, `HttpProvider` is the only one that does not support event. And the other 2: +[WebSocketProvider](/api/web3-providers-ws/class/WebSocketProvider) and [IpcProvider](/api/web3-providers-ipc/class/IpcProvider) enable the user to listen to emitted events. + +Actually, the events can be categorized as follows ([according to EIP 1193](https://eips.ethereum.org/EIPS/eip-1193#rationale)): + +- Communicate arbitrary messages: `message` +- Changes to the Provider’s ability to make RPC requests; + - `connect` + - `disconnect` +- Common Client and/or Wallet state changes that any non-trivial application must handle: + - `chainChanged` + - `accountsChanged` + +Below a sample code for listening and remove listening to EIP 1193 events: + +```ts +import { Web3 } from `web3` + +const web3 = new Web3(/* PROVIDER*/); + +web3.provider.on('message',()=>{ + // ... +}) + +web3.provider.on('connect',()=>{ + // ... +}) + +web3.provider.on('disconnect',()=>{ + // ... +}) + +web3.provider.on('accountsChanged',()=>{ + // ... +}) + +web3.provider.on('chainChanged',()=>{ + // ... +}) + +// it is possible to catch errors that could happen in the underlying connection Socket with the `error` event +// and it is also used to catch the error when max connection attempts exceeded +// as in section: /docs/guides/web3_providers_guide/#error-message +web3.provider.on('error',()=>{ + // ... +} + +// ... + +// for every event above `once` could be used to register to the event only once +web3.provider.once('SUPPORTED_EVENT_NAME',()=>{ + // ... +}) + +// And to unregister a listener `removeListener` could be called +web3.provider.removeListener('SUPPORTED_EVENT_NAME',()=>{ + // ... +}) +``` + +However, the underlying `SocketConnection` of both `WebSocketProvider` and `IpcProvider` could be accessed. This enables the user to access any special properties of the used Socket. As well as, registering to the custom server events directly. Actually the Socket used at `WebSocketProvider` is [isomorphic-ws](https://github.com/heineiuo/isomorphic-ws). And the Socket used at `IpcProvider` is [net.Server](https://nodejs.org/api/net.html#class-netserver) diff --git a/docs/docs/guides/web3_providers_guide/index.md b/docs/docs/guides/web3_providers_guide/index.md new file mode 100644 index 00000000000..c8d5f8ffe5b --- /dev/null +++ b/docs/docs/guides/web3_providers_guide/index.md @@ -0,0 +1,206 @@ +--- +sidebar_position: 1 +sidebar_label: 'Providers' +--- + +# web3.js Providers Guide + +Connecting to a chain happens through a provider. You can pass the provider to the constructor as in the following example: + +```ts +import { Web3 } from `web3` + +const web3 = new Web3(/* PROVIDER*/); + +// calling any method that interact with the network would involve using the early passed provider. +await web3.eth.sendTransaction({ + from, + to, + value, +}); +``` + +The created Web3 instance will use the passed provider to interact with the blockchain network. This interaction happen when sending a request and receiving the response, and when possibly listen to provider events (if the provider support this). + +## Providers Types + +Actually, the provider could be any of the following: + +- An instance of [HttpProvider](/api/web3-providers-http/class/HttpProvider) +- An instance of [WebSocketProvider](/api/web3-providers-ws/class/WebSocketProvider) +- An instance of [IpcProvider](/api/web3-providers-ipc/class/IpcProvider) +- A string containing string url for `http`/`https`, `ws`/`wss`, or `ipc` protocol. And when a string is passed, an instance of the compatible class above will be created accordingly. ex. WebSocketProvider instance will be created for string containing `ws` or `ws`. And you access this instance by calling `web3.provider` to read the provider and possibly register an event listener. +- Any provider object that adhere to [EIP-1193](https://eips.ethereum.org/EIPS/eip-1193). And it has been tested with Ganache provider, Hardhat provider, and Incubed (IN3) as a provider. + +For both [WebSocketProvider](/api/web3-providers-ws/class/WebSocketProvider) and [IpcProvider](/api/web3-providers-ipc/class/IpcProvider) the user can listen to emitted events. More on this is at [Providers Events Listening](events_listening). + +:::tip +The passed provider can be either type `string` or one of the [`SupportedProviders`](/api/web3-core#SupportedProviders). And if it is passed as a string, then internally the compatible provider object will be created and used. +::: + +## Providers Priorities + +There are multiple ways to set the provider. + +```ts title='Setting a provider' +web3.setProvider(myProvider); +web3.eth.setProvider(myProvider); +web3.Contract.setProvider(myProvider); +contractInstance.setProvider(myProvider); +``` + +The key rule for setting provider is as follows: + +1. Any provider set on the higher level will be applied to all lower levels. e.g. Any provider set using `web3.setProvider` will also be applied to `web3.eth` object. +2. For contracts `web3.Contract.setProvider` can be used to set provider for **all instances** of contracts created by `web3.eth.Contract`. + +--- + +## Examples + +### Local Geth Node + +```ts +const Web3 = require('web3'); +const web3 = new Web3('http://localhost:8545'); +// or +const web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:8545')); + +// change provider +web3.setProvider('ws://localhost:8546'); +// or +web3.setProvider(new Web3.providers.WebsocketProvider('ws://localhost:8546')); + +// Using the IPC provider in node.js +const net = require('net'); +const web3 = new Web3('/Users/myuser/Library/Ethereum/geth.ipc', net); // mac os path +// or +const web3 = new Web3( + new Web3.providers.IpcProvider('/Users/myuser/Library/Ethereum/geth.ipc', net), +); // mac os path +// on windows the path is: "\\\\.\\pipe\\geth.ipc" +// on linux the path is: "/users/myuser/.ethereum/geth.ipc" +``` + +### Remote Node Provider + +```ts +// Using a remote node provider, like Alchemy (https://www.alchemyapi.io/supernode), is simple. +const Web3 = require('web3'); +const web3 = new Web3('https://eth-mainnet.alchemyapi.io/v2/your-api-key'); +``` + +### Injected providers + +As stated above, the injected provider should be in compliance with [EIP-1193](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md). And it is tested with Ganache provider, Hardhat provider, and Incubed (IN3) as a provider. + +The web3.js 4.x Provider specifications are defined in [web3 base provider](https://github.com/ChainSafe/web3.js/blob/4.x/packages/web3-types/src/web3_base_provider.ts) for Injected Providers. + +```ts +const Web3 = require('web3'); +// Using an EIP1193 provider like MetaMask can be injected + +if (window.ethereum) { + // Check if ethereum object exists + await window.ethereum.request(); + window.web3 = new Web3(window.ethereum); // inject provider +} +``` + +### Provider Options + +There are differences in the objects that could be passed in the Provider constructors. + +#### HttpProvider + +The options is of type `HttpProviderOptions`, which is an object with a single key named `providerOptions` and its value is an object of type `RequestInit`. +Regarding `RequestInit` see [microsoft's github](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules_typedoc_node_modules_typescript_lib_lib_dom_d_.requestinit.html). + +For example: + +```ts +const httpOptions = { + providerOptions: { + body: undefined, + cache: 'force-cache', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + }, + integrity: 'foo', + keepalive: true, + method: 'GET', + mode: 'same-origin', + redirect: 'error', + referrer: 'foo', + referrerPolicy: 'same-origin', + signal: undefined, + window: undefined, + } as RequestInit, +}; +``` + +#### WebSocketProvider + +The options object is of type `ClientRequestArgs` or of `ClientOptions`. See [here](https://microsoft.github.io/PowerBI-JavaScript/interfaces/_node_modules__types_node_http_d_._http_.clientrequestargs.html) for `ClientRequestArgs` and [here](https://github.com/websockets/ws) for `ClientOptions`. + +The second option parameter can be given regarding reconnecting. And here is its type: + +```ts +type ReconnectOptions = { + autoReconnect: boolean; + delay: number; + maxAttempts: number; +}; +``` + +:::info +Here is how to catch the error if max attempts reached when the auto reconnecting: + +```ts +provider.on('error', errorMessage => { + if (errorMessage.startsWith('Max connection attempts exceeded')) { + // the `errorMessage` will be `Max connection attempts exceeded (${maxAttempts})` + // the `maxAttempts` is equal to the provided value by the user or the default `5`. + } +}); +``` + +::: + +##### Options example + +Below is an example for the passed options: + +```ts +let clientOptions: ClientOptions = { + // Useful for credentialed urls, e.g: ws://username:password@localhost:8546 + headers: { + authorization: 'Basic username:password', + }, + maxPayload: 100000000, +}; + +const reconnectOptions: ReconnectOptions = { + autoReconnect: true, + delay: 5000, + maxAttempts: 5, +}; +``` + +##### Error message for reconnect attempts + +The error message (not wrapped in an Error object) for the max reconnect attempts, will contain the value of the variable `maxAttempts` as follows: + +`` `Max connection attempts exceeded (${maxAttempts})` `` + +And here is how to catch the error, if max attempts reached when there is auto reconnecting: + +```ts +provider.on('error', errorMessage => { + if (errorMessage.startsWith('Max connection attempts exceeded')) { + // the `errorMessage` will be `Max connection attempts exceeded (${maxAttempts})` + // the `maxAttempts` is equal to the provided value by the user or the default `5`. + } +}); +``` diff --git a/docs/docs/guides/web3_tree_shaking_support_guide/index.md b/docs/docs/guides/web3_tree_shaking_support_guide/index.md index 64835249d00..893af66f7fb 100644 --- a/docs/docs/guides/web3_tree_shaking_support_guide/index.md +++ b/docs/docs/guides/web3_tree_shaking_support_guide/index.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 sidebar_label: web3 Tree Shaking Guide --- diff --git a/packages/web3-providers-ipc/src/index.ts b/packages/web3-providers-ipc/src/index.ts index 67a3afb353f..7b4d8cae1f7 100644 --- a/packages/web3-providers-ipc/src/index.ts +++ b/packages/web3-providers-ipc/src/index.ts @@ -27,9 +27,6 @@ import { } from 'web3-types'; import { existsSync } from 'fs'; -// todo had to ignore, introduce error in doc generation,see why/better solution -/** @ignore */ - export default class IpcProvider extends SocketProvider< Buffer | string, CloseEvent, @@ -103,6 +100,7 @@ export default class IpcProvider exte this._socketConnection?.removeAllListeners('end'); this._socketConnection?.removeAllListeners('close'); this._socketConnection?.removeAllListeners('data'); + // note: we intentionally keep the error event listener to be able to emit it in case an error happens when closing the connection } protected _onCloseEvent(event: CloseEvent): void { diff --git a/packages/web3-providers-ws/src/index.ts b/packages/web3-providers-ws/src/index.ts index 8740ba4ea2a..e5352aba929 100644 --- a/packages/web3-providers-ws/src/index.ts +++ b/packages/web3-providers-ws/src/index.ts @@ -28,14 +28,14 @@ import { isNullish, SocketProvider } from 'web3-utils'; import { ConnectionNotOpenError } from 'web3-errors'; export { ClientRequestArgs } from 'http'; -// todo had to ignore, introduce error in doc generation,see why/better solution -/** @ignore */ + export { ClientOptions } from 'isomorphic-ws'; export default class WebSocketProvider< API extends Web3APISpec = EthExecutionAPI, > extends SocketProvider { protected readonly _providerOptions?: ClientOptions | ClientRequestArgs; + protected _socketConnection?: WebSocket; // eslint-disable-next-line class-methods-use-this @@ -59,6 +59,7 @@ export default class WebSocketProvider< } return 'disconnected'; } + protected _openSocketConnection() { this._socketConnection = new WebSocket( this._socketPath, diff --git a/packages/web3-utils/src/socket_provider.ts b/packages/web3-utils/src/socket_provider.ts index 7c5fcda3287..827228c549b 100644 --- a/packages/web3-utils/src/socket_provider.ts +++ b/packages/web3-utils/src/socket_provider.ts @@ -201,7 +201,7 @@ export abstract class SocketProvider< /** * Removes a listener for the specified event type. * @param type - The event type to remove the listener for - * @param callback - The callback to be exetuted + * @param callback - The callback to be executed */ public removeListener(type: EventType, callback: Web3ProviderEventCallback): void { this._eventEmitter.removeListener(type, callback); From e5c59af6131a2e194d858e50c2f43ec77ff64eab Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 18:43:12 -1000 Subject: [PATCH 25/67] Fixing tests for WS and IPC --- .../test/integration/web3_eth/send_transaction.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index e6705555bc6..641cdc5f074 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -36,6 +36,8 @@ import { createTempAccount, getSystemTestBackend, getSystemTestProvider, + isIpc, + isWs, } from '../../fixtures/system_test_utils'; import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; @@ -508,7 +510,7 @@ describe('Web3Eth.sendTransaction', () => { }; await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - expectedErrorObject, + isWs || isIpc ? [expectedErrorObject] : expectedErrorObject, ); }); @@ -565,7 +567,7 @@ describe('Web3Eth.sendTransaction', () => { }; await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - expectedErrorObject, + isWs || isIpc ? [expectedErrorObject] : expectedErrorObject, ); }); }); From de1fe5ebda327e6c5b8f04bff47ad9fdc1fae717 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 19:37:10 -1000 Subject: [PATCH 26/67] Remove jest specific test code that doesn't work in Cypress --- .../integration/web3_eth/send_transaction.test.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 641cdc5f074..7ca62bf0259 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -36,8 +36,6 @@ import { createTempAccount, getSystemTestBackend, getSystemTestProvider, - isIpc, - isWs, } from '../../fixtures/system_test_utils'; import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; @@ -492,10 +490,7 @@ describe('Web3Eth.sendTransaction', () => { signature: '0x08c379a0', data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', receipt: { - transactionHash: expect.any(String), transactionIndex: BigInt(0), - blockNumber: expect.any(BigInt), - blockHash: expect.any(String), from: tempAcc.address, to: simpleRevertContractAddress, cumulativeGasUsed: BigInt(23605), @@ -510,7 +505,7 @@ describe('Web3Eth.sendTransaction', () => { }; await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - isWs || isIpc ? [expectedErrorObject] : expectedErrorObject, + expectedErrorObject, ); }); @@ -549,10 +544,7 @@ describe('Web3Eth.sendTransaction', () => { name: 'TransactionRevertedWithoutReasonError', code: 405, receipt: { - transactionHash: expect.any(String), transactionIndex: BigInt(0), - blockNumber: expect.any(BigInt), - blockHash: expect.any(String), from: tempAcc.address, to: simpleRevertContractAddress, cumulativeGasUsed: BigInt(23605), @@ -567,7 +559,7 @@ describe('Web3Eth.sendTransaction', () => { }; await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - isWs || isIpc ? [expectedErrorObject] : expectedErrorObject, + expectedErrorObject, ); }); }); From f334a9ed9101a1f7affb169e101204e471e97736 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 20:10:34 -1000 Subject: [PATCH 27/67] Remove jest specific test code that doesn't work in Cypress --- .../test/integration/contract_methods.test.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts index e48d296eca3..591abccd899 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts @@ -152,17 +152,14 @@ describe('contract', () => { ).rejects.toMatchObject({ name: 'TransactionRevertedWithoutReasonError', receipt: { - blockHash: expect.any(String), - blockNumber: expect.any(BigInt), cumulativeGasUsed: BigInt(21543), - effectiveGasPrice: expect.any(BigInt), from: acc.address, gasUsed: BigInt(21543), logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: BigInt(0), - to: expect.any(String), + to: contractDeployed.options.address, transactionHash: expect.any(String), transactionIndex: BigInt(0), type: BigInt(0), From 71e8f1bbca5e5b61881319b03c9db49bec935652 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 20:36:07 -1000 Subject: [PATCH 28/67] Remove jest specific test code --- .../web3-eth-contract/test/integration/contract_methods.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts index 591abccd899..0b464573fb7 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts @@ -160,7 +160,6 @@ describe('contract', () => { '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: BigInt(0), to: contractDeployed.options.address, - transactionHash: expect.any(String), transactionIndex: BigInt(0), type: BigInt(0), }, From de2f1cfc73c5f0c0cf5c597c2aa61fd9ffdc1ce1 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 23 Feb 2023 20:37:23 -1000 Subject: [PATCH 29/67] Add toLowerCase for address --- .../web3-eth-contract/test/integration/contract_methods.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/test/integration/contract_methods.test.ts b/packages/web3-eth-contract/test/integration/contract_methods.test.ts index 0b464573fb7..1fa72966f00 100644 --- a/packages/web3-eth-contract/test/integration/contract_methods.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_methods.test.ts @@ -159,7 +159,7 @@ describe('contract', () => { logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: BigInt(0), - to: contractDeployed.options.address, + to: contractDeployed.options.address?.toLowerCase(), transactionIndex: BigInt(0), type: BigInt(0), }, From 42055770e55a4cd79a01acc83ddb3c3b2fe56735 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 16:08:00 -1000 Subject: [PATCH 30/67] Rename TransactionRevertError to TransactionRevertInstructionError --- .../src/errors/transaction_errors.ts | 12 ++++++++--- .../unit/__snapshots__/errors.test.ts.snap | 7 ++++--- packages/web3-errors/test/unit/errors.test.ts | 4 ++-- packages/web3-eth-ens/src/registry.ts | 20 +++++++++---------- packages/web3-eth/src/types.ts | 4 ++-- .../src/utils/get_transaction_error.ts | 8 ++++---- .../web3_eth/send_transaction.test.ts | 4 ++-- .../test/integration/handle_revert.test.ts | 6 +++--- 8 files changed, 36 insertions(+), 29 deletions(-) diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index 10fc84c78bb..e78c7c9a96c 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -85,7 +85,9 @@ export class RevertInstructionError extends BaseWeb3Error { } } -export class TransactionRevertError extends BaseWeb3Error { +export class TransactionRevertInstructionError< + ReceiptType = TransactionReceipt, +> extends BaseWeb3Error { public code = ERR_TX_REVERT_TRANSACTION; public constructor( @@ -94,7 +96,11 @@ export class TransactionRevertError extends Ba public receipt?: ReceiptType, public data?: string, ) { - super(reason); + super( + `Transaction has been reverted by the EVM${ + receipt === undefined ? '' : `:\n ${BaseWeb3Error.convertToString(receipt)}` + }`, + ); } public toJSON() { @@ -110,7 +116,7 @@ export class TransactionRevertError extends Ba export class TransactionRevertWithCustomError< ReceiptType = TransactionReceipt, -> extends TransactionRevertError { +> extends TransactionRevertInstructionError { public code = ERR_TX_REVERT_TRANSACTION_CUSTOM_ERROR; public constructor( diff --git a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap index 2bc868b11eb..03460675aa8 100644 --- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap @@ -283,13 +283,14 @@ Object { } `; -exports[`errors TransactionRevertError should have valid json structure 1`] = ` +exports[`errors TransactionRevertInstructionError should have valid json structure 1`] = ` Object { "code": 402, "data": undefined, "innerError": undefined, - "message": "message", - "name": "TransactionRevertError", + "message": "Transaction has been reverted by the EVM: + {\\"attr1\\":\\"attr1\\"}", + "name": "TransactionRevertInstructionError", "reason": "message", "receipt": Object { "attr1": "attr1", diff --git a/packages/web3-errors/test/unit/errors.test.ts b/packages/web3-errors/test/unit/errors.test.ts index 1ca30c26bb1..4869fcdedeb 100644 --- a/packages/web3-errors/test/unit/errors.test.ts +++ b/packages/web3-errors/test/unit/errors.test.ts @@ -162,10 +162,10 @@ describe('errors', () => { }); }); - describe('TransactionRevertError', () => { + describe('TransactionRevertInstructionError', () => { it('should have valid json structure', () => { expect( - new transactionErrors.TransactionRevertError('message', 'signature', { + new transactionErrors.TransactionRevertInstructionError('message', 'signature', { attr1: 'attr1', } as any).toJSON(), ).toMatchSnapshot(); diff --git a/packages/web3-eth-ens/src/registry.ts b/packages/web3-eth-ens/src/registry.ts index 88b91378862..c4989ceafe7 100644 --- a/packages/web3-eth-ens/src/registry.ts +++ b/packages/web3-eth-ens/src/registry.ts @@ -43,7 +43,7 @@ export class Registry { return result; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -60,7 +60,7 @@ export class Registry { return receipt; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -68,7 +68,7 @@ export class Registry { try { return this.contract.methods.ttl(namehash(name)).call(); } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -82,7 +82,7 @@ export class Registry { return promiEvent; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -104,7 +104,7 @@ export class Registry { .send(txConfig); return receipt; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -165,7 +165,7 @@ export class Registry { return result; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -175,7 +175,7 @@ export class Registry { return promise; } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -194,7 +194,7 @@ export class Registry { throw new Error(); }); } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -209,7 +209,7 @@ export class Registry { .setResolver(namehash(name), format({ eth: 'address' }, address, returnFormat)) .send(txConfig); } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } @@ -231,7 +231,7 @@ export class Registry { ) .send(txConfig); } catch (error) { - throw new Error(); // TODO: TransactionRevertError Needs to be added after web3-eth call method is implemented + throw new Error(); // TODO: TransactionRevertInstructionError Needs to be added after web3-eth call method is implemented } } public get events() { diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index d1819d76c46..e1c8fb8acd9 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -20,7 +20,7 @@ import { ContractExecutionError, ResponseError, TransactionRevertedWithoutReasonError, - TransactionRevertError, + TransactionRevertInstructionError, TransactionRevertWithCustomError, InvalidResponseError, } from 'web3-errors'; @@ -48,7 +48,7 @@ export type SendTransactionEvents = { }; error: | TransactionRevertedWithoutReasonError> - | TransactionRevertError> + | TransactionRevertInstructionError> | TransactionRevertWithCustomError> | InvalidResponseError | ContractExecutionError; diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts index e97fc29b166..ce47eaeb4ca 100644 --- a/packages/web3-eth/src/utils/get_transaction_error.ts +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -18,7 +18,7 @@ along with web3.js. If not, see . import { Web3Context } from 'web3-core'; import { TransactionRevertedWithoutReasonError, - TransactionRevertError, + TransactionRevertInstructionError, TransactionRevertWithCustomError, } from 'web3-errors'; import { ContractAbi, TransactionCall, TransactionReceipt } from 'web3-types'; @@ -45,14 +45,14 @@ export async function getTransactionError( let error: | TransactionRevertedWithoutReasonError> - | TransactionRevertError> + | TransactionRevertInstructionError> | TransactionRevertWithCustomError>; if (reason === undefined) { error = new TransactionRevertedWithoutReasonError< FormatType >(transactionReceiptFormatted); } else if (typeof reason === 'string') { - error = new TransactionRevertError>( + error = new TransactionRevertInstructionError>( reason, undefined, transactionReceiptFormatted, @@ -73,7 +73,7 @@ export async function getTransactionError( _reason.data, ); } else { - error = new TransactionRevertError>( + error = new TransactionRevertInstructionError>( reason.reason, reason.signature, transactionReceiptFormatted, diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 7ca62bf0259..e1bb94d0266 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -452,7 +452,7 @@ describe('Web3Eth.sendTransaction', () => { }); }); - it('Should throw TransactionRevertError because of contract revert and return revert reason', async () => { + it('Should throw TransactionRevertInstructionError because of contract revert and return revert reason', async () => { const simpleRevertDeployTransaction: Transaction = { from: tempAcc.address, data: SimpleRevertDeploymentData, @@ -484,7 +484,7 @@ describe('Web3Eth.sendTransaction', () => { }, } : { - name: 'TransactionRevertError', + name: 'TransactionRevertInstructionError', code: 402, reason: 'VM Exception while processing transaction: revert This is a send revert', signature: '0x08c379a0', diff --git a/packages/web3/test/integration/handle_revert.test.ts b/packages/web3/test/integration/handle_revert.test.ts index a0f65c500cc..db5fd91afdb 100644 --- a/packages/web3/test/integration/handle_revert.test.ts +++ b/packages/web3/test/integration/handle_revert.test.ts @@ -16,7 +16,7 @@ along with web3.js. If not, see . */ import WebSocketProvider from 'web3-providers-ws'; import { Contract } from 'web3-eth-contract'; -import { TransactionRevertError } from 'web3-errors'; +import { TransactionRevertInstructionError } from 'web3-errors'; import Web3 from '../../src/index'; import { closeOpenConnection, @@ -89,7 +89,7 @@ describe.skip('eth', () => { it('should get revert reason', async () => { contract.handleRevert = true; await expect(contract.methods.reverts().send({ from: accounts[0] })).rejects.toThrow( - new TransactionRevertError( + new TransactionRevertInstructionError( 'Returned error: execution reverted: REVERTED WITH REVERT', ), ); @@ -112,7 +112,7 @@ describe.skip('eth', () => { s: '0x39f77e0b68d5524826e4385ad4e1f01e748f32c177840184ae65d9592fdfe5c', }), ).rejects.toThrow( - new TransactionRevertError( + new TransactionRevertInstructionError( 'Returned error: invalid argument 0: json: cannot unmarshal invalid hex string into Go struct field TransactionArgs.data of type hexutil.Bytes', ), ); From a66aaf0ae90493dac85210b1dda9c88a83ac0f27 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 16:55:48 -1000 Subject: [PATCH 31/67] Add beforeAll for Transaction Error Scenario tests --- .../web3_eth/send_transaction.test.ts | 37 ++++++++----------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index e1bb94d0266..6396ac90c2c 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -364,6 +364,21 @@ describe('Web3Eth.sendTransaction', () => { }); describe('Transaction Error Scenarios', () => { + let simpleRevertContractAddress: Address; + + beforeAll(async () => { + const simpleRevertDeployTransaction: Transaction = { + from: tempAcc.address, + data: SimpleRevertDeploymentData, + }; + simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( + simpleRevertDeployTransaction, + ); + simpleRevertContractAddress = ( + await web3Eth.sendTransaction(simpleRevertDeployTransaction) + ).contractAddress as Address; + }); + it('Should throw InvalidResponseError because gas too low', async () => { const transaction: Transaction = { from: tempAcc.address, @@ -453,17 +468,6 @@ describe('Web3Eth.sendTransaction', () => { }); it('Should throw TransactionRevertInstructionError because of contract revert and return revert reason', async () => { - const simpleRevertDeployTransaction: Transaction = { - from: tempAcc.address, - data: SimpleRevertDeploymentData, - }; - simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( - simpleRevertDeployTransaction, - ); - const simpleRevertContractAddress = ( - await web3Eth.sendTransaction(simpleRevertDeployTransaction) - ).contractAddress as Address; - const transaction: Transaction = { from: tempAcc.address, to: simpleRevertContractAddress, @@ -510,17 +514,6 @@ describe('Web3Eth.sendTransaction', () => { }); it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { - const simpleRevertDeployTransaction: Transaction = { - from: tempAcc.address, - data: SimpleRevertDeploymentData, - }; - simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( - simpleRevertDeployTransaction, - ); - const simpleRevertContractAddress = ( - await web3Eth.sendTransaction(simpleRevertDeployTransaction) - ).contractAddress as Address; - const transaction: Transaction = { from: tempAcc.address, to: simpleRevertContractAddress, From 284f4adaaecfb4c4359056a46d6cf1202a5fe5a9 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 16:56:05 -1000 Subject: [PATCH 32/67] Add Transaction Error Scenario tests for call --- .../test/integration/web3_eth/call.test.ts | 39 ++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth/test/integration/web3_eth/call.test.ts b/packages/web3-eth/test/integration/web3_eth/call.test.ts index e49e6a72c82..010d0802195 100644 --- a/packages/web3-eth/test/integration/web3_eth/call.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/call.test.ts @@ -14,14 +14,16 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { TransactionCall, BlockTags, Transaction } from 'web3-types'; +import { TransactionCall, BlockTags, Transaction, Address } from 'web3-types'; import { decodeParameters } from 'web3-eth-abi'; import { Web3Eth } from '../../../src'; import { closeOpenConnection, createTempAccount, + getSystemTestBackend, getSystemTestProvider, } from '../../fixtures/system_test_utils'; +import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; describe('Web3Eth.call', () => { const expectedEncodedGreet = @@ -133,4 +135,39 @@ describe('Web3Eth.call', () => { expect(response).toBe('0x'); }); }); + + describe('Transaction Error Scenarios', () => { + let simpleRevertContractAddress: Address; + + beforeAll(async () => { + const simpleRevertDeployTransaction: Transaction = { + from: tempAcc.address, + data: SimpleRevertDeploymentData, + }; + simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( + simpleRevertDeployTransaction, + ); + simpleRevertContractAddress = ( + await web3Eth.sendTransaction(simpleRevertDeployTransaction) + ).contractAddress as Address; + }); + + it('Should throw ContractExecutionError', async () => { + const transaction: TransactionCall = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', + }; + + await expect(web3Eth.call(transaction)).rejects.toMatchObject({ + name: 'ContractExecutionError', + code: 310, + innerError: { + name: 'Eip838ExecutionError', + code: getSystemTestBackend() === 'geth' ? 3 : -32000, + data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }, + }); + }); + }); }); From 19aadcc0859a1b7c50c5a33e759862ae00caf4be Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 18:21:43 -1000 Subject: [PATCH 33/67] Add support for handleRevert in sendTransaction for geth --- packages/web3-eth/src/rpc_method_wrappers.ts | 80 ++++++++++++-------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index e3e102cd8a1..79a1e00e2b3 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -53,6 +53,9 @@ import { InvalidResponseError, SignatureError, TransactionError, + TransactionRevertedWithoutReasonError, + TransactionRevertInstructionError, + TransactionRevertWithCustomError, } from 'web3-errors'; import { ethRpcMethods } from 'web3-rpc-methods'; import { decodeSignedTransaction } from './utils/decode_signed_transaction'; @@ -1073,34 +1076,34 @@ export function sendTransaction< (resolve, reject) => { setImmediate(() => { (async () => { - try { - let transactionFormatted = formatTransaction( - { - ...transaction, - from: getTransactionFromOrToAttr('from', web3Context, transaction), - to: getTransactionFromOrToAttr('to', web3Context, transaction), - }, - ETH_DATA_FORMAT, - ); - - if ( - !options?.ignoreGasPricing && - isNullish(transactionFormatted.gasPrice) && - (isNullish(transaction.maxPriorityFeePerGas) || - isNullish(transaction.maxFeePerGas)) - ) { - transactionFormatted = { - ...transactionFormatted, - // TODO gasPrice, maxPriorityFeePerGas, maxFeePerGas - // should not be included if undefined, but currently are - ...(await getTransactionGasPricing( - transactionFormatted, - web3Context, - ETH_DATA_FORMAT, - )), - }; - } + let transactionFormatted = formatTransaction( + { + ...transaction, + from: getTransactionFromOrToAttr('from', web3Context, transaction), + to: getTransactionFromOrToAttr('to', web3Context, transaction), + }, + ETH_DATA_FORMAT, + ); + + if ( + !options?.ignoreGasPricing && + isNullish(transactionFormatted.gasPrice) && + (isNullish(transaction.maxPriorityFeePerGas) || + isNullish(transaction.maxFeePerGas)) + ) { + transactionFormatted = { + ...transactionFormatted, + // TODO gasPrice, maxPriorityFeePerGas, maxFeePerGas + // should not be included if undefined, but currently are + ...(await getTransactionGasPricing( + transactionFormatted, + web3Context, + ETH_DATA_FORMAT, + )), + }; + } + try { if (promiEvent.listenerCount('sending') > 0) { promiEvent.emit('sending', transactionFormatted); } @@ -1205,15 +1208,30 @@ export function sendTransaction< ); } } catch (error) { + let _error = error; + + if (_error instanceof ContractExecutionError && web3Context.handleRevert) { + _error = await getTransactionError( + web3Context, + transactionFormatted as TransactionCall, + undefined, + undefined, + options?.contractAbi, + ); + } + if ( - (error instanceof InvalidResponseError || - error instanceof ContractExecutionError) && + (_error instanceof InvalidResponseError || + _error instanceof ContractExecutionError || + _error instanceof TransactionRevertWithCustomError || + _error instanceof TransactionRevertedWithoutReasonError || + _error instanceof TransactionRevertInstructionError) && promiEvent.listenerCount('error') > 0 ) { - promiEvent.emit('error', error); + promiEvent.emit('error', _error); } - reject(error); + reject(_error); } })() as unknown; }); From 5376bc8318375acb85dcb7b81e9019187b70e196 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 18:22:01 -1000 Subject: [PATCH 34/67] Update tests and add test to verify event error is same as thrown error --- .../web3_eth/send_transaction.test.ts | 182 ++++++++++++++---- 1 file changed, 148 insertions(+), 34 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 6396ac90c2c..3e4c9d56804 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -37,7 +37,7 @@ import { getSystemTestBackend, getSystemTestProvider, } from '../../fixtures/system_test_utils'; -import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; +import { SimpleRevertAbi, SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; describe('Web3Eth.sendTransaction', () => { let web3Eth: Web3Eth; @@ -386,7 +386,8 @@ describe('Web3Eth.sendTransaction', () => { value: BigInt(1), gas: 1, }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + + const expectedThrownError = { name: 'InvalidResponseError', code: 101, message: expect.any(String), @@ -408,7 +409,13 @@ describe('Web3Eth.sendTransaction', () => { }, ], }, - }); + }; + + await expect( + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); }); it('Should throw InvalidResponseError because insufficient funds', async () => { @@ -417,7 +424,8 @@ describe('Web3Eth.sendTransaction', () => { to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + + const expectedThrownError = { name: 'InvalidResponseError', code: 101, message: expect.any(String), @@ -438,7 +446,13 @@ describe('Web3Eth.sendTransaction', () => { }, ], }, - }); + }; + + await expect( + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); }); it('Should throw InvalidResponseError because of unknown account', async () => { @@ -446,7 +460,8 @@ describe('Web3Eth.sendTransaction', () => { from: '0x0000000000000000000000000000000000000000', to: '0x0000000000000000000000000000000000000000', }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject({ + + const expectedThrownError = { name: 'InvalidResponseError', code: 101, message: expect.any(String), @@ -464,7 +479,13 @@ describe('Web3Eth.sendTransaction', () => { }, ], }, - }); + }; + + await expect( + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); }); it('Should throw TransactionRevertInstructionError because of contract revert and return revert reason', async () => { @@ -476,24 +497,19 @@ describe('Web3Eth.sendTransaction', () => { web3Eth.handleRevert = true; - const expectedErrorObject = - getSystemTestBackend() === 'geth' - ? { - name: 'ContractExecutionError', - code: 310, - innerError: { - name: 'Eip838ExecutionError', - code: 3, - data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - }, - } - : { - name: 'TransactionRevertInstructionError', - code: 402, - reason: 'VM Exception while processing transaction: revert This is a send revert', - signature: '0x08c379a0', - data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - receipt: { + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted: This is a send revert' + : 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { transactionIndex: BigInt(0), from: tempAcc.address, to: simpleRevertContractAddress, @@ -505,12 +521,108 @@ describe('Web3Eth.sendTransaction', () => { status: BigInt(0), effectiveGasPrice: BigInt(2000000000), type: BigInt(0), - }, - }; + }, + }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - expectedErrorObject, - ); + await expect( + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertWithCustomError because of contract revert and return custom error ErrorWithNoParams', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0x3ebf4d9c', + }; + + web3Eth.handleRevert = true; + + const expectedThrownError = { + name: 'TransactionRevertWithCustomError', + code: 438, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted' + : 'VM Exception while processing transaction: revert', + signature: '0x72090e4d', + customErrorName: 'ErrorWithNoParams', + customErrorDecodedSignature: 'ErrorWithNoParams()', + customErrorArguments: {}, + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21222), + gasUsed: BigInt(21222), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendTransaction(transaction, undefined, { contractAbi: SimpleRevertAbi }) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertWithCustomError because of contract revert and return custom error ErrorWithParams', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0x819f48fe', + }; + + web3Eth.handleRevert = true; + + const expectedThrownError = { + name: 'TransactionRevertWithCustomError', + code: 438, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted: This is a send revert' + : 'VM Exception while processing transaction: revert', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + customErrorName: 'ErrorWithParams', + customErrorDecodedSignature: 'ErrorWithParams(uint256,string)', + customErrorArguments: { + code: BigInt(42), + message: 'This is an error with params', + }, + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21730), + gasUsed: BigInt(21730), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendTransaction(transaction, undefined, { contractAbi: SimpleRevertAbi }) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); }); it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { @@ -522,7 +634,7 @@ describe('Web3Eth.sendTransaction', () => { web3Eth.handleRevert = false; - const expectedErrorObject = + const expectedThrownError = getSystemTestBackend() === 'geth' ? { name: 'ContractExecutionError', @@ -551,9 +663,11 @@ describe('Web3Eth.sendTransaction', () => { }, }; - await expect(web3Eth.sendTransaction(transaction)).rejects.toMatchObject( - expectedErrorObject, - ); + await expect( + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); }); }); }); From 662a3901de04771e5b4629e0faeb0845dbfc487c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 20:24:38 -1000 Subject: [PATCH 35/67] Correct test expected data --- .../web3-eth/test/integration/web3_eth/send_transaction.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 3e4c9d56804..a37f803fc8c 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -590,7 +590,7 @@ describe('Web3Eth.sendTransaction', () => { code: 438, reason: getSystemTestBackend() === 'geth' - ? 'execution reverted: This is a send revert' + ? 'execution reverted' : 'VM Exception while processing transaction: revert', signature: '0xc85bda60', data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', From 81be9d82a7666335a71ba47768c57224b9736168 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 21:21:35 -1000 Subject: [PATCH 36/67] Remove message from expectedThrownError for sendTransaction tests --- .../test/integration/web3_eth/send_transaction.test.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index a37f803fc8c..e905bc3a8ba 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -390,7 +390,6 @@ describe('Web3Eth.sendTransaction', () => { const expectedThrownError = { name: 'InvalidResponseError', code: 101, - message: expect.any(String), innerError: expect.any(Object), data: undefined, request: { @@ -428,7 +427,6 @@ describe('Web3Eth.sendTransaction', () => { const expectedThrownError = { name: 'InvalidResponseError', code: 101, - message: expect.any(String), innerError: expect.any(Object), data: undefined, request: { @@ -464,7 +462,6 @@ describe('Web3Eth.sendTransaction', () => { const expectedThrownError = { name: 'InvalidResponseError', code: 101, - message: expect.any(String), innerError: expect.any(Object), data: undefined, request: { From 0f655a5b18fc27cf4e0a40ee63227605368fb2d0 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 21:22:18 -1000 Subject: [PATCH 37/67] Add error refactors to sendSignedTransaction and init tests --- packages/web3-eth/src/rpc_method_wrappers.ts | 86 +++-- packages/web3-eth/src/types.ts | 11 +- packages/web3-eth/src/web3_eth.ts | 3 +- .../web3_eth/send_signed_transaction.test.ts | 299 +++++++++++++++++- 4 files changed, 365 insertions(+), 34 deletions(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 79a1e00e2b3..710ec8e718c 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -46,18 +46,27 @@ import { AccessListResult, } from 'web3-types'; import { Web3Context, Web3PromiEvent } from 'web3-core'; -import { ETH_DATA_FORMAT, FormatType, DataFormat, DEFAULT_RETURN_FORMAT, format } from 'web3-utils'; +import { + ETH_DATA_FORMAT, + FormatType, + DataFormat, + DEFAULT_RETURN_FORMAT, + format, + hexToBytes, + bytesToBuffer, +} from 'web3-utils'; import { isBlockTag, isBytes, isNullish, isString } from 'web3-validator'; import { ContractExecutionError, InvalidResponseError, SignatureError, - TransactionError, TransactionRevertedWithoutReasonError, TransactionRevertInstructionError, TransactionRevertWithCustomError, } from 'web3-errors'; import { ethRpcMethods } from 'web3-rpc-methods'; +import { TransactionFactory } from '@ethereumjs/tx'; + import { decodeSignedTransaction } from './utils/decode_signed_transaction'; import { accountSchema, @@ -1340,22 +1349,17 @@ export function sendSignedTransaction< (resolve, reject) => { setImmediate(() => { (async () => { - try { - // Formatting signedTransaction to be send to RPC endpoint - const signedTransactionFormattedHex = format( - { eth: 'bytes' }, - signedTransaction, - ETH_DATA_FORMAT, - ); + // Formatting signedTransaction to be send to RPC endpoint + const signedTransactionFormattedHex = format( + { eth: 'bytes' }, + signedTransaction, + ETH_DATA_FORMAT, + ); + try { if (promiEvent.listenerCount('sending') > 0) { promiEvent.emit('sending', signedTransactionFormattedHex); } - // todo enable handleRevert for sendSignedTransaction when we have a function to decode transactions - // importing a package for this would increase the size of the library - // if (web3Context.handleRevert) { - // await getRevertReason(web3Context, transaction, returnFormat); - // } const transactionHash = await trySendTransaction( web3Context, @@ -1403,17 +1407,22 @@ export function sendSignedTransaction< ) as unknown as ResolveType, ); } else if (transactionReceipt.status === BigInt(0)) { + const unSerializedTransaction = TransactionFactory.fromSerializedData( + bytesToBuffer(hexToBytes(signedTransactionFormattedHex)), + ).toJSON(); + const error = await getTransactionError( + web3Context, + unSerializedTransaction as TransactionCall, + transactionReceiptFormatted, + undefined, + options?.contractAbi, + ); + if (promiEvent.listenerCount('error') > 0) { - promiEvent.emit( - 'error', - new TransactionError( - 'Transaction failed', - transactionReceiptFormatted, - ), - ); + promiEvent.emit('error', error); } - reject(transactionReceiptFormatted as unknown as ResolveType); - return; + + reject(error); } else { resolve(transactionReceiptFormatted as unknown as ResolveType); } @@ -1432,13 +1441,34 @@ export function sendSignedTransaction< ); } } catch (error) { - if (promiEvent.listenerCount('error') > 0) { - promiEvent.emit( - 'error', - new TransactionError((error as Error).message), + const unSerializedTransaction = TransactionFactory.fromSerializedData( + bytesToBuffer(hexToBytes(signedTransactionFormattedHex)), + ).toJSON(); + + let _error = error; + + if (_error instanceof ContractExecutionError && web3Context.handleRevert) { + _error = await getTransactionError( + web3Context, + unSerializedTransaction as TransactionCall, + undefined, + undefined, + options?.contractAbi, ); } - reject(error); + + if ( + (_error instanceof InvalidResponseError || + _error instanceof ContractExecutionError || + _error instanceof TransactionRevertWithCustomError || + _error instanceof TransactionRevertedWithoutReasonError || + _error instanceof TransactionRevertInstructionError) && + promiEvent.listenerCount('error') > 0 + ) { + promiEvent.emit('error', _error); + } + + reject(_error); } })() as unknown; }); diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index e1c8fb8acd9..f1fe8263ae7 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -16,9 +16,7 @@ along with web3.js. If not, see . */ import { - TransactionError, ContractExecutionError, - ResponseError, TransactionRevertedWithoutReasonError, TransactionRevertInstructionError, TransactionRevertWithCustomError, @@ -64,8 +62,12 @@ export type SendSignedTransactionEvents = { receipt: FormatType; latestBlockHash: FormatType; }; - error: TransactionError>; - contractExecutionError: ContractExecutionError | ResponseError; + error: + | TransactionRevertedWithoutReasonError> + | TransactionRevertInstructionError> + | TransactionRevertWithCustomError> + | InvalidResponseError + | ContractExecutionError; }; export interface SendTransactionOptions { @@ -76,6 +78,7 @@ export interface SendTransactionOptions { export interface SendSignedTransactionOptions { transactionResolver?: (receipt: TransactionReceipt) => ResolveType; + contractAbi?: ContractAbi; } export interface RevertReason { diff --git a/packages/web3-eth/src/web3_eth.ts b/packages/web3-eth/src/web3_eth.ts index 6c0ecb7794f..8308ca60b52 100644 --- a/packages/web3-eth/src/web3_eth.ts +++ b/packages/web3-eth/src/web3_eth.ts @@ -1028,8 +1028,9 @@ export class Web3Eth extends Web3Context( transaction: Bytes, returnFormat: ReturnFormat = DEFAULT_RETURN_FORMAT as ReturnFormat, + options?: SendTransactionOptions, ) { - return rpcMethodsWrappers.sendSignedTransaction(this, transaction, returnFormat); + return rpcMethodsWrappers.sendSignedTransaction(this, transaction, returnFormat, options); } /** diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index 894966391b9..b63efa86d6d 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -15,16 +15,18 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { Bytes, SignedTransactionInfoAPI, Transaction } from 'web3-types'; +import { Address, Bytes, SignedTransactionInfoAPI, Transaction } from 'web3-types'; import { DEFAULT_RETURN_FORMAT, FMT_BYTES, FMT_NUMBER, format, hexToNumber } from 'web3-utils'; import { isHexStrict } from 'web3-validator'; import { Web3Eth, InternalTransaction, transactionSchema } from '../../../src'; import { closeOpenConnection, createTempAccount, + getSystemTestBackend, getSystemTestProvider, } from '../../fixtures/system_test_utils'; import { getTransactionGasPricing } from '../../../src/utils/get_transaction_gas_pricing'; +import { SimpleRevertAbi, SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; const HEX_NUMBER_DATA_FORMAT = { bytes: FMT_BYTES.HEX, number: FMT_NUMBER.HEX } as const; @@ -293,4 +295,299 @@ describe('Web3Eth.sendSignedTransaction', () => { expect.assertions(1); }); }); + + describe('Transaction Error Scenarios', () => { + let simpleRevertContractAddress: Address; + + beforeAll(async () => { + const simpleRevertDeployTransaction: Transaction = { + from: tempAcc.address, + data: SimpleRevertDeploymentData, + }; + simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( + simpleRevertDeployTransaction, + ); + simpleRevertContractAddress = ( + await web3Eth.sendTransaction(simpleRevertDeployTransaction) + ).contractAddress as Address; + }); + + it('Should throw InvalidResponseError because gas too low', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: BigInt(1), + gas: 1, + gasPrice: 1, + nonce: await web3Eth.getTransactionCount(tempAcc.address), + }; + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + const expectedThrownError = { + name: 'InvalidResponseError', + code: 101, + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendRawTransaction', + params: [expect.any(String)], + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw InvalidResponseError because insufficient funds', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: BigInt('999999999999999999999999999999999999999999999999999999999'), + gasPrice: 1, + nonce: await web3Eth.getTransactionCount(tempAcc.address), + }; + transaction.gas = await web3Eth.estimateGas(transaction); + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + const expectedThrownError = { + name: 'InvalidResponseError', + code: 101, + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendRawTransaction', + params: [expect.any(String)], + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertInstructionError because of contract revert and return revert reason', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', + gasPrice: 2000000000, + gas: 23605, + }; + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + web3Eth.handleRevert = true; + + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted: This is a send revert' + : 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertWithCustomError because of contract revert and return custom error ErrorWithNoParams', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0x3ebf4d9c', + gasPrice: 2000000000, + gas: 21222, + }; + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + web3Eth.handleRevert = true; + + const expectedThrownError = { + name: 'TransactionRevertWithCustomError', + code: 438, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted' + : 'VM Exception while processing transaction: revert', + signature: '0x72090e4d', + customErrorName: 'ErrorWithNoParams', + customErrorDecodedSignature: 'ErrorWithNoParams()', + customErrorArguments: {}, + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21222), + gasUsed: BigInt(21222), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw, undefined, { + contractAbi: SimpleRevertAbi, + }) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertWithCustomError because of contract revert and return custom error ErrorWithParams', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0x819f48fe', + gasPrice: 2000000000, + gas: 21730, + }; + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + web3Eth.handleRevert = true; + + const expectedThrownError = { + name: 'TransactionRevertWithCustomError', + code: 438, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted' + : 'VM Exception while processing transaction: revert', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + customErrorName: 'ErrorWithParams', + customErrorDecodedSignature: 'ErrorWithParams(uint256,string)', + customErrorArguments: { + code: BigInt(42), + message: 'This is an error with params', + }, + receipt: + getSystemTestBackend() === 'geth' + ? undefined + : { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21730), + gasUsed: BigInt(21730), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw, undefined, { + contractAbi: SimpleRevertAbi, + }) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + + it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { + const transaction: Transaction = { + from: tempAcc.address, + to: simpleRevertContractAddress, + data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', + gasPrice: 2000000000, + gas: 23605, + }; + const signedTransaction = await web3Eth.signTransaction(transaction, { + number: FMT_NUMBER.BIGINT, + bytes: FMT_BYTES.BUFFER, + }); + + web3Eth.handleRevert = false; + + const expectedThrownError = + getSystemTestBackend() === 'geth' + ? { + name: 'ContractExecutionError', + code: 310, + innerError: { + name: 'Eip838ExecutionError', + code: 3, + data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }, + } + : { + name: 'TransactionRevertedWithoutReasonError', + code: 405, + receipt: { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; + + await expect( + web3Eth + .sendSignedTransaction(signedTransaction.raw) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), + ).rejects.toMatchObject(expectedThrownError); + }); + }); }); From a1d1a566b87cd66f89b4de4a71ce911a210cf85f Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 21:38:35 -1000 Subject: [PATCH 38/67] Remove call Transaction Error Scenario tests --- .../test/integration/web3_eth/call.test.ts | 39 +------------------ 1 file changed, 1 insertion(+), 38 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/call.test.ts b/packages/web3-eth/test/integration/web3_eth/call.test.ts index 010d0802195..e49e6a72c82 100644 --- a/packages/web3-eth/test/integration/web3_eth/call.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/call.test.ts @@ -14,16 +14,14 @@ GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { TransactionCall, BlockTags, Transaction, Address } from 'web3-types'; +import { TransactionCall, BlockTags, Transaction } from 'web3-types'; import { decodeParameters } from 'web3-eth-abi'; import { Web3Eth } from '../../../src'; import { closeOpenConnection, createTempAccount, - getSystemTestBackend, getSystemTestProvider, } from '../../fixtures/system_test_utils'; -import { SimpleRevertDeploymentData } from '../../fixtures/simple_revert'; describe('Web3Eth.call', () => { const expectedEncodedGreet = @@ -135,39 +133,4 @@ describe('Web3Eth.call', () => { expect(response).toBe('0x'); }); }); - - describe('Transaction Error Scenarios', () => { - let simpleRevertContractAddress: Address; - - beforeAll(async () => { - const simpleRevertDeployTransaction: Transaction = { - from: tempAcc.address, - data: SimpleRevertDeploymentData, - }; - simpleRevertDeployTransaction.gas = await web3Eth.estimateGas( - simpleRevertDeployTransaction, - ); - simpleRevertContractAddress = ( - await web3Eth.sendTransaction(simpleRevertDeployTransaction) - ).contractAddress as Address; - }); - - it('Should throw ContractExecutionError', async () => { - const transaction: TransactionCall = { - from: tempAcc.address, - to: simpleRevertContractAddress, - data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', - }; - - await expect(web3Eth.call(transaction)).rejects.toMatchObject({ - name: 'ContractExecutionError', - code: 310, - innerError: { - name: 'Eip838ExecutionError', - code: getSystemTestBackend() === 'geth' ? 3 : -32000, - data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - }, - }); - }); - }); }); From d7ce12f9402b916ca66ef8296c898a74f552551c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 22:05:52 -1000 Subject: [PATCH 39/67] Fix type error --- scripts/system_tests_utils.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/scripts/system_tests_utils.ts b/scripts/system_tests_utils.ts index 3debb639814..a4e95111d3c 100644 --- a/scripts/system_tests_utils.ts +++ b/scripts/system_tests_utils.ts @@ -37,7 +37,6 @@ import { Bytes, Web3BaseProvider, Transaction, - Receipt, KeyStore, ProviderConnectInfo, Web3ProviderEventCallback, @@ -335,7 +334,7 @@ export const signTxAndSendEIP1559 = async ( provider: unknown, tx: Record, privateKey: string, -): Promise => { +) => { const web3 = new Web3(provider as Web3BaseProvider); const acc = web3.eth.accounts.privateKeyToAccount(privateKey); const signedTx = await acc.signTransaction({ @@ -351,7 +350,7 @@ export const signTxAndSendEIP2930 = async ( provider: unknown, tx: Record, privateKey: string, -): Promise => { +) => { const web3 = new Web3(provider as Web3BaseProvider); const acc = web3.eth.accounts.privateKeyToAccount(privateKey); const signedTx = await acc.signTransaction({ From dc03c2295feb5efe294e585c1084aae3bb557165 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Fri, 24 Feb 2023 22:27:18 -1000 Subject: [PATCH 40/67] Fix nonce issue in tests --- .../integration/web3_eth/send_signed_transaction.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index b63efa86d6d..f740ec8b475 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -352,9 +352,9 @@ describe('Web3Eth.sendSignedTransaction', () => { to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), gasPrice: 1, + gas: 21000, nonce: await web3Eth.getTransactionCount(tempAcc.address), }; - transaction.gas = await web3Eth.estimateGas(transaction); const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, bytes: FMT_BYTES.BUFFER, @@ -387,6 +387,7 @@ describe('Web3Eth.sendSignedTransaction', () => { data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', gasPrice: 2000000000, gas: 23605, + nonce: await web3Eth.getTransactionCount(tempAcc.address), }; const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, @@ -436,6 +437,7 @@ describe('Web3Eth.sendSignedTransaction', () => { data: '0x3ebf4d9c', gasPrice: 2000000000, gas: 21222, + nonce: await web3Eth.getTransactionCount(tempAcc.address), }; const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, @@ -489,6 +491,7 @@ describe('Web3Eth.sendSignedTransaction', () => { data: '0x819f48fe', gasPrice: 2000000000, gas: 21730, + nonce: await web3Eth.getTransactionCount(tempAcc.address), }; const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, @@ -546,6 +549,7 @@ describe('Web3Eth.sendSignedTransaction', () => { data: '0xba57a511000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000067265766572740000000000000000000000000000000000000000000000000000', gasPrice: 2000000000, gas: 23605, + nonce: await web3Eth.getTransactionCount(tempAcc.address), }; const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, From 32add6de516c34212cbaa0cc71cb6f99d5473593 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 28 Feb 2023 18:22:40 -1000 Subject: [PATCH 41/67] Fix error parsing bug for web3Eth.sendSignedTransaction --- packages/web3-eth/src/rpc_method_wrappers.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 710ec8e718c..4453ca92dc2 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -1412,7 +1412,12 @@ export function sendSignedTransaction< ).toJSON(); const error = await getTransactionError( web3Context, - unSerializedTransaction as TransactionCall, + { + ...unSerializedTransaction, + // Some providers will default from to address(0) causing the error + // reported from eth_call to not be the reason the user's tx failed + from: transactionReceipt.from, + } as TransactionCall, transactionReceiptFormatted, undefined, options?.contractAbi, From 66b73774523819ea1187f20c2aa24ceea5f738fe Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 28 Feb 2023 18:22:58 -1000 Subject: [PATCH 42/67] Update expected error for send_signed_transaction error tests --- .../web3_eth/send_signed_transaction.test.ts | 132 ++++++++---------- 1 file changed, 56 insertions(+), 76 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index f740ec8b475..26a0e1a4d77 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -405,22 +405,19 @@ describe('Web3Eth.sendSignedTransaction', () => { : 'VM Exception while processing transaction: revert This is a send revert', signature: '0x08c379a0', data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, }; await expect( @@ -457,22 +454,19 @@ describe('Web3Eth.sendSignedTransaction', () => { customErrorName: 'ErrorWithNoParams', customErrorDecodedSignature: 'ErrorWithNoParams()', customErrorArguments: {}, - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21222), - gasUsed: BigInt(21222), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21222), + gasUsed: BigInt(21222), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, }; await expect( @@ -515,22 +509,19 @@ describe('Web3Eth.sendSignedTransaction', () => { code: BigInt(42), message: 'This is an error with params', }, - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21730), - gasUsed: BigInt(21730), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(21730), + gasUsed: BigInt(21730), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, }; await expect( @@ -558,34 +549,23 @@ describe('Web3Eth.sendSignedTransaction', () => { web3Eth.handleRevert = false; - const expectedThrownError = - getSystemTestBackend() === 'geth' - ? { - name: 'ContractExecutionError', - code: 310, - innerError: { - name: 'Eip838ExecutionError', - code: 3, - data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - }, - } - : { - name: 'TransactionRevertedWithoutReasonError', - code: 405, - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, - }; + const expectedThrownError = { + name: 'TransactionRevertedWithoutReasonError', + code: 405, + receipt: { + transactionIndex: BigInt(0), + from: tempAcc.address, + to: simpleRevertContractAddress, + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + status: BigInt(0), + effectiveGasPrice: BigInt(2000000000), + type: BigInt(0), + }, + }; await expect( web3Eth From b998f8f788cbba2543bd6144cae50ba57d8acf3a Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 14:41:43 -1000 Subject: [PATCH 43/67] Revert ResponseError change to maintain 1.x parity --- packages/web3-errors/src/errors/response_errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-errors/src/errors/response_errors.ts b/packages/web3-errors/src/errors/response_errors.ts index 7efd4240ceb..fdd6ad5fe49 100644 --- a/packages/web3-errors/src/errors/response_errors.ts +++ b/packages/web3-errors/src/errors/response_errors.ts @@ -53,7 +53,7 @@ export class ResponseError extends B ) { super( message ?? - `${ + `Returned error: ${ Array.isArray(response) ? response.map(r => buildErrorMessage(r)).join(',') : buildErrorMessage(response) From 35293d680039e81625eef983b32e8c054cfb2c28 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 14:53:55 -1000 Subject: [PATCH 44/67] Add web3-errors test for TransactionRevertWithCustomError --- .../src/errors/transaction_errors.ts | 5 ++++ .../unit/__snapshots__/errors.test.ts.snap | 26 ++++++++++++++++--- packages/web3-errors/test/unit/errors.test.ts | 18 +++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/packages/web3-errors/src/errors/transaction_errors.ts b/packages/web3-errors/src/errors/transaction_errors.ts index e78c7c9a96c..807578a4097 100644 --- a/packages/web3-errors/src/errors/transaction_errors.ts +++ b/packages/web3-errors/src/errors/transaction_errors.ts @@ -114,6 +114,11 @@ export class TransactionRevertInstructionError< } } +/** + * This error is used when a transaction to a smart contract fails and + * a custom user error (https://blog.soliditylang.org/2021/04/21/custom-errors/) + * is able to be parsed from the revert reason + */ export class TransactionRevertWithCustomError< ReceiptType = TransactionReceipt, > extends TransactionRevertInstructionError { diff --git a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap index 03460675aa8..75b7e088919 100644 --- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap @@ -170,7 +170,7 @@ Object { }, "message": "error message", }, - "message": "error message", + "message": "Returned error: error message", "name": "InvalidResponseError", "request": undefined, } @@ -228,7 +228,7 @@ Object { "b": "20", }, "innerError": undefined, - "message": "error message", + "message": "Returned error: error message", "name": "ResponseError", "request": undefined, } @@ -239,7 +239,7 @@ Object { "code": 100, "data": undefined, "innerError": undefined, - "message": "error message", + "message": "Returned error: error message", "name": "ResponseError", "request": undefined, } @@ -299,6 +299,26 @@ Object { } `; +exports[`errors TransactionRevertWithCustomError should have valid json structure 1`] = ` +Object { + "code": 438, + "customErrorArguments": Object { + "customErrorArgument": "customErrorArgument", + }, + "customErrorDecodedSignature": "customErrorDecodedSignature", + "customErrorName": "customErrorName", + "data": "data", + "innerError": undefined, + "message": "Transaction has been reverted by the EVM", + "name": "TransactionRevertWithCustomError", + "reason": "reason", + "receipt": Object { + "attr1": "attr1", + }, + "signature": "signature", +} +`; + exports[`errors TransactionRevertedWithoutReasonError should have valid json structure 1`] = ` Object { "code": 405, diff --git a/packages/web3-errors/test/unit/errors.test.ts b/packages/web3-errors/test/unit/errors.test.ts index 4869fcdedeb..138a62030f1 100644 --- a/packages/web3-errors/test/unit/errors.test.ts +++ b/packages/web3-errors/test/unit/errors.test.ts @@ -172,6 +172,24 @@ describe('errors', () => { }); }); + describe('TransactionRevertWithCustomError', () => { + it('should have valid json structure', () => { + expect( + new transactionErrors.TransactionRevertWithCustomError( + 'reason', + 'customErrorName', + 'customErrorDecodedSignature', + { customErrorArgument: 'customErrorArgument' }, + 'signature', + { + attr1: 'attr1', + } as any, + 'data', + ).toJSON(), + ).toMatchSnapshot(); + }); + }); + describe('NoContractAddressFoundError', () => { it('should have valid json structure', () => { expect( From 68efd93480ca04f7b7d98337dccf2965c7c6c0ee Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 14:59:01 -1000 Subject: [PATCH 45/67] Update expected error message for RespnoseError in web3-eth-contract tests --- .../web3-eth-contract/test/integration/contract_deploy.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts index c97ad326171..f89008d7b95 100644 --- a/packages/web3-eth-contract/test/integration/contract_deploy.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_deploy.test.ts @@ -225,7 +225,7 @@ describe('contract', () => { it('should fail with errors on "intrinsic gas too low" OOG', async () => { await expect( contract.deploy(deployOptions).send({ ...sendOptions, gas: '100' }), - ).rejects.toThrow('intrinsic gas too low'); + ).rejects.toThrow('Returned error: intrinsic gas too low'); }); it('should fail with errors deploying a zero length bytecode', () => { From d6fc6586a512ad665f9d440d6346f4aad6912994 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 15:11:12 -1000 Subject: [PATCH 46/67] Add example to dev comment for sendSignedTransaction --- packages/web3-eth/src/rpc_method_wrappers.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 4453ca92dc2..3aa039499b8 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -1414,8 +1414,11 @@ export function sendSignedTransaction< web3Context, { ...unSerializedTransaction, - // Some providers will default from to address(0) causing the error - // reported from eth_call to not be the reason the user's tx failed + // Some providers will default `from` to address(0) causing the error + // reported from `eth_call` to not be the reason the user's tx failed + // e.g. `eth_call` will return an Out of Gas error for a failed + // smart contract execution contract, because the sender, address(0), + // has no balance to pay for the gas of the transaction execution from: transactionReceipt.from, } as TransactionCall, transactionReceiptFormatted, From 3d3e7bcdcb78ec72bc5769a9ec84a0f8b2fdcef4 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 15:15:51 -1000 Subject: [PATCH 47/67] Removed implemented TODO in packages/web3-eth/src/utils/get_transaction_error.ts --- packages/web3-eth/src/utils/get_transaction_error.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts index ce47eaeb4ca..7e5f182fe62 100644 --- a/packages/web3-eth/src/utils/get_transaction_error.ts +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -27,7 +27,6 @@ import { RevertReason, RevertReasonWithCustomError } from '../types'; // eslint-disable-next-line import/no-cycle import { getRevertReason, parseTransactionError } from './get_revert_reason'; -// TODO Add support for passing contract ABI to getRevertReason? export async function getTransactionError( web3Context: Web3Context, transactionFormatted?: TransactionCall, From 64a3e1f01a9b26c65aa9678732e3deee4e1d4744 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 15:30:48 -1000 Subject: [PATCH 48/67] Update CHANGELOGs --- CHANGELOG.md | 7 +++++++ packages/web3-errors/CHANGELOG.md | 4 ++++ packages/web3-eth/CHANGELOG.md | 2 ++ 3 files changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dc15600d92f..5e6bf73d4f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1155,11 +1155,15 @@ should use 4.0.1-alpha.0 for testing. #### web3-errors - Added error class `InvalidMethodParamsError` and error code `ERR_INVALID_METHOD_PARAMS = 207` (#5824) +- `request` property to `ResponseError` (#5854) +- `data` property to `TransactionRevertInstructionError` (#5854) +- `TransactionRevertWithCustomError` was added to handle custom solidity errors (#5854) #### web3-eth - Added `createAccessList` functionality ( #5780 ) - Added support of `safe` and `finalized` block tags (#5823) +- `contractAbi` option to `SendTransactionOptions` and `SendSignedTransactionOptions` to added the ability to parse custom solidity errors (#5854) #### web3-eth-abi @@ -1211,10 +1215,12 @@ should use 4.0.1-alpha.0 for testing. #### web3-errors - The abstract class `Web3Error` is renamed to `BaseWeb3Error` (#5771) +- Renamed TransactionRevertError to TransactionRevertInstructionError to remain consistent with 1.x #### web3-eth - Update imports statements for objects that was moved between web3 packages (#5771) +- `sendTransaction` and `sendSignedTransaction` now errors with (and `error` event emits) the following possible errors: `TransactionRevertedWithoutReasonError`, `TransactionRevertInstructionError`, `TransactionRevertWithCustomError`, `InvalidResponseError`, or `ContractExecutionError` (#5854) #### web3-eth-contract @@ -1257,3 +1263,4 @@ should use 4.0.1-alpha.0 for testing. #### web3-eth-contract - Fix contract defaults (#5756) +- Fixed getPastEventsError (#5819) diff --git a/packages/web3-errors/CHANGELOG.md b/packages/web3-errors/CHANGELOG.md index 0bb19126626..95890de8749 100644 --- a/packages/web3-errors/CHANGELOG.md +++ b/packages/web3-errors/CHANGELOG.md @@ -76,7 +76,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - The abstract class `Web3Error` is renamed to `BaseWeb3Error` (#5771) +- Renamed TransactionRevertError to TransactionRevertInstructionError to remain consistent with 1.x ### Added - Added error class `InvalidMethodParamsError` and error code `ERR_INVALID_METHOD_PARAMS = 207` (#5824) +- `request` property to `ResponseError` (#5854) +- `data` property to `TransactionRevertInstructionError` (#5854) +- `TransactionRevertWithCustomError` was added to handle custom solidity errors (#5854) diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 00162a400a2..203b5637db3 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -94,11 +94,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Update imports statements for objects that was moved between web3 packages (#5771) +- `sendTransaction` and `sendSignedTransaction` now errors with (and `error` event emits) the following possible errors: `TransactionRevertedWithoutReasonError`, `TransactionRevertInstructionError`, `TransactionRevertWithCustomError`, `InvalidResponseError`, or `ContractExecutionError` (#5854) ### Added - Added `createAccessList` functionality ( #5780 ) - Added support of `safe` and `finalized` block tags (#5823) +- `contractAbi` option to `SendTransactionOptions` and `SendSignedTransactionOptions` to added the ability to parse custom solidity errors (#5854) ### Removed From fedc9184d829741d266edddccdedde742bc96856 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 15:34:01 -1000 Subject: [PATCH 49/67] Update CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e6bf73d4f7..a4c648f425e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1215,7 +1215,7 @@ should use 4.0.1-alpha.0 for testing. #### web3-errors - The abstract class `Web3Error` is renamed to `BaseWeb3Error` (#5771) -- Renamed TransactionRevertError to TransactionRevertInstructionError to remain consistent with 1.x +- Renamed `TransactionRevertError` to `TransactionRevertInstructionError` to remain consistent with `1.x` (#5854) #### web3-eth From c54d2b964a37d8e0619b6e2d97c930f043ffa80d Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 17:45:52 -1000 Subject: [PATCH 50/67] Init get_transaction_error tests --- .../unit/utils/get_transaction_error.test.ts | 442 ++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 packages/web3-eth/test/unit/utils/get_transaction_error.test.ts diff --git a/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts b/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts new file mode 100644 index 00000000000..5b62038b8f3 --- /dev/null +++ b/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts @@ -0,0 +1,442 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { Web3Context } from 'web3-core'; +import { + InvalidResponseError, + TransactionRevertedWithoutReasonError, + TransactionRevertInstructionError, + TransactionRevertWithCustomError, +} from 'web3-errors'; + +import * as GetRevertReasonUtils from '../../../src/utils/get_revert_reason'; +import { getTransactionError } from '../../../src/utils/get_transaction_error'; +import { SimpleRevertAbi } from '../../fixtures/simple_revert'; + +describe('getTransactionError', () => { + let web3Context: Web3Context; + + beforeEach(() => { + web3Context = new Web3Context('http://127.0.0.1:8545'); + }); + + it('should call parseTransactionError to get error from receivedError', async () => { + const parseTransactionErrorSpy = jest.spyOn(GetRevertReasonUtils, 'parseTransactionError'); + + const receivedError = new InvalidResponseError( + { + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }, + { + jsonrpc: '2.0', + id: '2568856d-8ee5-43f4-a8db-dbd22cf97a53', + method: 'eth_sendTransaction', + params: [ + { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x0000000000000000000000000000000000000000', + value: '0x1', + gas: '0x1', + gasPrice: '0x15b61074', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }, + ], + }, + ); + await getTransactionError(web3Context, undefined, undefined, receivedError); + expect(parseTransactionErrorSpy).toHaveBeenCalledWith(receivedError); + }); + + it('should call getRevertReason to get error from transactionFormatted without contractAbi', async () => { + const getRevertReasonSpy = jest.spyOn(GetRevertReasonUtils, 'getRevertReason'); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + web3Context.handleRevert = true; + await getTransactionError(web3Context, transaction); + expect(getRevertReasonSpy).toHaveBeenCalledWith(web3Context, transaction, undefined); + }); + + it('should call getRevertReason to get error from transactionFormatted with contractAbi', async () => { + const getRevertReasonSpy = jest.spyOn(GetRevertReasonUtils, 'getRevertReason'); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + web3Context.handleRevert = true; + await getTransactionError(web3Context, transaction, undefined, undefined, SimpleRevertAbi); + expect(getRevertReasonSpy).toHaveBeenCalledWith(web3Context, transaction, SimpleRevertAbi); + }); + + describe('TransactionRevertedWithoutReasonError', () => { + it('should throw TransactionRevertedWithoutReasonError without receipt', async () => { + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + expect(await getTransactionError(web3Context, transaction)).toMatchObject( + new TransactionRevertedWithoutReasonError(), + ); + }); + + it('should throw TransactionRevertedWithoutReasonError with receipt', async () => { + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + const receipt = { + transactionHash: + '0x55de60905fb9efdaa5dc5ac6a2e05736e92067d44b8a3077c80ec849545cbcf0', + transactionIndex: BigInt(0), + blockHash: '0xc150c0a7f7f5c9014ea965d19b1be5f5ced07a6b17ea3b1126769d745dde9b2d', + blockNumber: BigInt(16738176), + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + effectiveGasPrice: BigInt(2000000000), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + root: '', + status: BigInt(0), + type: BigInt(0), + }; + + expect(await getTransactionError(web3Context, transaction, receipt)).toMatchObject( + new TransactionRevertedWithoutReasonError(receipt), + ); + }); + }); + + describe('TransactionRevertInstructionError', () => { + it('should throw TransactionRevertInstructionError without transaction and receipt', async () => { + const receivedError = new InvalidResponseError( + { + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }, + { + jsonrpc: '2.0', + id: '2568856d-8ee5-43f4-a8db-dbd22cf97a53', + method: 'eth_sendTransaction', + params: [ + { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x0000000000000000000000000000000000000000', + value: '0x1', + gas: '0x1', + gasPrice: '0x15b61074', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }, + ], + }, + ); + + expect( + await getTransactionError(web3Context, undefined, undefined, receivedError), + ).toMatchObject(new TransactionRevertInstructionError('intrinsic gas too low')); + }); + + it('should throw TransactionRevertInstructionError without transaction and with receipt', async () => { + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + const receipt = { + transactionHash: + '0x55de60905fb9efdaa5dc5ac6a2e05736e92067d44b8a3077c80ec849545cbcf0', + transactionIndex: BigInt(0), + blockHash: '0xc150c0a7f7f5c9014ea965d19b1be5f5ced07a6b17ea3b1126769d745dde9b2d', + blockNumber: BigInt(16738176), + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + effectiveGasPrice: BigInt(2000000000), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + root: '', + status: BigInt(0), + type: BigInt(0), + }; + const receivedError = new InvalidResponseError( + { + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }, + { + jsonrpc: '2.0', + id: '2568856d-8ee5-43f4-a8db-dbd22cf97a53', + method: 'eth_sendTransaction', + params: [ + { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x0000000000000000000000000000000000000000', + value: '0x1', + gas: '0x1', + gasPrice: '0x15b61074', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }, + ], + }, + ); + + expect( + await getTransactionError(web3Context, transaction, receipt, receivedError), + ).toMatchObject( + new TransactionRevertInstructionError('intrinsic gas too low', undefined, receipt), + ); + }); + + it('should throw TransactionRevertInstructionError without receipt', async () => { + jest.spyOn(GetRevertReasonUtils, 'getRevertReason').mockResolvedValueOnce({ + reason: 'execution reverted', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + }); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + web3Context.handleRevert = true; + expect( + await getTransactionError( + web3Context, + transaction, + undefined, + undefined, + SimpleRevertAbi, + ), + ).toMatchObject( + new TransactionRevertInstructionError( + 'execution reverted', + '0xc85bda60', + undefined, + '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + ), + ); + }); + + it('should throw TransactionRevertInstructionError with receipt', async () => { + jest.spyOn(GetRevertReasonUtils, 'getRevertReason').mockResolvedValueOnce({ + reason: 'execution reverted', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + }); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + const receipt = { + transactionHash: + '0x55de60905fb9efdaa5dc5ac6a2e05736e92067d44b8a3077c80ec849545cbcf0', + transactionIndex: BigInt(0), + blockHash: '0xc150c0a7f7f5c9014ea965d19b1be5f5ced07a6b17ea3b1126769d745dde9b2d', + blockNumber: BigInt(16738176), + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + effectiveGasPrice: BigInt(2000000000), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + root: '', + status: BigInt(0), + type: BigInt(0), + }; + + web3Context.handleRevert = true; + expect( + await getTransactionError( + web3Context, + transaction, + receipt, + undefined, + SimpleRevertAbi, + ), + ).toMatchObject( + new TransactionRevertInstructionError( + 'execution reverted', + '0xc85bda60', + receipt, + '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + ), + ); + }); + }); + + describe('TransactionRevertWithCustomError', () => { + it('should throw TransactionRevertWithCustomError without receipt', async () => { + jest.spyOn(GetRevertReasonUtils, 'getRevertReason').mockResolvedValueOnce({ + reason: 'execution reverted', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + customErrorName: 'ErrorWithParams', + customErrorDecodedSignature: 'ErrorWithParams(uint256,string)', + customErrorArguments: { + code: BigInt(42), + message: 'This is an error with params', + }, + }); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + web3Context.handleRevert = true; + expect( + await getTransactionError( + web3Context, + transaction, + undefined, + undefined, + SimpleRevertAbi, + ), + ).toMatchObject( + new TransactionRevertWithCustomError( + 'execution reverted', + 'ErrorWithParams', + 'ErrorWithParams(uint256,string)', + { + code: BigInt(42), + message: 'This is an error with params', + }, + '0xc85bda60', + undefined, + '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + ), + ); + }); + + it('should throw TransactionRevertWithCustomError with receipt', async () => { + jest.spyOn(GetRevertReasonUtils, 'getRevertReason').mockResolvedValueOnce({ + reason: 'execution reverted', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + customErrorName: 'ErrorWithParams', + customErrorDecodedSignature: 'ErrorWithParams(uint256,string)', + customErrorArguments: { + code: BigInt(42), + message: 'This is an error with params', + }, + }); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + const receipt = { + transactionHash: + '0x55de60905fb9efdaa5dc5ac6a2e05736e92067d44b8a3077c80ec849545cbcf0', + transactionIndex: BigInt(0), + blockHash: '0xc150c0a7f7f5c9014ea965d19b1be5f5ced07a6b17ea3b1126769d745dde9b2d', + blockNumber: BigInt(16738176), + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + cumulativeGasUsed: BigInt(23605), + gasUsed: BigInt(23605), + effectiveGasPrice: BigInt(2000000000), + logs: [], + logsBloom: + '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', + root: '', + status: BigInt(0), + type: BigInt(0), + }; + + web3Context.handleRevert = true; + expect( + await getTransactionError( + web3Context, + transaction, + receipt, + undefined, + SimpleRevertAbi, + ), + ).toMatchObject( + new TransactionRevertWithCustomError( + 'execution reverted', + 'ErrorWithParams', + 'ErrorWithParams(uint256,string)', + { + code: BigInt(42), + message: 'This is an error with params', + }, + '0xc85bda60', + receipt, + '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + ), + ); + }); + }); +}); From 683515c59f5dbe9ef9234f2c7aeed8e533614253 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 18:00:15 -1000 Subject: [PATCH 51/67] Add mock to getRevertReason for get_transaction_error tests --- .../test/unit/utils/get_transaction_error.test.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts b/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts index 5b62038b8f3..898947f4889 100644 --- a/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts +++ b/packages/web3-eth/test/unit/utils/get_transaction_error.test.ts @@ -65,7 +65,9 @@ describe('getTransactionError', () => { }); it('should call getRevertReason to get error from transactionFormatted without contractAbi', async () => { - const getRevertReasonSpy = jest.spyOn(GetRevertReasonUtils, 'getRevertReason'); + const getRevertReasonSpy = jest + .spyOn(GetRevertReasonUtils, 'getRevertReason') + .mockImplementation(); const transaction = { from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', @@ -82,7 +84,9 @@ describe('getTransactionError', () => { }); it('should call getRevertReason to get error from transactionFormatted with contractAbi', async () => { - const getRevertReasonSpy = jest.spyOn(GetRevertReasonUtils, 'getRevertReason'); + const getRevertReasonSpy = jest + .spyOn(GetRevertReasonUtils, 'getRevertReason') + .mockImplementation(); const transaction = { from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', From 547f9bedf97c3cb4ac53f1f85f4f44ee32f95969 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 1 Mar 2023 20:17:28 -1000 Subject: [PATCH 52/67] Init getRevertReason tests and parseTransactionError tests --- .../test/unit/utils/get_revert_reason.test.ts | 125 ++++++++++++++++++ .../utils/parse_transaction_error.test.ts | 89 +++++++++++++ 2 files changed, 214 insertions(+) create mode 100644 packages/web3-eth/test/unit/utils/get_revert_reason.test.ts create mode 100644 packages/web3-eth/test/unit/utils/parse_transaction_error.test.ts diff --git a/packages/web3-eth/test/unit/utils/get_revert_reason.test.ts b/packages/web3-eth/test/unit/utils/get_revert_reason.test.ts new file mode 100644 index 00000000000..7ae0b6493b0 --- /dev/null +++ b/packages/web3-eth/test/unit/utils/get_revert_reason.test.ts @@ -0,0 +1,125 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { Web3Context } from 'web3-core'; +import { DEFAULT_RETURN_FORMAT } from 'web3-utils'; + +import * as RpcMethodWrappers from '../../../src/rpc_method_wrappers'; +import * as GetRevertReason from '../../../src/utils/get_revert_reason'; +import { SimpleRevertAbi } from '../../fixtures/simple_revert'; + +describe('getRevertReason', () => { + const web3Context = new Web3Context(); + + it('should use the call rpc wrapper', async () => { + const callSpy = jest.spyOn(RpcMethodWrappers, 'call').mockImplementation(); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + await GetRevertReason.getRevertReason(web3Context, transaction); + + expect(callSpy).toHaveBeenCalledWith( + web3Context, + transaction, + web3Context.defaultBlock, + DEFAULT_RETURN_FORMAT, + ); + }); + + it('should return undefined', async () => { + jest.spyOn(RpcMethodWrappers, 'call').mockResolvedValueOnce( + '0x000000000000000000000000000000000000000000000000000000000000000a', + ); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + const result = await GetRevertReason.getRevertReason(web3Context, transaction); + + expect(result).toBeUndefined(); + }); + + it('should call parseTransactionError without contractAbi', async () => { + const expectedError = { + jsonrpc: '2.0', + id: 1, + error: { + code: -32000, + message: + 'err: insufficient funds for gas * price + value: address 0x0000000000000000000000000000000000000000 have 66 want 9983799287684 (supplied gas 26827)', + }, + }; + const parseTransactionErrorSpy = jest + .spyOn(GetRevertReason, 'parseTransactionError') + .mockImplementation(); + jest.spyOn(RpcMethodWrappers, 'call').mockRejectedValueOnce(expectedError); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + await GetRevertReason.getRevertReason(web3Context, transaction); + + expect(parseTransactionErrorSpy).toHaveBeenCalledWith(expectedError, undefined); + }); + + it('should call parseTransactionError with contractAbi', async () => { + const expectedError = { + jsonrpc: '2.0', + id: 1, + error: { + code: -32000, + message: + 'err: insufficient funds for gas * price + value: address 0x0000000000000000000000000000000000000000 have 66 want 9983799287684 (supplied gas 26827)', + }, + }; + const parseTransactionErrorSpy = jest + .spyOn(GetRevertReason, 'parseTransactionError') + .mockImplementation(); + jest.spyOn(RpcMethodWrappers, 'call').mockRejectedValueOnce(expectedError); + + const transaction = { + from: '0x4fec0a51024b13030d26e70904b066c6d41157a5', + to: '0x36361143b7e2c676f8ccd67743a89d26437f0529', + data: '0x819f48fe', + gasPrice: '0x15ab8f14', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }; + + await GetRevertReason.getRevertReason(web3Context, transaction, SimpleRevertAbi); + + expect(parseTransactionErrorSpy).toHaveBeenCalledWith(expectedError, SimpleRevertAbi); + }); +}); diff --git a/packages/web3-eth/test/unit/utils/parse_transaction_error.test.ts b/packages/web3-eth/test/unit/utils/parse_transaction_error.test.ts new file mode 100644 index 00000000000..e76baa54cf0 --- /dev/null +++ b/packages/web3-eth/test/unit/utils/parse_transaction_error.test.ts @@ -0,0 +1,89 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ +import { ContractExecutionError, InvalidResponseError } from 'web3-errors'; + +import { parseTransactionError } from '../../../src/utils/get_revert_reason'; +import { SimpleRevertAbi } from '../../fixtures/simple_revert'; + +describe('parseTransactionError', () => { + it('should return object of type RevertReason', () => { + const error = new ContractExecutionError({ + code: 3, + message: 'execution reverted: This is a send revert', + data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }); + + const result = parseTransactionError(error); + expect(result).toStrictEqual({ + reason: 'execution reverted: This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }); + }); + + it('should return object of type RevertReasonWithCustomError', () => { + const error = new ContractExecutionError({ + code: 3, + message: 'execution reverted', + data: '0xc85bda60000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + }); + + const result = parseTransactionError(error, SimpleRevertAbi); + expect(result).toStrictEqual({ + reason: 'execution reverted', + signature: '0xc85bda60', + data: '000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + customErrorName: 'ErrorWithParams', + customErrorDecodedSignature: 'ErrorWithParams(uint256,string)', + customErrorArguments: { + '0': BigInt(42), + '1': 'This is an error with params', + __length__: 2, + code: BigInt(42), + message: 'This is an error with params', + }, + }); + }); + + it('should return object of type string', () => { + const error = new InvalidResponseError({ + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }); + + const result = parseTransactionError(error); + expect(result).toBe('intrinsic gas too low'); + }); + + it('should throw an error', () => { + const error = new InvalidResponseError([ + { + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }, + { + jsonrpc: '2.0', + id: '3f839900-afdd-4553-bca7-b4e2b835c687', + error: { code: -32000, message: 'intrinsic gas too low' }, + }, + ]); + + expect(() => parseTransactionError(error)).toThrowError(error); + }); +}); From 9e3c63764ba5dbd434c3b9930b57232f30eb1bb7 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Thu, 2 Mar 2023 19:14:53 -1000 Subject: [PATCH 53/67] Add check for revert before sending tx --- packages/web3-eth/src/rpc_method_wrappers.ts | 87 ++++++-- packages/web3-eth/src/types.ts | 2 + .../src/utils/get_transaction_error.ts | 46 ++-- .../web3_eth/send_signed_transaction.test.ts | 134 +++++------ .../web3_eth/send_transaction.test.ts | 210 +++++------------- 5 files changed, 209 insertions(+), 270 deletions(-) diff --git a/packages/web3-eth/src/rpc_method_wrappers.ts b/packages/web3-eth/src/rpc_method_wrappers.ts index 3aa039499b8..5317e66e603 100644 --- a/packages/web3-eth/src/rpc_method_wrappers.ts +++ b/packages/web3-eth/src/rpc_method_wrappers.ts @@ -96,6 +96,8 @@ import { watchTransactionForConfirmations } from './utils/watch_transaction_for_ import { NUMBER_DATA_FORMAT } from './constants'; // eslint-disable-next-line import/no-cycle import { getTransactionError } from './utils/get_transaction_error'; +// eslint-disable-next-line import/no-cycle +import { getRevertReason } from './utils/get_revert_reason'; /** * @@ -1079,7 +1081,7 @@ export function sendTransaction< | TransactionWithToLocalWalletIndex | TransactionWithFromAndToLocalWalletIndex, returnFormat: ReturnFormat, - options?: SendTransactionOptions, + options: SendTransactionOptions = { checkRevertBeforeSending: true }, ): Web3PromiEvent> { const promiEvent = new Web3PromiEvent>( (resolve, reject) => { @@ -1113,6 +1115,31 @@ export function sendTransaction< } try { + if (options.checkRevertBeforeSending !== false) { + const reason = await getRevertReason( + web3Context, + transactionFormatted as TransactionCall, + options.contractAbi, + ); + if (reason !== undefined) { + const error = await getTransactionError( + web3Context, + transactionFormatted as TransactionCall, + undefined, + undefined, + options.contractAbi, + reason, + ); + + if (promiEvent.listenerCount('error') > 0) { + promiEvent.emit('error', error); + } + + reject(error); + return; + } + } + if (promiEvent.listenerCount('sending') > 0) { promiEvent.emit('sending', transactionFormatted); } @@ -1341,7 +1368,7 @@ export function sendSignedTransaction< web3Context: Web3Context, signedTransaction: Bytes, returnFormat: ReturnFormat, - options?: SendSignedTransactionOptions, + options: SendSignedTransactionOptions = { checkRevertBeforeSending: true }, ): Web3PromiEvent> { // TODO - Promise returned in function argument where a void return was expected // eslint-disable-next-line @typescript-eslint/no-misused-promises @@ -1355,8 +1382,45 @@ export function sendSignedTransaction< signedTransaction, ETH_DATA_FORMAT, ); + const unSerializedTransaction = TransactionFactory.fromSerializedData( + bytesToBuffer(hexToBytes(signedTransactionFormattedHex)), + ); + const unSerializedTransactionWithFrom = { + ...unSerializedTransaction.toJSON(), + // Some providers will default `from` to address(0) causing the error + // reported from `eth_call` to not be the reason the user's tx failed + // e.g. `eth_call` will return an Out of Gas error for a failed + // smart contract execution contract, because the sender, address(0), + // has no balance to pay for the gas of the transaction execution + from: unSerializedTransaction.getSenderAddress().toString(), + }; try { + if (options.checkRevertBeforeSending !== false) { + const reason = await getRevertReason( + web3Context, + unSerializedTransactionWithFrom as TransactionCall, + options.contractAbi, + ); + if (reason !== undefined) { + const error = await getTransactionError( + web3Context, + unSerializedTransactionWithFrom as TransactionCall, + undefined, + undefined, + options.contractAbi, + reason, + ); + + if (promiEvent.listenerCount('error') > 0) { + promiEvent.emit('error', error); + } + + reject(error); + return; + } + } + if (promiEvent.listenerCount('sending') > 0) { promiEvent.emit('sending', signedTransactionFormattedHex); } @@ -1407,20 +1471,9 @@ export function sendSignedTransaction< ) as unknown as ResolveType, ); } else if (transactionReceipt.status === BigInt(0)) { - const unSerializedTransaction = TransactionFactory.fromSerializedData( - bytesToBuffer(hexToBytes(signedTransactionFormattedHex)), - ).toJSON(); const error = await getTransactionError( web3Context, - { - ...unSerializedTransaction, - // Some providers will default `from` to address(0) causing the error - // reported from `eth_call` to not be the reason the user's tx failed - // e.g. `eth_call` will return an Out of Gas error for a failed - // smart contract execution contract, because the sender, address(0), - // has no balance to pay for the gas of the transaction execution - from: transactionReceipt.from, - } as TransactionCall, + unSerializedTransactionWithFrom as TransactionCall, transactionReceiptFormatted, undefined, options?.contractAbi, @@ -1449,16 +1502,12 @@ export function sendSignedTransaction< ); } } catch (error) { - const unSerializedTransaction = TransactionFactory.fromSerializedData( - bytesToBuffer(hexToBytes(signedTransactionFormattedHex)), - ).toJSON(); - let _error = error; if (_error instanceof ContractExecutionError && web3Context.handleRevert) { _error = await getTransactionError( web3Context, - unSerializedTransaction as TransactionCall, + unSerializedTransactionWithFrom as TransactionCall, undefined, undefined, options?.contractAbi, diff --git a/packages/web3-eth/src/types.ts b/packages/web3-eth/src/types.ts index f1fe8263ae7..fc9b5121543 100644 --- a/packages/web3-eth/src/types.ts +++ b/packages/web3-eth/src/types.ts @@ -74,11 +74,13 @@ export interface SendTransactionOptions { ignoreGasPricing?: boolean; transactionResolver?: (receipt: TransactionReceipt) => ResolveType; contractAbi?: ContractAbi; + checkRevertBeforeSending?: boolean; } export interface SendSignedTransactionOptions { transactionResolver?: (receipt: TransactionReceipt) => ResolveType; contractAbi?: ContractAbi; + checkRevertBeforeSending?: boolean; } export interface RevertReason { diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts index 7e5f182fe62..51249be6735 100644 --- a/packages/web3-eth/src/utils/get_transaction_error.ts +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -33,50 +33,54 @@ export async function getTransactionError( transactionReceiptFormatted?: FormatType, receivedError?: unknown, contractAbi?: ContractAbi, + knownReason?: string | RevertReason | RevertReasonWithCustomError, ) { - let reason: string | RevertReason | RevertReasonWithCustomError | undefined; + let _reason: string | RevertReason | RevertReasonWithCustomError | undefined = knownReason; - if (receivedError !== undefined) { - reason = parseTransactionError(receivedError); - } else if (web3Context.handleRevert && transactionFormatted !== undefined) { - reason = await getRevertReason(web3Context, transactionFormatted, contractAbi); + if (_reason === undefined) { + if (receivedError !== undefined) { + _reason = parseTransactionError(receivedError); + } else if (web3Context.handleRevert && transactionFormatted !== undefined) { + _reason = await getRevertReason(web3Context, transactionFormatted, contractAbi); + } } let error: | TransactionRevertedWithoutReasonError> | TransactionRevertInstructionError> | TransactionRevertWithCustomError>; - if (reason === undefined) { + if (_reason === undefined) { error = new TransactionRevertedWithoutReasonError< FormatType >(transactionReceiptFormatted); - } else if (typeof reason === 'string') { + } else if (typeof _reason === 'string') { error = new TransactionRevertInstructionError>( - reason, + _reason, undefined, transactionReceiptFormatted, ); } else if ( - (reason as RevertReasonWithCustomError).customErrorName !== undefined && - (reason as RevertReasonWithCustomError).customErrorDecodedSignature !== undefined && - (reason as RevertReasonWithCustomError).customErrorArguments !== undefined + (_reason as RevertReasonWithCustomError).customErrorName !== undefined && + (_reason as RevertReasonWithCustomError).customErrorDecodedSignature !== undefined && + (_reason as RevertReasonWithCustomError).customErrorArguments !== undefined ) { - const _reason: RevertReasonWithCustomError = reason as RevertReasonWithCustomError; + const reasonWithCustomError: RevertReasonWithCustomError = + knownReason as RevertReasonWithCustomError; error = new TransactionRevertWithCustomError>( - _reason.reason, - _reason.customErrorName, - _reason.customErrorDecodedSignature, - _reason.customErrorArguments, - _reason.signature, + reasonWithCustomError.reason, + reasonWithCustomError.customErrorName, + reasonWithCustomError.customErrorDecodedSignature, + reasonWithCustomError.customErrorArguments, + reasonWithCustomError.signature, transactionReceiptFormatted, - _reason.data, + reasonWithCustomError.data, ); } else { error = new TransactionRevertInstructionError>( - reason.reason, - reason.signature, + _reason.reason, + _reason.signature, transactionReceiptFormatted, - reason.data, + _reason.data, ); } diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index 26a0e1a4d77..11fd0ca4ded 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -15,6 +15,10 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +// TODO Seems to be an issue with linter falsely reporting this +// error for Transaction Error Scenarios tests +/* eslint-disable jest/no-conditional-expect */ + import { Address, Bytes, SignedTransactionInfoAPI, Transaction } from 'web3-types'; import { DEFAULT_RETURN_FORMAT, FMT_BYTES, FMT_NUMBER, format, hexToNumber } from 'web3-utils'; import { isHexStrict } from 'web3-validator'; @@ -312,7 +316,7 @@ describe('Web3Eth.sendSignedTransaction', () => { ).contractAddress as Address; }); - it('Should throw InvalidResponseError because gas too low', async () => { + it('Should throw TransactionRevertInstructionError because gas too low', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', @@ -327,16 +331,18 @@ describe('Web3Eth.sendSignedTransaction', () => { }); const expectedThrownError = { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), + name: 'TransactionRevertInstructionError', + innerError: undefined, + reason: + getSystemTestBackend() === 'geth' + ? expect.stringContaining( + 'err: max fee per gas less than block base fee: address 0x', + ) + : 'VM Exception while processing transaction: out of gas', + signature: undefined, + receipt: undefined, data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendRawTransaction', - params: [expect.any(String)], - }, + code: 402, }; await expect( @@ -351,27 +357,40 @@ describe('Web3Eth.sendSignedTransaction', () => { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), - gasPrice: 1, gas: 21000, nonce: await web3Eth.getTransactionCount(tempAcc.address), }; + transaction.gasPrice = await web3Eth.getGasPrice(); const signedTransaction = await web3Eth.signTransaction(transaction, { number: FMT_NUMBER.BIGINT, bytes: FMT_BYTES.BUFFER, }); - const expectedThrownError = { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendRawTransaction', - params: [expect.any(String)], - }, - }; + const expectedThrownError = + getSystemTestBackend() === 'geth' + ? { + name: 'TransactionRevertInstructionError', + innerError: undefined, + reason: expect.stringContaining( + 'err: insufficient funds for gas * price + value: address 0x', + ), + signature: undefined, + receipt: undefined, + data: undefined, + code: 402, + } + : { + name: 'InvalidResponseError', + code: 101, + innerError: expect.any(Object), + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendRawTransaction', + params: [expect.any(String)], + }, + }; await expect( web3Eth @@ -405,19 +424,7 @@ describe('Web3Eth.sendSignedTransaction', () => { : 'VM Exception while processing transaction: revert This is a send revert', signature: '0x08c379a0', data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -454,19 +461,7 @@ describe('Web3Eth.sendSignedTransaction', () => { customErrorName: 'ErrorWithNoParams', customErrorDecodedSignature: 'ErrorWithNoParams()', customErrorArguments: {}, - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21222), - gasUsed: BigInt(21222), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -509,19 +504,7 @@ describe('Web3Eth.sendSignedTransaction', () => { code: BigInt(42), message: 'This is an error with params', }, - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21730), - gasUsed: BigInt(21730), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -533,7 +516,7 @@ describe('Web3Eth.sendSignedTransaction', () => { ).rejects.toMatchObject(expectedThrownError); }); - it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { + it('Should throw TransactionRevertInstructionError because of contract revert', async () => { const transaction: Transaction = { from: tempAcc.address, to: simpleRevertContractAddress, @@ -550,21 +533,16 @@ describe('Web3Eth.sendSignedTransaction', () => { web3Eth.handleRevert = false; const expectedThrownError = { - name: 'TransactionRevertedWithoutReasonError', - code: 405, - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + name: 'TransactionRevertInstructionError', + innerError: undefined, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted: This is a send revert' + : 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + receipt: undefined, + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + code: 402, }; await expect( diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index e905bc3a8ba..507f0449551 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -379,7 +379,7 @@ describe('Web3Eth.sendTransaction', () => { ).contractAddress as Address; }); - it('Should throw InvalidResponseError because gas too low', async () => { + it('Should throw TransactionRevertInstructionError because gas too low', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', @@ -388,26 +388,12 @@ describe('Web3Eth.sendTransaction', () => { }; const expectedThrownError = { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: tempAcc.address, - gas: '0x1', - gasPrice: expect.any(String), - maxFeePerGas: undefined, - maxPriorityFeePerGas: undefined, - to: '0x0000000000000000000000000000000000000000', - value: '0x1', - }, - ], - }, + name: 'TransactionRevertInstructionError', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? 'err: intrinsic gas too low: have 1, want 21000 (supplied gas 1)' + : 'VM Exception while processing transaction: out of gas', }; await expect( @@ -417,66 +403,49 @@ describe('Web3Eth.sendTransaction', () => { ).rejects.toMatchObject(expectedThrownError); }); - it('Should throw InvalidResponseError because insufficient funds', async () => { + it('Should throw TransactionRevertInstructionError because insufficient funds', async () => { const transaction: Transaction = { from: tempAcc.address, to: '0x0000000000000000000000000000000000000000', value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - const expectedThrownError = { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: tempAcc.address, - gasPrice: expect.any(String), - maxFeePerGas: undefined, - maxPriorityFeePerGas: undefined, - to: '0x0000000000000000000000000000000000000000', - value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', - }, - ], - }, - }; - - await expect( - web3Eth - .sendTransaction(transaction) - .on('error', error => expect(error).toMatchObject(expectedThrownError)), - ).rejects.toMatchObject(expectedThrownError); - }); - - it('Should throw InvalidResponseError because of unknown account', async () => { - const transaction: Transaction = { - from: '0x0000000000000000000000000000000000000000', - to: '0x0000000000000000000000000000000000000000', - }; - - const expectedThrownError = { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: '0x0000000000000000000000000000000000000000', - to: '0x0000000000000000000000000000000000000000', - gasPrice: expect.any(String), - }, - ], - }, - }; + const expectedThrownError = + getSystemTestBackend() === 'geth' + ? { + name: 'TransactionRevertInstructionError', + code: 402, + reason: expect.stringContaining( + 'err: insufficient funds for gas * price + value: address', + ), + } + : { + name: 'InvalidResponseError', + innerError: { + message: 'insufficient funds for gas * price + value', + stack: + 'Error: insufficient funds for gas * price + value\n' + + ' at TransactionPool.prepareTransaction (/app/dist/node/1.js:2:167260)', + code: -32003, + }, + code: 101, + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', + gasPrice: '0x77359400', + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }, + ], + }, + }; await expect( web3Eth @@ -503,22 +472,7 @@ describe('Web3Eth.sendTransaction', () => { : 'VM Exception while processing transaction: revert This is a send revert', signature: '0x08c379a0', data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -548,22 +502,7 @@ describe('Web3Eth.sendTransaction', () => { customErrorName: 'ErrorWithNoParams', customErrorDecodedSignature: 'ErrorWithNoParams()', customErrorArguments: {}, - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21222), - gasUsed: BigInt(21222), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -597,22 +536,7 @@ describe('Web3Eth.sendTransaction', () => { code: BigInt(42), message: 'This is an error with params', }, - receipt: - getSystemTestBackend() === 'geth' - ? undefined - : { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(21730), - gasUsed: BigInt(21730), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, + receipt: undefined, }; await expect( @@ -622,7 +546,7 @@ describe('Web3Eth.sendTransaction', () => { ).rejects.toMatchObject(expectedThrownError); }); - it('Should throw TransactionRevertedWithoutReasonError because of contract revert', async () => { + it('Should throw TransactionRevertInstructionError because of contract revert', async () => { const transaction: Transaction = { from: tempAcc.address, to: simpleRevertContractAddress, @@ -631,34 +555,16 @@ describe('Web3Eth.sendTransaction', () => { web3Eth.handleRevert = false; - const expectedThrownError = - getSystemTestBackend() === 'geth' - ? { - name: 'ContractExecutionError', - code: 310, - innerError: { - name: 'Eip838ExecutionError', - code: 3, - data: '0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', - }, - } - : { - name: 'TransactionRevertedWithoutReasonError', - code: 405, - receipt: { - transactionIndex: BigInt(0), - from: tempAcc.address, - to: simpleRevertContractAddress, - cumulativeGasUsed: BigInt(23605), - gasUsed: BigInt(23605), - logs: [], - logsBloom: - '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', - status: BigInt(0), - effectiveGasPrice: BigInt(2000000000), - type: BigInt(0), - }, - }; + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? 'execution reverted: This is a send revert' + : 'VM Exception while processing transaction: revert This is a send revert', + signature: '0x08c379a0', + data: '000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000155468697320697320612073656e64207265766572740000000000000000000000', + }; await expect( web3Eth From f4f43f8ef68c36c78a0eda22a481e8271a519496 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 17:38:42 -1000 Subject: [PATCH 54/67] Update web3-plugin-example test to account for getRevertReason check --- .../test/unit/contract_method_wrappers.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts b/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts index 84732bb2b7d..80f6aa4f002 100644 --- a/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts +++ b/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts @@ -84,6 +84,8 @@ describe('CustomRpcMethodsPlugin Tests', () => { requestManagerSendSpy.mockResolvedValueOnce(expectedGasPrice); // Mocking block number for trySendTransaction call requestManagerSendSpy.mockResolvedValueOnce('0x1'); + // Mocking getRevertReason response + requestManagerSendSpy.mockResolvedValueOnce(undefined); requestManagerSendSpy.mockResolvedValueOnce(expectedTransactionHash); // Mocking response for getTransactionReceipt for waitForTransactionReceipt requestManagerSendSpy.mockResolvedValueOnce({}); From d72206cd4b03ae9ee3d48f005cf7567700ecf441 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 18:32:42 -1000 Subject: [PATCH 55/67] Turn off checkRevertBeforeSending for sendFewTxes helper --- packages/web3-eth/test/integration/helper.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/web3-eth/test/integration/helper.ts b/packages/web3-eth/test/integration/helper.ts index c4ca69f1585..77243cc4826 100644 --- a/packages/web3-eth/test/integration/helper.ts +++ b/packages/web3-eth/test/integration/helper.ts @@ -47,11 +47,15 @@ export const sendFewTxes = async ({ const tx: Web3PromiEvent< TransactionReceipt, SendTransactionEvents - > = web3Eth.sendTransaction({ - to, - value, - from, - }); + > = web3Eth.sendTransaction( + { + to, + value, + from, + }, + DEFAULT_RETURN_FORMAT, + { checkRevertBeforeSending: false }, + ); res.push( // eslint-disable-next-line no-await-in-loop (await new Promise((resolve: Resolve, reject) => { From 2b816bf9ec7bc6396e77a468ad5c807b2be07c22 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 21:28:36 -1000 Subject: [PATCH 56/67] Fix test data for send_signed_transaction tests --- .../fixtures/send_signed_transaction.ts | 29 +++++-------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/send_signed_transaction.ts b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/send_signed_transaction.ts index 0a4656be696..c08cbea7efc 100644 --- a/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/send_signed_transaction.ts +++ b/packages/web3-eth/test/unit/rpc_method_wrappers/fixtures/send_signed_transaction.ts @@ -15,6 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ import { Bytes, TransactionReceipt } from 'web3-types'; +import { hexToBytes } from 'web3-utils'; export const expectedTransactionHash = '0xe21194c9509beb01be7e90c2bcefff2804cd85836ae12134f22ad4acda0fc547'; @@ -23,8 +24,8 @@ export const expectedTransactionReceipt: TransactionReceipt = { transactionIndex: '0x41', blockHash: '0x1d59ff54b1eb26b013ce3cb5fc9dab3705b415a67127a003c3e61eb445bb8df2', blockNumber: '0x5daf3b', - from: '0xa7d9ddbe1f17865597fbd27ec712455208b6b76d', - to: '0xf02c1c8e6114b1dbe8937a39260b5b0a374432bb', + from: '0x7ed0e85b8e1e925600b4373e6d108f34ab38a401', + to: '0x0000000000000000000000000000000000000000', cumulativeGasUsed: '0x33bc', // 13244 effectiveGasPrice: '0x13a21bc946', // 84324108614 gasUsed: '0x4dc', // 1244 @@ -41,24 +42,10 @@ export const expectedTransactionReceipt: TransactionReceipt = { * - Input parameters: * - signedTransaction */ +const signedTransaction = + '0xf8650f8415aa14088252089400000000000000000000000000000000000000000180820a95a0e6d6bc9c7af306733eb44b2a8a4a4efed5db2fbff947e21521fe81dfb144a00aa01a8a87c872f59564abbbe60e9d4e54dee5e1f1647477ab170ecd7e2704d3c94d'; export const testData: [string, Bytes][] = [ - [ - 'signedTransaction = HexString', - '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', - ], - [ - 'signedTransaction = Buffer', - Buffer.from( - '0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675', - ), - ], - [ - 'signedTransaction = Uint8Array', - new Uint8Array([ - 30, 78, 64, 34, 36, 65, 38, 64, 64, 36, 37, 63, 35, 64, 33, 32, 62, 65, 38, 64, 34, 36, - 65, 38, 64, 64, 36, 37, 63, 35, 64, 33, 32, 62, 65, 38, 30, 35, 38, 62, 62, 38, 65, 62, - 39, 37, 30, 38, 37, 30, 66, 30, 37, 32, 34, 34, 35, 36, 37, 35, 30, 35, 38, 62, 62, 38, - 65, 62, 39, 37, 30, 38, 37, 30, 66, 30, 37, 32, 34, 34, 35, 36, 37, 35, - ]), - ], + ['signedTransaction = HexString', signedTransaction], + ['signedTransaction = Buffer', hexToBytes(signedTransaction)], + ['signedTransaction = Uint8Array', new Uint8Array(hexToBytes(signedTransaction))], ]; From c4180b606668654b8498cc656048ff00915cc304 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 21:29:32 -1000 Subject: [PATCH 57/67] Fix bug in get_transaction_error --- packages/web3-eth/src/utils/get_transaction_error.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/web3-eth/src/utils/get_transaction_error.ts b/packages/web3-eth/src/utils/get_transaction_error.ts index 51249be6735..2623ec53845 100644 --- a/packages/web3-eth/src/utils/get_transaction_error.ts +++ b/packages/web3-eth/src/utils/get_transaction_error.ts @@ -65,7 +65,7 @@ export async function getTransactionError( (_reason as RevertReasonWithCustomError).customErrorArguments !== undefined ) { const reasonWithCustomError: RevertReasonWithCustomError = - knownReason as RevertReasonWithCustomError; + _reason as RevertReasonWithCustomError; error = new TransactionRevertWithCustomError>( reasonWithCustomError.reason, reasonWithCustomError.customErrorName, From 306b65077a01512677c0e65a971897eb94ba7d9f Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 21:35:33 -1000 Subject: [PATCH 58/67] Fix send_transaction error test --- .../web3_eth/send_transaction.test.ts | 44 ++++--------------- 1 file changed, 9 insertions(+), 35 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 507f0449551..6db7e1fa6ef 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -410,42 +410,16 @@ describe('Web3Eth.sendTransaction', () => { value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - const expectedThrownError = - getSystemTestBackend() === 'geth' - ? { - name: 'TransactionRevertInstructionError', - code: 402, - reason: expect.stringContaining( + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? expect.stringContaining( 'err: insufficient funds for gas * price + value: address', - ), - } - : { - name: 'InvalidResponseError', - innerError: { - message: 'insufficient funds for gas * price + value', - stack: - 'Error: insufficient funds for gas * price + value\n' + - ' at TransactionPool.prepareTransaction (/app/dist/node/1.js:2:167260)', - code: -32003, - }, - code: 101, - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: tempAcc.address, - to: '0x0000000000000000000000000000000000000000', - value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', - gasPrice: '0x77359400', - maxPriorityFeePerGas: undefined, - maxFeePerGas: undefined, - }, - ], - }, - }; + ) + : 'VM Exception while processing transaction: insufficient balance', + }; await expect( web3Eth From 76ee3da50c65186dae16a51c134a03cfb38d8a57 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 22:01:03 -1000 Subject: [PATCH 59/67] Add checkRevertBeforeSending: false to sendTransaction calls in Contract class --- packages/web3-eth-contract/src/contract.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/web3-eth-contract/src/contract.ts b/packages/web3-eth-contract/src/contract.ts index 098575137e4..bca93dd7c2e 100644 --- a/packages/web3-eth-contract/src/contract.ts +++ b/packages/web3-eth-contract/src/contract.ts @@ -1050,7 +1050,10 @@ export class Contract options, contractOptions: modifiedContractOptions, }); - const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT); + const transactionToSend = sendTransaction(this, tx, DEFAULT_RETURN_FORMAT, { + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, + }); // eslint-disable-next-line no-void void transactionToSend.on('error', (error: unknown) => { @@ -1094,6 +1097,8 @@ export class Contract newContract.options.address = receipt.contractAddress; return newContract; }, + // TODO Should make this configurable by the user + checkRevertBeforeSending: false, }); } From bcffc9f61ad114c2f97ef9dd44f08b6a55cc12e7 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Mon, 6 Mar 2023 22:01:28 -1000 Subject: [PATCH 60/67] Add checkRevertBeforeSending: false for send tx test helpers --- scripts/system_tests_utils.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/system_tests_utils.ts b/scripts/system_tests_utils.ts index a4e95111d3c..a1da5816e67 100644 --- a/scripts/system_tests_utils.ts +++ b/scripts/system_tests_utils.ts @@ -343,7 +343,9 @@ export const signTxAndSendEIP1559 = async ( gas: tx.gas ?? '1000000', from: acc.address, }); - return web3.eth.sendSignedTransaction(signedTx.rawTransaction); + return web3.eth.sendSignedTransaction(signedTx.rawTransaction, undefined, { + checkRevertBeforeSending: false, + }); }; export const signTxAndSendEIP2930 = async ( @@ -359,7 +361,9 @@ export const signTxAndSendEIP2930 = async ( gas: tx.gas ?? '1000000', from: acc.address, }); - return web3.eth.sendSignedTransaction(signedTx.rawTransaction); + return web3.eth.sendSignedTransaction(signedTx.rawTransaction, undefined, { + checkRevertBeforeSending: false, + }); }; export const signAndSendContractMethodEIP1559 = async ( From 2828b41da20c6755dee4704dce0a4b5d84471a4c Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 7 Mar 2023 21:14:09 -1000 Subject: [PATCH 61/67] Remove getRevertReason mock --- .../test/unit/contract_method_wrappers.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts b/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts index 80f6aa4f002..84732bb2b7d 100644 --- a/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts +++ b/tools/web3-plugin-example/test/unit/contract_method_wrappers.test.ts @@ -84,8 +84,6 @@ describe('CustomRpcMethodsPlugin Tests', () => { requestManagerSendSpy.mockResolvedValueOnce(expectedGasPrice); // Mocking block number for trySendTransaction call requestManagerSendSpy.mockResolvedValueOnce('0x1'); - // Mocking getRevertReason response - requestManagerSendSpy.mockResolvedValueOnce(undefined); requestManagerSendSpy.mockResolvedValueOnce(expectedTransactionHash); // Mocking response for getTransactionReceipt for waitForTransactionReceipt requestManagerSendSpy.mockResolvedValueOnce({}); From 5838adfa1be1491b421757746c3e90582b625e50 Mon Sep 17 00:00:00 2001 From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Tue, 7 Mar 2023 17:36:55 +0100 Subject: [PATCH 62/67] A fix at `IpcProvider` and few changes at `SocketProvider` and its descendants (#5891) * rename `_providerOptions` to `_socketOptions` * pass `_socketOptions` from IpcProvider constructor to the underlying connection * move a comment to its correct position at `SocketProvider` * expose the getter of `SocketConnection` from `SocketProvider`. * update CHANGELOG.md files * add extremely simple unit test for SocketProvider --- packages/web3-providers-ipc/CHANGELOG.md | 2 + packages/web3-providers-ipc/src/index.ts | 8 ++- .../test/unit/ipc_provider.test.ts | 2 + packages/web3-providers-ws/CHANGELOG.md | 1 + packages/web3-providers-ws/src/index.ts | 6 +- .../test/unit/web_socket_provider.test.ts | 1 + packages/web3-utils/CHANGELOG.md | 1 + packages/web3-utils/src/socket_provider.ts | 14 ++-- .../test/unit/socket_provider.test.ts | 66 +++++++++++++++++++ 9 files changed, 91 insertions(+), 10 deletions(-) create mode 100644 packages/web3-utils/test/unit/socket_provider.test.ts diff --git a/packages/web3-providers-ipc/CHANGELOG.md b/packages/web3-providers-ipc/CHANGELOG.md index 23f92719a8a..1139852a19d 100644 --- a/packages/web3-providers-ipc/CHANGELOG.md +++ b/packages/web3-providers-ipc/CHANGELOG.md @@ -71,3 +71,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added named export for `IpcProvider` (#5771) +- Pass `_socketOptions` from `IpcProvider` constructor to the underlying `Socket` (#5891) +- The getter of `SocketConnection` in `IpcProvider` (inherited from `SocketProvider`) returns `net.Socket` (#5891) diff --git a/packages/web3-providers-ipc/src/index.ts b/packages/web3-providers-ipc/src/index.ts index 7b4d8cae1f7..abe5571c75d 100644 --- a/packages/web3-providers-ipc/src/index.ts +++ b/packages/web3-providers-ipc/src/index.ts @@ -15,7 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { Socket } from 'net'; +import { Socket, SocketConstructorOpts } from 'net'; import { ConnectionNotOpenError, InvalidClientError } from 'web3-errors'; import { SocketProvider } from 'web3-utils'; import { @@ -33,7 +33,8 @@ export default class IpcProvider exte Error, API > { - // Message handlers. Due to bounding of `this` and removing the listeners we have to keep it's reference. + protected readonly _socketOptions?: SocketConstructorOpts; + protected _socketConnection?: Socket; public getStatus(): Web3ProviderStatus { @@ -42,12 +43,13 @@ export default class IpcProvider exte } return this._connectionStatus; } + protected _openSocketConnection() { if (!existsSync(this._socketPath)) { throw new InvalidClientError(this._socketPath); } if (!this._socketConnection || this.getStatus() === 'disconnected') { - this._socketConnection = new Socket(); + this._socketConnection = new Socket(this._socketOptions); } this._socketConnection.connect({ path: this._socketPath }); diff --git a/packages/web3-providers-ipc/test/unit/ipc_provider.test.ts b/packages/web3-providers-ipc/test/unit/ipc_provider.test.ts index 822effbda1d..d765ac80238 100644 --- a/packages/web3-providers-ipc/test/unit/ipc_provider.test.ts +++ b/packages/web3-providers-ipc/test/unit/ipc_provider.test.ts @@ -15,6 +15,7 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ +import { Socket } from 'net'; import * as fs from 'fs'; import { ConnectionError, InvalidClientError } from 'web3-errors'; import IpcProvider from '../../src/index'; @@ -34,6 +35,7 @@ describe('IpcProvider', () => { it('should construct the instance of the provider', () => { const provider = new IpcProvider(socketPath); expect(provider).toBeInstanceOf(IpcProvider); + expect(provider.SocketConnection).toBeInstanceOf(Socket); }); it('should try to connect', () => { diff --git a/packages/web3-providers-ws/CHANGELOG.md b/packages/web3-providers-ws/CHANGELOG.md index 26dc1df74dc..694cd70b573 100644 --- a/packages/web3-providers-ws/CHANGELOG.md +++ b/packages/web3-providers-ws/CHANGELOG.md @@ -65,3 +65,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Added named export for `WebSocketProvider` (#5771) +- The getter of `SocketConnection` in `WebSocketProvider` (inherited from `SocketProvider`) returns isomorphic `WebSocket` (#5891) diff --git a/packages/web3-providers-ws/src/index.ts b/packages/web3-providers-ws/src/index.ts index e5352aba929..28d45d54c5f 100644 --- a/packages/web3-providers-ws/src/index.ts +++ b/packages/web3-providers-ws/src/index.ts @@ -34,7 +34,7 @@ export { ClientOptions } from 'isomorphic-ws'; export default class WebSocketProvider< API extends Web3APISpec = EthExecutionAPI, > extends SocketProvider { - protected readonly _providerOptions?: ClientOptions | ClientRequestArgs; + protected readonly _socketOptions?: ClientOptions | ClientRequestArgs; protected _socketConnection?: WebSocket; @@ -64,9 +64,9 @@ export default class WebSocketProvider< this._socketConnection = new WebSocket( this._socketPath, undefined, - this._providerOptions && Object.keys(this._providerOptions).length === 0 + this._socketOptions && Object.keys(this._socketOptions).length === 0 ? undefined - : this._providerOptions, + : this._socketOptions, ); } diff --git a/packages/web3-providers-ws/test/unit/web_socket_provider.test.ts b/packages/web3-providers-ws/test/unit/web_socket_provider.test.ts index eac7053e111..433f01c2ad7 100644 --- a/packages/web3-providers-ws/test/unit/web_socket_provider.test.ts +++ b/packages/web3-providers-ws/test/unit/web_socket_provider.test.ts @@ -57,6 +57,7 @@ describe('WebSocketProvider', () => { expect(wsProvider.connect).toBeDefined(); expect(wsProvider.disconnect).toBeDefined(); expect(wsProvider.reset).toBeDefined(); + expect(wsProvider.SocketConnection).toBeInstanceOf(WebSocket); }); it('should allow for providerOptions to be passed upon instantiation', () => { diff --git a/packages/web3-utils/CHANGELOG.md b/packages/web3-utils/CHANGELOG.md index d4b5aea1b98..adca4e6eca8 100644 --- a/packages/web3-utils/CHANGELOG.md +++ b/packages/web3-utils/CHANGELOG.md @@ -87,3 +87,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `compareBlockNumbers` function now only supports comparison of both blocktags params ( except `earliest` vs number) or both block number params (#5842) - `SocketProvider` abstract class now resolves JSON RPC response errors instead of rejecting them (#5844) +- Exposes the getter of `SocketConnection` in `SocketProvider` (#5891) diff --git a/packages/web3-utils/src/socket_provider.ts b/packages/web3-utils/src/socket_provider.ts index 827228c549b..762a5d83ad8 100644 --- a/packages/web3-utils/src/socket_provider.ts +++ b/packages/web3-utils/src/socket_provider.ts @@ -71,9 +71,12 @@ export abstract class SocketProvider< /* eslint-disable @typescript-eslint/no-explicit-any */ protected readonly _sentRequestsQueue: Map>; protected _reconnectAttempts!: number; - protected readonly _providerOptions?: object; + protected readonly _socketOptions?: object; protected readonly _reconnectOptions: ReconnectOptions; protected _socketConnection?: unknown; + public get SocketConnection() { + return this._socketConnection; + } protected _connectionStatus: Web3ProviderStatus; protected readonly _onMessageHandler: (event: MessageEvent) => void; protected readonly _onOpenHandler: () => void; @@ -83,20 +86,23 @@ export abstract class SocketProvider< /** * This is an abstract class for implementing a socket provider (e.g. WebSocket, IPC). It extends the EIP-1193 provider {@link EIP1193Provider}. * @param socketPath - The path to the socket (e.g. /ipc/path or ws://localhost:8546) - * @param options - The options for the socket connection + * @param socketOptions - The options for the socket connection * @param reconnectOptions - The options for the socket reconnection {@link ReconnectOptions} */ - public constructor(socketPath: string, options?: object, reconnectOptions?: object) { + public constructor(socketPath: string, socketOptions?: object, reconnectOptions?: object) { super(); this._connectionStatus = 'connecting'; + + // Message handlers. Due to bounding of `this` and removing the listeners we have to keep it's reference. this._onMessageHandler = this._onMessage.bind(this); this._onOpenHandler = this._onConnect.bind(this); this._onCloseHandler = this._onCloseEvent.bind(this); this._onErrorHandler = this._onError.bind(this); + if (!this._validateProviderPath(socketPath)) throw new InvalidClientError(socketPath); this._socketPath = socketPath; - this._providerOptions = options; + this._socketOptions = socketOptions; const DEFAULT_PROVIDER_RECONNECTION_OPTIONS = { autoReconnect: true, diff --git a/packages/web3-utils/test/unit/socket_provider.test.ts b/packages/web3-utils/test/unit/socket_provider.test.ts new file mode 100644 index 00000000000..593a75e1667 --- /dev/null +++ b/packages/web3-utils/test/unit/socket_provider.test.ts @@ -0,0 +1,66 @@ +/* +This file is part of web3.js. + +web3.js is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +web3.js is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License +along with web3.js. If not, see . +*/ + +import { Web3APIPayload, EthExecutionAPI, JsonRpcResponse, Web3ProviderStatus } from 'web3-types'; +import { SocketProvider } from '../../src/socket_provider'; + +const dummySocketConnection = { dummy: 'dummy' }; + +class TestProvider extends SocketProvider { + protected _socketConnection?: typeof dummySocketConnection; + + protected _openSocketConnection() { + this._socketConnection = dummySocketConnection; + } + + // Dummy implementation of the abstract base methods + // eslint-disable-next-line + protected _addSocketListeners(): void {} + // eslint-disable-next-line + protected _removeSocketListeners(): void {} + // eslint-disable-next-line + protected _onCloseEvent(_event: unknown): void {} + // eslint-disable-next-line + protected _sendToSocket(_payload: Web3APIPayload): void {} + // eslint-disable-next-line + protected _parseResponses(_event: any): JsonRpcResponse[] { + return [] as JsonRpcResponse[]; + } + // eslint-disable-next-line + protected _closeSocketConnection( + _code?: number | undefined, + _data?: string | undefined, + // eslint-disable-next-line + ): void {} + // eslint-disable-next-line + getStatus(): Web3ProviderStatus { + return 'connected'; + } +} + +describe('SocketProvider', () => { + const socketPath = `some_path`; + const socketOption = { dummyOption: true } as const; + + describe('constructor', () => { + it('should construct the instance of the provider', () => { + const provider = new TestProvider(socketPath, socketOption); + expect(provider).toBeInstanceOf(SocketProvider); + expect(provider.SocketConnection).toEqual(dummySocketConnection); + }); + }); +}); From e79e59f919ff081ab628a22d68d1ed9fd51c98a5 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Tue, 7 Mar 2023 22:05:37 -1000 Subject: [PATCH 63/67] Fix failed tx test for ganache --- .../web3_eth/send_transaction.test.ts | 49 ++++++++++++++----- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 6db7e1fa6ef..7f2922a7f11 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -410,21 +410,46 @@ describe('Web3Eth.sendTransaction', () => { value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - const expectedThrownError = { - name: 'TransactionRevertInstructionError', - code: 402, - reason: - getSystemTestBackend() === 'geth' - ? expect.stringContaining( + const expectedThrownError = + getSystemTestBackend() === 'geth' + ? { + name: 'TransactionRevertInstructionError', + code: 402, + reason: expect.stringContaining( 'err: insufficient funds for gas * price + value: address', - ) - : 'VM Exception while processing transaction: insufficient balance', - }; + ), + } + : { + name: 'InvalidResponseError', + code: 101, + innerError: { + message: 'insufficient funds for gas * price + value', + stack: expect.stringContaining( + 'Error: insufficient funds for gas * price + value', + ), + code: -32003, + }, + data: undefined, + request: { + jsonrpc: '2.0', + id: expect.any(String), + method: 'eth_sendTransaction', + params: [ + { + from: tempAcc.address, + to: '0x0000000000000000000000000000000000000000', + value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', + gasPrice: expect.stringContaining('0x'), + maxPriorityFeePerGas: undefined, + maxFeePerGas: undefined, + }, + ], + }, + }; await expect( - web3Eth - .sendTransaction(transaction) - .on('error', error => expect(error).toMatchObject(expectedThrownError)), + web3Eth.sendTransaction(transaction), + // .on('error', error => expect(error).toMatchObject(expectedThrownError)), ).rejects.toMatchObject(expectedThrownError); }); From a2175ff7f31eae6509bbd1a04ed4f4513edccef9 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 8 Mar 2023 14:50:47 -1000 Subject: [PATCH 64/67] Update expected transaction errors for ganache --- .../web3_eth/send_signed_transaction.test.ts | 38 ++++++-------- .../web3_eth/send_transaction.test.ts | 50 +++++-------------- 2 files changed, 27 insertions(+), 61 deletions(-) diff --git a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts index 11fd0ca4ded..685ec8842bf 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_signed_transaction.test.ts @@ -366,31 +366,21 @@ describe('Web3Eth.sendSignedTransaction', () => { bytes: FMT_BYTES.BUFFER, }); - const expectedThrownError = - getSystemTestBackend() === 'geth' - ? { - name: 'TransactionRevertInstructionError', - innerError: undefined, - reason: expect.stringContaining( + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + message: 'Transaction has been reverted by the EVM', + innerError: undefined, + reason: + getSystemTestBackend() === 'geth' + ? expect.stringContaining( 'err: insufficient funds for gas * price + value: address 0x', - ), - signature: undefined, - receipt: undefined, - data: undefined, - code: 402, - } - : { - name: 'InvalidResponseError', - code: 101, - innerError: expect.any(Object), - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendRawTransaction', - params: [expect.any(String)], - }, - }; + ) + : 'VM Exception while processing transaction: insufficient balance', + signature: undefined, + receipt: undefined, + data: undefined, + code: 402, + }; await expect( web3Eth diff --git a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts index 7f2922a7f11..896010aa2e5 100644 --- a/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts +++ b/packages/web3-eth/test/integration/web3_eth/send_transaction.test.ts @@ -410,46 +410,22 @@ describe('Web3Eth.sendTransaction', () => { value: BigInt('999999999999999999999999999999999999999999999999999999999'), }; - const expectedThrownError = - getSystemTestBackend() === 'geth' - ? { - name: 'TransactionRevertInstructionError', - code: 402, - reason: expect.stringContaining( + const expectedThrownError = { + name: 'TransactionRevertInstructionError', + message: 'Transaction has been reverted by the EVM', + code: 402, + reason: + getSystemTestBackend() === 'geth' + ? expect.stringContaining( 'err: insufficient funds for gas * price + value: address', - ), - } - : { - name: 'InvalidResponseError', - code: 101, - innerError: { - message: 'insufficient funds for gas * price + value', - stack: expect.stringContaining( - 'Error: insufficient funds for gas * price + value', - ), - code: -32003, - }, - data: undefined, - request: { - jsonrpc: '2.0', - id: expect.any(String), - method: 'eth_sendTransaction', - params: [ - { - from: tempAcc.address, - to: '0x0000000000000000000000000000000000000000', - value: '0x28c87cb5c89a2571ebfdcb54864ada8349ffffffffffffff', - gasPrice: expect.stringContaining('0x'), - maxPriorityFeePerGas: undefined, - maxFeePerGas: undefined, - }, - ], - }, - }; + ) + : 'VM Exception while processing transaction: insufficient balance', + }; await expect( - web3Eth.sendTransaction(transaction), - // .on('error', error => expect(error).toMatchObject(expectedThrownError)), + web3Eth + .sendTransaction(transaction) + .on('error', error => expect(error).toMatchObject(expectedThrownError)), ).rejects.toMatchObject(expectedThrownError); }); From 5cbb9bfc7f6200128e2fb643fd8bfbc8e7429bb7 Mon Sep 17 00:00:00 2001 From: Oleksii Kosynskyi Date: Wed, 8 Mar 2023 12:11:50 -0500 Subject: [PATCH 65/67] Fix method handler crashed (#5905) * version fix * use geth binary * try 1.11.2 --- scripts/geth.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/geth.sh b/scripts/geth.sh index df7731a57d6..f27a6a58547 100755 --- a/scripts/geth.sh +++ b/scripts/geth.sh @@ -12,12 +12,12 @@ start() { if [ -z "${ORIGARGS[1]}" ] then echo "Starting geth..." - echo "docker run -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:stable --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev" - docker run -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:stable --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev + echo "docker run -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:v1.11.2 --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev" + docker run -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:v1.11.2 --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev else echo "Starting geth..." - echo "docker run -d -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:stable --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev" - docker run -d -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:stable --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev + echo "docker run -d -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:v1.11.2 --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev" + docker run -d -p $WEB3_SYSTEM_TEST_PORT:$WEB3_SYSTEM_TEST_PORT ethereum/client-go:v1.11.2 --nodiscover --nousb --ws --ws.addr 0.0.0.0 --ws.port $WEB3_SYSTEM_TEST_PORT --http --http.addr 0.0.0.0 --http.port $WEB3_SYSTEM_TEST_PORT --allow-insecure-unlock --http.api personal,web3,eth,admin,debug,txpool,net --ws.api personal,web3,eth,admin,debug,miner,txpool,net --dev echo "Waiting for geth..." npx wait-port -t 10000 "$WEB3_SYSTEM_TEST_PORT" echo "Geth started" From e267663f1f5a80898adce57121eee5ccb4945911 Mon Sep 17 00:00:00 2001 From: Wyatt Barnes Date: Wed, 8 Mar 2023 15:34:07 -1000 Subject: [PATCH 66/67] Test fix --- .../test/integration/contract_defaults_extra.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts b/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts index da5bbf143e8..676d86b0de1 100644 --- a/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts +++ b/packages/web3-eth-contract/test/integration/contract_defaults_extra.test.ts @@ -186,6 +186,7 @@ describe('contract defaults (extra)', () => { }), expect.any(Object), expect.any(Object), + expect.any(Object), ); }); From 2662eafce1374bc2ce9c0e41d9e82d6246b1600f Mon Sep 17 00:00:00 2001 From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Thu, 9 Mar 2023 16:57:52 +0100 Subject: [PATCH 67/67] Use `v1` instead of Short Sha for cloudflare/pages-action (#5909) * use `v1` instead of short Sha for cloudflare/pages-action --- .github/workflows/deploy-docs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-docs.yaml b/.github/workflows/deploy-docs.yaml index adcc4053bc3..b766fb7e4a9 100644 --- a/.github/workflows/deploy-docs.yaml +++ b/.github/workflows/deploy-docs.yaml @@ -19,7 +19,7 @@ jobs: - run: yarn install --frozen-lockfile - run: yarn run build:docs - name: Publish to Cloudflare Pages - uses: cloudflare/pages-action@1 + uses: cloudflare/pages-action@v1 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: 2238a825c5aca59233eab1f221f7aefb