From bafc6cdd2a1bbbe4af5c672c3946ce6d719bc0dc Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:39:45 +0200 Subject: [PATCH 1/5] add asEip1193FullyCompatible to Web3BaseProvider --- packages/web3-types/src/web3_base_provider.ts | 47 ++++++++++++++ .../test/unit/web3_base_provider.test.ts | 65 +++++++++++++++++++ 2 files changed, 112 insertions(+) create mode 100644 packages/web3-types/test/unit/web3_base_provider.test.ts diff --git a/packages/web3-types/src/web3_base_provider.ts b/packages/web3-types/src/web3_base_provider.ts index 6ce832a0ae5..4fc62a0991e 100644 --- a/packages/web3-types/src/web3_base_provider.ts +++ b/packages/web3-types/src/web3_base_provider.ts @@ -133,6 +133,19 @@ export interface EIP1193Provider extends SimpleProvider removeListener(event: 'accountsChanged', listener: (accounts: ProviderAccounts) => void): void; } +export type Eip1193FullyCompatible = Omit< + // eslint-disable-next-line no-use-before-define + Omit, + 'asEip1193FullyCompatible' +> & { + request< + Method extends Web3APIMethod, + ResultType = Web3APIReturnType | unknown, + >( + request: Web3APIPayload, + ): Promise; +}; + // Provider interface compatible with EIP-1193 // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md export abstract class Web3BaseProvider @@ -189,6 +202,40 @@ export abstract class Web3BaseProvider; } + /** + * Modify the return type of the request method to be fully compatible with EIP-1193 + * + * [deprecated] In the future major releases (\>= v5) all providers are supposed to be fully compatible with EIP-1193. + * So this method will not be needed and would not be available in the future. + * + * @returns A new instance of the provider with the request method fully compatible with EIP-1193 + * + * @example + * ```ts + * const provider = new Web3HttpProvider('http://localhost:8545'); + * const fullyCompatibleProvider = provider.asEip1193FullyCompatible(); + * const result = await fullyCompatibleProvider.request({ method: 'eth_getBalance' }); + * console.log(result); // '0x0234c8a3397aab58' or something like that + * ``` + */ + public asEip1193FullyCompatible(): Eip1193FullyCompatible { + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const newObj = Object.create(this) as Eip1193FullyCompatible; + // eslint-disable-next-line @typescript-eslint/unbound-method + const originalRequest = newObj.request; + newObj.request = async function request( + args: Web3APIPayload>, + ): Promise { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion + const response = (await originalRequest(args)) as JsonRpcResponseWithResult; + return response.result; + } as typeof newObj.request; + // @ts-expect-error the property should not be available in the new object because of using Object.create(this). + // But it is available if we do not delete it. + newObj.asEip1193FullyCompatible = undefined; // to prevent the user for calling this method again + return newObj; + } + // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md#request public abstract request< Method extends Web3APIMethod, diff --git a/packages/web3-types/test/unit/web3_base_provider.test.ts b/packages/web3-types/test/unit/web3_base_provider.test.ts new file mode 100644 index 00000000000..7226b642492 --- /dev/null +++ b/packages/web3-types/test/unit/web3_base_provider.test.ts @@ -0,0 +1,65 @@ +/* +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 { + EthExecutionAPI, + JsonRpcResponseWithResult, + Web3APIMethod, + Web3APIPayload, + Web3APIReturnType, + Web3BaseProvider, +} from '../../src/index.js'; + +// @ts-expect-error mock class for testing. The abstract methods are not implemented. +class Web3ChildProvider extends Web3BaseProvider { + // eslint-disable-next-line class-methods-use-this + public async request< + Method extends Web3APIMethod, + ResultType = Web3APIReturnType | unknown, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + >(_: Web3APIPayload): Promise> { + return new Promise(resolve => + // eslint-disable-next-line no-promise-executor-return + resolve({ + jsonrpc: '2.0', + id: 1, + result: 'result' as unknown as ResultType, + }), + ); + } +} + +describe('Web3BaseProvider', () => { + it('asEip1193FullyCompatible will fix the returned result of the request method', async () => { + const childProvider = new Web3ChildProvider(); + const returnValue = await childProvider.request({ method: 'eth_getBalance' }); + expect(returnValue.result).toBe('result'); + + const eip1193FullyCompatibleClass = childProvider.asEip1193FullyCompatible(); + const returnValue2 = await eip1193FullyCompatibleClass.request({ + method: 'eth_getBalance', + }); + expect(returnValue2).toBe('result'); + }); + + it('asEip1193FullyCompatible would not be available inside the newly generated class', () => { + const childProvider = new Web3ChildProvider(); + + const eip1193FullyCompatibleClass = childProvider.asEip1193FullyCompatible(); + expect((eip1193FullyCompatibleClass as any).asEip1193FullyCompatible).toBeUndefined(); + }); +}); From f4deeb79d0d7345163d0a91c261393024704830b Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:40:52 +0200 Subject: [PATCH 2/5] modify jest config at web3-types --- packages/web3-types/test/unit/jest.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/web3-types/test/unit/jest.config.js b/packages/web3-types/test/unit/jest.config.js index ceac341e332..81c51a857f5 100644 --- a/packages/web3-types/test/unit/jest.config.js +++ b/packages/web3-types/test/unit/jest.config.js @@ -3,7 +3,9 @@ const base = require('../config/jest.config'); module.exports = { ...base, testMatch: ['/test/unit/**/*.(spec|test).(js|ts)'], - + moduleNameMapper: { + '^(\\.{1,2}/.*)\\.js$': '$1', + }, coverageDirectory: '.coverage/unit', collectCoverageFrom: ['src/**'], }; From dfe8c654a8005769ccb8e95559e5fe445065d7ae Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Thu, 7 Sep 2023 01:45:53 +0200 Subject: [PATCH 3/5] update CHANGELOG.md at web3-types --- packages/web3-types/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/web3-types/CHANGELOG.md b/packages/web3-types/CHANGELOG.md index f8a89a159cb..4d721460f22 100644 --- a/packages/web3-types/CHANGELOG.md +++ b/packages/web3-types/CHANGELOG.md @@ -158,3 +158,7 @@ Documentation: - Dependencies updated ## [Unreleased] + +### Added + +- add `asEip1193FullyCompatible` to `Web3BaseProvider` so every inherited class can have the returned value of `request` method, fully compatible with EIP-1193. (#6407) From 0e457680f0baab8ffd4df1b10b65bd31418860ca Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Thu, 7 Sep 2023 22:23:36 +0200 Subject: [PATCH 4/5] rename method to asEIP1193Provider --- packages/web3-types/CHANGELOG.md | 2 +- packages/web3-types/src/web3_base_provider.ts | 8 ++++---- .../web3-types/test/unit/web3_base_provider.test.ts | 10 +++++----- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/web3-types/CHANGELOG.md b/packages/web3-types/CHANGELOG.md index 4d721460f22..aacfb104cea 100644 --- a/packages/web3-types/CHANGELOG.md +++ b/packages/web3-types/CHANGELOG.md @@ -161,4 +161,4 @@ Documentation: ### Added -- add `asEip1193FullyCompatible` to `Web3BaseProvider` so every inherited class can have the returned value of `request` method, fully compatible with EIP-1193. (#6407) +- add `asEIP1193Provider` to `Web3BaseProvider` so every inherited class can have the returned value of `request` method, fully compatible with EIP-1193. (#6407) diff --git a/packages/web3-types/src/web3_base_provider.ts b/packages/web3-types/src/web3_base_provider.ts index 4fc62a0991e..15c6a609f91 100644 --- a/packages/web3-types/src/web3_base_provider.ts +++ b/packages/web3-types/src/web3_base_provider.ts @@ -136,7 +136,7 @@ export interface EIP1193Provider extends SimpleProvider export type Eip1193FullyCompatible = Omit< // eslint-disable-next-line no-use-before-define Omit, - 'asEip1193FullyCompatible' + 'asEIP1193Provider' > & { request< Method extends Web3APIMethod, @@ -213,12 +213,12 @@ export abstract class Web3BaseProvider { + public asEIP1193Provider(): Eip1193FullyCompatible { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const newObj = Object.create(this) as Eip1193FullyCompatible; // eslint-disable-next-line @typescript-eslint/unbound-method @@ -232,7 +232,7 @@ export abstract class Web3BaseProvider { - it('asEip1193FullyCompatible will fix the returned result of the request method', async () => { + it('asEIP1193Provider will fix the returned result of the request method', async () => { const childProvider = new Web3ChildProvider(); const returnValue = await childProvider.request({ method: 'eth_getBalance' }); expect(returnValue.result).toBe('result'); - const eip1193FullyCompatibleClass = childProvider.asEip1193FullyCompatible(); + const eip1193FullyCompatibleClass = childProvider.asEIP1193Provider(); const returnValue2 = await eip1193FullyCompatibleClass.request({ method: 'eth_getBalance', }); expect(returnValue2).toBe('result'); }); - it('asEip1193FullyCompatible would not be available inside the newly generated class', () => { + it('asEIP1193Provider would not be available inside the newly generated class', () => { const childProvider = new Web3ChildProvider(); - const eip1193FullyCompatibleClass = childProvider.asEip1193FullyCompatible(); - expect((eip1193FullyCompatibleClass as any).asEip1193FullyCompatible).toBeUndefined(); + const eip1193FullyCompatibleClass = childProvider.asEIP1193Provider(); + expect((eip1193FullyCompatibleClass as any).asEIP1193Provider).toBeUndefined(); }); }); From 850adca9c9bdda51ae2b7d74c4e2e55aef03bf63 Mon Sep 17 00:00:00 2001 From: Muhammad-Altabba <24407834+Muhammad-Altabba@users.noreply.github.com> Date: Fri, 8 Sep 2023 21:04:30 +0200 Subject: [PATCH 5/5] rename `Eip1193Compatible` class --- packages/web3-types/src/web3_base_provider.ts | 6 +++--- packages/web3-types/test/unit/web3_base_provider.test.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/web3-types/src/web3_base_provider.ts b/packages/web3-types/src/web3_base_provider.ts index 15c6a609f91..aac2e722bfc 100644 --- a/packages/web3-types/src/web3_base_provider.ts +++ b/packages/web3-types/src/web3_base_provider.ts @@ -133,7 +133,7 @@ export interface EIP1193Provider extends SimpleProvider removeListener(event: 'accountsChanged', listener: (accounts: ProviderAccounts) => void): void; } -export type Eip1193FullyCompatible = Omit< +export type Eip1193Compatible = Omit< // eslint-disable-next-line no-use-before-define Omit, 'asEIP1193Provider' @@ -218,9 +218,9 @@ export abstract class Web3BaseProvider { + public asEIP1193Provider(): Eip1193Compatible { // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const newObj = Object.create(this) as Eip1193FullyCompatible; + const newObj = Object.create(this) as Eip1193Compatible; // eslint-disable-next-line @typescript-eslint/unbound-method const originalRequest = newObj.request; newObj.request = async function request( diff --git a/packages/web3-types/test/unit/web3_base_provider.test.ts b/packages/web3-types/test/unit/web3_base_provider.test.ts index 5f508627476..7e95bf9f8c3 100644 --- a/packages/web3-types/test/unit/web3_base_provider.test.ts +++ b/packages/web3-types/test/unit/web3_base_provider.test.ts @@ -49,8 +49,8 @@ describe('Web3BaseProvider', () => { const returnValue = await childProvider.request({ method: 'eth_getBalance' }); expect(returnValue.result).toBe('result'); - const eip1193FullyCompatibleClass = childProvider.asEIP1193Provider(); - const returnValue2 = await eip1193FullyCompatibleClass.request({ + const eip1193CompatibleClass = childProvider.asEIP1193Provider(); + const returnValue2 = await eip1193CompatibleClass.request({ method: 'eth_getBalance', }); expect(returnValue2).toBe('result'); @@ -59,7 +59,7 @@ describe('Web3BaseProvider', () => { it('asEIP1193Provider would not be available inside the newly generated class', () => { const childProvider = new Web3ChildProvider(); - const eip1193FullyCompatibleClass = childProvider.asEIP1193Provider(); - expect((eip1193FullyCompatibleClass as any).asEIP1193Provider).toBeUndefined(); + const eip1193CompatibleClass = childProvider.asEIP1193Provider(); + expect((eip1193CompatibleClass as any).asEIP1193Provider).toBeUndefined(); }); });