diff --git a/src/app.js b/src/app.js index b0841855a9..40fd887493 100644 --- a/src/app.js +++ b/src/app.js @@ -251,6 +251,9 @@ function run () { config: self._api.config, detectNetwork: (cb) => { executionContext.detectNetwork(cb) + }, + personalMode: () => { + return self._api.config.get('settings/personal-mode') } }, opt: { removable: false, removable_instances: true } diff --git a/src/app/execution/txRunner.js b/src/app/execution/txRunner.js index 3a3ac11429..3f4863869f 100644 --- a/src/app/execution/txRunner.js +++ b/src/app/execution/txRunner.js @@ -11,6 +11,7 @@ var csjs = require('csjs-inject') var remixLib = require('remix-lib') var styleGuide = remixLib.ui.styleGuide var styles = styleGuide() +var modal = require('../ui/modal-dialog-custom') var css = csjs` .txInfoBox { @@ -25,12 +26,11 @@ var css = csjs` } ` -function TxRunner (vmaccounts, opts) { - this.personalMode = opts.personalMode + +function TxRunner (vmaccounts, api) { + this._api = api this.blockNumber = 0 this.runAsync = true - this.config = opts.config - this.detectNetwork = opts.detectNetwork if (executionContext.isVM()) { this.blockNumber = 1150000 // The VM is running in Homestead mode, which started at this block. this.runAsync = false // We have to run like this cause the VM Event Manager does not support running multiple txs at the same time. @@ -45,23 +45,21 @@ TxRunner.prototype.rawRun = function (args, cb) { } TxRunner.prototype.execute = function (args, callback) { + var self = this function execute (gasPrice) { if (gasPrice) tx.gasPrice = executionContext.web3().toHex(gasPrice) - var sendTransaction = self.personalMode ? executionContext.web3().personal.sendTransaction : executionContext.web3().eth.sendTransaction - try { - sendTransaction(tx, function (err, resp) { - if (err) { - return callback(err, resp) - } - - tryTillResponse(resp, callback) + if (self._api.personalMode()) { + modal.promptPassphrase(null, 'Personal mode is enabled. Please provide passphrase of account ' + tx.from, '', (value) => { + sendTransaction(executionContext.web3().personal.sendTransaction, tx, value, callback) + }, () => { + return callback('Canceled by user.') }) - } catch (e) { - return callback(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `) + } else { + sendTransaction(executionContext.web3().eth.sendTransaction, tx, null, callback) } } - var self = this + var from = args.from var to = args.to var data = args.data @@ -206,6 +204,21 @@ function tryTillResponse (txhash, done) { }) } +function sendTransaction (sendTx, tx, pass, callback) { + var cb = function (err, resp) { + if (err) { + return callback(err, resp) + } + tryTillResponse(resp, callback) + } + var args = pass !== null ? [tx, pass, cb] : [tx, cb] + try { + sendTx.apply({}, args) + } catch (e) { + return callback(`Send transaction failed: ${e.message} . if you use an injected provider, please check it is properly unlocked. `) + } +} + function run (self, tx, stamp, callback) { if (!self.runAsync && Object.keys(self.pendingTxs).length) { self.queusTxs.push({ tx, stamp, callback }) diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index 4553d8fe53..b3ddcbd4c2 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -90,6 +90,7 @@ function SettingsTab (container, appAPI, appEvents, opts) { var queryParams = new QueryParams() var optionVM = yo`` + var personal = yo`` var el = yo`
@@ -99,6 +100,37 @@ function SettingsTab (container, appAPI, appEvents, opts) {
+
+ +
+
+
+ Text Wrap +
+
+
${optionVM}
+ Always use VM at Load +
+
+
+ Enable Optimization +
+
+
${personal}>
+ Enable Personal Mode (transaction sent over Web3 will use the web3.personal API - be sure the endpoint is opened before enabling it -). +
+ This mode allows to provide the passphrase in the Remix interface without having to unlock the account.
+ Although this is very convenient, you should completely trust the backend you are connected to (Geth, Parity, ...).
+ It is not recommended (and also most likely not relevant) to use this mode with an injected provider (Mist, Metamask, ...) or with JavaScript VM
+ Remix never persist any passphrase. +
+
+
+

Themes ( Selecting a theme will trigger a page reload )

+
+ + +
General settings
@@ -166,6 +198,11 @@ function SettingsTab (container, appAPI, appEvents, opts) { appAPI.config.set('settings/always-use-vm', !appAPI.config.get('settings/always-use-vm')) }) + personal.checked = appAPI.config.get('settings/personal-mode') || false + personal.addEventListener('change', event => { + appAPI.config.set('settings/personal-mode', !appAPI.config.get('settings/personal-mode')) + }) + var optimize = el.querySelector('#optimize') if ((queryParams.get().optimize === 'true')) { optimize.setAttribute('checked', true) diff --git a/src/app/ui/modal-dialog-custom.js b/src/app/ui/modal-dialog-custom.js index 6e029696d0..f8658b2418 100644 --- a/src/app/ui/modal-dialog-custom.js +++ b/src/app/ui/modal-dialog-custom.js @@ -12,16 +12,10 @@ module.exports = { modal('', yo`
${text}
`, null, { label: null }) }, prompt: function (title, text, inputValue, ok, cancel) { - if (!inputValue) inputValue = '' - var input = yo`` - modal(title, yo`
${text}
${input}
`, - { - fn: () => { if (typeof ok === 'function') ok(document.getElementById('prompt_text').value) } - }, - { - fn: () => { if (typeof cancel === 'function') cancel() } - } - ) + prompt(title, text, false, inputValue, ok, cancel) + }, + promptPassphrase: function (title, text, inputValue, ok, cancel) { + prompt(title, text, true, inputValue, ok, cancel) }, promptMulti: function ({ title, text, inputValue }, ok, cancel) { if (!inputValue) inputValue = '' @@ -46,3 +40,17 @@ module.exports = { ) } } + +function prompt (title, text, hidden, inputValue, ok, cancel) { + if (!inputValue) inputValue = '' + var type = hidden ? 'password' : 'text' + var input = yo`` + modal(title, yo`
${text}
${input}
`, + { + fn: () => { if (typeof ok === 'function') ok(document.getElementById('prompt_text').value) } + }, + { + fn: () => { if (typeof cancel === 'function') cancel() } + } + ) +} diff --git a/src/universal-dapp.js b/src/universal-dapp.js index 430cebc347..fc669be700 100644 --- a/src/universal-dapp.js +++ b/src/universal-dapp.js @@ -159,17 +159,12 @@ function UniversalDApp (opts = {}) { self.removable = opts.opt.removable self.removable_instances = opts.opt.removable_instances self.el = yo`
` - self.personalMode = opts.opt.personalMode || false self.contracts self.transactionContextAPI executionContext.event.register('contextChanged', this, function (context) { self.reset(self.contracts) }) - self.txRunner = new TxRunner({}, { - personalMode: this.personalMode, - config: self._api.config, - detectNetwork: self._api.detectNetwork - }) + self.txRunner = new TxRunner({}, opts.api) } UniversalDApp.prototype.reset = function (contracts, transactionContextAPI) { @@ -187,16 +182,12 @@ UniversalDApp.prototype.reset = function (contracts, transactionContextAPI) { this._addAccount('71975fbf7fe448e004ac7ae54cad0a383c3906055a65468714156a07385e96ce', '0x56BC75E2D63100000') executionContext.vm().stateManager.cache.flush(function () {}) } - this.txRunner = new TxRunner(this.accounts, { - personalMode: this.personalMode, - config: this._api.config, - detectNetwork: this._api.detectNetwork - }) + this.txRunner = new TxRunner(this.accounts, this._api) } UniversalDApp.prototype.newAccount = function (password, cb) { if (!executionContext.isVM()) { - if (!this.personalMode) { + if (!this._api.personalMode()) { return cb('Not running in personal mode') } executionContext.web3().personal.newAccount(password, cb) @@ -233,7 +224,7 @@ UniversalDApp.prototype.getAccounts = function (cb) { if (!executionContext.isVM()) { // Weirdness of web3: listAccounts() is sync, `getListAccounts()` is async // See: https://github.com/ethereum/web3.js/issues/442 - if (self.personalMode) { + if (this._api.personalMode()) { executionContext.web3().personal.getListAccounts(cb) } else { executionContext.web3().eth.getAccounts(cb)