Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

6201 multi provider #6825

Merged
merged 8 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/web3/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,4 +191,8 @@ Documentation:

- Dependencies updated ( details are in root changelog )

## [Unreleased]
## [Unreleased]

### Added

- Added EIP-6963 utility function `requestEIP6963Providers` for multi provider discovery
2 changes: 2 additions & 0 deletions packages/web3/src/web3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import abi from './abi.js';
import { initAccountsForContext } from './accounts.js';
import { Web3EthInterface } from './types.js';
import { Web3PkgInfo } from './version.js';
import { requestEIP6963Providers } from './web3_eip6963.js';

export class Web3<
CustomRegisteredSubscription extends {
Expand All @@ -52,6 +53,7 @@ export class Web3<
> extends Web3Context<EthExecutionAPI, CustomRegisteredSubscription & RegisteredSubscription> {
public static version = Web3PkgInfo.version;
public static utils = utils;
public static requestEIP6963Providers = requestEIP6963Providers;
public static modules = {
Web3Eth,
Iban,
Expand Down
71 changes: 71 additions & 0 deletions packages/web3/src/web3_eip6963.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
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 { Web3APISpec, EIP1193Provider } from "web3-types";


export enum Eip6963EventName {
eip6963announceProvider = 'eip6963:announceProvider',
eip6963requestProvider = 'eip6963:requestProvider',
};

export interface EIP6963ProviderInfo {
uuid: string;
name: string;
icon: string;
rdns: string;
}

export interface EIP6963ProviderDetail<API = Web3APISpec> {
info: EIP6963ProviderInfo;
provider: EIP1193Provider<API>;
}

export interface EIP6963AnnounceProviderEvent<API = Web3APISpec> extends CustomEvent {
type: Eip6963EventName.eip6963announceProvider;
detail: EIP6963ProviderDetail<API>;
}

export interface EIP6963RequestProviderEvent extends Event {
type: Eip6963EventName.eip6963requestProvider;
}

export const eip6963Providers: Map<string, EIP6963ProviderDetail> = new Map();

export const requestEIP6963Providers = () => {

if (typeof window === 'undefined')
throw new Error(
"window object not available, EIP-6963 is intended to be used within a browser"
);

window.addEventListener(
Eip6963EventName.eip6963announceProvider as any,
(event: EIP6963AnnounceProviderEvent) => {

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not emitting eip6963:announceProvider event here via web3promi events as discussed in issue, because,

  • if user is listening to eip6963:announceProvider event after using this utility method then this utility method is just additional overlapping work also listening to same event and re-emitting without any need of processing,

  • EIP 6963 clearly specifies "... MUST use the window.dispatchEvent function to emit events and MUST use the window.addEventListener function to observe events ... ",

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be stated somewhere that we return web3promievent for the users

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

web3promievent is not returned due to above reasons.

eip6963Providers.set(
event.detail.info.uuid,
event.detail);
}
);

window.dispatchEvent(new Event(Eip6963EventName.eip6963requestProvider));

return eip6963Providers;
}


37 changes: 0 additions & 37 deletions packages/web3/test/unit/constructor.test.ts

This file was deleted.

86 changes: 86 additions & 0 deletions packages/web3/test/unit/web3eip6963.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
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 {
EIP6963AnnounceProviderEvent,
EIP6963ProviderDetail,
Eip6963EventName,
eip6963Providers,
requestEIP6963Providers
} from "../../src/web3_eip6963";

describe('requestEIP6963Providers', () => {

it('should request EIP6963 providers and store them in eip6963Providers', () => {

const mockProviderDetail: EIP6963ProviderDetail = {
info: {
uuid: '1',
name: 'MockProvider',
icon: 'icon-path',
rdns: 'mock.rdns'
},

provider: {} as any
};

const mockAnnounceEvent: EIP6963AnnounceProviderEvent = {
type: Eip6963EventName.eip6963announceProvider,
detail: mockProviderDetail
} as any;

// Mock the window object
(global as any).window = {
addEventListener: jest.fn(),
dispatchEvent: jest.fn()
};

// Call the function
requestEIP6963Providers();

// Validate event listener setup and event dispatch
expect((global as any).window.addEventListener)
.toHaveBeenCalledWith(Eip6963EventName.eip6963announceProvider, expect.any(Function));

expect((global as any).window.dispatchEvent).toHaveBeenCalled();

// Simulate the announce event
// Access the mock function calls for addEventListener
const addEventListenerMockCalls = (global as any).window.addEventListener.mock.calls;

// Retrieve the first call to addEventListener and access its second argument
const eventListenerArg = addEventListenerMockCalls[0][1];

// Now "eventListenerArg" represents the function to be called when the event occurs
const announceEventListener = eventListenerArg;
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
announceEventListener(mockAnnounceEvent);

// Validate if the provider detail is stored in the eip6963Providers map
expect(eip6963Providers.get('1')).toEqual(mockProviderDetail);
});

it('should throw an error if window object is not available', () => {
// Remove the window object
delete (global as any).window;

// Call the function and expect it to throw an error
expect(() => {
requestEIP6963Providers();
}).toThrow("window object not available, EIP-6963 is intended to be used within a browser");
});
});
Loading