From 0185af3d9858fd8360c4492c34ea78744da52296 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 26 Dec 2019 10:48:27 -0500 Subject: [PATCH 01/66] refactor recorder logic to extract modal and confirm dialogs out, use blockchain class --- package-lock.json | 6 +- src/app/tabs/runTab/model/recorder.js | 92 ++++++++++----------------- src/app/tabs/runTab/recorder.js | 38 ++++++++++- src/app/udapp/run-tab.js | 6 +- 4 files changed, 77 insertions(+), 65 deletions(-) diff --git a/package-lock.json b/package-lock.json index c789aacdc0..6ae97f99eb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17522,9 +17522,9 @@ } }, "solc": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/solc/-/solc-0.5.13.tgz", - "integrity": "sha512-osybDVPGjAqcmSKLU3vh5iHuxbhGlJjQI5ZvI7nRDR0fgblQqYte4MGvNjbew8DPvCrmoH0ZBiz/KBBLlPxfMg==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/solc/-/solc-0.6.0.tgz", + "integrity": "sha512-fYVRKbJLbg0oETBuAJN/ts0X/hj2YgOAl3ly3nrm/qhleVr22ecl3OSXW3hRmOWvH81hJ2KHRYRQWgqioK6d0A==", "dev": true, "requires": { "command-exists": "^1.2.8", diff --git a/src/app/tabs/runTab/model/recorder.js b/src/app/tabs/runTab/model/recorder.js index b25070aac2..73c15a15a7 100644 --- a/src/app/tabs/runTab/model/recorder.js +++ b/src/app/tabs/runTab/model/recorder.js @@ -288,7 +288,41 @@ class Recorder { return address } - runScenario (continueCb, promptCb, alertCb, confirmDialog, modalDialog, logCallBack, 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') + } + + 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 + } + + runScenario (continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { var currentFile = this.config.get('currentFile') this.fileManager.fileProviderOf(currentFile).get(currentFile, (error, json) => { if (error) { @@ -312,62 +346,6 @@ class Recorder { 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) => { cb(null, abi, address, contractName) }) diff --git a/src/app/tabs/runTab/recorder.js b/src/app/tabs/runTab/recorder.js index 2dca5afbe6..cbef6f1d71 100644 --- a/src/app/tabs/runTab/recorder.js +++ b/src/app/tabs/runTab/recorder.js @@ -10,7 +10,8 @@ var confirmDialog = require('../../ui/confirmDialog') class RecorderUI { - constructor (recorder, logCallBack) { + constructor (blockchain, recorder, logCallBack) { + this.blockchain = blockchain this.recorder = recorder this.logCallBack = logCallBack this.event = new EventManager() @@ -63,8 +64,10 @@ class RecorderUI { 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 - 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) { return modalDialogCustom.alert(error) } @@ -73,6 +76,37 @@ class RecorderUI { }) } + getConfirmationCb (modalDialog, confirmDialog) { + const confirmationCb = (network, tx, gasEstimation, continueTxExecution, cancelCb) => { + if (network.name !== 'Main') { + return continueTxExecution(null) + } + const amount = this.recorder.fromWei(tx.value, true, 'ether') + const content = confirmDialog(tx, amount, gasEstimation, null, this.recorder.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.recorder.toWei(content.querySelector('#gasprice').value, 'gwei') + continueTxExecution(gasPrice) + } + }}, { + label: 'Cancel', + fn: () => { + return cancelCb('Transaction canceled by user.') + } + } + ) + } + + return confirmationCb + } + triggerRecordButton () { this.recorder.saveScenario( (path, cb) => { diff --git a/src/app/udapp/run-tab.js b/src/app/udapp/run-tab.js index a9e33c7184..41124684f6 100644 --- a/src/app/udapp/run-tab.js +++ b/src/app/udapp/run-tab.js @@ -41,6 +41,7 @@ export class RunTab extends LibraryPlugin { this.config = config this.udapp = udapp this.executionContext = executionContext + this.blockchain = new Blockchain(this.executionContext, udapp) this.fileManager = fileManager this.editor = editor this.logCallback = (msg) => { mainView.getTerminal().logHtml(msg) } @@ -133,8 +134,7 @@ export class RunTab extends LibraryPlugin { renderDropdown (udappUI, fileManager, compilersArtefacts, config, editor, udapp, filePanel, logCallback) { const dropdownLogic = new DropdownLogic(compilersArtefacts, config, editor, this) - const blockchain = new Blockchain(this.executionContext, udapp) - this.contractDropdownUI = new ContractDropdownUI(blockchain, dropdownLogic, logCallback, this) + this.contractDropdownUI = new ContractDropdownUI(this.blockchain, dropdownLogic, logCallback, this) fileManager.events.on('currentFileChanged', this.contractDropdownUI.changeCurrentFile.bind(this.contractDropdownUI)) @@ -159,7 +159,7 @@ export class RunTab extends LibraryPlugin { }) this.event.register('clearInstance', recorder.clearAll.bind(recorder)) - this.recorderInterface = new RecorderUI(recorder, logCallback) + this.recorderInterface = new RecorderUI(this.blockchain, recorder, logCallback) this.recorderInterface.event.register('newScenario', (abi, address, contractName) => { var noInstancesText = this.noInstancesText From 5861a6c5c3b169072b0c7fdc046696536758d7a4 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 26 Dec 2019 10:56:39 -0500 Subject: [PATCH 02/66] move common fromWei/toWei/determineGasFee methods into blockchain module --- src/app/tabs/runTab/contractDropdown.js | 6 ++-- src/app/tabs/runTab/model/blockchain.js | 27 ++++++++++++++++ src/app/tabs/runTab/model/dropdownlogic.js | 36 ---------------------- src/app/tabs/runTab/model/recorder.js | 36 ---------------------- src/app/tabs/runTab/recorder.js | 6 ++-- 5 files changed, 33 insertions(+), 78 deletions(-) diff --git a/src/app/tabs/runTab/contractDropdown.js b/src/app/tabs/runTab/contractDropdown.js index fa727bbaed..0d5ae4fe3b 100644 --- a/src/app/tabs/runTab/contractDropdown.js +++ b/src/app/tabs/runTab/contractDropdown.js @@ -209,8 +209,8 @@ class ContractDropdownUI { 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) + 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', @@ -220,7 +220,7 @@ class ContractDropdownUI { if (!content.gasPriceStatus) { cancelCb('Given gas price is not correct') } else { - var gasPrice = this.dropdownLogic.toWei(content.querySelector('#gasprice').value, 'gwei') + var gasPrice = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei') continueTxExecution(gasPrice) } }}, { diff --git a/src/app/tabs/runTab/model/blockchain.js b/src/app/tabs/runTab/model/blockchain.js index db5643136b..b29fd80e9e 100644 --- a/src/app/tabs/runTab/model/blockchain.js +++ b/src/app/tabs/runTab/model/blockchain.js @@ -93,6 +93,33 @@ class Blockchain { 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 + } + } module.exports = Blockchain diff --git a/src/app/tabs/runTab/model/dropdownlogic.js b/src/app/tabs/runTab/model/dropdownlogic.js index 573245d223..78497907fa 100644 --- a/src/app/tabs/runTab/model/dropdownlogic.js +++ b/src/app/tabs/runTab/model/dropdownlogic.js @@ -1,10 +1,8 @@ var ethJSUtil = require('ethereumjs-util') var remixLib = require('remix-lib') var txHelper = remixLib.execution.txHelper -var typeConversion = remixLib.execution.typeConversion var CompilerAbstract = require('../../../compiler/compiler-abstract') var EventManager = remixLib.EventManager -var Web3 = require('web3') class DropdownLogic { 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 () { return this.compilersArtefacts['__last'].getData().contracts } diff --git a/src/app/tabs/runTab/model/recorder.js b/src/app/tabs/runTab/model/recorder.js index 73c15a15a7..7e3c48028b 100644 --- a/src/app/tabs/runTab/model/recorder.js +++ b/src/app/tabs/runTab/model/recorder.js @@ -4,9 +4,7 @@ var remixLib = require('remix-lib') var EventManager = remixLib.EventManager var format = remixLib.execution.txFormat var txHelper = remixLib.execution.txHelper -var typeConversion = remixLib.execution.typeConversion var helper = require('../../../../lib/helper.js') -var Web3 = require('web3') /** * Record transaction as long as the user create them. @@ -288,40 +286,6 @@ class Recorder { return address } - 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 - } - runScenario (continueCb, promptCb, alertCb, confirmationCb, logCallBack, cb) { var currentFile = this.config.get('currentFile') this.fileManager.fileProviderOf(currentFile).get(currentFile, (error, json) => { diff --git a/src/app/tabs/runTab/recorder.js b/src/app/tabs/runTab/recorder.js index cbef6f1d71..5c7231b6cc 100644 --- a/src/app/tabs/runTab/recorder.js +++ b/src/app/tabs/runTab/recorder.js @@ -81,8 +81,8 @@ class RecorderUI { if (network.name !== 'Main') { return continueTxExecution(null) } - const amount = this.recorder.fromWei(tx.value, true, 'ether') - const content = confirmDialog(tx, amount, gasEstimation, null, this.recorder.determineGasFees(tx), this.blockchain.determineGasPrice) + 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', @@ -92,7 +92,7 @@ class RecorderUI { if (!content.gasPriceStatus) { cancelCb('Given gas price is not correct') } else { - var gasPrice = this.recorder.toWei(content.querySelector('#gasprice').value, 'gwei') + var gasPrice = this.blockchain.toWei(content.querySelector('#gasprice').value, 'gwei') continueTxExecution(gasPrice) } }}, { From 32e10ac9ccba57a365c6d316e31885de5de40f6d Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 26 Dec 2019 11:47:40 -0500 Subject: [PATCH 03/66] refactor out of the recorder executioncontext and udapp --- src/app/tabs/runTab/model/blockchain.js | 25 +++++++++++ src/app/tabs/runTab/model/recorder.js | 59 +++++++++++-------------- src/app/udapp/run-tab.js | 2 +- 3 files changed, 52 insertions(+), 34 deletions(-) diff --git a/src/app/tabs/runTab/model/blockchain.js b/src/app/tabs/runTab/model/blockchain.js index b29fd80e9e..6e614f6546 100644 --- a/src/app/tabs/runTab/model/blockchain.js +++ b/src/app/tabs/runTab/model/blockchain.js @@ -2,13 +2,30 @@ const remixLib = require('remix-lib') const txFormat = remixLib.execution.txFormat const txExecution = remixLib.execution.txExecution const typeConversion = remixLib.execution.typeConversion +const EventManager = remixLib.EventManager const Web3 = require('web3') class Blockchain { constructor (executionContext, udapp) { + this.event = new EventManager() this.executionContext = executionContext this.udapp = udapp + this.setupEvents() + } + + setupEvents() { + this.executionContext.event.register('contextChanged', () => { + this.event.trigger('contextChanged', []) + }) + + this.udapp.event.register('initiatingTransaction', () => { + this.event.trigger('initiatingTransaction', []) + }) + + this.udapp.event.register('transactionExecuted', () => { + this.event.trigger('transactionExecuted', []) + }) } async deployContract (selectedContract, args, contractMetadata, compilerContracts, callbacks, confirmationCb) { @@ -120,6 +137,14 @@ class Blockchain { return determineGasFeesCb } + getAddressFromTransactionResult(txResult) { + return this.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress + } + + getAccounts (cb) { + return this.udapp.getAccounts(cb) + } + } module.exports = Blockchain diff --git a/src/app/tabs/runTab/model/recorder.js b/src/app/tabs/runTab/model/recorder.js index 7e3c48028b..c6f7eefa95 100644 --- a/src/app/tabs/runTab/model/recorder.js +++ b/src/app/tabs/runTab/model/recorder.js @@ -12,16 +12,15 @@ var helper = require('../../../../lib/helper.js') * */ class Recorder { - constructor (executionContext, udapp, fileManager, config) { + constructor (blockchain, fileManager, config) { var self = this self.event = new EventManager() - self.executionContext = executionContext + self.blockchain = blockchain self.data = { _listen: true, _replay: false, journal: [], _createdContracts: {}, _createdContractsReverse: {}, _usedAccounts: {}, _abis: {}, _contractABIReferences: {}, _linkReferences: {} } - this.udapp = udapp this.fileManager = fileManager this.config = config - this.udapp.event.register('initiatingTransaction', (timestamp, tx, payLoad) => { + this.blockchain.event.register('initiatingTransaction', (timestamp, tx, payLoad) => { if (tx.useCall) return var { from, to, value } = tx @@ -59,7 +58,7 @@ class Recorder { if (thistimestamp) record.parameters[p] = `created{${thistimestamp}}` } - this.udapp.getAccounts((error, accounts) => { + this.blockchain.getAccounts((error, accounts) => { if (error) return console.log(error) record.from = `account{${accounts.indexOf(from)}}` self.data._usedAccounts[record.from] = from @@ -68,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 (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 const stringAddress = this.addressToString(rawAddress) const address = ethutil.toChecksumAddress(stringAddress) @@ -80,7 +79,7 @@ class Recorder { this.data._createdContracts[address] = timestamp 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.trigger('recorderCountChange', [count]) }) @@ -183,7 +182,6 @@ class Recorder { * @param {Object} accounts * @param {Object} options * @param {Object} abis - * @param {Object} udapp * @param {Function} newContractFn * */ @@ -195,8 +193,7 @@ class Recorder { var record = self.resolveAddress(tx.record, accounts, options) var abi = abis[tx.record.abi] if (!abi) { - alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index) - return + return alertCb('cannot find ABI for ' + tx.record.abi + '. Execution stopped at ' + index) } /* Resolve Library */ if (record.linkReferences && Object.keys(record.linkReferences).length) { @@ -220,8 +217,7 @@ class Recorder { } if (!fnABI) { alertCb('cannot resolve abi of ' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index) - cb('cannot resolve abi') - return + return cb('cannot resolve abi') } if (tx.record.parameters) { /* check if we have some params to resolve */ @@ -239,35 +235,32 @@ class Recorder { tx.record.parameters[index] = value }) } catch (e) { - alertCb('cannot resolve input parameters ' + JSON.stringify(tx.record.parameters) + '. Execution stopped at ' + index) - return + return alertCb('cannot resolve input parameters ' + JSON.stringify(tx.record.parameters) + '. Execution stopped at ' + index) } } var data = format.encodeData(fnABI, tx.record.parameters, tx.record.bytecode) if (data.error) { alertCb(data.error + '. Record:' + JSON.stringify(record, null, '\t') + '. Execution stopped at ' + index) - cb(data.error) - return - } else { - logCallBack(`(${index}) ${JSON.stringify(record, null, '\t')}`) - 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 } + return cb(data.error) } - self.udapp.runTx(record, confirmationCb, continueCb, promptCb, + logCallBack(`(${index}) ${JSON.stringify(record, null, '\t')}`) + 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 } + + self.blockchain.runTransaction (record, continueCb, promptCb, confirmationCb, function (err, txResult) { if (err) { console.error(err) - logCallBack(err + '. Execution failed at ' + index) - } else { - const rawAddress = self.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress - if (rawAddress) { - const stringAddress = self.addressToString(rawAddress) - const address = ethutil.toChecksumAddress(stringAddress) - // save back created addresses for the convertion from tokens to real adresses - self.data._createdContracts[address] = tx.timestamp - self.data._createdContractsReverse[tx.timestamp] = address - newContractFn(abi, address, record.contractName) - } + return logCallBack(err + '. Execution failed at ' + index) + } + const rawAddress = self.blockchain.getAddressFromTransactionResult(txResult) + if (rawAddress) { + const stringAddress = self.addressToString(rawAddress) + const address = ethutil.toChecksumAddress(stringAddress) + // save back created addresses for the convertion from tokens to real adresses + self.data._createdContracts[address] = tx.timestamp + self.data._createdContractsReverse[tx.timestamp] = address + newContractFn(abi, address, record.contractName) } cb(err) } diff --git a/src/app/udapp/run-tab.js b/src/app/udapp/run-tab.js index 41124684f6..5e0ea44f12 100644 --- a/src/app/udapp/run-tab.js +++ b/src/app/udapp/run-tab.js @@ -153,7 +153,7 @@ export class RunTab extends LibraryPlugin { renderRecorder (udapp, udappUI, fileManager, config, logCallback) { this.recorderCount = yo`0` - const recorder = new Recorder(this.executionContext, udapp, fileManager, config) + const recorder = new Recorder(this.blockchain, fileManager, config) recorder.event.register('recorderCountChange', (count) => { this.recorderCount.innerText = count }) From 1f304eddda3ed543b13b4575bbded3897ab4c3ed Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 26 Dec 2019 12:04:37 -0500 Subject: [PATCH 04/66] fix linting issues --- src/app/tabs/runTab/model/blockchain.js | 4 ++-- src/app/tabs/runTab/model/recorder.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/tabs/runTab/model/blockchain.js b/src/app/tabs/runTab/model/blockchain.js index 6e614f6546..9bb8ca7ddd 100644 --- a/src/app/tabs/runTab/model/blockchain.js +++ b/src/app/tabs/runTab/model/blockchain.js @@ -14,7 +14,7 @@ class Blockchain { this.setupEvents() } - setupEvents() { + setupEvents () { this.executionContext.event.register('contextChanged', () => { this.event.trigger('contextChanged', []) }) @@ -137,7 +137,7 @@ class Blockchain { return determineGasFeesCb } - getAddressFromTransactionResult(txResult) { + getAddressFromTransactionResult (txResult) { return this.executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress } diff --git a/src/app/tabs/runTab/model/recorder.js b/src/app/tabs/runTab/model/recorder.js index c6f7eefa95..e56cdb5374 100644 --- a/src/app/tabs/runTab/model/recorder.js +++ b/src/app/tabs/runTab/model/recorder.js @@ -247,7 +247,7 @@ class Recorder { 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 } - self.blockchain.runTransaction (record, continueCb, promptCb, confirmationCb, + self.blockchain.runTransaction(record, continueCb, promptCb, confirmationCb, function (err, txResult) { if (err) { console.error(err) From c07d37b0082d548007e1af199aa031f928638535 Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Thu, 26 Dec 2019 12:29:41 -0500 Subject: [PATCH 05/66] add missing config param --- src/app/tabs/runTab/recorder.js | 3 ++- src/app/udapp/run-tab.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/tabs/runTab/recorder.js b/src/app/tabs/runTab/recorder.js index 5c7231b6cc..04e4692fe3 100644 --- a/src/app/tabs/runTab/recorder.js +++ b/src/app/tabs/runTab/recorder.js @@ -10,10 +10,11 @@ var confirmDialog = require('../../ui/confirmDialog') class RecorderUI { - constructor (blockchain, recorder, logCallBack) { + constructor (blockchain, recorder, logCallBack, config) { this.blockchain = blockchain this.recorder = recorder this.logCallBack = logCallBack + this.config = config this.event = new EventManager() } diff --git a/src/app/udapp/run-tab.js b/src/app/udapp/run-tab.js index 5e0ea44f12..76e940491a 100644 --- a/src/app/udapp/run-tab.js +++ b/src/app/udapp/run-tab.js @@ -159,7 +159,7 @@ export class RunTab extends LibraryPlugin { }) this.event.register('clearInstance', recorder.clearAll.bind(recorder)) - this.recorderInterface = new RecorderUI(this.blockchain, recorder, logCallback) + this.recorderInterface = new RecorderUI(this.blockchain, recorder, logCallback, config) this.recorderInterface.event.register('newScenario', (abi, address, contractName) => { var noInstancesText = this.noInstancesText From 7fdbf7c8a65ea189f2559b09a869223b5723a5ed Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 27 Dec 2019 14:26:08 -0500 Subject: [PATCH 06/66] add missing params to udapp events --- src/app/tabs/runTab/model/blockchain.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/tabs/runTab/model/blockchain.js b/src/app/tabs/runTab/model/blockchain.js index 9bb8ca7ddd..51e2735a16 100644 --- a/src/app/tabs/runTab/model/blockchain.js +++ b/src/app/tabs/runTab/model/blockchain.js @@ -19,12 +19,12 @@ class Blockchain { this.event.trigger('contextChanged', []) }) - this.udapp.event.register('initiatingTransaction', () => { - this.event.trigger('initiatingTransaction', []) + this.udapp.event.register('initiatingTransaction', (timestamp, tx, payLoad) => { + this.event.trigger('initiatingTransaction', [timestamp, tx, payLoad]) }) - this.udapp.event.register('transactionExecuted', () => { - this.event.trigger('transactionExecuted', []) + this.udapp.event.register('transactionExecuted', (error, from, to, data, call, txResult, timestamp) => { + this.event.trigger('transactionExecuted', [error, from, to, data, call, txResult, timestamp]) }) } From d0e80226d3b81f2f6d42a26bdc3fcd20fe2ecede Mon Sep 17 00:00:00 2001 From: Iuri Matias Date: Fri, 27 Dec 2019 14:56:18 -0500 Subject: [PATCH 07/66] move blockchain specific logic from settings to blockchain model --- src/app/tabs/runTab/model/blockchain.js | 99 ++++++++++++++++++- src/app/tabs/runTab/model/settings.js | 125 ++++-------------------- src/app/tabs/runTab/settings.js | 36 +++---- src/app/udapp/run-tab.js | 6 +- 4 files changed, 137 insertions(+), 129 deletions(-) diff --git a/src/app/tabs/runTab/model/blockchain.js b/src/app/tabs/runTab/model/blockchain.js index 51e2735a16..1043856428 100644 --- a/src/app/tabs/runTab/model/blockchain.js +++ b/src/app/tabs/runTab/model/blockchain.js @@ -3,6 +3,8 @@ const txFormat = remixLib.execution.txFormat const txExecution = remixLib.execution.txExecution const typeConversion = remixLib.execution.typeConversion const EventManager = remixLib.EventManager +const ethJSUtil = require('ethereumjs-util') +const Personal = require('web3-eth-personal') const Web3 = require('web3') class Blockchain { @@ -11,12 +13,22 @@ class Blockchain { this.event = new EventManager() this.executionContext = executionContext this.udapp = udapp + + this.networkcallid = 0 this.setupEvents() } setupEvents () { - this.executionContext.event.register('contextChanged', () => { - this.event.trigger('contextChanged', []) + 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) => { @@ -141,10 +153,93 @@ class Blockchain { 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) + } + + 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) + } + } + } module.exports = Blockchain diff --git a/src/app/tabs/runTab/model/settings.js b/src/app/tabs/runTab/model/settings.js index e126e583f0..8965312d9c 100644 --- a/src/app/tabs/runTab/model/settings.js +++ b/src/app/tabs/runTab/model/settings.js @@ -1,122 +1,35 @@ -var ethJSUtil = require('ethereumjs-util') -var Personal = require('web3-eth-personal') +// 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 Web3 = require('web3') +// const addTooltip = require('../../../ui/tooltip') var EventManager = remixLib.EventManager class Settings { - constructor (executionContext, udapp) { + constructor (blockchain, executionContext, udapp) { + this.blockchain = blockchain 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.blockchain.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.blockchain.event.register('contextChanged', (context, silent) => { + // this.event.trigger('contextChanged', [context, silent]) + // }) - this.executionContext.event.register('addProvider', (network) => { - this.event.trigger('addProvider', [network]) - }) + // this.blockchain.event.register('addProvider', (network) => { + // this.event.trigger('addProvider', [network]) + // }) - this.executionContext.event.register('removeProvider', (name) => { - this.event.trigger('removeProvider', [name]) - }) + // this.blockchain.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) - } + // this.networkcallid = 0 } } diff --git a/src/app/tabs/runTab/settings.js b/src/app/tabs/runTab/settings.js index 76032c4650..09375020a3 100644 --- a/src/app/tabs/runTab/settings.js +++ b/src/app/tabs/runTab/settings.js @@ -11,12 +11,12 @@ const globalRegistry = require('../../../global/registry') class SettingsUI { - constructor (settings, networkModule) { - this.settings = settings + constructor (blockchain, networkModule) { + this.blockchain = blockchain this.event = new EventManager() 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 (!lookupOnly) this.el.querySelector('#value').value = '0' this.updateAccountBalances() @@ -44,7 +44,7 @@ class SettingsUI { if (!this.el) return var accounts = $(this.el.querySelector('#txorigin')).children('option') accounts.each((index, account) => { - this.settings.getAccountBalanceForAddress(account.value, (err, balance) => { + this.blockchain.getAccountBalanceForAddress(account.value, (err, balance) => { if (err) return account.innerText = helper.shortenAddress(account.value, balance) }) @@ -139,7 +139,7 @@ class SettingsUI { var selectExEnv = environmentEl.querySelector('#selectExEnvOptions') this.setDropdown(selectExEnv) - this.settings.event.register('contextChanged', (context, silent) => { + this.blockchain.event.register('contextChanged', (context, silent) => { this.setFinalContext() }) @@ -156,7 +156,7 @@ class SettingsUI { setDropdown (selectExEnv) { this.selectExEnv = selectExEnv - this.settings.event.register('addProvider', (network) => { + this.blockchain.event.register('addProvider', (network) => { selectExEnv.appendChild(yo`