Display initialize inputs

pull/2260/head
David Disu 3 years ago
parent badf0e537e
commit 76045efb2d
  1. 29
      libs/remix-core-plugin/src/lib/openzeppelin-proxy.ts
  2. 10
      libs/remix-ui/run-tab/src/lib/actions/events.ts
  3. 3
      libs/remix-ui/run-tab/src/lib/actions/index.ts
  4. 2
      libs/remix-ui/run-tab/src/lib/actions/payload.ts
  5. 26
      libs/remix-ui/run-tab/src/lib/components/contractDropdownUI.tsx
  6. 69
      libs/remix-ui/run-tab/src/lib/components/contractGUI.tsx
  7. 26
      libs/remix-ui/run-tab/src/lib/reducers/runTab.ts
  8. 4
      libs/remix-ui/run-tab/src/lib/run-tab.tsx
  9. 20
      libs/remix-ui/run-tab/src/lib/types/index.ts

File diff suppressed because one or more lines are too long

@ -100,10 +100,14 @@ const broadcastCompilationResult = async (plugin: RunTab, dispatch: React.Dispat
const contracts = getCompiledContracts(compiler).map((contract) => {
return { name: languageVersion, alias: contract.name, file: contract.file, compiler }
})
const upgradeable = await plugin.call('openzeppelin-proxy', 'isConcerned', data.sources[file].ast, data.contracts[file])
const isUpgradeable = await plugin.call('openzeppelin-proxy', 'isConcerned', data.sources[file].ast)
if (upgradeable) dispatch(setDeployOptions([{ title: 'Deploy with Proxy', active: false, inputs: upgradeable.inputs }]))
else dispatch(setDeployOptions([]))
if (isUpgradeable) {
const options = await plugin.call('openzeppelin-proxy', 'getDeployOptions', data.contracts[file])
dispatch(setDeployOptions(options))
}
else dispatch(setDeployOptions({}))
dispatch(fetchContractListSuccess({ [file]: contracts }))
dispatch(setCurrentFile(file))
}

@ -3,7 +3,7 @@ import React from 'react'
import { RunTab } from '../types/run-tab'
import { resetAndInit, setupEvents } from './events'
import { createNewBlockchainAccount, fillAccountsList, setExecutionContext, signMessageWithAddress } from './account'
import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt, setNetworkNameFromProvider, setPassphrasePrompt, setSendTransactionValue, setUnit, updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath, updateTxFeeContent } from './actions'
import { clearInstances, clearPopUp, removeInstance, setAccount, setGasFee, setMatchPassphrasePrompt, setNetworkNameFromProvider, setPassphrasePrompt, setSelectedContract, setSendTransactionValue, setUnit, updateBaseFeePerGas, updateConfirmSettings, updateGasPrice, updateGasPriceStatus, updateMaxFee, updateMaxPriorityFee, updateScenarioPath, updateTxFeeContent } from './actions'
import { createInstance, getContext, getFuncABIInputs, getSelectedContract, loadAddress, runTransactions } from './deploy'
import { CompilerAbstract as CompilerAbstractType } from '@remix-project/remix-solidity-ts'
import { ContractData, FuncABI } from "@remix-project/core-plugin"
@ -58,3 +58,4 @@ export const runScenario = (gasEstimationPrompt: (msg: string) => JSX.Element, p
export const setScenarioPath = (path: string) => updateScenarioPath(dispatch, path)
export const getFuncABIValues = (funcABI: FuncABI) => getFuncABIInputs(plugin, funcABI)
export const setNetworkName = (networkName: string) => setNetworkNameFromProvider(dispatch, networkName)
export const updateSelectedContract = (contractName) => setSelectedContract(dispatch, contractName)

@ -294,7 +294,7 @@ export const removeDeployOption = (title: DeployMode) => {
}
}
export const setDeployOptions = (deployOptions: DeployOptions[]) => {
export const setDeployOptions = (deployOptions: DeployOptions) => {
return {
payload: deployOptions,
type: SET_DEPLOY_OPTIONS

@ -22,13 +22,12 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
title: 'Please compile *.sol file to deploy or access a contract',
disabled: true
})
const [selectedContract, setSelectedContract] = useState<string>('')
const [compFails, setCompFails] = useState<'none' | 'block'>('none')
const [loadedContractData, setLoadedContractData] = useState<ContractData>(null)
const [constructorInterface, setConstructorInterface] = useState<FuncABI>(null)
const [constructorInputs, setConstructorInputs] = useState(null)
const contractsRef = useRef<HTMLSelectElement>(null)
const { contractList, loadType, currentFile, compilationCount } = props.contracts
const { contractList, loadType, currentFile, currentContract, compilationCount, deployOptions } = props.contracts
useEffect(() => {
enableAtAddress(false)
@ -66,13 +65,13 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
display: 'none',
content: ''
})
if (!selectedContract) enableAtAddress(false)
if (!currentContract) enableAtAddress(false)
} else {
setAbiLabel({
display: 'none',
content: ''
})
if (!selectedContract) enableAtAddress(false)
if (!currentContract) enableAtAddress(false)
}
if (currentFile) {
enableContractNames(true)
@ -85,11 +84,11 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
}, [loadType, currentFile, compilationCount])
useEffect(() => {
if (selectedContract && contractList[currentFile]) {
const contract = contractList[currentFile].find(contract => contract.alias === selectedContract)
if (currentContract && contractList[currentFile]) {
const contract = contractList[currentFile].find(contract => contract.alias === currentContract)
if (contract) {
const loadedContractData = props.getSelectedContract(selectedContract, contract.compiler)
const loadedContractData = props.getSelectedContract(currentContract, contract.compiler)
if (loadedContractData) {
setLoadedContractData(loadedContractData)
@ -98,7 +97,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
}
}
}
}, [selectedContract, compilationCount])
}, [currentContract, compilationCount])
useEffect(() => {
initSelectedContract()
@ -108,9 +107,10 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const contracts = contractList[currentFile]
if (contracts && contracts.length > 0) {
const contract = contracts.find(contract => contract.alias === selectedContract)
const contract = contracts.find(contract => contract.alias === currentContract)
if (!selectedContract || !contract) setSelectedContract(contracts[0].alias)
if (!currentContract) props.setSelectedContract(contracts[0].alias)
else if (!contract) props.setSelectedContract(currentContract)
// TODO highlight contractlist box with css.
}
}
@ -189,7 +189,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const handleContractChange = (e) => {
const value = e.target.value
setSelectedContract(value)
props.setSelectedContract(value)
}
const checkSumWarning = () => {
@ -214,7 +214,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
<div className="udapp_container" data-id="contractDropdownContainer">
<label className="udapp_settingsLabel">Contract</label>
<div className="udapp_subcontainer">
<select ref={contractsRef} value={selectedContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} title={contractOptions.title} style={{ display: loadType === 'abi' ? 'none' : 'block' }}>
<select ref={contractsRef} value={currentContract} onChange={handleContractChange} className="udapp_contractNames custom-select" disabled={contractOptions.disabled} title={contractOptions.title} style={{ display: loadType === 'abi' ? 'none' : 'block' }}>
{ (contractList[currentFile] || []).map((contract, index) => {
return <option key={index} value={contract.alias}>{contract.alias} - {contract.file}</option>
}) }
@ -226,7 +226,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
<div className="udapp_deployDropdown">
{ ((contractList[currentFile] && contractList[currentFile].filter(contract => contract)) || []).length <= 0 ? 'No compiled contracts'
: loadedContractData ? <div>
<ContractGUI title='Deploy' isDeploy={true} deployOptions={props.deployOptions} funcABI={constructorInterface} clickCallBack={clickCallback} inputs={constructorInputs} widthClass='w-50' evmBC={loadedContractData.bytecodeObject} lookupOnly={false} />
<ContractGUI title='Deploy' isDeploy={true} deployOption={deployOptions[currentContract]} funcABI={constructorInterface} clickCallBack={clickCallback} inputs={constructorInputs} widthClass='w-50' evmBC={loadedContractData.bytecodeObject} lookupOnly={false} />
<div className="d-flex py-1 align-items-center custom-control custom-checkbox">
<input
id="deployAndRunPublishToIPFS"

@ -1,7 +1,7 @@
// eslint-disable-next-line no-use-before-define
import React, { useEffect, useRef, useState } from 'react'
import * as remixLib from '@remix-project/remix-lib'
import { ContractGUIProps, DeployOptions } from '../types'
import { ContractGUIProps } from '../types'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { ButtonGroup, Dropdown } from 'react-bootstrap'
@ -18,6 +18,7 @@ export function ContractGUI (props: ContractGUIProps) {
}>({ title: '', content: '', classList: '', dataId: '' })
const [selectedDeployIndex, setSelectedDeployIndex] = useState<number[]>([])
const [showOptions, setShowOptions] = useState<boolean>(false)
const [hasArgs, setHasArgs] = useState<boolean>(false)
const multiFields = useRef<Array<HTMLInputElement | null>>([])
const basicInputRef = useRef<HTMLInputElement>()
@ -34,6 +35,13 @@ export function ContractGUI (props: ContractGUIProps) {
basicInputRef.current.value = ''
multiFields.current.filter((el) => el !== null && el !== undefined).forEach((el) => el.value = '')
multiFields.current = []
const hasArgs = (props.funcABI.inputs && props.funcABI.inputs.length > 0) ||
(props.funcABI.type === 'fallback') ||
(props.funcABI.type === 'receive') ||
(props.isDeploy && props.deployOption && (props.deployOption.options.length > 0))
setHasArgs(hasArgs)
}, [props.title, props.funcABI])
useEffect(() => {
@ -145,7 +153,7 @@ export function ContractGUI (props: ContractGUIProps) {
}
const handleActionClick = () => {
const deployMode = selectedDeployIndex.map(index => props.deployOptions[index].title)
const deployMode = selectedDeployIndex.map(index => props.deployOption[index].title)
props.clickCallBack(props.funcABI.inputs, basicInput, props.isDeploy ? deployMode : null)
}
@ -180,20 +188,40 @@ export function ContractGUI (props: ContractGUIProps) {
}
return (
<div className={`udapp_contractProperty ${(props.funcABI.inputs && props.funcABI.inputs.length > 0) || (props.funcABI.type === 'fallback') || (props.funcABI.type === 'receive') ? 'udapp_hasArgs' : ''}`}>
<div className={`udapp_contractProperty ${hasArgs ? 'udapp_hasArgs' : ''}`}>
<div className="udapp_contractActionsContainerSingle pt-2" style={{ display: toggleContainer ? 'none' : 'flex' }}>
{
props.isDeploy && (props.deployOptions || []).length > 0?
props.isDeploy && props.deployOption && (props.deployOption.options || []).length > 0 ?
<Dropdown as={ButtonGroup} show={showOptions}>
<button onClick={handleActionClick} title={buttonOptions.title} className={`udapp_instanceButton ${props.widthClass} btn btn-sm ${buttonOptions.classList}`} data-id={buttonOptions.dataId}>Deploy</button>
<Dropdown.Toggle split id="dropdown-split-basic" className={`btn btn-sm dropdown-toggle dropdown-toggle-split ${buttonOptions.classList}`} style={{ maxWidth: 25, minWidth: 0, height: 32 }} onClick={toggleOptions} />
<Dropdown.Menu className="deploy-items border-0">
{
(props.deployOptions).map(({ title, active }, index) => <Dropdown.Item onClick={() => setSelectedDeploy(index)}> { selectedDeployIndex.includes(index) ? <span>&#10003; {title} </span> : <span className="pl-3">{title}</span> }</Dropdown.Item>)
(props.deployOption.options).map(({ title, active }, index) => <Dropdown.Item onClick={() => setSelectedDeploy(index)}> { selectedDeployIndex.includes(index) ? <span>&#10003; {title} </span> : <span className="pl-3">{title}</span> }</Dropdown.Item>)
}
</Dropdown.Menu>
</Dropdown> : <button onClick={handleActionClick} title={buttonOptions.title} className={`udapp_instanceButton ${props.widthClass} btn btn-sm ${buttonOptions.classList}`} data-id={buttonOptions.dataId}>{title}</button>
}
{
props.isDeploy && props.deployOption && props.deployOption.inputs.inputs.length > 0 &&
<>
<input
className="form-control"
data-id={props.deployOption.inputs.type === 'fallback' || props.deployOption.inputs.type === 'receive' ? `'(${props.deployOption.inputs.type}')` : 'multiParamManagerBasicInputField'}
placeholder={props.deployOption.initializeInputs}
title={props.deployOption.inputs.type === 'fallback' || props.deployOption.inputs.type === 'receive' ? `'(${props.deployOption.inputs.type}')` : props.deployOption.initializeInputs}
onChange={handleBasicInput}
ref={basicInputRef}
style={{ visibility: !((props.deployOption.inputs.inputs && props.deployOption.inputs.inputs.length > 0) || (props.deployOption.inputs.type === 'fallback') || (props.deployOption.inputs.type === 'receive')) ? 'hidden' : 'visible' }} />
<i
className="fas fa-angle-down udapp_methCaret"
onClick={switchMethodViewOn}
title={title}
style={{ visibility: !(props.deployOption.inputs.inputs && props.deployOption.inputs.inputs.length > 0) ? 'hidden' : 'visible' }}>
</i>
</>
}
{ !props.deployOption && <>
<input
className="form-control"
data-id={props.funcABI.type === 'fallback' || props.funcABI.type === 'receive' ? `'(${props.funcABI.type}')` : 'multiParamManagerBasicInputField'}
@ -206,8 +234,36 @@ export function ContractGUI (props: ContractGUIProps) {
className="fas fa-angle-down udapp_methCaret"
onClick={switchMethodViewOn}
title={title}
style={{ visibility: !(props.funcABI.inputs && props.funcABI.inputs.length > 0) ? 'hidden' : 'visible' }}></i>
style={{ visibility: !(props.funcABI.inputs && props.funcABI.inputs.length > 0) ? 'hidden' : 'visible' }}>
</i>
</>
}
</div>
{
props.isDeploy && props.deployOption && props.deployOption.inputs.inputs.length > 0 &&
<div className="udapp_contractActionsContainerMulti" style={{ display: toggleContainer ? 'flex' : 'none' }}>
<div className="udapp_contractActionsContainerMultiInner text-dark">
<div onClick={switchMethodViewOff} className="udapp_multiHeader">
<div className="udapp_multiTitle run-instance-multi-title">{title}</div>
<i className='fas fa-angle-up udapp_methCaret'></i>
</div>
<div>
{props.deployOption.inputs.inputs.map((inp, index) => {
return (
<div className="udapp_multiArg" key={index}>
<label htmlFor={inp.name}> {inp.name}: </label>
<input ref={el => { multiFields.current[index] = el }} className="form-control" placeholder={inp.type} title={inp.name} data-id={`multiParamManagerInput${inp.name}`} />
</div>)
})}
</div>
<div className="udapp_group udapp_multiArg">
{/* <CopyToClipboard tip='Encode values of input fields & copy to clipboard' icon='fa-clipboard' direction={'left'} getContent={getContentOnCTC} /> */}
<button onClick={handleExpandMultiClick} title={buttonOptions.title} data-id={buttonOptions.dataId} className={`udapp_instanceButton ${buttonOptions.classList}`}>{ buttonOptions.content }</button>
</div>
</div>
</div>
}
{ !props.deployOption &&
<div className="udapp_contractActionsContainerMulti" style={{ display: toggleContainer ? 'flex' : 'none' }}>
<div className="udapp_contractActionsContainerMultiInner text-dark">
<div onClick={switchMethodViewOff} className="udapp_multiHeader">
@ -229,6 +285,7 @@ export function ContractGUI (props: ContractGUIProps) {
</div>
</div>
</div>
}
</div>
)
}

@ -1,6 +1,6 @@
import { CompilerAbstract } from '@remix-project/remix-solidity-ts'
import { ContractData } from '@remix-project/core-plugin'
import { DeployMode, DeployOptions } from '../types'
import { DeployOption, DeployOptions } from '../types'
import { ADD_DEPLOY_OPTION, ADD_INSTANCE, 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_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_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_TX_FEE_CONTENT } from '../constants'
interface Action {
type: string
@ -64,6 +64,7 @@ export interface RunTabState {
compiler: CompilerAbstract
}[]
},
deployOptions: DeployOptions
loadType: 'abi' | 'sol' | 'other'
currentFile: string,
currentContract: string,
@ -93,8 +94,7 @@ export interface RunTabState {
recorder: {
pathToScenario: string,
transactionCount: number
},
deployOptions: DeployOptions[]
}
}
export const runTabInitialState: RunTabState = {
@ -158,6 +158,7 @@ export const runTabInitialState: RunTabState = {
matchPassphrase: '',
contracts: {
contractList: {},
deployOptions: {},
loadType: 'other',
currentFile: '',
currentContract: '',
@ -181,8 +182,7 @@ export const runTabInitialState: RunTabState = {
recorder: {
pathToScenario: 'scenario.json',
transactionCount: 0
},
deployOptions: []
}
}
type AddProvider = {
@ -688,27 +688,35 @@ export const runTabReducer = (state: RunTabState = runTabInitialState, action: A
return {
...state,
deployOptions: [...state.deployOptions, payload]
contracts: {
...state.contracts,
deployOptions: { ...state.contracts.deployOptions, ...payload }
}
}
}
case REMOVE_DEPLOY_OPTION: {
const payload: DeployMode = action.payload
const payload: string = action.payload
const options = state.contracts.deployOptions
delete options[payload]
return {
...state,
deployOptions: state.deployOptions.filter(option => option.title !== payload)
deployOptions: options
}
}
case SET_DEPLOY_OPTIONS: {
const payload: DeployOptions[] = action.payload
const payload: DeployOptions = action.payload
return {
...state,
contracts: {
...state.contracts,
deployOptions: payload
}
}
}
default:
return state

@ -26,7 +26,7 @@ import {
executeTransactions, loadFromAddress,
storeNewScenario, runScenario,
setScenarioPath, getFuncABIValues,
setNetworkName
setNetworkName, updateSelectedContract
} from './actions'
import './css/run-tab.css'
import { PublishToStorage } from '@remix-ui/publish-to-storage'
@ -244,7 +244,7 @@ export function RunTabUI (props: RunTabProps) {
loadAddress={loadFromAddress}
networkName={runTab.networkName}
setNetworkName={setNetworkName}
deployOptions={runTab.deployOptions}
setSelectedContract={updateSelectedContract}
/>
<RecorderUI
gasEstimationPrompt={gasEstimationPrompt}

@ -127,8 +127,10 @@ export interface ContractDropdownProps {
exEnvironment: string,
contracts: {
contractList: ContractList,
deployOptions: DeployOptions,
loadType: 'abi' | 'sol' | 'other',
currentFile: string,
currentContract: string,
compilationCount: number,
isRequesting: boolean,
isSuccessful: boolean,
@ -160,7 +162,7 @@ export interface ContractDropdownProps {
loadAddress: (contract: ContractData, address: string) => void,
networkName: string,
setNetworkName: (name: string) => void,
deployOptions: DeployOptions[]
setSelectedContract: (contractName: string) => void
}
export interface RecorderProps {
@ -221,12 +223,12 @@ export interface Modal {
cancelFn: () => void
}
export type DeployMode = 'Deploy with Proxy'
export interface DeployOptions {
title: DeployMode,
active: boolean,
export type DeployMode = 'Deploy with Proxy' | 'Upgrade Proxy'
export type DeployOption = {
options: { title: DeployMode, active: boolean }[],
initializeInputs: string,
inputs: {
[key: string]: {
inputs: [
{
internalType: string,
@ -240,19 +242,21 @@ export interface DeployOptions {
type: string
}
}
export interface DeployOptions {
[key: string]: DeployOption
}
export interface ContractGUIProps {
title?: string,
funcABI: FuncABI,
inputs: any,
inputs: string,
clickCallBack: (inputs: { name: string, type: string }[], input: string, deployMode?: DeployMode[]) => void,
widthClass?: string,
evmBC: any,
lookupOnly: boolean,
disabled?: boolean,
isDeploy?: boolean,
deployOptions?: DeployOptions[]
deployOption?: DeployOption
}
export interface MainnetProps {
network: Network,

Loading…
Cancel
Save