parent
57c73094d8
commit
9dc1ad76db
@ -0,0 +1,391 @@ |
||||
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 typeConversion = remixLib.execution.typeConversion |
||||
var confirmDialog = require('../../execution/confirmDialog') |
||||
var modalDialog = require('../../ui/modaldialog') |
||||
var MultiParamManager = require('../../../multiParamManager') |
||||
|
||||
function contractDropdown (events, self) { |
||||
var instanceContainer = self._view.instanceContainer |
||||
var instanceContainerTitle = self._view.instanceContainerTitle |
||||
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) => { |
||||
// TODO check whether the tab is configured
|
||||
let compiler = new CompilerAbstract(languageVersion, data) |
||||
self._deps.compilersArtefacts[languageVersion] = compiler |
||||
self._deps.compilersArtefacts['__last'] = compiler |
||||
newlyCompiled(true, data, source, compiler, languageVersion) |
||||
}) |
||||
|
||||
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) => { |
||||
self._view.createPanel.style.display = value |
||||
self._view.orLabel.style.display = value |
||||
} |
||||
|
||||
self._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>`) |
||||
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" />` |
||||
var 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>` |
||||
self._view.orLabel = yo`<div class="${css.orLabel}">or</div>` |
||||
var el = yo` |
||||
<div class="${css.container}"> |
||||
<div class="${css.subcontainer}"> |
||||
${selectContractNames} ${compFails} ${info} |
||||
</div> |
||||
<div> |
||||
${self._view.createPanel} |
||||
${self._view.orLabel} |
||||
<div class="${css.button} ${css.atAddressSect}"> |
||||
<div class="${css.atAddress}" onclick=${function () { loadFromAddress() }}>At Address</div> |
||||
${atAddressButtonInput} |
||||
</div> |
||||
</div> |
||||
</div> |
||||
` |
||||
|
||||
function setInputParamsPlaceHolder () { |
||||
self._view.createPanel.innerHTML = '' |
||||
if (selectContractNames.selectedIndex >= 0 && selectContractNames.children.length > 0) { |
||||
var selectedContract = 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) => { |
||||
createInstance(inputsValues, selectedContract.compiler) |
||||
}, txHelper.inputParametersDeclarationToString(ctrabi.inputs), 'Deploy', ctrEVMbc) |
||||
self._view.createPanel.appendChild(createConstructorInstance.render()) |
||||
return |
||||
} else { |
||||
self._view.createPanel.innerHTML = 'No compiled contracts' |
||||
} |
||||
} |
||||
|
||||
selectContractNames.addEventListener('change', setInputParamsPlaceHolder) |
||||
|
||||
function createInstanceCallback (selectedContract, data) { |
||||
self._deps.logCallback(`creation of ${selectedContract.name} pending...`) |
||||
if (data) { |
||||
data.contractName = selectedContract.name |
||||
data.linkReferences = selectedContract.contract.object.evm.bytecode.linkReferences |
||||
data.contractABI = selectedContract.contract.object.abi |
||||
} |
||||
self._deps.udapp.createContract(data, |
||||
|
||||
(network, tx, gasEstimation, continueTxExecution, cancelCb) => { |
||||
if (network.name !== 'Main') { |
||||
return continueTxExecution(null) |
||||
} |
||||
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether') |
||||
var content = confirmDialog(tx, amount, gasEstimation, self, |
||||
(gasPrice, cb) => { |
||||
let txFeeText, priceStatus |
||||
// TODO: this try catch feels like an anti pattern, can/should be
|
||||
// removed, but for now keeping the original logic
|
||||
try { |
||||
var fee = executionContext.web3().toBigNumber(tx.gas).mul(executionContext.web3().toBigNumber(executionContext.web3().toWei(gasPrice.toString(10), 'gwei'))) |
||||
txFeeText = ' ' + executionContext.web3().fromWei(fee.toString(10), 'ether') + ' Ether' |
||||
priceStatus = true |
||||
} catch (e) { |
||||
txFeeText = ' Please fix this issue before sending any transaction. ' + e.message |
||||
priceStatus = false |
||||
} |
||||
cb(txFeeText, priceStatus) |
||||
}, |
||||
(cb) => { |
||||
executionContext.web3().eth.getGasPrice((error, gasPrice) => { |
||||
var warnMessage = ' Please fix this issue before sending any transaction. ' |
||||
if (error) { |
||||
return cb('Unable to retrieve the current network gas price.' + warnMessage + error) |
||||
} |
||||
try { |
||||
var gasPriceValue = executionContext.web3().fromWei(gasPrice.toString(10), 'gwei') |
||||
cb(null, gasPriceValue) |
||||
} catch (e) { |
||||
cb(warnMessage + e.message, null, false) |
||||
} |
||||
}) |
||||
} |
||||
) |
||||
modalDialog('Confirm transaction', content, |
||||
{ label: 'Confirm', |
||||
fn: () => { |
||||
self._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) |
||||
// TODO: check if this is check is still valid given the refactor
|
||||
if (!content.gasPriceStatus) { |
||||
cancelCb('Given gas price is not correct') |
||||
} else { |
||||
var gasPrice = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei') |
||||
continueTxExecution(gasPrice) |
||||
} |
||||
}}, { |
||||
label: 'Cancel', |
||||
fn: () => { |
||||
return cancelCb('Transaction canceled by user.') |
||||
} |
||||
}) |
||||
}, |
||||
(error, continueTxExecution, cancelCb) => { |
||||
if (error) { |
||||
var msg = typeof error !== 'string' ? error.message : error |
||||
modalDialog('Gas estimation failed', yo`<div>Gas estimation errored with the following message (see below).
|
||||
The transaction execution will likely fail. Do you want to force sending? <br> |
||||
${msg} |
||||
</div>`, |
||||
{ |
||||
label: 'Send Transaction', |
||||
fn: () => { |
||||
continueTxExecution() |
||||
}}, { |
||||
label: 'Cancel Transaction', |
||||
fn: () => { |
||||
cancelCb() |
||||
} |
||||
}) |
||||
} else { |
||||
continueTxExecution() |
||||
} |
||||
}, |
||||
function (okCb, cancelCb) { |
||||
modalCustom.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) { |
||||
self._deps.logCallback(vmError.message) |
||||
return |
||||
} |
||||
} |
||||
if (txResult.result.status && txResult.result.status === '0x0') { |
||||
self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) |
||||
return |
||||
} |
||||
var noInstancesText = self._view.noInstancesText |
||||
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } |
||||
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress |
||||
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) |
||||
} else { |
||||
self._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`) |
||||
} |
||||
} |
||||
) |
||||
} |
||||
|
||||
// DEPLOY INSTANCE
|
||||
function createInstance (args, compiler) { |
||||
var selectedContract = getSelectedContract() |
||||
|
||||
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.') |
||||
return |
||||
} |
||||
|
||||
var forceSend = () => { |
||||
var constructor = txHelper.getConstructorInterface(selectedContract.contract.object.abi) |
||||
self._deps.filePanel.compilerMetadata().deployMetadataOf(selectedContract.name, (error, contractMetadata) => { |
||||
if (error) return self._deps.logCallback(`creation of ${selectedContract.name} errored: ` + error) |
||||
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) { |
||||
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) |
||||
createInstanceCallback(selectedContract, data) |
||||
}, (msg) => { |
||||
self._deps.logCallback(msg) |
||||
}, (data, runTxCallback) => { |
||||
// called for libraries deployment
|
||||
self._deps.udapp.runTx(data, |
||||
(network, tx, gasEstimation, continueTxExecution, cancelCb) => { |
||||
if (network.name !== 'Main') { |
||||
return continueTxExecution(null) |
||||
} |
||||
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether') |
||||
var content = confirmDialog(tx, amount, gasEstimation, self, |
||||
(gasPrice, cb) => { |
||||
let txFeeText, priceStatus |
||||
// TODO: this try catch feels like an anti pattern, can/should be
|
||||
// removed, but for now keeping the original logic
|
||||
try { |
||||
var fee = executionContext.web3().toBigNumber(tx.gas).mul(executionContext.web3().toBigNumber(executionContext.web3().toWei(gasPrice.toString(10), 'gwei'))) |
||||
txFeeText = ' ' + executionContext.web3().fromWei(fee.toString(10), 'ether') + ' Ether' |
||||
priceStatus = true |
||||
} catch (e) { |
||||
txFeeText = ' Please fix this issue before sending any transaction. ' + e.message |
||||
priceStatus = false |
||||
} |
||||
cb(txFeeText, priceStatus) |
||||
}, |
||||
(cb) => { |
||||
executionContext.web3().eth.getGasPrice((error, gasPrice) => { |
||||
var warnMessage = ' Please fix this issue before sending any transaction. ' |
||||
if (error) { |
||||
return cb('Unable to retrieve the current network gas price.' + warnMessage + error) |
||||
} |
||||
try { |
||||
var gasPriceValue = executionContext.web3().fromWei(gasPrice.toString(10), 'gwei') |
||||
cb(null, gasPriceValue) |
||||
} catch (e) { |
||||
cb(warnMessage + e.message, null, false) |
||||
} |
||||
}) |
||||
} |
||||
) |
||||
modalDialog('Confirm transaction', content, |
||||
{ label: 'Confirm', |
||||
fn: () => { |
||||
self._deps.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) |
||||
// TODO: check if this is check is still valid given the refactor
|
||||
if (!content.gasPriceStatus) { |
||||
cancelCb('Given gas price is not correct') |
||||
} else { |
||||
var gasPrice = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei') |
||||
continueTxExecution(gasPrice) |
||||
} |
||||
}}, { |
||||
label: 'Cancel', |
||||
fn: () => { |
||||
return cancelCb('Transaction canceled by user.') |
||||
} |
||||
}) |
||||
}, |
||||
function (okCb, cancelCb) { |
||||
modalCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) |
||||
}, |
||||
runTxCallback) |
||||
}) |
||||
} 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')}`) |
||||
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) |
||||
createInstanceCallback(selectedContract, data) |
||||
}) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
if (selectedContract.contract.object.evm.deployedBytecode && selectedContract.contract.object.evm.deployedBytecode.object.length / 2 > 24576) { |
||||
modalDialog('Contract code size over limit', yo`<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">eip-170</a> |
||||
</div>`, |
||||
{ |
||||
label: 'Force Send', |
||||
fn: () => { |
||||
forceSend() |
||||
}}, { |
||||
label: 'Cancel', |
||||
fn: () => { |
||||
self._deps.logCallback(`creation of ${selectedContract.name} canceled by user.`) |
||||
} |
||||
}) |
||||
} else { |
||||
forceSend() |
||||
} |
||||
} |
||||
|
||||
// ACCESS DEPLOYED INSTANCE
|
||||
function loadFromAddress () { |
||||
var noInstancesText = self._view.noInstancesText |
||||
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) } |
||||
var address = 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(self._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(self._deps.editor.currentContent()) |
||||
} catch (e) { |
||||
return modalDialogCustom.alert('Failed to parse the current file as JSON ABI.') |
||||
} |
||||
instanceContainer.appendChild(self._deps.udappUI.renderInstanceFromABI(abi, address, address)) |
||||
}) |
||||
} else { |
||||
var selectedContract = getSelectedContract() |
||||
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value)) |
||||
} |
||||
} |
||||
|
||||
// GET NAMES OF ALL THE CONTRACTS
|
||||
function getContractNames (success, data, compiler, compilerFullName) { |
||||
var contractNames = document.querySelector(`.${css.contractNames.classNames[0]}`) |
||||
contractNames.innerHTML = '' |
||||
if (success) { |
||||
selectContractNames.removeAttribute('disabled') |
||||
compiler.visitContracts((contract) => { |
||||
contractNames.appendChild(yo`<option compiler="${compilerFullName}">${contract.name}</option>`) |
||||
}) |
||||
} else { |
||||
selectContractNames.setAttribute('disabled', true) |
||||
} |
||||
setInputParamsPlaceHolder() |
||||
} |
||||
|
||||
return el |
||||
} |
||||
|
||||
module.exports = contractDropdown |
@ -0,0 +1,299 @@ |
||||
var $ = require('jquery') |
||||
var yo = require('yo-yo') |
||||
var ethJSUtil = require('ethereumjs-util') |
||||
var Personal = require('web3-eth-personal') |
||||
var css = require('../styles/run-tab-styles') |
||||
var executionContext = require('../../../execution-context') |
||||
var copyToClipboard = require('../../ui/copy-to-clipboard') |
||||
var modalDialogCustom = require('../../ui/modal-dialog-custom') |
||||
var addTooltip = require('../../ui/tooltip') |
||||
var modalCustom = require('../../ui/modal-dialog-custom') |
||||
var tootip = require('../../ui/tooltip') |
||||
var helper = require('../../../lib/helper.js') |
||||
|
||||
function settings (container, self) { |
||||
// VARIABLES
|
||||
var net = yo`<span class=${css.network}></span>` |
||||
var networkcallid = 0 |
||||
const updateNetwork = (cb) => { |
||||
networkcallid++ |
||||
(function (callid) { |
||||
executionContext.detectNetwork((err, { id, name } = {}) => { |
||||
if (networkcallid > callid) return |
||||
networkcallid++ |
||||
if (err) { |
||||
console.error(err) |
||||
net.innerHTML = 'can\'t detect network ' |
||||
} else { |
||||
net.innerHTML = `<i class="${css.networkItem} fa fa-plug" aria-hidden="true"></i> ${name} (${id || '-'})` |
||||
} |
||||
if (cb) cb(err, {id, name}) |
||||
}) |
||||
})(networkcallid) |
||||
} |
||||
var environmentEl = yo` |
||||
<div class="${css.crow}"> |
||||
<div id="selectExEnv" class="${css.col1_1}"> |
||||
Environment |
||||
</div> |
||||
<div class=${css.environment}> |
||||
${net} |
||||
<select id="selectExEnvOptions" onchange=${() => { updateNetwork() }} class="${css.select}"> |
||||
<option id="vm-mode" |
||||
title="Execution environment does not connect to any node, everything is local and in memory only." |
||||
value="vm" checked name="executionContext"> JavaScript VM |
||||
</option> |
||||
<option id="injected-mode" |
||||
title="Execution environment has been provided by Metamask or similar provider." |
||||
value="injected" checked name="executionContext"> Injected Web3 |
||||
</option> |
||||
<option id="web3-mode" |
||||
title="Execution environment connects to node at localhost (or via IPC if available), transactions will be sent to the network and can cause loss of money or worse! |
||||
If this page is served via https and you access your node via http, it might not work. In this case, try cloning the repository and serving it via http." |
||||
value="web3" name="executionContext"> Web3 Provider |
||||
</option> |
||||
</select> |
||||
<a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md" target="_blank"><i class="${css.icon} fa fa-info"></i></a> |
||||
</div> |
||||
</div> |
||||
` |
||||
var accountEl = yo` |
||||
<div class="${css.crow}"> |
||||
<div class="${css.col1_1}"> |
||||
Account |
||||
<i class="fa fa-plus-circle ${css.icon}" aria-hidden="true" onclick=${newAccount} title="Create a new account"></i> |
||||
</div> |
||||
<div class=${css.account}> |
||||
<select name="txorigin" class="${css.select}" id="txorigin"></select> |
||||
${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)} |
||||
<i class="fa fa-pencil-square-o ${css.icon}" aria-hiden="true" onclick=${signMessage} title="Sign a message using this account key"></i> |
||||
</div> |
||||
</div> |
||||
` |
||||
var gasPriceEl = yo` |
||||
<div class="${css.crow}"> |
||||
<div class="${css.col1_1}">Gas limit</div> |
||||
<input type="number" class="${css.col2}" id="gasLimit" value="3000000"> |
||||
</div> |
||||
` |
||||
var valueEl = yo` |
||||
<div class="${css.crow}"> |
||||
<div class="${css.col1_1}">Value</div> |
||||
<input type="text" class="${css.col2_1}" id="value" value="0" title="Enter the value and choose the unit"> |
||||
<select name="unit" class="${css.col2_2}" id="unit"> |
||||
<option data-unit="wei">wei</option> |
||||
<option data-unit="gwei">gwei</option> |
||||
<option data-unit="finney">finney</option> |
||||
<option data-unit="ether">ether</option> |
||||
</select> |
||||
</div> |
||||
` |
||||
// DOM ELEMENT
|
||||
var el = yo` |
||||
<div class="${css.settings}"> |
||||
${environmentEl} |
||||
${accountEl} |
||||
${gasPriceEl} |
||||
${valueEl} |
||||
</div> |
||||
` |
||||
// HELPER FUNCTIONS AND EVENTS
|
||||
self._deps.udapp.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { |
||||
if (error) return |
||||
if (!lookupOnly) el.querySelector('#value').value = '0' |
||||
updateAccountBalances(container, self) |
||||
}) |
||||
|
||||
// DROPDOWN
|
||||
var selectExEnv = environmentEl.querySelector('#selectExEnvOptions') |
||||
|
||||
function setFinalContext () { |
||||
// set the final context. Cause it is possible that this is not the one we've originaly selected
|
||||
selectExEnv.value = executionContext.getProvider() |
||||
self.event.trigger('clearInstance', []) |
||||
updateNetwork() |
||||
fillAccountsList(el, self) |
||||
} |
||||
|
||||
self.event.register('clearInstance', () => { |
||||
var instanceContainer = self._view.instanceContainer |
||||
var instanceContainerTitle = self._view.instanceContainerTitle |
||||
instanceContainer.innerHTML = '' // clear the instances list
|
||||
instanceContainer.appendChild(instanceContainerTitle) |
||||
instanceContainer.appendChild(self._view.noInstancesText) |
||||
}) |
||||
|
||||
executionContext.event.register('addProvider', (network) => { |
||||
selectExEnv.appendChild(yo`<option
|
||||
title="Manually added environment: ${network.url}" |
||||
value="${network.name}" name="executionContext"> ${network.name} |
||||
</option>`) |
||||
tootip(`${network.name} [${network.url}] added`) |
||||
}) |
||||
|
||||
executionContext.event.register('removeProvider', (name) => { |
||||
var env = selectExEnv.querySelector(`option[value="${name}"]`) |
||||
if (env) { |
||||
selectExEnv.removeChild(env) |
||||
tootip(`${name} removed`) |
||||
} |
||||
}) |
||||
|
||||
selectExEnv.addEventListener('change', function (event) { |
||||
let context = selectExEnv.options[selectExEnv.selectedIndex].value |
||||
executionContext.executionContextChange(context, null, () => { |
||||
modalDialogCustom.confirm(null, 'Are you sure you want to connect to an ethereum node?', () => { |
||||
modalDialogCustom.prompt(null, 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => { |
||||
executionContext.setProviderFromEndpoint(target, context, (alertMsg) => { |
||||
if (alertMsg) { |
||||
modalDialogCustom.alert(alertMsg) |
||||
} |
||||
setFinalContext() |
||||
}) |
||||
}, setFinalContext) |
||||
}, setFinalContext) |
||||
}, (alertMsg) => { |
||||
modalDialogCustom.alert(alertMsg) |
||||
}, setFinalContext) |
||||
}) |
||||
|
||||
selectExEnv.value = executionContext.getProvider() |
||||
executionContext.event.register('contextChanged', (context, silent) => { |
||||
setFinalContext() |
||||
}) |
||||
|
||||
setInterval(() => { |
||||
updateNetwork() |
||||
fillAccountsList(el, self) |
||||
}, 5000) |
||||
|
||||
setInterval(() => { |
||||
updateAccountBalances(container, self) |
||||
}, 10000) |
||||
|
||||
function newAccount () { |
||||
self._deps.udapp.newAccount('', |
||||
(cb) => { |
||||
modalCustom.promptPassphraseCreation((error, passphrase) => { |
||||
if (error) { |
||||
return modalCustom.alert(error) |
||||
} |
||||
cb(passphrase) |
||||
}, () => {}) |
||||
}, |
||||
(error, address) => { |
||||
if (!error) { |
||||
addTooltip(`account ${address} created`) |
||||
} else { |
||||
addTooltip('Cannot create an account: ' + error) |
||||
} |
||||
} |
||||
) |
||||
} |
||||
function signMessage (event) { |
||||
self._deps.udapp.getAccounts((err, accounts) => { |
||||
if (err) { addTooltip(`Cannot get account list: ${err}`) } |
||||
var signMessageDialog = { 'title': 'Sign a message', 'text': 'Enter a message to sign', 'inputvalue': 'Message to sign' } |
||||
var $txOrigin = container.querySelector('#txorigin') |
||||
var account = $txOrigin.selectedOptions[0].value |
||||
var isVM = executionContext.isVM() |
||||
var isInjected = executionContext.getProvider() === 'injected' |
||||
function alertSignedData (error, hash, signedData) { |
||||
if (error && error.message !== '') { |
||||
console.log(error) |
||||
addTooltip(error.message) |
||||
} else { |
||||
modalDialogCustom.alert(yo`<div><b>hash:</b>${hash}<br><b>signature:</b>${signedData}</div>`) |
||||
} |
||||
} |
||||
if (isVM) { |
||||
modalDialogCustom.promptMulti(signMessageDialog, (message) => { |
||||
const personalMsg = ethJSUtil.hashPersonalMessage(Buffer.from(message)) |
||||
var privKey = self._deps.udapp.accounts[account].privateKey |
||||
try { |
||||
var rsv = ethJSUtil.ecsign(personalMsg, privKey) |
||||
var signedData = ethJSUtil.toRpcSig(rsv.v, rsv.r, rsv.s) |
||||
alertSignedData(null, '0x' + personalMsg.toString('hex'), signedData) |
||||
} catch (e) { |
||||
addTooltip(e.message) |
||||
return |
||||
} |
||||
}, false) |
||||
} else if (isInjected) { |
||||
modalDialogCustom.promptMulti(signMessageDialog, (message) => { |
||||
const hashedMsg = executionContext.web3().sha3(message) |
||||
try { |
||||
executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => { |
||||
alertSignedData(error, hashedMsg, signedData) |
||||
}) |
||||
} catch (e) { |
||||
addTooltip(e.message) |
||||
console.log(e) |
||||
return |
||||
} |
||||
}) |
||||
} else { |
||||
modalDialogCustom.promptPassphrase('Passphrase to sign a message', 'Enter your passphrase for this account to sign the message', '', (passphrase) => { |
||||
modalDialogCustom.promptMulti(signMessageDialog, (message) => { |
||||
const hashedMsg = executionContext.web3().sha3(message) |
||||
try { |
||||
var personal = new Personal(executionContext.web3().currentProvider) |
||||
personal.sign(hashedMsg, account, passphrase, (error, signedData) => { |
||||
alertSignedData(error, hashedMsg, signedData) |
||||
}) |
||||
} catch (e) { |
||||
addTooltip(e.message) |
||||
console.log(e) |
||||
return |
||||
} |
||||
}) |
||||
}, false) |
||||
} |
||||
}) |
||||
} |
||||
|
||||
return el |
||||
} |
||||
|
||||
var accountListCallId = 0 |
||||
var loadedAccounts = {} |
||||
function fillAccountsList (container, self) { |
||||
accountListCallId++ |
||||
(function (callid) { |
||||
var txOrigin = container.querySelector('#txorigin') |
||||
self._deps.udapp.getAccounts((err, accounts) => { |
||||
if (accountListCallId > callid) return |
||||
accountListCallId++ |
||||
if (err) { addTooltip(`Cannot get account list: ${err}`) } |
||||
for (var loadedaddress in loadedAccounts) { |
||||
if (accounts.indexOf(loadedaddress) === -1) { |
||||
txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]')) |
||||
delete loadedAccounts[loadedaddress] |
||||
} |
||||
} |
||||
for (var i in accounts) { |
||||
var address = accounts[i] |
||||
if (!loadedAccounts[address]) { |
||||
txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`) |
||||
loadedAccounts[address] = 1 |
||||
} |
||||
} |
||||
txOrigin.setAttribute('value', accounts[0]) |
||||
}) |
||||
})(accountListCallId) |
||||
} |
||||
|
||||
function updateAccountBalances (container, self) { |
||||
var accounts = $(container.querySelector('#txorigin')).children('option') |
||||
accounts.each(function (index, value) { |
||||
(function (acc) { |
||||
self._deps.udapp.getBalanceInEther(accounts[acc].value, function (err, res) { |
||||
if (!err) { |
||||
accounts[acc].innerText = helper.shortenAddress(accounts[acc].value, res) |
||||
} |
||||
}) |
||||
})(index) |
||||
}) |
||||
} |
||||
|
||||
module.exports = settings |
Loading…
Reference in new issue