|
|
|
@ -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<any> { |
|
|
|
|
// 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<string> => { |
|
|
|
|
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<string> => { |
|
|
|
|
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<any> { |
|
|
|
|
// 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<void> { |
|
|
|
|
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 }) |
|
|
|
|