refactor contract dropdown into a class; add render method

pull/1/head
Iuri Matias 6 years ago committed by yann300
parent f3681345f9
commit 6a8c58cd8a
  1. 5
      src/app/tabs/run-tab.js
  2. 256
      src/app/tabs/runTab/contractDropdown.js

@ -12,7 +12,7 @@ var Recorder = require('../../recorder')
var css = require('./styles/run-tab-styles') var css = require('./styles/run-tab-styles')
var SettingsUI = require('./runTab/settings.js') var SettingsUI = require('./runTab/settings.js')
var contractDropdownUI = require('./runTab/contractDropdown.js') var ContractDropdownUI = require('./runTab/contractDropdown.js')
function runTab (opts, localRegistry) { function runTab (opts, localRegistry) {
/* ------------------------- /* -------------------------
@ -129,10 +129,11 @@ function runTab (opts, localRegistry) {
MAIN HTML ELEMENT MAIN HTML ELEMENT
--------------------------- */ --------------------------- */
var settingsUI = new SettingsUI(container, self) var settingsUI = new SettingsUI(container, self)
var contractDropdownUI = new ContractDropdownUI(self)
var el = yo` var el = yo`
<div> <div>
${settingsUI.render()} ${settingsUI.render()}
${contractDropdownUI(self.event, self)} ${contractDropdownUI.render()}
${recorderCard.render()} ${recorderCard.render()}
${self._view.instanceContainer} ${self._view.instanceContainer}
</div> </div>

@ -14,130 +14,137 @@ var confirmDialog = require('../../execution/confirmDialog')
var modalDialog = require('../../ui/modaldialog') var modalDialog = require('../../ui/modaldialog')
var MultiParamManager = require('../../../multiParamManager') var MultiParamManager = require('../../../multiParamManager')
function contractDropdown (events, self) { class ContractDropdownUI {
var instanceContainer = self._view.instanceContainer constructor (parentSelf) {
var instanceContainerTitle = self._view.instanceContainerTitle this.parentSelf = parentSelf
instanceContainer.appendChild(instanceContainerTitle)
instanceContainer.appendChild(self._view.noInstancesText)
var compFails = yo`<i title="Contract compilation failed. Please check the compile tab for more information." class="fa fa-times-circle ${css.errorIcon}" ></i>`
var info = yo`<i class="fa fa-info ${css.infoDeployAction}" aria-hidden="true" title="*.sol files allows deploying and accessing contracts. *.abi files only allows accessing contracts."></i>`
var newlyCompiled = (success, data, source, compiler, compilerFullName) => {
getContractNames(success, data, compiler, compilerFullName)
if (success) {
compFails.style.display = 'none'
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
} else {
compFails.style.display = 'block'
document.querySelector(`.${css.contractNames}`).classList.add(css.contractNamesError)
}
} }
self._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => { render () {
// TODO check whether the tab is configured this.instanceContainer = this.parentSelf._view.instanceContainer
let compiler = new CompilerAbstract(languageVersion, data) var instanceContainerTitle = this.parentSelf._view.instanceContainerTitle
self._deps.compilersArtefacts[languageVersion] = compiler this.instanceContainer.appendChild(instanceContainerTitle)
self._deps.compilersArtefacts['__last'] = compiler this.instanceContainer.appendChild(this.parentSelf._view.noInstancesText)
newlyCompiled(true, data, source, compiler, languageVersion) var compFails = yo`<i title="Contract compilation failed. Please check the compile tab for more information." class="fa fa-times-circle ${css.errorIcon}" ></i>`
}) var info = yo`<i class="fa fa-info ${css.infoDeployAction}" aria-hidden="true" title="*.sol files allows deploying and accessing contracts. *.abi files only allows accessing contracts."></i>`
self._deps.compiler.event.register('compilationFinished', (success, data, source) => {
var name = 'solidity'
let compiler = new CompilerAbstract(name, data)
self._deps.compilersArtefacts[name] = compiler
self._deps.compilersArtefacts['__last'] = compiler
newlyCompiled(success, data, source, self._deps.compiler, name)
})
var deployAction = (value) => { var newlyCompiled = (success, data, source, compiler, compilerFullName) => {
self._view.createPanel.style.display = value this.getContractNames(success, data, compiler, compilerFullName)
self._view.orLabel.style.display = value if (success) {
} compFails.style.display = 'none'
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
self._deps.fileManager.event.register('currentFileChanged', (currentFile) => { } else {
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) compFails.style.display = 'block'
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) document.querySelector(`.${css.contractNames}`).classList.add(css.contractNamesError)
contractNames.innerHTML = '' }
if (/.(.abi)$/.exec(currentFile)) {
deployAction('none')
compFails.style.display = 'none'
contractNames.appendChild(yo`<option>(abi)</option>`)
selectContractNames.setAttribute('disabled', true)
} else if (/.(.sol)$/.exec(currentFile)) {
deployAction('block')
} }
})
var atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />` this.parentSelf._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
var selectContractNames = yo`<select class="${css.contractNames}" disabled></select>` // TODO check whether the tab is configured
let compiler = new CompilerAbstract(languageVersion, data)
this.parentSelf._deps.compilersArtefacts[languageVersion] = compiler
this.parentSelf._deps.compilersArtefacts['__last'] = compiler
newlyCompiled(true, data, source, compiler, languageVersion)
})
function getSelectedContract () { this.parentSelf._deps.compiler.event.register('compilationFinished', (success, data, source) => {
var contract = selectContractNames.children[selectContractNames.selectedIndex] var name = 'solidity'
var contractName = contract.innerHTML let compiler = new CompilerAbstract(name, data)
var compiler = self._deps.compilersArtefacts[contract.getAttribute('compiler')] this.parentSelf._deps.compilersArtefacts[name] = compiler
if (!compiler) return null this.parentSelf._deps.compilersArtefacts['__last'] = compiler
newlyCompiled(success, data, source, this.parentSelf._deps.compiler, name)
})
if (contractName) { var deployAction = (value) => {
return { this.parentSelf._view.createPanel.style.display = value
name: contractName, this.parentSelf._view.orLabel.style.display = value
contract: compiler.getContract(contractName),
compiler
}
} }
return null
}
self._view.createPanel = yo`<div class="${css.button}"></div>` this.parentSelf._deps.fileManager.event.register('currentFileChanged', (currentFile) => {
self._view.orLabel = yo`<div class="${css.orLabel}">or</div>` document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
var el = yo` var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
<div class="${css.container}"> contractNames.innerHTML = ''
<div class="${css.subcontainer}"> if (/.(.abi)$/.exec(currentFile)) {
${selectContractNames} ${compFails} ${info} deployAction('none')
</div> compFails.style.display = 'none'
<div> contractNames.appendChild(yo`<option>(abi)</option>`)
${self._view.createPanel} this.selectContractNames.setAttribute('disabled', true)
${self._view.orLabel} } else if (/.(.sol)$/.exec(currentFile)) {
<div class="${css.button} ${css.atAddressSect}"> deployAction('block')
<div class="${css.atAddress}" onclick=${function () { loadFromAddress() }}>At Address</div> }
${atAddressButtonInput} })
this.atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />`
this.selectContractNames = yo`<select class="${css.contractNames}" disabled></select>`
this.parentSelf._view.createPanel = yo`<div class="${css.button}"></div>`
this.parentSelf._view.orLabel = yo`<div class="${css.orLabel}">or</div>`
var el = yo`
<div class="${css.container}">
<div class="${css.subcontainer}">
${this.selectContractNames} ${compFails} ${info}
</div>
<div>
${this.parentSelf._view.createPanel}
${this.parentSelf._view.orLabel}
<div class="${css.button} ${css.atAddressSect}">
<div class="${css.atAddress}" onclick=${function () { this.loadFromAddress() }}>At Address</div>
${this.atAddressButtonInput}
</div>
</div> </div>
</div> </div>
</div> `
` this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this))
return el
}
function setInputParamsPlaceHolder () { setInputParamsPlaceHolder () {
self._view.createPanel.innerHTML = '' this.parentSelf._view.createPanel.innerHTML = ''
if (selectContractNames.selectedIndex >= 0 && selectContractNames.children.length > 0) { if (this.selectContractNames.selectedIndex >= 0 && this.selectContractNames.children.length > 0) {
var selectedContract = getSelectedContract() var selectedContract = this.getSelectedContract()
var ctrabi = txHelper.getConstructorInterface(selectedContract.contract.object.abi) var ctrabi = txHelper.getConstructorInterface(selectedContract.contract.object.abi)
var ctrEVMbc = selectedContract.contract.object.evm.bytecode.object var ctrEVMbc = selectedContract.contract.object.evm.bytecode.object
var createConstructorInstance = new MultiParamManager(0, ctrabi, (valArray, inputsValues) => { var createConstructorInstance = new MultiParamManager(0, ctrabi, (valArray, inputsValues) => {
createInstance(inputsValues, selectedContract.compiler) this.createInstance(inputsValues, selectedContract.compiler)
}, txHelper.inputParametersDeclarationToString(ctrabi.inputs), 'Deploy', ctrEVMbc) }, txHelper.inputParametersDeclarationToString(ctrabi.inputs), 'Deploy', ctrEVMbc)
self._view.createPanel.appendChild(createConstructorInstance.render()) this.parentSelf._view.createPanel.appendChild(createConstructorInstance.render())
return return
} else { } else {
self._view.createPanel.innerHTML = 'No compiled contracts' this.parentSelf._view.createPanel.innerHTML = 'No compiled contracts'
} }
} }
selectContractNames.addEventListener('change', setInputParamsPlaceHolder) getSelectedContract () {
var contract = this.selectContractNames.children[this.selectContractNames.selectedIndex]
var contractName = contract.innerHTML
var compiler = this.parentSelf._deps.compilersArtefacts[contract.getAttribute('compiler')]
if (!compiler) return null
if (contractName) {
return {
name: contractName,
contract: compiler.getContract(contractName),
compiler
}
}
return null
}
function createInstanceCallback (selectedContract, data) { createInstanceCallback (selectedContract, data) {
self._deps.logCallback(`creation of ${selectedContract.name} pending...`) this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} pending...`)
if (data) { if (data) {
data.contractName = selectedContract.name data.contractName = selectedContract.name
data.linkReferences = selectedContract.contract.object.evm.bytecode.linkReferences data.linkReferences = selectedContract.contract.object.evm.bytecode.linkReferences
data.contractABI = selectedContract.contract.object.abi data.contractABI = selectedContract.contract.object.abi
} }
self._deps.udapp.createContract(data, this.parentSelf._deps.udapp.createContract(data,
(network, tx, gasEstimation, continueTxExecution, cancelCb) => { (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') { if (network.name !== 'Main') {
return continueTxExecution(null) return continueTxExecution(null)
} }
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether') var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self, var content = confirmDialog(tx, amount, gasEstimation, this.parentSelf,
(gasPrice, cb) => { (gasPrice, cb) => {
let txFeeText, priceStatus let txFeeText, priceStatus
// TODO: this try catch feels like an anti pattern, can/should be // TODO: this try catch feels like an anti pattern, can/should be
@ -170,7 +177,7 @@ function contractDropdown (events, self) {
modalDialog('Confirm transaction', content, modalDialog('Confirm transaction', content,
{ label: 'Confirm', { label: 'Confirm',
fn: () => { fn: () => {
self._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) this.parentSelf._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked)
// TODO: check if this is check is still valid given the refactor // TODO: check if this is check is still valid given the refactor
if (!content.gasPriceStatus) { if (!content.gasPriceStatus) {
cancelCb('Given gas price is not correct') cancelCb('Given gas price is not correct')
@ -215,28 +222,28 @@ function contractDropdown (events, self) {
if (isVM) { if (isVM) {
var vmError = txExecution.checkVMError(txResult) var vmError = txExecution.checkVMError(txResult)
if (vmError.error) { if (vmError.error) {
self._deps.logCallback(vmError.message) this.parentSelf._deps.logCallback(vmError.message)
return return
} }
} }
if (txResult.result.status && txResult.result.status === '0x0') { if (txResult.result.status && txResult.result.status === '0x0') {
self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`)
return return
} }
var noInstancesText = self._view.noInstancesText var noInstancesText = this.parentSelf._view.noInstancesText
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) }
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstance(selectedContract.contract.object, address, this.selectContractNames.value))
} else { } else {
self._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`) this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`)
} }
} }
) )
} }
// DEPLOY INSTANCE // DEPLOY INSTANCE
function createInstance (args, compiler) { createInstance (args, compiler) {
var selectedContract = getSelectedContract() var selectedContract = this.getSelectedContract()
if (selectedContract.contract.object.evm.bytecode.object.length === 0) { if (selectedContract.contract.object.evm.bytecode.object.length === 0) {
modalDialogCustom.alert('This contract may be abstract, not implement an abstract parent\'s methods completely or not invoke an inherited contract\'s constructor correctly.') modalDialogCustom.alert('This contract may be abstract, not implement an abstract parent\'s methods completely or not invoke an inherited contract\'s constructor correctly.')
@ -245,23 +252,23 @@ function contractDropdown (events, self) {
var forceSend = () => { var forceSend = () => {
var constructor = txHelper.getConstructorInterface(selectedContract.contract.object.abi) var constructor = txHelper.getConstructorInterface(selectedContract.contract.object.abi)
self._deps.filePanel.compilerMetadata().deployMetadataOf(selectedContract.name, (error, contractMetadata) => { this.parentSelf._deps.filePanel.compilerMetadata().deployMetadataOf(selectedContract.name, (error, contractMetadata) => {
if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) if (error) return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error)
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) { if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
txFormat.buildData(selectedContract.name, selectedContract.contract.object, compiler.getContracts(), true, constructor, args, (error, data) => { txFormat.buildData(selectedContract.name, selectedContract.contract.object, compiler.getContracts(), true, constructor, args, (error, data) => {
if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) if (error) return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error)
createInstanceCallback(selectedContract, data) this.createInstanceCallback(selectedContract, data)
}, (msg) => { }, (msg) => {
self._deps.logCallback(msg) this.parentSelf._deps.logCallback(msg)
}, (data, runTxCallback) => { }, (data, runTxCallback) => {
// called for libraries deployment // called for libraries deployment
self._deps.udapp.runTx(data, this.parentSelf._deps.udapp.runTx(data,
(network, tx, gasEstimation, continueTxExecution, cancelCb) => { (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') { if (network.name !== 'Main') {
return continueTxExecution(null) return continueTxExecution(null)
} }
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether') var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self, var content = confirmDialog(tx, amount, gasEstimation, this.parentSelf,
(gasPrice, cb) => { (gasPrice, cb) => {
let txFeeText, priceStatus let txFeeText, priceStatus
// TODO: this try catch feels like an anti pattern, can/should be // TODO: this try catch feels like an anti pattern, can/should be
@ -294,7 +301,7 @@ function contractDropdown (events, self) {
modalDialog('Confirm transaction', content, modalDialog('Confirm transaction', content,
{ label: 'Confirm', { label: 'Confirm',
fn: () => { fn: () => {
self._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) this.parentSelf._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked)
// TODO: check if this is check is still valid given the refactor // TODO: check if this is check is still valid given the refactor
if (!content.gasPriceStatus) { if (!content.gasPriceStatus) {
cancelCb('Given gas price is not correct') cancelCb('Given gas price is not correct')
@ -315,10 +322,10 @@ function contractDropdown (events, self) {
runTxCallback) runTxCallback)
}) })
} else { } else {
if (Object.keys(selectedContract.contract.object.evm.bytecode.linkReferences).length) self._deps.logCallback(`linking ${JSON.stringify(selectedContract.contract.object.evm.bytecode.linkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`) if (Object.keys(selectedContract.contract.object.evm.bytecode.linkReferences).length) this.parentSelf._deps.logCallback(`linking ${JSON.stringify(selectedContract.contract.object.evm.bytecode.linkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.contract.object, args, constructor, contractMetadata.linkReferences, selectedContract.contract.object.evm.bytecode.linkReferences, (error, data) => { txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.contract.object, args, constructor, contractMetadata.linkReferences, selectedContract.contract.object.evm.bytecode.linkReferences, (error, data) => {
if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) if (error) return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error)
createInstanceCallback(selectedContract, data) this.createInstanceCallback(selectedContract, data)
}) })
} }
}) })
@ -335,7 +342,7 @@ function contractDropdown (events, self) {
}}, { }}, {
label: 'Cancel', label: 'Cancel',
fn: () => { fn: () => {
self._deps.logCallback(`creation of ${selectedContract.name} canceled by user.`) this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} canceled by user.`)
} }
}) })
} else { } else {
@ -344,48 +351,47 @@ function contractDropdown (events, self) {
} }
// ACCESS DEPLOYED INSTANCE // ACCESS DEPLOYED INSTANCE
function loadFromAddress () { loadFromAddress () {
var noInstancesText = self._view.noInstancesText var noInstancesText = this.parentSelf._view.noInstancesText
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) }
var address = atAddressButtonInput.value var address = this.atAddressButtonInput.value
if (!ethJSUtil.isValidAddress(address)) { if (!ethJSUtil.isValidAddress(address)) {
return modalDialogCustom.alert('Invalid address.') return modalDialogCustom.alert('Invalid address.')
} }
if (/[a-f]/.test(address) && /[A-F]/.test(address) && !ethJSUtil.isValidChecksumAddress(address)) { if (/[a-f]/.test(address) && /[A-F]/.test(address) && !ethJSUtil.isValidChecksumAddress(address)) {
return modalDialogCustom.alert('Invalid checksum address.') return modalDialogCustom.alert('Invalid checksum address.')
} }
if (/.(.abi)$/.exec(self._deps.config.get('currentFile'))) { if (/.(.abi)$/.exec(this.parentSelf._deps.config.get('currentFile'))) {
modalDialogCustom.confirm(null, 'Do you really want to interact with ' + address + ' using the current ABI definition ?', () => { modalDialogCustom.confirm(null, 'Do you really want to interact with ' + address + ' using the current ABI definition ?', () => {
var abi var abi
try { try {
abi = JSON.parse(self._deps.editor.currentContent()) abi = JSON.parse(this.parentSelf._deps.editor.currentContent())
} catch (e) { } catch (e) {
return modalDialogCustom.alert('Failed to parse the current file as JSON ABI.') return modalDialogCustom.alert('Failed to parse the current file as JSON ABI.')
} }
instanceContainer.appendChild(self._deps.udappUI.renderInstanceFromABI(abi, address, address)) this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstanceFromABI(abi, address, address))
}) })
} else { } else {
var selectedContract = getSelectedContract() var selectedContract = this.getSelectedContract()
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstance(selectedContract.contract.object, address, this.selectContractNames.value))
} }
} }
// GET NAMES OF ALL THE CONTRACTS // GET NAMES OF ALL THE CONTRACTS
function getContractNames (success, data, compiler, compilerFullName) { getContractNames (success, data, compiler, compilerFullName) {
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
contractNames.innerHTML = '' contractNames.innerHTML = ''
if (success) { if (success) {
selectContractNames.removeAttribute('disabled') this.selectContractNames.removeAttribute('disabled')
compiler.visitContracts((contract) => { compiler.visitContracts((contract) => {
contractNames.appendChild(yo`<option compiler="${compilerFullName}">${contract.name}</option>`) contractNames.appendChild(yo`<option compiler="${compilerFullName}">${contract.name}</option>`)
}) })
} else { } else {
selectContractNames.setAttribute('disabled', true) this.selectContractNames.setAttribute('disabled', true)
} }
setInputParamsPlaceHolder() this.setInputParamsPlaceHolder()
} }
return el
} }
module.exports = contractDropdown module.exports = ContractDropdownUI

Loading…
Cancel
Save