move settings and contractsDropdown UI to their own modules

pull/1/head
Iuri Matias 6 years ago committed by yann300
parent 57c73094d8
commit 9dc1ad76db
  1. 74
      src/app/panels/righthand-panel.js
  2. 675
      src/app/tabs/run-tab.js
  3. 391
      src/app/tabs/runTab/contractDropdown.js
  4. 299
      src/app/tabs/runTab/settings.js

@ -11,8 +11,43 @@ const DraggableContent = require('../ui/draggableContent')
const styles = styleguide.chooser()
module.exports = class RighthandPanel {
constructor ({pluginManager, tabs}, localRegistry) {
const css = csjs`
.righthandpanel {
display : flex;
flex-direction : column;
top : 0;
right : 0;
bottom : 0;
box-sizing : border-box;
overflow : hidden;
height : 100%;
}
.header {
height : 100%;
}
.dragbar {
position : absolute;
width : 0.5em;
top : 3em;
bottom : 0;
cursor : col-resize;
z-index : 999;
border-left : 2px solid ${styles.rightPanel.bar_Dragging};
}
.ghostbar {
width : 3px;
background-color : ${styles.rightPanel.bar_Ghost};
opacity : 0.5;
position : absolute;
cursor : col-resize;
z-index : 9999;
top : 0;
bottom : 0;
}
`
class RighthandPanel {
constructor (localRegistry) {
const self = this
self._components = {}
self._components.registry = localRegistry || globalRegistry
@ -125,37 +160,4 @@ module.exports = class RighthandPanel {
}
}
const css = csjs`
.righthandpanel {
display : flex;
flex-direction : column;
top : 0;
right : 0;
bottom : 0;
box-sizing : border-box;
overflow : hidden;
height : 100%;
}
.header {
height : 100%;
}
.dragbar {
position : absolute;
width : 0.5em;
top : 3em;
bottom : 0;
cursor : col-resize;
z-index : 999;
border-left : 2px solid ${styles.rightPanel.bar_Dragging};
}
.ghostbar {
width : 3px;
background-color : ${styles.rightPanel.bar_Ghost};
opacity : 0.5;
position : absolute;
cursor : col-resize;
z-index : 9999;
top : 0;
bottom : 0;
}
`
module.exports = RighthandPanel

@ -1,32 +1,18 @@
'use strict'
var $ = require('jquery')
var yo = require('yo-yo')
var remixLib = require('remix-lib')
var ethJSUtil = require('ethereumjs-util')
var csjs = require('csjs-inject')
var txExecution = remixLib.execution.txExecution
var txFormat = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
var EventManager = require('../../lib/events')
var globlalRegistry = require('../../global/registry')
var helper = require('../../lib/helper.js')
var executionContext = require('../../execution-context')
var modalDialogCustom = require('../ui/modal-dialog-custom')
var copyToClipboard = require('../ui/copy-to-clipboard')
const Buffer = require('safe-buffer').Buffer
var Personal = require('web3-eth-personal')
var Card = require('../ui/card')
var Recorder = require('../../recorder')
var addTooltip = require('../ui/tooltip')
var css = require('./styles/run-tab-styles')
var MultiParamManager = require('../../multiParamManager')
var modalDialog = require('../ui/modaldialog')
var CompilerAbstract = require('../compiler/compiler-abstract')
var tootip = require('../ui/tooltip')
var confirmDialog = require('../execution/confirmDialog')
var modalCustom = require('../ui/modal-dialog-custom')
var settingsUI = require('./runTab/settings.js')
var contractDropdownUI = require('./runTab/contractDropdown.js')
function runTab (opts, localRegistry) {
/* -------------------------
@ -144,8 +130,8 @@ function runTab (opts, localRegistry) {
--------------------------- */
var el = yo`
<div>
${settings(container, self)}
${contractDropdown(self.event, self)}
${settingsUI(container, self)}
${contractDropdownUI(self.event, self)}
${recorderCard.render()}
${self._view.instanceContainer}
</div>
@ -155,47 +141,6 @@ function runTab (opts, localRegistry) {
return { render () { return container } }
}
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)
})
}
/* ------------------------------------------------
RECORDER
------------------------------------------------ */
@ -289,617 +234,5 @@ function makeRecorder (registry, runTabEvent, self) {
return { recordButton, runButton }
}
/* ------------------------------------------------
CONTRACT (deploy or access deployed)
------------------------------------------------ */
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) => {
let compiler = new CompilerAbstract(languageVersion, data, source)
newlyCompiled(true, data, source, compiler, languageVersion)
})
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['__last']
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
}
/* ------------------------------------------------
section SETTINGS: Environment, Account, Gas, Value
------------------------------------------------ */
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
}
module.exports = runTab

@ -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…
Cancel
Save