Skip to content

Commit

Permalink
create a new type Eip1193Compatible (#6407)
Browse files Browse the repository at this point in the history
* add asEip1193Compatible to Web3BaseProvider

* modify jest config at web3-types

* update CHANGELOG.md at web3-types
  • Loading branch information
Muhammad-Altabba authored Sep 12, 2023
1 parent dd4de22 commit 3ab3b39
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/web3-types/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,7 @@ Documentation:
- Dependencies updated

## [Unreleased]

### Added

- add `asEIP1193Provider` to `Web3BaseProvider` so every inherited class can have the returned value of `request` method, fully compatible with EIP-1193. (#6407)
47 changes: 47 additions & 0 deletions packages/web3-types/src/web3_base_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,19 @@ export interface EIP1193Provider<API extends Web3APISpec> extends SimpleProvider
removeListener(event: 'accountsChanged', listener: (accounts: ProviderAccounts) => void): void;
}

export type Eip1193Compatible<API extends Web3APISpec = EthExecutionAPI> = Omit<
// eslint-disable-next-line no-use-before-define
Omit<Web3BaseProvider, 'request'>,
'asEIP1193Provider'
> & {
request<
Method extends Web3APIMethod<API>,
ResultType = Web3APIReturnType<API, Method> | unknown,
>(
request: Web3APIPayload<API, Method>,
): Promise<ResultType>;
};

// Provider interface compatible with EIP-1193
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1193.md
export abstract class Web3BaseProvider<API extends Web3APISpec = EthExecutionAPI>
Expand Down Expand Up @@ -189,6 +202,40 @@ export abstract class Web3BaseProvider<API extends Web3APISpec = EthExecutionAPI
>;
}

/**
* 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.asEIP1193Provider();
* const result = await fullyCompatibleProvider.request({ method: 'eth_getBalance' });
* console.log(result); // '0x0234c8a3397aab58' or something like that
* ```
*/
public asEIP1193Provider(): Eip1193Compatible<API> {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const newObj = Object.create(this) as Eip1193Compatible<API>;
// eslint-disable-next-line @typescript-eslint/unbound-method
const originalRequest = newObj.request;
newObj.request = async function request(
args: Web3APIPayload<API, Web3APIMethod<API>>,
): Promise<unknown> {
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
const response = (await originalRequest(args)) as JsonRpcResponseWithResult<unknown>;
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.asEIP1193Provider = 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<API>,
Expand Down
4 changes: 3 additions & 1 deletion packages/web3-types/test/unit/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ const base = require('../config/jest.config');
module.exports = {
...base,
testMatch: ['<rootDir>/test/unit/**/*.(spec|test).(js|ts)'],

moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
coverageDirectory: '.coverage/unit',
collectCoverageFrom: ['src/**'],
};
65 changes: 65 additions & 0 deletions packages/web3-types/test/unit/web3_base_provider.test.ts
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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<EthExecutionAPI>,
ResultType = Web3APIReturnType<EthExecutionAPI, Method> | unknown,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
>(_: Web3APIPayload<EthExecutionAPI, Method>): Promise<JsonRpcResponseWithResult<ResultType>> {
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('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 eip1193CompatibleClass = childProvider.asEIP1193Provider();
const returnValue2 = await eip1193CompatibleClass.request({
method: 'eth_getBalance',
});
expect(returnValue2).toBe('result');
});

it('asEIP1193Provider would not be available inside the newly generated class', () => {
const childProvider = new Web3ChildProvider();

const eip1193CompatibleClass = childProvider.asEIP1193Provider();
expect((eip1193CompatibleClass as any).asEIP1193Provider).toBeUndefined();
});
});

0 comments on commit 3ab3b39

Please sign in to comment.