aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorkumavis <kumavis@users.noreply.github.com>2016-05-05 02:11:37 +0800
committerkumavis <kumavis@users.noreply.github.com>2016-05-05 02:11:37 +0800
commit95582f8bde3abda5b6b7cf0e027bc7913e5953ce (patch)
tree6409dd6ea4aee0f58e243959568a4dca3fd0e63d /ui
parentdcbf17af2d547ce676178bf78328d5c01135e31a (diff)
parent9c6ec054b13f24e88b78ca4124b0d3a46234b1d7 (diff)
downloadtangerine-wallet-browser-95582f8bde3abda5b6b7cf0e027bc7913e5953ce.tar.gz
tangerine-wallet-browser-95582f8bde3abda5b6b7cf0e027bc7913e5953ce.tar.zst
tangerine-wallet-browser-95582f8bde3abda5b6b7cf0e027bc7913e5953ce.zip
Merge pull request #169 from MetaMask/ImplementEthSign
implement eth_sign
Diffstat (limited to 'ui')
-rw-r--r--ui/app/account-detail.js3
-rw-r--r--ui/app/actions.js19
-rw-r--r--ui/app/app.js19
-rw-r--r--ui/app/components/pending-msg.js72
-rw-r--r--ui/app/components/pending-tx.js78
-rw-r--r--ui/app/components/template.js19
-rw-r--r--ui/app/conf-tx.js118
-rw-r--r--ui/app/reducers/app.js28
-rw-r--r--ui/app/reducers/metamask.js8
-rw-r--r--ui/index.js5
-rw-r--r--ui/lib/tx-helper.js8
11 files changed, 303 insertions, 74 deletions
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index 250e7318c..a876b275f 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -13,7 +13,7 @@ function mapStateToProps(state) {
return {
identities: state.metamask.identities,
accounts: state.metamask.accounts,
- address: state.appState.currentView.context,
+ address: state.metamask.selectedAccount,
accountDetail: state.appState.accountDetail,
transactions: state.metamask.transactions,
networkVersion: state.metamask.network,
@@ -27,6 +27,7 @@ function AccountDetailScreen() {
AccountDetailScreen.prototype.render = function() {
var state = this.props
+ var selected = state.address || Object.keys(state.accounts[0]).address
var identity = state.identities[state.address]
var account = state.accounts[state.address]
var accountDetail = state.accountDetail
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 12e20e0cf..072139e1a 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -42,6 +42,7 @@ var actions = {
SHOW_ACCOUNT_DETAIL: 'SHOW_ACCOUNT_DETAIL',
SHOW_ACCOUNTS_PAGE: 'SHOW_ACCOUNTS_PAGE',
SHOW_CONF_TX_PAGE: 'SHOW_CONF_TX_PAGE',
+ SHOW_CONF_MSG_PAGE: 'SHOW_CONF_MSG_PAGE',
// account detail screen
SHOW_SEND_PAGE: 'SHOW_SEND_PAGE',
showSendPage: showSendPage,
@@ -57,7 +58,8 @@ var actions = {
NEXT_TX: 'NEXT_TX',
PREVIOUS_TX: 'PREV_TX',
setSelectedAddress: setSelectedAddress,
- signTx: signTx,
+ signMsg: signMsg,
+ cancelMsg: cancelMsg,
sendTx: sendTx,
cancelTx: cancelTx,
completedTx: completedTx,
@@ -111,7 +113,6 @@ function tryUnlockMetamask(password) {
dispatch(this.unlockFailed())
} else {
dispatch(this.unlockMetamask())
- dispatch(this.showAccountDetail(selectedAccount))
}
})
}
@@ -152,16 +153,15 @@ function setSelectedAddress(address) {
}
}
-function signTx(txData) {
+function signMsg(msgData) {
return (dispatch) => {
dispatch(this.showLoadingIndication())
- web3.eth.sendTransaction(txData, (err, data) => {
+ _accountManager.signMessage(msgData, (err) => {
dispatch(this.hideLoadingIndication())
if (err) return dispatch(this.displayWarning(err.message))
- dispatch(this.hideWarning())
- dispatch(this.goHome())
+ dispatch(this.completedTx(msgData.metamaskId))
})
}
}
@@ -193,9 +193,14 @@ function txError(err) {
}
}
+function cancelMsg(msgData){
+ _accountManager.cancelMessage(msgData.id)
+ return this.completedTx(msgData.id)
+}
+
function cancelTx(txData){
_accountManager.cancelTransaction(txData.id)
- return this.goHome()
+ return this.completedTx(txData.id)
}
//
diff --git a/ui/app/app.js b/ui/app/app.js
index fa375fb7f..94c72a3c8 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -23,6 +23,7 @@ const ConfirmTxScreen = require('./conf-tx')
const ConfigScreen = require('./config')
const InfoScreen = require('./info')
const LoadingIndicator = require('./loading')
+const txHelper = require('../lib/tx-helper')
module.exports = connect(mapStateToProps)(App)
@@ -39,6 +40,8 @@ function mapStateToProps(state) {
activeAddress: state.appState.activeAddress,
transForward: state.appState.transForward,
seedWords: state.metamask.seedWords,
+ unconfTxs: state.metamask.unconfTxs,
+ unconfMsgs: state.metamask.unconfMsgs,
}
}
@@ -202,8 +205,20 @@ App.prototype.renderPrimary = function(state){
return h(CreateVaultScreen, {key: 'createVault'})
default:
- return h(AccountsScreen, {key: 'accounts'})
- }
+ if (this.hasPendingTxs()) {
+ return h(ConfirmTxScreen, {key: 'confirm-tx'})
+ } else {
+ return h(AccountDetailScreen, {key: 'account-detail'})
+ }
+ }
+}
+
+App.prototype.hasPendingTxs = function() {
+ var state = this.props
+ var unconfTxs = state.unconfTxs
+ var unconfMsgs = state.unconfMsgs
+ var unconfTxList = txHelper(unconfTxs, unconfMsgs)
+ return unconfTxList.length > 0
}
function onOffToggle(state){
diff --git a/ui/app/components/pending-msg.js b/ui/app/components/pending-msg.js
new file mode 100644
index 000000000..b0a6bb87d
--- /dev/null
+++ b/ui/app/components/pending-msg.js
@@ -0,0 +1,72 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+const AccountPanel = require('./account-panel')
+const addressSummary = require('../util').addressSummary
+const readableDate = require('../util').readableDate
+const formatBalance = require('../util').formatBalance
+const dataSize = require('../util').dataSize
+
+module.exports = PendingMsg
+
+
+inherits(PendingMsg, Component)
+function PendingMsg() {
+ Component.call(this)
+}
+
+PendingMsg.prototype.render = function() {
+ var state = this.props
+ var msgData = state.txData
+
+ var msgParams = msgData.msgParams || {}
+ var address = msgParams.from || state.selectedAddress
+ var identity = state.identities[address] || { address: address }
+ var account = state.accounts[address] || { address: address }
+
+ return (
+ h('.transaction', {
+ key: msgData.id,
+ }, [
+
+ h('h3', {
+ style: {
+ fontWeight: 'bold',
+ textAlign: 'center',
+ }
+ }, 'Sign Message'),
+
+ // account that will sign
+ h(AccountPanel, {
+ showFullAddress: true,
+ identity: identity,
+ account: account,
+ }),
+
+ // tx data
+ h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
+ h('.flex-row.flex-space-between', [
+ h('label.font-small', 'DATE'),
+ h('span.font-small', readableDate(msgData.time)),
+ ]),
+
+ h('.flex-row.flex-space-between', [
+ h('label.font-small', 'MESSAGE'),
+ h('span.font-small', msgParams.data),
+ ]),
+ ]),
+
+ // send + cancel
+ h('.flex-row.flex-space-around', [
+ h('button', {
+ onClick: state.cancelMessage,
+ }, 'Cancel'),
+ h('button', {
+ onClick: state.signMessage,
+ }, 'Sign'),
+ ]),
+ ])
+ )
+}
+
diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js
new file mode 100644
index 000000000..2bfb89705
--- /dev/null
+++ b/ui/app/components/pending-tx.js
@@ -0,0 +1,78 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+const AccountPanel = require('./account-panel')
+const addressSummary = require('../util').addressSummary
+const readableDate = require('../util').readableDate
+const formatBalance = require('../util').formatBalance
+const dataSize = require('../util').dataSize
+
+module.exports = PendingTx
+
+
+inherits(PendingTx, Component)
+function PendingTx() {
+ Component.call(this)
+}
+
+PendingTx.prototype.render = function() {
+ var state = this.props
+ var txData = state.txData
+
+ var txParams = txData.txParams || {}
+ var address = txParams.from || state.selectedAddress
+ var identity = state.identities[address] || { address: address }
+ var account = state.accounts[address] || { address: address }
+
+ return (
+ h('.transaction', {
+ key: txData.id,
+ }, [
+
+ h('h3', {
+ style: {
+ fontWeight: 'bold',
+ textAlign: 'center',
+ }
+ }, 'Submit Transaction'),
+
+ // account that will sign
+ h(AccountPanel, {
+ showFullAddress: true,
+ identity: identity,
+ account: account,
+ }),
+
+ // tx data
+ h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
+
+ h('.flex-row.flex-space-between', [
+ h('label.font-small', 'TO ADDRESS'),
+ h('span.font-small', addressSummary(txParams.to)),
+ ]),
+
+ h('.flex-row.flex-space-between', [
+ h('label.font-small', 'DATE'),
+ h('span.font-small', readableDate(txData.time)),
+ ]),
+
+ h('.flex-row.flex-space-between', [
+ h('label.font-small', 'AMOUNT'),
+ h('span.font-small', formatBalance(txParams.value)),
+ ]),
+ ]),
+
+ // send + cancel
+ h('.flex-row.flex-space-around', [
+ h('button', {
+ onClick: state.cancelTransaction,
+ }, 'Cancel'),
+ h('button', {
+ onClick: state.sendTransaction,
+ }, 'Send'),
+ ]),
+ ])
+ )
+}
+
diff --git a/ui/app/components/template.js b/ui/app/components/template.js
new file mode 100644
index 000000000..9e4eca20f
--- /dev/null
+++ b/ui/app/components/template.js
@@ -0,0 +1,19 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+
+module.exports = NewComponent
+
+
+inherits(NewComponent, Component)
+function NewComponent() {
+ Component.call(this)
+}
+
+NewComponent.prototype.render = function() {
+ var state = this.props
+
+ return (
+ h('span', 'Placeholder component')
+ )
+}
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index 983070013..8ab79c3b9 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -7,10 +7,10 @@ const copyToClipboard = require('copy-to-clipboard')
const actions = require('./actions')
const AccountPanel = require('./components/account-panel')
const valuesFor = require('./util').valuesFor
-const addressSummary = require('./util').addressSummary
-const readableDate = require('./util').readableDate
-const formatBalance = require('./util').formatBalance
-const dataSize = require('./util').dataSize
+const txHelper = require('../lib/tx-helper')
+
+const ConfirmTx = require('./components/pending-tx')
+const PendingMsg = require('./components/pending-msg')
module.exports = connect(mapStateToProps)(ConfirmTxScreen)
@@ -20,7 +20,9 @@ function mapStateToProps(state) {
accounts: state.metamask.accounts,
selectedAddress: state.metamask.selectedAddress,
unconfTxs: state.metamask.unconfTxs,
+ unconfMsgs: state.metamask.unconfMsgs,
index: state.appState.currentView.context,
+ warning: state.appState.warning,
}
}
@@ -32,12 +34,12 @@ function ConfirmTxScreen() {
ConfirmTxScreen.prototype.render = function() {
var state = this.props
- var unconfTxList = valuesFor(state.unconfTxs).sort(tx => tx.time)
- var txData = unconfTxList[state.index] || {}
- var txParams = txData.txParams || {}
- var address = txParams.from || state.selectedAddress
- var identity = state.identities[address] || { address: address }
- var account = state.accounts[address] || { address: address }
+
+ var unconfTxs = state.unconfTxs
+ var unconfMsgs = state.unconfMsgs
+ var unconfTxList = txHelper(unconfTxs, unconfMsgs)
+ var index = state.index !== undefined ? state.index : 0
+ var txData = unconfTxList[index] || {}
return (
@@ -46,9 +48,9 @@ ConfirmTxScreen.prototype.render = function() {
// subtitle and nav
h('.section-title.flex-row.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
- onClick: this.navigateToAccounts.bind(this),
+ onClick: this.goHome.bind(this),
}),
- h('h2.page-subtitle', 'Confirm Transaction'),
+ h('h2.page-subtitle', 'Confirmation'),
]),
h('h3', {
@@ -63,7 +65,7 @@ ConfirmTxScreen.prototype.render = function() {
},
onClick: () => state.dispatch(actions.previousTx()),
}),
- ` Transaction ${state.index + 1} of ${unconfTxList.length} `,
+ ` ${state.index + 1} of ${unconfTxList.length} `,
h('i.fa.fa-arrow-right.fa-lg.cursor-pointer', {
style: {
display: state.index + 1 === unconfTxList.length ? 'none' : 'inline-block',
@@ -72,58 +74,44 @@ ConfirmTxScreen.prototype.render = function() {
}),
]),
+ warningIfExists(state.warning),
+
h(ReactCSSTransitionGroup, {
transitionName: "main",
transitionEnterTimeout: 300,
transitionLeaveTimeout: 300,
}, [
- h('.transaction', {
+ currentTxView({
+ // Properties
+ txData: txData,
key: txData.id,
- }, [
-
- // account that will sign
- h(AccountPanel, {
- showFullAddress: true,
- identity: identity,
- account: account,
- }),
-
- // tx data
- h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
-
- h('.flex-row.flex-space-between', [
- h('label.font-small', 'TO ADDRESS'),
- h('span.font-small', addressSummary(txParams.to)),
- ]),
-
- h('.flex-row.flex-space-between', [
- h('label.font-small', 'DATE'),
- h('span.font-small', readableDate(txData.time)),
- ]),
-
- h('.flex-row.flex-space-between', [
- h('label.font-small', 'AMOUNT'),
- h('span.font-small', formatBalance(txParams.value)),
- ]),
-
- ]),
-
- // send + cancel
- h('.flex-row.flex-space-around', [
- h('button', {
- onClick: this.cancelTransaction.bind(this, txData),
- }, 'Cancel'),
- h('button', {
- onClick: this.sendTransaction.bind(this, txData),
- }, 'Send'),
- ]),
- ]),
+ selectedAddress: state.selectedAddress,
+ accounts: state.accounts,
+ identities: state.identities,
+ // Actions
+ sendTransaction: this.sendTransaction.bind(this, txData),
+ cancelTransaction: this.cancelTransaction.bind(this, txData),
+ signMessage: this.signMessage.bind(this, txData),
+ cancelMessage: this.cancelMessage.bind(this, txData),
+ }),
+
]),
- ]) // No comma or semicolon can go here
+ ])
)
}
+function currentTxView (opts) {
+
+ if ('txParams' in opts.txData) {
+ // This is a pending transaction
+ return h(ConfirmTx, opts)
+ } else if ('msgParams' in opts.txData) {
+ // This is a pending message to sign
+ return h(PendingMsg, opts)
+ }
+}
+
ConfirmTxScreen.prototype.sendTransaction = function(txData, event){
event.stopPropagation()
this.props.dispatch(actions.sendTx(txData))
@@ -134,7 +122,25 @@ ConfirmTxScreen.prototype.cancelTransaction = function(txData, event){
this.props.dispatch(actions.cancelTx(txData))
}
-ConfirmTxScreen.prototype.navigateToAccounts = function(event){
+ConfirmTxScreen.prototype.signMessage = function(msgData, event){
+ var params = msgData.msgParams
+ params.metamaskId = msgData.id
event.stopPropagation()
- this.props.dispatch(actions.showAccountsPage())
+ this.props.dispatch(actions.signMsg(params))
+}
+
+ConfirmTxScreen.prototype.cancelMessage = function(msgData, event){
+ event.stopPropagation()
+ this.props.dispatch(actions.cancelMsg(msgData))
+}
+
+ConfirmTxScreen.prototype.goHome = function(event){
+ event.stopPropagation()
+ this.props.dispatch(actions.goHome())
+}
+
+function warningIfExists(warning) {
+ if (warning) {
+ return h('span.error', { style: { margin: 'auto' } }, warning)
+ }
}
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index 57cdccbac..14f92a8c5 100644
--- a/ui/app/reducers/app.js
+++ b/ui/app/reducers/app.js
@@ -1,6 +1,7 @@
const extend = require('xtend')
const actions = require('../actions')
const valuesFor = require('../util').valuesFor
+const txHelper = require('../../lib/tx-helper')
module.exports = reduceApp
@@ -107,6 +108,7 @@ function reduceApp(state, action) {
case actions.UNLOCK_METAMASK:
return extend(appState, {
+ currentView: {},
transForward: true,
warning: null,
})
@@ -127,10 +129,7 @@ function reduceApp(state, action) {
case actions.GO_HOME:
return extend(appState, {
- currentView: {
- name: 'accountDetail',
- context: appState.currentView.context,
- },
+ currentView: {},
accountDetail: {
accountExport: 'none',
privateKey: '',
@@ -185,9 +184,24 @@ function reduceApp(state, action) {
warning: null,
})
+ case actions.SHOW_CONF_MSG_PAGE:
+ return extend(appState, {
+ currentView: {
+ name: 'confTx',
+ context: 0,
+ },
+ transForward: true,
+ warning: null,
+ })
+
case actions.COMPLETED_TX:
- var unconfTxs = Object.keys(state.metamask.unconfTxs).filter(tx => tx !== tx.id)
- if (unconfTxs && unconfTxs.length > 0) {
+ var unconfTxs = state.metamask.unconfTxs
+ var unconfMsgs = state.metamask.unconfMsgs
+
+ var unconfTxList = txHelper(unconfTxs, unconfMsgs)
+ .filter(tx => tx !== tx.id)
+
+ if (unconfTxList && unconfTxList.length > 0) {
return extend(appState, {
transForward: false,
currentView: {
@@ -202,7 +216,7 @@ function reduceApp(state, action) {
warning: null,
currentView: {
name: 'accountDetail',
- context: appState.currentView.context,
+ context: state.metamask.selectedAddress,
},
})
}
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 43bb3f761..2fe96c453 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -44,13 +44,19 @@ function reduceMetamask(state, action) {
case actions.COMPLETED_TX:
var stringId = String(action.id)
var newState = extend(metamaskState, {
- unconfTxs: {}
+ unconfTxs: {},
+ unconfMsgs: {},
})
for (var id in metamaskState.unconfTxs) {
if (id !== stringId) {
newState.unconfTxs[id] = metamaskState.unconfTxs[id]
}
}
+ for (var id in metamaskState.unconfMsgs) {
+ if (id !== stringId) {
+ newState.unconfMsgs[id] = metamaskState.unconfMsgs[id]
+ }
+ }
return newState
case actions.CLEAR_SEED_WORD_CACHE:
diff --git a/ui/index.js b/ui/index.js
index 4ecce2fbe..d67c6f096 100644
--- a/ui/index.js
+++ b/ui/index.js
@@ -43,6 +43,11 @@ function startApp(metamaskState, accountManager, opts){
store.dispatch(actions.showConfTxPage())
}
+ // if unconfirmed messages, start on msgConf page
+ if (Object.keys(metamaskState.unconfMsgs || {}).length) {
+ store.dispatch(actions.showConfTxPage())
+ }
+
accountManager.on('update', function(metamaskState){
store.dispatch(actions.updateMetamaskState(metamaskState))
})
diff --git a/ui/lib/tx-helper.js b/ui/lib/tx-helper.js
new file mode 100644
index 000000000..49845b01a
--- /dev/null
+++ b/ui/lib/tx-helper.js
@@ -0,0 +1,8 @@
+const valuesFor = require('../app/util').valuesFor
+
+module.exports = function(unconfTxs, unconfMsgs) {
+ var txValues = valuesFor(unconfTxs)
+ var msgValues = valuesFor(unconfMsgs)
+ var allValues = txValues.concat(msgValues)
+ return allValues.sort(tx => tx.time)
+}