From 311d5be84c11caa15c4dc5559bd9561c2f105418 Mon Sep 17 00:00:00 2001
From: Muhammad Altabba <24407834+Muhammad-Altabba@users.noreply.github.com>
Date: Fri, 16 Sep 2022 06:58:15 +0200
Subject: [PATCH] Use BigInt when decoding functions' and events' parameters
returned from Smart Contracts calls and events (#5435)
* Use BigInt when decoding functions' and events' parameters returned from Smart Contracts calls and events
* modify tests accordingly and Handle jest issues dealing with BigInt
* Add optional innerError to Web3Error class
* update CHANGELOG.md
---
CHANGELOG.md | 17 ++++++++
packages/web3-errors/CHANGELOG.md | 6 +++
packages/web3-errors/src/web3_error_base.ts | 11 ++++-
.../unit/__snapshots__/errors.test.ts.snap | 27 +++++++++++++
packages/web3-eth-abi/CHANGELOG.md | 9 +++++
.../web3-eth-abi/src/api/parameters_api.ts | 2 +-
packages/web3-eth-abi/src/ethers_abi_coder.ts | 15 +++----
packages/web3-eth-abi/test/fixtures/data.ts | 9 +++++
.../test/unit/api/logs_api.test.ts | 3 +-
.../test/unit/api/parameters_api.test.ts | 14 ++++---
packages/web3-eth-contract/CHANGELOG.md | 6 +++
.../test/integration/contract_erc20.test.ts | 13 +++---
.../test/integration/contract_erc721.test.ts | 2 +-
.../test/integration/contract_events.test.ts | 40 +++++++++----------
.../test/integration/contract_methods.test.ts | 2 +-
.../web3-eth-ens/test/integration/ens.test.ts | 6 +--
packages/web3-validator/src/errors.ts | 4 --
17 files changed, 129 insertions(+), 57 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 715a13e1b43..d63bb804723 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -733,3 +733,20 @@ should use 4.0.1-alpha.0 for testing.
- Dependency tree cannot be resolved by Yarn due to old deprecated packages picked by yarn - fixed (#5382)
## [Unreleased]
+
+### Added
+
+#### web3-error
+
+- Add optional `innerError` property to the abstract class `Web3Error`.
+
+### 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`.
+
+#### 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`.
diff --git a/packages/web3-errors/CHANGELOG.md b/packages/web3-errors/CHANGELOG.md
index dc93264a3e0..58dd54d066b 100644
--- a/packages/web3-errors/CHANGELOG.md
+++ b/packages/web3-errors/CHANGELOG.md
@@ -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
+
+- Add optional `innerError` property to the abstract class `Web3Error`.
diff --git a/packages/web3-errors/src/web3_error_base.ts b/packages/web3-errors/src/web3_error_base.ts
index 50c542ad267..eaaf87dc593 100644
--- a/packages/web3-errors/src/web3_error_base.ts
+++ b/packages/web3-errors/src/web3_error_base.ts
@@ -23,9 +23,11 @@ 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 constructor(msg?: string) {
+ public constructor(msg?: string, innerError?: Error) {
super(msg);
+ this.innerError = innerError;
this.name = this.constructor.name;
if (typeof Error.captureStackTrace === 'function') {
@@ -51,7 +53,12 @@ export abstract class Web3Error extends Error implements ErrorInterface {
}
public toJSON() {
- return { name: this.name, code: this.code, message: this.message };
+ return {
+ name: this.name,
+ code: this.code,
+ message: this.message,
+ innerError: this.innerError,
+ };
}
}
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 974cbc16369..f5de39c141a 100644
--- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap
+++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap
@@ -5,6 +5,7 @@ Object {
"code": 504,
"errorCode": 10,
"errorReason": "reason",
+ "innerError": undefined,
"message": "CONNECTION ERROR: The connection got closed with the close code 10 and the following reason string reason",
"name": "ConnectionCloseError",
}
@@ -15,6 +16,7 @@ Object {
"code": 500,
"errorCode": 10,
"errorReason": "reason",
+ "innerError": undefined,
"message": "error message",
"name": "ConnectionError",
}
@@ -25,6 +27,7 @@ Object {
"code": 503,
"errorCode": 10,
"errorReason": "reason",
+ "innerError": undefined,
"message": "Connection not open",
"name": "ConnectionNotOpenError",
}
@@ -36,6 +39,7 @@ Object {
"duration": 5000,
"errorCode": undefined,
"errorReason": undefined,
+ "innerError": undefined,
"message": "CONNECTION TIMEOUT: timeout of 5000ms achieved",
"name": "ConnectionTimeoutError",
}
@@ -44,6 +48,7 @@ Object {
exports[`errors ContractCodeNotStoredError should have valid json structure 1`] = `
Object {
"code": 404,
+ "innerError": undefined,
"message": "The contract code couldn't be stored, please check your gas limit.",
"name": "ContractCodeNotStoredError",
"receipt": Object {
@@ -56,6 +61,7 @@ exports[`errors ContractEventDoesNotExistError should have valid json structure
Object {
"code": 304,
"eventName": "eventName",
+ "innerError": undefined,
"message": "Event \\"eventName\\" doesn't exist in this contract.",
"name": "ContractEventDoesNotExistError",
}
@@ -64,6 +70,7 @@ Object {
exports[`errors ContractMissingABIError should have valid json structure 1`] = `
Object {
"code": 302,
+ "innerError": undefined,
"message": "You must provide the json interface of the contract when instantiating a contract object.",
"name": "ContractMissingABIError",
}
@@ -72,6 +79,7 @@ Object {
exports[`errors ContractMissingDeployDataError should have valid json structure 1`] = `
Object {
"code": 306,
+ "innerError": undefined,
"message": "No \\"data\\" specified in neither the given options, nor the default options.",
"name": "ContractMissingDeployDataError",
}
@@ -80,6 +88,7 @@ Object {
exports[`errors ContractNoAddressDefinedError should have valid json structure 1`] = `
Object {
"code": 307,
+ "innerError": undefined,
"message": "This contract object doesn't have address set yet, please set an address first.",
"name": "ContractNoAddressDefinedError",
}
@@ -88,6 +97,7 @@ Object {
exports[`errors ContractNoFromAddressDefinedError should have valid json structure 1`] = `
Object {
"code": 308,
+ "innerError": undefined,
"message": "No \\"from\\" address specified in neither the given options, nor the default options.",
"name": "ContractNoFromAddressDefinedError",
}
@@ -96,6 +106,7 @@ Object {
exports[`errors ContractOnceRequiresCallbackError should have valid json structure 1`] = `
Object {
"code": 303,
+ "innerError": undefined,
"message": "Once requires a callback as the second parameter.",
"name": "ContractOnceRequiresCallbackError",
}
@@ -104,6 +115,7 @@ Object {
exports[`errors ContractReservedEventError should have valid json structure 1`] = `
Object {
"code": 305,
+ "innerError": undefined,
"message": "Event \\"type\\" doesn't exist in this contract.",
"name": "ContractReservedEventError",
"type": "type",
@@ -116,6 +128,7 @@ Object {
"errorCode": 10,
"errorReason": "reason",
"host": "my host",
+ "innerError": undefined,
"message": "CONNECTION ERROR: Couldn't connect to node my host.",
"name": "InvalidConnectionError",
}
@@ -126,6 +139,7 @@ Object {
"code": 200,
"expected": 20,
"got": 10,
+ "innerError": undefined,
"message": "Invalid number of parameters for \\"method\\". Got \\"10\\" expected \\"20\\"!",
"method": "method",
"name": "InvalidNumberOfParamsError",
@@ -135,6 +149,7 @@ Object {
exports[`errors InvalidProviderError should have valid json structure 1`] = `
Object {
"code": 601,
+ "innerError": undefined,
"message": "Provider with url \\"my url\\" is not set or invalid",
"name": "InvalidProviderError",
}
@@ -147,6 +162,7 @@ Object {
"a": "10",
"b": "20",
},
+ "innerError": undefined,
"message": "Returned error: error message",
"name": "InvalidResponseError",
}
@@ -157,6 +173,7 @@ Object {
"code": 505,
"errorCode": undefined,
"errorReason": undefined,
+ "innerError": undefined,
"message": "Maximum number of reconnect attempts reached!",
"name": "MaxAttemptsReachedOnReconnectingError",
}
@@ -165,6 +182,7 @@ Object {
exports[`errors NoContractAddressFoundError should have valid json structure 1`] = `
Object {
"code": 403,
+ "innerError": undefined,
"message": "The transaction receipt didn't contain a contract address.",
"name": "NoContractAddressFoundError",
"receipt": Object {
@@ -178,6 +196,7 @@ Object {
"code": 506,
"errorCode": undefined,
"errorReason": undefined,
+ "innerError": undefined,
"message": "CONNECTION ERROR: Provider started to reconnect before the response got received!",
"name": "PendingRequestsOnReconnectingError",
}
@@ -187,6 +206,7 @@ exports[`errors ResolverMethodMissingError should have valid json structure 1`]
Object {
"address": "address",
"code": 301,
+ "innerError": undefined,
"message": "The resolver at address does not implement requested method: \\"name\\".",
"name": "name",
}
@@ -199,6 +219,7 @@ Object {
"a": "10",
"b": "20",
},
+ "innerError": undefined,
"message": "Returned error: error message",
"name": "ResponseError",
}
@@ -208,6 +229,7 @@ exports[`errors ResponseError should have valid json structure without data 1`]
Object {
"code": 100,
"data": undefined,
+ "innerError": undefined,
"message": "Returned error: error message",
"name": "ResponseError",
}
@@ -216,6 +238,7 @@ Object {
exports[`errors RevertInstructionError should have valid json structure 1`] = `
Object {
"code": 401,
+ "innerError": undefined,
"message": "Your request got reverted with the following reason string: message",
"name": "RevertInstructionError",
"reason": "message",
@@ -226,6 +249,7 @@ Object {
exports[`errors TransactionError should have valid json structure 1`] = `
Object {
"code": 400,
+ "innerError": undefined,
"message": "message",
"name": "TransactionError",
"receipt": Object {
@@ -237,6 +261,7 @@ Object {
exports[`errors TransactionOutOfGasError should have valid json structure 1`] = `
Object {
"code": 406,
+ "innerError": undefined,
"message": "Transaction ran out of gas. Please provide more gas:
{
\\"attr1\\": \\"attr1\\"
@@ -251,6 +276,7 @@ Object {
exports[`errors TransactionRevertError should have valid json structure 1`] = `
Object {
"code": 402,
+ "innerError": undefined,
"message": "Transaction has been reverted by the EVM:
{
\\"attr1\\": \\"attr1\\"
@@ -267,6 +293,7 @@ Object {
exports[`errors TransactionRevertedWithoutReasonError should have valid json structure 1`] = `
Object {
"code": 405,
+ "innerError": undefined,
"message": "Transaction has been reverted by the EVM:
{
\\"attr1\\": \\"attr1\\"
diff --git a/packages/web3-eth-abi/CHANGELOG.md b/packages/web3-eth-abi/CHANGELOG.md
index dc93264a3e0..7c2c0e3f978 100644
--- a/packages/web3-eth-abi/CHANGELOG.md
+++ b/packages/web3-eth-abi/CHANGELOG.md
@@ -34,3 +34,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- I've improved the security in XY (#1000)
-->
+
+## [Unreleased]
+
+### Fixed
+
+#### 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`.
diff --git a/packages/web3-eth-abi/src/api/parameters_api.ts b/packages/web3-eth-abi/src/api/parameters_api.ts
index 8223c0cd0e9..6cb3cc9aca4 100644
--- a/packages/web3-eth-abi/src/api/parameters_api.ts
+++ b/packages/web3-eth-abi/src/api/parameters_api.ts
@@ -83,7 +83,7 @@ export const encodeParameters = (abi: ReadonlyArray