Skip to content

Commit

Permalink
Nikos/5931/coverage web3 abi (#5934)
Browse files Browse the repository at this point in the history
* Fix type in Events test

* Add data and tests for encodeErrorSignature

* Decode contract errors test

* Delete unused function

* Add invalid data for decode contract erros

* Add tuple in data

* isAbiCostructor

* Update changelog
  • Loading branch information
nikoulai authored Mar 22, 2023
1 parent 5e469af commit 7a18c7e
Show file tree
Hide file tree
Showing 8 changed files with 243 additions and 30 deletions.
4 changes: 4 additions & 0 deletions packages/web3-eth-abi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
27 changes: 0 additions & 27 deletions packages/web3-eth-abi/src/api/parameters_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
110 changes: 110 additions & 0 deletions packages/web3-eth-abi/test/fixtures/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, unknown>;
Expand Down Expand Up @@ -677,6 +706,13 @@ export const validEncodeParametersData: {
],
output: '0x00000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000002a0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000002d000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000ff',
},
{
input: [
['uint', 'tuple(uint256, string)'],
[1234, [5678, 'Hello World']],
],
output: '0x00000000000000000000000000000000000000000000000000000000000004d20000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000162e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000b48656c6c6f20576f726c64000000000000000000000000000000000000000000',
},
];

export const inValidEncodeParametersData: {
Expand Down Expand Up @@ -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' },
},
];
41 changes: 41 additions & 0 deletions packages/web3-eth-abi/test/unit/api/errors_api.test.ts
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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);
},
);
});
});
});
2 changes: 1 addition & 1 deletion packages/web3-eth-abi/test/unit/api/events_api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
},
Expand Down
60 changes: 60 additions & 0 deletions packages/web3-eth-abi/test/unit/decodeContractErrorData.test.ts
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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();
},
);
});
});
22 changes: 20 additions & 2 deletions packages/web3-eth-abi/test/unit/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ 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 { 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', () => {
Expand All @@ -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();
});
});
});
});
7 changes: 7 additions & 0 deletions packages/web3/test/shared_fixtures/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@ export const validEncodeParametersData: {
],
output: '0x000000000000000000000000000000000000000000000000000000008bd02b7b0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000748656c6c6f212500000000000000000000000000000000000000000000000000',
},
{
input: [
['uint', 'tuple(uint256, string)'],
[1234, [5678, 'Hello World']],
],
output: '',
},
];

0 comments on commit 7a18c7e

Please sign in to comment.