Skip to content

Commit

Permalink
Use cause instead of innerError (#6631)
Browse files Browse the repository at this point in the history
* use cause and deprecate innerError

* fix linting errors

* update test snapshots

* remove cyclic dependencies to same file

* fix issue with collecting response errors

* fix linting issues

* rename and format some files

* add unit test for BaseWeb3Error
  • Loading branch information
Muhammad-Altabba authored Dec 5, 2023
1 parent 5afcb54 commit cdd99e7
Show file tree
Hide file tree
Showing 26 changed files with 265 additions and 112 deletions.
2 changes: 1 addition & 1 deletion docs/docs/guides/basics/sign_and_send_tx/promi_event.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ web3.eth.sendTransaction({...})
// at Generator.next (<anonymous>)
// at fulfilled (.../web3_request_manager.js:5:58)
// at processTicksAndRejections (node:internal/process/task_queues:96:5) {
// innerError: { code: -32000, message: 'exceeds block gas limit' },
// cause: { code: -32000, message: 'exceeds block gas limit' },
// code: 101,
// data: undefined,
// request: {
Expand Down
55 changes: 29 additions & 26 deletions packages/web3-core/src/web3_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class Web3Context<
| Web3ContextInitOptions<API, RegisteredSubs>,
) {
super();

// If "providerOrContext" is provided as "string" or an objects matching "SupportedProviders" interface
if (
isNullish(providerOrContext) ||
Expand Down Expand Up @@ -364,7 +364,7 @@ export class Web3Context<

/**
* This method allows extending the web3 modules.
* Note: This method is only for backward compatibility, and It is recommended to use Web3 v4 Plugin feature for extending web3.js functionality if you are developing some thing new.
* Note: This method is only for backward compatibility, and It is recommended to use Web3 v4 Plugin feature for extending web3.js functionality if you are developing something new.
*/
public extend(extendObj: ExtensionObject) {
// @ts-expect-error No index signature with a parameter of type 'string' was found on type 'Web3Context<API, RegisteredSubs>'
Expand Down Expand Up @@ -407,36 +407,39 @@ export class Web3Context<
* class CustomPlugin extends Web3PluginBase<CustomRpcApi> {...}
* ```
*/
export abstract class Web3PluginBase<
API extends Web3APISpec = Web3APISpec,
export abstract class Web3PluginBase<
API extends Web3APISpec = Web3APISpec,
> extends Web3Context<API> {
public abstract pluginNamespace: string;
public abstract pluginNamespace: string;

// eslint-disable-next-line class-methods-use-this
protected registerNewTransactionType<NewTxTypeClass extends typeof BaseTransaction<unknown>>(type: Numbers, txClass: NewTxTypeClass): void {
TransactionFactory.registerTransactionType(type, txClass);
}
// eslint-disable-next-line class-methods-use-this
protected registerNewTransactionType<NewTxTypeClass extends typeof BaseTransaction<unknown>>(
type: Numbers,
txClass: NewTxTypeClass,
): void {
TransactionFactory.registerTransactionType(type, txClass);
}
}

/**
* Extend this class when creating a plugin that makes use of {@link EthExecutionAPI},
* or depends on other Web3 packages (such as `web3-eth-contract`) that depend on {@link EthExecutionAPI}.
*
* To add type support for RPC methods to the {@link Web3RequestManager} (in addition to {@link EthExecutionAPI}),
* define a {@link Web3APISpec} and pass it as a generic to Web3PluginBase like so:
*
* @example
* ```ts
* type CustomRpcApi = {
* custom_rpc_method: () => string;
* custom_rpc_method_with_parameters: (parameter1: string, parameter2: number) => string;
* };
*
* class CustomPlugin extends Web3PluginBase<CustomRpcApi> {...}
* ```
*/
* Extend this class when creating a plugin that makes use of {@link EthExecutionAPI},
* or depends on other Web3 packages (such as `web3-eth-contract`) that depend on {@link EthExecutionAPI}.
*
* To add type support for RPC methods to the {@link Web3RequestManager} (in addition to {@link EthExecutionAPI}),
* define a {@link Web3APISpec} and pass it as a generic to Web3PluginBase like so:
*
* @example
* ```ts
* type CustomRpcApi = {
* custom_rpc_method: () => string;
* custom_rpc_method_with_parameters: (parameter1: string, parameter2: number) => string;
* };
*
* class CustomPlugin extends Web3PluginBase<CustomRpcApi> {...}
* ```
*/
export abstract class Web3EthPluginBase<API extends Web3APISpec = unknown> extends Web3PluginBase<
API & EthExecutionAPI
API & EthExecutionAPI
> {}

// To avoid cycle dependency declare this type in this file
Expand Down
2 changes: 1 addition & 1 deletion packages/web3-core/test/unit/web3_request_manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -688,7 +688,7 @@ describe('Web3RequestManager', () => {
err = error;
} finally {
expect(err).toBeInstanceOf(ResponseError);
expect(err.innerError).toEqual(rpcErrorResponse.error);
expect(err.cause).toEqual(rpcErrorResponse.error);
}
});
});
Expand Down
1 change: 1 addition & 0 deletions packages/web3-errors/src/error_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const ERR_OPERATION_ABORT = 204;
export const ERR_ABI_ENCODING = 205;
export const ERR_EXISTING_PLUGIN_NAMESPACE = 206;
export const ERR_INVALID_METHOD_PARAMS = 207;
export const ERR_MULTIPLE_ERRORS = 208;

// Contract error codes
export const ERR_CONTRACT = 300;
Expand Down
15 changes: 7 additions & 8 deletions packages/web3-errors/src/errors/contract_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export type ProviderErrorData =
| { originalError: { data: HexString } };

/**
* This class is expected to be set as an `innerError` inside ContractExecutionError
* This class is expected to be set as an `cause` inside ContractExecutionError
* The properties would be typically decoded from the `data` if it was encoded according to EIP-838
*/
export class Eip838ExecutionError extends Web3ContractError {
Expand All @@ -144,7 +144,7 @@ export class Eip838ExecutionError extends Web3ContractError {
public errorArgs?: { [K in string]: unknown };

// eslint-disable-next-line no-use-before-define
public innerError: Eip838ExecutionError | undefined;
public cause: Eip838ExecutionError | undefined;

public constructor(error: JsonRpcError<ProviderErrorData> | Eip838ExecutionError) {
super(error.message || 'Error');
Expand All @@ -166,9 +166,7 @@ export class Eip838ExecutionError extends Web3ContractError {
originalError = error.data;
}
this.data = originalError.data;
this.innerError = new Eip838ExecutionError(
originalError as JsonRpcError<ProviderErrorData>,
);
this.cause = new Eip838ExecutionError(originalError as JsonRpcError<ProviderErrorData>);
} else {
this.data = error.data;
}
Expand All @@ -192,7 +190,8 @@ export class Eip838ExecutionError extends Web3ContractError {
name: string;
code: number;
message: string;
innerError: Error | Error[] | undefined;
innerError: Eip838ExecutionError | undefined;
cause: Eip838ExecutionError | undefined;
data: string;
errorName?: string;
errorSignature?: string;
Expand All @@ -216,12 +215,12 @@ export class Eip838ExecutionError extends Web3ContractError {
* The data is expected to be encoded according to EIP-848.
*/
export class ContractExecutionError extends Web3ContractError {
public innerError: Eip838ExecutionError;
public cause: Eip838ExecutionError;

public constructor(rpcError: JsonRpcError) {
super('Error happened while trying to execute a function inside a smart contract');
this.code = ERR_CONTRACT_EXECUTION_REVERTED;
this.innerError = new Eip838ExecutionError(rpcError as JsonRpcError<ProviderErrorData>);
this.cause = new Eip838ExecutionError(rpcError as JsonRpcError<ProviderErrorData>);
}
}

Expand Down
19 changes: 13 additions & 6 deletions packages/web3-errors/src/errors/response_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
JsonRpcResponse,
JsonRpcResponseWithError,
} from 'web3-types';
import { BaseWeb3Error } from '../web3_error_base.js';
import { BaseWeb3Error, MultipleErrors } from '../web3_error_base.js';
import { ERR_INVALID_RESPONSE, ERR_RESPONSE } from '../error_codes.js';

// To avoid circular package dependency, copied to code here. If you update this please update same function in `json_rpc.ts`
Expand Down Expand Up @@ -71,10 +71,14 @@ export class ResponseError<ErrorType = unknown, RequestType = unknown> extends B
if (`error` in response) {
errorOrErrors = response.error as JsonRpcError;
} else if (response instanceof Array) {
errorOrErrors = response.map(r => r.error) as JsonRpcError[];
errorOrErrors = response.filter(r => r.error).map(r => r.error) as JsonRpcError[];
}

this.innerError = errorOrErrors as Error | Error[] | undefined;
if (Array.isArray(errorOrErrors) && errorOrErrors.length > 0) {
this.cause = new MultipleErrors(errorOrErrors as unknown as Error[]);
} else {
this.cause = errorOrErrors as Error | undefined;
}
}

public toJSON() {
Expand All @@ -98,7 +102,10 @@ export class InvalidResponseError<ErrorType = unknown, RequestType = unknown> ex
} else if (result instanceof Array) {
errorOrErrors = result.map(r => r.error) as JsonRpcError[];
}

this.innerError = errorOrErrors as Error | Error[] | undefined;
if (Array.isArray(errorOrErrors)) {
this.cause = new MultipleErrors(errorOrErrors as unknown as Error[]);
} else {
this.cause = errorOrErrors as Error | undefined;
}
}
}
}
4 changes: 2 additions & 2 deletions packages/web3-errors/src/errors/transaction_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ export class MissingGasError extends InvalidValueError {
}`,
'"gas" is missing',
);
this.innerError = new MissingGasInnerError();
this.cause = new MissingGasInnerError();
}
}

Expand Down Expand Up @@ -372,7 +372,7 @@ export class TransactionGasMismatchError extends InvalidValueError {
}`,
'transaction must specify legacy or fee market gas properties, not both',
);
this.innerError = new TransactionGasMismatchInnerError();
this.cause = new TransactionGasMismatchInnerError();
}
}

Expand Down
54 changes: 50 additions & 4 deletions packages/web3-errors/src/web3_error_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,50 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
/* eslint-disable max-classes-per-file */

import { Web3Error } from 'web3-types';
import { ERR_MULTIPLE_ERRORS } from './error_codes.js';

/**
* Base class for Web3 errors.
*/
export abstract class BaseWeb3Error extends Error implements Web3Error {
public readonly name: string;
public abstract readonly code: number;
public stack: string | undefined;
public innerError: Error | Error[] | undefined;

public constructor(msg?: string, innerError?: Error | Error[]) {
public cause: Error | undefined;

/**
* @deprecated Use the `cause` property instead.
*/
public get innerError(): Error | Error[] | undefined {
// eslint-disable-next-line no-use-before-define
if (this.cause instanceof MultipleErrors) {
return this.cause.errors;
}
return this.cause;
}
/**
* @deprecated Use the `cause` property instead.
*/
public set innerError(cause: Error | Error[] | undefined) {
if (Array.isArray(cause)) {
// eslint-disable-next-line no-use-before-define
this.cause = new MultipleErrors(cause);
} else {
this.cause = cause;
}
}

public constructor(msg?: string, cause?: Error | Error[]) {
super(msg);
this.innerError = innerError;

if (Array.isArray(cause)) {
// eslint-disable-next-line no-use-before-define
this.cause = new MultipleErrors(cause);
} else {
this.cause = cause;
}

this.name = this.constructor.name;

if (typeof Error.captureStackTrace === 'function') {
Expand Down Expand Up @@ -57,11 +91,23 @@ export abstract class BaseWeb3Error extends Error implements Web3Error {
name: this.name,
code: this.code,
message: this.message,
innerError: this.innerError,
cause: this.cause,
// deprecated
innerError: this.cause,
};
}
}

export class MultipleErrors extends BaseWeb3Error {
public code = ERR_MULTIPLE_ERRORS;
public errors: Error[];

public constructor(errors: Error[]) {
super(`Multiple errors occurred: [${errors.map(e => e.message).join('], [')}]`);
this.errors = errors;
}
}

export abstract class InvalidValueError extends BaseWeb3Error {
public readonly name: string;

Expand Down
Loading

0 comments on commit cdd99e7

Please sign in to comment.