diff --git a/src/app/tabs/runTab/contractDropdown.js b/src/app/tabs/runTab/contractDropdown.js index d7eb237453..1b25a2fc92 100644 --- a/src/app/tabs/runTab/contractDropdown.js +++ b/src/app/tabs/runTab/contractDropdown.js @@ -2,7 +2,6 @@ var yo = require('yo-yo') var css = require('../styles/run-tab-styles') var modalDialogCustom = require('../../ui/modal-dialog-custom') var remixLib = require('remix-lib') -var txExecution = remixLib.execution.txExecution var txFormat = remixLib.execution.txFormat var EventManager = remixLib.EventManager var confirmDialog = require('../../execution/confirmDialog') @@ -111,114 +110,49 @@ class ContractDropdownUI { return this.dropdownLogic.getSelectedContract(contractName, compilerAtributeName) } + // =============== + // TODO: move this to DropdownLogic + // =============== createInstanceCallback (selectedContract, data) { this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} pending...`) - if (data) { - data.contractName = selectedContract.name - data.linkReferences = selectedContract.bytecodeLinkReferences - data.contractABI = selectedContract.abi - } - this.parentSelf._deps.udapp.createContract(data, - (network, tx, gasEstimation, continueTxExecution, cancelCb) => { - if (network.name !== 'Main') { - return continueTxExecution(null) - } - var amount = this.dropdownLogic.fromWei(tx.value, true) - var content = confirmDialog(tx, amount, gasEstimation, this.parentSelf, - (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.dropdownLogic.calculateFee(tx.gas, gasPrice, 'gwei') - txFeeText = ' ' + this.dropdownLogic.fromWei(fee) + ' Ether' - priceStatus = true - } catch (e) { - txFeeText = ' Please fix this issue before sending any transaction. ' + e.message - priceStatus = false - } - cb(txFeeText, priceStatus) - }, - (cb) => { - this.dropdownLogic.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.dropdownLogic.fromWei(gasPrice, false, 'gwei') - cb(null, gasPriceValue) - } catch (e) { - cb(warnMessage + e.message, null, false) - } - }) - } - ) - modalDialog('Confirm transaction', content, - { label: 'Confirm', + var continueCb = (error, continueTxExecution, cancelCb) => { + if (error) { + var msg = typeof error !== 'string' ? error.message : error + modalDialog('Gas estimation failed', yo`
Gas estimation errored with the following message (see below). + The transaction execution will likely fail. Do you want to force sending?
+ ${msg} +
`, + { + label: 'Send Transaction', fn: () => { - this.parentSelf._deps.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) - } + continueTxExecution() }}, { - label: 'Cancel', + label: 'Cancel Transaction', fn: () => { - return cancelCb('Transaction canceled by user.') + cancelCb() } }) - }, - (error, continueTxExecution, cancelCb) => { - if (error) { - var msg = typeof error !== 'string' ? error.message : error - modalDialog('Gas estimation failed', yo`
Gas estimation errored with the following message (see below). - The transaction execution will likely fail. Do you want to force sending?
- ${msg} -
`, - { - label: 'Send Transaction', - fn: () => { - continueTxExecution() - }}, { - label: 'Cancel Transaction', - fn: () => { - cancelCb() - } - }) - } else { - continueTxExecution() - } - }, - function (okCb, cancelCb) { - modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) - }, - (error, txResult) => { - if (error) { - return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`) - } - var isVM = this.dropdownLogic.isVM() - if (isVM) { - var vmError = txExecution.checkVMError(txResult) - if (vmError.error) { - return this.parentSelf._deps.logCallback(vmError.message) - } - } - if (txResult.result.status && txResult.result.status === '0x0') { - return this.parentSelf._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`) - } - this.event.trigger('clearInstance') - var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress - this.event.trigger('newContractInstanceAdded', [selectedContract, address, this.selectContractNames.value]) + } else { + continueTxExecution() } - ) + } + + var promptCb = function (okCb, cancelCb) { + modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) + } + + this.dropdownLogic.createContract(selectedContract, data, continueCb, promptCb, modalDialog, confirmDialog, (error, contractObject, address) => { + this.event.trigger('clearInstance') + + if (error) { + return this.parentSelf._deps.logCallback(error) + } + + this.event.trigger('newContractInstanceAdded', [contractObject, address, this.selectContractNames.value]) + }) } - // DEPLOY INSTANCE createInstance (args, compiler) { var selectedContract = this.getSelectedContract() @@ -226,6 +160,9 @@ class ContractDropdownUI { 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.') } + // =============== + // TODO: move this to DropdownLogic + // =============== var forceSend = () => { var constructor = selectedContract.getConstructorInterface() this.parentSelf._deps.filePanel.compilerMetadata().deployMetadataOf(selectedContract.name, (error, contractMetadata) => { @@ -237,65 +174,11 @@ class ContractDropdownUI { }, (msg) => { this.parentSelf._deps.logCallback(msg) }, (data, runTxCallback) => { + var promptCb = (okCb, cancelCb) => { + modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) + } // called for libraries deployment - this.parentSelf._deps.udapp.runTx(data, - (network, tx, gasEstimation, continueTxExecution, cancelCb) => { - if (network.name !== 'Main') { - return continueTxExecution(null) - } - var amount = this.dropdownLogic.fromWei(tx.value, true, 'ether') - var content = confirmDialog(tx, amount, gasEstimation, this.parentSelf, - (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.dropdownLogic.calculateFee(tx.gas, gasPrice) - txFeeText = ' ' + this.dropdownLogic.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.dropdownLogic.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.dropdownLogic.fromWei(gasPrice, false, 'gwei') - cb(null, gasPriceValue) - } catch (e) { - cb(warnMessage + e.message, null, false) - } - }) - } - ) - modalDialog('Confirm transaction', content, - { label: 'Confirm', - fn: () => { - this.parentSelf._deps.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.') - } - }) - }, - function (okCb, cancelCb) { - modalDialogCustom.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account', '', okCb, cancelCb) - }, - runTxCallback) + this.dropdownLogic.runTransaction(data, promptCb, modalDialog, confirmDialog, runTxCallback) }) } else { if (Object.keys(selectedContract.bytecodeLinkReferences).length) this.parentSelf._deps.logCallback(`linking ${JSON.stringify(selectedContract.bytecodeLinkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`) diff --git a/src/app/tabs/runTab/model/dropdownlogic.js b/src/app/tabs/runTab/model/dropdownlogic.js index de525fb40f..cbd3f33bce 100644 --- a/src/app/tabs/runTab/model/dropdownlogic.js +++ b/src/app/tabs/runTab/model/dropdownlogic.js @@ -3,6 +3,7 @@ var remixLib = require('remix-lib') var txHelper = remixLib.execution.txHelper 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 @@ -119,6 +120,150 @@ class DropdownLogic { return executionContext.isVM() } + // TODO: check if selectedContract and data can be joined + createContract (selectedContract, data, continueCb, promptCb, confirmDialog, modalDialog, 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) + } + var amount = executionContext.web3().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 = executionContext.web3().toBigNumber(tx.gas).mul(executionContext.web3().toBigNumber(executionContext.web3().toWei(gasPrice.toString(10), 'gwei'))) + txFeeText = ' ' + executionContext.web3().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 = executionContext.web3().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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei') + continueTxExecution(gasPrice) + } + }}, { + label: 'Cancel', + fn: () => { + return cancelCb('Transaction canceled by user.') + } + }) + } + + this.parentSelf._deps.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, 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, this.parentSelf, + (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.parentSelf._deps.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.parentSelf._deps.udapp.runTx(data, confirmationCb, promptCb, finalCb) + } + } module.exports = DropdownLogic