diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 338af4bbec..e0aff565c4 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -20,6 +20,8 @@ import Registry from './app/state/registry' import { ConfigPlugin } from './app/plugins/config' import { Layout } from './app/panels/layout' import { ModalPlugin } from './app/plugins/modal' +import { Blockchain } from './blockchain/blockchain.js' +import { HardhatProvider } from './app/tabs/hardhat-provider' const isElectron = require('is-electron') @@ -28,7 +30,6 @@ const remixLib = require('@remix-project/remix-lib') const QueryParams = require('./lib/query-params') const Storage = remixLib.Storage const RemixDProvider = require('./app/files/remixDProvider') -const HardhatProvider = require('./app/tabs/hardhat-provider') const Config = require('./config') const FileManager = require('./app/files/fileManager') @@ -37,8 +38,6 @@ const DGitProvider = require('./app/files/dgitProvider') const WorkspaceFileProvider = require('./app/files/workspaceFileProvider') const toolTip = require('./app/ui/tooltip') -const Blockchain = require('./blockchain/blockchain.js') - const PluginManagerComponent = require('./app/components/plugin-manager-component') const CompileTab = require('./app/tabs/compile-tab') diff --git a/apps/remix-ide/src/app/tabs/hardhat-provider.js b/apps/remix-ide/src/app/tabs/hardhat-provider.js deleted file mode 100644 index 75c20a90cd..0000000000 --- a/apps/remix-ide/src/app/tabs/hardhat-provider.js +++ /dev/null @@ -1,82 +0,0 @@ -import * as packageJson from '../../../../../package.json' -import { Plugin } from '@remixproject/engine' -import Web3 from 'web3' -const yo = require('yo-yo') -const modalDialogCustom = require('../ui/modal-dialog-custom') - -const profile = { - name: 'hardhat-provider', - displayName: 'Hardhat Provider', - kind: 'provider', - description: 'Hardhat provider', - methods: ['sendAsync'], - version: packageJson.version -} - -export default class HardhatProvider extends Plugin { - 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 - } - - onDeactivation () { - this.provider = null - this.blocked = false - } - - hardhatProviderDialogBody () { - return yo` -
- Note: To run Hardhat network node on your system, go to hardhat project folder and run command: -
npx hardhat node
-
- For more info, visit: Hardhat Documentation -

- Hardhat JSON-RPC Endpoint -
- ` - } - - sendAsync (data) { - return new Promise((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) { - modalDialogCustom.prompt('Hardhat node request', this.hardhatProviderDialogBody(), 'http://127.0.0.1:8545', (target) => { - this.provider = new Web3.providers.HttpProvider(target) - this.sendAsyncInternal(data, resolve, reject) - }, () => { - this.sendAsyncInternal(data, resolve, reject) - }) - } else { - this.sendAsyncInternal(data, resolve, reject) - } - }) - } - - sendAsyncInternal (data, resolve, reject) { - 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 !!')) - this.provider[this.provider.sendAsync ? 'sendAsync' : 'send'](data, async (error, message) => { - if (error) { - this.blocked = true - modalDialogCustom.alert('Hardhat Provider', `Error while connecting to the hardhat provider: ${error.message}`) - 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 - return reject(error) - } - resolve(message) - }) - } else { - const result = data.method === 'net_listening' ? 'canceled' : [] - resolve({ jsonrpc: '2.0', result: result, id: data.id }) - } - } -} - -module.exports = HardhatProvider diff --git a/apps/remix-ide/src/app/tabs/hardhat-provider.tsx b/apps/remix-ide/src/app/tabs/hardhat-provider.tsx new file mode 100644 index 0000000000..abb5eabddf --- /dev/null +++ b/apps/remix-ide/src/app/tabs/hardhat-provider.tsx @@ -0,0 +1,128 @@ +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, +} + +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 + + 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 + } + + onDeactivation () { + this.provider = null + this.blocked = false + } + + hardhatProviderDialogBody (): JSX.Element { + return (
Note: To run Hardhat network node on your system, go to hardhat project folder and run command: +
npx hardhat node
+ For more info, visit: Hardhat Documentation + Hardhat JSON-RPC Endpoint +
) + } + + sendAsync (data: JsonDataRequest): Promise { + 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: 'harrhatprovider', + 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('modal', '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 { + 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: 'harrhatprovider', + title: 'Hardhat Provider', + message: `Error while connecting to the hardhat provider: ${error.message}`, + } + this.call('modal', '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 }) + } + } +} \ No newline at end of file diff --git a/apps/remix-ide/src/blockchain/blockchain.js b/apps/remix-ide/src/blockchain/blockchain.js index f280e47d8b..486c3041f6 100644 --- a/apps/remix-ide/src/blockchain/blockchain.js +++ b/apps/remix-ide/src/blockchain/blockchain.js @@ -23,7 +23,7 @@ const profile = { version: packageJson.version } -class Blockchain extends Plugin { +export class Blockchain extends Plugin { // NOTE: the config object will need to be refactored out in remix-lib constructor (config) { super(profile) @@ -545,5 +545,3 @@ class Blockchain extends Plugin { }) } } - -module.exports = Blockchain diff --git a/libs/remix-ui/app/src/index.ts b/libs/remix-ui/app/src/index.ts index d02ade520c..e706f1ad94 100644 --- a/libs/remix-ui/app/src/index.ts +++ b/libs/remix-ui/app/src/index.ts @@ -3,4 +3,4 @@ export { dispatchModalContext } from './lib/remix-app/context/context' export { ModalProvider } from './lib/remix-app/context/provider' export { AppModal } from './lib/remix-app/interface/index' export { AlertModal } from './lib/remix-app/interface/index' -export * from './lib/remix-app/types/index' +export { ModalTypes } from './lib/remix-app/types/index'