From 5f0f0fc9d3ae6b42530ab54c7d9e5dba3b5a77c3 Mon Sep 17 00:00:00 2001 From: shanejonas Date: Tue, 11 May 2021 14:46:41 -0700 Subject: [PATCH 1/3] fix: _handleChainChanged in MetaMaskInpageProvider to handle networkVersion --- src/BaseProvider.rpc.test.ts | 20 +++++++++++ src/BaseProvider.ts | 25 ++++--------- src/MetaMaskInpageProvider.rpc.test.ts | 38 ++++++++++++++++++++ src/MetaMaskInpageProvider.ts | 50 ++++++++++++++++++++++++++ 4 files changed, 115 insertions(+), 18 deletions(-) diff --git a/src/BaseProvider.rpc.test.ts b/src/BaseProvider.rpc.test.ts index 707aa463..9627744d 100644 --- a/src/BaseProvider.rpc.test.ts +++ b/src/BaseProvider.rpc.test.ts @@ -309,4 +309,24 @@ describe('BaseProvider: RPC', () => { }); }); }); + describe('provider events', () => { + // eslint-disable-next-line jest/no-test-callback + it('calls chainChanged when it chainId changes ', (done) => { + const mockStream = new MockDuplexStream(); + const p = new BaseProvider(mockStream); + (p as any)._state.initialized = true; + p.on('chainChanged', (changed) => { + expect(changed).toBeDefined(); + done(); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1' }, + }, + }); + }); + }); }); diff --git a/src/BaseProvider.ts b/src/BaseProvider.ts index 24d3aedd..a4d5f892 100644 --- a/src/BaseProvider.ts +++ b/src/BaseProvider.ts @@ -420,32 +420,21 @@ export default class BaseProvider extends SafeEventEmitter { */ protected _handleChainChanged({ chainId, - networkVersion, }: { chainId?: string; networkVersion?: string } = {}) { - if ( - !chainId || - typeof chainId !== 'string' || - !chainId.startsWith('0x') || - !networkVersion || - typeof networkVersion !== 'string' - ) { + if (!chainId || typeof chainId !== 'string' || !chainId.startsWith('0x')) { this._log.error( 'MetaMask: Received invalid network parameters. Please report this bug.', - { chainId, networkVersion }, + { chainId }, ); return; } - if (networkVersion === 'loading') { - this._handleDisconnect(true); - } else { - this._handleConnect(chainId); + this._handleConnect(chainId); - if (chainId !== this.chainId) { - this.chainId = chainId; - if (this._state.initialized) { - this.emit('chainChanged', this.chainId); - } + if (chainId !== this.chainId) { + this.chainId = chainId; + if (this._state.initialized) { + this.emit('chainChanged', this.chainId); } } } diff --git a/src/MetaMaskInpageProvider.rpc.test.ts b/src/MetaMaskInpageProvider.rpc.test.ts index f9950da7..3b592e37 100644 --- a/src/MetaMaskInpageProvider.rpc.test.ts +++ b/src/MetaMaskInpageProvider.rpc.test.ts @@ -636,4 +636,42 @@ describe('MetaMaskInpageProvider: RPC', () => { ); }); }); + describe('provider events', () => { + // eslint-disable-next-line jest/no-test-callback + it('calls chainChanged when it chainId changes ', (done) => { + const mockStream = new MockDuplexStream(); + const p = new MetaMaskInpageProvider(mockStream); + (p as any)._state.initialized = true; + p.on('chainChanged', (changed) => { + expect(changed).toBe('0x1'); + done(); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1', networkVersion: '0x1' }, + }, + }); + }); + // eslint-disable-next-line jest/no-test-callback + it('calls networkChanged when it networkVersion changes ', (done) => { + const mockStream = new MockDuplexStream(); + const p = new MetaMaskInpageProvider(mockStream); + (p as any)._state.initialized = true; + p.on('networkChanged', (changed) => { + expect(changed).toBe('0x1'); + done(); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1', networkVersion: '0x1' }, + }, + }); + }); + }); }); diff --git a/src/MetaMaskInpageProvider.ts b/src/MetaMaskInpageProvider.ts index 3b3e7319..62d2d55e 100644 --- a/src/MetaMaskInpageProvider.ts +++ b/src/MetaMaskInpageProvider.ts @@ -395,4 +395,54 @@ export default class MetaMaskInpageProvider extends BaseProvider { }, ); } + + /** + * Upon receipt of a new chainId and networkVersion, emits corresponding + * events and sets relevant public state. + * Does nothing if neither the chainId nor the networkVersion are different + * from existing values. + * + * @emits MetamaskInpageProvider#chainChanged + * @param networkInfo - An object with network info. + * @param networkInfo.chainId - The latest chain ID. + * @param networkInfo.networkVersion - The latest network ID. + */ + protected _handleChainChanged({ + chainId, + networkVersion, + }: { chainId?: string; networkVersion?: string } = {}) { + if ( + !chainId || + typeof chainId !== 'string' || + !chainId.startsWith('0x') || + !networkVersion || + typeof networkVersion !== 'string' + ) { + this._log.error( + 'MetaMask: Received invalid network parameters. Please report this bug.', + { chainId, networkVersion }, + ); + return; + } + + if (networkVersion === 'loading') { + this._handleDisconnect(true); + } else { + this._handleConnect(chainId); + + if (chainId !== this.chainId) { + this.chainId = chainId; + if (this._state.initialized) { + this.emit('chainChanged', this.chainId); + } + } + + if (networkVersion !== this.networkVersion) { + this.networkVersion = networkVersion; + if (this._state.initialized) { + this.emit('networkChanged', this.networkVersion); + } + } + } + } } From 89037b768273614c99f10115bf24c09037e935b2 Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 12 May 2021 09:55:46 -0700 Subject: [PATCH 2/3] Update src/MetaMaskInpageProvider.ts Co-authored-by: Erik Marks <25517051+rekmarks@users.noreply.github.com> --- src/MetaMaskInpageProvider.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/MetaMaskInpageProvider.ts b/src/MetaMaskInpageProvider.ts index 62d2d55e..ead17ed7 100644 --- a/src/MetaMaskInpageProvider.ts +++ b/src/MetaMaskInpageProvider.ts @@ -403,6 +403,7 @@ export default class MetaMaskInpageProvider extends BaseProvider { * from existing values. * * @emits MetamaskInpageProvider#chainChanged + * @emits MetamaskInpageProvider#networkChanged * @param networkInfo - An object with network info. * @param networkInfo.chainId - The latest chain ID. * @param networkInfo.networkVersion - The latest network ID. From 7a7dafdcb548118a21d54cfe935528eca3a77e3b Mon Sep 17 00:00:00 2001 From: shanejonas Date: Wed, 12 May 2021 11:43:21 -0700 Subject: [PATCH 3/3] fix: pr fixups --- src/BaseProvider.rpc.test.ts | 31 +++++++------ src/BaseProvider.ts | 25 +++++++--- src/MetaMaskInpageProvider.rpc.test.ts | 64 ++++++++++++++------------ src/MetaMaskInpageProvider.ts | 37 ++++----------- 4 files changed, 76 insertions(+), 81 deletions(-) diff --git a/src/BaseProvider.rpc.test.ts b/src/BaseProvider.rpc.test.ts index 9627744d..bb1b6389 100644 --- a/src/BaseProvider.rpc.test.ts +++ b/src/BaseProvider.rpc.test.ts @@ -310,22 +310,23 @@ describe('BaseProvider: RPC', () => { }); }); describe('provider events', () => { - // eslint-disable-next-line jest/no-test-callback - it('calls chainChanged when it chainId changes ', (done) => { + it('calls chainChanged when it chainId changes ', async () => { const mockStream = new MockDuplexStream(); - const p = new BaseProvider(mockStream); - (p as any)._state.initialized = true; - p.on('chainChanged', (changed) => { - expect(changed).toBeDefined(); - done(); - }); - mockStream.push({ - name: 'metamask-provider', - data: { - jsonrpc: '2.0', - method: 'metamask_chainChanged', - params: { chainId: '0x1' }, - }, + const baseProvider = new BaseProvider(mockStream); + (baseProvider as any)._state.initialized = true; + await new Promise((resolve) => { + baseProvider.on('chainChanged', (changed) => { + expect(changed).toBeDefined(); + resolve(undefined); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1', networkVersion: '0x1' }, + }, + }); }); }); }); diff --git a/src/BaseProvider.ts b/src/BaseProvider.ts index a4d5f892..24d3aedd 100644 --- a/src/BaseProvider.ts +++ b/src/BaseProvider.ts @@ -420,21 +420,32 @@ export default class BaseProvider extends SafeEventEmitter { */ protected _handleChainChanged({ chainId, + networkVersion, }: { chainId?: string; networkVersion?: string } = {}) { - if (!chainId || typeof chainId !== 'string' || !chainId.startsWith('0x')) { + if ( + !chainId || + typeof chainId !== 'string' || + !chainId.startsWith('0x') || + !networkVersion || + typeof networkVersion !== 'string' + ) { this._log.error( 'MetaMask: Received invalid network parameters. Please report this bug.', - { chainId }, + { chainId, networkVersion }, ); return; } - this._handleConnect(chainId); + if (networkVersion === 'loading') { + this._handleDisconnect(true); + } else { + this._handleConnect(chainId); - if (chainId !== this.chainId) { - this.chainId = chainId; - if (this._state.initialized) { - this.emit('chainChanged', this.chainId); + if (chainId !== this.chainId) { + this.chainId = chainId; + if (this._state.initialized) { + this.emit('chainChanged', this.chainId); + } } } } diff --git a/src/MetaMaskInpageProvider.rpc.test.ts b/src/MetaMaskInpageProvider.rpc.test.ts index 3b592e37..14b62a79 100644 --- a/src/MetaMaskInpageProvider.rpc.test.ts +++ b/src/MetaMaskInpageProvider.rpc.test.ts @@ -636,41 +636,45 @@ describe('MetaMaskInpageProvider: RPC', () => { ); }); }); + describe('provider events', () => { - // eslint-disable-next-line jest/no-test-callback - it('calls chainChanged when it chainId changes ', (done) => { + it('calls chainChanged when it chainId changes ', async () => { const mockStream = new MockDuplexStream(); - const p = new MetaMaskInpageProvider(mockStream); - (p as any)._state.initialized = true; - p.on('chainChanged', (changed) => { - expect(changed).toBe('0x1'); - done(); - }); - mockStream.push({ - name: 'metamask-provider', - data: { - jsonrpc: '2.0', - method: 'metamask_chainChanged', - params: { chainId: '0x1', networkVersion: '0x1' }, - }, + const inpageProvider = new MetaMaskInpageProvider(mockStream); + (inpageProvider as any)._state.initialized = true; + await new Promise((resolve) => { + inpageProvider.on('chainChanged', (changed) => { + expect(changed).toBe('0x1'); + resolve(undefined); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1', networkVersion: '0x1' }, + }, + }); }); }); - // eslint-disable-next-line jest/no-test-callback - it('calls networkChanged when it networkVersion changes ', (done) => { + + it('calls networkChanged when it networkVersion changes ', async () => { const mockStream = new MockDuplexStream(); - const p = new MetaMaskInpageProvider(mockStream); - (p as any)._state.initialized = true; - p.on('networkChanged', (changed) => { - expect(changed).toBe('0x1'); - done(); - }); - mockStream.push({ - name: 'metamask-provider', - data: { - jsonrpc: '2.0', - method: 'metamask_chainChanged', - params: { chainId: '0x1', networkVersion: '0x1' }, - }, + const inpageProvider = new MetaMaskInpageProvider(mockStream); + (inpageProvider as any)._state.initialized = true; + await new Promise((resolve) => { + inpageProvider.on('networkChanged', (changed) => { + expect(changed).toBe('0x1'); + resolve(undefined); + }); + mockStream.push({ + name: 'metamask-provider', + data: { + jsonrpc: '2.0', + method: 'metamask_chainChanged', + params: { chainId: '0x1', networkVersion: '0x1' }, + }, + }); }); }); }); diff --git a/src/MetaMaskInpageProvider.ts b/src/MetaMaskInpageProvider.ts index ead17ed7..1caddd4b 100644 --- a/src/MetaMaskInpageProvider.ts +++ b/src/MetaMaskInpageProvider.ts @@ -412,37 +412,16 @@ export default class MetaMaskInpageProvider extends BaseProvider { chainId, networkVersion, }: { chainId?: string; networkVersion?: string } = {}) { + super._handleChainChanged({ chainId, networkVersion }); + if ( - !chainId || - typeof chainId !== 'string' || - !chainId.startsWith('0x') || - !networkVersion || - typeof networkVersion !== 'string' + networkVersion && + networkVersion !== 'loading' && + networkVersion !== this.networkVersion ) { - this._log.error( - 'MetaMask: Received invalid network parameters. Please report this bug.', - { chainId, networkVersion }, - ); - return; - } - - if (networkVersion === 'loading') { - this._handleDisconnect(true); - } else { - this._handleConnect(chainId); - - if (chainId !== this.chainId) { - this.chainId = chainId; - if (this._state.initialized) { - this.emit('chainChanged', this.chainId); - } - } - - if (networkVersion !== this.networkVersion) { - this.networkVersion = networkVersion; - if (this._state.initialized) { - this.emit('networkChanged', this.networkVersion); - } + this.networkVersion = networkVersion; + if (this._state.initialized) { + this.emit('networkChanged', this.networkVersion); } } }