diff --git a/packages/web3-eth-abi/CHANGELOG.md b/packages/web3-eth-abi/CHANGELOG.md index be586bd83d1..3237aba303e 100644 --- a/packages/web3-eth-abi/CHANGELOG.md +++ b/packages/web3-eth-abi/CHANGELOG.md @@ -89,3 +89,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `decodeErrorData` from `web3-eth-contract` is now exported from this package and was renamed to `decodeContractErrorData` (#5844) ## [Unreleased] + +### Removed + +- Removed `formatDecodedObject` function (#5934) diff --git a/packages/web3-eth-abi/src/api/parameters_api.ts b/packages/web3-eth-abi/src/api/parameters_api.ts index 5a36afee006..2b34c925e9d 100644 --- a/packages/web3-eth-abi/src/api/parameters_api.ts +++ b/packages/web3-eth-abi/src/api/parameters_api.ts @@ -21,33 +21,6 @@ import { HexString, AbiInput, DecodedParams } from 'web3-types'; import ethersAbiCoder from '../ethers_abi_coder'; import { formatParam, isAbiFragment, mapTypes, modifyParams } from '../utils'; -/** - * Helper function to format the decoded object - */ -const formatDecodedObject = ( - abi: { [key: string]: unknown }, - input: { [key: string]: unknown }, -): { [key: string]: unknown } => { - let index = 0; - const res: { [key: string]: unknown } = {}; - for (const j of Object.keys(abi)) { - if (typeof abi[j] === 'string') { - res[j] = input[j]; - res[index] = input[j]; - } - if (typeof abi[j] === 'object') { - res[j] = formatDecodedObject( - abi[j] as { [key: string]: unknown }, - input[j] as { [key: string]: unknown }, - ); - res[index] = res[j]; - } - index += 1; - } - - return res; -}; - /** * Encodes a parameter based on its type to its ABI representation. * @param abi - An array of {@link AbiInput}. See [Solidity's documentation](https://solidity.readthedocs.io/en/v0.5.3/abi-spec.html#json) for more details. diff --git a/packages/web3-eth-abi/test/fixtures/data.ts b/packages/web3-eth-abi/test/fixtures/data.ts index a018b1c0f1e..b2710922177 100644 --- a/packages/web3-eth-abi/test/fixtures/data.ts +++ b/packages/web3-eth-abi/test/fixtures/data.ts @@ -289,6 +289,35 @@ export const invalidEventsSignatures: { input: any; output: string }[] = [ { input: undefined, output: 'Invalid parameter value in encodeEventSignature' }, ]; +export const validErrorsSignatures: { input: any; output: string }[] = [ + { + input: 'Unauthorized()', + output: '0x82b4290015f7ec7256ca2a6247d3c2a89c4865c0e791456df195f40ad0a81367', + }, + { + input: { + inputs: [{ internalType: 'string', name: '', type: 'string' }], + name: 'CustomError', + type: 'error', + }, + output: '0x8d6ea8bed4afafaebcad40e72174583b8bf4969c5d3bc84536051f3939bf9d81', + }, + { + input: 'Error(string)', + output: '0x08c379a0afcc32b1a39302f7cb8073359698411ab5fd6e3edb2c02c0b5fba8aa', + }, +]; + +export const invalidErrorSignatures: { input: any; output: string }[] = [ + { input: 345, output: 'Invalid parameter value in encodeErrorSignature' }, + { input: {}, output: 'Invalid parameter value in encodeErrorSignature' }, + { input: ['mystring'], output: 'Invalid parameter value in encodeErrorSignature' }, + // Using "null" value intentionally for validation + // eslint-disable-next-line no-null/no-null + { input: null, output: 'Invalid parameter value in encodeErrorSignature' }, + { input: undefined, output: 'Invalid parameter value in encodeErrorSignature' }, +]; + export const validDecodeLogsData: { input: { abi: any; data: any; topics: any }; output: Record; @@ -677,6 +706,13 @@ export const validEncodeParametersData: { ], output: '0x00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000ff', }, + { + input: [ + ['uint', 'tuple(uint256, string)'], + [1234, [5678, 'Hello World']], + ], + output: '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000162e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000', + }, ]; export const inValidEncodeParametersData: { @@ -900,3 +936,77 @@ export const inValidDecodeParametersData: { output: 'Parameter decoding error', }, ]; + +export const validDecodeContractErrorData: { + input: any[]; + output: any; +}[] = [ + { + input: [ + [ + { inputs: [], name: 'ErrorWithNoParams', type: 'error' }, + { + inputs: [ + { name: 'code', type: 'uint256' }, + { name: 'message', type: 'string' }, + ], + name: 'ErrorWithParams', + type: 'error', + }, + ], + { + code: 12, + message: 'message', + data: '0xc85bda60000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + }, + ], + output: { + errorName: 'ErrorWithParams', + errorSignature: 'ErrorWithParams(uint256,string)', + errorArgs: { + code: 42, + message: 'This is an error with params', + }, + }, + }, +]; + +export const invalidDecodeContractErrorData: { + input: any[]; +}[] = [ + { + input: [ + [ + { inputs: [], name: 'ErrorWithNoParams', type: 'error' }, + { + inputs: [ + { name: 'code', type: 'uint256' }, + { name: 'message', type: 'string' }, + ], + name: 'ErrorWithParams', + type: 'error', + }, + ], + { + code: 12, + message: 'message', + data: '0xc85bda60000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000123450000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c5468697320697320616e206572726f72207769746820706172616d7300000000', + }, + ], + }, +]; + +export const validIsAbiConstructorFragment: { + input: any; +}[] = [ + { + input: { inputs: [], stateMutability: 'nonpayable', type: 'constructor' }, + }, +]; +export const invalidIsAbiConstructorFragment: { + input: any; +}[] = [ + { + input: { inputs: [], stateMutability: 'nonpayable', type: 'function' }, + }, +]; diff --git a/packages/web3-eth-abi/test/unit/api/errors_api.test.ts b/packages/web3-eth-abi/test/unit/api/errors_api.test.ts new file mode 100644 index 00000000000..dae7ec783a5 --- /dev/null +++ b/packages/web3-eth-abi/test/unit/api/errors_api.test.ts @@ -0,0 +1,41 @@ +/* +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 { encodeErrorSignature } from '../../../src/api/errors_api'; +import { validErrorsSignatures, invalidErrorSignatures } from '../../fixtures/data'; + +describe('errors_api', () => { + describe('encodeErrorSignature', () => { + describe('valid data', () => { + it.each(validErrorsSignatures)( + 'should pass for valid values: %s', + ({ input, output }) => { + expect(encodeErrorSignature(input)).toEqual(output); + }, + ); + }); + + describe('invalid data', () => { + it.each(invalidErrorSignatures)( + 'should pass for valid values: %s', + ({ input, output }) => { + expect(() => encodeErrorSignature(input)).toThrow(output); + }, + ); + }); + }); +}); diff --git a/packages/web3-eth-abi/test/unit/api/events_api.test.ts b/packages/web3-eth-abi/test/unit/api/events_api.test.ts index c4ed4a4b5b6..f607e38c2d7 100644 --- a/packages/web3-eth-abi/test/unit/api/events_api.test.ts +++ b/packages/web3-eth-abi/test/unit/api/events_api.test.ts @@ -30,7 +30,7 @@ describe('events_api', () => { }); describe('invalid data', () => { it.each(invalidEventsSignatures)( - 'should pass for valid values: %s', + 'should fail for invalid values: %s', ({ input, output }) => { expect(() => encodeEventSignature(input)).toThrow(output); }, diff --git a/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts b/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts new file mode 100644 index 00000000000..eb3aff26739 --- /dev/null +++ b/packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts @@ -0,0 +1,60 @@ +/* +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 { Eip838ExecutionError } from 'web3-errors'; +import { decodeContractErrorData } from '../../src/decode_contract_error_data'; + +import { validDecodeContractErrorData, invalidDecodeContractErrorData } from '../fixtures/data'; + +describe('decodeContractErrorData', () => { + describe('valid data', () => { + it.each(validDecodeContractErrorData)( + '%#: should pass for valid values: %j', + ({ input: [abi, errorData], output }) => { + const err = new Eip838ExecutionError( + errorData.code, + errorData.message, + errorData.data, + ); + + decodeContractErrorData(abi, err); + + expect(err.errorName).toEqual(output.errorName); + expect(err.errorSignature).toEqual(output.errorSignature); + expect(err.errorArgs?.message).toEqual(output.errorArgs?.message); + expect(Number(err.errorArgs?.code)).toEqual(output.errorArgs?.code); + }, + ); + }); + + describe('invalid data', () => { + it.each(invalidDecodeContractErrorData)( + '%#: should throw for invalid values: %j', + ({ input: [abi, errorData] }) => { + // mock console.error + const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => 'error'); + const err = new Eip838ExecutionError( + errorData.code, + errorData.message, + errorData.data, + ); + decodeContractErrorData(abi, err); + expect(consoleSpy).toHaveBeenCalled(); + }, + ); + }); +}); diff --git a/packages/web3-eth-abi/test/unit/utils.test.ts b/packages/web3-eth-abi/test/unit/utils.test.ts index 8d78d12caba..548e1b6a78a 100644 --- a/packages/web3-eth-abi/test/unit/utils.test.ts +++ b/packages/web3-eth-abi/test/unit/utils.test.ts @@ -15,8 +15,13 @@ You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ -import { jsonInterfaceMethodToString } from '../../src/utils'; -import { jsonInterfaceInvalidData, jsonInterfaceValidData } from '../fixtures/data'; +import { jsonInterfaceMethodToString, isAbiConstructorFragment } from '../../src/utils'; +import { + jsonInterfaceInvalidData, + jsonInterfaceValidData, + validIsAbiConstructorFragment, + invalidIsAbiConstructorFragment, +} from '../fixtures/data'; describe('utils', () => { describe('jsonInterfaceMethodToString', () => { @@ -42,4 +47,17 @@ describe('utils', () => { }); }); }); + describe('isAbiConstructorFragment', () => { + describe('valid cases', () => { + it.each(validIsAbiConstructorFragment)('%s', ({ input }) => { + expect(isAbiConstructorFragment(input)).toBeTruthy(); + }); + }); + + describe('invalid cases', () => { + it.each(invalidIsAbiConstructorFragment)('%s', ({ input }) => { + expect(isAbiConstructorFragment(input)).toBeFalsy(); + }); + }); + }); }); diff --git a/packages/web3/test/shared_fixtures/data.ts b/packages/web3/test/shared_fixtures/data.ts index bab9890ce31..20f19bd5e80 100644 --- a/packages/web3/test/shared_fixtures/data.ts +++ b/packages/web3/test/shared_fixtures/data.ts @@ -27,4 +27,11 @@ export const validEncodeParametersData: { ], output: '0x000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000', }, + { + input: [ + ['uint', 'tuple(uint256, string)'], + [1234, [5678, 'Hello World']], + ], + output: '', + }, ];