refactor & allow saving already forked state

pull/5772/head
yann300 3 weeks ago
parent 9d62a2fed8
commit 61e568ad9a
  1. 40
      apps/remix-ide/src/app/udapp/run-tab.tsx
  2. 18
      apps/remix-ide/src/blockchain/blockchain.tsx
  3. 14
      libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx
  4. 14
      libs/remix-ui/environment-explorer/src/lib/types/index.ts
  5. 29
      libs/remix-ui/run-tab/src/lib/components/environment.tsx
  6. 7
      libs/remix-ui/run-tab/src/lib/types/index.ts

@ -8,6 +8,7 @@ import { InjectedCustomProvider } from '../providers/injected-custom-provider'
import * as packageJson from '../../../../../package.json'
import { EventManager } from '@remix-project/remix-lib'
import type { Blockchain } from '../../blockchain/blockchain'
import { ProviderConfig } from '@remix-ui/environment-explorer'
import type { CompilerArtefacts } from '@remix-project/core-plugin'
import { ForkedVMStateProvider } from '../providers/vm-provider'
import { Recorder } from '../tabs/runTab/model/recorder'
@ -179,7 +180,7 @@ export class RunTab extends ViewPlugin {
'foundry-provider': ['assets/img/foundry.png']
}
const addProvider = async (position, name, displayName, isInjected, isVM, isForkedState, fork = '', dataId = '', title = '', forkedVM = false) => {
const addProvider = async (position: number, name: string, displayName: string, providerConfig: ProviderConfig, fork = '', dataId = '', title = '') => {
await this.call('blockchain', 'addProvider', {
position,
options: {},
@ -189,10 +190,7 @@ export class RunTab extends ViewPlugin {
description: descriptions[name] || displayName,
logos: logos[name],
fork,
isInjected,
isForkedVM: forkedVM,
isVM,
isForkedState,
config: providerConfig,
title,
init: async function () {
const options = await udapp.call(name, 'init')
@ -208,13 +206,13 @@ export class RunTab extends ViewPlugin {
const addCustomInjectedProvider = async (position, event, name, displayName, networkId, urls, nativeCurrency?) => {
// name = `${name} through ${event.detail.info.name}`
await this.engine.register([new InjectedCustomProvider(event.detail.provider, name, displayName, networkId, urls, nativeCurrency)])
await addProvider(position, name, displayName + ' - ' + event.detail.info.name, true, false, false)
await addProvider(position, name, displayName + ' - ' + event.detail.info.name, { isInjected: true, isVM: false, isRpcForkedState: false })
}
const registerInjectedProvider = async (event) => {
const name = 'injected-' + event.detail.info.name
const displayName = 'Injected Provider - ' + event.detail.info.name
await this.engine.register([new InjectedProviderDefault(event.detail.provider, name)])
await addProvider(0, name, displayName, true, false, false)
await addProvider(0, name, displayName, { isInjected: true, isVM: false, isRpcForkedState: false })
if (event.detail.info.name === 'MetaMask') {
await addCustomInjectedProvider(7, event, 'injected-metamask-optimism', 'L2 - Optimism', '0xa', ['https://mainnet.optimism.io'])
@ -251,14 +249,14 @@ export class RunTab extends ViewPlugin {
// VM
const titleVM = 'Execution environment is local to Remix. Data is only saved to browser memory and will vanish upon reload.'
await addProvider(1, 'vm-cancun', 'Remix VM (Cancun)', false, true, false, 'cancun', 'settingsVMCancunMode', titleVM)
await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', false, true, false, 'shanghai', 'settingsVMShanghaiMode', titleVM)
await addProvider(51, 'vm-paris', 'Remix VM (Paris)', false, true, false, 'paris', 'settingsVMParisMode', titleVM)
await addProvider(52, 'vm-london', 'Remix VM (London)', false, true, false, 'london', 'settingsVMLondonMode', titleVM)
await addProvider(53, 'vm-berlin', 'Remix VM (Berlin)', false, true, false, 'berlin', 'settingsVMBerlinMode', titleVM)
await addProvider(2, 'vm-mainnet-fork', 'Remix VM - Mainnet fork', false, true, false, 'cancun', 'settingsVMMainnetMode', titleVM, true)
await addProvider(3, 'vm-sepolia-fork', 'Remix VM - Sepolia fork', false, true, false, 'cancun', 'settingsVMSepoliaMode', titleVM, true)
await addProvider(4, 'vm-custom-fork', 'Remix VM - Custom fork', false, true, false, '', 'settingsVMCustomMode', titleVM, true)
await addProvider(1, 'vm-cancun', 'Remix VM (Cancun)', { isInjected: false, isVM: true, isRpcForkedState: false, statePath: '.states/vm-cancun/state.json' }, 'cancun', 'settingsVMCancunMode', titleVM)
await addProvider(50, 'vm-shanghai', 'Remix VM (Shanghai)', { isInjected: false, isVM: true, isRpcForkedState: false, statePath: '.states/vm-shanghai/state.json' }, 'shanghai', 'settingsVMShanghaiMode', titleVM)
await addProvider(51, 'vm-paris', 'Remix VM (Paris)', { isInjected: false, isVM: true, isRpcForkedState: false, statePath: '.states/vm-paris/state.json' }, 'paris', 'settingsVMParisMode', titleVM)
await addProvider(52, 'vm-london', 'Remix VM (London)', { isInjected: false, isVM: true, isRpcForkedState: false, statePath: '.states/vm-london/state.json' }, 'london', 'settingsVMLondonMode', titleVM)
await addProvider(53, 'vm-berlin', 'Remix VM (Berlin)', { isInjected: false, isVM: true, isRpcForkedState: false, statePath: '.states/vm-berlin/state.json' }, 'berlin', 'settingsVMBerlinMode', titleVM)
await addProvider(2, 'vm-mainnet-fork', 'Remix VM - Mainnet fork', { isInjected: false, isVM: true, isRpcForkedState: true }, 'cancun', 'settingsVMMainnetMode', titleVM)
await addProvider(3, 'vm-sepolia-fork', 'Remix VM - Sepolia fork', { isInjected: false, isVM: true, isRpcForkedState: true }, 'cancun', 'settingsVMSepoliaMode', titleVM)
await addProvider(4, 'vm-custom-fork', 'Remix VM - Custom fork', { isInjected: false, isVM: true, isRpcForkedState: true }, '', 'settingsVMCustomMode', titleVM)
// Forked VM States
const addFVSProvider = async(stateFilePath, pos) => {
@ -280,7 +278,7 @@ export class RunTab extends ViewPlugin {
version: packageJson.version
}, this.blockchain, stateDetail.forkName)
this.engine.register(fvsProvider)
await addProvider(pos, providerName, stateDetail.stateName, false, false, true, stateDetail.forkName)
await addProvider(pos, providerName, stateDetail.stateName, { isInjected: false, isVM: true, isRpcForkedState: false, isVMStateForked: true, statePath: `.states/forked_states/${stateDetail.stateName}.json` }, stateDetail.forkName)
}
this.on('filePanel', 'workspaceInitializationCompleted', async () => {
@ -302,13 +300,13 @@ export class RunTab extends ViewPlugin {
})
// wallet connect
await addProvider(6, 'walletconnect', 'WalletConnect', false, false, false)
await addProvider(6, 'walletconnect', 'WalletConnect', { isInjected: false, isVM: false, isRpcForkedState: false })
// external provider
await addProvider(10, 'basic-http-provider', 'Custom - External Http Provider', false, false, false)
await addProvider(20, 'hardhat-provider', 'Dev - Hardhat Provider', false, false, false)
await addProvider(21, 'ganache-provider', 'Dev - Ganache Provider', false, false, false)
await addProvider(22, 'foundry-provider', 'Dev - Foundry Provider', false, false, false)
await addProvider(10, 'basic-http-provider', 'Custom - External Http Provider', { isInjected: false, isVM: false, isRpcForkedState: false })
await addProvider(20, 'hardhat-provider', 'Dev - Hardhat Provider', { isInjected: false, isVM: false, isRpcForkedState: false })
await addProvider(21, 'ganache-provider', 'Dev - Ganache Provider', { isInjected: false, isVM: false, isRpcForkedState: false })
await addProvider(22, 'foundry-provider', 'Dev - Foundry Provider', { isInjected: false, isVM: false, isRpcForkedState: false })
// register injected providers

@ -12,6 +12,8 @@ import { NodeProvider } from './providers/node'
import { execution, EventManager, helpers } from '@remix-project/remix-lib'
import { etherScanLink } from './helper'
import { logBuilder, cancelUpgradeMsg, cancelProxyMsg, addressToString } from '@remix-ui/helper'
import { Provider } from '@remix-ui/environment-explorer'
const { txFormat, txExecution, typeConversion, txListener: Txlistener, TxRunner, TxRunnerWeb3, txHelper } = execution
const { txResultHelper } = helpers
const { resultToRemixTx } = txResultHelper
@ -44,6 +46,15 @@ export type Transaction = {
timestamp?: number
}
/*
export type ProviderConfig = {
isVM: boolean
isInjected: boolean
isRpcForkedState?: boolean
isVMStateForked?: boolean
statePath?: string
}
export type Provider = {
options: { [key: string]: string }
dataId: string
@ -53,16 +64,13 @@ export type Provider = {
logos?: string[],
fork: string
description?: string
isInjected: boolean
isVM: boolean
isForkedState: boolean
isForkedVM: boolean
config: ProviderConfig
title: string
init: () => Promise<void>
provider:{
sendAsync: (payload: any) => Promise<void>
}
}
}*/
export class Blockchain extends Plugin {
active: boolean

@ -9,19 +9,19 @@ const defaultSections: environmentExplorerUIGridSections = {
title: 'Deploy using a Browser Extension.',
keywords: ['Injected'],
providers: [],
filterFn: (provider) => provider.isInjected
filterFn: (provider) => provider.config.isInjected
},
'Remix VMs': {
title: 'Deploy to an In-browser Virtual Machine.',
keywords: ['Remix VMs'],
providers: [],
filterFn: (provider) => provider.isVM && !provider.isForkedVM
filterFn: (provider) => provider.config.isVM && !provider.config.isVMStateForked && !provider.config.isRpcForkedState
},
'Forked States': {
title: 'Deploy to an In-browser Forked State.',
keywords: ['Forked State'],
providers: [],
filterFn: (provider) => provider.isForkedState,
filterFn: (provider) => provider.config.isVMStateForked,
descriptionFn: (provider) => {
const { latestBlock, timestamp } = JSON.parse(provider.description)
return (
@ -38,16 +38,16 @@ const defaultSections: environmentExplorerUIGridSections = {
}
},
'Remix forked VMs': {
title: 'Deploy to a Remix forked Virtual Machine.',
title: 'Deploy to a Live forked Virtual Machine.',
keywords: ['Remix forked VMs'],
providers: [],
filterFn: (provider) => provider.isForkedVM
filterFn: (provider) => provider.config.isRpcForkedState
},
'Externals': {
title: 'Deploy to an external Provider.',
keywords: ['Externals'],
providers: [],
filterFn: (provider) => (!provider.isInjected && !provider.isVM && !provider.isForkedState && !provider.isForkedVM)
filterFn: (provider) => (!provider.config.isInjected && !provider.config.isVM && !provider.config.isRpcForkedState && !provider.config.isVMStateForked)
},
}
export const EnvironmentExplorerUI = (props: environmentExplorerUIProps) => {
@ -102,7 +102,7 @@ export const EnvironmentExplorerUI = (props: environmentExplorerUIProps) => {
}}
>
<div data-id={`${provider.name}desc`}>{(section.descriptionFn && section.descriptionFn(provider)) || provider.description}</div>
{ provider.isForkedState && <CustomTooltip
{ provider.config.isVMStateForked && <CustomTooltip
placement="auto"
tooltipId={`overlay-tooltip-${provider.name}`}
tooltipText="Delete Environment Immediately"

@ -26,7 +26,16 @@ export type environmentExplorerUIGridSections = {
[key in ProvidersSection]: environmentExplorerUIGridSection
}
export type ProviderConfig = {
isVM: boolean
isInjected: boolean
isRpcForkedState?: boolean
isVMStateForked?: boolean
statePath?: string
}
export type Provider = {
position: number
options: { [key: string]: string }
dataId: string
name: string
@ -35,10 +44,7 @@ export type Provider = {
logos?: string[],
fork: string
description?: string
isInjected: boolean
isVM: boolean
isForkedState: boolean
isForkedVM: boolean
config: ProviderConfig
title: string
init: () => Promise<void>
provider:{

@ -1,7 +1,8 @@
// eslint-disable-next-line no-use-before-define
import React, { useRef } from 'react'
import { FormattedMessage, useIntl } from 'react-intl'
import { EnvironmentProps, Provider } from '../types'
import { EnvironmentProps } from '../types'
import { Provider } from '@remix-ui/environment-explorer'
import { Dropdown } from 'react-bootstrap'
import { CustomMenu, CustomToggle, CustomTooltip } from '@remix-ui/helper'
const _paq = (window._paq = window._paq || [])
@ -9,9 +10,9 @@ const _paq = (window._paq = window._paq || [])
export function EnvironmentUI(props: EnvironmentProps) {
const vmStateName = useRef('')
Object.entries(props.providers.providerList.filter((provider) => { return provider.isVM }))
Object.entries(props.providers.providerList.filter((provider) => { return provider.isInjected }))
Object.entries(props.providers.providerList.filter((provider) => { return !(provider.isVM || provider.isInjected) }))
Object.entries(props.providers.providerList.filter((provider) => { return provider.config.isVM }))
Object.entries(props.providers.providerList.filter((provider) => { return provider.config.isInjected }))
Object.entries(props.providers.providerList.filter((provider) => { return !(provider.config.isVM || provider.config.isInjected) }))
const handleChangeExEnv = (env: string) => {
const provider = props.providers.providerList.find((exEnv) => exEnv.name === env)
@ -65,14 +66,14 @@ export function EnvironmentUI(props: EnvironmentProps) {
_paq.push(['trackEvent', 'udapp', 'forkState', `forkState clicked`])
const context = currentProvider.name
vmStateName.current = `${context}_${Date.now()}`
const contextExists = await props.runTabPlugin.call('fileManager', 'exists', `.states/${context}/state.json`)
const contextExists = await props.runTabPlugin.call('fileManager', 'exists', currentProvider.config.statePath)
if (contextExists) {
props.modal(
intl.formatMessage({ id: 'udapp.forkStateTitle' }),
forkStatePrompt(vmStateName.current),
intl.formatMessage({ id: 'udapp.fork' }),
async () => {
let currentStateDb = await props.runTabPlugin.call('fileManager', 'readFile', `.states/${context}/state.json`)
let currentStateDb = await props.runTabPlugin.call('fileManager', 'readFile', currentProvider.config.statePath)
currentStateDb = JSON.parse(currentStateDb)
currentStateDb.stateName = vmStateName.current
currentStateDb.forkName = currentProvider.fork
@ -121,12 +122,12 @@ export function EnvironmentUI(props: EnvironmentProps) {
<div className="udapp_crow">
<label id="selectExEnv" className="udapp_settingsLabel w-100">
<FormattedMessage id="udapp.environment" />
{ currentProvider && currentProvider.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="forkStatetooltip" tooltipText={<FormattedMessage id="udapp.forkStateTitle" />}>
{ currentProvider && currentProvider.config.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="forkStatetooltip" tooltipText={<FormattedMessage id="udapp.forkStateTitle" />}>
<i className="udapp_infoDeployAction ml-2 fas fa-code-branch" style={{ cursor: 'pointer' }} onClick={forkState} data-id="fork-state-icon"></i>
</CustomTooltip> }
{ currentProvider && currentProvider.isVM && isSaveEvmStateChecked && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="deleteVMStatetooltip" tooltipText={<FormattedMessage id="udapp.resetVmStateTitle" />}>
{ currentProvider && currentProvider.config.isVM && isSaveEvmStateChecked && !currentProvider.config.isVMStateForked && !currentProvider.config.isRpcForkedState && <CustomTooltip placement={'auto-end'} tooltipClasses="text-wrap" tooltipId="deleteVMStatetooltip" tooltipText={<FormattedMessage id="udapp.resetVmStateTitle" />}>
<span onClick={resetVmState} style={{ cursor: 'pointer', float: 'right', textTransform: 'none' }}>
<i className="udapp_infoDeployAction ml-2 fas fa-refresh" data-id="delete-state-icon"></i>
<i className="udapp_infoDeployAction ml-2 fas fa-refresh fa-solid fa-rotate-right" data-id="delete-state-icon"></i>
<span className="ml-1" style = {{ textTransform: 'none', fontSize: '13px' }}>Reset State</span>
</span>
</CustomTooltip> }
@ -155,7 +156,7 @@ export function EnvironmentUI(props: EnvironmentProps) {
No provider pinned
</span>
</Dropdown.Item>}
{ (props.providers.providerList.filter((provider) => { return provider.isInjected })).map(({ name, displayName }) => (
{ (props.providers.providerList.filter((provider) => { return provider.config.isInjected })).map(({ name, displayName }) => (
<Dropdown.Item
key={name}
onClick={async () => {
@ -168,8 +169,8 @@ export function EnvironmentUI(props: EnvironmentProps) {
</span>
</Dropdown.Item>
))}
{ props.providers.providerList.filter((provider) => { return provider.isInjected }).length !== 0 && <Dropdown.Divider className='border-secondary'></Dropdown.Divider> }
{ (props.providers.providerList.filter((provider) => { return provider.isVM })).map(({ displayName, name }) => (
{ props.providers.providerList.filter((provider) => { return provider.config.isInjected }).length !== 0 && <Dropdown.Divider className='border-secondary'></Dropdown.Divider> }
{ (props.providers.providerList.filter((provider) => { return provider.config.isVM })).map(({ displayName, name }) => (
<Dropdown.Item
key={name}
onClick={() => {
@ -182,8 +183,8 @@ export function EnvironmentUI(props: EnvironmentProps) {
</span>
</Dropdown.Item>
))}
{ props.providers.providerList.filter((provider) => { return provider.isVM }).length !== 0 && <Dropdown.Divider className='border-secondary'></Dropdown.Divider> }
{ (props.providers.providerList.filter((provider) => { return !(provider.isVM || provider.isInjected) })).map(({ displayName, name }) => (
{ props.providers.providerList.filter((provider) => { return provider.config.isVM }).length !== 0 && <Dropdown.Divider className='border-secondary'></Dropdown.Divider> }
{ (props.providers.providerList.filter((provider) => { return !(provider.config.isVM || provider.config.isInjected) })).map(({ displayName, name }) => (
<Dropdown.Item
key={name}
onClick={() => {

@ -3,6 +3,7 @@ import { CompilerAbstract } from '@remix-project/remix-solidity'
import { ContractData, FuncABI, OverSizeLimit } from '@remix-project/core-plugin'
import { RunTab } from './run-tab'
import { SolcInput, SolcOutput } from '@openzeppelin/upgrades-core'
import { Provider } from '@remix-ui/environment-explorer'
import { LayoutCompatibilityReport } from '@openzeppelin/upgrades-core/dist/storage/report'
import { CheckStatus } from '../run-tab'
export interface RunTabProps {
@ -22,6 +23,7 @@ export interface ContractList {
[file: string]: Contract[]
}
/*
export type Provider = {
name: string
displayName: string
@ -35,8 +37,11 @@ export type Provider = {
fork: boolean
isVM: boolean
isInjected: boolean
isRpcForkedState?: boolean
isVMStateForked?: boolean
statePath?: string
position: number
}
}*/
export interface RunTabState {
accounts: {

Loading…
Cancel
Save