Merge pull request #2506 from ethereum/refactor_logic1

Refactor dropdown logic
pull/5370/head
Iuri Matias 5 years ago committed by GitHub
commit 4934b694b7
  1. 15
      src/app.js
  2. 6
      src/app/files/compiler-metadata.js
  3. 6
      src/app/panels/main-view.js
  4. 10
      src/app/panels/terminal.js
  5. 5
      src/app/tabs/debugger-tab.js
  6. 10
      src/app/tabs/debugger/debuggerUI.js
  7. 18
      src/app/tabs/network-module.js
  8. 61
      src/app/tabs/runTab/contractDropdown.js
  9. 98
      src/app/tabs/runTab/model/blockchain.js
  10. 201
      src/app/tabs/runTab/model/dropdownlogic.js
  11. 12
      src/app/tabs/runTab/model/recorder.js
  12. 32
      src/app/tabs/runTab/model/settings.js
  13. 2
      src/app/tabs/runTab/settings.js
  14. 7
      src/app/udapp/make-udapp.js
  15. 24
      src/app/udapp/run-tab.js
  16. 17
      src/app/ui/txLogger.js
  17. 11
      src/app/ui/universal-dapp-ui.js
  18. 4
      src/execution-context.js
  19. 10
      src/lib/cmdInterpreterAPI.js
  20. 6
      src/lib/transactionReceiptResolver.js

@ -23,6 +23,8 @@ var toolTip = require('./app/ui/tooltip')
var CompilerMetadata = require('./app/files/compiler-metadata')
var CompilerImport = require('./app/compiler/compiler-imports')
var executionContext = remixLib.execution.executionContext
const PluginManagerComponent = require('./app/components/plugin-manager-component')
const CompilersArtefacts = require('./app/compiler/compiler-artefacts')
@ -222,15 +224,15 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
const fileManager = new FileManager(editor)
registry.put({api: fileManager, name: 'filemanager'})
// ----------------- compilation metadata generation servive ----------------------------
const compilerMetadataGenerator = new CompilerMetadata(fileManager, registry.get('config').api)
const compilerMetadataGenerator = new CompilerMetadata(executionContext, fileManager, registry.get('config').api)
// ----------------- compilation result service (can keep track of compilation results) ----------------------------
const compilersArtefacts = new CompilersArtefacts() // store all the compilation results (key represent a compiler name)
registry.put({api: compilersArtefacts, name: 'compilersartefacts'})
// ----------------- universal dapp: run transaction, listen on transactions, decode events
const udapp = new UniversalDApp(registry.get('config').api)
const {eventsDecoder, txlistener} = makeUdapp(udapp, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
const udapp = new UniversalDApp(registry.get('config').api, executionContext)
const {eventsDecoder, txlistener} = makeUdapp(udapp, executionContext, compilersArtefacts, (domEl) => mainview.getTerminal().logHtml(domEl))
// ----------------- network service (resolve network id / name) ----------------------------
const networkModule = new NetworkModule()
const networkModule = new NetworkModule(executionContext)
// ----------------- convert offset to line/column service ----------------------------
var offsetToLineColumnConverter = new OffsetToLineColumnConverter()
registry.put({api: offsetToLineColumnConverter, name: 'offsettolinecolumnconverter'})
@ -248,7 +250,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
// LAYOUT & SYSTEM VIEWS
const appPanel = new MainPanel()
const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder)
const mainview = new MainView(editor, appPanel, fileManager, appManager, txlistener, eventsDecoder, executionContext)
registry.put({ api: mainview, name: 'mainview' })
appManager.register([
@ -293,6 +295,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
)
const run = new RunTab(
udapp,
executionContext,
registry.get('config').api,
registry.get('filemanager').api,
registry.get('editor').api,
@ -302,7 +305,7 @@ Please make a backup of your contracts and start using http://remix.ethereum.org
mainview
)
const analysis = new AnalysisTab(registry)
const debug = new DebuggerTab()
const debug = new DebuggerTab(executionContext)
const test = new TestTab(
registry.get('filemanager').api,
filePanel,

@ -1,5 +1,4 @@
'use strict'
var executionContext = require('../../execution-context')
var CompilerAbstract = require('../compiler/compiler-abstract')
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
@ -12,9 +11,10 @@ const profile = {
}
class CompilerMetadata extends Plugin {
constructor (fileManager, config) {
constructor (executionContext, fileManager, config) {
super(profile)
var self = this
self.executionContext = executionContext
self.fileManager = fileManager
self.config = config
self.networks = ['VM:-', 'main:1', 'ropsten:3', 'rinkeby:4', 'kovan:42', 'görli:5', 'Custom']
@ -97,7 +97,7 @@ class CompilerMetadata extends Plugin {
var provider = self.fileManager.currentFileProvider()
var path = self.fileManager.currentPath()
if (provider && path) {
executionContext.detectNetwork((err, { id, name } = {}) => {
self.executionContext.detectNetwork((err, { id, name } = {}) => {
if (err) {
console.log(err)
} else {

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

@ -10,7 +10,6 @@ var Web3 = require('web3')
var swarmgw = require('swarmgw')()
var CommandInterpreterAPI = require('../../lib/cmdInterpreterAPI')
var executionContext = require('../../execution-context')
var AutoCompletePopup = require('../ui/auto-complete-popup')
var TxLogger = require('../../app/ui/txLogger')
@ -42,6 +41,7 @@ class Terminal extends Plugin {
super(profile)
var self = this
self.event = new EventManager()
self.executionContext = opts.executionContext
self._api = api
self._opts = opts
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._components = {}
self._components.cmdInterpreter = new CommandInterpreterAPI(this)
self._components.cmdInterpreter = new CommandInterpreterAPI(this, null, self.executionContext)
self._components.autoCompletePopup = new AutoCompletePopup(self._opts)
self._components.autoCompletePopup.event.register('handleSelect', function (input) {
let textList = self._view.input.innerText.split(' ')
@ -437,7 +437,7 @@ class Terminal extends Plugin {
self._shell('remix.help()', self.commands, () => {})
self.commands.html(intro)
self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this)
self._components.txLogger = new TxLogger(self._opts.eventsDecoder, self._opts.txListener, this, self.executionContext)
self._components.txLogger.event.register('debuggingRequested', (hash) => {
// TODO should probably be in the run module
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.')
}
var self = this
var context = domTerminalFeatures(self, scopedCommands)
var context = domTerminalFeatures(self, scopedCommands, self.executionContext)
try {
var cmds = vm.createContext(Object.assign(self._jsSandboxContext, context, self._jsSandboxRegistered))
var result = vm.runInContext(script, cmds)
@ -680,7 +680,7 @@ class Terminal extends Plugin {
}
}
function domTerminalFeatures (self, scopedCommands) {
function domTerminalFeatures (self, scopedCommands, executionContext) {
return {
swarmgw,
ethers,

@ -21,9 +21,10 @@ const profile = {
class DebuggerTab extends ViewPlugin {
constructor () {
constructor (executionContext) {
super(profile)
this.el = null
this.executionContext = executionContext
}
render () {
@ -33,7 +34,7 @@ class DebuggerTab extends ViewPlugin {
<div class="${css.debuggerTabView}" id="debugView">
<div id="debugger" class="${css.debugger}"></div>
</div>`
this.debuggerUI = new DebuggerUI(this.el.querySelector('#debugger'))
this.debuggerUI = new DebuggerUI(this.el.querySelector('#debugger'), this.executionContext)
return this.el
}

@ -9,7 +9,6 @@ var SourceHighlighter = require('../../editor/sourceHighlighter')
var EventManager = require('../../../lib/events')
var executionContext = require('../../../execution-context')
var globalRegistry = require('../../../global/registry')
var remixLib = require('remix-lib')
@ -31,8 +30,9 @@ var css = csjs`
class DebuggerUI {
constructor (container) {
constructor (container, executionContext) {
this.registry = globalRegistry
this.executionContext = executionContext
this.event = new EventManager()
this.isActive = false
@ -105,13 +105,13 @@ class DebuggerUI {
getDebugWeb3 () {
return new Promise((resolve, reject) => {
executionContext.detectNetwork((error, network) => {
this.executionContext.detectNetwork((error, network) => {
let web3
if (error || !network) {
web3 = init.web3DebugNode(executionContext.web3())
web3 = init.web3DebugNode(this.executionContext.web3())
} else {
const webDebugNode = init.web3DebugNode(network.name)
web3 = !webDebugNode ? executionContext.web3() : webDebugNode
web3 = !webDebugNode ? this.executionContext.web3() : webDebugNode
}
init.extendWeb3(web3)
resolve(web3)

@ -1,4 +1,3 @@
const executionContext = require('../../execution-context')
import { Plugin } from '@remixproject/engine'
import * as packageJson from '../../../package.json'
@ -15,10 +14,11 @@ export const profile = {
// - methods: ['getNetworkProvider', 'getEndpoint', 'detectNetwork', 'addNetwork', 'removeNetwork']
export class NetworkModule extends Plugin {
constructor () {
constructor (executionContext) {
super(profile)
this.executionContext = executionContext
// TODO: See with remix-lib to make sementic coherent
executionContext.event.register('contextChanged', (provider) => {
this.executionContext.event.register('contextChanged', (provider) => {
this.emit('providerChanged', provider)
})
/*
@ -37,13 +37,13 @@ export class NetworkModule extends Plugin {
/** Return the current network provider (web3, vm, injected) */
getNetworkProvider () {
return executionContext.getProvider()
return this.executionContext.getProvider()
}
/** Return the current network */
detectNetwork () {
return new Promise((resolve, reject) => {
executionContext.detectNetwork((error, network) => {
this.executionContext.detectNetwork((error, network) => {
error ? reject(error) : resolve(network)
})
})
@ -51,20 +51,20 @@ export class NetworkModule extends Plugin {
/** Return the url only if network provider is 'web3' */
getEndpoint () {
const provider = executionContext.getProvider()
const provider = this.executionContext.getProvider()
if (provider !== 'web3') {
throw new Error('no endpoint: current provider is either injected or vm')
}
return executionContext.web3().currentProvider.host
return this.executionContext.web3().currentProvider.host
}
/** Add a custom network to the list of available networks */
addNetwork (customNetwork) {
executionContext.addProvider(customNetwork)
this.executionContext.addProvider(customNetwork)
}
/** Remove a network to the list of availble networks */
removeNetwork (name) {
executionContext.removeProvider(name)
this.executionContext.removeProvider(name)
}
}

@ -8,9 +8,11 @@ var modalDialog = require('../../ui/modaldialog')
var MultiParamManager = require('../../ui/multiParamManager')
class ContractDropdownUI {
constructor (dropdownLogic, logCallback) {
constructor (blockchain, dropdownLogic, logCallback, runView) {
this.blockchain = blockchain
this.dropdownLogic = dropdownLogic
this.logCallback = logCallback
this.runView = runView
this.event = new EventManager()
this.listenToEvents()
@ -39,8 +41,6 @@ class ContractDropdownUI {
document.querySelector(`.${css.contractNames}`).classList.add(css.contractNamesError)
}
})
this.dropdownLogic.event.register('currentFileChanged', this.changeCurrentFile.bind(this))
}
render () {
@ -108,8 +108,9 @@ class ContractDropdownUI {
}
const selectedContract = this.getSelectedContract()
const clickCallback = (valArray, inputsValues) => {
this.createInstance(inputsValues)
const clickCallback = async (valArray, inputsValues) => {
var selectedContract = this.getSelectedContract()
this.createInstance(selectedContract, inputsValues)
}
const createConstructorInstance = new MultiParamManager(
0,
@ -130,9 +131,7 @@ class ContractDropdownUI {
return this.dropdownLogic.getSelectedContract(contractName, compilerAtributeName)
}
createInstance (args) {
var selectedContract = this.getSelectedContract()
async createInstance (selectedContract, args) {
if (selectedContract.bytecodeObject.length === 0) {
return modalDialogCustom.alert('This contract may be abstract, not implement an abstract parent\'s methods completely or not invoke an inherited contract\'s constructor correctly.')
}
@ -177,6 +176,16 @@ class ContractDropdownUI {
this.event.trigger('newContractInstanceAdded', [contractObject, address, contractObject.name])
}
let contractMetadata
try {
contractMetadata = await this.runView.call('compilerMetadata', 'deployMetadataOf', selectedContract.name)
} catch (error) {
return statusCb(`creation of ${selectedContract.name} errored: ` + error)
}
const compilerContracts = this.dropdownLogic.getCompilerContracts()
const confirmationCb = this.getConfirmationCb(modalDialog, confirmDialog)
if (selectedContract.isOverSizeLimit()) {
return modalDialog('Contract code size over limit', yo`<div>Contract creation initialization returns data with length of more than 24576 bytes. The deployment will likely fails. <br>
More info: <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-170.md" target="_blank">eip-170</a>
@ -184,7 +193,7 @@ class ContractDropdownUI {
{
label: 'Force Send',
fn: () => {
this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, finalCb)
this.blockchain.deployContract(selectedContract, args, contractMetadata, compilerContracts, {continueCb, promptCb, statusCb, finalCb}, confirmationCb)
}}, {
label: 'Cancel',
fn: () => {
@ -192,7 +201,38 @@ class ContractDropdownUI {
}
})
}
this.dropdownLogic.forceSend(selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, finalCb)
this.blockchain.deployContract(selectedContract, args, contractMetadata, compilerContracts, {continueCb, promptCb, statusCb, finalCb}, confirmationCb)
}
getConfirmationCb (modalDialog, confirmDialog) {
const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
const amount = this.dropdownLogic.fromWei(tx.value, true, 'ether')
const content = confirmDialog(tx, amount, gasEstimation, null, this.dropdownLogic.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.dropdownLogic.toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
}
)
}
return confirmationCb
}
loadFromAddress () {
@ -215,7 +255,6 @@ class ContractDropdownUI {
}
)
}
}
module.exports = ContractDropdownUI

@ -0,0 +1,98 @@
const remixLib = require('remix-lib')
const txFormat = remixLib.execution.txFormat
const txExecution = remixLib.execution.txExecution
const typeConversion = remixLib.execution.typeConversion
const Web3 = require('web3')
class Blockchain {
constructor (executionContext, udapp) {
this.executionContext = executionContext
this.udapp = udapp
}
async deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) {
const { continueCb, promptCb, statusCb, finalCb } = callbacks
var constructor = selectedContract.getConstructorInterface()
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
return txFormat.buildData(selectedContract.name, selectedContract.object, compilerContracts, true, constructor, args, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb)
}, statusCb, (data, runTxCallback) => {
// called for libraries deployment
this.runTransaction(data, continueCb, promptCb, confirmationCb, runTxCallback)
})
}
if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, confirmationCb, finalCb)
})
}
runTransaction (data, continueCb, promptCb, confirmationCb, finalCb) {
this.udapp.runTx(data, confirmationCb, continueCb, promptCb, finalCb)
}
createContract (selectedContract, data, continueCb, promptCb, confirmationCb, finalCb) {
if (data) {
data.contractName = selectedContract.name
data.linkReferences = selectedContract.bytecodeLinkReferences
data.contractABI = selectedContract.abi
}
this.udapp.createContract(data, confirmationCb, continueCb, promptCb,
(error, txResult) => {
if (error) {
return finalCb(`creation of ${selectedContract.name} errored: ${error}`)
}
var isVM = this.executionContext.isVM()
if (isVM) {
var vmError = txExecution.checkVMError(txResult)
if (vmError.error) {
return finalCb(vmError.message)
}
}
if (txResult.result.status && txResult.result.status === '0x0') {
return finalCb(`creation of ${selectedContract.name} errored: transaction execution failed`)
}
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
finalCb(null, selectedContract, address)
}
)
}
determineGasPrice (cb) {
this.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 = this.fromWei(gasPrice, false, 'gwei')
cb(null, gasPriceValue)
} catch (e) {
cb(warnMessage + e.message, null, false)
}
})
}
getGasPrice (cb) {
return this.executionContext.web3().eth.getGasPrice(cb)
}
fromWei (value, doTypeConversion, unit) {
if (doTypeConversion) {
return Web3.utils.fromWei(typeConversion.toInt(value), unit || 'ether')
}
return Web3.utils.fromWei(value.toString(10), unit || 'ether')
}
}
module.exports = Blockchain

@ -1,30 +1,21 @@
var ethJSUtil = require('ethereumjs-util')
var remixLib = require('remix-lib')
var txHelper = remixLib.execution.txHelper
var txFormat = remixLib.execution.txFormat
var executionContext = remixLib.execution.executionContext
var typeConversion = remixLib.execution.typeConversion
var txExecution = remixLib.execution.txExecution
var CompilerAbstract = require('../../../compiler/compiler-abstract')
var EventManager = remixLib.EventManager
var Web3 = require('web3')
class DropdownLogic {
constructor (fileManager, compilersArtefacts, config, editor, udapp, filePanel, runView) {
constructor (compilersArtefacts, config, editor, runView) {
this.compilersArtefacts = compilersArtefacts
this.config = config
this.editor = editor
this.udapp = udapp
this.runView = runView
this.filePanel = filePanel
this.event = new EventManager()
this.listenToCompilationEvents()
fileManager.events.on('currentFileChanged', (currentFile) => {
this.event.trigger('currentFileChanged', [currentFile])
})
}
// TODO: can be moved up; the event in contractDropdown will have to refactored a method instead
@ -120,185 +111,27 @@ class DropdownLogic {
return Web3.utils.toBN(gas).mul(Web3.utils.toBN(Web3.utils.toWei(gasPrice.toString(10), unit || 'gwei')))
}
getGasPrice (cb) {
return executionContext.web3().eth.getGasPrice(cb)
}
isVM () {
return executionContext.isVM()
}
// TODO: check if selectedContract and data can be joined
createContract (selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, finalCb) {
if (data) {
data.contractName = selectedContract.name
data.linkReferences = selectedContract.bytecodeLinkReferences
data.contractABI = selectedContract.abi
}
var confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
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
}
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) => {
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.')
}
})
cb(txFeeText, priceStatus)
}
this.udapp.createContract(data, confirmationCb, continueCb, promptCb,
(error, txResult) => {
if (error) {
return finalCb(`creation of ${selectedContract.name} errored: ${error}`)
}
var isVM = executionContext.isVM()
if (isVM) {
var vmError = txExecution.checkVMError(txResult)
if (vmError.error) {
return finalCb(vmError.message)
}
}
if (txResult.result.status && txResult.result.status === '0x0') {
return finalCb(`creation of ${selectedContract.name} errored: transaction execution failed`)
}
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
finalCb(null, selectedContract, address)
}
)
}
runTransaction (data, continueCb, promptCb, modalDialog, confirmDialog, finalCb) {
var confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
var amount = this.fromWei(tx.value, true, 'ether')
var content = confirmDialog(tx, amount, gasEstimation, null,
(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)
},
(cb) => {
this.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 = this.fromWei(gasPrice, false, '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 = this.toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
}
)
}
this.udapp.runTx(data, confirmationCb, continueCb, promptCb, finalCb)
return determineGasFeesCb
}
async forceSend (selectedContract, args, continueCb, promptCb, modalDialog, confirmDialog, statusCb, cb) {
var constructor = selectedContract.getConstructorInterface()
// TODO: deployMetadataOf can be moved here
let contractMetadata
try {
contractMetadata = await this.runView.call('compilerMetadata', 'deployMetadataOf', selectedContract.name)
} catch (error) {
return statusCb(`creation of ${selectedContract.name} errored: ` + error)
}
if (!contractMetadata || (contractMetadata && contractMetadata.autoDeployLib)) {
return txFormat.buildData(selectedContract.name, selectedContract.object, this.compilersArtefacts['__last'].getData().contracts, true, constructor, args, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, cb)
}, statusCb, (data, runTxCallback) => {
// called for libraries deployment
this.runTransaction(data, continueCb, promptCb, modalDialog, confirmDialog, runTxCallback)
})
}
if (Object.keys(selectedContract.bytecodeLinkReferences).length) statusCb(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)
txFormat.encodeConstructorCallAndLinkLibraries(selectedContract.object, args, constructor, contractMetadata.linkReferences, selectedContract.bytecodeLinkReferences, (error, data) => {
if (error) return statusCb(`creation of ${selectedContract.name} errored: ` + error)
statusCb(`creation of ${selectedContract.name} pending...`)
this.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, cb)
})
getCompilerContracts () {
return this.compilersArtefacts['__last'].getData().contracts
}
}

@ -2,7 +2,6 @@ var async = require('async')
var ethutil = require('ethereumjs-util')
var remixLib = require('remix-lib')
var EventManager = remixLib.EventManager
var executionContext = remixLib.execution.executionContext
var format = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
@ -15,9 +14,10 @@ var Web3 = require('web3')
*
*/
class Recorder {
constructor (udapp, fileManager, config) {
constructor (executionContext, udapp, fileManager, config) {
var self = this
self.event = new EventManager()
self.executionContext = executionContext
self.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} }
this.udapp = udapp
this.fileManager = fileManager
@ -74,7 +74,7 @@ class Recorder {
if (error) return console.log(error)
if (call) return
const rawAddress = executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
const rawAddress = this.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
if (!rawAddress) return // not a contract creation
const stringAddress = this.addressToString(rawAddress)
const address = ethutil.toChecksumAddress(stringAddress)
@ -82,7 +82,7 @@ class Recorder {
this.data._createdContracts[address] = timestamp
this.data._createdContractsReverse[timestamp] = address
})
executionContext.event.register('contextChanged', this.clearAll.bind(this))
this.executionContext.event.register('contextChanged', this.clearAll.bind(this))
this.event.register('newTxRecorded', (count) => {
this.event.trigger('recorderCountChange', [count])
})
@ -261,7 +261,7 @@ class Recorder {
console.error(err)
logCallBack(err + '. Execution failed at ' + index)
} else {
const rawAddress = executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
const rawAddress = self.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
if (rawAddress) {
const stringAddress = self.addressToString(rawAddress)
const address = ethutil.toChecksumAddress(stringAddress)
@ -335,7 +335,7 @@ class Recorder {
cb(txFeeText, priceStatus)
},
(cb) => {
executionContext.web3().eth.getGasPrice((error, gasPrice) => {
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)

@ -4,11 +4,11 @@ var remixLib = require('remix-lib')
var Web3 = require('web3')
const addTooltip = require('../../../ui/tooltip')
var EventManager = remixLib.EventManager
var executionContext = remixLib.execution.executionContext
class Settings {
constructor (udapp) {
constructor (executionContext, udapp) {
this.executionContext = executionContext
this.udapp = udapp
this.event = new EventManager()
@ -16,15 +16,15 @@ class Settings {
this.event.trigger('transactionExecuted', [error, from, to, data, lookupOnly, txResult])
})
executionContext.event.register('contextChanged', (context, silent) => {
this.executionContext.event.register('contextChanged', (context, silent) => {
this.event.trigger('contextChanged', [context, silent])
})
executionContext.event.register('addProvider', (network) => {
this.executionContext.event.register('addProvider', (network) => {
this.event.trigger('addProvider', [network])
})
executionContext.event.register('removeProvider', (name) => {
this.executionContext.event.register('removeProvider', (name) => {
this.event.trigger('removeProvider', [name])
})
@ -32,15 +32,15 @@ class Settings {
}
changeExecutionContext (context, confirmCb, infoCb, cb) {
return executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
return this.executionContext.executionContextChange(context, null, confirmCb, infoCb, cb)
}
setProviderFromEndpoint (target, context, cb) {
return executionContext.setProviderFromEndpoint(target, context, cb)
return this.executionContext.setProviderFromEndpoint(target, context, cb)
}
getProvider () {
return executionContext.getProvider()
return this.executionContext.getProvider()
}
getAccountBalanceForAddress (address, cb) {
@ -50,7 +50,7 @@ class Settings {
updateNetwork (cb) {
this.networkcallid++
((callid) => {
executionContext.detectNetwork((err, { id, name } = {}) => {
this.executionContext.detectNetwork((err, { id, name } = {}) => {
if (this.networkcallid > callid) return
this.networkcallid++
if (err) {
@ -70,18 +70,18 @@ class Settings {
}
isWeb3Provider () {
var isVM = executionContext.isVM()
var isInjected = executionContext.getProvider() === 'injected'
var isVM = this.executionContext.isVM()
var isInjected = this.executionContext.getProvider() === 'injected'
return (!isVM && !isInjected)
}
isInjectedWeb3 () {
return executionContext.getProvider() === 'injected'
return this.executionContext.getProvider() === 'injected'
}
signMessage (message, account, passphrase, cb) {
var isVM = executionContext.isVM()
var isInjected = executionContext.getProvider() === 'injected'
var isVM = this.executionContext.isVM()
var isInjected = this.executionContext.getProvider() === 'injected'
if (isVM) {
const personalMsg = ethJSUtil.hashPersonalMessage(Buffer.from(message))
@ -99,7 +99,7 @@ class Settings {
const hashedMsg = Web3.utils.sha3(message)
try {
addTooltip('Please check your provider to approve')
executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
this.executionContext.web3().eth.sign(account, hashedMsg, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})
} catch (e) {
@ -110,7 +110,7 @@ class Settings {
const hashedMsg = Web3.utils.sha3(message)
try {
var personal = new Personal(executionContext.web3().currentProvider)
var personal = new Personal(this.executionContext.web3().currentProvider)
personal.sign(hashedMsg, account, passphrase, (error, signedData) => {
cb(error.message, hashedMsg, signedData)
})

@ -320,7 +320,7 @@ class SettingsUI {
this.netUI.innerHTML = 'can\'t detect network '
return
}
let network = this._components.networkModule.getNetworkProvider
let network = this._components.networkModule.getNetworkProvider.bind(this._components.networkModule)
this.netUI.innerHTML = (network() !== 'vm') ? `${name} (${id || '-'}) network` : ''
})
this.fillAccountsList()

@ -1,12 +1,11 @@
var registry = require('../../global/registry')
var remixLib = require('remix-lib')
var yo = require('yo-yo')
var executionContext = remixLib.execution.executionContext
var Txlistener = remixLib.execution.txListener
var EventsDecoder = remixLib.execution.EventsDecoder
var TransactionReceiptResolver = require('../../lib/transactionReceiptResolver')
export function makeUdapp (udapp, compilersArtefacts, logHtmlCallback) {
export function makeUdapp (udapp, executionContext, compilersArtefacts, logHtmlCallback) {
// ----------------- UniversalDApp -----------------
// TODO: to remove when possible
udapp.event.register('transactionBroadcasted', (txhash, networkName) => {
@ -15,7 +14,7 @@ export function makeUdapp (udapp, compilersArtefacts, logHtmlCallback) {
})
// ----------------- Tx listener -----------------
const transactionReceiptResolver = new TransactionReceiptResolver()
const transactionReceiptResolver = new TransactionReceiptResolver(executionContext)
const txlistener = new Txlistener({
api: {
@ -29,7 +28,7 @@ export function makeUdapp (udapp, compilersArtefacts, logHtmlCallback) {
},
event: {
udapp: udapp.event
}})
}}, executionContext)
registry.put({api: txlistener, name: 'txlistener'})
udapp.startListening(txlistener)

@ -15,9 +15,9 @@ const Recorder = require('../tabs/runTab/model/recorder.js')
const RecorderUI = require('../tabs/runTab/recorder.js')
const DropdownLogic = require('../tabs/runTab/model/dropdownlogic.js')
const ContractDropdownUI = require('../tabs/runTab/contractDropdown.js')
const Blockchain = require('../tabs/runTab/model/blockchain.js')
const UniversalDAppUI = require('../ui/universal-dapp-ui')
const executionContext = require('../../execution-context')
const profile = {
name: 'udapp',
@ -35,11 +35,12 @@ const profile = {
export class RunTab extends LibraryPlugin {
constructor (udapp, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView) {
constructor (udapp, executionContext, config, fileManager, editor, filePanel, compilersArtefacts, networkModule, mainView) {
super(udapp, profile)
this.event = new EventManager()
this.config = config
this.udapp = udapp
this.executionContext = executionContext
this.fileManager = fileManager
this.editor = editor
this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) }
@ -49,7 +50,7 @@ export class RunTab extends LibraryPlugin {
}
onActivationInternal () {
this.udappUI = new UniversalDAppUI(this.udapp, this.logCallback)
this.udappUI = new UniversalDAppUI(this.udapp, this.logCallback, this.executionContext)
this.udapp.resetAPI({
getAddress: (cb) => {
cb(null, $('#txorigin').val())
@ -122,7 +123,7 @@ export class RunTab extends LibraryPlugin {
}
renderSettings (udapp) {
var settings = new Settings(udapp)
var settings = new Settings(this.executionContext, udapp)
this.settingsUI = new SettingsUI(settings, this.networkModule)
this.settingsUI.event.register('clearInstance', () => {
@ -131,8 +132,11 @@ export class RunTab extends LibraryPlugin {
}
renderDropdown (udappUI, fileManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) {
const dropdownLogic = new DropdownLogic(fileManager, compilersArtefacts, config, editor, udapp, filePanel, this)
this.contractDropdownUI = new ContractDropdownUI(dropdownLogic, logCallback)
const dropdownLogic = new DropdownLogic(compilersArtefacts, config, editor, this)
const blockchain = new Blockchain(this.executionContext, udapp)
this.contractDropdownUI = new ContractDropdownUI(blockchain, dropdownLogic, logCallback, this)
fileManager.events.on('currentFileChanged', this.contractDropdownUI.changeCurrentFile.bind(this.contractDropdownUI))
this.contractDropdownUI.event.register('clearInstance', () => {
const noInstancesText = this.noInstancesText
@ -149,7 +153,7 @@ export class RunTab extends LibraryPlugin {
renderRecorder (udapp, udappUI, fileManager, config, logCallback) {
this.recorderCount = yo`<span>0</span>`
const recorder = new Recorder(udapp, fileManager, config)
const recorder = new Recorder(this.executionContext, udapp, fileManager, config)
recorder.event.register('recorderCountChange', (count) => {
this.recorderCount.innerText = count
})
@ -200,9 +204,9 @@ export class RunTab extends LibraryPlugin {
render () {
this.onActivationInternal()
executionContext.init(this.config)
executionContext.stopListenOnLastBlock()
executionContext.listenOnLastBlock()
this.executionContext.init(this.config)
this.executionContext.stopListenOnLastBlock()
this.executionContext.listenOnLastBlock()
this.udapp.resetEnvironment()
this.renderInstanceContainer()
this.renderSettings(this.udapp)

@ -8,7 +8,6 @@ var remixLib = require('remix-lib')
var EventManager = require('../../lib/events')
var helper = require('../../lib/helper')
var executionContext = require('../../execution-context')
var modalDialog = require('./modal-dialog-custom')
var typeConversion = remixLib.execution.typeConversion
var globlalRegistry = require('../../global/registry')
@ -117,7 +116,7 @@ var css = csjs`
*
*/
class TxLogger {
constructor (eventsDecoder, txListener, terminal) {
constructor (eventsDecoder, txListener, terminal, executionContext) {
this.event = new EventManager()
this.seen = {}
function filterTx (value, query) {
@ -140,7 +139,7 @@ class TxLogger {
if (data.tx.isCall) {
el = renderCall(this, data)
} else {
el = renderKnownTransaction(this, data)
el = renderKnownTransaction(this, data, executionContext)
}
this.seen[data.tx.hash] = el
append(el)
@ -149,7 +148,7 @@ class TxLogger {
this.logUnknownTX = this.terminal.registerCommand('unknownTransaction', (args, cmds, append) => {
// triggered for transaction AND call
var data = args[0]
var el = renderUnknownTransaction(this, data)
var el = renderUnknownTransaction(this, data, executionContext)
append(el)
}, { activate: false, filterFn: filterTx })
@ -205,7 +204,7 @@ function log (self, tx, receipt) {
}
}
function renderKnownTransaction (self, data) {
function renderKnownTransaction (self, data, executionContext) {
var from = data.tx.from
var to = data.resolvedData.contractName + '.' + data.resolvedData.fn
var obj = {from, to}
@ -214,7 +213,7 @@ function renderKnownTransaction (self, data) {
<span id="tx${data.tx.hash}">
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}>
${checkTxStatus(data.receipt, txType)}
${context(self, {from, to, data})}
${context(self, {from, to, data}, executionContext)}
<div class=${css.buttons}>
<button class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div>
@ -251,7 +250,7 @@ function renderCall (self, data) {
return tx
}
function renderUnknownTransaction (self, data) {
function renderUnknownTransaction (self, data, executionContext) {
var from = data.tx.from
var to = data.tx.to
var obj = {from, to}
@ -260,7 +259,7 @@ function renderUnknownTransaction (self, data) {
<span id="tx${data.tx.hash}">
<div class="${css.log}" onclick=${e => txDetails(e, tx, data, obj)}>
${checkTxStatus(data.receipt || data.tx, txType)}
${context(self, {from, to, data})}
${context(self, {from, to, data}, executionContext)}
<div class=${css.buttons}>
<div class="${css.debug} btn btn-primary btn-sm" onclick=${(e) => debug(e, data, self)}>Debug</div>
</div>
@ -291,7 +290,7 @@ function checkTxStatus (tx, type) {
}
}
function context (self, opts) {
function context (self, opts, executionContext) {
var data = opts.data || ''
var from = opts.from ? helper.shortenHexData(opts.from) : ''
var to = opts.to

@ -15,17 +15,16 @@ var typeConversion = remixLib.execution.typeConversion
var txExecution = remixLib.execution.txExecution
var txFormat = remixLib.execution.txFormat
var executionContext = require('../../execution-context')
var confirmDialog = require('./confirmDialog')
var modalCustom = require('./modal-dialog-custom')
var modalDialog = require('./modaldialog')
var TreeView = require('./TreeView')
function UniversalDAppUI (udapp, logCallback) {
function UniversalDAppUI (udapp, logCallback, executionContext) {
this.udapp = udapp
this.logCallback = logCallback
this.compilerData = {contractsDetails: {}}
this.executionContext = executionContext
}
function decodeResponseToTreeView (response, fnabi) {
@ -181,7 +180,7 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
cb(txFeeText, priceStatus)
},
(cb) => {
executionContext.web3().eth.getGasPrice((error, gasPrice) => {
self.executionContext.web3().eth.getGasPrice((error, gasPrice) => {
const warnMessage = ' Please fix this issue before sending any transaction. '
if (error) {
return cb('Unable to retrieve the current network gas price.' + warnMessage + error)
@ -263,7 +262,7 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
if (args.funABI.type === 'fallback') data.dataHex = value
self.udapp.callFunction(args.address, data, args.funABI, confirmationCb, continueCb, promptCb, (error, txResult) => {
if (!error) {
var isVM = executionContext.isVM()
var isVM = self.executionContext.isVM()
if (isVM) {
var vmError = txExecution.checkVMError(txResult)
if (vmError.error) {
@ -272,7 +271,7 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
}
}
if (lookupOnly) {
const decoded = decodeResponseToTreeView(executionContext.isVM() ? txResult.result.execResult.returnValue : ethJSUtil.toBuffer(txResult.result), args.funABI)
const decoded = decodeResponseToTreeView(self.executionContext.isVM() ? txResult.result.execResult.returnValue : ethJSUtil.toBuffer(txResult.result), args.funABI)
outputCb(decoded)
}
} else {

@ -1,4 +0,0 @@
var remixLib = require('remix-lib')
var executionContext = remixLib.execution.executionContext
module.exports = executionContext

@ -5,7 +5,6 @@ var remixLib = require('remix-lib')
var EventManager = require('../lib/events')
var CompilerImport = require('../app/compiler/compiler-imports')
var executionContext = require('../execution-context')
var toolTip = require('../app/ui/tooltip')
var globalRegistry = require('../global/registry')
var SourceHighlighter = require('../app/editor/sourceHighlighter')
@ -15,9 +14,10 @@ var solidityTypeFormatter = require('../app/tabs/debugger/debuggerUI/vmDebugger/
var GistHandler = require('./gist-handler')
class CmdInterpreterAPI {
constructor (terminal, localRegistry) {
constructor (terminal, localRegistry, executionContext) {
const self = this
self.event = new EventManager()
self.executionContext = executionContext
self._components = {}
self._components.registry = localRegistry || globalRegistry
self._components.terminal = terminal
@ -62,14 +62,14 @@ class CmdInterpreterAPI {
debug (hash, cb) {
var self = this
delete self.d
executionContext.web3().eth.getTransaction(hash, (error, tx) => {
self.executionContext.web3().eth.getTransaction(hash, (error, tx) => {
if (error) return cb(error)
var debugSession = new RemixDebug({
compilationResult: () => {
return self._deps.compilersArtefacts['__last'].getData()
}
})
debugSession.addProvider('web3', executionContext.web3())
debugSession.addProvider('web3', self.executionContext.web3())
debugSession.switchProvider('web3')
debugSession.debug(tx)
self.d = debugSession
@ -180,7 +180,7 @@ class CmdInterpreterAPI {
})
}
setproviderurl (url, cb) {
executionContext.setProviderFromEndpoint(url, 'web3', (error) => {
this.executionContext.setProviderFromEndpoint(url, 'web3', (error) => {
if (error) toolTip(error)
if (cb) cb()
})

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

Loading…
Cancel
Save