Skip to content
This repository was archived by the owner on Mar 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
bfa0831
draft implementation and test for 838 error codes
Muhammad-Altabba Sep 13, 2022
b6a7fdc
use BigInt when returning the encoded function parameters
Muhammad-Altabba Sep 13, 2022
d2ace26
modify ens integration test to use bigint for numbers
Muhammad-Altabba Sep 13, 2022
c564e5b
modify web3-eth-contract integration test to use bigint for numbers
Muhammad-Altabba Sep 14, 2022
4dbd149
modify ens integration test to use bigint for numbers
Muhammad-Altabba Sep 14, 2022
b0de20c
Handle jest issue dealing with BigInt at web3-eth-abi unit tests
Muhammad-Altabba Sep 14, 2022
bb610f3
Add optional innerError to Web3Error class
Muhammad-Altabba Sep 14, 2022
39b916d
Handle jest issue dealing with BigInt at web3-eth-contract integratio…
Muhammad-Altabba Sep 14, 2022
65fdb3d
Merge branch '4.x' into feature/4235/eip-838-error-codes
Muhammad-Altabba Sep 14, 2022
2c26ab3
Merge branch 'fix/5431/use-BigInt-when-returning-the-encoded-function…
Muhammad-Altabba Sep 14, 2022
262196e
Merge branch 'feature/4235/eip-838-error-codes' of https://github.com…
Muhammad-Altabba Sep 14, 2022
2bc40a4
Merge branch '4.x' into feature/4235/eip-838-error-codes
Muhammad-Altabba Sep 16, 2022
d15d63f
few refactoring, commenting and code cleaning for code related to EIP…
Muhammad-Altabba Sep 16, 2022
e082ef3
Merge branch '4.x' into feature/4235/eip-838-error-codes
Muhammad-Altabba Sep 18, 2022
ccd20f6
refactor and clean some code related to EIP-838
Muhammad-Altabba Sep 19, 2022
45bb0b7
update CHANGELOG.md files
Muhammad-Altabba Sep 19, 2022
6ce6c7c
Add MRs numbers to CHANGELOG.md
Muhammad-Altabba Sep 19, 2022
714fb4b
Merge branch '4.x' into feature/4235/eip-838-error-codes
Muhammad-Altabba Sep 20, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -736,17 +736,31 @@ should use 4.0.1-alpha.0 for testing.

### Added

#### web3-core

- If the response error was `execution reverted`, raise `ContractExecutionError` and pass the response error to it in order to be set as `innerError` (this innerError will be decoded at web3-eth-contract if its ABI was provided according to EIP-838). (#5434)

#### web3-error

- Add optional `innerError` property to the abstract class `Web3Error`.
- Add optional `innerError` property to the abstract class `Web3Error`. This `innerError` could be `Error`, `Error[]` or `undefined`. (#5435) (#5434)
- The class `Web3ContractError` is moved to this package from `web3-eth-contract`. (#5434)

#### web3-eth-abi

- If an error happens when decoding a value, preserve that exception at `innerError` inside the error class `AbiError`. (#5435)
- Add basic functionality that is used, by `web3-eth-contract`, when decoding error data according to EIP-838. (#5434)

#### web3-eth-contract

- Decoding error data, using Error ABI if available, according to EIP-838. (#5434)
- The class `Web3ContractError` is moved from this package to `web3-error`. (#5434)

### Fixed

#### web3-eth-contract

- According to the latest change in `web3-eth-abi`, the decoded values of the large numbers, returned from function calls or events, are now available as `BigInt`.
- According to the latest change in `web3-eth-abi`, the decoded values of the large numbers, returned from function calls or events, are now available as `BigInt`. (#5435)

#### web3-eth-abi

- Return `BigInt` instead of `string` when decoding function parameters for large numbers, such as `uint256`.
- If an error happens when decoding a value, preserve that exception at `innerError` inside the `AbiError`.
- Return `BigInt` instead of `string` when decoding function parameters for large numbers, such as `uint256`. (#5435)
6 changes: 6 additions & 0 deletions packages/web3-core/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- I've improved the security in XY (#1000)

-->

## [Unreleased]

### Added

- If the response error was `execution reverted`, raise `ContractExecutionError` and pass the response error to it in order to be set as `innerError` (this innerError will be decoded at web3-eth-contract if its ABI was provided according to EIP-838). (#5434)
19 changes: 17 additions & 2 deletions packages/web3-core/src/web3_request_manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

import { Socket } from 'net';
import { InvalidResponseError, ProviderError, ResponseError } from 'web3-errors';
import {
ContractExecutionError,
InvalidResponseError,
ProviderError,
ResponseError,
} from 'web3-errors';
import HttpProvider from 'web3-providers-http';
import IpcProvider from 'web3-providers-ipc';
import WSProvider from 'web3-providers-ws';
Expand All @@ -26,6 +31,7 @@ import {
JsonRpcBatchResponse,
JsonRpcPayload,
JsonRpcResponse,
JsonRpcResponseWithError,
SupportedProviders,
Web3APIMethod,
Web3APIPayload,
Expand Down Expand Up @@ -287,7 +293,16 @@ export class Web3RequestManager<
// This is the majority of the cases so check these first
// A valid JSON-RPC response with error object
if (jsonRpc.isResponseWithError<ErrorType>(response)) {
throw new InvalidResponseError<ErrorType>(response);
if (
(response.error as unknown as { message: string })?.message === 'execution reverted'
) {
// This message means that there was an error while executing the code of the smart contract
// However, more processing will happen at a higher level to decode the error data,
// according to the Error ABI, if it was available as of EIP-838.
throw new ContractExecutionError((response as JsonRpcResponseWithError).error);
} else {
throw new InvalidResponseError<ErrorType>(response);
}
}

// This is the majority of the cases so check these first
Expand Down
3 changes: 2 additions & 1 deletion packages/web3-errors/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,5 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add optional `innerError` property to the abstract class `Web3Error`.
- Add optional `innerError` property to the abstract class `Web3Error`. This `innerError` could be `Error`, `Error[]` or `undefined`. (#5435) (#5434)
- The class `Web3ContractError` is moved to this package from `web3-eth-contract`. (#5434)
2 changes: 2 additions & 0 deletions packages/web3-errors/src/error_codes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const ERR_CONTRACT_MISSING_DEPLOY_DATA = 306;
export const ERR_CONTRACT_MISSING_ADDRESS = 307;
export const ERR_CONTRACT_MISSING_FROM_ADDRESS = 308;
export const ERR_CONTRACT_INSTANTIATION = 309;
export const ERR_CONTRACT_EXECUTION_REVERTED = 310;

// Transaction error codes
export const ERR_TX = 400;
Expand Down Expand Up @@ -75,6 +76,7 @@ export const ERR_TX_LOCAL_WALLET_NOT_AVAILABLE = 429;

export const ERR_TX_NOT_FOUND = 430;
export const ERR_TX_SEND_TIMEOUT = 431;

// Connection error codes
export const ERR_CONN = 500;
export const ERR_CONN_INVALID = 501;
Expand Down
61 changes: 61 additions & 0 deletions packages/web3-errors/src/errors/contract_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.

/* eslint-disable max-classes-per-file */

import { JsonRpcError, TransactionReceipt, HexString } from 'web3-types';
import {
ERR_CONTRACT,
ERR_CONTRACT_ABI_MISSING,
ERR_CONTRACT_EXECUTION_REVERTED,
ERR_CONTRACT_EVENT_NOT_EXISTS,
ERR_CONTRACT_INSTANTIATION,
ERR_CONTRACT_MISSING_ADDRESS,
Expand All @@ -30,6 +33,16 @@ import {
} from '../error_codes';
import { Web3Error } from '../web3_error_base';

export class Web3ContractError extends Web3Error {
public code = ERR_CONTRACT;
public receipt?: TransactionReceipt;

public constructor(message: string, receipt?: TransactionReceipt) {
super(message);

this.receipt = receipt;
}
}
export class ResolverMethodMissingError extends Web3Error {
public code = ERR_CONTRACT_RESOLVER_MISSING;

Expand Down Expand Up @@ -111,3 +124,51 @@ export class ContractNoFromAddressDefinedError extends Web3Error {
export class ContractInstantiationError extends Web3Error {
public code = ERR_CONTRACT_INSTANTIATION;
}

/**
* This class is expected to be set as an `innerError` inside ContractExecutionError
* The properties would be typically decoded from the `data` if it was encoded according to EIP-838
*/
export class Eip838ExecutionError extends Web3ContractError {
public readonly name: string;
public code: number;
public data?: HexString;
public errorName?: string;
public errorSignature?: string;
public errorArgs?: { [K in string]: unknown };

public constructor(code: number, message: string, data?: HexString) {
super(message);
this.name = this.constructor.name;
this.code = code;
this.data = data;
}

public setDecodedProperties(
errorName: string,
errorSignature?: string,
errorArgs?: { [K in string]: unknown },
) {
this.errorName = errorName;
this.errorSignature = errorSignature;
this.errorArgs = errorArgs;
}
}

/**
* Used when an error is raised while executing a function inside a smart contract.
* The data is expected to be encoded according to EIP-848.
*/
export class ContractExecutionError extends Web3ContractError {
public innerError: 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.code,
rpcError.message,
rpcError.data as string,
);
}
}
14 changes: 10 additions & 4 deletions packages/web3-errors/src/errors/response_errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

// eslint-disable-next-line max-classes-per-file
import { JsonRpcResponse, JsonRpcResponseWithError } from 'web3-types';
import { JsonRpcError, JsonRpcResponse, JsonRpcResponseWithError } from 'web3-types';
import { Web3Error } from '../web3_error_base';
import { ERR_INVALID_RESPONSE, ERR_RESPONSE } from '../error_codes';

Expand Down Expand Up @@ -65,9 +65,15 @@ export class ResponseError<ErrorType = unknown> extends Web3Error {
export class InvalidResponseError<ErrorType = unknown> extends ResponseError<ErrorType> {
public constructor(result: JsonRpcResponse<unknown, ErrorType>) {
super(result);
if (!this.message || this.message === '') {
this.message = `Invalid JSON RPC response: ${JSON.stringify(result)}`;
}
this.code = ERR_INVALID_RESPONSE;

let errorOrErrors: JsonRpcError | JsonRpcError[] | undefined;
if (`error` in result) {
errorOrErrors = result.error as JsonRpcError;
} else if (result instanceof Array) {
errorOrErrors = result.map(r => r.error) as JsonRpcError[];
}

this.innerError = errorOrErrors as Error | Error[] | undefined;
}
}
4 changes: 2 additions & 2 deletions packages/web3-errors/src/web3_error_base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ export abstract class Web3Error extends Error implements ErrorInterface {
public readonly name: string;
public abstract readonly code: number;
public stack: string | undefined;
public innerError: Error | undefined;
public innerError: Error | Error[] | undefined;

public constructor(msg?: string, innerError?: Error) {
public constructor(msg?: string, innerError?: Error | Error[]) {
super(msg);
this.innerError = innerError;
this.name = this.constructor.name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,14 @@ Object {
"a": "10",
"b": "20",
},
"innerError": undefined,
"innerError": Object {
"code": 123,
"data": Object {
"a": "10",
"b": "20",
},
"message": "error message",
},
"message": "Returned error: error message",
"name": "InvalidResponseError",
}
Expand Down
10 changes: 7 additions & 3 deletions packages/web3-eth-abi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

#### web3-eth-abi
### Added

- If an error happens when decoding a value, preserve that exception at `innerError` inside the error class `AbiError`. (#5435)
- Add basic functionality that is used, by `web3-eth-contract`, when decoding error data according to EIP-838. (#5434)

### Fixed

- Return `BigInt` instead of `string` when decoding function parameters for large numbers, such as `uint256`.
- If an error happens when decoding a value, preserve that exception at `innerError` inside the `AbiError`.
- Return `BigInt` instead of `string` when decoding function parameters for large numbers, such as `uint256`. (#5435)
40 changes: 40 additions & 0 deletions packages/web3-eth-abi/src/api/errors_api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
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 <http://www.gnu.org/licenses/>.
*/

import { sha3Raw } from 'web3-utils';
import { AbiError } from 'web3-errors';
import { AbiErrorFragment } from '../types';
import { jsonInterfaceMethodToString, isAbiErrorFragment } from '../utils';

/**
* Encodes the error name to its ABI signature, which are the sha3 hash of the error name including input types.
*/
export const encodeErrorSignature = (functionName: string | AbiErrorFragment): string => {
if (typeof functionName !== 'string' && !isAbiErrorFragment(functionName)) {
throw new AbiError('Invalid parameter value in encodeErrorSignature');
}

let name: string;

if (functionName && (typeof functionName === 'function' || typeof functionName === 'object')) {
name = jsonInterfaceMethodToString(functionName);
} else {
name = functionName;
}

return sha3Raw(name);
};
1 change: 1 addition & 0 deletions packages/web3-eth-abi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ along with web3.js. If not, see <http://www.gnu.org/licenses/>.
*/

export * from './types';
export * from './api/errors_api';
export * from './api/events_api';
export * from './api/functions_api';
export * from './api/logs_api';
Expand Down
8 changes: 8 additions & 0 deletions packages/web3-eth-abi/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,19 @@ export type AbiEventFragment = AbiBaseFragment & {
readonly anonymous?: boolean;
};

// https://docs.soliditylang.org/en/latest/abi-spec.html#errors
export type AbiErrorFragment = AbiBaseFragment & {
readonly name: string;
readonly type: string | 'error';
readonly inputs?: ReadonlyArray<AbiParameter>;
};

// https://docs.soliditylang.org/en/latest/abi-spec.html#json
export type AbiFragment =
| AbiConstructorFragment
| AbiFunctionFragment
| AbiEventFragment
| AbiErrorFragment
| AbiFallbackFragment;

export type ContractAbi = ReadonlyArray<AbiFragment>;
Expand Down
10 changes: 8 additions & 2 deletions packages/web3-eth-abi/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@ export const isAbiFragment = (item: unknown): item is AbiFragment =>
!isNullish(item) &&
typeof item === 'object' &&
!isNullish((item as { type: string }).type) &&
['function', 'event', 'constructor'].includes((item as { type: string }).type);
['function', 'event', 'constructor', 'error'].includes((item as { type: string }).type);

export const isAbiErrorFragment = (item: unknown): item is AbiEventFragment =>
!isNullish(item) &&
typeof item === 'object' &&
!isNullish((item as { type: string }).type) &&
(item as { type: string }).type === 'error';

export const isAbiEventFragment = (item: unknown): item is AbiEventFragment =>
!isNullish(item) &&
Expand Down Expand Up @@ -278,7 +284,7 @@ export const flattenTypes = (
* returns a string
*/
export const jsonInterfaceMethodToString = (json: AbiFragment): string => {
if (isAbiEventFragment(json) || isAbiFunctionFragment(json)) {
if (isAbiErrorFragment(json) || isAbiEventFragment(json) || isAbiFunctionFragment(json)) {
if (json.name?.includes('(')) {
return json.name;
}
Expand Down
7 changes: 6 additions & 1 deletion packages/web3-eth-contract/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ const transactionHash = receipt.transactionHash;

## [Unreleased]

### Added

- Decoding error data, using Error ABI if available, according to EIP-838. (#5434)
- The class `Web3ContractError` is moved from this package to `web3-error`. (#5434)

### Fixed

- According to the latest change in `web3-eth-abi`, the decoded values of the large numbers, returned from function calls or events, are now available as `BigInt`.
- According to the latest change in `web3-eth-abi`, the decoded values of the large numbers, returned from function calls or events, are now available as `BigInt`. (#5435)
Loading