Merge pull request #2510 from ethereum/refactor_logic2

Refactor executionContext and udapp, into common class
pull/5370/head
Iuri Matias 5 years ago committed by GitHub
commit a3e6336764
  1. 17
      src/app.js
  2. 22
      src/app/files/compiler-metadata.js
  3. 6
      src/app/panels/main-view.js
  4. 12
      src/app/panels/terminal.js
  5. 6
      src/app/tabs/runTab/contractDropdown.js
  6. 172
      src/app/tabs/runTab/model/blockchain.js
  7. 36
      src/app/tabs/runTab/model/dropdownlogic.js
  8. 101
      src/app/tabs/runTab/model/recorder.js
  9. 124
      src/app/tabs/runTab/model/settings.js
  10. 39
      src/app/tabs/runTab/recorder.js
  11. 36
      src/app/tabs/runTab/settings.js
  12. 36
      src/app/udapp/make-udapp.js
  13. 27
      src/app/udapp/run-tab.js
  14. 20
      src/app/ui/txLogger.js
  15. 10
      src/lib/cmdInterpreterAPI.js
  16. 6
      src/lib/transactionReceiptResolver.js

@ -24,6 +24,8 @@ var CompilerImport = require('./app/compiler/compiler-imports')
var executionContext = remixLib.execution.executionContext var executionContext = remixLib.execution.executionContext
const Blockchain = require('./app/tabs/runTab/model/blockchain.js')
const PluginManagerComponent = require('./app/components/plugin-manager-component') const PluginManagerComponent = require('./app/components/plugin-manager-component')
const CompilersArtefacts = require('./app/compiler/compiler-artefacts') const CompilersArtefacts = require('./app/compiler/compiler-artefacts')
@ -222,14 +224,18 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// ----------------- fileManager servive ---------------------------- // ----------------- fileManager servive ----------------------------
const fileManager = new FileManager(editor) const fileManager = new FileManager(editor)
registry.put({api: fileManager, name: 'filemanager'}) registry.put({api: fileManager, name: 'filemanager'})
// ----------------- universal dapp: run transaction, listen on transactions, decode events
const udapp = new UniversalDApp(registry.get('config').api, executionContext)
const blockchain = new Blockchain(executionContext, udapp)
// ----------------- compilation metadata generation servive ---------------------------- // ----------------- compilation metadata generation servive ----------------------------
const compilerMetadataGenerator = new CompilerMetadata(executionContext, fileManager, registry.get('config').api) const compilerMetadataGenerator = new CompilerMetadata(blockchain, fileManager, registry.get('config').api)
// ----------------- compilation result service (can keep track of compilation results) ---------------------------- // ----------------- compilation result service (can keep track of compilation results) ----------------------------
const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name) const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name)
registry.put({api: compilersArtefacts, name: 'compilersartefacts'}) registry.put({api: compilersArtefacts, name: 'compilersartefacts'})
// ----------------- universal dapp: run transaction, listen on transactions, decode events
const udapp = new UniversalDApp(registry.get('config').api, executionContext) const {eventsDecoder, txlistener} = makeUdapp(blockchain, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
const {eventsDecoder, txlistener} = makeUdapp(udapp, executionContext, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
// ----------------- network service (resolve network id / name) ---------------------------- // ----------------- network service (resolve network id / name) ----------------------------
const networkModule = new NetworkModule(executionContext) const networkModule = new NetworkModule(executionContext)
// ----------------- convert offset to line/column service ---------------------------- // ----------------- convert offset to line/column service ----------------------------
@ -249,7 +255,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// LAYOUT & SYSTEM VIEWS // LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel() const appPanel = new MainPanel()
const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder, executionContext) const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder, blockchain)
registry.put({ api: mainview, name: 'mainview' }) registry.put({ api: mainview, name: 'mainview' })
appManager.register([ appManager.register([
@ -293,6 +299,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
registry.get('filemanager').api registry.get('filemanager').api
) )
const run = new RunTab( const run = new RunTab(
blockchain,
udapp, udapp,
executionContext, executionContext,
registry.get('config').api, registry.get('config').api,

@ -11,14 +11,13 @@ const profile = {
} }
class CompilerMetadata extends Plugin { class CompilerMetadata extends Plugin {
constructor (executionContext, fileManager, config) { constructor (blockchain, fileManager, config) {
super(profile) super(profile)
var self = this this.blockchain = blockchain
self.executionContext = executionContext this.fileManager = fileManager
self.fileManager = fileManager this.config = config
self.config = config this.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom']
self.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom'] this.innerPath = 'artifacts'
self.innerPath = 'artifacts'
} }
_JSONFileName (path, contractName) { _JSONFileName (path, contractName) {
@ -93,15 +92,14 @@ class CompilerMetadata extends Plugin {
// TODO: is only called by dropdownLogic and can be moved there // TODO: is only called by dropdownLogic and can be moved there
deployMetadataOf (contractName) { deployMetadataOf (contractName) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var self = this var provider = this.fileManager.currentFileProvider()
var provider = self.fileManager.currentFileProvider() var path = this.fileManager.currentPath()
var path = self.fileManager.currentPath()
if (provider && path) { if (provider && path) {
self.executionContext.detectNetwork((err, { id, name } = {}) => { this.blockchain.detectNetwork((err, { id, name } = {}) => {
if (err) { if (err) {
console.log(err) console.log(err)
} else { } else {
var fileName = self._JSONFileName(path, contractName) var fileName = this._JSONFileName(path, contractName)
provider.get(fileName, (error, content) => { provider.get(fileName, (error, content) => {
if (error) return reject(error) if (error) return reject(error)
if (!content) return resolve() if (!content) return resolve()

@ -20,7 +20,7 @@ var css = csjs`
` `
export class MainView { export class MainView {
constructor (editor, mainPanel, fileManager, appManager, txListener, eventsDecoder, executionContext) { constructor (editor, mainPanel, fileManager, appManager, txListener, eventsDecoder, blockchain) {
var self = this var self = this
self.event = new EventManager() self.event = new EventManager()
self._view = {} self._view = {}
@ -31,7 +31,7 @@ export class MainView {
self.mainPanel = mainPanel self.mainPanel = mainPanel
self.txListener = txListener self.txListener = txListener
self.eventsDecoder = eventsDecoder self.eventsDecoder = eventsDecoder
self.executionContext = executionContext self.blockchain = blockchain
this.appManager = appManager this.appManager = appManager
this.init() this.init()
} }
@ -101,7 +101,7 @@ export class MainView {
appManager: this.appManager, appManager: this.appManager,
eventsDecoder: this.eventsDecoder, eventsDecoder: this.eventsDecoder,
txListener: this.txListener, txListener: this.txListener,
executionContext: this.executionContext blockchain: this.blockchain
}, },
{ {
getPosition: (event) => { getPosition: (event) => {

@ -41,7 +41,7 @@ class Terminal extends Plugin {
super(profile) super(profile)
var self = this var self = this
self.event = new EventManager() self.event = new EventManager()
self.executionContext = opts.executionContext self.blockchain = opts.blockchain
self._api = api self._api = api
self._opts = opts self._opts = opts
self.data = { self.data = {
@ -52,7 +52,7 @@ class Terminal extends Plugin {
} }
self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null } self._view = { el: null, bar: null, input: null, term: null, journal: null, cli: null }
self._components = {} self._components = {}
self._components.cmdInterpreter = new CommandInterpreterAPI(this, null, self.executionContext) self._components.cmdInterpreter = new CommandInterpreterAPI(this, null, self.blockchain)
self._components.autoCompletePopup = new AutoCompletePopup(self._opts) self._components.autoCompletePopup = new AutoCompletePopup(self._opts)
self._components.autoCompletePopup.event.register('handleSelect', function (input) { self._components.autoCompletePopup.event.register('handleSelect', function (input) {
let textList = self._view.input.innerText.split(' ') let textList = self._view.input.innerText.split(' ')
@ -437,7 +437,7 @@ class Terminal extends Plugin {
self._shell('remix.help()', self.commands, () => {}) self._shell('remix.help()', self.commands, () => {})
self.commands.html(intro) self.commands.html(intro)
self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this, self.executionContext) self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this, self.blockchain)
self._components.txLogger.event.register('debuggingRequested', (hash) => { self._components.txLogger.event.register('debuggingRequested', (hash) => {
// TODO should probably be in the run module // TODO should probably be in the run module
if (!self._opts.appManager.isActive('debugger')) self._opts.appManager.activateOne('debugger') if (!self._opts.appManager.isActive('debugger')) self._opts.appManager.activateOne('debugger')
@ -668,7 +668,7 @@ class Terminal extends Plugin {
return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.') return done(null, 'This type of command has been deprecated and is not functionning anymore. Please run remix.help() to list available commands.')
} }
var self = this var self = this
var context = domTerminalFeatures(self, scopedCommands, self.executionContext) var context = domTerminalFeatures(self, scopedCommands, self.blockchain)
try { try {
var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered)) var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered))
var result = vm.runInContext(script, cmds) var result = vm.runInContext(script, cmds)
@ -680,12 +680,12 @@ class Terminal extends Plugin {
} }
} }
function domTerminalFeatures (self, scopedCommands, executionContext) { function domTerminalFeatures (self, scopedCommands, blockchain) {
return { return {
swarmgw, swarmgw,
ethers, ethers,
remix: self._components.cmdInterpreter, remix: self._components.cmdInterpreter,
web3: new Web3(executionContext.web3().currentProvider), web3: new Web3(blockchain.web3().currentProvider),
console: { console: {
log: function () { scopedCommands.log.apply(scopedCommands, arguments) }, log: function () { scopedCommands.log.apply(scopedCommands, arguments) },
info: function () { scopedCommands.info.apply(scopedCommands, arguments) }, info: function () { scopedCommands.info.apply(scopedCommands, arguments) },

@ -209,8 +209,8 @@ class ContractDropdownUI {
if (network.name !== 'Main') { if (network.name !== 'Main') {
return continueTxExecution(null) return continueTxExecution(null)
} }
const amount = this.dropdownLogic.fromWei(tx.value, true, 'ether') const amount = this.blockchain.fromWei(tx.value, true, 'ether')
const content = confirmDialog(tx, amount, gasEstimation, null, this.dropdownLogic.determineGasFees(tx), this.blockchain.determineGasPrice) const content = confirmDialog(tx, amount, gasEstimation, null, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice)
modalDialog('Confirm transaction', content, modalDialog('Confirm transaction', content,
{ label: 'Confirm', { label: 'Confirm',
@ -220,7 +220,7 @@ class ContractDropdownUI {
if (!content.gasPriceStatus) { if (!content.gasPriceStatus) {
cancelCb('Given gas price is not correct') cancelCb('Given gas price is not correct')
} else { } else {
var gasPrice = this.dropdownLogic.toWei(content.querySelector('#gasprice').value, 'gwei') var gasPrice = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice) continueTxExecution(gasPrice)
} }
}}, { }}, {

@ -2,13 +2,47 @@ const remixLib = require('remix-lib')
const txFormat = remixLib.execution.txFormat const txFormat = remixLib.execution.txFormat
const txExecution = remixLib.execution.txExecution const txExecution = remixLib.execution.txExecution
const typeConversion = remixLib.execution.typeConversion const typeConversion = remixLib.execution.typeConversion
const Txlistener = remixLib.execution.txListener
const EventManager = remixLib.EventManager
const ethJSUtil = require('ethereumjs-util')
const Personal = require('web3-eth-personal')
const Web3 = require('web3') const Web3 = require('web3')
class Blockchain { class Blockchain {
constructor (executionContext, udapp) { constructor (executionContext, udapp) {
this.event = new EventManager()
this.executionContext = executionContext this.executionContext = executionContext
this.udapp = udapp this.udapp = udapp
this.networkcallid = 0
this.setupEvents()
}
setupEvents () {
this.executionContext.event.register('contextChanged', (context, silent) => {
this.event.trigger('contextChanged', [context, silent])
})
this.executionContext.event.register('addProvider', (network) => {
this.event.trigger('addProvider', [network])
})
this.executionContext.event.register('removeProvider', (name) => {
this.event.trigger('removeProvider', [name])
})
this.udapp.event.register('initiatingTransaction', (timestamp, tx, payLoad) => {
this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
})
this.udapp.event.register('transactionExecuted', (error, from, to, data, call, txResult, timestamp) => {
this.event.trigger('transactionExecuted', [error, from, to, data, call, txResult, timestamp])
})
this.udapp.event.register('transactionBroadcasted', (txhash, networkName) => {
this.event.trigger('transactionBroadcasted', [txhash, networkName])
})
} }
async deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { async deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) {
@ -93,6 +127,144 @@ class Blockchain {
return Web3.utils.fromWei(value.toString(10), unit || 'ether') return Web3.utils.fromWei(value.toString(10), unit || 'ether')
} }
toWei (value, unit) {
return Web3.utils.toWei(value, unit || 'gwei')
}
calculateFee (gas, gasPrice, unit) {
return Web3.utils.toBN(gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10), unit || 'gwei')))
}
determineGasFees (tx) {
const determineGasFeesCb = (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 = this.calculateFee(tx.gas, gasPrice)
txFeeText = ' ' + this.fromWei(fee, false, 'ether') + ' Ether'
priceStatus = true
} catch (e) {
txFeeText = ' Please fix this issue before sending any transaction. ' + e.message
priceStatus = false
}
cb(txFeeText, priceStatus)
}
return determineGasFeesCb
}
getAddressFromTransactionResult (txResult) {
return this.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
}
changeExecutionContext (context, confirmCb, infoCb, cb) {
return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
}
setProviderFromEndpoint (target, context, cb) {
return this.executionContext.setProviderFromEndpoint(target, context, cb)
}
getProvider () {
return this.executionContext.getProvider()
}
getAccountBalanceForAddress (address, cb) {
return this.udapp.getBalanceInEther(address, cb)
}
updateNetwork (cb) {
this.networkcallid++
((callid) => {
this.executionContext.detectNetwork((err, { id, name } = {}) => {
if (this.networkcallid > callid) return
this.networkcallid++
if (err) {
return cb(err)
}
cb(null, {id, name})
})
})(this.networkcallid)
}
detectNetwork (cb) {
return this.executionContext.detectNetwork(cb)
}
newAccount (passphraseCb, cb) {
return this.udapp.newAccount('', passphraseCb, cb)
}
getAccounts (cb) {
return this.udapp.getAccounts(cb)
}
isWeb3Provider () {
var isVM = this.executionContext.isVM()
var isInjected = this.executionContext.getProvider() === 'injected'
return (!isVM && !isInjected)
}
isInjectedWeb3 () {
return this.executionContext.getProvider() === 'injected'
}
signMessage (message, account, passphrase, cb) {
var isVM = this.executionContext.isVM()
var isInjected = this.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 = Web3.utils.sha3(message)
try {
this.executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})
} catch (e) {
cb(e.message)
}
return
}
const hashedMsg = Web3.utils.sha3(message)
try {
var personal = new Personal(this.executionContext.web3().currentProvider)
personal.sign(hashedMsg, account, passphrase, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})
} catch (e) {
cb(e.message)
}
}
web3 () {
return this.executionContext.web3()
}
getTxListener (opts) {
opts.event = {
udapp: this.udapp.event
}
const txlistener = new Txlistener(opts, this.executionContext)
return txlistener
}
startListening (txlistener) {
this.udapp.startListening(txlistener)
}
} }
module.exports = Blockchain module.exports = Blockchain

@ -1,10 +1,8 @@
var ethJSUtil = require('ethereumjs-util') var ethJSUtil = require('ethereumjs-util')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var txHelper = remixLib.execution.txHelper var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
var CompilerAbstract = require('../../../compiler/compiler-abstract') var CompilerAbstract = require('../../../compiler/compiler-abstract')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var Web3 = require('web3')
class DropdownLogic { class DropdownLogic {
constructor (compilersArtefacts, config, editor, runView) { constructor (compilersArtefacts, config, editor, runView) {
@ -96,40 +94,6 @@ class DropdownLogic {
} }
} }
fromWei (value, doTypeConversion, unit) {
if (doTypeConversion) {
return Web3.utils.fromWei(typeConversion.toInt(value), unit || 'ether')
}
return Web3.utils.fromWei(value.toString(10), unit || 'ether')
}
toWei (value, unit) {
return Web3.utils.toWei(value, unit || 'gwei')
}
calculateFee (gas, gasPrice, unit) {
return Web3.utils.toBN(gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10), unit || 'gwei')))
}
determineGasFees (tx) {
const determineGasFeesCb = (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 = this.calculateFee(tx.gas, gasPrice)
txFeeText = ' ' + this.fromWei(fee, false, 'ether') + ' Ether'
priceStatus = true
} catch (e) {
txFeeText = ' Please fix this issue before sending any transaction. ' + e.message
priceStatus = false
}
cb(txFeeText, priceStatus)
}
return determineGasFeesCb
}
getCompilerContracts () { getCompilerContracts () {
return this.compilersArtefacts['__last'].getData().contracts return this.compilersArtefacts['__last'].getData().contracts
} }

@ -4,9 +4,7 @@ var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager var EventManager = remixLib.EventManager
var format = remixLib.execution.txFormat var format = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
var helper = require('../../../../lib/helper.js') var helper = require('../../../../lib/helper.js')
var Web3 = require('web3')
/** /**
* Record transaction as long as the user create them. * Record transaction as long as the user create them.
@ -14,16 +12,15 @@ var Web3 = require('web3')
* *
*/ */
class Recorder { class Recorder {
constructor (executionContext, udapp, fileManager, config) { constructor (blockchain, fileManager, config) {
var self = this var self = this
self.event = new EventManager() self.event = new EventManager()
self.executionContext = executionContext self.blockchain = blockchain
self.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} } self.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} }
this.udapp = udapp
this.fileManager = fileManager this.fileManager = fileManager
this.config = config this.config = config
this.udapp.event.register('initiatingTransaction', (timestamp, tx, payLoad) => { this.blockchain.event.register('initiatingTransaction', (timestamp, tx, payLoad) => {
if (tx.useCall) return if (tx.useCall) return
var { from, to, value } = tx var { from, to, value } = tx
@ -61,7 +58,7 @@ class Recorder {
if (thistimestamp) record.parameters[p] = `created{${thistimestamp}}` if (thistimestamp) record.parameters[p] = `created{${thistimestamp}}`
} }
this.udapp.getAccounts((error, accounts) => { this.blockchain.getAccounts((error, accounts) => {
if (error) return console.log(error) if (error) return console.log(error)
record.from = `account{${accounts.indexOf(from)}}` record.from = `account{${accounts.indexOf(from)}}`
self.data._usedAccounts[record.from] = from self.data._usedAccounts[record.from] = from
@ -70,11 +67,11 @@ class Recorder {
} }
}) })
this.udapp.event.register('transactionExecuted', (error, from, to, data, call, txResult, timestamp) => { this.blockchain.event.register('transactionExecuted', (error, from, to, data, call, txResult, timestamp) => {
if (error) return console.log(error) if (error) return console.log(error)
if (call) return if (call) return
const rawAddress = this.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress const rawAddress = this.blockchain.getAddressFromTransactionResult(txResult)
if (!rawAddress) return // not a contract creation if (!rawAddress) return // not a contract creation
const stringAddress = this.addressToString(rawAddress) const stringAddress = this.addressToString(rawAddress)
const address = ethutil.toChecksumAddress(stringAddress) const address = ethutil.toChecksumAddress(stringAddress)
@ -82,7 +79,7 @@ class Recorder {
this.data._createdContracts[address] = timestamp this.data._createdContracts[address] = timestamp
this.data._createdContractsReverse[timestamp] = address this.data._createdContractsReverse[timestamp] = address
}) })
this.executionContext.event.register('contextChanged', this.clearAll.bind(this)) this.blockchain.event.register('contextChanged', this.clearAll.bind(this))
this.event.register('newTxRecorded', (count) => { this.event.register('newTxRecorded', (count) => {
this.event.trigger('recorderCountChange', [count]) this.event.trigger('recorderCountChange', [count])
}) })
@ -185,7 +182,6 @@ class Recorder {
* @param {Object} accounts * @param {Object} accounts
* @param {Object} options * @param {Object} options
* @param {Object} abis * @param {Object} abis
* @param {Object} udapp
* @param {Function} newContractFn * @param {Function} newContractFn
* *
*/ */
@ -197,8 +193,7 @@ class Recorder {
var record = self.resolveAddress(tx.record, accounts, options) var record = self.resolveAddress(tx.record, accounts, options)
var abi = abis[tx.record.abi] var abi = abis[tx.record.abi]
if (!abi) { if (!abi) {
alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index) return alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index)
return
} }
/* Resolve Library */ /* Resolve Library */
if (record.linkReferences && Object.keys(record.linkReferences).length) { if (record.linkReferences && Object.keys(record.linkReferences).length) {
@ -222,8 +217,7 @@ class Recorder {
} }
if (!fnABI) { if (!fnABI) {
alertCb('cannot resolve abi of ' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index) alertCb('cannot resolve abi of ' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index)
cb('cannot resolve abi') return cb('cannot resolve abi')
return
} }
if (tx.record.parameters) { if (tx.record.parameters) {
/* check if we have some params to resolve */ /* check if we have some params to resolve */
@ -241,27 +235,25 @@ class Recorder {
tx.record.parameters[index] = value tx.record.parameters[index] = value
}) })
} catch (e) { } catch (e) {
alertCb('cannot resolve input parameters ' + JSON.stringify(tx.record.parameters) + '. Execution stopped at ' + index) return alertCb('cannot resolve input parameters ' + JSON.stringify(tx.record.parameters) + '. Execution stopped at ' + index)
return
} }
} }
var data = format.encodeData(fnABI, tx.record.parameters, tx.record.bytecode) var data = format.encodeData(fnABI, tx.record.parameters, tx.record.bytecode)
if (data.error) { if (data.error) {
alertCb(data.error + '. Record:' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index) alertCb(data.error + '. Record:' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index)
cb(data.error) return cb(data.error)
return }
} else {
logCallBack(`(${index}) ${JSON.stringify(record, null, '\t')}`) logCallBack(`(${index}) ${JSON.stringify(record, null, '\t')}`)
logCallBack(`(${index}) data: ${data.data}`) logCallBack(`(${index}) data: ${data.data}`)
record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName, timestamp: tx.timestamp } record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName, timestamp: tx.timestamp }
}
self.udapp.runTx(record, confirmationCb, continueCb, promptCb, self.blockchain.runTransaction(record, continueCb, promptCb, confirmationCb,
function (err, txResult) { function (err, txResult) {
if (err) { if (err) {
console.error(err) console.error(err)
logCallBack(err + '. Execution failed at ' + index) return logCallBack(err + '. Execution failed at ' + index)
} else { }
const rawAddress = self.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress const rawAddress = self.blockchain.getAddressFromTransactionResult(txResult)
if (rawAddress) { if (rawAddress) {
const stringAddress = self.addressToString(rawAddress) const stringAddress = self.addressToString(rawAddress)
const address = ethutil.toChecksumAddress(stringAddress) const address = ethutil.toChecksumAddress(stringAddress)
@ -270,7 +262,6 @@ class Recorder {
self.data._createdContractsReverse[tx.timestamp] = address self.data._createdContractsReverse[tx.timestamp] = address
newContractFn(abi, address, record.contractName) newContractFn(abi, address, record.contractName)
} }
}
cb(err) cb(err)
} }
) )
@ -288,7 +279,7 @@ class Recorder {
return address return address
} }
runScenario (continueCb, promptCb, alertCb, confirmDialog, modalDialog, logCallBack, cb) { runScenario (continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) {
var currentFile = this.config.get('currentFile') var currentFile = this.config.get('currentFile')
this.fileManager.fileProviderOf(currentFile).get(currentFile, (error, json) => { this.fileManager.fileProviderOf(currentFile).get(currentFile, (error, json) => {
if (error) { if (error) {
@ -312,62 +303,6 @@ class Recorder {
return return
} }
var confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
var amount = Web3.utils.fromWei(typeConversion.toInt(tx.value), 'ether')
// TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily
var content = confirmDialog(tx, amount, gasEstimation, this.recorder,
(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 = Web3.utils.toBN(tx.gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10), 'gwei')))
txFeeText = ' ' + Web3.utils.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) => {
this.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 = Web3.utils.fromWei(gasPrice.toString(10), 'gwei')
cb(null, gasPriceValue)
} catch (e) {
cb(warnMessage + e.message, null, false)
}
})
}
)
modalDialog('Confirm transaction', content,
{ label: 'Confirm',
fn: () => {
this.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 = Web3.utils.toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
}
this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, (abi, address, contractName) => { this.run(txArray, accounts, options, abis, linkReferences, confirmationCb, continueCb, promptCb, alertCb, logCallBack, (abi, address, contractName) => {
cb(null, abi, address, contractName) cb(null, abi, address, contractName)
}) })

@ -1,124 +0,0 @@
var ethJSUtil = require('ethereumjs-util')
var Personal = require('web3-eth-personal')
var remixLib = require('remix-lib')
var Web3 = require('web3')
const addTooltip = require('../../../ui/tooltip')
var EventManager = remixLib.EventManager
class Settings {
constructor (executionContext, udapp) {
this.executionContext = executionContext
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])
})
this.executionContext.event.register('contextChanged', (context, silent) => {
this.event.trigger('contextChanged', [context, silent])
})
this.executionContext.event.register('addProvider', (network) => {
this.event.trigger('addProvider', [network])
})
this.executionContext.event.register('removeProvider', (name) => {
this.event.trigger('removeProvider', [name])
})
this.networkcallid = 0
}
changeExecutionContext (context, confirmCb, infoCb, cb) {
return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
}
setProviderFromEndpoint (target, context, cb) {
return this.executionContext.setProviderFromEndpoint(target, context, cb)
}
getProvider () {
return this.executionContext.getProvider()
}
getAccountBalanceForAddress (address, cb) {
return this.udapp.getBalanceInEther(address, cb)
}
updateNetwork (cb) {
this.networkcallid++
((callid) => {
this.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 = this.executionContext.isVM()
var isInjected = this.executionContext.getProvider() === 'injected'
return (!isVM && !isInjected)
}
isInjectedWeb3 () {
return this.executionContext.getProvider() === 'injected'
}
signMessage (message, account, passphrase, cb) {
var isVM = this.executionContext.isVM()
var isInjected = this.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 = Web3.utils.sha3(message)
try {
addTooltip('Please check your provider to approve')
this.executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})
} catch (e) {
cb(e.message)
}
return
}
const hashedMsg = Web3.utils.sha3(message)
try {
var personal = new Personal(this.executionContext.web3().currentProvider)
personal.sign(hashedMsg, account, passphrase, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})
} catch (e) {
cb(e.message)
}
}
}
module.exports = Settings

@ -10,9 +10,11 @@ var confirmDialog = require('../../ui/confirmDialog')
class RecorderUI { class RecorderUI {
constructor (recorder, logCallBack) { constructor (blockchain, recorder, logCallBack, config) {
this.blockchain = blockchain
this.recorder = recorder this.recorder = recorder
this.logCallBack = logCallBack this.logCallBack = logCallBack
this.config = config
this.event = new EventManager() this.event = new EventManager()
} }
@ -63,8 +65,10 @@ class RecorderUI {
modalDialogCustom.alert(msg) modalDialogCustom.alert(msg)
} }
const confirmationCb = this.getConfirmationCb(modalDialog, confirmDialog)
// TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily // TODO: there is still a UI dependency to remove here, it's still too coupled at this point to remove easily
this.recorder.runScenario(continueCb, promptCb, alertCb, confirmDialog, modalDialog, this.logCallBack, (error, abi, address, contractName) => { this.recorder.runScenario(continueCb, promptCb, alertCb, confirmationCb, this.logCallBack, (error, abi, address, contractName) => {
if (error) { if (error) {
return modalDialogCustom.alert(error) return modalDialogCustom.alert(error)
} }
@ -73,6 +77,37 @@ class RecorderUI {
}) })
} }
getConfirmationCb (modalDialog, confirmDialog) {
const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
const amount = this.blockchain.fromWei(tx.value, true, 'ether')
const content = confirmDialog(tx, amount, gasEstimation, null, this.blockchain.determineGasFees(tx), this.blockchain.determineGasPrice)
modalDialog('Confirm transaction', content,
{ label: 'Confirm',
fn: () => {
this.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 = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
}
)
}
return confirmationCb
}
triggerRecordButton () { triggerRecordButton () {
this.recorder.saveScenario( this.recorder.saveScenario(
(path, cb) => { (path, cb) => {

@ -11,12 +11,12 @@ const globalRegistry = require('../../../global/registry')
class SettingsUI { class SettingsUI {
constructor (settings, networkModule) { constructor (blockchain, networkModule) {
this.settings = settings this.blockchain = blockchain
this.event = new EventManager() this.event = new EventManager()
this._components = {} this._components = {}
this.settings.event.register('transactionExecuted', (error, from, to, data, lookupOnly, txResult) => { this.blockchain.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'
this.updateAccountBalances() this.updateAccountBalances()
@ -44,7 +44,7 @@ class SettingsUI {
if (!this.el) return if (!this.el) return
var accounts = $(this.el.querySelector('#txorigin')).children('option') var accounts = $(this.el.querySelector('#txorigin')).children('option')
accounts.each((index, account) => { accounts.each((index, account) => {
this.settings.getAccountBalanceForAddress(account.value, (err, balance) => { this.blockchain.getAccountBalanceForAddress(account.value, (err, balance) => {
if (err) return if (err) return
account.innerText = helper.shortenAddress(account.value, balance) account.innerText = helper.shortenAddress(account.value, balance)
}) })
@ -139,7 +139,7 @@ class SettingsUI {
var selectExEnv = environmentEl.querySelector('#selectExEnvOptions') var selectExEnv = environmentEl.querySelector('#selectExEnvOptions')
this.setDropdown(selectExEnv) this.setDropdown(selectExEnv)
this.settings.event.register('contextChanged', (context, silent) => { this.blockchain.event.register('contextChanged', (context, silent) => {
this.setFinalContext() this.setFinalContext()
}) })
@ -156,7 +156,7 @@ class SettingsUI {
setDropdown (selectExEnv) { setDropdown (selectExEnv) {
this.selectExEnv = selectExEnv this.selectExEnv = selectExEnv
this.settings.event.register('addProvider', (network) => { this.blockchain.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}" value="${network.name}"
@ -167,7 +167,7 @@ class SettingsUI {
addTooltip(`${network.name} [${network.url}] added`) addTooltip(`${network.name} [${network.url}] added`)
}) })
this.settings.event.register('removeProvider', (name) => { this.blockchain.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)
@ -177,9 +177,9 @@ class SettingsUI {
selectExEnv.addEventListener('change', (event) => { selectExEnv.addEventListener('change', (event) => {
let context = selectExEnv.options[selectExEnv.selectedIndex].value let context = selectExEnv.options[selectExEnv.selectedIndex].value
this.settings.changeExecutionContext(context, () => { this.blockchain.changeExecutionContext(context, () => {
modalDialogCustom.prompt('External node request', this.web3ProviderDialogBody(), 'http://localhost:8545', (target) => { modalDialogCustom.prompt('External node request', this.web3ProviderDialogBody(), 'http://localhost:8545', (target) => {
this.settings.setProviderFromEndpoint(target, context, (alertMsg) => { this.blockchain.setProviderFromEndpoint(target, context, (alertMsg) => {
if (alertMsg) addTooltip(alertMsg) if (alertMsg) addTooltip(alertMsg)
this.setFinalContext() this.setFinalContext()
}) })
@ -189,7 +189,7 @@ class SettingsUI {
}, this.setFinalContext.bind(this)) }, this.setFinalContext.bind(this))
}) })
selectExEnv.value = this.settings.getProvider() selectExEnv.value = this.blockchain.getProvider()
} }
web3ProviderDialogBody () { web3ProviderDialogBody () {
@ -208,7 +208,7 @@ class SettingsUI {
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 = this.settings.getProvider() this.selectExEnv.value = this.blockchain.getProvider()
this.event.trigger('clearInstance', []) this.event.trigger('clearInstance', [])
this.updateNetwork() this.updateNetwork()
this.updatePlusButton() this.updatePlusButton()
@ -250,7 +250,7 @@ class SettingsUI {
} }
newAccount () { newAccount () {
this.settings.newAccount( this.blockchain.newAccount(
(cb) => { (cb) => {
modalDialogCustom.promptPassphraseCreation((error, passphrase) => { modalDialogCustom.promptPassphraseCreation((error, passphrase) => {
if (error) { if (error) {
@ -269,14 +269,14 @@ class SettingsUI {
} }
signMessage () { signMessage () {
this.settings.getAccounts((err, accounts) => { this.blockchain.getAccounts((err, accounts) => {
if (err) { if (err) {
return addTooltip(`Cannot get account list: ${err}`) return 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.el.querySelector('#txorigin') var $txOrigin = this.el.querySelector('#txorigin')
if (!$txOrigin.selectedOptions[0] && (this.settings.isInjectedWeb3() || this.settings.isWeb3Provider())) { if (!$txOrigin.selectedOptions[0] && (this.blockchain.isInjectedWeb3() || this.blockchain.isWeb3Provider())) {
return addTooltip(`Account list is empty, please make sure the current provider is properly connected to remix`) return addTooltip(`Account list is empty, please make sure the current provider is properly connected to remix`)
} }
@ -284,7 +284,7 @@ class SettingsUI {
var promptCb = (passphrase) => { var promptCb = (passphrase) => {
const modal = modalDialogCustom.promptMulti(signMessageDialog, (message) => { const modal = modalDialogCustom.promptMulti(signMessageDialog, (message) => {
this.settings.signMessage(message, account, passphrase, (err, msgHash, signedData) => { this.blockchain.signMessage(message, account, passphrase, (err, msgHash, signedData) => {
if (err) { if (err) {
return addTooltip(err) return addTooltip(err)
} }
@ -301,7 +301,7 @@ class SettingsUI {
}, false) }, false)
} }
if (this.settings.isWeb3Provider()) { if (this.blockchain.isWeb3Provider()) {
return modalDialogCustom.promptPassphrase( return modalDialogCustom.promptPassphrase(
'Passphrase to sign a message', 'Passphrase to sign a message',
'Enter your passphrase for this account to sign the message', 'Enter your passphrase for this account to sign the message',
@ -315,7 +315,7 @@ class SettingsUI {
} }
updateNetwork () { updateNetwork () {
this.settings.updateNetwork((err, {id, name} = {}) => { this.blockchain.updateNetwork((err, {id, name} = {}) => {
if (err) { if (err) {
this.netUI.innerHTML = 'can\'t detect network ' this.netUI.innerHTML = 'can\'t detect network '
return return
@ -331,7 +331,7 @@ class SettingsUI {
this.accountListCallId++ this.accountListCallId++
var callid = this.accountListCallId var callid = this.accountListCallId
var txOrigin = this.el.querySelector('#txorigin') var txOrigin = this.el.querySelector('#txorigin')
this.settings.getAccounts((err, accounts) => { this.blockchain.getAccounts((err, accounts) => {
if (this.accountListCallId > callid) return if (this.accountListCallId > callid) return
this.accountListCallId++ this.accountListCallId++
if (err) { addTooltip(`Cannot get account list: ${err}`) } if (err) { addTooltip(`Cannot get account list: ${err}`) }

@ -1,22 +1,35 @@
var registry = require('../../global/registry') var registry = require('../../global/registry')
var remixLib = require('remix-lib') var remixLib = require('remix-lib')
var yo = require('yo-yo') var yo = require('yo-yo')
var Txlistener = remixLib.execution.txListener
var EventsDecoder = remixLib.execution.EventsDecoder var EventsDecoder = remixLib.execution.EventsDecoder
var TransactionReceiptResolver = require('../../lib/transactionReceiptResolver') var TransactionReceiptResolver = require('../../lib/transactionReceiptResolver')
export function makeUdapp (udapp, executionContext, compilersArtefacts, logHtmlCallback) { const transactionDetailsLinks = {
'Main': 'https://www.etherscan.io/tx/',
'Rinkeby': 'https://rinkeby.etherscan.io/tx/',
'Ropsten': 'https://ropsten.etherscan.io/tx/',
'Kovan': 'https://kovan.etherscan.io/tx/',
'Goerli': 'https://goerli.etherscan.io/tx/'
}
function txDetailsLink (network, hash) {
if (transactionDetailsLinks[network]) {
return transactionDetailsLinks[network] + hash
}
}
export function makeUdapp (blockchain, compilersArtefacts, logHtmlCallback) {
// ----------------- UniversalDApp ----------------- // ----------------- UniversalDApp -----------------
// TODO: to remove when possible // TODO: to remove when possible
udapp.event.register('transactionBroadcasted', (txhash, networkName) => { blockchain.event.register('transactionBroadcasted', (txhash, networkName) => {
var txLink = executionContext.txDetailsLink(networkName, txhash) var txLink = txDetailsLink(networkName, txhash)
if (txLink && logHtmlCallback) logHtmlCallback(yo`<a href="${txLink}" target="_blank">${txLink}</a>`) if (txLink && logHtmlCallback) logHtmlCallback(yo`<a href="${txLink}" target="_blank">${txLink}</a>`)
}) })
// ----------------- Tx listener ----------------- // ----------------- Tx listener -----------------
const transactionReceiptResolver = new TransactionReceiptResolver(executionContext) const transactionReceiptResolver = new TransactionReceiptResolver(blockchain)
const txlistener = new Txlistener({ const txlistener = blockchain.getTxListener({
api: { api: {
contracts: function () { contracts: function () {
if (compilersArtefacts['__last']) return compilersArtefacts['__last'].getContracts() if (compilersArtefacts['__last']) return compilersArtefacts['__last'].getContracts()
@ -25,12 +38,11 @@ export function makeUdapp (udapp, executionContext, compilersArtefacts, logHtmlC
resolveReceipt: function (tx, cb) { resolveReceipt: function (tx, cb) {
transactionReceiptResolver.resolve(tx, cb) transactionReceiptResolver.resolve(tx, cb)
} }
}, }
event: { })
udapp: udapp.event
}}, executionContext)
registry.put({api: txlistener, name: 'txlistener'}) registry.put({api: txlistener, name: 'txlistener'})
udapp.startListening(txlistener) blockchain.startListening(txlistener)
const eventsDecoder = new EventsDecoder({ const eventsDecoder = new EventsDecoder({
api: { api: {
@ -41,5 +53,5 @@ export function makeUdapp (udapp, executionContext, compilersArtefacts, logHtmlC
}) })
txlistener.startListening() txlistener.startListening()
return {udapp, txlistener, eventsDecoder} return {txlistener, eventsDecoder}
} }

@ -9,13 +9,11 @@ const EventManager = require('../../lib/events')
const Card = require('../ui/card') const Card = require('../ui/card')
const css = require('../tabs/styles/run-tab-styles') const css = require('../tabs/styles/run-tab-styles')
const Settings = require('../tabs/runTab/model/settings.js')
const SettingsUI = require('../tabs/runTab/settings.js') const SettingsUI = require('../tabs/runTab/settings.js')
const Recorder = require('../tabs/runTab/model/recorder.js') const Recorder = require('../tabs/runTab/model/recorder.js')
const RecorderUI = require('../tabs/runTab/recorder.js') const RecorderUI = require('../tabs/runTab/recorder.js')
const DropdownLogic = require('../tabs/runTab/model/dropdownlogic.js') const DropdownLogic = require('../tabs/runTab/model/dropdownlogic.js')
const ContractDropdownUI = require('../tabs/runTab/contractDropdown.js') const ContractDropdownUI = require('../tabs/runTab/contractDropdown.js')
const Blockchain = require('../tabs/runTab/model/blockchain.js')
const UniversalDAppUI = require('../ui/universal-dapp-ui') const UniversalDAppUI = require('../ui/universal-dapp-ui')
@ -35,12 +33,13 @@ const profile = {
export class RunTab extends LibraryPlugin { export class RunTab extends LibraryPlugin {
constructor (udapp, executionContext, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView) { constructor (blockchain, udapp, executionContext, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView) {
super(udapp, profile) super(udapp, profile)
this.event = new EventManager() this.event = new EventManager()
this.config = config this.config = config
this.udapp = udapp this.udapp = udapp
this.executionContext = executionContext this.executionContext = executionContext
this.blockchain = blockchain
this.fileManager = fileManager this.fileManager = fileManager
this.editor = editor this.editor = editor
this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) } this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) }
@ -122,19 +121,17 @@ export class RunTab extends LibraryPlugin {
this.instanceContainer.appendChild(this.noInstancesText) this.instanceContainer.appendChild(this.noInstancesText)
} }
renderSettings (udapp) { renderSettings () {
var settings = new Settings(this.executionContext, udapp) this.settingsUI = new SettingsUI(this.blockchain, this.networkModule)
this.settingsUI = new SettingsUI(settings, this.networkModule)
this.settingsUI.event.register('clearInstance', () => { this.settingsUI.event.register('clearInstance', () => {
this.event.trigger('clearInstance', []) this.event.trigger('clearInstance', [])
}) })
} }
renderDropdown (udappUI, fileManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) { renderDropdown (udappUI, fileManager, compilersArtefacts, config, editor, logCallback) {
const dropdownLogic = new DropdownLogic(compilersArtefacts, config, editor, this) const dropdownLogic = new DropdownLogic(compilersArtefacts, config, editor, this)
const blockchain = new Blockchain(this.executionContext, udapp) this.contractDropdownUI = new ContractDropdownUI(this.blockchain, dropdownLogic, logCallback, this)
this.contractDropdownUI = new ContractDropdownUI(blockchain, dropdownLogic, logCallback, this)
fileManager.events.on('currentFileChanged', this.contractDropdownUI.changeCurrentFile.bind(this.contractDropdownUI)) fileManager.events.on('currentFileChanged', this.contractDropdownUI.changeCurrentFile.bind(this.contractDropdownUI))
@ -150,16 +147,16 @@ export class RunTab extends LibraryPlugin {
}) })
} }
renderRecorder (udapp, udappUI, fileManager, config, logCallback) { renderRecorder (udappUI, fileManager, config, logCallback) {
this.recorderCount = yo`<span>0</span>` this.recorderCount = yo`<span>0</span>`
const recorder = new Recorder(this.executionContext, udapp, fileManager, config) const recorder = new Recorder(this.blockchain, fileManager, config)
recorder.event.register('recorderCountChange', (count) => { recorder.event.register('recorderCountChange', (count) => {
this.recorderCount.innerText = count this.recorderCount.innerText = count
}) })
this.event.register('clearInstance', recorder.clearAll.bind(recorder)) this.event.register('clearInstance', recorder.clearAll.bind(recorder))
this.recorderInterface = new RecorderUI(recorder, logCallback) this.recorderInterface = new RecorderUI(this.blockchain, recorder, logCallback, config)
this.recorderInterface.event.register('newScenario', (abi, address, contractName) => { this.recorderInterface.event.register('newScenario', (abi, address, contractName) => {
var noInstancesText = this.noInstancesText var noInstancesText = this.noInstancesText
@ -209,9 +206,9 @@ export class RunTab extends LibraryPlugin {
this.executionContext.listenOnLastBlock() this.executionContext.listenOnLastBlock()
this.udapp.resetEnvironment() this.udapp.resetEnvironment()
this.renderInstanceContainer() this.renderInstanceContainer()
this.renderSettings(this.udapp) this.renderSettings()
this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.udapp, this.filePanel, this.logCallback) this.renderDropdown(this.udappUI, this.fileManager, this.compilersArtefacts, this.config, this.editor, this.logCallback)
this.renderRecorder(this.udapp, this.udappUI, this.fileManager, this.config, this.logCallback) this.renderRecorder(this.udappUI, this.fileManager, this.config, this.logCallback)
this.renderRecorderCard() this.renderRecorderCard()
return this.renderContainer() return this.renderContainer()
} }

@ -116,7 +116,7 @@ var css = csjs`
* *
*/ */
class TxLogger { class TxLogger {
constructor (eventsDecoder, txListener, terminal, executionContext) { constructor (eventsDecoder, txListener, terminal, blockchain) {
this.event = new EventManager() this.event = new EventManager()
this.seen = {} this.seen = {}
function filterTx (value, query) { function filterTx (value, query) {
@ -139,7 +139,7 @@ class TxLogger {
if (data.tx.isCall) { if (data.tx.isCall) {
el = renderCall(this, data) el = renderCall(this, data)
} else { } else {
el = renderKnownTransaction(this, data, executionContext) el = renderKnownTransaction(this, data, blockchain)
} }
this.seen[data.tx.hash] = el this.seen[data.tx.hash] = el
append(el) append(el)
@ -148,7 +148,7 @@ class TxLogger {
this.logUnknownTX = this.terminal.registerCommand('unknownTransaction', (args, cmds, append) => { this.logUnknownTX = this.terminal.registerCommand('unknownTransaction', (args, cmds, append) => {
// triggered for transaction AND call // triggered for transaction AND call
var data = args[0] var data = args[0]
var el = renderUnknownTransaction(this, data, executionContext) var el = renderUnknownTransaction(this, data, blockchain)
append(el) append(el)
}, { activate: false, filterFn: filterTx }) }, { activate: false, filterFn: filterTx })
@ -204,7 +204,7 @@ function log (self, tx, receipt) {
} }
} }
function renderKnownTransaction (self, data, executionContext) { function renderKnownTransaction (self, data, blockchain) {
var from = data.tx.from var from = data.tx.from
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn var to = data.resolvedData.contractName + '.' + data.resolvedData.fn
var obj = {from, to} var obj = {from, to}
@ -213,7 +213,7 @@ function renderKnownTransaction (self, data, executionContext) {
<span id="tx${data.tx.hash}"> <span id="tx${data.tx.hash}">
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> <div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}>
${checkTxStatus(data.receipt, txType)} ${checkTxStatus(data.receipt, txType)}
${context(self, {from, to, data}, executionContext)} ${context(self, {from, to, data}, blockchain)}
<div class=${css.buttons}> <div class=${css.buttons}>
<button class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div> <button class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
@ -250,7 +250,7 @@ function renderCall (self, data) {
return tx return tx
} }
function renderUnknownTransaction (self, data, executionContext) { function renderUnknownTransaction (self, data, blockchain) {
var from = data.tx.from var from = data.tx.from
var to = data.tx.to var to = data.tx.to
var obj = {from, to} var obj = {from, to}
@ -259,7 +259,7 @@ function renderUnknownTransaction (self, data, executionContext) {
<span id="tx${data.tx.hash}"> <span id="tx${data.tx.hash}">
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}> <div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}>
${checkTxStatus(data.receipt || data.tx, txType)} ${checkTxStatus(data.receipt || data.tx, txType)}
${context(self, {from, to, data}, executionContext)} ${context(self, {from, to, data}, blockchain)}
<div class=${css.buttons}> <div class=${css.buttons}>
<div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div> <div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div> </div>
@ -290,7 +290,7 @@ function checkTxStatus (tx, type) {
} }
} }
function context (self, opts, executionContext) { function context (self, opts, blockchain) {
var data = opts.data || '' var data = opts.data || ''
var from = opts.from ? helper.shortenHexData(opts.from) : '' var from = opts.from ? helper.shortenHexData(opts.from) : ''
var to = opts.to var to = opts.to
@ -302,7 +302,7 @@ function context (self, opts, executionContext) {
var block = data.tx.blockNumber || '' var block = data.tx.blockNumber || ''
var i = data.tx.transactionIndex var i = data.tx.transactionIndex
var value = val ? typeConversion.toInt(val) : 0 var value = val ? typeConversion.toInt(val) : 0
if (executionContext.getProvider() === 'vm') { if (blockchain.getProvider() === 'vm') {
return yo` return yo`
<div> <div>
<span class=${css.txLog}> <span class=${css.txLog}>
@ -315,7 +315,7 @@ function context (self, opts, executionContext) {
<div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div> <div class=${css.txItem}><span class=${css.txItemTitle}>hash:</span> ${hash}</div>
</span> </span>
</div>` </div>`
} else if (executionContext.getProvider() !== 'vm' && data.resolvedData) { } else if (blockchain.getProvider() !== 'vm' && data.resolvedData) {
return yo` return yo`
<div> <div>
<span class=${css.txLog}> <span class=${css.txLog}>

@ -14,10 +14,10 @@ var solidityTypeFormatter = require('../app/tabs/debugger/debuggerUI/vmDebugger/
var GistHandler = require('./gist-handler') var GistHandler = require('./gist-handler')
class CmdInterpreterAPI { class CmdInterpreterAPI {
constructor (terminal, localRegistry, executionContext) { constructor (terminal, localRegistry, blockchain) {
const self = this const self = this
self.event = new EventManager() self.event = new EventManager()
self.executionContext = executionContext self.blockchain = blockchain
self._components = {} self._components = {}
self._components.registry = localRegistry || globalRegistry self._components.registry = localRegistry || globalRegistry
self._components.terminal = terminal self._components.terminal = terminal
@ -62,14 +62,14 @@ class CmdInterpreterAPI {
debug (hash, cb) { debug (hash, cb) {
var self = this var self = this
delete self.d delete self.d
self.executionContext.web3().eth.getTransaction(hash, (error, tx) => { self.blockchain.web3().eth.getTransaction(hash, (error, tx) => {
if (error) return cb(error) if (error) return cb(error)
var debugSession = new RemixDebug({ var debugSession = new RemixDebug({
compilationResult: () => { compilationResult: () => {
return self._deps.compilersArtefacts['__last'].getData() return self._deps.compilersArtefacts['__last'].getData()
} }
}) })
debugSession.addProvider('web3', self.executionContext.web3()) debugSession.addProvider('web3', self.blockchain.web3())
debugSession.switchProvider('web3') debugSession.switchProvider('web3')
debugSession.debug(tx) debugSession.debug(tx)
self.d = debugSession self.d = debugSession
@ -180,7 +180,7 @@ class CmdInterpreterAPI {
}) })
} }
setproviderurl (url, cb) { setproviderurl (url, cb) {
this.executionContext.setProviderFromEndpoint(url, 'web3', (error) => { this.blockchain.setProviderFromEndpoint(url, 'web3', (error) => {
if (error) toolTip(error) if (error) toolTip(error)
if (cb) cb() if (cb) cb()
}) })

@ -1,16 +1,16 @@
'use strict' 'use strict'
module.exports = class TransactionReceiptResolver { module.exports = class TransactionReceiptResolver {
constructor (executionContext) { constructor (blockchain) {
this._transactionReceipts = {} this._transactionReceipts = {}
this.executionContext = executionContext this.blockchain = blockchain
} }
resolve (tx, cb) { resolve (tx, cb) {
if (this._transactionReceipts[tx.hash]) { if (this._transactionReceipts[tx.hash]) {
return cb(null, this._transactionReceipts[tx.hash]) return cb(null, this._transactionReceipts[tx.hash])
} }
this.executionContext.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => { this.blockchain.web3().eth.getTransactionReceipt(tx.hash, (error, receipt) => {
if (!error) { if (!error) {
this._transactionReceipts[tx.hash] = receipt this._transactionReceipts[tx.hash] = receipt
cb(null, receipt) cb(null, receipt)

Loading…
Cancel
Save