Skip to content

Commit

Permalink
Fix validation of nested tuples (#6125)
Browse files Browse the repository at this point in the history
* fix nested

* fix tests

* skip in3

* fix

* fix validator import
  • Loading branch information
avkos committed May 30, 2023
1 parent 408332d commit 4f423fc
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 10 deletions.
20 changes: 14 additions & 6 deletions packages/web3-validator/src/utils.ts
Expand Up @@ -138,7 +138,7 @@ export const abiSchemaToJsonSchema = (
let abiName!: string;
let abiComponents: ShortValidationSchema | FullValidationSchema | undefined = [];

// If its a complete Abi Parameter
// If it's a complete Abi Parameter
// e.g. {name: 'a', type: 'uint'}
if (isAbiParameterSchema(abi)) {
abiType = abi.type;
Expand All @@ -149,11 +149,19 @@ export const abiSchemaToJsonSchema = (
abiType = abi;
abiName = `${level}/${index}`;

// If its provided in short form of tuple e.g. [['uint', 'string']]
// If it's provided in short form of tuple e.g. [['uint', 'string']]
} else if (Array.isArray(abi)) {
// If its custom tuple e.g. ['tuple[2]', ['uint', 'string']]
if (abi[1] && Array.isArray(abi[1])) {
abiType = abi[0] as string;
if (
abi[0] &&
typeof abi[0] === 'string' &&
abi[0].startsWith('tuple') &&
!Array.isArray(abi[0]) &&
abi[1] &&
Array.isArray(abi[1])
) {
// eslint-disable-next-line prefer-destructuring
abiType = abi[0];
abiName = `${level}/${index}`;
abiComponents = abi[1] as ReadonlyArray<ShortValidationSchema>;
} else {
Expand Down Expand Up @@ -258,7 +266,7 @@ export const transformJsonDataToAbiFormat = (
let abiName!: string;
let abiComponents: ShortValidationSchema | FullValidationSchema | undefined = [];

// If its a complete Abi Parameter
// If it's a complete Abi Parameter
// e.g. {name: 'a', type: 'uint'}
if (isAbiParameterSchema(abi)) {
abiType = abi.type;
Expand All @@ -268,7 +276,7 @@ export const transformJsonDataToAbiFormat = (
} else if (typeof abi === 'string') {
abiType = abi;

// If its provided in short form of tuple e.g. [['uint', 'string']]
// If it's provided in short form of tuple e.g. [['uint', 'string']]
} else if (Array.isArray(abi)) {
// If its custom tuple e.g. ['tuple[2]', ['uint', 'string']]
if (abi[1] && Array.isArray(abi[1])) {
Expand Down
9 changes: 5 additions & 4 deletions packages/web3-validator/src/validator.ts
Expand Up @@ -18,13 +18,11 @@ import { Web3ValidationErrorObject } from 'web3-types';

import { toHex, utf8ToBytes } from 'ethereum-cryptography/utils';
import { blake2b } from 'ethereum-cryptography/blake2b';
import validator from 'is-my-json-valid';
import formats from './formats';
import { Web3ValidatorError } from './errors';
import { Validate, Json, Schema, RawValidationError } from './types';

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-var-requires
const validator = require('is-my-json-valid');

export class Validator {
// eslint-disable-next-line no-use-before-define
private static validatorInstance?: Validator;
Expand All @@ -48,6 +46,7 @@ export class Validator {
// eslint-disable-next-line class-methods-use-this
private createValidator(schema: Schema): Validate {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
// @ts-expect-error validator params correction
return validator(schema, {
formats,
greedy: true,
Expand Down Expand Up @@ -91,8 +90,10 @@ export class Validator {

const { field } = error;
const _instancePath =
schemaPath ||
// eslint-disable-next-line no-useless-escape
field?.length >= 4 ? `${field.slice(4).replace(/\"|\[|\]/g, '')}` : '/';
(field?.length >= 4 ? `${field.slice(4).replace(/\"|\[|\]/g, '')}` : '/');

const instancePath = _instancePath ? `/${_instancePath}` : '';
if (error?.message === 'has less items than allowed') {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
Expand Down
95 changes: 95 additions & 0 deletions packages/web3-validator/test/unit/web3_validator_tuples.test.ts
@@ -0,0 +1,95 @@
/*
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 { Web3Validator } from '../../src/web3_validator';

describe('web3-validator', () => {
describe('Web3Validator', () => {
let validator: Web3Validator;

beforeEach(() => {
validator = new Web3Validator();
});
describe('validate', () => {
it('nested tuples', () => {
const schema = [['uint', 'uint'], 'uint'];
validator.validate(schema, [[7, 5], 3]);
});
it('nested tuples deep', () => {
const address = '0x7ab80aeb6bb488b7f6c41c58e83ef248eb39c882';

const schema = [
[
['uint', ['uint', ['uint', ['uint', 'uint'], 'address']]],
['uint', 'uint'],
],
'uint',
];
validator.validate(schema, [
[
[7, [7, [7, [7, 5], address]]],
[7, 5],
],
3,
]);
});
it('nested tuples deep object schema', () => {
const schema = {
type: 'array',
items: [
{
$id: '/0/0',
format: 'uint',
required: true,
},
{
type: 'array',
items: [
{
$id: '/0/0',
format: 'uint',
required: true,
},
{
type: 'array',
items: [
{
$id: '/0/0',
format: 'uint',
required: true,
},
{
$id: '/0/1',
format: 'uint',
required: true,
},
],
maxItems: 2,
minItems: 2,
},
],
maxItems: 2,
minItems: 2,
},
],
maxItems: 2,
minItems: 2,
};
expect(validator.validateJSONSchema(schema, [7, [7, [7, 5]]])).toBeUndefined();
});
});
});
});

0 comments on commit 4f423fc

Please sign in to comment.