refactor settings; separate logic from view code; refactor code

pull/1/head
Iuri Matias 6 years ago committed by yann300
parent 9a63d0977d
commit 7ff7b8e5bf
  1. 18
      src/app/tabs/run-tab.js
  2. 117
      src/app/tabs/runTab/model/settings.js
  3. 233
      src/app/tabs/runTab/settings.js

@ -6,7 +6,9 @@ var executionContext = require('../../execution-context')
var Card = require('../ui/card') var Card = require('../ui/card')
var css = require('./styles/run-tab-styles') var css = require('./styles/run-tab-styles')
var Settings = require('./runTab/model/settings.js')
var SettingsUI = require('./runTab/settings.js') var SettingsUI = require('./runTab/settings.js')
var ContractDropdownUI = require('./runTab/contractDropdown.js') var ContractDropdownUI = require('./runTab/contractDropdown.js')
var Recorder = require('./runTab/model/recorder.js') var Recorder = require('./runTab/model/recorder.js')
@ -126,7 +128,21 @@ function runTab (opts, localRegistry) {
status.appendChild(self._view.collapsedView) 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 contractDropdownUI = new ContractDropdownUI(self)
var el = yo` var el = yo`
<div> <div>

@ -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

@ -1,26 +1,41 @@
var $ = require('jquery') var $ = require('jquery')
var yo = require('yo-yo') var yo = require('yo-yo')
var ethJSUtil = require('ethereumjs-util') var remixLib = require('remix-lib')
var Personal = require('web3-eth-personal') var EventManager = remixLib.EventManager
var css = require('../styles/run-tab-styles') var css = require('../styles/run-tab-styles')
var executionContext = require('../../../execution-context')
var copyToClipboard = require('../../ui/copy-to-clipboard') var copyToClipboard = require('../../ui/copy-to-clipboard')
var modalDialogCustom = require('../../ui/modal-dialog-custom') var modalDialogCustom = require('../../ui/modal-dialog-custom')
var addTooltip = require('../../ui/tooltip') var addTooltip = require('../../ui/tooltip')
var modalCustom = require('../../ui/modal-dialog-custom')
var tootip = require('../../ui/tooltip')
var helper = require('../../../lib/helper.js') var helper = require('../../../lib/helper.js')
class SettingsUI { class SettingsUI {
constructor (container, parentSelf) { constructor (settings) {
this.container = container this.settings = settings
this.parentSelf = parentSelf this.event = new EventManager()
// HELPER FUNCTIONS AND EVENTS
this.parentSelf._deps.udapp.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => {
if (error) return if (error) return
if (!lookupOnly) this.el.querySelector('#value').value = '0' 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 {
</div> </div>
` `
// DOM ELEMENT
var el = yo` var el = yo`
<div class="${css.settings}"> <div class="${css.settings}">
${environmentEl} ${environmentEl}
@ -98,40 +112,47 @@ class SettingsUI {
</div> </div>
` `
// DROPDOWN
var selectExEnv = environmentEl.querySelector('#selectExEnvOptions') var selectExEnv = environmentEl.querySelector('#selectExEnvOptions')
this.selectExEnv = selectExEnv this.setDropdown(selectExEnv)
this.parentSelf.event.register('clearInstance', () => { this.settings.event.register('contextChanged', (context, silent) => {
var instanceContainer = this.parentSelf._view.instanceContainer this.setFinalContext()
var instanceContainerTitle = this.parentSelf._view.instanceContainerTitle
instanceContainer.innerHTML = '' // clear the instances list
instanceContainer.appendChild(instanceContainerTitle)
instanceContainer.appendChild(this.parentSelf._view.noInstancesText)
}) })
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`<option selectExEnv.appendChild(yo`<option
title="Manually added environment: ${network.url}" title="Manually added environment: ${network.url}"
value="${network.name}" name="executionContext"> ${network.name} value="${network.name}" name="executionContext"> ${network.name}
</option>`) </option>`)
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}"]`) var env = selectExEnv.querySelector(`option[value="${name}"]`)
if (env) { if (env) {
selectExEnv.removeChild(env) selectExEnv.removeChild(env)
tootip(`${name} removed`) addTooltip(`${name} removed`)
} }
}) })
selectExEnv.addEventListener('change', (event) => { selectExEnv.addEventListener('change', (event) => {
let context = selectExEnv.options[selectExEnv.selectedIndex].value 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.confirm(null, 'Are you sure you want to connect to an ethereum node?', () => {
modalDialogCustom.prompt(null, 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => { modalDialogCustom.prompt(null, 'Web3 Provider Endpoint', 'http://localhost:8545', (target) => {
executionContext.setProviderFromEndpoint(target, context, (alertMsg) => { this.settings.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) { if (alertMsg) {
modalDialogCustom.alert(alertMsg) modalDialogCustom.alert(alertMsg)
} }
@ -144,38 +165,23 @@ class SettingsUI {
}, this.setFinalContext.bind(this)) }, this.setFinalContext.bind(this))
}) })
selectExEnv.value = executionContext.getProvider() selectExEnv.value = this.settings.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
} }
setFinalContext () { setFinalContext () {
// set the final context. Cause it is possible that this is not the one we've originaly selected // set the final context. Cause it is possible that this is not the one we've originaly selected
this.selectExEnv.value = executionContext.getProvider() this.selectExEnv.value = this.settings.getProvider()
this.parentSelf.event.trigger('clearInstance', []) this.event.trigger('clearInstance', [])
this.updateNetwork() this.updateNetwork()
fillAccountsList(this.el, this.parentSelf) this.fillAccountsList()
} }
newAccount () { newAccount () {
this.parentSelf._deps.udapp.newAccount('', this.settings.newAccount(
(cb) => { (cb) => {
modalCustom.promptPassphraseCreation((error, passphrase) => { modalDialogCustom.promptPassphraseCreation((error, passphrase) => {
if (error) { if (error) {
return modalCustom.alert(error) return modalDialogCustom.alert(error)
} }
cb(passphrase) cb(passphrase)
}, () => {}) }, () => {})
@ -189,127 +195,70 @@ class SettingsUI {
) )
} }
alertSignedData (error, hash, signedData) { signMessage () {
if (error && error.message !== '') { this.settings.getAccounts((err, accounts) => {
console.log(error) if (err) {
addTooltip(error.message) return addTooltip(`Cannot get account list: ${err}`)
} else { }
modalDialogCustom.alert(yo`<div><b>hash:</b>${hash}<br><b>signature:</b>${signedData}</div>`)
}
}
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 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 account = $txOrigin.selectedOptions[0].value
var isVM = executionContext.isVM()
var isInjected = executionContext.getProvider() === 'injected' var promptCb = (passphrase) => {
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) {
modalDialogCustom.promptMulti(signMessageDialog, (message) => { modalDialogCustom.promptMulti(signMessageDialog, (message) => {
const hashedMsg = executionContext.web3().sha3(message) this.settings.signMessage(message, account, passphrase, (err, msgHash, signedData) => {
try { if (err) {
executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => { return addTooltip(err)
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
} }
modalDialogCustom.alert(yo`<div><b>hash:</b>${msgHash}<br><b>signature:</b>${signedData}</div>`)
}) })
}, false) }, 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 () { updateNetwork () {
let self = this this.settings.updateNetwork((err, {id, name} = {}) => {
var networkcallid = 0 if (err) {
networkcallid++ this.netUI.innerHTML = 'can\'t detect network '
((callid) => { return
executionContext.detectNetwork((err, { id, name } = {}) => { }
if (networkcallid > callid) return this.netUI.innerHTML = `<i class="${css.networkItem} fa fa-plug" aria-hidden="true"></i> ${name} (${id || '-'})`
networkcallid++ })
if (err) {
console.error(err)
self.netUI.innerHTML = 'can\'t detect network '
} else {
self.netUI.innerHTML = `<i class="${css.networkItem} fa fa-plug" aria-hidden="true"></i> ${name} (${id || '-'})`
}
})
})(networkcallid)
} }
} // TODO: unclear what's the goal of accountListCallId, feels like it can be simplified
fillAccountsList () {
var accountListCallId = 0 this.accountListCallId++
var loadedAccounts = {} var callid = this.accountListCallId
function fillAccountsList (container, self) { var txOrigin = this.el.querySelector('#txorigin')
accountListCallId++ this.settings.getAccounts((err, accounts) => {
((callid) => { if (this.accountListCallId > callid) return
var txOrigin = container.querySelector('#txorigin') this.accountListCallId++
self._deps.udapp.getAccounts((err, accounts) => {
if (accountListCallId > callid) return
accountListCallId++
if (err) { addTooltip(`Cannot get account list: ${err}`) } if (err) { addTooltip(`Cannot get account list: ${err}`) }
for (var loadedaddress in loadedAccounts) { for (var loadedaddress in this.loadedAccounts) {
if (accounts.indexOf(loadedaddress) === -1) { if (accounts.indexOf(loadedaddress) === -1) {
txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]')) txOrigin.removeChild(txOrigin.querySelector('option[value="' + loadedaddress + '"]'))
delete loadedAccounts[loadedaddress] delete this.loadedAccounts[loadedaddress]
} }
} }
for (var i in accounts) { for (var i in accounts) {
var address = accounts[i] var address = accounts[i]
if (!loadedAccounts[address]) { if (!this.loadedAccounts[address]) {
txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`) txOrigin.appendChild(yo`<option value="${address}" >${address}</option>`)
loadedAccounts[address] = 1 this.loadedAccounts[address] = 1
} }
} }
txOrigin.setAttribute('value', accounts[0]) 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 module.exports = SettingsUI

Loading…
Cancel
Save