|
|
|
@ -1,93 +1,71 @@ |
|
|
|
|
var yo = require('yo-yo') |
|
|
|
|
var ethJSUtil = require('ethereumjs-util') |
|
|
|
|
var css = require('../styles/run-tab-styles') |
|
|
|
|
var executionContext = require('../../../execution-context') |
|
|
|
|
var modalDialogCustom = require('../../ui/modal-dialog-custom') |
|
|
|
|
var modalCustom = require('../../ui/modal-dialog-custom') |
|
|
|
|
var CompilerAbstract = require('../../compiler/compiler-abstract') |
|
|
|
|
var remixLib = require('remix-lib') |
|
|
|
|
var txExecution = remixLib.execution.txExecution |
|
|
|
|
var txFormat = remixLib.execution.txFormat |
|
|
|
|
var txHelper = remixLib.execution.txHelper |
|
|
|
|
var EventManager = remixLib.EventManager |
|
|
|
|
var typeConversion = remixLib.execution.typeConversion |
|
|
|
|
var confirmDialog = require('../../execution/confirmDialog') |
|
|
|
|
var modalDialog = require('../../ui/modaldialog') |
|
|
|
|
var MultiParamManager = require('../../../multiParamManager') |
|
|
|
|
|
|
|
|
|
class ContractDropdownUI { |
|
|
|
|
constructor (parentSelf) { |
|
|
|
|
constructor (dropdownLogic, parentSelf) { |
|
|
|
|
this.parentSelf = parentSelf |
|
|
|
|
this.dropdownLogic = dropdownLogic |
|
|
|
|
this.event = new EventManager() |
|
|
|
|
|
|
|
|
|
this.listenToEvents() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 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>` |
|
|
|
|
listenToEvents () { |
|
|
|
|
this.dropdownLogic.event.register('newlyCompiled', (success, data, source, compiler, compilerFullName) => { |
|
|
|
|
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) |
|
|
|
|
contractNames.innerHTML = '' |
|
|
|
|
if (success) { |
|
|
|
|
this.selectContractNames.removeAttribute('disabled') |
|
|
|
|
this.dropdownLogic.getCompiledContracts(compiler, compilerFullName).forEach((contract) => { |
|
|
|
|
contractNames.appendChild(yo`<option compiler="${compilerFullName}">${contract.name}</option>`) |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
this.selectContractNames.setAttribute('disabled', true) |
|
|
|
|
} |
|
|
|
|
this.setInputParamsPlaceHolder() |
|
|
|
|
|
|
|
|
|
var newlyCompiled = (success, data, source, compiler, compilerFullName) => { |
|
|
|
|
this.getContractNames(success, data, compiler, compilerFullName) |
|
|
|
|
if (success) { |
|
|
|
|
compFails.style.display = 'none' |
|
|
|
|
this.compFails.style.display = 'none' |
|
|
|
|
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) |
|
|
|
|
} else { |
|
|
|
|
compFails.style.display = 'block' |
|
|
|
|
this.compFails.style.display = 'block' |
|
|
|
|
document.querySelector(`.${css.contractNames}`).classList.add(css.contractNamesError) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.parentSelf._deps.pluginManager.event.register('sendCompilationResult', (file, source, languageVersion, data) => { |
|
|
|
|
// 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) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
this.parentSelf._deps.compiler.event.register('compilationFinished', (success, data, source) => { |
|
|
|
|
var name = 'solidity' |
|
|
|
|
let compiler = new CompilerAbstract(name, data) |
|
|
|
|
this.parentSelf._deps.compilersArtefacts[name] = compiler |
|
|
|
|
this.parentSelf._deps.compilersArtefacts['__last'] = compiler |
|
|
|
|
newlyCompiled(success, data, source, this.parentSelf._deps.compiler, name) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
var deployAction = (value) => { |
|
|
|
|
this.parentSelf._view.createPanel.style.display = value |
|
|
|
|
this.parentSelf._view.orLabel.style.display = value |
|
|
|
|
} |
|
|
|
|
this.dropdownLogic.event.register('currentFileChanged', this.changeCurrentFile.bind(this)) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.parentSelf._deps.fileManager.event.register('currentFileChanged', (currentFile) => { |
|
|
|
|
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) |
|
|
|
|
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) |
|
|
|
|
contractNames.innerHTML = '' |
|
|
|
|
if (/.(.abi)$/.exec(currentFile)) { |
|
|
|
|
deployAction('none') |
|
|
|
|
compFails.style.display = 'none' |
|
|
|
|
contractNames.appendChild(yo`<option>(abi)</option>`) |
|
|
|
|
this.selectContractNames.setAttribute('disabled', true) |
|
|
|
|
} else if (/.(.sol)$/.exec(currentFile)) { |
|
|
|
|
deployAction('block') |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
render () { |
|
|
|
|
this.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>` |
|
|
|
|
|
|
|
|
|
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>` |
|
|
|
|
this.createPanel = yo`<div class="${css.button}"></div>` |
|
|
|
|
this.orLabel = yo`<div class="${css.orLabel}">or</div>` |
|
|
|
|
var el = yo` |
|
|
|
|
<div class="${css.container}"> |
|
|
|
|
<div class="${css.subcontainer}"> |
|
|
|
|
${this.selectContractNames} ${compFails} ${info} |
|
|
|
|
${this.selectContractNames} ${this.compFails} ${info} |
|
|
|
|
</div> |
|
|
|
|
<div> |
|
|
|
|
${this.parentSelf._view.createPanel} |
|
|
|
|
${this.parentSelf._view.orLabel} |
|
|
|
|
${this.createPanel} |
|
|
|
|
${this.orLabel} |
|
|
|
|
<div class="${css.button} ${css.atAddressSect}"> |
|
|
|
|
<div class="${css.atAddress}" onclick=${function () { this.loadFromAddress() }}>At Address</div> |
|
|
|
|
<div class="${css.atAddress}" onclick=${this.loadFromAddress.bind(this)}>At Address</div> |
|
|
|
|
${this.atAddressButtonInput} |
|
|
|
|
</div> |
|
|
|
|
</div> |
|
|
|
@ -98,36 +76,50 @@ class ContractDropdownUI { |
|
|
|
|
return el |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
changeCurrentFile (currentFile) { |
|
|
|
|
document.querySelector(`.${css.contractNames}`).classList.remove(css.contractNamesError) |
|
|
|
|
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) |
|
|
|
|
contractNames.innerHTML = '' |
|
|
|
|
if (/.(.abi)$/.exec(currentFile)) { |
|
|
|
|
this.createPanel.style.display = 'none' |
|
|
|
|
this.orLabel.style.display = 'none' |
|
|
|
|
this.compFails.style.display = 'none' |
|
|
|
|
contractNames.appendChild(yo`<option>(abi)</option>`) |
|
|
|
|
this.selectContractNames.setAttribute('disabled', true) |
|
|
|
|
} else if (/.(.sol)$/.exec(currentFile)) { |
|
|
|
|
this.createPanel.style.display = 'block' |
|
|
|
|
this.orLabel.style.display = 'block' |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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 ctrEVMbc = selectedContract.contract.object.evm.bytecode.object |
|
|
|
|
var createConstructorInstance = new MultiParamManager(0, ctrabi, (valArray, inputsValues) => { |
|
|
|
|
this.createInstance(inputsValues, selectedContract.compiler) |
|
|
|
|
}, txHelper.inputParametersDeclarationToString(ctrabi.inputs), 'Deploy', ctrEVMbc) |
|
|
|
|
this.parentSelf._view.createPanel.appendChild(createConstructorInstance.render()) |
|
|
|
|
this.createPanel.innerHTML = '' |
|
|
|
|
if (this.selectContractNames.selectedIndex < 0 || this.selectContractNames.children.length <= 0) { |
|
|
|
|
this.createPanel.innerHTML = 'No compiled contracts' |
|
|
|
|
return |
|
|
|
|
} else { |
|
|
|
|
this.parentSelf._view.createPanel.innerHTML = 'No compiled contracts' |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var selectedContract = this.getSelectedContract() |
|
|
|
|
var ctrabi = txHelper.getConstructorInterface(selectedContract.contract.object.abi) |
|
|
|
|
var ctrEVMbc = selectedContract.contract.object.evm.bytecode.object |
|
|
|
|
var createConstructorInstance = new MultiParamManager(0, ctrabi, (valArray, inputsValues) => { |
|
|
|
|
this.createInstance(inputsValues, selectedContract.compiler) |
|
|
|
|
}, txHelper.inputParametersDeclarationToString(ctrabi.inputs), 'Deploy', ctrEVMbc) |
|
|
|
|
this.createPanel.appendChild(createConstructorInstance.render()) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getSelectedContract () { |
|
|
|
|
var contract = this.selectContractNames.children[this.selectContractNames.selectedIndex] |
|
|
|
|
var contractName = contract.innerHTML |
|
|
|
|
var compiler = this.parentSelf._deps.compilersArtefacts[contract.getAttribute('compiler')] |
|
|
|
|
var compiler = this.dropdownLogic.getContractCompiler(contract.getAttribute('compiler')) |
|
|
|
|
if (!compiler) return null |
|
|
|
|
|
|
|
|
|
if (contractName) { |
|
|
|
|
return { |
|
|
|
|
name: contractName, |
|
|
|
|
contract: compiler.getContract(contractName), |
|
|
|
|
compiler |
|
|
|
|
} |
|
|
|
|
if (!contractName) return null |
|
|
|
|
return { |
|
|
|
|
name: contractName, |
|
|
|
|
contract: compiler.getContract(contractName), |
|
|
|
|
compiler |
|
|
|
|
} |
|
|
|
|
return null |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
createInstanceCallback (selectedContract, data) { |
|
|
|
@ -214,29 +206,27 @@ class ContractDropdownUI { |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
function (okCb, cancelCb) { |
|
|
|
|
modalCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) |
|
|
|
|
modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) |
|
|
|
|
}, |
|
|
|
|
(error, txResult) => { |
|
|
|
|
if (!error) { |
|
|
|
|
var isVM = executionContext.isVM() |
|
|
|
|
if (isVM) { |
|
|
|
|
var vmError = txExecution.checkVMError(txResult) |
|
|
|
|
if (vmError.error) { |
|
|
|
|
this.parentSelf._deps.logCallback(vmError.message) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (txResult.result.status && txResult.result.status === '0x0') { |
|
|
|
|
this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) |
|
|
|
|
if (error) { |
|
|
|
|
return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`) |
|
|
|
|
} |
|
|
|
|
var isVM = executionContext.isVM() |
|
|
|
|
if (isVM) { |
|
|
|
|
var vmError = txExecution.checkVMError(txResult) |
|
|
|
|
if (vmError.error) { |
|
|
|
|
this.parentSelf._deps.logCallback(vmError.message) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
var noInstancesText = this.parentSelf._view.noInstancesText |
|
|
|
|
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } |
|
|
|
|
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress |
|
|
|
|
this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstance(selectedContract.contract.object, address, this.selectContractNames.value)) |
|
|
|
|
} else { |
|
|
|
|
this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`) |
|
|
|
|
} |
|
|
|
|
if (txResult.result.status && txResult.result.status === '0x0') { |
|
|
|
|
this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
this.event.trigger('clearInstance') |
|
|
|
|
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress |
|
|
|
|
this.event.trigger('newContractInstanceAdded', [selectedContract.contract.object, address, this.selectContractNames.value]) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
@ -317,7 +307,7 @@ class ContractDropdownUI { |
|
|
|
|
}) |
|
|
|
|
}, |
|
|
|
|
function (okCb, cancelCb) { |
|
|
|
|
modalCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) |
|
|
|
|
modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) |
|
|
|
|
}, |
|
|
|
|
runTxCallback) |
|
|
|
|
}) |
|
|
|
@ -350,46 +340,25 @@ class ContractDropdownUI { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ACCESS DEPLOYED INSTANCE
|
|
|
|
|
loadFromAddress () { |
|
|
|
|
var noInstancesText = this.parentSelf._view.noInstancesText |
|
|
|
|
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } |
|
|
|
|
this.event.trigger('clearInstance') |
|
|
|
|
|
|
|
|
|
var address = this.atAddressButtonInput.value |
|
|
|
|
if (!ethJSUtil.isValidAddress(address)) { |
|
|
|
|
return modalDialogCustom.alert('Invalid address.') |
|
|
|
|
} |
|
|
|
|
if (/[a-f]/.test(address) && /[A-F]/.test(address) && !ethJSUtil.isValidChecksumAddress(address)) { |
|
|
|
|
return modalDialogCustom.alert('Invalid checksum address.') |
|
|
|
|
} |
|
|
|
|
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 ?', () => { |
|
|
|
|
var abi |
|
|
|
|
try { |
|
|
|
|
abi = JSON.parse(this.parentSelf._deps.editor.currentContent()) |
|
|
|
|
} catch (e) { |
|
|
|
|
return modalDialogCustom.alert('Failed to parse the current file as JSON ABI.') |
|
|
|
|
this.dropdownLogic.loadContractFromAddress(address, |
|
|
|
|
(cb) => { |
|
|
|
|
modalDialogCustom.confirm(null, 'Do you really want to interact with ' + address + ' using the current ABI definition ?', cb) |
|
|
|
|
}, |
|
|
|
|
(error, loadType, abi) => { |
|
|
|
|
if (error) { |
|
|
|
|
return modalDialogCustom.alert(error) |
|
|
|
|
} |
|
|
|
|
this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstanceFromABI(abi, address, address)) |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
var selectedContract = this.getSelectedContract() |
|
|
|
|
this.instanceContainer.appendChild(this.parentSelf._deps.udappUI.renderInstance(selectedContract.contract.object, address, this.selectContractNames.value)) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// GET NAMES OF ALL THE CONTRACTS
|
|
|
|
|
getContractNames (success, data, compiler, compilerFullName) { |
|
|
|
|
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) |
|
|
|
|
contractNames.innerHTML = '' |
|
|
|
|
if (success) { |
|
|
|
|
this.selectContractNames.removeAttribute('disabled') |
|
|
|
|
compiler.visitContracts((contract) => { |
|
|
|
|
contractNames.appendChild(yo`<option compiler="${compilerFullName}">${contract.name}</option>`) |
|
|
|
|
}) |
|
|
|
|
} else { |
|
|
|
|
this.selectContractNames.setAttribute('disabled', true) |
|
|
|
|
} |
|
|
|
|
this.setInputParamsPlaceHolder() |
|
|
|
|
if (loadType === 'abi') { |
|
|
|
|
return this.event.trigger('newContractABIAdded', [abi, address]) |
|
|
|
|
} |
|
|
|
|
var selectedContract = this.getSelectedContract() |
|
|
|
|
this.event.trigger('newContractInstanceAdded', [selectedContract.contract.object, address, this.selectContractNames.value]) |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|