diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js
index 8e4fa9d51e..48999f914e 100644
--- a/src/app/tabs/run-tab.js
+++ b/src/app/tabs/run-tab.js
@@ -6,7 +6,9 @@ var executionContext = require('../../execution-context')
var Card = require('../ui/card')
var css = require('./styles/run-tab-styles')
+var Settings = require('./runTab/model/settings.js')
var SettingsUI = require('./runTab/settings.js')
+
var ContractDropdownUI = require('./runTab/contractDropdown.js')
var Recorder = require('./runTab/model/recorder.js')
@@ -126,7 +128,21 @@ function runTab (opts, localRegistry) {
status.appendChild(self._view.collapsedView)
}
})
- var settingsUI = new SettingsUI(container, self)
+
+ var settings = new Settings(self._deps.udapp)
+ var settingsUI = new SettingsUI(settings)
+
+ 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)
+ })
+ settingsUI.event.register('clearInstance', () => {
+ this.event.trigger('clearInstance', [])
+ })
+
var contractDropdownUI = new ContractDropdownUI(self)
var el = yo`
diff --git a/src/app/tabs/runTab/model/settings.js b/src/app/tabs/runTab/model/settings.js
new file mode 100644
index 0000000000..5d961c077c
--- /dev/null
+++ b/src/app/tabs/runTab/model/settings.js
@@ -0,0 +1,117 @@
+var ethJSUtil = require('ethereumjs-util')
+var Personal = require('web3-eth-personal')
+var remixLib = require('remix-lib')
+var EventManager = remixLib.EventManager
+var executionContext = remixLib.execution.executionContext
+
+class Settings {
+
+ constructor (udapp) {
+ this.udapp = udapp
+ this.event = new EventManager()
+
+ this.udapp.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
+ this.event.trigger('transactionExecuted', [error, from, to, data, lookupOnly, txResult])
+ })
+
+ executionContext.event.register('contextChanged', (context, silent) => {
+ this.event.trigger('contextChanged', [context, silent])
+ })
+
+ executionContext.event.register('addProvider', (network) => {
+ this.event.trigger('addProvider', [network])
+ })
+
+ executionContext.event.register('removeProvider', (name) => {
+ this.event.trigger('removeProvider', [name])
+ })
+
+ this.networkcallid = 0
+ }
+
+ changeExecutionContext (context, cb) {
+ return executionContext.executionContextChange(context, null, cb)
+ }
+
+ setProviderFromEndpoint (target, context, cb) {
+ return executionContext.setProviderFromEndpoint(target, context, cb)
+ }
+
+ getProvider () {
+ return executionContext.getProvider()
+ }
+
+ getAccountBalanceForAddress (address, cb) {
+ return this.udapp.getBalanceInEther(address, cb)
+ }
+
+ updateNetwork (cb) {
+ this.networkcallid++
+ ((callid) => {
+ executionContext.detectNetwork((err, { id, name } = {}) => {
+ if (this.networkcallid > callid) return
+ this.networkcallid++
+ if (err) {
+ return cb(err)
+ }
+ cb(null, {id, name})
+ })
+ })(this.networkcallid)
+ }
+
+ newAccount (passphraseCb, cb) {
+ return this.udapp.newAccount('', passphraseCb, cb)
+ }
+
+ getAccounts (cb) {
+ return this.udapp.getAccounts(cb)
+ }
+
+ isWeb3Provider () {
+ var isVM = executionContext.isVM()
+ var isInjected = executionContext.getProvider() === 'injected'
+ return (!isVM && !isInjected)
+ }
+
+ signMessage (message, account, passphrase, cb) {
+ var isVM = executionContext.isVM()
+ var isInjected = executionContext.getProvider() === 'injected'
+
+ if (isVM) {
+ const personalMsg = ethJSUtil.hashPersonalMessage(Buffer.from(message))
+ var privKey = this.udapp.accounts[account].privateKey
+ try {
+ var rsv = ethJSUtil.ecsign(personalMsg, privKey)
+ var signedData = ethJSUtil.toRpcSig(rsv.v, rsv.r, rsv.s)
+ cb(null, '0x' + personalMsg.toString('hex'), signedData)
+ } catch (e) {
+ cb(e.message)
+ }
+ return
+ }
+ if (isInjected) {
+ const hashedMsg = executionContext.web3().sha3(message)
+ try {
+ executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
+ cb(error, hashedMsg, signedData)
+ })
+ } catch (e) {
+ cb(e.message)
+ }
+ return
+ }
+
+ const hashedMsg = executionContext.web3().sha3(message)
+ try {
+ var personal = new Personal(executionContext.web3().currentProvider)
+ personal.sign(hashedMsg, account, passphrase, (error, signedData) => {
+ cb(error, hashedMsg, signedData)
+ })
+ } catch (e) {
+ cb(e.message)
+ }
+ }
+
+}
+
+module.exports = Settings
diff --git a/src/app/tabs/runTab/settings.js b/src/app/tabs/runTab/settings.js
index f51c992904..2a60b0f91e 100644
--- a/src/app/tabs/runTab/settings.js
+++ b/src/app/tabs/runTab/settings.js
@@ -1,26 +1,41 @@
var $ = require('jquery')
var yo = require('yo-yo')
-var ethJSUtil = require('ethereumjs-util')
-var Personal = require('web3-eth-personal')
+var remixLib = require('remix-lib')
+var EventManager = remixLib.EventManager
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')
class SettingsUI {
- constructor (container, parentSelf) {
- this.container = container
- this.parentSelf = parentSelf
- // HELPER FUNCTIONS AND EVENTS
- this.parentSelf._deps.udapp.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
+ constructor (settings) {
+ this.settings = settings
+ this.event = new EventManager()
+
+ this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
if (error) return
if (!lookupOnly) this.el.querySelector('#value').value = '0'
- updateAccountBalances(this.container, this.parentSelf)
+ this.updateAccountBalances()
+ })
+
+ setInterval(() => {
+ this.updateAccountBalances()
+ }, 10 * 1000)
+
+ this.accountListCallId = 0
+ this.loadedAccounts = {}
+ }
+
+ updateAccountBalances () {
+ if (!this.el) return
+ var accounts = $(this.el.querySelector('#txorigin')).children('option')
+ accounts.each((index, account) => {
+ this.settings.getAccountBalanceForAddress(account.value, (err, balance) => {
+ if (err) return
+ account.innerText = helper.shortenAddress(account.value, balance)
+ })
})
}
@@ -88,7 +103,6 @@ class SettingsUI {
`
- // DOM ELEMENT
var el = yo`
${environmentEl}
@@ -98,40 +112,47 @@ class SettingsUI {
`
- // DROPDOWN
var selectExEnv = environmentEl.querySelector('#selectExEnvOptions')
- this.selectExEnv = selectExEnv
+ this.setDropdown(selectExEnv)
- this.parentSelf.event.register('clearInstance', () => {
- var instanceContainer = this.parentSelf._view.instanceContainer
- var instanceContainerTitle = this.parentSelf._view.instanceContainerTitle
- instanceContainer.innerHTML = '' // clear the instances list
- instanceContainer.appendChild(instanceContainerTitle)
- instanceContainer.appendChild(this.parentSelf._view.noInstancesText)
+ this.settings.event.register('contextChanged', (context, silent) => {
+ this.setFinalContext()
})
- executionContext.event.register('addProvider', (network) => {
+ setInterval(() => {
+ this.updateNetwork()
+ this.fillAccountsList()
+ }, 5000)
+
+ this.el = el
+ return el
+ }
+
+ setDropdown (selectExEnv) {
+ this.selectExEnv = selectExEnv
+
+ this.settings.event.register('addProvider', (network) => {
selectExEnv.appendChild(yo``)
- tootip(`${network.name} [${network.url}] added`)
+ addTooltip(`${network.name} [${network.url}] added`)
})
- executionContext.event.register('removeProvider', (name) => {
+ this.settings.event.register('removeProvider', (name) => {
var env = selectExEnv.querySelector(`option[value="${name}"]`)
if (env) {
selectExEnv.removeChild(env)
- tootip(`${name} removed`)
+ addTooltip(`${name} removed`)
}
})
selectExEnv.addEventListener('change', (event) => {
let context = selectExEnv.options[selectExEnv.selectedIndex].value
- executionContext.executionContextChange(context, null, () => {
+ this.settings.changeExecutionContext(context, () => {
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) => {
+ this.settings.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) {
modalDialogCustom.alert(alertMsg)
}
@@ -144,38 +165,23 @@ class SettingsUI {
}, this.setFinalContext.bind(this))
})
- selectExEnv.value = executionContext.getProvider()
- executionContext.event.register('contextChanged', (context, silent) => {
- this.setFinalContext()
- })
-
- setInterval(() => {
- this.updateNetwork()
- fillAccountsList(el, this.parentSelf)
- }, 5000)
-
- setInterval(() => {
- updateAccountBalances(this.container, this.parentSelf)
- }, 10000)
-
- this.el = el
- return el
+ selectExEnv.value = this.settings.getProvider()
}
setFinalContext () {
// set the final context. Cause it is possible that this is not the one we've originaly selected
- this.selectExEnv.value = executionContext.getProvider()
- this.parentSelf.event.trigger('clearInstance', [])
+ this.selectExEnv.value = this.settings.getProvider()
+ this.event.trigger('clearInstance', [])
this.updateNetwork()
- fillAccountsList(this.el, this.parentSelf)
+ this.fillAccountsList()
}
newAccount () {
- this.parentSelf._deps.udapp.newAccount('',
+ this.settings.newAccount(
(cb) => {
- modalCustom.promptPassphraseCreation((error, passphrase) => {
+ modalDialogCustom.promptPassphraseCreation((error, passphrase) => {
if (error) {
- return modalCustom.alert(error)
+ return modalDialogCustom.alert(error)
}
cb(passphrase)
}, () => {})
@@ -189,127 +195,70 @@ class SettingsUI {
)
}
- alertSignedData (error, hash, signedData) {
- if (error && error.message !== '') {
- console.log(error)
- addTooltip(error.message)
- } else {
- modalDialogCustom.alert(yo`hash:${hash}
signature:${signedData}
`)
- }
- }
+ signMessage () {
+ this.settings.getAccounts((err, accounts) => {
+ if (err) {
+ return addTooltip(`Cannot get account list: ${err}`)
+ }
- signMessage (event) {
- this.parentSelf._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 = this.container.querySelector('#txorigin')
+ var $txOrigin = this.el.querySelector('#txorigin')
var account = $txOrigin.selectedOptions[0].value
- var isVM = executionContext.isVM()
- var isInjected = executionContext.getProvider() === 'injected'
- if (isVM) {
- modalDialogCustom.promptMulti(signMessageDialog, (message) => {
- const personalMsg = ethJSUtil.hashPersonalMessage(Buffer.from(message))
- var privKey = this.parentSelf._deps.udapp.accounts[account].privateKey
- try {
- var rsv = ethJSUtil.ecsign(personalMsg, privKey)
- var signedData = ethJSUtil.toRpcSig(rsv.v, rsv.r, rsv.s)
- this.alertSignedData(null, '0x' + personalMsg.toString('hex'), signedData)
- } catch (e) {
- addTooltip(e.message)
- return
- }
- }, false)
- } else if (isInjected) {
+
+ var promptCb = (passphrase) => {
modalDialogCustom.promptMulti(signMessageDialog, (message) => {
- const hashedMsg = executionContext.web3().sha3(message)
- try {
- executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
- this.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) => {
- this.alertSignedData(error, hashedMsg, signedData)
- })
- } catch (e) {
- addTooltip(e.message)
- console.log(e)
- return
+ this.settings.signMessage(message, account, passphrase, (err, msgHash, signedData) => {
+ if (err) {
+ return addTooltip(err)
}
+ modalDialogCustom.alert(yo`hash:${msgHash}
signature:${signedData}
`)
})
}, false)
}
+
+ if (this.settings.isWeb3Provider()) {
+ return modalDialogCustom.promptPassphrase('Passphrase to sign a message', 'Enter your passphrase for this account to sign the message', '', promptCb, false)
+ }
+ promptCb()
})
}
updateNetwork () {
- let self = this
- var networkcallid = 0
- networkcallid++
- ((callid) => {
- executionContext.detectNetwork((err, { id, name } = {}) => {
- if (networkcallid > callid) return
- networkcallid++
- if (err) {
- console.error(err)
- self.netUI.innerHTML = 'can\'t detect network '
- } else {
- self.netUI.innerHTML = ` ${name} (${id || '-'})`
- }
- })
- })(networkcallid)
+ this.settings.updateNetwork((err, {id, name} = {}) => {
+ if (err) {
+ this.netUI.innerHTML = 'can\'t detect network '
+ return
+ }
+ this.netUI.innerHTML = ` ${name} (${id || '-'})`
+ })
}
-}
-
-var accountListCallId = 0
-var loadedAccounts = {}
-function fillAccountsList (container, self) {
- accountListCallId++
- ((callid) => {
- var txOrigin = container.querySelector('#txorigin')
- self._deps.udapp.getAccounts((err, accounts) => {
- if (accountListCallId > callid) return
- accountListCallId++
+ // TODO: unclear what's the goal of accountListCallId, feels like it can be simplified
+ fillAccountsList () {
+ this.accountListCallId++
+ var callid = this.accountListCallId
+ var txOrigin = this.el.querySelector('#txorigin')
+ this.settings.getAccounts((err, accounts) => {
+ if (this.accountListCallId > callid) return
+ this.accountListCallId++
if (err) { addTooltip(`Cannot get account list: ${err}`) }
- for (var loadedaddress in loadedAccounts) {
+ for (var loadedaddress in this.loadedAccounts) {
if (accounts.indexOf(loadedaddress) === -1) {
txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]'))
- delete loadedAccounts[loadedaddress]
+ delete this.loadedAccounts[loadedaddress]
}
}
for (var i in accounts) {
var address = accounts[i]
- if (!loadedAccounts[address]) {
+ if (!this.loadedAccounts[address]) {
txOrigin.appendChild(yo``)
- loadedAccounts[address] = 1
+ this.loadedAccounts[address] = 1
}
}
txOrigin.setAttribute('value', accounts[0])
})
- })(accountListCallId)
-}
+ }
-function updateAccountBalances (container, self) {
- var accounts = $(container.querySelector('#txorigin')).children('option')
- accounts.each((index, value) => {
- ((acc) => {
- self._deps.udapp.getBalanceInEther(accounts[acc].value, (err, res) => {
- if (err) return
- accounts[acc].innerText = helper.shortenAddress(accounts[acc].value, res)
- })
- })(index)
- })
}
module.exports = SettingsUI