From f3bb8ea519f744170cbb2c69f61373cac322e8bb Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 8 Feb 2023 17:08:35 +0100 Subject: [PATCH] fix bug in injected and external provider --- .../src/app/providers/abstract-provider.tsx | 122 +++++++----------- .../src/app/providers/injected-provider.tsx | 4 +- 2 files changed, 47 insertions(+), 79 deletions(-) diff --git a/apps/remix-ide/src/app/providers/abstract-provider.tsx b/apps/remix-ide/src/app/providers/abstract-provider.tsx index 1edd82a1e8..d9d73c32e9 100644 --- a/apps/remix-ide/src/app/providers/abstract-provider.tsx +++ b/apps/remix-ide/src/app/providers/abstract-provider.tsx @@ -21,105 +21,78 @@ export type SuccessRequest = (data: JsonDataResult) => void export abstract class AbstractProvider extends Plugin { provider: ethers.providers.JsonRpcProvider - blocked: boolean blockchain: Blockchain defaultUrl: string connected: boolean + nodeUrl: string constructor (profile, blockchain, defaultUrl) { super(profile) this.defaultUrl = defaultUrl this.provider = null - this.blocked = false // used to block any call when trying to recover after a failed connection. this.connected = false this.blockchain = blockchain + this.nodeUrl = 'http://localhost:8545' } abstract body(): JSX.Element onDeactivation () { this.provider = null - this.blocked = false } - sendAsync (data: JsonDataRequest): Promise { - // eslint-disable-next-line no-async-promise-executor - return new Promise(async (resolve, reject) => { - if (this.blocked) return reject(new Error('provider unable to connect')) - // If provider is not set, allow to open modal only when provider is trying to connect - if (!this.provider) { - let value: string - try { - value = await ((): Promise => { - return new Promise((resolve, reject) => { - const modalContent: AppModal = { - id: this.profile.name, - title: this.profile.displayName, - message: this.body(), - modalType: ModalTypes.prompt, - okLabel: 'OK', - cancelLabel: 'Cancel', - validationFn: (value) => { - if (!value) return { valid: false, message: "value is empty" } - if (value.startsWith('https://') || value.startsWith('http://')) { - return { - valid: true, - message: '' - } - } else { - return { - valid: false, - message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )' - } - } - }, - okFn: (value: string) => { - setTimeout(() => resolve(value), 0) - }, - cancelFn: () => { - setTimeout(() => reject(new Error('Canceled')), 0) - }, - hideFn: () => { - setTimeout(() => reject(new Error('Hide')), 0) - }, - defaultValue: this.defaultUrl + async init () { + this.nodeUrl = await ((): Promise => { + return new Promise((resolve, reject) => { + const modalContent: AppModal = { + id: this.profile.name, + title: this.profile.displayName, + message: this.body(), + modalType: ModalTypes.prompt, + okLabel: 'OK', + cancelLabel: 'Cancel', + validationFn: (value) => { + if (!value) return { valid: false, message: "value is empty" } + if (value.startsWith('https://') || value.startsWith('http://')) { + return { + valid: true, + message: '' + } + } else { + return { + valid: false, + message: 'the provided value should contain the protocol ( e.g starts with http:// or https:// )' } - this.call('notification', 'modal', modalContent) - }) - })() - } catch (e) { - // the modal has been canceled/hide - const result = data.method === 'net_listening' ? 'canceled' : [] - resolve({ jsonrpc: '2.0', result: result, id: data.id }) - this.switchAway(false) - return - } - this.provider = new ethers.providers.JsonRpcProvider(value) - try { - setTimeout(() => { - if (!this.connected) { - this.switchAway(true) - reject('Unable to connect') } - }, 2000) - await this.provider.detectNetwork() // this throws if the network cannot be detected - this.connected = true - } catch (e) { - this.switchAway(true) - reject('Unable to connect') - return + }, + okFn: (value: string) => { + setTimeout(() => resolve(value), 0) + }, + cancelFn: () => { + setTimeout(() => reject(new Error('Canceled')), 0) + }, + hideFn: () => { + setTimeout(() => reject(new Error('Hide')), 0) + }, + defaultValue: this.defaultUrl } - this.sendAsyncInternal(data, resolve, reject) - } else { - this.sendAsyncInternal(data, resolve, reject) - } + this.call('notification', 'modal', modalContent) + }) + })() + this.provider = new ethers.providers.JsonRpcProvider(this.nodeUrl) + } + + sendAsync (data: JsonDataRequest): Promise { + // eslint-disable-next-line no-async-promise-executor + return new Promise(async (resolve, reject) => { + if (!this.provider) return reject(new Error('provider node set')) + this.sendAsyncInternal(data, resolve, reject) }) } private async switchAway (showError) { if (!this.provider) return this.provider = null - this.blocked = true this.connected = false if (showError) { const modalContent: AlertModal = { @@ -130,16 +103,11 @@ export abstract class AbstractProvider extends Plugin { this.call('notification', 'alert', modalContent) } await this.call('udapp', 'setEnvironmentMode', { context: 'vm-london'}) - setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm return } private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise { if (this.provider) { - // Check the case where current environment is VM on UI and it still sends RPC requests - // This will be displayed on UI tooltip as 'cannot get account list: Environment Updated !!' - if (this.blockchain.getProvider() !== this.profile.displayName && data.method !== 'net_listening') return reject(new Error('Environment Updated !!')) - try { const result = await this.provider.send(data.method, data.params) resolve({ jsonrpc: '2.0', result, id: data.id }) diff --git a/apps/remix-ide/src/app/providers/injected-provider.tsx b/apps/remix-ide/src/app/providers/injected-provider.tsx index 98330d1b83..928c3133cd 100644 --- a/apps/remix-ide/src/app/providers/injected-provider.tsx +++ b/apps/remix-ide/src/app/providers/injected-provider.tsx @@ -16,8 +16,8 @@ export class InjectedProvider extends Plugin { } askPermission (throwIfNoInjectedProvider) { - if (typeof (window as any).ethereum !== "undefined" && typeof (window as any).request === "function") { - (window as any).request({ method: "eth_requestAccounts" }) + if ((typeof (window as any).ethereum) !== "undefined" && (typeof (window as any).ethereum.request) === "function") { + (window as any).ethereum.request({ method: "eth_requestAccounts" }) } else if (throwIfNoInjectedProvider) { throw new Error(noInjectedProviderMsg) }