diff --git a/packages/web3-errors/CHANGELOG.md b/packages/web3-errors/CHANGELOG.md index 6c242768467..303bff74b62 100644 --- a/packages/web3-errors/CHANGELOG.md +++ b/packages/web3-errors/CHANGELOG.md @@ -154,4 +154,6 @@ Documentation: - Dependencies updated -## [Unreleased] \ No newline at end of file +## [Unreleased] + +- Added new SchemaFormatError (#6434) \ No newline at end of file diff --git a/packages/web3-errors/src/error_codes.ts b/packages/web3-errors/src/error_codes.ts index c7c5d27b9a9..f7cbf5329e0 100644 --- a/packages/web3-errors/src/error_codes.ts +++ b/packages/web3-errors/src/error_codes.ts @@ -159,10 +159,14 @@ export const ERR_INVALID_NIBBLE_WIDTH = 1014; // Validation error codes export const ERR_VALIDATION = 1100; + // Core error codes export const ERR_CORE_HARDFORK_MISMATCH = 1101; export const ERR_CORE_CHAIN_MISMATCH = 1102; +// Schema error codes +export const ERR_SCHEMA_FORMAT = 1200; + // RPC error codes (EIP-1474) // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1474.md export const ERR_RPC_INVALID_JSON = -32700; diff --git a/packages/web3-errors/src/errors/schema_errors.ts b/packages/web3-errors/src/errors/schema_errors.ts new file mode 100644 index 00000000000..4d61684c616 --- /dev/null +++ b/packages/web3-errors/src/errors/schema_errors.ts @@ -0,0 +1,32 @@ +/* +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 { ERR_SCHEMA_FORMAT } from '../error_codes.js'; +import { BaseWeb3Error } from '../web3_error_base.js'; + +export class SchemaFormatError extends BaseWeb3Error { + public code = ERR_SCHEMA_FORMAT; + + public constructor(public type: string) { + super(`Format for the type ${type} is unsupported`); + } + + public toJSON() { + return { ...super.toJSON(), type: this.type }; + } + +} diff --git a/packages/web3-errors/src/index.ts b/packages/web3-errors/src/index.ts index 5916321f8a6..2e4ef7abca6 100644 --- a/packages/web3-errors/src/index.ts +++ b/packages/web3-errors/src/index.ts @@ -30,3 +30,4 @@ export * from './errors/response_errors.js'; export * from './errors/core_errors.js'; export * from './errors/rpc_errors.js'; export * from './errors/rpc_error_messages.js'; +export * from './errors/schema_errors.js'; \ No newline at end of file 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 a0f890a4b88..ab49d6aaa0a 100644 --- a/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap +++ b/packages/web3-errors/test/unit/__snapshots__/errors.test.ts.snap @@ -333,6 +333,16 @@ Object { } `; +exports[`errors SchemaFormatError should have valid json structure 1`] = ` +Object { + "code": 1200, + "innerError": undefined, + "message": "Format for the type unsupported is unsupported", + "name": "SchemaFormatError", + "type": "unsupported", +} +`; + exports[`errors TransactionError should have valid json structure 1`] = ` Object { "code": 400, diff --git a/packages/web3-errors/test/unit/errors.test.ts b/packages/web3-errors/test/unit/errors.test.ts index f8dd8466fcd..7428cc9b6b3 100644 --- a/packages/web3-errors/test/unit/errors.test.ts +++ b/packages/web3-errors/test/unit/errors.test.ts @@ -26,6 +26,7 @@ import * as signatureErrors from '../../src/errors/signature_errors'; import * as transactionErrors from '../../src/errors/transaction_errors'; import * as utilsErrors from '../../src/errors/utils_errors'; import * as responseErrors from '../../src/errors/response_errors'; +import * as schemaErrors from '../../src/errors/schema_errors'; import { ConvertValueToString } from '../fixtures/errors'; import { BaseWeb3Error } from '../../src/web3_error_base'; @@ -50,6 +51,7 @@ describe('errors', () => { ...signatureErrors, ...transactionErrors, ...utilsErrors, + ...schemaErrors, })) { if (ErrorClass === transactionErrors.InvalidPropertiesForTransactionTypeError) break; // To disable error for the abstract class @@ -379,4 +381,13 @@ describe('errors', () => { ).toMatchSnapshot(); }); }); + + describe('SchemaFormatError', () => { + it('should have valid json structure', () => { + expect( + new schemaErrors.SchemaFormatError("unsupported" + ).toJSON(), + ).toMatchSnapshot(); + }); + }); }); diff --git a/packages/web3-eth/CHANGELOG.md b/packages/web3-eth/CHANGELOG.md index 9a0c99f76f2..21fa4c5d8a0 100644 --- a/packages/web3-eth/CHANGELOG.md +++ b/packages/web3-eth/CHANGELOG.md @@ -201,6 +201,7 @@ Documentation: - Ensure provider.supportsSubscriptions exists before watching by subscription (#6440) - Fixed param sent to `checkRevertBeforeSending` in `sendSignedTransaction` +- Fixed `defaultTransactionBuilder` for value issue (#6509) ### Added diff --git a/packages/web3-eth/src/utils/transaction_builder.ts b/packages/web3-eth/src/utils/transaction_builder.ts index 04ee6d8a7b3..13edd253330 100644 --- a/packages/web3-eth/src/utils/transaction_builder.ts +++ b/packages/web3-eth/src/utils/transaction_builder.ts @@ -155,7 +155,7 @@ export async function defaultTransactionBuilder(option } if (isNullish(populatedTransaction.value)) { - populatedTransaction.value = '0x'; + populatedTransaction.value = '0x0'; } if (!isNullish(populatedTransaction.data)) { diff --git a/packages/web3-eth/test/unit/default_transaction_builder.test.ts b/packages/web3-eth/test/unit/default_transaction_builder.test.ts index 6199f7e1a3f..0e065806393 100644 --- a/packages/web3-eth/test/unit/default_transaction_builder.test.ts +++ b/packages/web3-eth/test/unit/default_transaction_builder.test.ts @@ -228,7 +228,7 @@ describe('defaultTransactionBuilder', () => { }); describe('should populate value', () => { - it('should populate with 0x', async () => { + it('should populate with 0x0 if not provided', async () => { const input = { ...transaction }; delete input.value; delete input.maxPriorityFeePerGas; @@ -239,7 +239,21 @@ describe('defaultTransactionBuilder', () => { web3Context, fillGasPrice: true, }); - expect(result.value).toBe('0x'); + expect(result.value).toBe('0x0'); + }); + + + it('should not populate with 0x0 if provided', async () => { + const input = { ...transaction }; + delete input.maxPriorityFeePerGas; + delete input.maxFeePerGas; + + const result = await defaultTransactionBuilder({ + transaction: input, + web3Context, + fillGasPrice: true, + }); + expect(result.value).not.toBe('0x0'); }); }); diff --git a/packages/web3-validator/CHANGELOG.md b/packages/web3-validator/CHANGELOG.md index 44852713656..94cda5fb867 100644 --- a/packages/web3-validator/CHANGELOG.md +++ b/packages/web3-validator/CHANGELOG.md @@ -153,3 +153,5 @@ Documentation: - Multi-dimensional arrays are now handled properly when parsing ABIs (#6435) - Fix issue with default config with babel (and React): "TypeError: Cannot convert a BigInt value to a number #6187" (#6506) +- Validator will now properly handle all valid numeric type sizes: intN / uintN where 8 <= N <= 256 and N % 8 == 0 (#6434) +- Will now throw SchemaFormatError when unsupported format is passed to `convertToZod` method (#6434) diff --git a/packages/web3-validator/src/formats.ts b/packages/web3-validator/src/formats.ts index da0c0ba6564..69d6fa9cf1f 100644 --- a/packages/web3-validator/src/formats.ts +++ b/packages/web3-validator/src/formats.ts @@ -41,8 +41,7 @@ const formats: { [key: string]: (data: unknown) => boolean } = { string: (data: unknown) => isString(data as ValidInputTypes), }; // generate formats for all numbers types -for (let i = 3; i <= 8; i += 1) { - const bitSize = 2 ** i; +for (let bitSize = 8; bitSize <= 256; bitSize += 8) { formats[`int${bitSize}`] = data => isInt(data as ValidInputTypes, { bitSize }); formats[`uint${bitSize}`] = data => isUInt(data as ValidInputTypes, { bitSize }); } diff --git a/packages/web3-validator/src/validator.ts b/packages/web3-validator/src/validator.ts index c1779992125..d477a06d96b 100644 --- a/packages/web3-validator/src/validator.ts +++ b/packages/web3-validator/src/validator.ts @@ -14,6 +14,7 @@ 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 { SchemaFormatError } from 'web3-errors'; import { Web3ValidationErrorObject } from 'web3-types'; import { z, ZodType, ZodIssue, ZodIssueCode, ZodTypeAny } from 'zod'; @@ -67,6 +68,10 @@ const convertToZod = (schema: JsonSchema): ZodType => { } if (schema?.format) { + if (!formats[schema.format]) { + throw new SchemaFormatError(schema.format); + } + return z.any().refine(formats[schema.format], (value: unknown) => ({ params: { value, format: schema.format }, })); diff --git a/packages/web3-validator/test/config/jest.config.js b/packages/web3-validator/test/config/jest.config.js index 4a60f95b353..c8c21e06e6a 100644 --- a/packages/web3-validator/test/config/jest.config.js +++ b/packages/web3-validator/test/config/jest.config.js @@ -12,7 +12,7 @@ module.exports = { }, moduleNameMapper: { '^(\\.{1,2}/.*)\\.js$': '$1', - }, + }, verbose: false, collectCoverage: false, coverageReporters: ['json'], diff --git a/packages/web3-validator/test/fixtures/abi_to_json_schema.ts b/packages/web3-validator/test/fixtures/abi_to_json_schema.ts index dcac24e2046..1a2cb7bd36f 100644 --- a/packages/web3-validator/test/fixtures/abi_to_json_schema.ts +++ b/packages/web3-validator/test/fixtures/abi_to_json_schema.ts @@ -30,7 +30,7 @@ export type AbiToJsonSchemaCase = { data: Record | Array; }; }; -export const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [ +const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [ { title: 'single param uint', abi: { @@ -1659,3 +1659,36 @@ export const abiToJsonSchemaCases: AbiToJsonSchemaCase[] = [ }, }, ]; + +function generateSingleParamNumericCase(type: string, bitSize: number) { + return { + title: `single param ${type}${bitSize}`, + abi: { + fullSchema: [{ name: 'a', type: `${type}${bitSize}` }], + shortSchema: [`${type}${bitSize}`], + data: [12], + }, + json: { + fullSchema: { + type: 'array', + items: [{ $id: 'a', format: `${type}${bitSize}`, required: true }], + minItems: 1, + maxItems: 1, + }, + shortSchema: { + type: 'array', + items: [{ $id: '/0/0', format: `${type}${bitSize}`, required: true }], + minItems: 1, + maxItems: 1, + }, + data: [12], + }, + }; +} + +for (let i = 256; i >= 8; i -= 8) { + abiToJsonSchemaCases.unshift(generateSingleParamNumericCase('int', i)); + abiToJsonSchemaCases.unshift(generateSingleParamNumericCase('uint', i)); +} + +export { abiToJsonSchemaCases }; diff --git a/packages/web3-validator/test/unit/load.test.ts b/packages/web3-validator/test/unit/load.test.ts index 919214ef7af..9053be7e8f0 100644 --- a/packages/web3-validator/test/unit/load.test.ts +++ b/packages/web3-validator/test/unit/load.test.ts @@ -16,7 +16,7 @@ along with web3.js. If not, see . */ import { Web3Validator } from '../../src/web3_validator'; -import { Json, JsonSchema, ValidationSchemaInput } from '../..'; +import { Json, JsonSchema, ValidationSchemaInput } from '../../src/types'; const abi = [ { indexed: true, internalType: 'address', name: 'from', type: 'address' }, diff --git a/packages/web3-validator/test/unit/web3_validator.test.ts b/packages/web3-validator/test/unit/web3_validator.test.ts index e1a49fa6e3a..0b910c31f17 100644 --- a/packages/web3-validator/test/unit/web3_validator.test.ts +++ b/packages/web3-validator/test/unit/web3_validator.test.ts @@ -14,6 +14,7 @@ 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 { SchemaFormatError } from 'web3-errors' import { abiToJsonSchemaCases } from '../fixtures/abi_to_json_schema'; import { Web3Validator } from '../../src/web3_validator'; import { Web3ValidatorError } from '../../src/errors'; @@ -101,14 +102,32 @@ describe('web3-validator', () => { ), ).toBeUndefined(); }); + + it('should throw due to unsupported format', () => { + expect(() => { + validator.validateJSONSchema( + { + type: 'array', + items: [{ $id: 'a', format: 'unsupportedFormat', required: true }], + minItems: 1, + maxItems: 1, + }, + ['0x2df0879f1ee2b2b1f2448c64c089c29e3ad7ccc5'], + ); + }).toThrow(SchemaFormatError); + }); }); describe('validateJsonSchema', () => { - it.each(abiToJsonSchemaCases.slice(0, 5))('should pass for valid data', abi => { - const jsonSchema = abi.json; - expect( - validator.validateJSONSchema(jsonSchema.fullSchema, jsonSchema.data), - ).toBeUndefined(); - }); + // only single param test cases + it.each(abiToJsonSchemaCases.slice(0, 69))( + `$title - should pass for valid data`, + abi => { + const jsonSchema = abi.json; + expect( + validator.validateJSONSchema(jsonSchema.fullSchema, jsonSchema.data), + ).toBeUndefined(); + }, + ); it('should throw', () => { expect(() => {