Merge branch 'master' into desktope2e-remixai

pull/5370/head
STetsing 5 months ago committed by GitHub
commit 7d743e6383
  1. 34
      apps/remix-ide-e2e/src/tests/pinned_contracts.test.ts
  2. 12
      apps/remix-ide/src/app/tabs/locales/en/udapp.json
  3. 10
      apps/remix-ide/src/app/udapp/run-tab.js
  4. 22
      libs/remix-ui/run-tab/src/lib/actions/actions.ts
  5. 8
      libs/remix-ui/run-tab/src/lib/actions/deploy.ts
  6. 17
      libs/remix-ui/run-tab/src/lib/actions/events.ts
  7. 8
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  8. 38
      libs/remix-ui/run-tab/src/lib/actions/payload.ts
  9. 68
      libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx
  10. 41
      libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx
  11. 4
      libs/remix-ui/run-tab/src/lib/constants/index.ts
  12. 73
      libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
  13. 5
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  14. 39
      libs/remix-ui/run-tab/src/lib/types/index.ts

@ -7,13 +7,11 @@ module.exports = {
before: function (browser: NightwatchBrowser, done: VoidFunction) { before: function (browser: NightwatchBrowser, done: VoidFunction) {
init(browser, done) init(browser, done)
}, },
'Should show text in pinned contracts section #group1': function (browser: NightwatchBrowser) { 'Should show badge in deployed contracts section #group1': function (browser: NightwatchBrowser) {
browser browser
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.assert.elementPresent('*[data-id="pinnedContracts"]') .assert.elementPresent('*[data-id="deployedContracts"]')
.assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') .assert.textContains('*[data-id="deployedContractsBadge"]', '0')
.assert.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network')
}, },
'Deploy & pin contract #group1': function (browser: NightwatchBrowser) { 'Deploy & pin contract #group1': function (browser: NightwatchBrowser) {
browser browser
@ -24,22 +22,18 @@ module.exports = {
.clickLaunchIcon('udapp') .clickLaunchIcon('udapp')
.click('*[data-id="Deploy - transact (not payable)"]') .click('*[data-id="Deploy - transact (not payable)"]')
.assert.elementPresent('*[data-id="unpinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="unpinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
.assert.textContains('*[data-id="deployedContractsBadge"]', '1')
.click('*[data-id="universalDappUiUdappPin"]') .click('*[data-id="universalDappUiUdappPin"]')
.assert.elementPresent('*[data-id="deployAndRunNoInstanceText"]') .assert.elementPresent('*[data-id="universalDappUiUdappUnpin"]')
.assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) { 'Test pinned contract loading on environment change #group1': function (browser: NightwatchBrowser) {
browser browser
.switchEnvironment('vm-shanghai') .switchEnvironment('vm-shanghai')
.assert.elementPresent('*[data-id="pinnedContracts"]') .assert.elementPresent('*[data-id="deployedContracts"]')
.assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-shanghai)') .assert.textContains('*[data-id="deployedContractsBadge"]', '0')
.assert.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network')
.switchEnvironment('vm-cancun') .switchEnvironment('vm-cancun')
.assert.textContains('*[data-id="pinnedContractsSublabel"]', '(network: vm-cancun)') .assert.textContains('*[data-id="deployedContractsBadge"]', '1')
.assert.not.elementPresent('*[data-id="NoPinnedInstanceText"]')
.assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]') .assert.elementPresent('*[data-id="pinnedInstance0xd9145CCE52D386f254917e481eB44e9943F39138"]')
}, },
'Interact with pinned contract #group1': function (browser: NightwatchBrowser) { 'Interact with pinned contract #group1': function (browser: NightwatchBrowser) {
@ -71,9 +65,6 @@ module.exports = {
'Unpin & interact #group1': function (browser: NightwatchBrowser) { 'Unpin & interact #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappUnpin"]') .click('*[data-id="universalDappUiUdappUnpin"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network')
.assert.not.elementPresent('*[data-id="deployAndRunNoInstanceText"]')
.click('*[data-id="universalDappUiTitleExpander0"]')
.assert.not.elementPresent('*[data-id="instanceContractPinnedAt"]') .assert.not.elementPresent('*[data-id="instanceContractPinnedAt"]')
.assert.not.elementPresent('*[data-id="instanceContractFilePath"]') .assert.not.elementPresent('*[data-id="instanceContractFilePath"]')
.clickFunction('retrieve - call') .clickFunction('retrieve - call')
@ -95,12 +86,11 @@ module.exports = {
'decoded output': { "0": "uint256: 55" } 'decoded output': { "0": "uint256: 55" }
}) })
}, },
'Re-pin & delete immediately #group1': function (browser: NightwatchBrowser) { 'Re-pin & remove from list #group1': function (browser: NightwatchBrowser) {
browser browser
.click('*[data-id="universalDappUiUdappPin"]') .click('*[data-id="universalDappUiUdappPin"]')
.assert.elementPresent('*[data-id="deployAndRunNoInstanceText"]') .assert.textContains('*[data-id="deployedContractsBadge"]', '1')
.click('*[data-id="universalDappUiUdappDelete"]') .click('*[data-id="universalDappUiUdappClose"]')
.assert.textContains('*[data-id="NoPinnedInstanceText"]', 'No pinned contracts found for selected workspace & network') .assert.textContains('*[data-id="deployedContractsBadge"]', '0')
.assert.textContains('*[data-id="deployAndRunNoInstanceText"]', 'Currently you have no unpinned contracts to interact with.')
}, },
} }

@ -67,16 +67,16 @@
"udapp.tooltipText3": "Click to open a bridge for converting L1 mainnet ETH to the selected network currency.", "udapp.tooltipText3": "Click to open a bridge for converting L1 mainnet ETH to the selected network currency.",
"udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx", "udapp._comment_instanceContainerUI.tsx": "libs/remix-ui/run-tab/src/lib/components/instanceContainerUI.tsx",
"udapp.deployedContracts": "Deployed/Unpinned Contracts", "udapp.deployedContracts": "Deployed Contracts",
"udapp.deployAndRunClearInstances": "Clear instances list and reset recorder", "udapp.deployAndRunClearInstances": "Clear all deployed contracts (including pinned) and reset recorder",
"udapp.deployAndRunNoInstanceText": "Currently you have no unpinned contracts to interact with.", "udapp.deployAndRunNoInstanceText": "Currently you have no unpinned contracts to interact with.",
"udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed/unpinned contracts", "udapp.tooltipText6": "Autogenerated generic user interfaces for interaction with deployed contracts",
"udapp.pinnedContracts": "Pinned Contracts", "udapp.pinnedContracts": "Pinned Contracts",
"udapp.tooltipTextPinnedContracts": "List of pinned contracts for selected workspace & network", "udapp.tooltipTextPinnedContracts": "List of pinned contracts for selected workspace & network",
"udapp.NoPinnedInstanceText": "No pinned contracts found for selected workspace & network", "udapp.NoPinnedInstanceText": "No pinned contracts found for selected workspace & network",
"udapp.tooltipTextDelete": "Delete immediately", "udapp.tooltipTextDelete": "Delete immediately",
"udapp.tooltipTextUnpin": "Unpin contract", "udapp.tooltipTextUnpin": "Unpin contract to delete after reload",
"udapp.pinnedAt": "Pinned at", "udapp.pinnedAt": "Pinned at",
"udapp.filePath": "File path", "udapp.filePath": "File path",
@ -108,9 +108,9 @@
"udapp.tooltipText13": "Deployed {date}", "udapp.tooltipText13": "Deployed {date}",
"udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx", "udapp._comment_universalDappUI.tsx": "libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx",
"udapp.tooltipTextRemove": "Remove from the list", "udapp.tooltipTextRemove": "Permanently remove from the list",
"udapp.tooltipTextEdit": "Create a DApp using this contract in the main panel", "udapp.tooltipTextEdit": "Create a DApp using this contract in the main panel",
"udapp.tooltipTextPin": "Pin contract", "udapp.tooltipTextPin": "Pin contract for current workspace and network to persist after reload",
"udapp.tooltipText8": "Click for docs about using 'receive'/'fallback'", "udapp.tooltipText8": "Click for docs about using 'receive'/'fallback'",
"udapp.tooltipText9": "The Calldata to send to fallback function of the contract.", "udapp.tooltipText9": "The Calldata to send to fallback function of the contract.",
"udapp.tooltipText10": "Send data to contract.", "udapp.tooltipText10": "Send data to contract.",

@ -31,9 +31,7 @@ const profile = {
'getSettings', 'getSettings',
'setEnvironmentMode', 'setEnvironmentMode',
'clearAllInstances', 'clearAllInstances',
'clearAllPinnedInstances',
'addInstance', 'addInstance',
'addPinnedInstance',
'resolveContractAndAddInstance' 'resolveContractAndAddInstance'
] ]
} }
@ -85,18 +83,10 @@ export class RunTab extends ViewPlugin {
this.emit('clearAllInstancesReducer') this.emit('clearAllInstancesReducer')
} }
clearAllPinnedInstances() {
this.emit('clearAllPinnedInstancesReducer')
}
addInstance(address, abi, name, contractData) { addInstance(address, abi, name, contractData) {
this.emit('addInstanceReducer', address, abi, name, contractData) this.emit('addInstanceReducer', address, abi, name, contractData)
} }
addPinnedInstance(address, abi, name, pinnedAt, filePath) {
this.emit('addPinnedInstanceReducer', address, abi, name, pinnedAt, filePath)
}
createVMAccount(newAccount) { createVMAccount(newAccount) {
return this.blockchain.createVMAccount(newAccount) return this.blockchain.createVMAccount(newAccount)
} }

@ -1,5 +1,5 @@
import { ContractData } from "@remix-project/core-plugin" import { ContractData } from "@remix-project/core-plugin"
import { addNewInstance, addNewPinnedInstance, addProvider, clearAllInstances, clearAllPinnedInstances, clearRecorderCount, hidePopUp, newProxyDeployment, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setChainId, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue } from "./payload" import { addNewInstance, pinUnpinnedInstance, unpinPinnedInstance, addProvider, clearAllInstances, clearRecorderCount, hidePopUp, newProxyDeployment, removeExistingInstance, removeProvider, setBaseFeePerGas, setConfirmSettings, setCurrentContract, setExecutionEnvironment, setExternalEndpoint, setGasLimit, setGasPrice, setGasPriceStatus, setMatchPassphrase, setMaxFee, setMaxPriorityFee, setNetworkName, setChainId, setPassphrase, setPathToScenario, setSelectedAccount, setSendUnit, setSendValue } from "./payload"
export const setAccount = (dispatch: React.Dispatch<any>, account: string) => { export const setAccount = (dispatch: React.Dispatch<any>, account: string) => {
dispatch(setSelectedAccount(account)) dispatch(setSelectedAccount(account))
@ -69,27 +69,25 @@ export const updateGasPrice = (dispatch: React.Dispatch<any>, price: string) =>
dispatch(setGasPrice(price)) dispatch(setGasPrice(price))
} }
export const addInstance = (dispatch: React.Dispatch<any>, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record<number, any> }) => { export const addInstance = (dispatch: React.Dispatch<any>, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record<number, any>, isPinned?: boolean, pinnedAt?: number, filePath?: string }) => {
instance.decodedResponse = {} instance.decodedResponse = {}
dispatch(addNewInstance(instance)) dispatch(addNewInstance(instance))
} }
export const addPinnedInstance = (dispatch: React.Dispatch<any>, instance: { contractData?: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record<number, any>, pinnedAt?: number, filePath?: string }) => { export const pinInstance = (dispatch: React.Dispatch<any>, index: number, pinnedAt: number, filePath: string) => {
instance.decodedResponse = {} dispatch(pinUnpinnedInstance(index, pinnedAt, filePath))
dispatch(addNewPinnedInstance(instance))
} }
export const removeInstance = (dispatch: React.Dispatch<any>, index: number, isPinnedContract: boolean, shouldDelete: boolean) => { export const unpinInstance = (dispatch: React.Dispatch<any>, index: number) => {
dispatch(removeExistingInstance(index, isPinnedContract, shouldDelete)) dispatch(unpinPinnedInstance(index))
} }
export const clearInstances = (dispatch: React.Dispatch<any>) => { export const removeInstance = (dispatch: React.Dispatch<any>, index: number) => {
dispatch(clearAllInstances()) dispatch(removeExistingInstance(index))
dispatch(clearRecorderCount())
} }
export const clearPinnedInstances = (dispatch: React.Dispatch<any>) => { export const clearInstances = (dispatch: React.Dispatch<any>) => {
dispatch(clearAllPinnedInstances()) dispatch(clearAllInstances())
dispatch(clearRecorderCount()) dispatch(clearRecorderCount())
} }

@ -286,7 +286,6 @@ export const runTransactions = (
plugin: RunTab, plugin: RunTab,
dispatch: React.Dispatch<any>, dispatch: React.Dispatch<any>,
instanceIndex: number, instanceIndex: number,
isPinnedContract: boolean,
lookupOnly: boolean, lookupOnly: boolean,
funcABI: FuncABI, funcABI: FuncABI,
inputsValues: string, inputsValues: string,
@ -323,7 +322,7 @@ export const runTransactions = (
(returnValue) => { (returnValue) => {
const response = txFormat.decodeResponse(returnValue, funcABI) const response = txFormat.decodeResponse(returnValue, funcABI)
dispatch(setDecodedResponse(instanceIndex, response, funcIndex, isPinnedContract)) dispatch(setDecodedResponse(instanceIndex, response, funcIndex))
}, },
(network, tx, gasEstimation, continueTxExecution, cancelCb) => { (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
confirmationHandler(plugin, dispatch, mainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb) confirmationHandler(plugin, dispatch, mainnetPrompt, network, tx, gasEstimation, continueTxExecution, cancelCb)
@ -342,9 +341,8 @@ export const getFuncABIInputs = (plugin: RunTab, funcABI: FuncABI) => {
} }
export const updateInstanceBalance = async (plugin: RunTab, dispatch: React.Dispatch<any>) => { export const updateInstanceBalance = async (plugin: RunTab, dispatch: React.Dispatch<any>) => {
if (plugin.REACT_API?.instances?.instanceList?.length || plugin.REACT_API?.pinnedInstances?.instanceList?.length) { if (plugin.REACT_API?.instances?.instanceList?.length) {
let instances = plugin.REACT_API?.instances?.instanceList?.length ? plugin.REACT_API?.instances?.instanceList : [] const instances = plugin.REACT_API?.instances?.instanceList?.length ? plugin.REACT_API?.instances?.instanceList : []
instances = plugin.REACT_API?.pinnedInstances?.instanceList.length ? instances.concat(plugin.REACT_API.pinnedInstances.instanceList) : instances
for (const instance of instances) { for (const instance of instances) {
const balInEth = await plugin.blockchain.getBalanceInEther(instance.address) const balInEth = await plugin.blockchain.getBalanceInEther(instance.address)
instance.balance = balInEth instance.balance = balInEth

@ -1,8 +1,8 @@
import { envChangeNotification } from "@remix-ui/helper" import { envChangeNotification } from "@remix-ui/helper"
import { RunTab } from "../types/run-tab" import { RunTab } from "../types/run-tab"
import { setExecutionContext, setFinalContext, updateAccountBalances, fillAccountsList } from "./account" import { setExecutionContext, setFinalContext, updateAccountBalances, fillAccountsList } from "./account"
import { addExternalProvider, addInstance, addPinnedInstance, addNewProxyDeployment, removeExternalProvider, setNetworkNameFromProvider, setPinnedChainId } from "./actions" import { addExternalProvider, addInstance, addNewProxyDeployment, removeExternalProvider, setNetworkNameFromProvider, setPinnedChainId } from "./actions"
import { addDeployOption, clearAllInstances, clearAllPinnedInstances, clearRecorderCount, fetchContractListSuccess, resetProxyDeployments, resetUdapp, setCurrentContract, setCurrentFile, setLoadType, setRecorderCount, setRemixDActivated, setSendValue, fetchAccountsListSuccess } from "./payload" import { addDeployOption, clearAllInstances, clearRecorderCount, fetchContractListSuccess, resetProxyDeployments, resetUdapp, setCurrentContract, setCurrentFile, setLoadType, setRecorderCount, setRemixDActivated, setSendValue, fetchAccountsListSuccess } from "./payload"
import { updateInstanceBalance } from './deploy' import { updateInstanceBalance } from './deploy'
import { CompilerAbstract } from '@remix-project/remix-solidity' import { CompilerAbstract } from '@remix-project/remix-solidity'
import BN from 'bn.js' import BN from 'bn.js'
@ -100,18 +100,10 @@ export const setupEvents = (plugin: RunTab) => {
dispatch(clearAllInstances()) dispatch(clearAllInstances())
}) })
plugin.on('udapp', 'clearAllPinnedInstancesReducer', () => {
dispatch(clearAllPinnedInstances())
})
plugin.on('udapp', 'addInstanceReducer', (address, abi, name, contractData?) => { plugin.on('udapp', 'addInstanceReducer', (address, abi, name, contractData?) => {
addInstance(dispatch, { contractData, abi, address, name }) addInstance(dispatch, { contractData, abi, address, name })
}) })
plugin.on('udapp', 'addPinnedInstanceReducer', (address, abi, name, pinnedAt, filePath) => {
addPinnedInstance(dispatch, { abi, address, name, pinnedAt, filePath })
})
plugin.on('filePanel', 'setWorkspace', async () => { plugin.on('filePanel', 'setWorkspace', async () => {
dispatch(resetUdapp()) dispatch(resetUdapp())
resetAndInit(plugin) resetAndInit(plugin)
@ -182,7 +174,7 @@ export const setupEvents = (plugin: RunTab) => {
} }
const loadPinnedContracts = async (plugin, dispatch, dirName) => { const loadPinnedContracts = async (plugin, dispatch, dirName) => {
await plugin.call('udapp', 'clearAllPinnedInstances') await plugin.call('udapp', 'clearAllInstances')
const isPinnedAvailable = await plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${dirName}`) const isPinnedAvailable = await plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${dirName}`)
if (isPinnedAvailable) { if (isPinnedAvailable) {
try { try {
@ -191,7 +183,8 @@ const loadPinnedContracts = async (plugin, dispatch, dirName) => {
for (const file of filePaths) { for (const file of filePaths) {
const pinnedContract = await plugin.call('fileManager', 'readFile', file) const pinnedContract = await plugin.call('fileManager', 'readFile', file)
const pinnedContractObj = JSON.parse(pinnedContract) const pinnedContractObj = JSON.parse(pinnedContract)
if (pinnedContractObj) addPinnedInstance(dispatch, pinnedContractObj) pinnedContractObj.isPinned = true
if (pinnedContractObj) addInstance(dispatch, pinnedContractObj)
} }
} catch (err) { } catch (err) {
console.log(err) console.log(err)

@ -3,7 +3,7 @@ import React from 'react'
import { RunTab } from '../types/run-tab' import { RunTab } from '../types/run-tab'
import { resetAndInit, setupEvents, setEventsDispatch } from './events' import { resetAndInit, setupEvents, setEventsDispatch } from './events'
import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress } from './account' import { createNewBlockchainAccount, setExecutionContext, signMessageWithAddress } from './account'
import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt, import { clearInstances, clearPopUp, removeInstance, pinInstance, unpinInstance, setAccount, setGasFee, setMatchPassphrasePrompt,
setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit, setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit,
updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath } from './actions' updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath } from './actions'
import { createInstance, getContext, getFuncABIInputs, getSelectedContract, loadAddress, runTransactions, updateInstanceBalance, syncContractsInternal, isValidContractAddress, isValidContractUpgrade } from './deploy' import { createInstance, getContext, getFuncABIInputs, getSelectedContract, loadAddress, runTransactions, updateInstanceBalance, syncContractsInternal, isValidContractAddress, isValidContractUpgrade } from './deploy'
@ -50,10 +50,12 @@ export const setGasPrice = (price: string) => updateGasPrice(dispatch, price)
export const setGasPriceStatus = (status: boolean) => updateGasPriceStatus(dispatch, status) export const setGasPriceStatus = (status: boolean) => updateGasPriceStatus(dispatch, status)
export const setMaxFee = (fee: string) => updateMaxFee(dispatch, fee) export const setMaxFee = (fee: string) => updateMaxFee(dispatch, fee)
export const setMaxPriorityFee = (fee: string) => updateMaxPriorityFee(dispatch, fee) export const setMaxPriorityFee = (fee: string) => updateMaxPriorityFee(dispatch, fee)
export const pinUnpinnedInstance = (index: number, pinnedAt: number, filePath: string) => pinInstance(dispatch, index, pinnedAt, filePath)
export const unpinPinnedInstance = (index: number) => unpinInstance(dispatch, index)
export const removeInstances = () => clearInstances(dispatch) export const removeInstances = () => clearInstances(dispatch)
export const removeSingleInstance = (index: number, isPinnedContract: boolean, shouldDelete: boolean) => removeInstance(dispatch, index, isPinnedContract, shouldDelete) export const removeSingleInstance = (index: number) => removeInstance(dispatch, index)
export const getExecutionContext = () => getContext(plugin) export const getExecutionContext = () => getContext(plugin)
export const executeTransactions = (instanceIndex: number, isPinnedContract: boolean, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, contractName: string, contractABI, contract, address, logMsg:string, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => runTransactions(plugin, dispatch, instanceIndex, isPinnedContract, lookupOnly, funcABI, inputsValues, contractName, contractABI, contract, address, logMsg, mainnetPrompt, gasEstimationPrompt, passphrasePrompt, funcIndex) export const executeTransactions = (instanceIndex: number, lookupOnly: boolean, funcABI: FuncABI, inputsValues: string, contractName: string, contractABI, contract, address, logMsg:string, mainnetPrompt: MainnetPrompt, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, funcIndex?: number) => runTransactions(plugin, dispatch, instanceIndex, lookupOnly, funcABI, inputsValues, contractName, contractABI, contract, address, logMsg, mainnetPrompt, gasEstimationPrompt, passphrasePrompt, funcIndex)
export const loadFromAddress = (contract: ContractData, address: string) => loadAddress(plugin, dispatch, contract, address) export const loadFromAddress = (contract: ContractData, address: string) => loadAddress(plugin, dispatch, contract, address)
export const storeNewScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => storeScenario(plugin, dispatch, prompt) export const storeNewScenario = async (prompt: (msg: string, defaultValue: string) => JSX.Element) => storeScenario(plugin, dispatch, prompt)
export const runScenario = (liveMode: boolean, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => runCurrentScenario(liveMode, plugin, dispatch, gasEstimationPrompt, passphrasePrompt, confirmDialogContent) export const runScenario = (liveMode: boolean, gasEstimationPrompt: (msg: string) => JSX.Element, passphrasePrompt: (msg: string) => JSX.Element, confirmDialogContent: MainnetPrompt) => runCurrentScenario(liveMode, plugin, dispatch, gasEstimationPrompt, passphrasePrompt, confirmDialogContent)

@ -1,5 +1,5 @@
import { ContractData } from '@remix-project/core-plugin' import { ContractData } from '@remix-project/core-plugin'
import { ADD_DEPLOY_OPTION, ADD_INSTANCE, ADD_PINNED_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_PINNED_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_CHAIN_ID, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants' import { ADD_DEPLOY_OPTION, ADD_INSTANCE, PIN_INSTANCE, UNPIN_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_DEPLOY_OPTION, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_CHAIN_ID, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants'
import { ContractList, DeployOptions } from '../types' import { ContractList, DeployOptions } from '../types'
export const fetchAccountsListRequest = () => { export const fetchAccountsListRequest = () => {
@ -230,51 +230,55 @@ export const updateInstancesBalance = (instances: Array<{ contractData?: Contrac
} }
} }
export const addNewInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any }) => { export const addNewInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any, isPinned?: boolean, pinnedAt?: number }) => {
return { return {
type: ADD_INSTANCE, type: ADD_INSTANCE,
payload: instance payload: instance
} }
} }
export const addNewPinnedInstance = (instance: { contractData?: ContractData, address: string, name: string, abi?: any, pinnedAt?: number }) => { export const pinUnpinnedInstance = (index: number, pinnedAt: number, filePath: string) => {
return { return {
type: ADD_PINNED_INSTANCE, type: PIN_INSTANCE,
payload: instance payload: {
index,
pinnedAt,
filePath
}
} }
} }
export const removeExistingInstance = (index: number, isPinnedContract: boolean, shouldDelete: boolean) => { export const unpinPinnedInstance = (index: number) => {
return { return {
type: REMOVE_INSTANCE, type: UNPIN_INSTANCE,
payload: { payload: {
index, index
isPinnedContract,
shouldDelete
} }
} }
} }
export const clearAllInstances = () => { export const removeExistingInstance = (index: number) => {
return { return {
type: CLEAR_INSTANCES type: REMOVE_INSTANCE,
payload: {
index
}
} }
} }
export const clearAllPinnedInstances = () => { export const clearAllInstances = () => {
return { return {
type: CLEAR_PINNED_INSTANCES type: CLEAR_INSTANCES
} }
} }
export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: number, isPinnedContract?: boolean) => { export const setDecodedResponse = (instanceIndex: number, response, funcIndex?: number) => {
return { return {
type: SET_DECODED_RESPONSE, type: SET_DECODED_RESPONSE,
payload: { payload: {
instanceIndex, instanceIndex,
funcIndex, funcIndex,
response, response
isPinnedContract
} }
} }
} }

@ -8,60 +8,24 @@ import { UniversalDappUI } from './universalDappUI'
export function InstanceContainerUI(props: InstanceContainerProps) { export function InstanceContainerUI(props: InstanceContainerProps) {
const { instanceList } = props.instances const { instanceList } = props.instances
const clearInstance = () => { const clearInstance = async() => {
const isPinnedAvailable = await props.plugin.call('fileManager', 'exists', `.deploys/pinned-contracts/${props.plugin.REACT_API.chainId}`)
if (isPinnedAvailable) await props.plugin.call('fileManager', 'remove', `.deploys/pinned-contracts/${props.plugin.REACT_API.chainId}`)
props.clearInstances() props.clearInstances()
} }
return ( return (
<div className="udapp_instanceContainer mt-3 border-0 list-group-item"> <div className="udapp_instanceContainer mt-2 border-0 list-group-item">
<div className="d-flex justify-content-between align-items-center pl-2"> <div className="d-flex justify-content-between align-items-center p-2">
<CustomTooltip placement="top-start" tooltipClasses="text-nowrap" tooltipId="deployAndRunPinnedContractsTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextPinnedContracts" />}>
<label className="udapp_deployedContracts" data-id="pinnedContracts">
<FormattedMessage id="udapp.pinnedContracts" />
<span style={{ fontSize: '0.75rem' }} data-id="pinnedContractsSublabel"> (network: {props.plugin.REACT_API.chainId}) </span>
</label>
</CustomTooltip>
</div>
{props.pinnedInstances.instanceList.length > 0 ? (
<div>
{' '}
{props.pinnedInstances.instanceList.map((instance, index) => {
return (
<UniversalDappUI
key={index}
instance={instance}
isPinnedContract={true}
context={props.getContext()}
removeInstance={props.removeInstance}
index={index}
gasEstimationPrompt={props.gasEstimationPrompt}
passphrasePrompt={props.passphrasePrompt}
mainnetPrompt={props.mainnetPrompt}
runTransactions={props.runTransactions}
sendValue={props.sendValue}
getFuncABIInputs={props.getFuncABIInputs}
plugin={props.plugin}
exEnvironment={props.exEnvironment}
editInstance={props.editInstance}
solcVersion={props.solcVersion}
getVersion={props.getVersion}
/>
)
})}
</div>
) : (
<span className="mx-2 mt-3 alert alert-secondary" data-id="NoPinnedInstanceText">
<FormattedMessage id="udapp.NoPinnedInstanceText" />
</span>
)}
<div className="d-flex justify-content-between align-items-center pl-2 mb-2 mt-2">
<CustomTooltip placement="top-start" tooltipClasses="text-nowrap" tooltipId="deployAndRunClearInstancesTooltip" tooltipText={<FormattedMessage id="udapp.tooltipText6" />}> <CustomTooltip placement="top-start" tooltipClasses="text-nowrap" tooltipId="deployAndRunClearInstancesTooltip" tooltipText={<FormattedMessage id="udapp.tooltipText6" />}>
<label className="udapp_deployedContracts" data-id="unpinnedContracts"> <label className="udapp_deployedContracts text-nowrap" data-id="deployedContracts">
<FormattedMessage id="udapp.deployedContracts" /> <FormattedMessage id="udapp.deployedContracts" />
</label> </label>
</CustomTooltip> </CustomTooltip>
<CustomTooltip placement="top-start" tooltipClasses="text-nowrap" tooltipId="numOfDeployedInstancesTooltip" tooltipText="Number of deployed contracts">
<div className="badge badge-pill badge-primary text-center ml-2 mb-1" data-id="deployedContractsBadge">{instanceList.length}</div>
</CustomTooltip>
<div className="w-100"></div>
{instanceList.length > 0 ? ( {instanceList.length > 0 ? (
<CustomTooltip <CustomTooltip
placement={'auto-end'} placement={'auto-end'}
@ -69,10 +33,11 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
tooltipId="deployAndRunClearInstancesTooltip" tooltipId="deployAndRunClearInstancesTooltip"
tooltipText={<FormattedMessage id="udapp.deployAndRunClearInstances" />} tooltipText={<FormattedMessage id="udapp.deployAndRunClearInstances" />}
> >
<i className="mr-1 p-2 udapp_icon far fa-trash-alt" data-id="deployAndRunClearInstances" onClick={clearInstance} aria-hidden="true"></i> <i className="far fa-trash-alt udapp_icon mr-1 mb-2" data-id="deployAndRunClearInstances" onClick={clearInstance} aria-hidden="true"></i>
</CustomTooltip> </CustomTooltip>
) : null} ) : null}
</div> </div>
{instanceList.length > 0 ? ( {instanceList.length > 0 ? (
<div> <div>
{' '} {' '}
@ -81,8 +46,9 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
<UniversalDappUI <UniversalDappUI
key={index} key={index}
instance={instance} instance={instance}
isPinnedContract={false}
context={props.getContext()} context={props.getContext()}
pinInstance={props.pinInstance}
unpinInstance={props.unpinInstance}
removeInstance={props.removeInstance} removeInstance={props.removeInstance}
index={index} index={index}
gasEstimationPrompt={props.gasEstimationPrompt} gasEstimationPrompt={props.gasEstimationPrompt}
@ -100,11 +66,7 @@ export function InstanceContainerUI(props: InstanceContainerProps) {
) )
})} })}
</div> </div>
) : ( ) : ''}
<span className="mx-2 mt-3 alert alert-secondary" data-id="deployAndRunNoInstanceText" role="alert">
<FormattedMessage id="udapp.deployAndRunNoInstanceText" />
</span>
)}
</div> </div>
) )
} }

@ -115,17 +115,17 @@ export function UniversalDappUI(props: UdappProps) {
} }
const remove = async() => { const remove = async() => {
if (props.isPinnedContract) { if (props.instance.isPinned) {
await unsavePinnedContract() await unsavePinnedContract()
_paq.push(['trackEvent', 'udapp', 'pinContracts', 'unpinned']) _paq.push(['trackEvent', 'udapp', 'pinContracts', 'removePinned'])
} }
props.removeInstance(props.index, props.isPinnedContract, false) props.removeInstance(props.index)
} }
const deletePinnedContract = async() => { const unpinContract = async() => {
await unsavePinnedContract() await unsavePinnedContract()
_paq.push(['trackEvent', 'udapp', 'pinContracts', 'deletePinned']) _paq.push(['trackEvent', 'udapp', 'pinContracts', 'unpinned'])
props.removeInstance(props.index, props.isPinnedContract, true) props.unpinInstance(props.index)
} }
const pinContract = async() => { const pinContract = async() => {
@ -138,21 +138,17 @@ export function UniversalDappUI(props: UdappProps) {
pinnedAt: Date.now() pinnedAt: Date.now()
} }
await props.plugin.call('fileManager', 'writeFile', `.deploys/pinned-contracts/${props.plugin.REACT_API.chainId}/${props.instance.address}.json`, JSON.stringify(objToSave, null, 2)) await props.plugin.call('fileManager', 'writeFile', `.deploys/pinned-contracts/${props.plugin.REACT_API.chainId}/${props.instance.address}.json`, JSON.stringify(objToSave, null, 2))
// Add contract to saved contracts list on UI
await props.plugin.call('udapp', 'addPinnedInstance', objToSave.address, objToSave.abi, objToSave.name, objToSave.pinnedAt, objToSave.filePath)
_paq.push(['trackEvent', 'udapp', 'pinContracts', `pinned at ${props.plugin.REACT_API.chainId}`]) _paq.push(['trackEvent', 'udapp', 'pinContracts', `pinned at ${props.plugin.REACT_API.chainId}`])
// Remove contract from deployed contracts list on UI props.pinInstance(props.index, objToSave.pinnedAt, objToSave.filePath)
props.removeInstance(props.index, false, false)
} }
const runTransaction = (lookupOnly, funcABI: FuncABI, valArr, inputsValues, funcIndex?: number) => { const runTransaction = (lookupOnly, funcABI: FuncABI, valArr, inputsValues, funcIndex?: number) => {
if (props.isPinnedContract) _paq.push(['trackEvent', 'udapp', 'pinContracts', 'interactWithPinned']) if (props.instance.isPinned) _paq.push(['trackEvent', 'udapp', 'pinContracts', 'interactWithPinned'])
const functionName = funcABI.type === 'function' ? funcABI.name : `(${funcABI.type})` const functionName = funcABI.type === 'function' ? funcABI.name : `(${funcABI.type})`
const logMsg = `${lookupOnly ? 'call' : 'transact'} to ${props.instance.name}.${functionName}` const logMsg = `${lookupOnly ? 'call' : 'transact'} to ${props.instance.name}.${functionName}`
props.runTransactions( props.runTransactions(
props.index, props.index,
props.isPinnedContract,
lookupOnly, lookupOnly,
funcABI, funcABI,
inputsValues, inputsValues,
@ -248,7 +244,7 @@ export function UniversalDappUI(props: UdappProps) {
className={`instance udapp_instance udapp_run-instance border-dark ${toggleExpander ? 'udapp_hidesub' : 'bg-light'}`} className={`instance udapp_instance udapp_run-instance border-dark ${toggleExpander ? 'udapp_hidesub' : 'bg-light'}`}
id={`instance${address}`} id={`instance${address}`}
data-shared="universalDappUiInstance" data-shared="universalDappUiInstance"
data-id={props.isPinnedContract ? `pinnedInstance${address}` : `unpinnedInstance${address}`} data-id={props.instance.isPinned ? `pinnedInstance${address}` : `unpinnedInstance${address}`}
> >
<div className="udapp_title pb-0 alert alert-secondary"> <div className="udapp_title pb-0 alert alert-secondary">
<span data-id={`universalDappUiTitleExpander${props.index}`} className="btn udapp_titleExpander" onClick={toggleClass} style={{ padding: "0.45rem" }}> <span data-id={`universalDappUiTitleExpander${props.index}`} className="btn udapp_titleExpander" onClick={toggleClass} style={{ padding: "0.45rem" }}>
@ -256,7 +252,7 @@ export function UniversalDappUI(props: UdappProps) {
</span> </span>
<div className="input-group udapp_nameNbuts"> <div className="input-group udapp_nameNbuts">
<div className="udapp_titleText input-group-prepend"> <div className="udapp_titleText input-group-prepend">
{ props.isPinnedContract ? ( <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={props.isPinnedContract ? `Contract: ${props.instance.name}, Address: ${address}, Pinned at: ${new Date(props.instance.pinnedAt).toLocaleString()}` : '' }> { props.instance.isPinned ? ( <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={props.instance.isPinned ? `Pinned for network: ${props.plugin.REACT_API.chainId}, at: ${new Date(props.instance.pinnedAt).toLocaleString()}` : '' }>
<span className="input-group-text udapp_spanTitleText"> <span className="input-group-text udapp_spanTitleText">
{props.instance.name} at {shortenAddress(address)} {props.instance.name} at {shortenAddress(address)}
</span> </span>
@ -267,9 +263,9 @@ export function UniversalDappUI(props: UdappProps) {
<div className="btn" style={{ padding: '0.15rem' }}> <div className="btn" style={{ padding: '0.15rem' }}>
<CopyToClipboard tip={intl.formatMessage({ id: 'udapp.copyAddress' })} content={address} direction={'top'} /> <CopyToClipboard tip={intl.formatMessage({ id: 'udapp.copyAddress' })} content={address} direction={'top'} />
</div> </div>
{ props.isPinnedContract ? ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}> { props.instance.isPinned ? ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}>
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextUnpin" />}> <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappUnpinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextUnpin" />}>
<i className="fas fa-thumbtack p-2" aria-hidden="true" data-id="universalDappUiUdappUnpin" onClick={remove}></i> <i className="fas fa-thumbtack p-2" aria-hidden="true" data-id="universalDappUiUdappUnpin" onClick={unpinContract}></i>
</CustomTooltip> </CustomTooltip>
</div> ) : ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}> </div> ) : ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}>
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappPinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextPin" />}> <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappPinTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextPin" />}>
@ -278,16 +274,11 @@ export function UniversalDappUI(props: UdappProps) {
</div> ) </div> )
} }
</div> </div>
{ props.isPinnedContract ? ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}> <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}>
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappDeleteTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextDelete" />}>
<i className="far fa-trash p-2" aria-hidden="true" data-id="universalDappUiUdappDelete" onClick={deletePinnedContract}></i>
</CustomTooltip>
</div> ) : ( <div className="btn" style={{ padding: '0.15rem', marginLeft: '-0.5rem' }}>
<CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappCloseTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextRemove" />}> <CustomTooltip placement="top" tooltipClasses="text-nowrap" tooltipId="udapp_udappCloseTooltip" tooltipText={<FormattedMessage id="udapp.tooltipTextRemove" />}>
<i className="fas fa-times p-2" aria-hidden="true" data-id="universalDappUiUdappClose" onClick={remove}></i> <i className="fas fa-times p-2" aria-hidden="true" data-id="universalDappUiUdappClose" onClick={remove}></i>
</CustomTooltip> </CustomTooltip>
</div> ) </div>
}
</div> </div>
<div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper"> <div className="udapp_cActionsWrapper" data-id="universalDappUiContractActionWrapper">
<div className="udapp_contractActionsContainer"> <div className="udapp_contractActionsContainer">
@ -310,14 +301,14 @@ export function UniversalDappUI(props: UdappProps) {
)} )}
</div> </div>
</div> </div>
{ props.isPinnedContract && props.instance.pinnedAt ? ( { props.instance.isPinned && props.instance.pinnedAt ? (
<div className="d-flex" data-id="instanceContractPinnedAt"> <div className="d-flex" data-id="instanceContractPinnedAt">
<label> <label>
<b><FormattedMessage id="udapp.pinnedAt" />:</b> {(new Date(props.instance.pinnedAt)).toLocaleString()} <b><FormattedMessage id="udapp.pinnedAt" />:</b> {(new Date(props.instance.pinnedAt)).toLocaleString()}
</label> </label>
</div> </div>
) : null } ) : null }
{ props.isPinnedContract && props.instance.filePath ? ( { props.instance.isPinned && props.instance.filePath ? (
<div className="d-flex" data-id="instanceContractFilePath" style={{ textAlign: "start", lineBreak: "anywhere" }}> <div className="d-flex" data-id="instanceContractFilePath" style={{ textAlign: "start", lineBreak: "anywhere" }}>
<label> <label>
<b><FormattedMessage id="udapp.filePath" />:</b> {props.instance.filePath} <b><FormattedMessage id="udapp.filePath" />:</b> {props.instance.filePath}

@ -33,11 +33,11 @@ export const SET_MAX_PRIORITY_FEE = 'SET_MAX_PRIORITY_FEE'
export const SET_BASE_FEE_PER_GAS = 'SET_BASE_FEE_PER_GAS' export const SET_BASE_FEE_PER_GAS = 'SET_BASE_FEE_PER_GAS'
export const SET_GAS_PRICE = 'SET_GAS_PRICE' export const SET_GAS_PRICE = 'SET_GAS_PRICE'
export const ADD_INSTANCE = 'ADD_INSTANCE' export const ADD_INSTANCE = 'ADD_INSTANCE'
export const ADD_PINNED_INSTANCE = 'ADD_PINNED_INSTANCE' export const PIN_INSTANCE = 'PIN_INSTANCE'
export const UNPIN_INSTANCE = 'UNPIN_INSTANCE'
export const UPDATE_INSTANCES_BALANCE = 'UPDATE_INSTANCES_BALANCE' export const UPDATE_INSTANCES_BALANCE = 'UPDATE_INSTANCES_BALANCE'
export const REMOVE_INSTANCE = 'REMOVE_INSTANCE' export const REMOVE_INSTANCE = 'REMOVE_INSTANCE'
export const CLEAR_INSTANCES = 'CLEAR_INSTANCES' export const CLEAR_INSTANCES = 'CLEAR_INSTANCES'
export const CLEAR_PINNED_INSTANCES = 'CLEAR_PINNED_INSTANCES'
export const SET_DECODED_RESPONSE = 'SET_DECODED_RESPONSE' export const SET_DECODED_RESPONSE = 'SET_DECODED_RESPONSE'
export const SET_PATH_TO_SCENARIO = 'SET_PATH_TO_SCENARIO' export const SET_PATH_TO_SCENARIO = 'SET_PATH_TO_SCENARIO'
export const SET_RECORDER_COUNT = 'SET_RECORDER_COUNT' export const SET_RECORDER_COUNT = 'SET_RECORDER_COUNT'

@ -1,6 +1,6 @@
import { ContractData } from '@remix-project/core-plugin' import { ContractData } from '@remix-project/core-plugin'
import { ContractList, DeployOptions, RunTabState } from '../types' import { ContractList, DeployOptions, RunTabState } from '../types'
import { ADD_INSTANCE, ADD_PINNED_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_PINNED_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, FETCH_PROVIDER_LIST_FAILED, FETCH_PROVIDER_LIST_REQUEST, FETCH_PROVIDER_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CHAIN_ID, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, ADD_DEPLOY_OPTION, REMOVE_DEPLOY_OPTION, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants' import { ADD_INSTANCE, PIN_INSTANCE, UNPIN_INSTANCE, UPDATE_INSTANCES_BALANCE, ADD_PROVIDER, CLEAR_INSTANCES, CLEAR_RECORDER_COUNT, DISPLAY_NOTIFICATION, DISPLAY_POPUP_MESSAGE, FETCH_ACCOUNTS_LIST_FAILED, FETCH_ACCOUNTS_LIST_REQUEST, FETCH_ACCOUNTS_LIST_SUCCESS, FETCH_CONTRACT_LIST_FAILED, FETCH_CONTRACT_LIST_REQUEST, FETCH_CONTRACT_LIST_SUCCESS, FETCH_PROVIDER_LIST_FAILED, FETCH_PROVIDER_LIST_REQUEST, FETCH_PROVIDER_LIST_SUCCESS, HIDE_NOTIFICATION, HIDE_POPUP_MESSAGE, REMOVE_INSTANCE, REMOVE_PROVIDER, RESET_STATE, SET_BASE_FEE_PER_GAS, SET_CONFIRM_SETTINGS, SET_CHAIN_ID, SET_CURRENT_CONTRACT, SET_CURRENT_FILE, SET_DECODED_RESPONSE, SET_DEPLOY_OPTIONS, SET_EXECUTION_ENVIRONMENT, SET_EXTERNAL_WEB3_ENDPOINT, SET_GAS_LIMIT, SET_GAS_PRICE, SET_GAS_PRICE_STATUS, SET_IPFS_CHECKED_STATE, SET_LOAD_TYPE, SET_MATCH_PASSPHRASE, SET_MAX_FEE, SET_MAX_PRIORITY_FEE, SET_NETWORK_NAME, SET_PASSPHRASE, SET_PATH_TO_SCENARIO, SET_PERSONAL_MODE, SET_RECORDER_COUNT, SET_SELECTED_ACCOUNT, SET_SEND_UNIT, SET_SEND_VALUE, ADD_DEPLOY_OPTION, REMOVE_DEPLOY_OPTION, SET_REMIXD_ACTIVATED, FETCH_PROXY_DEPLOYMENTS, NEW_PROXY_DEPLOYMENT, RESET_PROXY_DEPLOYMENTS, EXTRACT_COMPILER_VERSION } from '../constants'
declare const window: any declare const window: any
interface Action { interface Action {
@ -64,10 +64,6 @@ export const runTabInitialState: RunTabState = {
instanceList: [], instanceList: [],
error: null error: null
}, },
pinnedInstances: {
instanceList: [],
error: null
},
recorder: { recorder: {
pathToScenario: 'scenario.json', pathToScenario: 'scenario.json',
transactionCount: 0 transactionCount: 0
@ -488,7 +484,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case ADD_INSTANCE: { case ADD_INSTANCE: {
const payload: { contractData: ContractData, address: string, name: string, abi?: any, decodedResponse?: Record<number, any> } = action.payload const payload: { contractData?: ContractData, address: string, name: string, abi?: any, isPinned?: boolean, pinnedAt?: number } = action.payload
return { return {
...state, ...state,
@ -499,17 +495,6 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
} }
case ADD_PINNED_INSTANCE: {
const payload: { contractData: ContractData, address: string, name: string, abi?: any, pinnedAt: number, decodedResponse?: Record<number, any> } = action.payload
return {
...state,
pinnedInstances: {
...state.pinnedInstances,
instanceList: [...state.pinnedInstances.instanceList, payload]
}
}
}
case UPDATE_INSTANCES_BALANCE: { case UPDATE_INSTANCES_BALANCE: {
const payload: Array<{ contractData: ContractData, address: string, balance: number, name: string, abi?: any, decodedResponse?: Record<number, any> }> = action.payload const payload: Array<{ contractData: ContractData, address: string, balance: number, name: string, abi?: any, decodedResponse?: Record<number, any> }> = action.payload
@ -523,50 +508,44 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case REMOVE_INSTANCE: { case REMOVE_INSTANCE: {
const payload: { index: number, isPinnedContract: boolean, shouldDelete: boolean } = action.payload const payload: { index: number } = action.payload
return {
if (payload.isPinnedContract) {
if (payload.shouldDelete) return {
...state,
pinnedInstances: {
...state.pinnedInstances,
instanceList: state.pinnedInstances.instanceList.filter((_, index) => index !== payload.index)
}
}
else return {
...state, ...state,
pinnedInstances: {
...state.pinnedInstances,
instanceList: state.pinnedInstances.instanceList.filter((_, index) => index !== payload.index)
},
instances: { instances: {
...state.instances, ...state.instances,
instanceList: [...state.instances.instanceList, state.pinnedInstances.instanceList[payload.index]] instanceList: state.instances.instanceList.filter((_, index) => index !== payload.index)
}
} }
} }
} else return {
case PIN_INSTANCE: {
const payload: { index: number, pinnedAt: number, filePath: string } = action.payload
state.instances.instanceList[payload.index].isPinned = true
state.instances.instanceList[payload.index].pinnedAt = payload.pinnedAt
state.instances.instanceList[payload.index].filePath = payload.filePath
return {
...state, ...state,
instances: { instances: {
...state.instances, ...state.instances,
instanceList: state.instances.instanceList.filter((_, index) => index !== payload.index)
} }
} }
} }
case CLEAR_INSTANCES: { case UNPIN_INSTANCE: {
const payload: { index: number } = action.payload
state.instances.instanceList[payload.index].isPinned = false
return { return {
...state, ...state,
instances: { instances: {
instanceList: [], ...state.instances,
error: null
} }
} }
} }
case CLEAR_PINNED_INSTANCES: { case CLEAR_INSTANCES: {
return { return {
...state, ...state,
pinnedInstances: { instances: {
instanceList: [], instanceList: [],
error: null error: null
} }
@ -574,19 +553,7 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
} }
case SET_DECODED_RESPONSE: { case SET_DECODED_RESPONSE: {
const payload: { instanceIndex: number, funcIndex: number, response: any, isPinnedContract: boolean } = action.payload const payload: { instanceIndex: number, funcIndex: number, response: any } = action.payload
if (action.payload.isPinnedContract)
return {
...state,
pinnedInstances: {
...state.pinnedInstances,
instanceList: state.pinnedInstances.instanceList.map((instance, index) => {
if (payload.instanceIndex === index) instance.decodedResponse[payload.funcIndex] = payload.response
return instance
})
}
}
else
return { return {
...state, ...state,
instances: { instances: {

@ -32,6 +32,8 @@ import {
setGasPriceStatus, setGasPriceStatus,
setMaxFee, setMaxFee,
setMaxPriorityFee, setMaxPriorityFee,
unpinPinnedInstance,
pinUnpinnedInstance,
removeInstances, removeInstances,
removeSingleInstance, removeSingleInstance,
getExecutionContext, getExecutionContext,
@ -342,8 +344,9 @@ export function RunTabUI(props: RunTabProps) {
<InstanceContainerUI <InstanceContainerUI
plugin={plugin} plugin={plugin}
instances={runTab.instances} instances={runTab.instances}
pinnedInstances={runTab.pinnedInstances}
clearInstances={removeInstances} clearInstances={removeInstances}
unpinInstance={unpinPinnedInstance}
pinInstance={pinUnpinnedInstance}
removeInstance={removeSingleInstance} removeInstance={removeSingleInstance}
getContext={getExecutionContext} getContext={getExecutionContext}
gasEstimationPrompt={gasEstimationPrompt} gasEstimationPrompt={gasEstimationPrompt}

@ -98,17 +98,6 @@ export interface RunTabState {
baseFeePerGas: string, baseFeePerGas: string,
gasPrice: string, gasPrice: string,
instances: { instances: {
instanceList: {
contractData?: ContractData,
address: string,
balance?: number,
name: string,
decodedResponse?: Record<number, any>,
abi?: any
}[],
error: string
},
pinnedInstances: {
instanceList: { instanceList: {
contractData?: ContractData, contractData?: ContractData,
address: string, address: string,
@ -116,7 +105,9 @@ export interface RunTabState {
name: string, name: string,
decodedResponse?: Record<number, any>, decodedResponse?: Record<number, any>,
abi?: any, abi?: any,
pinnedAt?: number isPinned?: boolean,
pinnedAt?: number,
filePath?: string
}[], }[],
error: string error: string
}, },
@ -300,17 +291,6 @@ export interface RecorderProps {
export interface InstanceContainerProps { export interface InstanceContainerProps {
instances: { instances: {
instanceList: {
contractData?: ContractData,
address: string,
balance?: number,
name: string,
decodedResponse?: Record<number, any>,
abi?: any
}[],
error: string
},
pinnedInstances: {
instanceList: { instanceList: {
contractData?: ContractData, contractData?: ContractData,
address: string, address: string,
@ -318,17 +298,19 @@ export interface InstanceContainerProps {
name: string, name: string,
decodedResponse?: Record<number, any>, decodedResponse?: Record<number, any>,
abi?: any, abi?: any,
isPinned?: boolean,
pinnedAt?: number, pinnedAt?: number,
filePath?: string filePath?: string
}[], }[],
error: string error: string
}, },
clearInstances: () => void, clearInstances: () => void,
removeInstance: (index: number, isPinnedContract:boolean, shouldDelete: boolean) => void, removeInstance: (index: number) => void,
pinInstance: (index: number, pinnedAt: number, filePath: string) => void,
unpinInstance: (index: number) => void,
getContext: () => 'memory' | 'blockchain', getContext: () => 'memory' | 'blockchain',
runTransactions: ( runTransactions: (
instanceIndex: number, instanceIndex: number,
isPinnedContract: boolean,
lookupOnly: boolean, lookupOnly: boolean,
funcABI: FuncABI, funcABI: FuncABI,
inputsValues: string, inputsValues: string,
@ -435,19 +417,20 @@ export interface UdappProps {
name: string, name: string,
decodedResponse?: Record<number, any>, decodedResponse?: Record<number, any>,
abi?: any, abi?: any,
isPinned?: boolean
pinnedAt?: number, pinnedAt?: number,
filePath?: string filePath?: string
}, },
context: 'memory' | 'blockchain', context: 'memory' | 'blockchain',
isPinnedContract?: boolean removeInstance: (index: number) => void,
removeInstance: (index: number, isPinnedContract: boolean, shouldDelete: boolean) => void, pinInstance: (index: number, pinnedAt: number, filePath: string) => void,
unpinInstance: (index: number) => void,
index: number, index: number,
gasEstimationPrompt: (msg: string) => JSX.Element, gasEstimationPrompt: (msg: string) => JSX.Element,
passphrasePrompt: (message: string) => JSX.Element, passphrasePrompt: (message: string) => JSX.Element,
mainnetPrompt: (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => JSX.Element, mainnetPrompt: (tx: Tx, network: Network, amount: string, gasEstimation: string, gasFees: (maxFee: string, cb: (txFeeText: string, priceStatus: boolean) => void) => void, determineGasPrice: (cb: (txFeeText: string, gasPriceValue: string, gasPriceStatus: boolean) => void) => void) => JSX.Element,
runTransactions: ( runTransactions: (
instanceIndex: number, instanceIndex: number,
isPinnedContract: boolean,
lookupOnly: boolean, lookupOnly: boolean,
funcABI: FuncABI, funcABI: FuncABI,
inputsValues: string, inputsValues: string,

Loading…
Cancel
Save