activate hardhat provider at load

pull/2265/head^2
yann300 3 years ago
parent fcdbf0beb5
commit 6926ab13d7
  1. 123
      apps/remix-ide/src/app/tabs/abstract-provider.tsx
  2. 106
      apps/remix-ide/src/app/tabs/hardhat-provider.tsx
  3. 6
      apps/remix-ide/src/app/udapp/run-tab.js
  4. 2
      apps/remix-ide/src/remixAppManager.js
  5. 3
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  6. 1
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  7. 1
      libs/remix-ui/run-tab/src/lib/types/run-tab.d.ts

@ -0,0 +1,123 @@
import * as packageJson from '../../../../../package.json'
import { Plugin } from '@remixproject/engine'
import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app'
import React from 'react' // eslint-disable-line
import { Blockchain } from '../../blockchain/blockchain'
import { ethers } from 'ethers'
const profile = {
name: 'hardhat-provider',
displayName: 'Hardhat Provider',
kind: 'provider',
description: 'Hardhat provider',
methods: ['sendAsync'],
version: packageJson.version
}
type JsonDataRequest = {
id: number,
jsonrpc: string // version
method: string,
params: Array<any>,
}
type JsonDataResult = {
id: number,
jsonrpc: string // version
result: any
}
type RejectRequest = (error: Error) => void
type SuccessRequest = (data: JsonDataResult) => void
export abstract class AbstractProvider extends Plugin {
provider: ethers.providers.JsonRpcProvider
blocked: boolean
blockchain: Blockchain
defaultUrl: 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.blockchain = blockchain
}
abstract body(): JSX.Element
onDeactivation () {
this.provider = null
this.blocked = false
}
sendAsync (data: JsonDataRequest): Promise<any> {
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',
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.call('notification', 'modal', modalContent)
})
})()
} catch (e) {
// the modal has been canceled/hide
return
}
this.provider = new ethers.providers.JsonRpcProvider(value)
this.sendAsyncInternal(data, resolve, reject)
} else {
this.sendAsyncInternal(data, resolve, reject)
}
})
}
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 })
} catch (error) {
this.blocked = true
const modalContent: AlertModal = {
id: this.profile.name,
title: this.profile.displayName,
message: `Error while connecting to the provider: ${error.message}`,
}
this.call('notification', 'alert', modalContent)
await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' })
this.provider = null
setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm
reject(error)
}
} else {
const result = data.method === 'net_listening' ? 'canceled' : []
resolve({ jsonrpc: '2.0', result: result, id: data.id })
}
}
}

@ -4,6 +4,7 @@ import { AppModal, AlertModal, ModalTypes } from '@remix-ui/app'
import React from 'react' // eslint-disable-line
import { Blockchain } from '../../blockchain/blockchain'
import { ethers } from 'ethers'
import { AbstractProvider } from './abstract-provider'
const profile = {
name: 'hardhat-provider',
@ -14,41 +15,12 @@ const profile = {
version: packageJson.version
}
type JsonDataRequest = {
id: number,
jsonrpc: string // version
method: string,
params: Array<any>,
}
type JsonDataResult = {
id: number,
jsonrpc: string // version
result: any
}
type RejectRequest = (error: Error) => void
type SuccessRequest = (data: JsonDataResult) => void
export class HardhatProvider extends Plugin {
provider: ethers.providers.JsonRpcProvider
blocked: boolean
blockchain: Blockchain
target: String
export class HardhatProvider extends AbstractProvider {
constructor (blockchain) {
super(profile)
this.provider = null
this.blocked = false // used to block any call when trying to recover after a failed connection.
this.blockchain = blockchain
super(profile, blockchain, 'http://127.0.0.1:8545')
}
onDeactivation () {
this.provider = null
this.blocked = false
}
hardhatProviderDialogBody (): JSX.Element {
body (): JSX.Element {
return (
<div> Note: To run Hardhat network node on your system, go to hardhat project folder and run command:
<div className="border p-1">npx hardhat node</div>
@ -57,74 +29,4 @@ export class HardhatProvider extends Plugin {
</div>
)
}
sendAsync (data: JsonDataRequest): Promise<any> {
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: 'hardhatprovider',
title: 'Hardhat node request',
message: this.hardhatProviderDialogBody(),
modalType: ModalTypes.prompt,
okLabel: 'OK',
cancelLabel: 'Cancel',
okFn: (value: string) => {
setTimeout(() => resolve(value), 0)
},
cancelFn: () => {
setTimeout(() => reject(new Error('Canceled')), 0)
},
hideFn: () => {
setTimeout(() => reject(new Error('Hide')), 0)
},
defaultValue: 'http://127.0.0.1:8545'
}
this.call('notification', 'modal', modalContent)
})
})()
} catch (e) {
// the modal has been canceled/hide
return
}
this.provider = new ethers.providers.JsonRpcProvider(value)
this.sendAsyncInternal(data, resolve, reject)
} else {
this.sendAsyncInternal(data, resolve, reject)
}
})
}
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() !== 'Hardhat Provider' && 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 })
} catch (error) {
this.blocked = true
const modalContent: AlertModal = {
id: 'hardhatprovider',
title: 'Hardhat Provider',
message: `Error while connecting to the hardhat provider: ${error.message}`,
}
this.call('notification', 'alert', modalContent)
await this.call('udapp', 'setEnvironmentMode', { context: 'vm', fork: 'london' })
this.provider = null
setTimeout(_ => { this.blocked = false }, 1000) // we wait 1 second for letting remix to switch to vm
reject(error)
}
} else {
const result = data.method === 'net_listening' ? 'canceled' : []
resolve({ jsonrpc: '2.0', result: result, id: data.id })
}
}
}

@ -39,7 +39,6 @@ export class RunTab extends ViewPlugin {
this.el = document.createElement('div')
}
setupEvents () {
this.blockchain.events.on('newTransaction', (tx, receipt) => {
this.emit('newTransaction', tx, receipt)
@ -93,11 +92,14 @@ export class RunTab extends ViewPlugin {
return <div><RunTabUI plugin={this} /></div>
}
onReady (api) {
this.REACT_API = api
}
onInitDone () {
this.call('manager', 'activatePlugin', 'hardhat-provider')
}
writeFile (fileName, content) {
return this.call('fileManager', 'writeFile', fileName, content)
}

@ -8,7 +8,7 @@ const requiredModules = [ // services + layout views + system views
'manager', 'config', 'compilerArtefacts', 'compilerMetadata', 'contextualListener', 'editor', 'offsetToLineColumnConverter', 'network', 'theme',
'fileManager', 'contentImport', 'blockchain', 'web3Provider', 'scriptRunner', 'fetchAndCompile', 'mainPanel', 'hiddenPanel', 'sidePanel', 'menuicons',
'filePanel', 'terminal', 'settings', 'pluginManager', 'tabs', 'udapp', 'dGitProvider', 'solidity-logic', 'gistHandler', 'layout',
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'intelligentScriptExecutor']
'notification', 'permissionhandler', 'walkthrough', 'storage', 'restorebackupzip', 'link-libraries', 'deploy-libraries', 'hardhat-provider', 'intelligentScriptExecutor']
const dependentModules = ['git', 'hardhat', 'truffle', 'slither'] // module which shouldn't be manually activated (e.g git is activated by remixd)

@ -188,6 +188,7 @@ export const setGasFee = (value: number) => {
const addPluginProvider = (profile) => {
if (profile.kind === 'provider') {
console.log(profile);
((profile, app) => {
const web3Provider = {
async sendAsync (payload, callback) {
@ -232,8 +233,8 @@ export const setNetworkNameFromProvider = (networkName: string) => {
}
const addExternalProvider = (network) => {
console.log('adding ext provider', network)
dispatch(addProvider(network))
dispatch(displayPopUp(`${network.name} provider added`))
}
const removeExternalProvider = (name) => {

@ -61,6 +61,7 @@ export function RunTabUI (props: RunTabProps) {
useEffect(() => {
initRunTab(plugin)(dispatch)
plugin.onInitDone()
}, [plugin])
useEffect(() => {

@ -34,6 +34,7 @@ export class RunTab extends ViewPlugin {
udappUI: any;
renderComponent(): void;
onReady(api: any): void;
onInitDone(): void;
recorder: Recorder;
}
import { ViewPlugin } from "@remixproject/engine-web/lib/view";

Loading…
Cancel
Save