@ -5,9 +5,9 @@ import { ContractData, FuncABI } from '@remix-project/core-plugin'
import * as ethJSUtil from 'ethereumjs-util'
import { ContractGUI } from './contractGUI'
import { deployWithProxyMsg , upgradeWithProxyMsg } from '@remix-ui/helper'
import { OverlayTrigger , Tooltip } from 'react-bootstrap'
import { Dropdown , OverlayTrigger , Tooltip } from 'react-bootstrap'
export function ContractDropdownUI ( props : ContractDropdownProps ) {
export function ContractDropdownUI ( props : ContractDropdownProps ) {
const [ abiLabel , setAbiLabel ] = useState < {
display : string ,
content : string
@ -15,18 +15,19 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
display : '' ,
content : ''
} )
const [ atAddressOptions , setAtAddressOptions ] = useState < { title : string , disabled : boolean } > ( {
const [ atAddressOptions , setAtAddressOptions ] = useState < { title : string , disabled : boolean } > ( {
title : 'address of contract' ,
disabled : true
} )
const [ loadedAddress , setLoadedAddress ] = useState < string > ( '' )
const [ contractOptions , setContractOptions ] = useState < { title : string , disabled : boolean } > ( {
const [ contractOptions , setContractOptions ] = useState < { title : string , disabled : boolean } > ( {
title : 'Please compile *.sol file to deploy or access a contract' ,
disabled : true
} )
const [ loadedContractData , setLoadedContractData ] = useState < ContractData > ( null )
const [ constructorInterface , setConstructorInterface ] = useState < FuncABI > ( null )
const [ constructorInputs , setConstructorInputs ] = useState ( null )
const [ compilerName , setCompilerName ] = useState < string > ( '' )
const contractsRef = useRef < HTMLSelectElement > ( null )
const atAddressValue = useRef < HTMLInputElement > ( null )
const { contractList , loadType , currentFile , compilationSource , currentContract , compilationCount , deployOptions , proxyKey } = props . contracts
@ -97,20 +98,23 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
useEffect ( ( ) = > {
initSelectedContract ( )
updateCompilerName ( )
} , [ contractList ] )
useEffect ( ( ) = > {
// if the file change the ui is already feed with another bunch of contracts.
// we also need to update the state
const contracts = contractList [ currentFile ]
const contracts = contractList [ currentFile ]
if ( contracts && contracts . length > 0 ) {
props . setSelectedContract ( contracts [ 0 ] . alias )
}
updateCompilerName ( )
} , [ currentFile ] )
const initSelectedContract = ( ) = > {
const contracts = contractList [ currentFile ]
if ( contracts && contracts . length > 0 ) {
const contract = contracts . find ( contract = > contract . alias === currentContract )
@ -122,9 +126,9 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const isContractFile = ( file ) = > {
return /.(.sol)$/ . exec ( file ) ||
/.(.vy)$/ . exec ( file ) || // vyper
/.(.lex)$/ . exec ( file ) || // lexon
/.(.contract)$/ . exec ( file )
/.(.vy)$/ . exec ( file ) || // vyper
/.(.lex)$/ . exec ( file ) || // lexon
/.(.contract)$/ . exec ( file )
}
const enableAtAddress = ( enable : boolean ) = > {
@ -161,20 +165,20 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const createInstance = ( selectedContract , args , deployMode? : DeployMode [ ] ) = > {
if ( selectedContract . bytecodeObject . length === 0 ) {
return props . modal ( 'Alert' , 'This contract may be abstract, it may not implement an abstract parent\'s methods completely or it may not invoke an inherited contract\'s constructor correctly.' , 'OK' , ( ) = > { } )
return props . modal ( 'Alert' , 'This contract may be abstract, it may not implement an abstract parent\'s methods completely or it may not invoke an inherited contract\'s constructor correctly.' , 'OK' , ( ) = > { } )
}
if ( ( selectedContract . name !== currentContract ) && ( selectedContract . name === 'ERC1967Proxy' ) ) selectedContract . name = currentContract
const isProxyDeployment = ( deployMode || [ ] ) . find ( mode = > mode === 'Deploy with Proxy' )
const isContractUpgrade = ( deployMode || [ ] ) . find ( mode = > mode === 'Upgrade with Proxy' )
if ( isProxyDeployment ) {
props . modal ( 'Deploy Implementation & Proxy (ERC1967)' , deployWithProxyMsg ( ) , 'Proceed' , ( ) = > {
props . createInstance ( loadedContractData , props . gasEstimationPrompt , props . passphrasePrompt , props . publishToStorage , props . mainnetPrompt , isOverSizePrompt , args , deployMode )
} , 'Cancel' , ( ) = > { } )
} , 'Cancel' , ( ) = > { } )
} else if ( isContractUpgrade ) {
props . modal ( 'Deploy Implementation & Update Proxy' , upgradeWithProxyMsg ( ) , 'Proceed' , ( ) = > {
props . createInstance ( loadedContractData , props . gasEstimationPrompt , props . passphrasePrompt , props . publishToStorage , props . mainnetPrompt , isOverSizePrompt , args , deployMode )
} , 'Cancel' , ( ) = > { } )
} , 'Cancel' , ( ) = > { } )
} else {
props . createInstance ( loadedContractData , props . gasEstimationPrompt , props . passphrasePrompt , props . publishToStorage , props . mainnetPrompt , isOverSizePrompt , args , deployMode )
}
@ -211,9 +215,25 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
window . localStorage . setItem ( ` ipfs/ ${ props . exEnvironment } / ${ props . networkName } ` , checkedState . toString ( ) )
}
const updateCompilerName = ( ) = > {
console . log ( 'updateCompilerName' , contractsRef . current . value )
if ( contractsRef . current . value ) {
console . log ( contractsRef . current . value )
const compilerNames = [ . . . new Set ( [ . . . contractList [ currentFile ] . map ( contract = > contract . compilerName ) ] ) ]
console . log ( compilerNames )
contractList [ currentFile ] . forEach ( contract = > {
if ( contract . alias === contractsRef . current . value ) {
setCompilerName ( contract . compilerName )
}
} )
} else {
setCompilerName ( '' )
}
}
const handleContractChange = ( e ) = > {
const value = e . target . value
updateCompilerName ( )
props . setSelectedContract ( value )
}
@ -230,7 +250,7 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
const isOverSizePrompt = ( ) = > {
return (
< div > Contract creation initialization returns data with length of more than 24576 bytes . The deployment will likely fails . < br / >
More info : < a href = "https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md" target = "_blank" rel = "noreferrer" > eip - 170 < / a >
More info : < a href = "https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md" target = "_blank" rel = "noreferrer" > eip - 170 < / a >
< / div >
)
}
@ -240,30 +260,34 @@ export function ContractDropdownUI (props: ContractDropdownProps) {
< div className = 'd-flex justify-content-between' >
< div className = "d-flex justify-content-between align-items-end" >
< label className = "udapp_settingsLabel pr-1" > Contract < / label >
< div className = "d-flex" > { Object . keys ( props . contracts . contractList ) . length > 0 && compilationSourc e !== '' && < label className = "text-capitalize" style = { { maxHeight : '0.6rem' , lineHeight : '1rem' } } data - id = "udappCompiledBy" > ( Compiled by { compilationSourc e } ) < / label > } < / div >
< div className = "d-flex" > { compilerName && compilerNam e !== '' && < label className = "text-capitalize" style = { { maxHeight : '0.6rem' , lineHeight : '1rem' } } data - id = "udappCompiledBy" > ( Compiled by { compilerNam e } ) < / label > } < / div >
< / div >
< OverlayTrigger placement = { 'right' } overlay = {
< Tooltip className = "text-nowrap" id = "info-sync-compiled-contract" >
< div > Click here to import contracts compiled from an external framework . < / div >
< div > This action is enabled when Remix is connected to an external framework ( hardhat , truffle , foundry ) through remixd . < / div >
< / Tooltip >
} >
< button className = "btn d-flex py-0" onClick = { _ = > props . syncContracts ( ) } >
< i style = { { cursor : 'pointer' } } className = "fa fa-refresh mr-2 mt-2" aria - hidden = "true" > < / i >
< / button >
< / OverlayTrigger >
{ props . remixdActivated ?
< OverlayTrigger placement = { 'right' } overlay = {
< Tooltip className = "text-nowrap" id = "info-sync-compiled-contract" >
< div > Click here to import contracts compiled from an external framework . < / div >
< div > This action is enabled when Remix is connected to an external framework ( hardhat , truffle , foundry ) through remixd . < / div >
< / Tooltip >
} >
< button className = "btn d-flex py-0" onClick = { _ = > props . syncContracts ( ) } >
< i style = { { cursor : 'pointer' } } className = "fa fa-refresh mr-2 mt-2" aria - hidden = "true" > < / i >
< / button >
< / OverlayTrigger >
: null }
< / div >
< div className = "udapp_subcontainer" >
< select ref = { contractsRef } value = { currentContract } onChange = { handleContractChange } className = "udapp_contractNames custom-select" disabled = { contractOptions . disabled } title = { contractOptions . title } style = { { display : loadType === 'abi' && ! isContractFile ( currentFile ) ? 'none' : 'block' } } >
{ ( contractList [ currentFile ] || [ ] ) . map ( ( contract , index ) = > {
return < option key = { index } value = { contract . alias } > { contract . alias } - { contract . file } < / option >
} ) }
< select ref = { contractsRef } value = { currentContract } onChange = { handleContractChange } className = "udapp_contractNames custom-select" disabled = { contractOptions . disabled } title = { contractOptions . title } style = { { display : loadType === 'abi' && ! isContractFile ( currentFile ) ? 'none' : 'block' } } >
{ ( contractList [ currentFile ] || [ ] ) . map ( ( contract , index ) = > {
return < option key = { index } value = { contract . alias } >
{ contract . alias } - { contract . file }
< / option >
} ) }
< / select >
< span className = "py-1" style = { { display : abiLabel.display } } > { abiLabel . content } < / span >
< span className = "py-1" style = { { display : abiLabel.display } } > { abiLabel . content } < / span >
< / div >
< div >
< div className = "udapp_deployDropdown" >
{ ( ( contractList [ currentFile ] && contractList [ currentFile ] . filter ( contract = > contract ) ) || [ ] ) . length <= 0 ? 'No compiled contracts'
{ ( ( contractList [ currentFile ] && contractList [ currentFile ] . filter ( contract = > contract ) ) || [ ] ) . length <= 0 ? 'No compiled contracts'
: loadedContractData ? < div >
< ContractGUI
title = 'Deploy'