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. 182
      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,16 +14,21 @@ 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)
render () {
this.instanceContainer = this.parentSelf._view.instanceContainer
var instanceContainerTitle = this.parentSelf._view.instanceContainerTitle
this.instanceContainer.appendChild(instanceContainerTitle)
this.instanceContainer.appendChild(this.parentSelf._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 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 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) => { var newlyCompiled = (success, data, source, compiler, compilerFullName) => {
getContractNames(success, data, compiler, compilerFullName) this.getContractNames(success, data, compiler, compilerFullName)
if (success) { if (success) {
compFails.style.display = 'none' compFails.style.display = 'none'
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
@ -33,28 +38,28 @@ function contractDropdown (events, self) {
} }
} }
self._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => { this.parentSelf._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => {
// TODO check whether the tab is configured // TODO check whether the tab is configured
let compiler = new CompilerAbstract(languageVersion, data) let compiler = new CompilerAbstract(languageVersion, data)
self._deps.compilersArtefacts[languageVersion] = compiler this.parentSelf._deps.compilersArtefacts[languageVersion] = compiler
self._deps.compilersArtefacts['__last'] = compiler this.parentSelf._deps.compilersArtefacts['__last'] = compiler
newlyCompiled(true, data, source, compiler, languageVersion) newlyCompiled(true, data, source, compiler, languageVersion)
}) })
self._deps.compiler.event.register('compilationFinished', (success, data, source) => { this.parentSelf._deps.compiler.event.register('compilationFinished', (success, data, source) => {
var name = 'solidity' var name = 'solidity'
let compiler = new CompilerAbstract(name, data) let compiler = new CompilerAbstract(name, data)
self._deps.compilersArtefacts[name] = compiler this.parentSelf._deps.compilersArtefacts[name] = compiler
self._deps.compilersArtefacts['__last'] = compiler this.parentSelf._deps.compilersArtefacts['__last'] = compiler
newlyCompiled(success, data, source, self._deps.compiler, name) newlyCompiled(success, data, source, this.parentSelf._deps.compiler, name)
}) })
var deployAction = (value) => { var deployAction = (value) => {
self._view.createPanel.style.display = value this.parentSelf._view.createPanel.style.display = value
self._view.orLabel.style.display = value this.parentSelf._view.orLabel.style.display = value
} }
self._deps.fileManager.event.register('currentFileChanged', (currentFile) => { this.parentSelf._deps.fileManager.event.register('currentFileChanged', (currentFile) => {
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError)
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`)
contractNames.innerHTML = '' contractNames.innerHTML = ''
@ -62,82 +67,84 @@ function contractDropdown (events, self) {
deployAction('none') deployAction('none')
compFails.style.display = 'none' compFails.style.display = 'none'
contractNames.appendChild(yo`<option>(abi)</option>`) contractNames.appendChild(yo`<option>(abi)</option>`)
selectContractNames.setAttribute('disabled', true) this.selectContractNames.setAttribute('disabled', true)
} else if (/.(.sol)$/.exec(currentFile)) { } else if (/.(.sol)$/.exec(currentFile)) {
deployAction('block') deployAction('block')
} }
}) })
var atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />` this.atAddressButtonInput = yo`<input class="${css.input} ataddressinput" placeholder="Load contract from Address" title="atAddress" />`
var selectContractNames = yo`<select class="${css.contractNames}" disabled></select>` this.selectContractNames = yo`<select class="${css.contractNames}" disabled></select>`
function getSelectedContract () {
var contract = selectContractNames.children[selectContractNames.selectedIndex]
var contractName = contract.innerHTML
var compiler = self._deps.compilersArtefacts[contract.getAttribute('compiler')]
if (!compiler) return null
if (contractName) {
return {
name: contractName,
contract: compiler.getContract(contractName),
compiler
}
}
return null
}
self._view.createPanel = yo`<div class="${css.button}"></div>` this.parentSelf._view.createPanel = yo`<div class="${css.button}"></div>`
self._view.orLabel = yo`<div class="${css.orLabel}">or</div>` this.parentSelf._view.orLabel = yo`<div class="${css.orLabel}">or</div>`
var el = yo` var el = yo`
<div class="${css.container}"> <div class="${css.container}">
<div class="${css.subcontainer}"> <div class="${css.subcontainer}">
${selectContractNames} ${compFails} ${info} ${this.selectContractNames} ${compFails} ${info}
</div> </div>
<div> <div>
${self._view.createPanel} ${this.parentSelf._view.createPanel}
${self._view.orLabel} ${this.parentSelf._view.orLabel}
<div class="${css.button} ${css.atAddressSect}"> <div class="${css.button} ${css.atAddressSect}">
<div class="${css.atAddress}" onclick=${function () { loadFromAddress() }}>At Address</div> <div class="${css.atAddress}" onclick=${function () { this.loadFromAddress() }}>At Address</div>
${atAddressButtonInput} ${this.atAddressButtonInput}
</div> </div>
</div> </div>
</div> </div>
` `
this.selectContractNames.addEventListener('change', this.setInputParamsPlaceHolder.bind(this))
function setInputParamsPlaceHolder () { return el
self._view.createPanel.innerHTML = '' }
if (selectContractNames.selectedIndex >= 0 && selectContractNames.children.length > 0) {
var selectedContract = getSelectedContract() setInputParamsPlaceHolder () {
this.parentSelf._view.createPanel.innerHTML = ''
if (this.selectContractNames.selectedIndex >= 0 && this.selectContractNames.children.length > 0) {
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
function createInstanceCallback (selectedContract, data) { if (contractName) {
self._deps.logCallback(`creation of ${selectedContract.name} pending...`) return {
name: contractName,
contract: compiler.getContract(contractName),
compiler
}
}
return null
}
createInstanceCallback (selectedContract, data) {
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