From 60f904bd46d7cd79528e43c8ea95f5f0adee29cc Mon Sep 17 00:00:00 2001 From: yann300 Date: Wed, 17 Jan 2018 15:05:13 +0100 Subject: [PATCH 1/6] make use of personal mode --- src/app.js | 3 +++ src/app/execution/txRunner.js | 43 ++++++++++++++++++++----------- src/app/tabs/settings-tab.js | 37 ++++++++++++++++++++++++++ src/app/ui/modal-dialog-custom.js | 28 +++++++++++++------- src/universal-dapp.js | 17 +++--------- 5 files changed, 90 insertions(+), 38 deletions(-) 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) From f6a3efc7401416638f941799646fb45621e514f3 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 22 Jan 2018 11:34:30 +0100 Subject: [PATCH 2/6] account creation for personla mode and VM mode --- src/app.js | 3 +++ src/app/execution/txRunner.js | 7 +++--- src/app/tabs/run-tab.js | 15 +++++++++++ src/app/tabs/settings-tab.js | 41 ++++++++----------------------- src/app/ui/modal-dialog-custom.js | 27 ++++++++++++++++++++ src/universal-dapp.js | 13 +++++++--- 6 files changed, 68 insertions(+), 38 deletions(-) diff --git a/src/app.js b/src/app.js index 40fd887493..ff9c8c175e 100644 --- a/src/app.js +++ b/src/app.js @@ -622,6 +622,9 @@ function run () { }, getCompilationResult: () => { return compiler.lastCompilationResult + }, + newAccount: (pass, cb) => { + udapp.newAccount(pass, cb) } } var rhpEvents = { diff --git a/src/app/execution/txRunner.js b/src/app/execution/txRunner.js index 3f4863869f..0d040fae8b 100644 --- a/src/app/execution/txRunner.js +++ b/src/app/execution/txRunner.js @@ -26,7 +26,6 @@ var css = csjs` } ` - function TxRunner (vmaccounts, api) { this._api = api this.blockNumber = 0 @@ -105,8 +104,8 @@ TxRunner.prototype.execute = function (args, callback) { tx.gas = gasEstimation - if (!self.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { - self.detectNetwork((err, network) => { + if (!self._api.config.getUnpersistedProperty('doNotShowTransactionConfirmationAgain')) { + self._api.detectNetwork((err, network) => { if (err) { console.log(err) } else { @@ -115,7 +114,7 @@ TxRunner.prototype.execute = function (args, callback) { modalDialog('Confirm transaction', content, { label: 'Confirm', fn: () => { - self.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) + self._api.config.setUnpersistedProperty('doNotShowTransactionConfirmationAgain', content.querySelector('input#confirmsetting').checked) if (!content.gasPriceStatus) { callback('Given gas grice is not correct') } else { diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js index 02df26e3d1..0e5f14fe3f 100644 --- a/src/app/tabs/run-tab.js +++ b/src/app/tabs/run-tab.js @@ -191,6 +191,11 @@ var css = csjs` } .transactionActions { float: right; + } + .createAccount { + margin-left: 5px; + cursor: pointer; + } ` module.exports = runTab @@ -526,6 +531,15 @@ function settings (container, appAPI, appEvents) { }) } setInterval(updateNetwork, 5000) + function newAccount () { + appAPI.newAccount('', (error, address) => { + if (!error) { + container.querySelector('#txorigin').appendChild(yo``) + } else { + modalDialogCustom.alert('Cannot create an account: ' + error) + } + }) + } var el = yo`
@@ -562,6 +576,7 @@ function settings (container, appAPI, appEvents) {
Account
${copyToClipboard(() => document.querySelector('#runTabView #txorigin').value)} +
Gas limit
diff --git a/src/app/tabs/settings-tab.js b/src/app/tabs/settings-tab.js index b3ddcbd4c2..1cfab7b5c2 100644 --- a/src/app/tabs/settings-tab.js +++ b/src/app/tabs/settings-tab.js @@ -100,37 +100,6 @@ 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
@@ -145,6 +114,16 @@ function SettingsTab (container, appAPI, appEvents, opts) {
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
diff --git a/src/app/ui/modal-dialog-custom.js b/src/app/ui/modal-dialog-custom.js index f8658b2418..192dae5a97 100644 --- a/src/app/ui/modal-dialog-custom.js +++ b/src/app/ui/modal-dialog-custom.js @@ -17,6 +17,33 @@ module.exports = { promptPassphrase: function (title, text, inputValue, ok, cancel) { prompt(title, text, true, inputValue, ok, cancel) }, + promptPassphraseCreation: function (ok, cancel) { + var text = 'Please provide a Passphrase for the account creation' + var input = yo`
+ +
+
+ +
` + modal(null, yo`
${text}
${input}
`, + { + fn: () => { + if (typeof ok === 'function') { + if (input.querySelector('#prompt1').value === input.querySelector('#prompt2').value) { + ok(null, input.querySelector('#prompt1').value) + } else { + ok('Passphase does not match') + } + } + } + }, + { + fn: () => { + if (typeof cancel === 'function') cancel() + } + } + ) + }, promptMulti: function ({ title, text, inputValue }, ok, cancel) { if (!inputValue) inputValue = '' var input = yo`` diff --git a/src/universal-dapp.js b/src/universal-dapp.js index fc669be700..bf28945711 100644 --- a/src/universal-dapp.js +++ b/src/universal-dapp.js @@ -15,6 +15,7 @@ var txExecution = require('./app/execution/txExecution') var helper = require('./lib/helper') var executionContext = require('./execution-context') var copyToClipboard = require('./app/ui/copy-to-clipboard') +var modalCustom = require('./app/ui/modal-dialog-custom') // -------------- styling ---------------------- var csjs = require('csjs-inject') @@ -190,14 +191,20 @@ UniversalDApp.prototype.newAccount = function (password, cb) { if (!this._api.personalMode()) { return cb('Not running in personal mode') } - executionContext.web3().personal.newAccount(password, cb) + modalCustom.promptPassphraseCreation((error, passphrase) => { + if (error) { + modalCustom.alert(error) + } else { + executionContext.web3().personal.newAccount(passphrase, cb) + } + }, () => {}) } else { var privateKey do { privateKey = crypto.randomBytes(32) } while (!ethJSUtil.isValidPrivate(privateKey)) - this._addAccount(privateKey) - cb(null, '0x' + ethJSUtil.privateToAddress(privateKey)) + this._addAccount(privateKey, '0x56BC75E2D63100000') + cb(null, '0x' + ethJSUtil.privateToAddress(privateKey).toString('hex')) } } From f55ebeb6d32426b1a31a6d23f6a7cdfa1171e485 Mon Sep 17 00:00:00 2001 From: yann300 Date: Sun, 28 Jan 2018 12:37:12 +0100 Subject: [PATCH 3/6] add link to gas station --- src/app/execution/txRunner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/execution/txRunner.js b/src/app/execution/txRunner.js index 0d040fae8b..0d48c8e485 100644 --- a/src/app/execution/txRunner.js +++ b/src/app/execution/txRunner.js @@ -246,7 +246,7 @@ function confirmDialog (tx, gasEstimation, self) {
Amount: ${amount} Ether
Gas estimation: ${gasEstimation}
Gas limit: ${tx.gas}
-
Gas price: Gwei
+
Gas price: Gwei (visit ethgasstation.info to get more info about gas price)
Max transaction fee:
Data:
${tx.data}
From d969ea2630bb7e0493cad6a3c866fa3a6341f180 Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 29 Jan 2018 10:44:36 +0100 Subject: [PATCH 4/6] fix addTooltip params --- src/app/ui/copy-to-clipboard.js | 2 +- src/app/ui/tooltip.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/ui/copy-to-clipboard.js b/src/app/ui/copy-to-clipboard.js index 869dfd53c5..5a8313bff9 100644 --- a/src/app/ui/copy-to-clipboard.js +++ b/src/app/ui/copy-to-clipboard.js @@ -29,7 +29,7 @@ module.exports = function copyToClipboard (getContent) { } } catch (e) {} copy(copiableContent) - addTooltip(event, 'Successfully copied!') + addTooltip('Successfully copied!') } } return copyIcon diff --git a/src/app/ui/tooltip.js b/src/app/ui/tooltip.js index 0f58d70ae1..402b90450c 100644 --- a/src/app/ui/tooltip.js +++ b/src/app/ui/tooltip.js @@ -38,7 +38,7 @@ var css = csjs` } ` -module.exports = function addTooltip (event, tooltipText) { +module.exports = function addTooltip (tooltipText) { var tooltip = yo`
${tooltipText}
` document.body.appendChild(tooltip) setTimeout(function () { From 0c9bdd41840fa2267ee40e616fa472496c39697e Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 29 Jan 2018 10:44:52 +0100 Subject: [PATCH 5/6] use addToolTip --- src/app/tabs/run-tab.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js index 0e5f14fe3f..ef1a5f896a 100644 --- a/src/app/tabs/run-tab.js +++ b/src/app/tabs/run-tab.js @@ -10,6 +10,7 @@ var executionContext = require('../../execution-context') var copyToClipboard = require('../ui/copy-to-clipboard') var Recorder = require('../../recorder') var EventManager = require('remix-lib').EventManager +var addTooltip = require('../ui/tooltip') // -------------- styling ---------------------- var csjs = require('csjs-inject') @@ -270,7 +271,7 @@ function fillAccountsList (appAPI, container) { var $txOrigin = $(container.querySelector('#txorigin')) $txOrigin.empty() appAPI.udapp().getAccounts((err, accounts) => { - if (err) { console.log(err) } + if (err) { addTooltip(`Cannot get account list: ${err}`) } if (accounts && accounts[0]) { for (var a in accounts) { $txOrigin.append($('`) + addTooltip(`account ${address} created`) } else { - modalDialogCustom.alert('Cannot create an account: ' + error) + addTooltip('Cannot create an account: ' + error) } }) } From f1a8d82bd6df7bf7553453a3db65ba1ac75245eb Mon Sep 17 00:00:00 2001 From: yann300 Date: Mon, 29 Jan 2018 14:18:46 +0100 Subject: [PATCH 6/6] styling --- src/app/tabs/run-tab.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/tabs/run-tab.js b/src/app/tabs/run-tab.js index ef1a5f896a..243806d8e5 100644 --- a/src/app/tabs/run-tab.js +++ b/src/app/tabs/run-tab.js @@ -197,6 +197,9 @@ var css = csjs` margin-left: 5px; cursor: pointer; } + .createAccount:hover { + color: ${styles.colors.orange}; + } ` module.exports = runTab