Fix merge conflicts from uat-next

feature/default_network_editable
Alexander Tseung 7 years ago
commit 4f1fe1da62
  1. 10
      CHANGELOG.md
  2. 2
      app/manifest.json
  3. 15
      app/scripts/background.js
  4. 32
      app/scripts/controllers/transactions.js
  5. 3
      app/scripts/lib/tx-gas-utils.js
  6. 9
      app/scripts/popup.js
  7. 26
      app/scripts/setupRaven.js
  8. 3
      app/scripts/vendor/raven.min.js
  9. 5
      development/mockExtension.js
  10. 154
      development/states/confirm-new-ui.json
  11. 154
      development/states/send-edit.json
  12. 133
      development/states/send-new-ui.json
  13. 2
      gulpfile.js
  14. 2
      mock-dev.js
  15. 12
      old-ui/app/components/loading.js
  16. 6
      old-ui/app/conf-tx.js
  17. 12
      package.json
  18. 41
      test/integration/lib/first-time.js
  19. 229
      test/integration/lib/send-new-ui.js
  20. 29
      test/stub/provider.js
  21. 4
      test/unit/pending-tx-test.js
  22. 32
      test/unit/tx-controller-test.js
  23. 4
      test/unit/tx-gas-util-test.js
  24. 13
      ui/app/actions.js
  25. 2
      ui/app/components/network.js
  26. 1
      ui/app/components/pages/add-token.js
  27. 2
      ui/app/components/pages/create-account/import-account/index.js
  28. 19
      ui/app/components/pages/create-account/import-account/private-key.js
  29. 12
      ui/app/components/pages/create-account/new-account.js
  30. 1
      ui/app/components/send/send-v2-container.js
  31. 31
      ui/app/components/tooltip-v2.js
  32. 36
      ui/app/components/wallet-view.js
  33. 1
      ui/app/conf-tx.js
  34. 2
      ui/app/css/itcss/components/index.scss
  35. 25
      ui/app/css/itcss/components/new-account.scss
  36. 11
      ui/app/css/itcss/components/newui-sections.scss
  37. 7
      ui/app/css/itcss/components/tooltip.scss
  38. 199
      ui/app/info.js
  39. 5
      ui/app/reducers/app.js
  40. 96
      yarn.lock

@ -2,6 +2,16 @@
## Current Master
## 3.13.7 2018-1-22
- Add ability to bypass gas estimation loading indicator.
- Forward failed transactions to Sentry error reporting service
- Re-add changes from 3.13.5
## 3.13.6 2017-1-18
- Roll back changes to 3.13.4 to fix some issues with the new Infura REST provider.
## 3.13.5 2018-1-16
- Estimating gas limit for simple ether sends now faster & cheaper, by avoiding VM usage on recipients with no code.

@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
"version": "4.0.9",
"version": "3.13.7",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",

@ -13,6 +13,7 @@ const PortStream = require('./lib/port-stream.js')
const NotificationManager = require('./lib/notification-manager.js')
const MetamaskController = require('./metamask-controller')
const firstTimeState = require('./first-time-state')
const setupRaven = require('./setupRaven')
const STORAGE_KEY = 'metamask-config'
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
@ -24,6 +25,10 @@ const platform = new ExtensionPlatform()
const notificationManager = new NotificationManager()
global.METAMASK_NOTIFIER = notificationManager
// setup sentry error reporting
const release = platform.getVersion()
const raven = setupRaven({ release })
let popupIsOpen = false
// state persistence
@ -72,6 +77,16 @@ function setupController (initState) {
})
global.metamaskController = controller
// report failed transactions to Sentry
controller.txController.on(`tx:status-update`, (txId, status) => {
if (status !== 'failed') return
const txMeta = controller.txController.txStateManager.getTx(txId)
raven.captureMessage('Transaction Failed', {
// "extra" key is required by Sentry
extra: txMeta,
})
})
// setup state persistence
pump(
asStream(controller.store),

@ -43,6 +43,28 @@ module.exports = class TransactionController extends EventEmitter {
txHistoryLimit: opts.txHistoryLimit,
getNetwork: this.getNetwork.bind(this),
})
this.txStateManager.getFilteredTxList({
status: 'unapproved',
loadingDefaults: true,
}).forEach((tx) => {
this.addTxDefaults(tx)
.then((txMeta) => {
txMeta.loadingDefaults = false
this.txStateManager.updateTx(txMeta, 'transactions: gas estimation for tx on boot')
}).catch((error) => {
this.txStateManager.setTxStatusFailed(tx.id, error)
})
})
this.txStateManager.getFilteredTxList({
status: 'approved',
}).forEach((txMeta) => {
const txSignError = new Error('Transaction found as "approved" during boot - possibly stuck during signing')
this.txStateManager.setTxStatusFailed(txMeta.id, txSignError)
})
this.store = this.txStateManager.store
this.txStateManager.on('tx:status-update', this.emit.bind(this, 'tx:status-update'))
this.nonceTracker = new NonceTracker({
@ -171,11 +193,17 @@ module.exports = class TransactionController extends EventEmitter {
this.addTx(txMeta)
this.emit('newUnapprovedTx', txMeta)
// add default tx params
await this.addTxDefaults(txMeta)
try {
await this.addTxDefaults(txMeta)
} catch (error) {
console.log(error)
this.txStateManager.setTxStatusFailed(txMeta.id, error)
throw error
}
txMeta.loadingDefaults = false
// save txMeta
this.txStateManager.updateTx(txMeta)
return txMeta
}

@ -12,7 +12,8 @@ its passed ethquery
and used to do things like calculate gas of a tx.
*/
module.exports = class txProvideUtil {
module.exports = class TxGasUtil {
constructor (provider) {
this.query = new EthQuery(provider)
}

@ -8,10 +8,19 @@ const extension = require('extensionizer')
const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
const setupRaven = require('./setupRaven')
// create platform global
global.platform = new ExtensionPlatform()
// setup sentry error reporting
const release = global.platform.getVersion()
setupRaven({ release })
// inject css
// const css = MetaMaskUiCss()
// injectCss(css)
// identify window type (popup, notification)
const windowType = isPopupOrNotification()
global.METAMASK_UI_TYPE = windowType

@ -0,0 +1,26 @@
const Raven = require('./vendor/raven.min.js')
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
module.exports = setupRaven
// Setup raven / sentry remote error reporting
function setupRaven(opts) {
const { release } = opts
let ravenTarget
if (METAMASK_DEBUG) {
console.log('Setting up Sentry Remote Error Reporting: DEV')
ravenTarget = DEV
} else {
console.log('Setting up Sentry Remote Error Reporting: PROD')
ravenTarget = PROD
}
Raven.config(ravenTarget, {
release,
}).install()
return Raven
}

File diff suppressed because one or more lines are too long

@ -37,3 +37,8 @@ apis.forEach(function (api) {
extension.runtime.reload = noop
extension.tabs.create = noop
extension.runtime.getManifest = function () {
return {
version: 'development'
}
}

@ -0,0 +1,154 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"featureFlags": {"betaUI": true},
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"name": "Send Account 1"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"name": "Send Account 2"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"name": "Send Account 3"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
"name": "Send Account 4"
}
},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
"frequentRpcList": [],
"network": "3",
"accounts": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"code": "0x",
"balance": "0x47c9d71831c76efe",
"nonce": "0x1b",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"code": "0x",
"balance": "0x37452b1315889f80",
"nonce": "0xa",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"code": "0x",
"balance": "0x30c9d71831c76efe",
"nonce": "0x1c",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
}
},
"addressBook": [
{
"address": "0x06195827297c7a80a443b6894d3bdb8824b43896",
"name": "Address Book Account 1"
}
],
"tokens": [],
"transactions": {},
"selectedAddressTxList": [],
"unapprovedTxs": {
"4768706228115573": {
"id": 4768706228115573,
"time": 1487363153561,
"status": "unapproved",
"gasMultiplier": 1,
"metamaskNetworkId": "3",
"txParams": {
"from": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"to": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"value": "0x1bc16d674ec80000",
"metamaskId": 4768706228115573,
"metamaskNetworkId": "3",
"gas": "0xea60",
"gasPrice": "0xba43b7400"
}
}
},
"unapprovedMsgs": {},
"unapprovedMsgCount": 0,
"unapprovedPersonalMsgs": {},
"unapprovedPersonalMsgCount": 0,
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
],
"keyrings": [
{
"type": "HD Key Tree",
"accounts": [
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
]
},
{
"type": "Simple Key Pair",
"accounts": [
"0xd85a4b6a394794842887b8284293d69163007bbb"
]
}
],
"selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb",
"currentCurrency": "USD",
"provider": {
"type": "testnet"
},
"shapeShiftTxList": [],
"lostAccounts": [],
"send": {
"gasLimit": "0xea60",
"gasPrice": "0xba43b7400",
"gasTotal": "0xb451dc41b578",
"tokenBalance": null,
"from": {
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"balance": "0x37452b1315889f80"
},
"to": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"amount": "0x1bc16d674ec80000",
"memo": "",
"errors": {},
"maxModeOn": false,
"editingTransactionId": null
}
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "confTx",
"detailView": null,
"context": 0
},
"accountDetail": {
"subview": "transactions"
},
"modal": {
"modalState": {},
"previousModalState": {}
},
"transForward": true,
"isLoading": false,
"warning": null,
"scrollToBottom": false,
"forgottenPassword": null
},
"identities": {}
}

@ -0,0 +1,154 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"featureFlags": {"betaUI": true},
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"name": "Send Account 1"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"name": "Send Account 2"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"name": "Send Account 3"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
"name": "Send Account 4"
}
},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
"frequentRpcList": [],
"network": "3",
"accounts": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"code": "0x",
"balance": "0x47c9d71831c76efe",
"nonce": "0x1b",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"code": "0x",
"balance": "0x37452b1315889f80",
"nonce": "0xa",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"code": "0x",
"balance": "0x30c9d71831c76efe",
"nonce": "0x1c",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
}
},
"addressBook": [
{
"address": "0x06195827297c7a80a443b6894d3bdb8824b43896",
"name": "Address Book Account 1"
}
],
"tokens": [],
"transactions": {},
"selectedAddressTxList": [],
"unapprovedTxs": {
"4768706228115573": {
"id": 4768706228115573,
"time": 1487363153561,
"status": "unapproved",
"gasMultiplier": 1,
"metamaskNetworkId": "3",
"txParams": {
"from": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"to": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"value": "0x1bc16d674ec80000",
"metamaskId": 4768706228115573,
"metamaskNetworkId": "3",
"gas": "0xea60",
"gasPrice": "0xba43b7400"
}
}
},
"unapprovedMsgs": {},
"unapprovedMsgCount": 0,
"unapprovedPersonalMsgs": {},
"unapprovedPersonalMsgCount": 0,
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
],
"keyrings": [
{
"type": "HD Key Tree",
"accounts": [
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
]
},
{
"type": "Simple Key Pair",
"accounts": [
"0xd85a4b6a394794842887b8284293d69163007bbb"
]
}
],
"selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb",
"currentCurrency": "USD",
"provider": {
"type": "testnet"
},
"shapeShiftTxList": [],
"lostAccounts": [],
"send": {
"gasLimit": "0xea60",
"gasPrice": "0xba43b7400",
"gasTotal": "0xb451dc41b578",
"tokenBalance": null,
"from": {
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"balance": "0x37452b1315889f80"
},
"to": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"amount": "0x1bc16d674ec80000",
"memo": "",
"errors": {},
"maxModeOn": false,
"editingTransactionId": null
}
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "confTx",
"detailView": null,
"context": 0
},
"accountDetail": {
"subview": "transactions"
},
"modal": {
"modalState": {},
"previousModalState": {}
},
"transForward": true,
"isLoading": false,
"warning": null,
"scrollToBottom": false,
"forgottenPassword": null
},
"identities": {}
}

@ -0,0 +1,133 @@
{
"metamask": {
"isInitialized": true,
"isUnlocked": true,
"featureFlags": {"betaUI": true},
"rpcTarget": "https://rawtestrpc.metamask.io/",
"identities": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825",
"name": "Send Account 1"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"name": "Send Account 2"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d",
"name": "Send Account 3"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"address": "0xd85a4b6a394794842887b8284293d69163007bbb",
"name": "Send Account 4"
}
},
"unapprovedTxs": {},
"currentCurrency": "USD",
"conversionRate": 1200.88200327,
"conversionDate": 1489013762,
"noActiveNotices": true,
"frequentRpcList": [],
"network": "3",
"accounts": {
"0xfdea65c8e26263f6d9a1b5de9555d2931a33b825": {
"code": "0x",
"balance": "0x47c9d71831c76efe",
"nonce": "0x1b",
"address": "0xfdea65c8e26263f6d9a1b5de9555d2931a33b825"
},
"0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb": {
"code": "0x",
"balance": "0x37452b1315889f80",
"nonce": "0xa",
"address": "0xc5b8dbac4c1d3f152cdeb400e2313f309c410acb"
},
"0x2f8d4a878cfa04a6e60d46362f5644deab66572d": {
"code": "0x",
"balance": "0x30c9d71831c76efe",
"nonce": "0x1c",
"address": "0x2f8d4a878cfa04a6e60d46362f5644deab66572d"
},
"0xd85a4b6a394794842887b8284293d69163007bbb": {
"code": "0x",
"balance": "0x0",
"nonce": "0x0",
"address": "0xd85a4b6a394794842887b8284293d69163007bbb"
}
},
"addressBook": [
{
"address": "0x06195827297c7a80a443b6894d3bdb8824b43896",
"name": "Address Book Account 1"
}
],
"tokens": [],
"transactions": {},
"selectedAddressTxList": [],
"unapprovedMsgs": {},
"unapprovedMsgCount": 0,
"unapprovedPersonalMsgs": {},
"unapprovedPersonalMsgCount": 0,
"keyringTypes": [
"Simple Key Pair",
"HD Key Tree"
],
"keyrings": [
{
"type": "HD Key Tree",
"accounts": [
"fdea65c8e26263f6d9a1b5de9555d2931a33b825",
"c5b8dbac4c1d3f152cdeb400e2313f309c410acb",
"2f8d4a878cfa04a6e60d46362f5644deab66572d"
]
},
{
"type": "Simple Key Pair",
"accounts": [
"0xd85a4b6a394794842887b8284293d69163007bbb"
]
}
],
"selectedAddress": "0xd85a4b6a394794842887b8284293d69163007bbb",
"currentCurrency": "USD",
"provider": {
"type": "testnet"
},
"shapeShiftTxList": [],
"lostAccounts": [],
"send": {
"gasLimit": null,
"gasPrice": null,
"gasTotal": "0xb451dc41b578",
"tokenBalance": null,
"from": "",
"to": "",
"amount": "0x0",
"memo": "",
"errors": {},
"maxModeOn": false,
"editingTransactionId": null
}
},
"appState": {
"menuOpen": false,
"currentView": {
"name": "accountDetail",
"detailView": null,
"context": "0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc"
},
"accountDetail": {
"subview": "transactions"
},
"modal": {
"modalState": {},
"previousModalState": {}
},
"transForward": true,
"isLoading": false,
"warning": null,
"scrollToBottom": false,
"forgottenPassword": null
},
"identities": {}
}

@ -179,7 +179,7 @@ gulp.task('deps', function (cb) {
gulp.task('lint', function () {
// Ignoring node_modules, dist/firefox, and docs folders:
return gulp.src(['app/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js'])
return gulp.src(['app/**/*.js', '!app/scripts/vendor/**/*.js', 'ui/**/*.js', 'mascara/src/*.js', 'mascara/server/*.js', '!node_modules/**', '!dist/firefox/**', '!docs/**', '!app/scripts/chromereload.js', '!mascara/test/jquery-3.1.0.min.js'])
.pipe(eslint(fs.readFileSync(path.join(__dirname, '.eslintrc'))))
// eslint.format() outputs the lint results to the console.
// Alternatively use eslint.formatEach() (see Docs).

@ -23,6 +23,7 @@ const states = require('./development/states')
const Selector = require('./development/selector')
const MetamaskController = require('./app/scripts/metamask-controller')
const firstTimeState = require('./app/scripts/first-time-state')
const ExtensionPlatform = require('./app/scripts/platforms/extension')
const extension = require('./development/mockExtension')
const noop = function () {}
@ -67,6 +68,7 @@ const controller = new MetamaskController({
initState: firstTimeState,
})
global.metamaskController = controller
global.platform = new ExtensionPlatform
//
// User Interface

@ -11,7 +11,7 @@ function LoadingIndicator () {
}
LoadingIndicator.prototype.render = function () {
const { isLoading, loadingMessage } = this.props
const { isLoading, loadingMessage, canBypass, bypass } = this.props
return (
isLoading ? h('.full-flex-height', {
@ -28,6 +28,16 @@ LoadingIndicator.prototype.render = function () {
background: 'rgba(255, 255, 255, 0.8)',
},
}, [
canBypass ? h( 'i.fa.fa-close.cursor-pointer.close-loading', {
style: {
position: 'absolute',
top: '1px',
right: '15px',
color: '#AEAEAE',
},
onClick: bypass,
}) : null,
h('img', {
src: 'images/loading.svg',
}),

@ -62,8 +62,12 @@ ConfirmTxScreen.prototype.render = function () {
h('.flex-column.flex-grow', [
h(LoadingIndicator, {
isLoading: txData.loadingDefaults,
isLoading: this.state ? !this.state.bypassLoadingScreen : txData.loadingDefaults,
loadingMessage: 'Estimating transaction cost…',
canBypass: true,
bypass: () => {
this.setState({bypassLoadingScreen: true})
},
}),
// subtitle and nav

@ -76,9 +76,9 @@
"ensnare": "^1.0.0",
"eslint-plugin-react": "^7.4.0",
"eth-bin-to-ops": "^1.0.1",
"eth-block-tracker": "^2.2.0",
"eth-block-tracker": "^2.3.0",
"eth-json-rpc-filters": "^1.2.5",
"eth-json-rpc-infura": "^2.0.5",
"eth-json-rpc-infura": "^2.0.11",
"eth-keyring-controller": "^2.1.4",
"eth-contract-metadata": "^1.1.5",
"eth-hd-keyring": "^1.2.1",
@ -113,7 +113,7 @@
"iframe-stream": "^3.0.0",
"inject-css": "^0.1.1",
"jazzicon": "^1.2.0",
"json-rpc-engine": "3.2.0",
"json-rpc-engine": "^3.6.1",
"json-rpc-middleware-stream": "^1.0.1",
"lodash.debounce": "^4.0.8",
"lodash.memoize": "^4.1.2",
@ -150,6 +150,7 @@
"react-router-dom": "^4.2.2",
"react-select": "^1.0.0",
"react-simple-file-input": "^2.0.0",
"react-tippy": "^1.2.2",
"react-toggle-button": "^2.2.0",
"react-tooltip-component": "^0.3.0",
"react-transition-group": "^2.2.1",
@ -171,7 +172,7 @@
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "^0.20.1",
"web3-provider-engine": "^13.5.0",
"web3-provider-engine": "^13.5.6",
"web3-stream-provider": "^3.0.1",
"xtend": "^4.0.1"
},
@ -189,6 +190,7 @@
"brfs": "^1.4.3",
"browserify": "^14.4.0",
"chai": "^4.1.0",
"compression": "^1.7.1",
"coveralls": "^3.0.0",
"deep-freeze-strict": "^1.1.1",
"del": "^3.0.0",
@ -200,7 +202,7 @@
"eslint-plugin-react": "^7.4.0",
"eth-json-rpc-middleware": "^1.2.7",
"fs-promise": "^2.0.3",
"gulp": "github:gulpjs/gulp#4.0",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0",
"gulp-if": "^2.0.2",
"gulp-json-editor": "^2.2.1",

@ -39,9 +39,8 @@ async function runFirstTimeUsageTest(assert, done) {
await timeout()
// Scroll through terms
const title = app.find('h1').text()
// TODO Find where Metamask is getting added twice in the title
assert.equal(title, 'MetaMaskMetaMask', 'title screen')
const title = app.find('h1')[1]
assert.equal(title.textContent, 'MetaMask', 'title screen')
// enter password
const pwBox = app.find('#password-box')[0]
@ -67,19 +66,19 @@ async function runFirstTimeUsageTest(assert, done) {
await timeout(1000)
const detail = app.find('.wallet-view')[0]
const detail = app.find('.account-detail-section')[0]
assert.ok(detail, 'Account detail section loaded.')
await timeout(1000)
const menu = app.find('.account-menu__icon')[0]
menu.click()
const sandwich = app.find('.sandwich-expando')[0]
sandwich.click()
await timeout(1000)
await timeout()
const lock = app.find('.account-menu__logout-button')[0]
assert.ok(lock, 'Lock menu item found')
lock.click()
const menu = app.find('.menu-droppo')[0]
const children = menu.children
const logout = children[2]
assert.ok(logout, 'Lock menu item found')
logout.click()
await timeout(1000)
@ -91,30 +90,36 @@ async function runFirstTimeUsageTest(assert, done) {
await timeout(1000)
const detail2 = app.find('.wallet-view')[0]
const detail2 = app.find('.account-detail-section')[0]
assert.ok(detail2, 'Account detail section loaded again.')
await timeout()
// open account settings dropdown
const qrButton = app.find('.wallet-view__details-button')[0]
const qrButton = app.find('.fa.fa-ellipsis-h')[0]
qrButton.click()
await timeout(1000)
const qrHeader = app.find('.editable-label__value')[0]
const qrContainer = app.find('.qr-wrapper')[0]
// qr code item
const qrButton2 = app.find('.dropdown-menu-item')[1]
qrButton2.click()
await timeout(1000)
const qrHeader = app.find('.qr-header')[0]
const qrContainer = app.find('#qr-container')[0]
assert.equal(qrHeader.textContent, 'Account 1', 'Should show account label.')
assert.ok(qrContainer, 'QR Container found')
await timeout()
const networkMenu = app.find('.network-component')[0]
const networkMenu = app.find('.network-indicator')[0]
networkMenu.click()
await timeout()
const networkMenu2 = app.find('.menu-droppo')[0]
const networkMenu2 = app.find('.network-indicator')[0]
const children2 = networkMenu2.children
children2.length[3]
assert.ok(children2, 'All network options present')

@ -0,0 +1,229 @@
const reactTriggerChange = require('react-trigger-change')
const PASSWORD = 'password123'
QUnit.module('new ui send flow')
QUnit.test('successful send flow', (assert) => {
const done = assert.async()
runSendFlowTest(assert).then(done).catch((err) => {
assert.notOk(err, `Error was thrown: ${err.stack}`)
done()
})
})
global.ethQuery = {
sendTransaction: () => {},
}
async function runSendFlowTest(assert, done) {
console.log('*** start runSendFlowTest')
const selectState = $('select')
selectState.val('send new ui')
reactTriggerChange(selectState[0])
await timeout(2000)
const sendScreenButton = $('button.btn-clear.hero-balance-button')
assert.ok(sendScreenButton[1], 'send screen button present')
sendScreenButton[1].click()
await timeout(1000)
const sendContainer = $('.send-v2__container')
assert.ok(sendContainer[0], 'send container renders')
const sendHeader = $('.send-v2__send-header-icon')
assert.ok(sendHeader[0], 'send screen has a header icon')
const sendTitle = $('.send-v2__title')
assert.equal(sendTitle[0].textContent, 'Send Funds', 'Send screen title is correct')
const sendCopy = $('.send-v2__copy')
assert.equal(sendCopy[0].textContent, 'Only send ETH to an Ethereum address.', 'Send screen has copy')
const sendFromField = $('.send-v2__form-field')
assert.ok(sendFromField[0], 'send screen has a from field')
let sendFromFieldItemAddress = $('.account-list-item__account-name')
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 4', 'send from field shows correct account name')
const sendFromFieldItem = $('.account-list-item')
sendFromFieldItem[0].click()
await timeout()
const sendFromDropdownList = $('.send-v2__from-dropdown__list')
assert.equal(sendFromDropdownList.children().length, 4, 'send from dropdown shows all accounts')
console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromDropdownList.children()[1]`, sendFromDropdownList.children()[1]);
sendFromDropdownList.children()[1].click()
await timeout()
sendFromFieldItemAddress = $('.account-list-item__account-name')
console.log(`!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! sendFromFieldItemAddress[0]`, sendFromFieldItemAddress[0]);
assert.equal(sendFromFieldItemAddress[0].textContent, 'Send Account 2', 'send from field dropdown changes account name')
let sendToFieldInput = $('.send-v2__to-autocomplete__input')
sendToFieldInput[0].focus()
await timeout()
const sendToDropdownList = $('.send-v2__from-dropdown__list')
assert.equal(sendToDropdownList.children().length, 5, 'send to dropdown shows all accounts and address book accounts')
sendToDropdownList.children()[2].click()
await timeout()
const sendToAccountAddress = sendToFieldInput.val()
assert.equal(sendToAccountAddress, '0x2f8d4a878cfa04a6e60d46362f5644deab66572d', 'send to dropdown selects the correct address')
const sendAmountField = $('.send-v2__form-row:eq(2)')
sendAmountField.find('.currency-display')[0].click()
await timeout()
const sendAmountFieldInput = sendAmountField.find('input:text')
sendAmountFieldInput.val('5.1')
reactTriggerChange(sendAmountField.find('input')[0])
await timeout()
let errorMessage = $('.send-v2__error')
assert.equal(errorMessage[0].textContent, 'Insufficient funds.', 'send should render an insufficient fund error message')
sendAmountFieldInput.val('2.0')
reactTriggerChange(sendAmountFieldInput[0])
await timeout()
errorMessage = $('.send-v2__error')
assert.equal(errorMessage.length, 0, 'send should stop rendering amount error message after amount is corrected')
const sendGasField = $('.send-v2__gas-fee-display')
assert.equal(
sendGasField.find('.currency-display__input-wrapper > input').val(),
'0.000198',
'send gas field should show estimated gas total'
)
assert.equal(
sendGasField.find('.currency-display__converted-value')[0].textContent,
'0.24 USD',
'send gas field should show estimated gas total converted to USD'
)
const sendGasOpenCustomizeModalButton = $('.send-v2__sliders-icon-container'
)
sendGasOpenCustomizeModalButton[0].click()
await timeout(1000)
const customizeGasModal = $('.send-v2__customize-gas')
assert.ok(customizeGasModal[0], 'should render the customize gas modal')
const customizeGasPriceInput = $('.send-v2__gas-modal-card').first().find('input')
customizeGasPriceInput.val(50)
reactTriggerChange(customizeGasPriceInput[0])
const customizeGasLimitInput = $('.send-v2__gas-modal-card').last().find('input')
customizeGasLimitInput.val(60000)
reactTriggerChange(customizeGasLimitInput[0])
await timeout()
const customizeGasSaveButton = $('.send-v2__customize-gas__save')
customizeGasSaveButton[0].click()
await timeout()
assert.equal(
sendGasField.find('.currency-display__input-wrapper > input').val(),
'0.003',
'send gas field should show customized gas total'
)
assert.equal(
sendGasField.find('.currency-display__converted-value')[0].textContent,
'3.60 USD',
'send gas field should show customized gas total converted to USD'
)
const sendButton = $('.send-v2__next-btn')
sendButton[0].click()
await timeout(2000)
selectState.val('send edit')
reactTriggerChange(selectState[0])
await timeout(2000)
const confirmFromName = $('.confirm-screen-account-name').first()
assert.equal(confirmFromName[0].textContent, 'Send Account 2', 'confirm screen should show correct from name')
const confirmToName = $('.confirm-screen-account-name').last()
assert.equal(confirmToName[0].textContent, 'Send Account 3', 'confirm screen should show correct to name')
const confirmScreenRows = $('.confirm-screen-rows')
const confirmScreenGas = confirmScreenRows.find('.confirm-screen-row-info')[2]
assert.equal(confirmScreenGas.textContent, '3.6 USD', 'confirm screen should show correct gas')
const confirmScreenTotal = confirmScreenRows.find('.confirm-screen-row-info')[3]
assert.equal(confirmScreenTotal.textContent, '2405.36 USD', 'confirm screen should show correct total')
const confirmScreenBackButton = $('.confirm-screen-back-button')
confirmScreenBackButton[0].click()
await timeout(1000)
const sendFromFieldItemInEdit = $('.account-list-item')
sendFromFieldItemInEdit[0].click()
await timeout()
const sendFromDropdownListInEdit = $('.send-v2__from-dropdown__list')
sendFromDropdownListInEdit.children()[2].click()
await timeout()
const sendToFieldInputInEdit = $('.send-v2__to-autocomplete__input')
sendToFieldInputInEdit[0].focus()
sendToFieldInputInEdit.val('0xd85a4b6a394794842887b8284293d69163007bbb')
await timeout()
const sendAmountFieldInEdit = $('.send-v2__form-row:eq(2)')
sendAmountFieldInEdit.find('.currency-display')[0].click()
await timeout()
const sendAmountFieldInputInEdit = sendAmountFieldInEdit.find('input:text')
sendAmountFieldInputInEdit.val('1.0')
reactTriggerChange(sendAmountFieldInputInEdit[0])
await timeout()
const sendButtonInEdit = $('.send-v2__next-btn')
sendButtonInEdit[0].click()
await timeout()
// TODO: Need a way to mock background so that we can test correct transition from editing to confirm
selectState.val('confirm new ui')
reactTriggerChange(selectState[0])
await timeout(2000)
const confirmScreenConfirmButton = $('.confirm-screen-confirm-button')
console.log(`+++++++++++++++++++++++++++++++= confirmScreenConfirmButton[0]`, confirmScreenConfirmButton[0]);
confirmScreenConfirmButton[0].click()
await timeout(2000)
const txView = $('.tx-view')
console.log(`++++++++++++++++++++++++++++++++ txView[0]`, txView[0]);
assert.ok(txView[0], 'Should return to the account details screen after confirming')
}
function timeout (time) {
return new Promise((resolve, reject) => {
setTimeout(resolve, time || 1500)
})
}

@ -1,12 +1,12 @@
const JsonRpcEngine = require('json-rpc-engine')
const scaffoldMiddleware = require('eth-json-rpc-middleware/scaffold')
const TestBlockchain = require('eth-block-tracker/test/util/testBlockMiddleware')
module.exports = {
createEngineForTestData,
providerFromEngine,
scaffoldMiddleware,
createEthJsQueryStub,
createStubedProvider,
createTestProviderTools,
}
@ -19,20 +19,13 @@ function providerFromEngine (engine) {
return provider
}
function createEthJsQueryStub (stubProvider) {
return new Proxy({}, {
get: (obj, method) => {
return (...params) => {
return new Promise((resolve, reject) => {
stubProvider.sendAsync({ method: `eth_${method}`, params }, (err, ress) => resolve(ress.result))
})
}
},
})
}
function createStubedProvider (resultStub) {
function createTestProviderTools (opts = {}) {
const engine = createEngineForTestData()
engine.push(scaffoldMiddleware(resultStub))
return providerFromEngine(engine)
}
const testBlockchain = new TestBlockchain()
// handle provided hooks
engine.push(scaffoldMiddleware(opts.scaffold || {}))
// handle block tracker methods
engine.push(testBlockchain.createMiddleware())
const provider = providerFromEngine(engine)
return { provider, engine, testBlockchain }
}

@ -3,7 +3,7 @@ const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx')
const ObservableStore = require('obs-store')
const clone = require('clone')
const { createStubedProvider } = require('../stub/provider')
const { createTestProviderTools } = require('../stub/provider')
const PendingTransactionTracker = require('../../app/scripts/lib/pending-tx-tracker')
const MockTxGen = require('../lib/mock-tx-gen')
const sinon = require('sinon')
@ -40,7 +40,7 @@ describe('PendingTransactionTracker', function () {
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
}
providerResultStub = {}
provider = createStubedProvider(providerResultStub)
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
pendingTxTracker = new PendingTransactionTracker({
provider,

@ -1,11 +1,12 @@
const assert = require('assert')
const ethUtil = require('ethereumjs-util')
const EthTx = require('ethereumjs-tx')
const EthjsQuery = require('ethjs-query')
const ObservableStore = require('obs-store')
const sinon = require('sinon')
const TransactionController = require('../../app/scripts/controllers/transactions')
const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils')
const { createStubedProvider, createEthJsQueryStub } = require('../stub/provider')
const { createTestProviderTools } = require('../stub/provider')
const noop = () => true
const currentNetworkId = 42
@ -14,11 +15,18 @@ const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f3
describe('Transaction Controller', function () {
let txController, provider, providerResultStub
let txController, provider, providerResultStub, testBlockchain
beforeEach(function () {
providerResultStub = {}
provider = createStubedProvider(providerResultStub)
providerResultStub = {
// 1 gwei
eth_gasPrice: '0x0de0b6b3a7640000',
// by default, all accounts are external accounts (not contracts)
eth_getCode: '0x',
}
const providerTools = createTestProviderTools({ scaffold: providerResultStub })
provider = providerTools.provider
testBlockchain = providerTools.testBlockchain
txController = new TransactionController({
provider,
@ -30,10 +38,7 @@ describe('Transaction Controller', function () {
resolve()
}),
})
txController.query = createEthJsQueryStub(provider)
txController.txGasUtil.query = createEthJsQueryStub(provider)
txController.nonceTracker.getNonceLock = () => Promise.resolve({ nextNonce: 0, releaseLock: noop })
txController.txProviderUtils = new TxGasUtils(txController.provider)
})
describe('#getState', function () {
@ -155,15 +160,6 @@ describe('Transaction Controller', function () {
})
describe('#addUnapprovedTransaction', function () {
let addTxDefaults
beforeEach(() => {
addTxDefaults = txController.addTxDefaults
txController.addTxDefaults = function addTxDefaultsStub () { return Promise.resolve() }
})
afterEach(() => {
txController.addTxDefaults = addTxDefaults
})
it('should add an unapproved transaction and return a valid txMeta', function (done) {
txController.addUnapprovedTransaction({})
@ -219,7 +215,7 @@ describe('Transaction Controller', function () {
var sample = {
value: '0x01',
}
txController.txProviderUtils.validateTxParams(sample).then(() => {
txController.txGasUtil.validateTxParams(sample).then(() => {
done()
}).catch(done)
})
@ -228,7 +224,7 @@ describe('Transaction Controller', function () {
var sample = {
value: '-0x01',
}
txController.txProviderUtils.validateTxParams(sample)
txController.txGasUtil.validateTxParams(sample)
.then(() => done('expected to thrown on negativity values but didn\'t'))
.catch((err) => {
assert.ok(err, 'error')

@ -1,12 +1,12 @@
const assert = require('assert')
const TxGasUtils = require('../../app/scripts/lib/tx-gas-utils')
const { createStubedProvider } = require('../stub/provider')
const { createTestProviderTools } = require('../stub/provider')
describe('Tx Gas Util', function () {
let txGasUtil, provider, providerResultStub
beforeEach(function () {
providerResultStub = {}
provider = createStubedProvider(providerResultStub)
provider = createTestProviderTools({ scaffold: providerResultStub }).provider
txGasUtil = new TxGasUtils({
provider,
})

@ -55,6 +55,7 @@ var actions = {
SET_NEW_ACCOUNT_FORM: 'SET_NEW_ACCOUNT_FORM',
unlockMetamask: unlockMetamask,
unlockFailed: unlockFailed,
unlockSucceeded,
showCreateVault: showCreateVault,
showRestoreVault: showRestoreVault,
showInitializeMenu: showInitializeMenu,
@ -78,6 +79,7 @@ var actions = {
// unlock screen
UNLOCK_IN_PROGRESS: 'UNLOCK_IN_PROGRESS',
UNLOCK_FAILED: 'UNLOCK_FAILED',
UNLOCK_SUCCEEDED: 'UNLOCK_SUCCEEDED',
UNLOCK_METAMASK: 'UNLOCK_METAMASK',
LOCK_METAMASK: 'LOCK_METAMASK',
tryUnlockMetamask: tryUnlockMetamask,
@ -281,12 +283,14 @@ function tryUnlockMetamask (password) {
log.debug(`background.submitPassword`)
return new Promise((resolve, reject) => {
background.submitPassword(password, err => {
background.submitPassword(password, (err) => {
dispatch(actions.hideLoadingIndication())
if (err) {
dispatch(actions.unlockFailed(err.message))
reject(err)
} else {
dispatch(actions.unlockSucceeded())
dispatch(actions.transitionForward())
return forceUpdateMetamaskState(dispatch).then(resolve)
}
@ -967,6 +971,13 @@ function unlockFailed (message) {
}
}
function unlockSucceeded (message) {
return {
type: actions.UNLOCK_SUCCEEDED,
value: message,
}
}
function unlockMetamask (account) {
return {
type: actions.UNLOCK_METAMASK,

@ -24,7 +24,7 @@ Network.prototype.render = function () {
let iconName, hoverText
if (networkNumber === 'loading') {
return h('span.pointer', {
return h('span.pointer.network-indicator', {
style: {
display: 'flex',
alignItems: 'center',

@ -43,7 +43,6 @@ function mapStateToProps (state) {
function mapDispatchToProps (dispatch) {
return {
goHome: () => dispatch(actions.goHome()),
addTokens: tokens => dispatch(actions.addTokens(tokens)),
}
}

@ -37,7 +37,7 @@ AccountImportSubview.prototype.render = function () {
h('div.new-account-import-form__select-section', [
h('div.new-account-import-form__select-label', 'SELECT TYPE'),
h('div.new-account-import-form__select-label', 'Select Type'),
h(Select, {
className: 'new-account-import-form__select',

@ -37,15 +37,20 @@ PrivateKeyImportView.prototype.render = function () {
return (
h('div.new-account-import-form__private-key', [
h('span.new-account-create-form__instruction', 'Paste your private key string here:'),
h('input.new-account-import-form__input-password', {
type: 'password',
id: 'private-key-box',
onKeyPress: () => this.createKeyringOnEnter(),
}),
h('div.new-account-import-form__private-key-password-container', [
h('div.new-account-create-form__buttons', {}, [
h('span.new-account-import-form__instruction', 'Paste your private key string here:'),
h('input.new-account-import-form__input-password', {
type: 'password',
id: 'private-key-box',
onKeyPress: () => this.createKeyringOnEnter(),
}),
]),
h('div.new-account-import-form__buttons', {}, [
h('button.new-account-create-form__button-cancel', {
onClick: () => this.props.history.push(DEFAULT_ROUTE),

@ -8,16 +8,18 @@ const { DEFAULT_ROUTE } = require('../../../routes')
class NewAccountCreateForm extends Component {
constructor (props) {
super(props)
const { numberOfExistingAccounts = 0 } = props
const newAccountNumber = numberOfExistingAccounts + 1
this.state = {
newAccountName: `Account ${newAccountNumber}`,
newAccountName: '',
defaultAccountName: `Account ${newAccountNumber}`,
}
}
render () {
const { newAccountName } = this.state
const { newAccountName, defaultAccountName } = this.state
const { history, createAccount } = this.props
return h('div.new-account-create-form', [
@ -28,8 +30,8 @@ class NewAccountCreateForm extends Component {
h('div.new-account-create-form__input-wrapper', {}, [
h('input.new-account-create-form__input', {
value: this.state.newAccountName,
placeholder: 'E.g. My new account',
value: newAccountName,
placeholder: defaultAccountName,
onChange: event => this.setState({ newAccountName: event.target.value }),
}, []),
]),
@ -44,7 +46,7 @@ class NewAccountCreateForm extends Component {
h('button.new-account-create-form__button-create', {
onClick: () => {
createAccount(newAccountName)
createAccount(newAccountName || defaultAccountName)
.then(() => history.push(DEFAULT_ROUTE))
},
}, [

@ -83,7 +83,6 @@ function mapDispatchToProps (dispatch) {
updateSendAmount: newAmount => dispatch(actions.updateSendAmount(newAmount)),
updateSendMemo: newMemo => dispatch(actions.updateSendMemo(newMemo)),
updateSendErrors: newError => dispatch(actions.updateSendErrors(newError)),
goHome: () => dispatch(actions.goHome()),
clearSend: () => dispatch(actions.clearSend()),
setMaxModeTo: bool => dispatch(actions.setMaxModeTo(bool)),
}

@ -0,0 +1,31 @@
const Component = require('react').Component
const h = require('react-hyperscript')
const inherits = require('util').inherits
const ReactTippy = require('react-tippy').Tooltip
module.exports = Tooltip
inherits(Tooltip, Component)
function Tooltip () {
Component.call(this)
}
Tooltip.prototype.render = function () {
const props = this.props
const { position, title, children, wrapperClassName } = props
return h('div', {
className: wrapperClassName,
}, [
h(ReactTippy, {
title,
position: position || 'left',
trigger: 'mouseenter',
hideOnClick: false,
size: 'small',
arrow: true,
}, children),
])
}

@ -4,8 +4,10 @@ const h = require('react-hyperscript')
const { withRouter } = require('react-router-dom')
const { compose } = require('recompose')
const inherits = require('util').inherits
const classnames = require('classnames')
const Identicon = require('./identicon')
// const AccountDropdowns = require('./dropdowns/index.js').AccountDropdowns
const Tooltip = require('./tooltip-v2.js')
const copyToClipboard = require('copy-to-clipboard')
const actions = require('../actions')
const BalanceComponent = require('./balance-component')
@ -51,6 +53,7 @@ function WalletView () {
Component.call(this)
this.state = {
hasCopied: false,
copyToClipboardPressed: false,
}
}
@ -140,17 +143,30 @@ WalletView.prototype.render = function () {
]),
]),
h('div.wallet-view__address', {
onClick: () => {
copyToClipboard(selectedAddress)
this.setState({ hasCopied: true })
setTimeout(() => this.setState({ hasCopied: false }), 3000)
},
h(Tooltip, {
position: 'bottom',
title: this.state.hasCopied ? 'Copied!' : 'Copy to clipboard',
wrapperClassName: 'wallet-view__tooltip',
}, [
this.state.hasCopied && 'Copied to Clipboard',
!this.state.hasCopied && `${selectedAddress.slice(0, 4)}...${selectedAddress.slice(-4)}`,
h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }),
h('button.wallet-view__address', {
className: classnames({
'wallet-view__address__pressed': this.state.copyToClipboardPressed,
}),
onClick: () => {
copyToClipboard(selectedAddress)
this.setState({ hasCopied: true })
setTimeout(() => this.setState({ hasCopied: false }), 3000)
},
onMouseDown: () => {
this.setState({ copyToClipboardPressed: true })
},
onMouseUp: () => {
this.setState({ copyToClipboardPressed: false })
},
}, [
`${selectedAddress.slice(0, 4)}...${selectedAddress.slice(-4)}`,
h('i.fa.fa-clipboard', { style: { marginLeft: '8px' } }),
]),
]),
this.renderWalletBalance(),

@ -126,7 +126,6 @@ ConfirmTxScreen.prototype.render = function () {
cancelPersonalMessage: this.cancelPersonalMessage.bind(this, txData),
cancelTypedMessage: this.cancelTypedMessage.bind(this, txData),
})
}
function currentTxView (opts) {

@ -55,3 +55,5 @@
@import './pages/index.scss';
@import './new-account.scss';
@import './tooltip.scss';

@ -56,11 +56,17 @@
}
.new-account-import-form {
display: flex;
flex-flow: column;
align-items: center;
padding: 0 30px;
&__select-section {
display: flex;
justify-content: space-evenly;
justify-content: space-between;
align-items: center;
margin-top: 29px;
width: 100%;
}
&__select-label {
@ -92,19 +98,25 @@
}
}
&__private-key-password-container {
display: flex;
flex-flow: column;
align-items: center;
width: 100%;
}
&__instruction {
color: $scorpion;
font-family: Roboto;
font-size: 16px;
line-height: 21px;
align-self: flex-start;
margin-left: 30px;
}
&__private-key {
display: flex;
flex-flow: column;
align-items: center;
align-items: flex-start;
margin-top: 34px;
}
@ -127,6 +139,13 @@
align-items: center;
margin-top: 29px;
}
&__buttons {
margin-top: 39px;
display: flex;
width: 100%;
justify-content: space-between;
}
}
.new-account-create-form {

@ -89,6 +89,12 @@ $wallet-view-bg: $alabaster;
flex: 0 0 auto;
}
&__tooltip {
display: flex;
justify-content: center;
padding: 24px;
}
&__address {
border-radius: 3px;
background-color: $alto;
@ -96,10 +102,13 @@ $wallet-view-bg: $alabaster;
font-size: 14px;
line-height: 12px;
padding: 4px 12px;
margin: 24px auto;
font-weight: 300;
cursor: pointer;
flex: 0 0 auto;
&__pressed {
background-color: $manatee,
}
}
&__sidebar-close {

File diff suppressed because one or more lines are too long

@ -15,134 +15,91 @@ function InfoScreen () {
Component.call(this)
}
InfoScreen.prototype.render = function () {
const state = this.props
const version = global.platform.getVersion()
InfoScreen.prototype.renderLogo = function () {
return (
h('.flex-column.flex-grow', {
style: {
maxWidth: '400px',
},
}, [
h('div.settings__info-logo-wrapper', [
h('img.settings__info-logo', { src: 'images/info-logo.png' }),
])
)
}
// subtitle and nav
h('.section-title.flex-row.flex-center', [
h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: (event) => {
state.dispatch(actions.goHome())
},
}),
h('h2.page-subtitle', 'Info'),
InfoScreen.prototype.renderInfoLinks = function () {
return (
h('div.settings__content-item.settings__content-item--without-height', [
h('div.settings__info-link-header', 'Links'),
h('div.settings__info-link-item', [
h('a', {
href: 'https://metamask.io/privacy.html',
target: '_blank',
}, [
h('span.settings__info-link', 'Privacy Policy'),
]),
]),
// main view
h('.flex-column.flex-justify-center.flex-grow.select-none', [
h('.flex-space-around', {
style: {
padding: '20px',
},
h('div.settings__info-link-item', [
h('a', {
href: 'https://metamask.io/terms.html',
target: '_blank',
}, [
// current version number
h('.info.info-gray', [
h('div', 'Metamask'),
h('div', {
style: {
marginBottom: '10px',
},
}, `Version: ${version}`),
]),
h('div', {
style: {
marginBottom: '5px',
}},
[
h('div', [
h('a', {
href: 'https://metamask.io/privacy.html',
target: '_blank',
onClick (event) { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Privacy Policy'),
]),
]),
h('div', [
h('a', {
href: 'https://metamask.io/terms.html',
target: '_blank',
onClick (event) { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Terms of Use'),
]),
]),
h('div', [
h('a', {
href: 'https://metamask.io/attributions.html',
target: '_blank',
onClick (event) { this.navigateTo(event.target.href) },
}, [
h('div.info', 'Attributions'),
]),
]),
]
),
h('hr', {
style: {
margin: '10px 0 ',
width: '7em',
},
}),
h('div', {
style: {
paddingLeft: '30px',
}},
[
h('div.fa.fa-support', [
h('a.info', {
href: 'https://metamask.helpscoutdocs.com/',
target: '_blank',
}, 'Visit our Knowledge Base'),
]),
h('div', [
h('a', {
href: 'https://metamask.io/',
target: '_blank',
}, [
h('img.icon-size', {
src: 'images/icon-128.png',
style: {
// IE6-9
filter: 'grayscale(100%)',
// Microsoft Edge and Firefox 35+
WebkitFilter: 'grayscale(100%)',
},
}),
h('div.info', 'Visit our web site'),
]),
]),
h('span.settings__info-link', 'Terms of Use'),
]),
]),
h('div.settings__info-link-item', [
h('a', {
href: 'https://metamask.io/attributions.html',
target: '_blank',
}, [
h('span.settings__info-link', 'Attributions'),
]),
]),
h('hr.settings__info-separator'),
h('div.settings__info-link-item', [
h('a', {
href: 'https://support.metamask.io',
target: '_blank',
}, [
h('span.settings__info-link', 'Visit our Support Center'),
]),
]),
h('div.settings__info-link-item', [
h('a', {
href: 'https://metamask.io/',
target: '_blank',
}, [
h('span.settings__info-link', 'Visit our web site'),
]),
]),
h('div.settings__info-link-item', [
h('a', {
target: '_blank',
href: 'mailto:help@metamask.io?subject=Feedback',
}, [
h('span.settings__info-link', 'Email us!'),
]),
]),
])
)
}
h('div', [
h('.fa.fa-twitter', [
h('a.info', {
href: 'https://twitter.com/metamask_io',
target: '_blank',
}, 'Follow us on Twitter'),
]),
]),
InfoScreen.prototype.render = function () {
const version = global.platform.getVersion()
h('div.fa.fa-envelope', [
h('a.info', {
target: '_blank',
href: 'mailto:support@metamask.io?subject=MetaMask Support',
}, 'Email us!'),
]),
]),
return (
h('div.settings__content', [
h('div.settings__content-row', [
h('div.settings__content-item.settings__content-item--without-height', [
this.renderLogo(),
h('div.settings__info-item', [
h('div.settings__info-version-header', 'MetaMask Version'),
h('div.settings__info-version-number', `${version}`),
]),
h('div.settings__info-item', [
h(
'div.settings__info-about',
'MetaMask is designed and built in California.'
),
]),
]),
this.renderInfoLinks(),
]),
])
)

@ -484,6 +484,11 @@ function reduceApp (state, action) {
warning: action.value || 'Incorrect password. Try again.',
})
case actions.UNLOCK_SUCCEEDED:
return extend(appState, {
warning: '',
})
case actions.SHOW_LOADING:
return extend(appState, {
isLoading: true,

@ -2503,6 +2503,24 @@ component-inherit@0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
compressible@~2.0.11:
version "2.0.12"
resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.12.tgz#c59a5c99db76767e9876500e271ef63b3493bd66"
dependencies:
mime-db ">= 1.30.0 < 2"
compression@^1.7.1:
version "1.7.1"
resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.1.tgz#eff2603efc2e22cf86f35d2eb93589f9875373db"
dependencies:
accepts "~1.3.4"
bytes "3.0.0"
compressible "~2.0.11"
debug "2.6.9"
on-headers "~1.0.1"
safe-buffer "5.1.1"
vary "~1.1.2"
concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
@ -3805,7 +3823,18 @@ eth-block-tracker@^1.0.7:
pify "^2.3.0"
tape "^4.6.3"
eth-block-tracker@^2.1.2, eth-block-tracker@^2.2.0, eth-block-tracker@^2.2.2:
eth-block-tracker@^2.1.2, eth-block-tracker@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-2.2.2.tgz#b3d72cd82ba5ee37471d22bac4f56387ee4137cf"
dependencies:
async-eventemitter ahultgren/async-eventemitter#fa06e39e56786ba541c180061dbf2c0a5bbf951c
babelify "^7.3.0"
eth-query "^2.1.0"
ethjs-util "^0.1.3"
pify "^2.3.0"
tape "^4.6.3"
eth-block-tracker@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/eth-block-tracker/-/eth-block-tracker-2.3.0.tgz#4cb782c8ef8fde2f5dc894921ae1f5c1077c35a4"
dependencies:
@ -3849,7 +3878,7 @@ eth-json-rpc-filters@^1.2.5:
json-rpc-engine "^3.4.0"
lodash.flatmap "^4.5.0"
eth-json-rpc-infura@^2.0.5:
eth-json-rpc-infura@^2.0.11:
version "2.0.11"
resolved "https://registry.yarnpkg.com/eth-json-rpc-infura/-/eth-json-rpc-infura-2.0.11.tgz#134bf54ff15e96a9116424c0db9b66aa079bfbbe"
dependencies:
@ -6379,16 +6408,27 @@ json-parse-better-errors@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz#50183cd1b2d25275de069e9e71b467ac9eab973a"
json-rpc-engine@3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.2.0.tgz#d34dff106c8339c337a894da801f73b1f77b1bc8"
json-rpc-engine@^3.0.1, json-rpc-engine@^3.1.0, json-rpc-engine@^3.4.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.4.0.tgz#8a1647a7f2cc7018f4802f41ec8208d281f78bfc"
dependencies:
async "^2.0.1"
babel-preset-env "^1.3.2"
babelify "^7.3.0"
json-rpc-error "^2.0.0"
promise-to-callback "^1.0.0"
json-rpc-engine@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.6.0.tgz#0cc673dcb4b71103523fec81d1bba195a457f993"
dependencies:
async "^2.0.1"
babel-preset-env "^1.3.2"
babelify "^7.3.0"
json-rpc-error "^2.0.0"
promise-to-callback "^1.0.0"
json-rpc-engine@^3.0.1, json-rpc-engine@^3.1.0, json-rpc-engine@^3.4.0, json-rpc-engine@^3.6.0:
json-rpc-engine@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-3.6.1.tgz#f53084726dc6dedeead0e2c457eeb997135f1e25"
dependencies:
@ -7341,6 +7381,10 @@ miller-rabin@^4.0.0:
bn.js "^4.0.0"
brorand "^1.0.1"
"mime-db@>= 1.30.0 < 2":
version "1.32.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.32.0.tgz#485b3848b01a3cda5f968b4882c0771e58e09414"
mime-db@~1.30.0:
version "1.30.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.30.0.tgz#74c643da2dd9d6a45399963465b26d5ca7d71f01"
@ -8040,6 +8084,10 @@ on-finished@~2.3.0:
dependencies:
ee-first "1.1.1"
on-headers@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.1.tgz#928f5d0f470d49342651ea6794b0857c100693f7"
once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.3.3, once@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@ -8479,6 +8527,10 @@ polyfill-crypto.getrandomvalues@^1.0.0:
dependencies:
mersenne-twister "^1.0.1"
popper.js@^1.11.1:
version "1.13.0"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.13.0.tgz#e1e7ff65cc43f7cf9cf16f1510a75e81f84f4565"
portfinder@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-0.2.1.tgz#b2b9b0164f9e17fa3a9c7db2304d0a75140c71ad"
@ -9040,6 +9092,12 @@ react-testutils-additions@^15.2.0:
object-assign "3.0.0"
sizzle "2.3.3"
react-tippy@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/react-tippy/-/react-tippy-1.2.2.tgz#061467d34d29e7a5a9421822d125c451d6bb5153"
dependencies:
popper.js "^1.11.1"
react-toggle-button@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-toggle-button/-/react-toggle-button-2.2.0.tgz#a1b92143aa0df414642fcb141f0879f545bc5a89"
@ -11553,7 +11611,31 @@ weak@^1.0.0:
bindings "^1.2.1"
nan "^2.0.5"
web3-provider-engine@^13.3.2, web3-provider-engine@^13.5.0:
web3-provider-engine@^13.3.2:
version "13.4.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.4.0.tgz#78c2794ba926d0c5b94c6e8955abb994bb8e8854"
dependencies:
async "^2.5.0"
clone "^2.0.0"
eth-block-tracker "^2.2.2"
eth-sig-util "^1.3.0"
ethereumjs-block "^1.2.2"
ethereumjs-tx "^1.2.0"
ethereumjs-util "^5.1.1"
ethereumjs-vm "^2.0.2"
fetch-ponyfill "^4.0.0"
json-rpc-error "^2.0.0"
json-stable-stringify "^1.0.1"
promise-to-callback "^1.0.0"
readable-stream "^2.2.9"
request "^2.67.0"
semaphore "^1.0.3"
solc "^0.4.2"
tape "^4.4.0"
xhr "^2.2.0"
xtend "^4.0.1"
web3-provider-engine@^13.5.6:
version "13.6.0"
resolved "https://registry.yarnpkg.com/web3-provider-engine/-/web3-provider-engine-13.6.0.tgz#836f51c4ee48bd7583acf3696033779c704c2214"
dependencies:

Loading…
Cancel
Save