move confirm dialog requirement out of universal-dapp logic

pull/3094/head
Iuri Matias 6 years ago committed by yann300
parent 416f34fde0
commit ea3e37996f
  1. 154
      src/app/tabs/run-tab.js
  2. 89
      src/recorder.js
  3. 72
      src/universal-dapp-ui.js
  4. 77
      src/universal-dapp.js

@ -7,6 +7,7 @@ var csjs = require('csjs-inject')
var txExecution = remixLib.execution.txExecution var txExecution = remixLib.execution.txExecution
var txFormat = remixLib.execution.txFormat var txFormat = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
var EventManager = require('../../lib/events') var EventManager = require('../../lib/events')
var globlalRegistry = require('../../global/registry') var globlalRegistry = require('../../global/registry')
var helper = require('../../lib/helper.js') var helper = require('../../lib/helper.js')
@ -24,6 +25,8 @@ var modalDialog = require('../ui/modaldialog')
var CompilerAbstract = require('../compiler/compiler-abstract') var CompilerAbstract = require('../compiler/compiler-abstract')
var tootip = require('../ui/tooltip') var tootip = require('../ui/tooltip')
var confirmDialog = require('../execution/confirmDialog')
function runTab (opts, localRegistry) { function runTab (opts, localRegistry) {
/* ------------------------- /* -------------------------
VARIABLES VARIABLES
@ -394,28 +397,85 @@ function contractDropdown (events, self) {
data.linkReferences = selectedContract.contract.object.evm.bytecode.linkReferences data.linkReferences = selectedContract.contract.object.evm.bytecode.linkReferences
data.contractABI = selectedContract.contract.object.abi data.contractABI = selectedContract.contract.object.abi
} }
self._deps.udapp.createContract(data, (error, txResult) => { self._deps.udapp.createContract(data,
if (!error) {
var isVM = executionContext.isVM() (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (isVM) { if (network.name !== 'Main') {
var vmError = txExecution.checkVMError(txResult) return continueTxExecution(null)
if (vmError.error) { }
self._deps.logCallback(vmError.message) var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self,
(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: () => {
self._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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
},
(error, txResult) => {
if (!error) {
var isVM = executionContext.isVM()
if (isVM) {
var vmError = txExecution.checkVMError(txResult)
if (vmError.error) {
self._deps.logCallback(vmError.message)
return
}
}
if (txResult.result.status && txResult.result.status === '0x0') {
self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`)
return return
} }
var noInstancesText = self._view.noInstancesText
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) }
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value))
} else {
self._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`)
} }
if (txResult.result.status && txResult.result.status === '0x0') {
self._deps.logCallback(`creation of ${selectedContract.name} errored: transaction execution failed`)
return
}
var noInstancesText = self._view.noInstancesText
if (noInstancesText.parentNode) { noInstancesText.parentNode.removeChild(noInstancesText) }
var address = isVM ? txResult.result.createdAddress : txResult.result.contractAddress
instanceContainer.appendChild(self._deps.udappUI.renderInstance(selectedContract.contract.object, address, selectContractNames.value))
} else {
self._deps.logCallback(`creation of ${selectedContract.name} errored: ${error}`)
} }
}) )
} }
// DEPLOY INSTANCE // DEPLOY INSTANCE
@ -439,7 +499,63 @@ function contractDropdown (events, self) {
self._deps.logCallback(msg) self._deps.logCallback(msg)
}, (data, runTxCallback) => { }, (data, runTxCallback) => {
// called for libraries deployment // called for libraries deployment
self._deps.udapp.runTx(data, runTxCallback) self._deps.udapp.runTx(data,
(network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self,
(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: () => {
self._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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
},
runTxCallback)
}) })
} else { } else {
if (Object.keys(selectedContract.contract.object.evm.bytecode.linkReferences).length) self._deps.logCallback(`linking ${JSON.stringify(selectedContract.contract.object.evm.bytecode.linkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`) if (Object.keys(selectedContract.contract.object.evm.bytecode.linkReferences).length) self._deps.logCallback(`linking ${JSON.stringify(selectedContract.contract.object.evm.bytecode.linkReferences, null, '\t')} using ${JSON.stringify(contractMetadata.linkReferences, null, '\t')}`)

@ -4,9 +4,13 @@ var ethutil = require('ethereumjs-util')
var executionContext = require('./execution-context') var executionContext = require('./execution-context')
var format = remixLib.execution.txFormat var format = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper var txHelper = remixLib.execution.txHelper
var typeConversion = remixLib.execution.typeConversion
var async = require('async') var async = require('async')
var modal = require('./app/ui/modal-dialog-custom') var modal = require('./app/ui/modal-dialog-custom')
var modalDialog = require('./app/ui/modaldialog')
var confirmDialog = require('./app/execution/confirmDialog')
/** /**
* Record transaction as long as the user create them. * Record transaction as long as the user create them.
* *
@ -238,22 +242,79 @@ class Recorder {
self.logCallBack(`(${index}) data: ${data.data}`) self.logCallBack(`(${index}) data: ${data.data}`)
record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName } record.data = { dataHex: data.data, funArgs: tx.record.parameters, funAbi: fnABI, contractBytecode: tx.record.bytecode, contractName: tx.record.contractName }
} }
udapp.runTx(record, function (err, txResult) { udapp.runTx(record,
if (err) {
console.error(err) (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
self.logCallBack(err + '. Execution failed at ' + index) if (network.name !== 'Main') {
} else { return continueTxExecution(null)
var address = executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress }
if (address) { var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
address = addressToString(address) var content = confirmDialog(tx, amount, gasEstimation, self,
// save back created addresses for the convertion from tokens to real adresses (gasPrice, cb) => {
self.data._createdContracts[address] = tx.timestamp let txFeeText, priceStatus
self.data._createdContractsReverse[tx.timestamp] = address // TODO: this try catch feels like an anti pattern, can/should be
newContractFn(abi, address, record.contractName) // 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: () => {
udapp._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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
},
function (err, txResult) {
if (err) {
console.error(err)
self.logCallBack(err + '. Execution failed at ' + index)
} else {
var address = executionContext.isVM() ? txResult.result.createdAddress : txResult.result.contractAddress
if (address) {
address = addressToString(address)
// 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)
} }
cb(err) )
})
}, () => { self.setListen(true); self.clearAll() }) }, () => { self.setListen(true); self.clearAll() })
} }
} }

@ -7,6 +7,13 @@ var helper = require('./lib/helper')
var copyToClipboard = require('./app/ui/copy-to-clipboard') var copyToClipboard = require('./app/ui/copy-to-clipboard')
var css = require('./universal-dapp-styles') var css = require('./universal-dapp-styles')
var MultiParamManager = require('./multiParamManager') var MultiParamManager = require('./multiParamManager')
var remixLib = require('remix-lib')
var typeConversion = remixLib.execution.typeConversion
var executionContext = require('./execution-context')
var modalDialog = require('./app/ui/modaldialog')
var confirmDialog = require('./app/execution/confirmDialog')
function UniversalDAppUI (udapp, opts = {}) { function UniversalDAppUI (udapp, opts = {}) {
this.udapp = udapp this.udapp = udapp
@ -90,10 +97,67 @@ UniversalDAppUI.prototype.getCallButton = function (args) {
var outputOverride = yo`<div class=${css.value}></div>` // show return value var outputOverride = yo`<div class=${css.value}></div>` // show return value
function clickButton (valArr, inputsValues) { function clickButton (valArr, inputsValues) {
self.udapp.call(true, args, inputsValues, lookupOnly, (decoded) => { self.udapp.call(true, args, inputsValues, lookupOnly,
outputOverride.innerHTML = ''
outputOverride.appendChild(decoded) (network, tx, gasEstimation, continueTxExecution, cancelCb) => {
}) if (network.name !== 'Main') {
return continueTxExecution(null)
}
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self,
(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: () => {
self._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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
},
(decoded) => {
outputOverride.innerHTML = ''
outputOverride.appendChild(decoded)
}
)
} }
var multiParamManager = new MultiParamManager(lookupOnly, args.funABI, (valArray, inputsValues, domEl) => { var multiParamManager = new MultiParamManager(lookupOnly, args.funABI, (valArray, inputsValues, domEl) => {

@ -13,13 +13,10 @@ var txExecution = remixLib.execution.txExecution
var txFormat = remixLib.execution.txFormat var txFormat = remixLib.execution.txFormat
var txHelper = remixLib.execution.txHelper var txHelper = remixLib.execution.txHelper
var executionContext = require('./execution-context') var executionContext = require('./execution-context')
var modalCustom = require('./app/ui/modal-dialog-custom')
var globalRegistry = require('./global/registry') var globalRegistry = require('./global/registry')
var modalCustom = require('./app/ui/modal-dialog-custom')
var modalDialog = require('./app/ui/modaldialog') var modalDialog = require('./app/ui/modaldialog')
var typeConversion = remixLib.execution.typeConversion
var confirmDialog = require('./app/execution/confirmDialog')
var TreeView = require('./app/ui/TreeView') var TreeView = require('./app/ui/TreeView')
function decodeResponseToTreeView (response, fnabi) { function decodeResponseToTreeView (response, fnabi) {
@ -205,7 +202,7 @@ UniversalDApp.prototype.pendingTransactionsCount = function () {
return Object.keys(this.txRunner.pendingTxs).length return Object.keys(this.txRunner.pendingTxs).length
} }
UniversalDApp.prototype.call = function (isUserAction, args, value, lookupOnly, outputCb) { UniversalDApp.prototype.call = function (isUserAction, args, value, lookupOnly, confirmationCb, outputCb) {
const self = this const self = this
var logMsg var logMsg
if (isUserAction) { if (isUserAction) {
@ -225,7 +222,7 @@ UniversalDApp.prototype.call = function (isUserAction, args, value, lookupOnly,
} }
} }
if (args.funABI.type === 'fallback') data.dataHex = value if (args.funABI.type === 'fallback') data.dataHex = value
self.callFunction(args.address, data, args.funABI, (error, txResult) => { self.callFunction(args.address, data, args.funABI, confirmationCb, (error, txResult) => {
if (!error) { if (!error) {
var isVM = executionContext.isVM() var isVM = executionContext.isVM()
if (isVM) { if (isVM) {
@ -250,7 +247,7 @@ UniversalDApp.prototype.call = function (isUserAction, args, value, lookupOnly,
self._deps.logCallback(msg) self._deps.logCallback(msg)
}, (data, runTxCallback) => { }, (data, runTxCallback) => {
// called for libraries deployment // called for libraries deployment
self.runTx(data, runTxCallback) self.runTx(data, confirmationCb, runTxCallback)
}) })
} }
@ -260,8 +257,8 @@ UniversalDApp.prototype.call = function (isUserAction, args, value, lookupOnly,
* @param {String} data - data to send with the transaction ( return of txFormat.buildData(...) ). * @param {String} data - data to send with the transaction ( return of txFormat.buildData(...) ).
* @param {Function} callback - callback. * @param {Function} callback - callback.
*/ */
UniversalDApp.prototype.createContract = function (data, callback) { UniversalDApp.prototype.createContract = function (data, confirmationCb, callback) {
this.runTx({data: data, useCall: false}, (error, txResult) => { this.runTx({data: data, useCall: false}, confirmationCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case) // see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
callback(error, txResult) callback(error, txResult)
}) })
@ -275,8 +272,8 @@ UniversalDApp.prototype.createContract = function (data, callback) {
* @param {Object} funAbi - abi definition of the function to call. * @param {Object} funAbi - abi definition of the function to call.
* @param {Function} callback - callback. * @param {Function} callback - callback.
*/ */
UniversalDApp.prototype.callFunction = function (to, data, funAbi, callback) { UniversalDApp.prototype.callFunction = function (to, data, funAbi, confirmationCb, callback) {
this.runTx({to: to, data: data, useCall: funAbi.constant}, (error, txResult) => { this.runTx({to: to, data: data, useCall: funAbi.constant}, confirmationCb, (error, txResult) => {
// see universaldapp.js line 660 => 700 to check possible values of txResult (error case) // see universaldapp.js line 660 => 700 to check possible values of txResult (error case)
callback(error, txResult) callback(error, txResult)
}) })
@ -318,7 +315,7 @@ UniversalDApp.prototype.silentRunTx = function (tx, cb) {
cb) cb)
} }
UniversalDApp.prototype.runTx = function (args, cb) { UniversalDApp.prototype.runTx = function (args, confirmationCb, cb) {
const self = this const self = this
async.waterfall([ async.waterfall([
function getGasLimit (next) { function getGasLimit (next) {
@ -364,61 +361,7 @@ UniversalDApp.prototype.runTx = function (args, cb) {
var timestamp = Date.now() var timestamp = Date.now()
self.event.trigger('initiatingTransaction', [timestamp, tx, payLoad]) self.event.trigger('initiatingTransaction', [timestamp, tx, payLoad])
self.txRunner.rawRun(tx, self.txRunner.rawRun(tx, confirmationCb,
(network, tx, gasEstimation, continueTxExecution, cancelCb) => {
if (network.name !== 'Main') {
return continueTxExecution(null)
}
var amount = executionContext.web3().fromWei(typeConversion.toInt(tx.value), 'ether')
var content = confirmDialog(tx, amount, gasEstimation, self,
(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: () => {
self._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 = executionContext.web3().toWei(content.querySelector('#gasprice').value, 'gwei')
continueTxExecution(gasPrice)
}
}}, {
label: 'Cancel',
fn: () => {
return cancelCb('Transaction canceled by user.')
}
})
},
(error, continueTxExecution, cancelCb) => { (error, continueTxExecution, cancelCb) => {
if (error) { if (error) {
var msg = typeof error !== 'string' ? error.message : error var msg = typeof error !== 'string' ? error.message : error

Loading…
Cancel
Save