aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md8
-rw-r--r--README.md3
-rw-r--r--app/manifest.json2
-rw-r--r--app/scripts/config.js5
-rw-r--r--app/scripts/lib/auto-reload.js5
-rw-r--r--app/scripts/lib/tx-utils.js14
-rw-r--r--package.json2
-rw-r--r--ui/app/account-detail.js121
-rw-r--r--ui/app/components/buy-button-subview.js156
-rw-r--r--ui/app/components/dropdowns/components/account-dropdowns.js11
10 files changed, 271 insertions, 56 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f0151e6d..516e8f9e8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,12 +2,16 @@
## Current Master
+- Added a deprecation warning for web3 https://github.com/ethereum/mist/releases/tag/v0.9.0
+
+## 3.9.6 2017-8-09
+
- Replace account screen with an account drop-down menu.
-- Replace confusing buttons with a new account-specific drop-down menu.
+- Replace account buttons with a new account-specific drop-down menu.
## 3.9.5 2017-8-04
-- Improved phishing detection configuration update rate
+- Improved phishing detection configuration update rate
## 3.9.4 2017-8-03
diff --git a/README.md b/README.md
index e39058790..075db79c2 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-# MetaMask Plugin [![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/)
+# MetaMask Plugin
+[![Build Status](https://circleci.com/gh/MetaMask/metamask-extension.svg?style=shield&circle-token=a1ddcf3cd38e29267f254c9c59d556d513e3a1fd)](https://circleci.com/gh/MetaMask/metamask-extension) [![Coverage Status](https://coveralls.io/repos/github/MetaMask/metamask-extension/badge.svg?branch=master)](https://coveralls.io/github/MetaMask/metamask-extension?branch=master) [![Greenkeeper badge](https://badges.greenkeeper.io/MetaMask/metamask-extension.svg)](https://greenkeeper.io/) [![Stories in Ready](https://badge.waffle.io/MetaMask/metamask-extension.png?label=in%20progress&title=waffle.io)](http://waffle.io/MetaMask/metamask-extension)
## Support
diff --git a/app/manifest.json b/app/manifest.json
index 3b9194eb9..f34bdcec3 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "3.9.5",
+ "version": "3.9.6",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",
diff --git a/app/scripts/config.js b/app/scripts/config.js
index 8e28db80e..c5f260583 100644
--- a/app/scripts/config.js
+++ b/app/scripts/config.js
@@ -12,4 +12,9 @@ module.exports = {
kovan: KOVAN_RPC_URL,
rinkeby: RINKEBY_RPC_URL,
},
+ networkNames: {
+ 3: 'Ropsten',
+ 4: 'Rinkeby',
+ 42: 'Kovan',
+ },
}
diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js
index 534047330..6abce73ea 100644
--- a/app/scripts/lib/auto-reload.js
+++ b/app/scripts/lib/auto-reload.js
@@ -5,7 +5,10 @@ function setupDappAutoReload (web3, observable) {
global.web3 = new Proxy(web3, {
get: (_web3, name) => {
// get the time of use
- if (name !== '_used') _web3._used = Date.now()
+ if (name !== '_used') {
+ console.warn('MetaMask: web3 will be deprecated in the near future in favor of the ethereumProvider \nhttps://github.com/ethereum/mist/releases/tag/v0.9.0')
+ _web3._used = Date.now()
+ }
return _web3[name]
},
set: (_web3, name, value) => {
diff --git a/app/scripts/lib/tx-utils.js b/app/scripts/lib/tx-utils.js
index b64ea6712..5af078dc4 100644
--- a/app/scripts/lib/tx-utils.js
+++ b/app/scripts/lib/tx-utils.js
@@ -20,7 +20,15 @@ module.exports = class txProvideUtil {
async analyzeGasUsage (txMeta) {
const block = await this.query.getBlockByNumber('latest', true)
- const estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit)
+ let estimatedGasHex
+ try {
+ estimatedGasHex = await this.estimateTxGas(txMeta, block.gasLimit)
+ } catch (err) {
+ if (err.message.includes('Transaction execution error.')) {
+ txMeta.simulationFails = true
+ return txMeta
+ }
+ }
this.setTxGas(txMeta, block.gasLimit, estimatedGasHex)
return txMeta
}
@@ -35,8 +43,8 @@ module.exports = class txProvideUtil {
const saferGasLimitBN = BnMultiplyByFraction(blockGasLimitBN, 19, 20)
txParams.gas = bnToHex(saferGasLimitBN)
}
- // run tx, see if it will OOG
- return this.query.estimateGas(txParams)
+ // run tx
+ return await this.query.estimateGas(txParams)
}
setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) {
diff --git a/package.json b/package.json
index d6b5752d0..8092e03c5 100644
--- a/package.json
+++ b/package.json
@@ -80,7 +80,7 @@
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
"ethereumjs-wallet": "^0.6.0",
"ethjs-ens": "^2.0.0",
- "ethjs-query": "^0.2.6",
+ "ethjs-query": "^0.2.9",
"express": "^4.14.0",
"extension-link-enabler": "^1.0.0",
"extensionizer": "^1.0.0",
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
new file mode 100644
index 000000000..2be5d5c3a
--- /dev/null
+++ b/ui/app/account-detail.js
@@ -0,0 +1,121 @@
+const inherits = require('util').inherits
+const extend = require('xtend')
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const connect = require('react-redux').connect
+const actions = require('./actions')
+const valuesFor = require('./util').valuesFor
+const Identicon = require('./components/identicon')
+const EthBalance = require('./components/eth-balance')
+const TransactionList = require('./components/transaction-list')
+const ExportAccountView = require('./components/account-export')
+const ethUtil = require('ethereumjs-util')
+const EditableLabel = require('./components/editable-label')
+const TabBar = require('./components/tab-bar')
+const TokenList = require('./components/token-list')
+const AccountDropdowns = require('./components/account-dropdowns').AccountDropdowns
+
+module.exports = connect(mapStateToProps)(AccountDetailScreen)
+
+function mapStateToProps (state) {
+ return {
+ metamask: state.metamask,
+ identities: state.metamask.identities,
+ accounts: state.metamask.accounts,
+ address: state.metamask.selectedAddress,
+ accountDetail: state.appState.accountDetail,
+ network: state.metamask.network,
+ unapprovedMsgs: valuesFor(state.metamask.unapprovedMsgs),
+ shapeShiftTxList: state.metamask.shapeShiftTxList,
+ transactions: state.metamask.selectedAddressTxList || [],
+ conversionRate: state.metamask.conversionRate,
+ currentCurrency: state.metamask.currentCurrency,
+ currentAccountTab: state.metamask.currentAccountTab,
+ tokens: state.metamask.tokens,
+ }
+}
+
+inherits(AccountDetailScreen, Component)
+function AccountDetailScreen () {
+ Component.call(this)
+}
+
+// Note: This component is no longer used. Leaving the file for reference:
+// - structuring routing for add token
+// - state required for TxList
+// Delete file when those features are complete
+AccountDetailScreen.prototype.render = function () {}
+
+AccountDetailScreen.prototype.subview = function () {
+ var subview
+ try {
+ subview = this.props.accountDetail.subview
+ } catch (e) {
+ subview = null
+ }
+
+ switch (subview) {
+ case 'transactions':
+ return this.tabSections()
+ case 'export':
+ var state = extend({key: 'export'}, this.props)
+ return h(ExportAccountView, state)
+ default:
+ return this.tabSections()
+ }
+}
+
+AccountDetailScreen.prototype.tabSections = function () {
+ const { currentAccountTab } = this.props
+
+ return h('section.tabSection.full-flex-height.grow-tenx', [
+
+ h(TabBar, {
+ tabs: [
+ { content: 'Sent', key: 'history' },
+ { content: 'Tokens', key: 'tokens' },
+ ],
+ defaultTab: currentAccountTab || 'history',
+ tabSelected: (key) => {
+ this.props.dispatch(actions.setCurrentAccountTab(key))
+ },
+ }),
+
+ this.tabSwitchView(),
+ ])
+}
+
+AccountDetailScreen.prototype.tabSwitchView = function () {
+ const props = this.props
+ const { address, network } = props
+ const { currentAccountTab, tokens } = this.props
+
+ switch (currentAccountTab) {
+ case 'tokens':
+ return h(TokenList, {
+ userAddress: address,
+ network,
+ tokens,
+ addToken: () => this.props.dispatch(actions.showAddTokenPage()),
+ })
+ default:
+ return this.transactionList()
+ }
+}
+
+AccountDetailScreen.prototype.transactionList = function () {
+ const {transactions, unapprovedMsgs, address,
+ network, shapeShiftTxList, conversionRate } = this.props
+
+ return h(TransactionList, {
+ transactions: transactions.sort((a, b) => b.time - a.time),
+ network,
+ unapprovedMsgs,
+ conversionRate,
+ address,
+ shapeShiftTxList,
+ viewPendingTx: (txId) => {
+ this.props.dispatch(actions.viewPendingTx(txId))
+ },
+ })
+}
diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js
index 759eb15bd..15281171c 100644
--- a/ui/app/components/buy-button-subview.js
+++ b/ui/app/components/buy-button-subview.js
@@ -8,6 +8,7 @@ const ShapeshiftForm = require('./shapeshift-form')
const Loading = require('./loading')
const AccountPanel = require('./account-panel')
const RadioList = require('./custom-radio-list')
+const networkNames = require('../../../app/scripts/config.js').networkNames
module.exports = connect(mapStateToProps)(BuyButtonSubview)
@@ -30,16 +31,30 @@ function BuyButtonSubview () {
}
BuyButtonSubview.prototype.render = function () {
+ return (
+ h('div', {
+ style: {
+ width: '100%',
+ },
+ }, [
+ this.headerSubview(),
+ this.primarySubview(),
+ ])
+ )
+}
+
+BuyButtonSubview.prototype.headerSubview = function () {
const props = this.props
const isLoading = props.isSubLoading
-
return (
- h('.buy-eth-section.flex-column', {
+
+ h('.flex-column', {
style: {
alignItems: 'center',
},
}, [
- // back button
+
+ // header bar (back button, label)
h('.flex-row', {
style: {
alignItems: 'center',
@@ -63,6 +78,8 @@ BuyButtonSubview.prototype.render = function () {
},
}, 'Buy Eth'),
]),
+
+ // loading indication
h('div', {
style: {
position: 'absolute',
@@ -70,8 +87,10 @@ BuyButtonSubview.prototype.render = function () {
left: '49vw',
},
}, [
- h(Loading, {isLoading}),
+ h(Loading, { isLoading }),
]),
+
+ // account panel
h('div', {
style: {
width: '80%',
@@ -83,17 +102,92 @@ BuyButtonSubview.prototype.render = function () {
account: props.account,
}),
]),
- h('h3.text-transform-uppercase', {
+
+ h('.flex-row', {
style: {
- paddingLeft: '15px',
- fontFamily: 'Montserrat Light',
- width: '100vw',
- background: 'rgb(235, 235, 235)',
- color: 'rgb(174, 174, 174)',
- paddingTop: '4px',
- paddingBottom: '4px',
+ alignItems: 'center',
+ justifyContent: 'center',
},
- }, 'Select Service'),
+ }, [
+ h('h3.text-transform-uppercase.flex-center', {
+ style: {
+ paddingLeft: '15px',
+ width: '100vw',
+ background: 'rgb(235, 235, 235)',
+ color: 'rgb(174, 174, 174)',
+ paddingTop: '4px',
+ paddingBottom: '4px',
+ },
+ }, 'Select Service'),
+ ]),
+
+ ])
+
+ )
+}
+
+
+BuyButtonSubview.prototype.primarySubview = function () {
+ const props = this.props
+ const network = props.network
+
+ switch (network) {
+ case 'loading':
+ return
+
+ case '1':
+ return this.mainnetSubview()
+
+ // Ropsten, Rinkeby, Kovan
+ case '3':
+ case '4':
+ case '42':
+ const networkName = networkNames[network]
+ const label = `${networkName} Test Faucet`
+ return (
+ h('div.flex-column', {
+ style: {
+ alignItems: 'center',
+ margin: '20px 50px',
+ },
+ }, [
+ h('button.text-transform-uppercase', {
+ onClick: () => this.props.dispatch(actions.buyEth({ network })),
+ style: {
+ marginTop: '15px',
+ },
+ }, label),
+ // Kovan only: Dharma loans beta
+ network === '42' ? (
+ h('button.text-transform-uppercase', {
+ onClick: () => this.navigateTo('https://borrow.dharma.io/'),
+ style: {
+ marginTop: '15px',
+ },
+ }, 'Borrow With Dharma (Beta)')
+ ) : null,
+ ])
+ )
+
+ default:
+ return (
+ h('h2.error', 'Unknown network ID')
+ )
+
+ }
+}
+
+BuyButtonSubview.prototype.mainnetSubview = function () {
+ const props = this.props
+
+ return (
+
+ h('.flex-column', {
+ style: {
+ alignItems: 'center',
+ },
+ }, [
+
h('.flex-row.selected-exchange', {
style: {
position: 'relative',
@@ -115,6 +209,7 @@ BuyButtonSubview.prototype.render = function () {
onClick: this.radioHandler.bind(this),
}),
]),
+
h('h3.text-transform-uppercase', {
style: {
paddingLeft: '15px',
@@ -126,8 +221,10 @@ BuyButtonSubview.prototype.render = function () {
paddingBottom: '4px',
},
}, props.buyView.subview),
+
this.formVersionSubview(),
])
+
)
}
@@ -139,39 +236,6 @@ BuyButtonSubview.prototype.formVersionSubview = function () {
} else if (this.props.buyView.formView.shapeshift) {
return h(ShapeshiftForm, this.props)
}
- } else {
- return h('div.flex-column', {
- style: {
- alignItems: 'center',
- margin: '20px 50px',
- },
- }, [
- h('h3.text-transform-uppercase', {
- style: {
- width: '225px',
- marginBottom: '15px',
- },
- }, 'In order to access this feature, please switch to the Main Network'),
- ((network === '3') || (network === '4') || (network === '42')) ? h('h3.text-transform-uppercase', 'or go to the') : null,
- (network === '3') ? h('button.text-transform-uppercase', {
- onClick: () => this.props.dispatch(actions.buyEth({ network })),
- style: {
- marginTop: '15px',
- },
- }, 'Ropsten Test Faucet') : null,
- (network === '4') ? h('button.text-transform-uppercase', {
- onClick: () => this.props.dispatch(actions.buyEth({ network })),
- style: {
- marginTop: '15px',
- },
- }, 'Rinkeby Test Faucet') : null,
- (network === '42') ? h('button.text-transform-uppercase', {
- onClick: () => this.props.dispatch(actions.buyEth({ network })),
- style: {
- marginTop: '15px',
- },
- }, 'Kovan Test Faucet') : null,
- ])
}
}
diff --git a/ui/app/components/dropdowns/components/account-dropdowns.js b/ui/app/components/dropdowns/components/account-dropdowns.js
index 11d109d73..b59f9bbf4 100644
--- a/ui/app/components/dropdowns/components/account-dropdowns.js
+++ b/ui/app/components/dropdowns/components/account-dropdowns.js
@@ -56,7 +56,16 @@ class AccountDropdowns extends Component {
},
},
),
- h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, identity.name || ''),
+ h('span', {
+ style: {
+ marginLeft: '20px',
+ fontSize: '24px',
+ maxWidth: '145px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden',
+ textOverflow: 'ellipsis',
+ },
+ }, identity.name || ''),
h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, isSelected ? h('.check', '✓') : null),
]
)