From d7d3b038c82c83e3ffc8b15af89f355b19f65abe Mon Sep 17 00:00:00 2001 From: ioedeveloper Date: Mon, 15 Nov 2021 17:01:44 +0100 Subject: [PATCH] setup environment list and events --- apps/remix-ide/src/app/udapp/run-tab.js | 23 --- .../run-tab/src/lib/actions/custom.ts | 106 +++++++++- .../run-tab/src/lib/actions/payload.ts | 37 +++- .../run-tab/src/lib/components/account.tsx | 58 ++++-- .../src/lib/components/environment.tsx | 39 ++-- .../run-tab/src/lib/components/network.tsx | 2 +- .../run-tab/src/lib/components/settingsUI.tsx | 46 +---- .../run-tab/src/lib/reducers/runTab.ts | 185 +++++++++++++++--- libs/remix-ui/run-tab/src/lib/run-tab.tsx | 26 +-- libs/remix-ui/run-tab/src/lib/types/index.ts | 14 +- 10 files changed, 375 insertions(+), 161 deletions(-) diff --git a/apps/remix-ide/src/app/udapp/run-tab.js b/apps/remix-ide/src/app/udapp/run-tab.js index c99bfc2493..d3fb7851ac 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.js +++ b/apps/remix-ide/src/app/udapp/run-tab.js @@ -222,29 +222,6 @@ export class RunTab extends ViewPlugin { this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.logCallback) this.renderRecorder(this.udappUI, this.fileManager, this.config, this.logCallback) this.renderRecorderCard() - - const addPluginProvider = (profile) => { - if (profile.kind === 'provider') { - ((profile, app) => { - const web3Provider = { - async sendAsync (payload, callback) { - try { - const result = await app.call(profile.name, 'sendAsync', payload) - callback(null, result) - } catch (e) { - callback(e) - } - } - } - app.blockchain.addProvider({ name: profile.displayName, provider: web3Provider }) - })(profile, this) - } - } - const removePluginProvider = (profile) => { - if (profile.kind === 'provider') this.blockchain.removeProvider(profile.displayName) - } - this.on('manager', 'pluginActivated', addPluginProvider.bind(this)) - this.on('manager', 'pluginDeactivated', removePluginProvider.bind(this)) return this.renderContainer() } diff --git a/libs/remix-ui/run-tab/src/lib/actions/custom.ts b/libs/remix-ui/run-tab/src/lib/actions/custom.ts index 8b1d8b838c..1100411043 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/custom.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/custom.ts @@ -3,7 +3,7 @@ import React from 'react' import * as ethJSUtil from 'ethereumjs-util' import Web3 from 'web3' import { shortenAddress } from '@remix-ui/helper' -import { fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, setGasLimit, setSelectedAccount, setSendUnit, setSendValue } from './payload' +import { addProvider, fetchAccountsListFailed, fetchAccountsListRequest, fetchAccountsListSuccess, removeProvider, setExecutionEnvironment, setGasLimit, setNetworkName, setSelectedAccount, setSendUnit, setSendValue } from './payload' import { runTabInitialState, runTabReducer } from '../reducers/runTab' export function useRunTabPlugin (plugin) { @@ -20,6 +20,26 @@ export function useRunTabPlugin (plugin) { updateAccountBalances() }) + plugin.blockchain.event.register('contextChanged', (context, silent) => { + setFinalContext() + }) + + plugin.blockchain.event.register('networkStatus', ({ error, network }) => { + if (error) { + const netUI = 'can\'t detect network ' + setNetworkNameFromProvider(netUI) + + return + } + const networkProvider = plugin.networkModule.getNetworkProvider.bind(plugin.networkModule) + const netUI = (networkProvider() !== 'vm') ? `${network.name} (${network.id || '-'}) network` : '' + + setNetworkNameFromProvider(netUI) + }) + + plugin.blockchain.event.register('addProvider', provider => addExternalProvider(provider)) + plugin.blockchain.event.register('removeProvider', name => removeExternalProvider(name)) + plugin.blockchain.resetAndInit(plugin.config, { getAddress: (cb) => { cb(null, runTab.accounts.selectedAccount) @@ -42,7 +62,6 @@ export function useRunTabPlugin (plugin) { } } }) - console.log('called: reset and init') } const updateAccountBalances = () => { @@ -56,6 +75,7 @@ export function useRunTabPlugin (plugin) { accounts[value] = updated }) }) + dispatch(fetchAccountsListSuccess(accounts)) } const fillAccountsList = async () => { @@ -64,7 +84,18 @@ export function useRunTabPlugin (plugin) { const promise = plugin.blockchain.getAccounts() promise.then((accounts: string[]) => { - dispatch(fetchAccountsListSuccess(accounts)) + const loadedAccounts = {} + + if (!accounts) accounts = [] + accounts.forEach((account) => { + plugin.blockchain.getBalanceInEther(account, (err, balance) => { + if (err) return + const updated = shortenAddress(account, balance) + + loadedAccounts[account] = updated + }) + }) + dispatch(fetchAccountsListSuccess(loadedAccounts)) }).catch((e) => { dispatch(fetchAccountsListFailed(e.message)) }) @@ -85,5 +116,72 @@ export function useRunTabPlugin (plugin) { dispatch(setGasLimit(value)) } - return { runTab, setupEvents, fillAccountsList, setAccount, setUnit, setGasFee } + const addPluginProvider = (profile) => { + if (profile.kind === 'provider') { + ((profile, app) => { + const web3Provider = { + async sendAsync (payload, callback) { + try { + const result = await app.call(profile.name, 'sendAsync', payload) + callback(null, result) + } catch (e) { + callback(e) + } + } + } + app.blockchain.addProvider({ name: profile.displayName, provider: web3Provider }) + })(profile, plugin) + } + } + + const removePluginProvider = (profile) => { + if (profile.kind === 'provider') plugin.blockchain.removeProvider(profile.displayName) + } + + const setFinalContext = () => { + // set the final context. Cause it is possible that this is not the one we've originaly selected + const value = _getProviderDropdownValue() + + setExecEnv(value) + // this.event.trigger('clearInstance', []) + } + + const _getProviderDropdownValue = (): string => { + const provider = plugin.blockchain.getProvider() + const fork = plugin.blockchain.getCurrentFork() + + return provider === 'vm' ? provider + '-' + fork : provider + } + + const setExecEnv = (env: string) => { + dispatch(setExecutionEnvironment(env)) + } + + const setNetworkNameFromProvider = (networkName: string) => { + dispatch(setNetworkName(networkName)) + } + + const addExternalProvider = (network) => { + dispatch(addProvider(network)) + // addTooltip(yo`${network.name} provider added`) + } + + const removeExternalProvider = (name) => { + dispatch(removeProvider(name)) + } + + const setExecutionContext = (executionContext: { context: string, fork: string }) => { + plugin.blockchain.changeExecutionContext(executionContext, () => { + // modalDialogCustom.prompt('External node request', this.web3ProviderDialogBody(), 'http://127.0.0.1:8545', (target) => { + // this.blockchain.setProviderFromEndpoint(target, context, (alertMsg) => { + // if (alertMsg) addTooltip(alertMsg) + // setFinalContext() + // }) + // }, this.setFinalContext.bind(this)) + // }, (alertMsg) => { + // addTooltip(alertMsg) + }, setFinalContext()) + } + + return { runTab, setupEvents, fillAccountsList, setAccount, setUnit, setGasFee, addPluginProvider, removePluginProvider, setExecEnv, setFinalContext, setExecutionContext } } diff --git a/libs/remix-ui/run-tab/src/lib/actions/payload.ts b/libs/remix-ui/run-tab/src/lib/actions/payload.ts index 8d7e29efd6..5387638cc0 100644 --- a/libs/remix-ui/run-tab/src/lib/actions/payload.ts +++ b/libs/remix-ui/run-tab/src/lib/actions/payload.ts @@ -5,7 +5,7 @@ export const fetchAccountsListRequest = () => { } } -export const fetchAccountsListSuccess = (accounts: string[]) => { +export const fetchAccountsListSuccess = (accounts: Record) => { return { type: 'FETCH_ACCOUNTS_LIST_SUCCESS', payload: accounts @@ -46,3 +46,38 @@ export const setGasLimit = (gasLimit: number) => { payload: gasLimit } } + +export const setExecutionEnvironment = (executionEnvironment: string) => { + return { + type: 'SET_EXECUTION_ENVIRONMENT', + payload: executionEnvironment + } +} + +export const setPersonalMode = (mode: boolean) => { + return { + type: 'SET_PERSONAL_MODE', + payload: mode + } +} + +export const setNetworkName = (networkName: string) => { + return { + type: 'SET_NETWORK_NAME', + payload: networkName + } +} + +export const addProvider = (provider: string) => { + return { + type: 'ADD_PROVIDER', + payload: provider + } +} + +export const removeProvider = (provider: string) => { + return { + type: 'REMOVE_PROVIDER', + payload: provider + } +} diff --git a/libs/remix-ui/run-tab/src/lib/components/account.tsx b/libs/remix-ui/run-tab/src/lib/components/account.tsx index 449d4c6448..527aad815b 100644 --- a/libs/remix-ui/run-tab/src/lib/components/account.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/account.tsx @@ -1,42 +1,58 @@ // eslint-disable-next-line no-use-before-define -import React, { useEffect, useRef } from 'react' +import React, { useEffect, useState } from 'react' import { CopyToClipboard } from '@remix-ui/clipboard' import { AccountProps } from '../types' export function AccountUI (props: AccountProps) { const { selectedAccount, loadedAccounts } = props.accounts const accounts = Object.keys(loadedAccounts) - const plusBtn = useRef(null) - const plusTitle = useRef(null) + const [plusOpt, setPlusOpt] = useState({ + classList: '', + title: '' + }) useEffect(() => { if (!selectedAccount && accounts.length > 0) props.setAccount(accounts[0]) }, [accounts, selectedAccount]) - const updatePlusButton = () => { - // enable/disable + button + useEffect(() => { switch (props.selectExEnv) { case 'injected': - plusBtn.current.classList.add('udapp_disableMouseEvents') - plusTitle.current.title = "Unfortunately it's not possible to create an account using injected web3. Please create the account directly from your provider (i.e metamask or other of the same type)." - + setPlusOpt({ + classList: 'udapp_disableMouseEvents', + title: "Unfortunately it's not possible to create an account using injected web3. Please create the account directly from your provider (i.e metamask or other of the same type)." + }) break - case 'vm': - plusBtn.current.classList.remove('udapp_disableMouseEvents') - plusTitle.current.title = 'Create a new account' + case 'vm': + setPlusOpt({ + classList: '', + title: 'Create a new account' + }) break case 'web3': - this.onPersonalChange() - + if (!props.personalMode) { + setPlusOpt({ + classList: 'disableMouseEvents', + title: 'Creating an account is possible only in Personal mode. Please go to Settings to enable it.' + }) + } else { + setPlusOpt({ + classList: '', + title: 'Create a new account' + }) + } break - default: { - plusBtn.current.classList.add('udapp_disableMouseEvents') - plusTitle.current.title = `Unfortunately it's not possible to create an account using an external wallet (${props.selectExEnv}).` - } + + default: + setPlusOpt({ + classList: 'disableMouseEvents', + title: `Unfortunately it's not possible to create an account using an external wallet (${props.selectExEnv}).` + }) } - } + // this._deps.config.get('settings/personal-mode') + }, [props.selectExEnv, props.personalMode]) const newAccount = () => { // dispatch createNewBlockchainAccount @@ -110,14 +126,14 @@ export function AccountUI (props: AccountProps) {
diff --git a/libs/remix-ui/run-tab/src/lib/components/environment.tsx b/libs/remix-ui/run-tab/src/lib/components/environment.tsx index 84685ef58f..e9ba916433 100644 --- a/libs/remix-ui/run-tab/src/lib/components/environment.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/environment.tsx @@ -1,10 +1,8 @@ // eslint-disable-next-line no-use-before-define -import React, { useState } from 'react' +import React from 'react' import { EnvironmentProps } from '../types' export function EnvironmentUI (props: EnvironmentProps) { - const [exEnv, setExEnv] = useState('') - // setDropdown (selectExEnv) { // this.selectExEnv = selectExEnv @@ -41,33 +39,28 @@ export function EnvironmentUI (props: EnvironmentProps) { // } const handleChangeExEnv = (env: string) => { - setExEnv(env) - props.updateExEnv(env) + props.setExecEnv(env) + const fork = provider.getAttribute('fork') // can be undefined if connected to an external source (web3 provider / injected) + let context = provider.value + context = context.startsWith('vm') ? 'vm' : context // context has to be 'vm', 'web3' or 'injected' + this.setExecutionContext({ context, fork }) } + return (
- { handleChangeExEnv(e.target.value) }}> + { + props.providerList.map((provider) => + + ) + }
diff --git a/libs/remix-ui/run-tab/src/lib/components/network.tsx b/libs/remix-ui/run-tab/src/lib/components/network.tsx index f33e568e19..3a7a9c7480 100644 --- a/libs/remix-ui/run-tab/src/lib/components/network.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/network.tsx @@ -8,7 +8,7 @@ export function NetworkUI (props: NetworkProps) {
- + { props.networkName }
) diff --git a/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx b/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx index 87f127fbb3..a1e72fd470 100644 --- a/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/settingsUI.tsx @@ -77,25 +77,6 @@ export function SettingsUI (props: SettingsProps) { // return provider === 'vm' ? provider + '-' + fork : provider // } - // setFinalContext () { - // // set the final context. Cause it is possible that this is not the one we've originaly selected - // this.selectExEnv.value = this._getProviderDropdownValue() - // this.event.trigger('clearInstance', []) - // this.updatePlusButton() - // } - - // onPersonalChange () { - // const plusBtn = document.getElementById('remixRunPlus') - // const plusTitle = document.getElementById('remixRunPlusWraper') - // if (!this._deps.config.get('settings/personal-mode')) { - // plusBtn.classList.add(css.disableMouseEvents) - // plusTitle.title = 'Creating an account is possible only in Personal mode. Please go to Settings to enable it.' - // } else { - // plusBtn.classList.remove(css.disableMouseEvents) - // plusTitle.title = 'Create a new account' - // } - // } - // getSelectedAccount () { // return this.el.querySelector('#txorigin').selectedOptions[0].value // } @@ -105,31 +86,10 @@ export function SettingsUI (props: SettingsProps) { // } return ( - // this.blockchain.event.register('contextChanged', (context, silent) => { - // this.setFinalContext() - // }) - - // this.blockchain.event.register('networkStatus', ({ error, network }) => { - // if (error) { - // this.netUI.innerHTML = 'can\'t detect network ' - // return - // } - // const networkProvider = this._components.networkModule.getNetworkProvider.bind(this._components.networkModule) - // this.netUI.innerHTML = (networkProvider() !== 'vm') ? `${network.name} (${network.id || '-'}) network` : '' - // }) - - // setInterval(() => { - // this.fillAccountsList() - // }, 1000) - - // this.el = el - - // this.fillAccountsList() - // return el
- - - + + +
diff --git a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts index d6606a2c2f..d73b945767 100644 --- a/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts +++ b/libs/remix-ui/run-tab/src/lib/reducers/runTab.ts @@ -5,7 +5,7 @@ interface Action { export interface RunTabState { accounts: { - loadedAccounts: Record, + loadedAccounts: Record, isRequesting: boolean, isSuccessful: boolean, error: string, @@ -13,7 +13,23 @@ export interface RunTabState { }, sendValue: string, sendUnit: 'ether' | 'finney' | 'gwei' | 'wei', - gasLimit: number + gasLimit: number, + selectExEnv: string, + personalMode: boolean, + networkName: string, + providers: { + providerList: { + id?: string, + dataId?: string, + title?: string, + value: string, + fork?: string + content: string + }[], + isRequesting: boolean, + isSuccessful: boolean, + error: string + } } export const runTabInitialState: RunTabState = { @@ -26,7 +42,43 @@ export const runTabInitialState: RunTabState = { }, sendValue: '0', sendUnit: 'ether', - gasLimit: 3000000 + gasLimit: 3000000, + selectExEnv: 'vm', + personalMode: false, + networkName: '', + providers: { + providerList: [{ + id: 'vm-mode-london', + dataId: 'settingsVMLondonMode', + title: 'Execution environment does not connect to any node, everything is local and in memory only.', + value: 'vm-london', + fork: 'london', + content: 'JavaScript VM (London)' + }, { + id: 'vm-mode-berlin', + dataId: 'settingsVMBerlinMode', + title: 'Execution environment does not connect to any node, everything is local and in memory only.', + value: 'vm-berlin', + fork: 'berlin', + content: 'JavaScript VM (Berlin)' + }, { + id: 'injected-mode', + dataId: 'settingsInjectedMode', + title: 'Execution environment has been provided by Metamask or similar provider.', + value: 'injected', + content: 'Injected Web3' + }, { + id: 'web3-mode', + dataId: 'settingsWeb3Mode', + title: `Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse! + If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http.`, + value: 'web3', + content: 'Web3 Provider' + }], + isRequesting: false, + isSuccessful: false, + error: null + } } export const runTabReducer = (state: RunTabState = runTabInitialState, action: Action) => { @@ -42,22 +94,24 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } } + case 'FETCH_ACCOUNTS_LIST_SUCCESS': { - const payload: string[] = action.payload as string[] + const payload: Record = action.payload return { ...state, accounts: { ...state.accounts, - loadedAccounts: resolveAccountsList(state, payload), + loadedAccounts: payload, isSuccessful: true, isRequesting: false, error: null } } } + case 'FETCH_ACCOUNTS_LIST_FAILED': { - const payload = action.payload as string + const payload: string = action.payload return { ...state, @@ -69,16 +123,18 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } } + case 'SET_SEND_VALUE': { - const payload = action.payload as string + const payload: string = action.payload return { ...state, sendValue: payload } } + case 'SET_SELECTED_ACCOUNT': { - const payload = action.payload as string + const payload: string = action.payload return { ...state, @@ -88,8 +144,9 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } } } + case 'SET_SEND_UNIT': { - const payload = action.payload as 'ether' | 'finney' | 'gwei' | 'wei' + const payload: 'ether' | 'finney' | 'gwei' | 'wei' = action.payload return { ...state, @@ -98,33 +155,107 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A } case 'SET_GAS_LIMIT': { - const payload = action.payload as number + const payload: number = action.payload return { ...state, gasLimit: payload } } - default: - return state - } -} -// TODO: unclear what's the goal of accountListCallId, feels like it can be simplified -const resolveAccountsList = async (state: RunTabState, accounts: string[]) => { - const loadedAccounts = state.accounts.loadedAccounts + case 'SET_EXECUTION_ENVIRONMENT': { + const payload: string = action.payload - if (!accounts) accounts = [] - for (const loadedaddress in loadedAccounts) { - if (accounts.indexOf(loadedaddress) === -1) { - delete loadedAccounts[loadedaddress] + return { + ...state, + selectExEnv: payload + } } - } - for (const i in accounts) { - const address = accounts[i] - if (!loadedAccounts[address]) { - loadedAccounts[address] = 1 + + case 'SET_PERSONAL_MODE': { + const payload: boolean = action.payload + + return { + ...state, + personalMode: payload + } + } + + case 'SET_NETWORK_NAME': { + const payload: string = action.payload + + return { + ...state, + networkName: payload + } + } + + case 'FETCH_PROVIDER_LIST_REQUEST': { + return { + ...state, + providers: { + ...state.providers, + isRequesting: true, + isSuccessful: false, + error: null + } + } + } + + case 'FETCH_PROVIDER_LIST_SUCCESS': { + const payload: Record = action.payload + + return { + ...state, + providers: { + ...state.providers, + providerList: payload, + isSuccessful: true, + isRequesting: false, + error: null + } + } + } + + case 'FETCH_PROVIDER_LIST_FAILED': { + const payload: string = action.payload + + return { + ...state, + providers: { + ...state.providers, + isRequesting: false, + isSuccessful: false, + error: payload + } + } + } + + case 'ADD_PROVIDER': { + const payload: string = action.payload + + return { + ...state, + providers: { + ...state.providers, + providerList: { ...state.providers.providerList, payload } + } + } } + + case 'REMOVE_PROVIDER': { + const payload: string = action.payload + + return { + ...state, + providers: { + ...state.providers, + providerList: delete state.providers.providerList[payload] ? state.providers.providerList : state.providers.providerList + } + } + } + + default: + return state } - return loadedAccounts } diff --git a/libs/remix-ui/run-tab/src/lib/run-tab.tsx b/libs/remix-ui/run-tab/src/lib/run-tab.tsx index 9d311dfe14..72b9a0fbb0 100644 --- a/libs/remix-ui/run-tab/src/lib/run-tab.tsx +++ b/libs/remix-ui/run-tab/src/lib/run-tab.tsx @@ -1,5 +1,5 @@ // eslint-disable-next-line no-use-before-define -import React, { useState, useEffect } from 'react' +import React, { useEffect } from 'react' import { useRunTabPlugin } from './actions/custom' import { ContractDropdownUI } from './components/contractDropdownUI' import { InstanceContainerUI } from './components/instanceContainerUI' @@ -9,27 +9,27 @@ import './css/run-tab.css' import { RunTabProps } from './types' export function RunTabUI (props: RunTabProps) { - const { runTab, setupEvents, fillAccountsList, setAccount, setUnit, setGasFee } = useRunTabPlugin(props.plugin) - const [selectExEnv, setSelectExEnv] = useState('') + const { runTab, setupEvents, fillAccountsList, setAccount, setUnit, setGasFee, addPluginProvider, removePluginProvider, setExecEnv, setExecutionContext } = useRunTabPlugin(props.plugin) useEffect(() => { setupEvents() - - setInterval(() => { + // setInterval(() => { + // fillAccountsList() + // }, 1000) + // fillAccountsList() + setTimeout(() => { fillAccountsList() - }, 1000) - fillAccountsList() - }, []) + }, 0) - const updateExEnv = (env: string) => { - setSelectExEnv(env) - } + props.plugin.on('manager', 'pluginActivated', addPluginProvider.bind(props.plugin)) + props.plugin.on('manager', 'pluginDeactivated', removePluginProvider.bind(props.plugin)) + }, []) return (
- - + +
diff --git a/libs/remix-ui/run-tab/src/lib/types/index.ts b/libs/remix-ui/run-tab/src/lib/types/index.ts index 0dd3da14d3..9fae57d56c 100644 --- a/libs/remix-ui/run-tab/src/lib/types/index.ts +++ b/libs/remix-ui/run-tab/src/lib/types/index.ts @@ -4,7 +4,6 @@ export interface RunTabProps { export interface SettingsProps { selectExEnv: string, - updateExEnv: (env: string) => void, accounts: { loadedAccounts: Record, selectedAccount: string, @@ -17,15 +16,19 @@ export interface SettingsProps { sendValue: string, sendUnit: string, gasLimit: number, - setGasFee: (value: number) => void + setGasFee: (value: number) => void, + setExecEnv: (env: string) => void, + personalMode: boolean, + networkName: string } export interface EnvironmentProps { - updateExEnv: (env: string) => void + setExecEnv: (env: string) => void, + selectedEnv: string } export interface NetworkProps { - + networkName: string } export interface AccountProps { @@ -37,7 +40,8 @@ export interface AccountProps { isSuccessful: boolean, error: string }, - setAccount: (account: string) => void + setAccount: (account: string) => void, + personalMode: boolean } export interface GasPriceProps {