aboutsummaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDan Finlay <dan@danfinlay.com>2016-08-30 07:14:51 +0800
committerDan Finlay <dan@danfinlay.com>2016-08-30 07:14:51 +0800
commite85418b11ad14bf6f0cc3fdbcdbb5669330c4778 (patch)
treedf71d73fa1533cea8b36fb24db90e02a07766607 /ui
parent40d5b446cfbea436a012d1799d0d7710caca752c (diff)
parenta9c738d4d3226f61942641a41c399c75a3e9eb3e (diff)
downloadtangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar.gz
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar.bz2
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar.lz
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar.xz
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.tar.zst
tangerine-wallet-browser-e85418b11ad14bf6f0cc3fdbcdbb5669330c4778.zip
Merge branch 'master' into EdgeCompatibility
Diffstat (limited to 'ui')
-rw-r--r--ui/app/account-detail.js39
-rw-r--r--ui/app/accounts/account-list-item.js8
-rw-r--r--ui/app/actions.js227
-rw-r--r--ui/app/app.js151
-rw-r--r--ui/app/components/account-eth-balance.js140
-rw-r--r--ui/app/components/account-info-link.js42
-rw-r--r--ui/app/components/buy-button-subview.js123
-rw-r--r--ui/app/components/coinbase-form.js162
-rw-r--r--ui/app/components/drop-menu-item.js3
-rw-r--r--ui/app/components/eth-balance.js21
-rw-r--r--ui/app/components/mascot.js18
-rw-r--r--ui/app/components/network.js16
-rw-r--r--ui/app/components/pending-msg-details.js9
-rw-r--r--ui/app/components/qr-code.js71
-rw-r--r--ui/app/components/shapeshift-form.js322
-rw-r--r--ui/app/components/shift-list-item.js202
-rw-r--r--ui/app/components/transaction-list-item.js9
-rw-r--r--ui/app/components/transaction-list.js33
-rw-r--r--ui/app/conf-tx.js8
-rw-r--r--ui/app/config.js25
-rw-r--r--ui/app/conversion-util.js5
-rw-r--r--ui/app/css/index.css125
-rw-r--r--ui/app/eth-store-warning.js7
-rw-r--r--ui/app/first-time/init-menu.js2
-rw-r--r--ui/app/first-time/restore-vault.js17
-rw-r--r--ui/app/reducers/app.js144
-rw-r--r--ui/app/reducers/metamask.js13
-rw-r--r--ui/app/send.js19
-rw-r--r--ui/app/store.js15
-rw-r--r--ui/app/unlock.js82
-rw-r--r--ui/app/util.js21
-rw-r--r--ui/lib/account-link.js18
-rw-r--r--ui/lib/persistent-form.js57
33 files changed, 1999 insertions, 155 deletions
diff --git a/ui/app/account-detail.js b/ui/app/account-detail.js
index b1b0495eb..486a1a633 100644
--- a/ui/app/account-detail.js
+++ b/ui/app/account-detail.js
@@ -4,22 +4,24 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const CopyButton = require('./components/copyButton')
+const AccountInfoLink = require('./components/account-info-link')
const actions = require('./actions')
const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
const valuesFor = require('./util').valuesFor
const Identicon = require('./components/identicon')
-const EtherBalance = require('./components/eth-balance')
+const AccountEtherBalance = require('./components/account-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 Tooltip = require('./components/tooltip')
-
+const BuyButtonSubview = require('./components/buy-button-subview')
module.exports = connect(mapStateToProps)(AccountDetailScreen)
function mapStateToProps (state) {
return {
+ metamask: state.metamask,
identities: state.metamask.identities,
accounts: state.metamask.accounts,
address: state.metamask.selectedAccount,
@@ -29,6 +31,7 @@ function mapStateToProps (state) {
unconfTxs: valuesFor(state.metamask.unconfTxs),
unconfMsgs: valuesFor(state.metamask.unconfMsgs),
isEthWarningConfirmed: state.metamask.isEthConfirmed,
+ shapeShiftTxList: state.metamask.shapeShiftTxList,
}
}
@@ -42,6 +45,7 @@ AccountDetailScreen.prototype.render = function () {
var selected = props.address || Object.keys(props.accounts)[0]
var identity = props.identities[selected]
var account = props.accounts[selected]
+ const { network } = props
return (
@@ -125,6 +129,9 @@ AccountDetailScreen.prototype.render = function () {
bottom: '15px',
},
}, [
+
+ h(AccountInfoLink, { selected, network }),
+
h(CopyButton, {
value: ethUtil.toChecksumAddress(selected),
}),
@@ -134,16 +141,15 @@ AccountDetailScreen.prototype.render = function () {
}, [
h('div', {
style: {
- margin: '5px',
+ display: 'flex',
+ alignItems: 'center',
},
}, [
h('img.cursor-pointer.color-orange', {
src: 'images/key-32.png',
onClick: () => this.requestAccountExport(selected),
style: {
- margin: '0px 5px',
- width: '20px',
- height: '20px',
+ height: '19px',
},
}),
]),
@@ -162,9 +168,8 @@ AccountDetailScreen.prototype.render = function () {
},
}, [
- h(EtherBalance, {
+ h(AccountEtherBalance, {
value: account && account.balance,
- mainBalance: true,
style: {
lineHeight: '7px',
marginTop: '10px',
@@ -172,7 +177,7 @@ AccountDetailScreen.prototype.render = function () {
}),
h('button', {
- onClick: () => props.dispatch(actions.buyEth(selected)),
+ onClick: () => props.dispatch(actions.buyEthView(selected)),
style: {
marginBottom: '20px',
marginRight: '8px',
@@ -220,13 +225,15 @@ AccountDetailScreen.prototype.subview = function () {
case 'export':
var state = extend({key: 'export'}, this.props)
return h(ExportAccountView, state)
+ case 'buyForm':
+ return h(BuyButtonSubview, extend({key: 'buyForm'}, this.props))
default:
return this.transactionList()
}
}
AccountDetailScreen.prototype.transactionList = function () {
- const { transactions, unconfTxs, unconfMsgs, address, network } = this.props
+ const { transactions, unconfTxs, unconfMsgs, address, network, shapeShiftTxList } = this.props
var txsToRender = transactions
// only transactions that are from the current address
@@ -241,6 +248,8 @@ AccountDetailScreen.prototype.transactionList = function () {
network,
unconfTxs,
unconfMsgs,
+ address,
+ shapeShiftTxList,
viewPendingTx: (txId) => {
this.props.dispatch(actions.viewPendingTx(txId))
},
@@ -251,3 +260,13 @@ AccountDetailScreen.prototype.requestAccountExport = function () {
this.props.dispatch(actions.requestExportAccount())
}
+
+AccountDetailScreen.prototype.buyButtonDeligator = function () {
+ var props = this.props
+
+ if (this.props.accountDetail.subview === 'buyForm') {
+ props.dispatch(actions.backToAccountDetail(props.address))
+ } else {
+ props.dispatch(actions.buyEthView())
+ }
+}
diff --git a/ui/app/accounts/account-list-item.js b/ui/app/accounts/account-list-item.js
index 1010516e2..aa80e0e23 100644
--- a/ui/app/accounts/account-list-item.js
+++ b/ui/app/accounts/account-list-item.js
@@ -3,7 +3,7 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const ethUtil = require('ethereumjs-util')
-const EtherBalance = require('../components/eth-balance')
+const AccountEtherBalance = require('../components/account-eth-balance')
const CopyButton = require('../components/copyButton')
const Identicon = require('../components/identicon')
@@ -50,8 +50,12 @@ NewComponent.prototype.render = function () {
textOverflow: 'ellipsis',
},
}, ethUtil.toChecksumAddress(identity.address)),
- h(EtherBalance, {
+ h(AccountEtherBalance, {
value: account.balance,
+ style: {
+ lineHeight: '7px',
+ marginTop: '10px',
+ },
}),
]),
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 82a319907..c92138f68 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -55,6 +55,8 @@ var actions = {
SHOW_CONF_MSG_PAGE: 'SHOW_CONF_MSG_PAGE',
REVEAL_ACCOUNT: 'REVEAL_ACCOUNT',
revealAccount: revealAccount,
+ SET_CURRENT_FIAT: 'SET_CURRENT_FIAT',
+ setCurrentFiat: setCurrentFiat,
// account detail screen
SHOW_SEND_PAGE: 'SHOW_SEND_PAGE',
showSendPage: showSendPage,
@@ -113,6 +115,34 @@ var actions = {
// buy Eth with coinbase
BUY_ETH: 'BUY_ETH',
buyEth: buyEth,
+ buyEthView: buyEthView,
+ BUY_ETH_VIEW: 'BUY_ETH_VIEW',
+ UPDATE_COINBASE_AMOUNT: 'UPDATE_COIBASE_AMOUNT',
+ updateCoinBaseAmount: updateCoinBaseAmount,
+ UPDATE_BUY_ADDRESS: 'UPDATE_BUY_ADDRESS',
+ updateBuyAddress: updateBuyAddress,
+ COINBASE_SUBVIEW: 'COINBASE_SUBVIEW',
+ coinBaseSubview: coinBaseSubview,
+ SHAPESHIFT_SUBVIEW: 'SHAPESHIFT_SUBVIEW',
+ shapeShiftSubview: shapeShiftSubview,
+ PAIR_UPDATE: 'PAIR_UPDATE',
+ pairUpdate: pairUpdate,
+ coinShiftRquest: coinShiftRquest,
+ SHOW_SUB_LOADING_INDICATION: 'SHOW_SUB_LOADING_INDICATION',
+ showSubLoadingIndication: showSubLoadingIndication,
+ HIDE_SUB_LOADING_INDICATION: 'HIDE_SUB_LOADING_INDICATION',
+ hideSubLoadingIndication: hideSubLoadingIndication,
+// QR STUFF:
+ SHOW_QR: 'SHOW_QR',
+ getQr: getQr,
+ reshowQrCode: reshowQrCode,
+ SHOW_QR_VIEW: 'SHOW_QR_VIEW',
+// FORGOT PASSWORD:
+ BACK_TO_INIT_MENU: 'BACK_TO_INIT_MENU',
+ goBackToInitView: goBackToInitView,
+ RECOVERY_IN_PROGRESS: 'RECOVERY_IN_PROGRESS',
+ BACK_TO_UNLOCK_VIEW: 'BACK_TO_UNLOCK_VIEW',
+ backToUnlockView: backToUnlockView,
}
module.exports = actions
@@ -214,6 +244,23 @@ function revealAccount () {
}
}
+function setCurrentFiat (fiat) {
+ return (dispatch) => {
+ dispatch(this.showLoadingIndication())
+ _accountManager.setCurrentFiat(fiat, (data, err) => {
+ dispatch(this.hideLoadingIndication())
+ dispatch({
+ type: this.SET_CURRENT_FIAT,
+ value: {
+ currentFiat: data.currentFiat,
+ conversionRate: data.conversionRate,
+ conversionDate: data.conversionDate,
+ },
+ })
+ })
+ }
+}
+
function signMsg (msgData) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
@@ -329,6 +376,12 @@ function showNewVaultSeed (seed) {
}
}
+function backToUnlockView () {
+ return {
+ type: actions.BACK_TO_UNLOCK_VIEW,
+ }
+}
+
//
// unlock screen
//
@@ -457,6 +510,12 @@ function showConfigPage (transitionForward = true) {
}
}
+function goBackToInitView () {
+ return {
+ type: actions.BACK_TO_INIT_MENU,
+ }
+}
+
//
// config
//
@@ -496,6 +555,18 @@ function hideLoadingIndication () {
}
}
+function showSubLoadingIndication () {
+ return {
+ type: actions.SHOW_SUB_LOADING_INDICATION,
+ }
+}
+
+function hideSubLoadingIndication () {
+ return {
+ type: actions.HIDE_SUB_LOADING_INDICATION,
+ }
+}
+
function showWarning (text) {
return this.displayWarning(text)
}
@@ -594,3 +665,159 @@ function buyEth (address, amount) {
})
}
}
+
+function buyEthView (address) {
+ return {
+ type: actions.BUY_ETH_VIEW,
+ value: address,
+ }
+}
+
+function updateCoinBaseAmount (value) {
+ return {
+ type: actions.UPDATE_COINBASE_AMOUNT,
+ value,
+ }
+}
+
+function updateBuyAddress (value) {
+ return {
+ type: actions.UPDATE_BUY_ADDRESS,
+ value,
+ }
+}
+
+function coinBaseSubview () {
+ return {
+ type: actions.COINBASE_SUBVIEW,
+ }
+}
+
+function pairUpdate (coin) {
+ return (dispatch) => {
+ dispatch(actions.showSubLoadingIndication())
+ dispatch(actions.hideWarning())
+ shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
+ dispatch(actions.hideSubLoadingIndication())
+ dispatch({
+ type: actions.PAIR_UPDATE,
+ value: {
+ marketinfo: mktResponse,
+ },
+ })
+ })
+ }
+}
+
+function shapeShiftSubview (network) {
+ var pair = 'btc_eth'
+
+ return (dispatch) => {
+ dispatch(actions.showSubLoadingIndication())
+ shapeShiftRequest('marketinfo', {pair}, (mktResponse) => {
+ shapeShiftRequest('getcoins', {}, (response) => {
+ dispatch(actions.hideSubLoadingIndication())
+ if (mktResponse.error) return dispatch(actions.showWarning(mktResponse.error))
+ dispatch({
+ type: actions.SHAPESHIFT_SUBVIEW,
+ value: {
+ marketinfo: mktResponse,
+ coinOptions: response,
+ },
+ })
+ })
+ })
+ }
+}
+
+function coinShiftRquest (data, marketData) {
+ return (dispatch) => {
+ dispatch(actions.showLoadingIndication())
+ shapeShiftRequest('shift', { method: 'POST', data}, (response) => {
+ if (response.error) return dispatch(actions.showWarning(response.error))
+ var message = `
+ Deposit your ${response.depositType} to the address bellow:`
+ _accountManager.createShapeShiftTx(response.deposit, response.depositType)
+ dispatch(actions.getQr(response.deposit, '125x125', [message].concat(marketData)))
+ })
+ }
+}
+
+function getQr (data, size, message) {
+ return (dispatch) => {
+ qrRequest(data, size, (response) => {
+ dispatch(actions.hideLoadingIndication())
+ if (response.error) return dispatch(actions.showWarning(response.error))
+ dispatch({
+ type: actions.SHOW_QR,
+ value: {
+ qr: response,
+ message: message,
+ data: data,
+ },
+ })
+ })
+ }
+}
+function reshowQrCode (data, coin) {
+ return (dispatch) => {
+ dispatch(actions.showLoadingIndication())
+ shapeShiftRequest('marketinfo', {pair: `${coin.toLowerCase()}_eth`}, (mktResponse) => {
+ if (mktResponse.error) return dispatch(actions.showWarning(mktResponse.error))
+
+ var message = [
+ `Deposit your ${coin} to the address bellow:`,
+ `Deposit Limit: ${mktResponse.limit}`,
+ `Deposit Minimum:${mktResponse.minimum}`,
+ ]
+
+ qrRequest(data, '125x125', (response) => {
+ dispatch(actions.hideLoadingIndication())
+ dispatch({
+ type: actions.SHOW_QR_VIEW,
+ value: {
+ qr: response,
+ message: message,
+ data: data,
+ },
+ })
+ })
+ })
+ }
+}
+
+function shapeShiftRequest (query, options, cb) {
+ var queryResponse, method
+ !options ? options = {} : null
+ options.method ? method = options.method : method = 'GET'
+
+ var requestListner = function (request) {
+ queryResponse = JSON.parse(this.responseText)
+ cb ? cb(queryResponse) : null
+ return queryResponse
+ }
+
+ var shapShiftReq = new XMLHttpRequest()
+ shapShiftReq.addEventListener('load', requestListner)
+ shapShiftReq.open(method, `https://shapeshift.io/${query}/${options.pair ? options.pair : ''}`, true)
+
+ if (options.method === 'POST') {
+ var jsonObj = JSON.stringify(options.data)
+ shapShiftReq.setRequestHeader('Content-Type', 'application/json')
+ return shapShiftReq.send(jsonObj)
+ } else {
+ return shapShiftReq.send()
+ }
+}
+
+function qrRequest (data, size, cb) {
+ var requestListner = function (request) {
+ cb ? cb(this.responseText) : null
+ return this.responseText
+ }
+
+ var qrReq = new XMLHttpRequest()
+ qrReq.addEventListener('load', requestListner)
+ qrReq.open('GET', `https://api.qrserver.com/v1/create-qr-code/?size=${size}&format=svg&data=${data}`, true)
+ qrReq.send()
+}
diff --git a/ui/app/app.js b/ui/app/app.js
index cc616fb7c..b674efff1 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -28,7 +28,8 @@ const DropMenuItem = require('./components/drop-menu-item')
const NetworkIndicator = require('./components/network')
const Tooltip = require('./components/tooltip')
const EthStoreWarning = require('./eth-store-warning')
-
+const BuyView = require('./components/buy-button-subview')
+const QrView = require('./components/qr-code')
module.exports = connect(mapStateToProps)(App)
inherits(App, Component)
@@ -50,6 +51,7 @@ function mapStateToProps (state) {
menuOpen: state.appState.menuOpen,
network: state.metamask.network,
provider: state.metamask.provider,
+ forgottenPassword: state.appState.forgottenPassword,
}
}
@@ -88,6 +90,7 @@ App.prototype.render = function () {
transitionLeaveTimeout: 300,
}, [
this.renderPrimary(),
+ this.renderBackToInitButton(),
]),
]),
])
@@ -95,6 +98,11 @@ App.prototype.render = function () {
}
App.prototype.renderAppBar = function () {
+
+ if (window.METAMASK_UI_TYPE === 'notification') {
+ return null
+ }
+
const props = this.props
const state = this.state || {}
const isNetworkMenuOpen = state.isNetworkMenuOpen || false
@@ -226,15 +234,6 @@ App.prototype.renderNetworkDropdown = function () {
}),
h(DropMenuItem, {
- label: 'Ethereum Classic Network',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => props.dispatch(actions.setProviderType('classic')),
- icon: h('.menu-icon.hollow-diamond'),
- activeNetworkRender: props.network,
- provider: props.provider,
- }),
-
- h(DropMenuItem, {
label: 'Morden Test Network',
closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
action: () => props.dispatch(actions.setProviderType('testnet')),
@@ -250,6 +249,13 @@ App.prototype.renderNetworkDropdown = function () {
activeNetworkRender: props.provider.rpcTarget,
}),
+ h(DropMenuItem, {
+ label: 'Custom RPC',
+ closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
+ action: () => this.props.dispatch(actions.showConfigPage()),
+ icon: h('i.fa.fa-question-circle.fa-lg', { ariaHidden: true }),
+ }),
+
this.renderCustomOption(props.provider.rpcTarget),
])
}
@@ -301,6 +307,92 @@ App.prototype.renderDropdown = function () {
}),
])
}
+App.prototype.renderBackButton = function (style, justArrow = false) {
+ var props = this.props
+ return (
+ h('.flex-row', {
+ key: 'leftArrow',
+ transForward: false,
+ style: style,
+ onClick: () => props.dispatch(actions.goBackToInitView()),
+ }, [
+ h('i.fa.fa-arrow-left.cursor-pointer'),
+ justArrow ? null : h('div.cursor-pointer', {
+ style: {
+ marginLeft: '3px',
+ },
+ onClick: () => props.dispatch(actions.goBackToInitView()),
+ }, 'BACK'),
+ ])
+ )
+
+}
+App.prototype.renderBackToInitButton = function () {
+ var props = this.props
+ var button = null
+ if (!props.isUnlocked) {
+ if (props.currentView.name === 'InitMenu') {
+ button = props.forgottenPassword ? h('.flex-row', {
+ key: 'rightArrow',
+ style: {
+ position: 'absolute',
+ bottom: '10px',
+ right: '15px',
+ fontSize: '21px',
+ fontFamily: 'Montserrat Light',
+ color: '#7F8082',
+ width: '77.578px',
+ alignItems: 'flex-end',
+ },
+ }, [
+ h('div.cursor-pointer', {
+ style: {
+ marginRight: '3px',
+ },
+ onClick: () => props.dispatch(actions.backToUnlockView()),
+ }, 'LOGIN'),
+ h('i.fa.fa-arrow-right.cursor-pointer'),
+ ]) : null
+ } else if (props.isInitialized) {
+ var style
+ switch (props.currentView.name) {
+ case 'createVault':
+ style = {
+ position: 'absolute',
+ top: '41px',
+ left: '80px',
+ fontSize: '21px',
+ fontFamily: 'Montserrat Bold',
+ color: 'rgb(174, 174, 174)',
+ }
+ return this.renderBackButton(style, true)
+ case 'restoreVault':
+ style = {
+ position: 'absolute',
+ top: '41px',
+ left: '70px',
+ fontSize: '21px',
+ fontFamily: 'Montserrat Bold',
+ color: 'rgb(174, 174, 174)',
+ }
+ return this.renderBackButton(style, true)
+ default:
+ style = {
+ position: 'absolute',
+ bottom: '10px',
+ left: '15px',
+ fontSize: '21px',
+ fontFamily: 'Montserrat Light',
+ color: '#7F8082',
+ width: '71.969px',
+ alignItems: 'flex-end',
+ }
+ return this.renderBackButton(style)
+ }
+ }
+ }
+ return button
+}
App.prototype.renderPrimary = function () {
var props = this.props
@@ -314,7 +406,7 @@ App.prototype.renderPrimary = function () {
}
// show initialize screen
- if (!props.isInitialized) {
+ if (!props.isInitialized || props.forgottenPassword) {
// show current view
switch (props.currentView.name) {
@@ -366,6 +458,35 @@ App.prototype.renderPrimary = function () {
case 'createVault':
return h(CreateVaultScreen, {key: 'createVault'})
+ case 'buyEth':
+ return h(BuyView, {key: 'buyEthView'})
+ case 'qr':
+ return h('div', {
+ style: {
+ position: 'absolute',
+ height: '100%',
+ top: '0px',
+ left: '0px',
+ },
+ }, [
+ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
+ onClick: () => props.dispatch(actions.backToAccountDetail(props.activeAddress)),
+ style: {
+ marginLeft: '10px',
+ marginTop: '50px',
+ },
+ }),
+ h('div', {
+ style: {
+ position: 'absolute',
+ bottom: '115px',
+ left: '44px',
+ width: '285px',
+ },
+ }, [
+ h(QrView, {key: 'qr'}),
+ ]),
+ ])
default:
return h(AccountDetailScreen, {key: 'account-detail'})
@@ -387,12 +508,8 @@ App.prototype.toggleMetamaskActive = function () {
App.prototype.renderCustomOption = function (rpcTarget) {
switch (rpcTarget) {
case undefined:
- return h(DropMenuItem, {
- label: 'Custom RPC',
- closeMenu: () => this.setState({ isNetworkMenuOpen: false }),
- action: () => this.props.dispatch(actions.showConfigPage()),
- icon: h('i.fa.fa-question-circle.fa-lg', { ariaHidden: true }),
- })
+ return null
+
case 'http://localhost:8545':
return h(DropMenuItem, {
label: 'Custom RPC',
diff --git a/ui/app/components/account-eth-balance.js b/ui/app/components/account-eth-balance.js
new file mode 100644
index 000000000..8d693685f
--- /dev/null
+++ b/ui/app/components/account-eth-balance.js
@@ -0,0 +1,140 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const formatBalance = require('../util').formatBalance
+const generateBalanceObject = require('../util').generateBalanceObject
+const Tooltip = require('./tooltip.js')
+
+module.exports = connect(mapStateToProps)(EthBalanceComponent)
+
+function mapStateToProps (state) {
+ return {
+ conversionRate: state.metamask.conversionRate,
+ conversionDate: state.metamask.conversionDate,
+ currentFiat: state.metamask.currentFiat,
+ }
+}
+
+inherits(EthBalanceComponent, Component)
+function EthBalanceComponent () {
+ Component.call(this)
+}
+
+EthBalanceComponent.prototype.render = function () {
+ var state = this.props
+ var style = state.style
+
+ const value = formatBalance(state.value, 6)
+ var width = state.width
+
+ return (
+
+ h('.ether-balance', {
+ style: style,
+ }, [
+ h('.ether-balance-amount', {
+ style: {
+ display: 'inline',
+ width: width,
+ },
+ }, this.renderBalance(value, state)),
+ ])
+
+ )
+}
+EthBalanceComponent.prototype.renderBalance = function (value, state) {
+ if (value === 'None') return value
+ var balanceObj = generateBalanceObject(value, state.shorten ? 1 : 3)
+ var balance, fiatDisplayNumber, fiatTooltipNumber
+ var splitBalance = value.split(' ')
+ var ethNumber = splitBalance[0]
+ var ethSuffix = splitBalance[1]
+
+
+ if (state.conversionRate !== 0) {
+ fiatTooltipNumber = Number(splitBalance[0]) * state.conversionRate
+ fiatDisplayNumber = fiatTooltipNumber.toFixed(2)
+ } else {
+ fiatDisplayNumber = 'N/A'
+ }
+
+ var fiatSuffix = state.currentFiat
+
+ if (state.shorten) {
+ balance = balanceObj.shortBalance
+ } else {
+ balance = balanceObj.balance
+ }
+
+ var label = balanceObj.label
+
+ return (
+ h('.flex-column', [
+ h(Tooltip, {
+ position: 'bottom',
+ title: `${ethNumber} ${ethSuffix}`,
+ }, [
+ h('.flex-row', {
+ style: {
+ alignItems: 'flex-end',
+ lineHeight: '13px',
+ fontFamily: 'Montserrat Light',
+ textRendering: 'geometricPrecision',
+ marginBottom: '5px',
+ },
+ }, [
+ h('div', {
+ style: {
+ width: '100%',
+ textAlign: 'right',
+ },
+ }, balance),
+ h('div', {
+ style: {
+ color: '#AEAEAE',
+ marginLeft: '5px',
+ },
+ }, label),
+ ]),
+ ]),
+ h(Tooltip, {
+ position: 'bottom',
+ title: `${fiatTooltipNumber} ${fiatSuffix}`,
+ }, [
+ fiatDisplay(fiatDisplayNumber, fiatSuffix),
+ ]),
+ ])
+ )
+}
+
+function fiatDisplay (fiatDisplayNumber, fiatSuffix) {
+ if (fiatDisplayNumber !== 'N/A') {
+ return h('.flex-row', {
+ style: {
+ alignItems: 'flex-end',
+ lineHeight: '13px',
+ fontFamily: 'Montserrat Light',
+ textRendering: 'geometricPrecision',
+ },
+ }, [
+ h('div', {
+ style: {
+ width: '100%',
+ textAlign: 'right',
+ fontSize: '12px',
+ color: '#333333',
+ },
+ }, fiatDisplayNumber),
+ h('div', {
+ style: {
+ color: '#AEAEAE',
+ marginLeft: '5px',
+ fontSize: '12px',
+ },
+ }, fiatSuffix),
+ ])
+ } else {
+ return h('div')
+ }
+}
diff --git a/ui/app/components/account-info-link.js b/ui/app/components/account-info-link.js
new file mode 100644
index 000000000..4fe3b8b5d
--- /dev/null
+++ b/ui/app/components/account-info-link.js
@@ -0,0 +1,42 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const Tooltip = require('./tooltip')
+const genAccountLink = require('../../lib/account-link')
+const extension = require('../../../app/scripts/lib/extension')
+
+module.exports = AccountInfoLink
+
+inherits(AccountInfoLink, Component)
+function AccountInfoLink () {
+ Component.call(this)
+}
+
+AccountInfoLink.prototype.render = function () {
+ const { selected, network } = this.props
+ const title = 'View account on etherscan'
+ const url = genAccountLink(selected, network)
+
+ if (!url) {
+ return null
+ }
+
+ return h('.account-info-link', {
+ style: {
+ display: 'flex',
+ alignItems: 'center',
+ },
+ }, [
+
+ h(Tooltip, {
+ title,
+ }, [
+ h('i.fa.fa-info-circle.cursor-pointer.color-orange', {
+ style: {
+ margin: '5px',
+ },
+ onClick () { extension.tabs.create({ url }) },
+ }),
+ ]),
+ ])
+}
diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js
new file mode 100644
index 000000000..742241e5b
--- /dev/null
+++ b/ui/app/components/buy-button-subview.js
@@ -0,0 +1,123 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../actions')
+const CoinbaseForm = require('./coinbase-form')
+const ShapeshiftForm = require('./shapeshift-form')
+const extension = require('../../../app/scripts/lib/extension')
+
+module.exports = connect(mapStateToProps)(BuyButtonSubview)
+
+function mapStateToProps (state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ buyView: state.appState.buyView,
+ network: state.metamask.network,
+ provider: state.metamask.provider,
+ }
+}
+
+inherits(BuyButtonSubview, Component)
+function BuyButtonSubview () {
+ Component.call(this)
+}
+
+BuyButtonSubview.prototype.render = function () {
+ const props = this.props
+ const currentForm = props.buyView.formView
+
+ return (
+ h('.buy-eth-section', [
+ // back button
+ h('.flex-row', {
+ style: {
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ }, [
+ h('i.fa.fa-arrow-left.fa-lg.cursor-pointer.color-orange', {
+ onClick: () => props.dispatch(actions.backToAccountDetail(props.selectedAccount)),
+ style: {
+ position: 'absolute',
+ left: '10px',
+ },
+ }),
+ h('h2.page-subtitle', 'Buy Eth'),
+ ]),
+ h('h3.flex-row.text-transform-uppercase', {
+ style: {
+ background: '#EBEBEB',
+ color: '#AEAEAE',
+ paddingTop: '4px',
+ justifyContent: 'space-around',
+ },
+ }, [
+ h(currentForm.coinbase ? '.activeForm' : '.inactiveForm.pointer', {
+ onClick: () => props.dispatch(actions.coinBaseSubview()),
+ }, 'Coinbase'),
+ h('a', {
+ onClick: (event) => this.navigateTo('https://github.com/MetaMask/faq/blob/master/COINBASE.md'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ position: 'relative',
+ right: '33px',
+ },
+ }),
+ ]),
+ h(currentForm.shapeshift ? '.activeForm' : '.inactiveForm.pointer', {
+ onClick: () => props.dispatch(actions.shapeShiftSubview(props.provider.type)),
+ }, 'Shapeshift'),
+
+ h('a', {
+ href: 'https://github.com/MetaMask/faq/blob/master/COINBASE.md',
+ onClick: (event) => this.navigateTo('https://info.shapeshift.io/about'),
+ }, [
+ h('i.fa.fa-question-circle', {
+ style: {
+ position: 'relative',
+ right: '28px',
+ },
+ }),
+ ]),
+ ]),
+ this.formVersionSubview(),
+ ])
+ )
+}
+
+BuyButtonSubview.prototype.formVersionSubview = function () {
+ if (this.props.network === '1') {
+ if (this.props.buyView.formView.coinbase) {
+ return h(CoinbaseForm, this.props)
+ } else if (this.props.buyView.formView.shapeshift) {
+ return h(ShapeshiftForm, this.props)
+ }
+ } else {
+ return h('div.flex-column', {
+ style: {
+ alignItems: 'center',
+ margin: '50px',
+ },
+ }, [
+ h('h3.text-transform-uppercase', {
+ style: {
+ width: '225px',
+ },
+ }, 'In order to access this feature please switch too the Main Network'),
+ h('h3.text-transform-uppercase', 'or:'),
+ this.props.network === '2' ? h('button.text-transform-uppercase', {
+ onClick: () => this.props.dispatch(actions.buyEth()),
+ style: {
+ marginTop: '15px',
+ },
+ }, 'Go To Test Faucet') : null,
+ ])
+ }
+}
+
+BuyButtonSubview.prototype.navigateTo = function (url) {
+ extension.tabs.create({ url })
+}
diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js
new file mode 100644
index 000000000..efd05ec96
--- /dev/null
+++ b/ui/app/components/coinbase-form.js
@@ -0,0 +1,162 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const actions = require('../actions')
+
+const isValidAddress = require('../util').isValidAddress
+module.exports = connect(mapStateToProps)(CoinbaseForm)
+
+function mapStateToProps(state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ }
+}
+
+inherits(CoinbaseForm, Component)
+
+function CoinbaseForm() {
+ Component.call(this)
+}
+
+CoinbaseForm.prototype.render = function () {
+ var props = this.props
+ var amount = props.buyView.amount
+ var address = props.buyView.buyAddress
+
+ return h('.flex-column', {
+ style: {
+ // margin: '10px',
+ padding: '25px',
+ },
+ }, [
+ h('.flex-column', {
+ style: {
+ alignItems: 'flex-start',
+ },
+ }, [
+ h('.flex-row', [
+ h('div', 'Address:'),
+ h('.ellip-address', address),
+ ]),
+ h('.flex-row', [
+ h('div', 'Amount: $'),
+ h('.input-container', [
+ h('input.buy-inputs', {
+ style: {
+ width: '3em',
+ boxSizing: 'border-box',
+ },
+ defaultValue: amount,
+ onChange: this.handleAmount.bind(this),
+ }),
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '5px',
+ right: '11px',
+ },
+ }),
+ ]),
+ ]),
+ ]),
+
+ h('.info-gray', {
+ style: {
+ fontSize: '10px',
+ fontFamily: 'Montserrat Light',
+ margin: '15px',
+ lineHeight: '13px',
+ },
+ },
+ `there is a USD$ 5 a day max and a USD$ 50
+ dollar limit per the life time of an account without a
+ coinbase account. A fee of 3.75% will be aplied to debit/credit cards.`),
+
+ !props.warning ? h('div', {
+ style: {
+ width: '340px',
+ height: '22px',
+ },
+ }) : props.warning && h('span.error.flex-center', props.warning),
+
+
+ h('.flex-row', {
+ style: {
+ justifyContent: 'space-around',
+ margin: '33px',
+ },
+ }, [
+ h('button', {
+ onClick: this.toCoinbase.bind(this),
+ }, 'Continue to Coinbase'),
+
+ h('button', {
+ onClick: () => props.dispatch(actions.backTobuyView(props.accounts.address)),
+ }, 'Cancel'),
+ ]),
+ ])
+}
+CoinbaseForm.prototype.handleAmount = function (event) {
+ this.props.dispatch(actions.updateCoinBaseAmount(event.target.value))
+}
+CoinbaseForm.prototype.handleAddress = function (event) {
+ this.props.dispatch(actions.updateBuyAddress(event.target.value))
+}
+CoinbaseForm.prototype.toCoinbase = function () {
+ var props = this.props
+ var amount = props.buyView.amount
+ var address = props.buyView.buyAddress
+ var message
+
+ if (isValidAddress(address) && isValidAmountforCoinBase(amount).valid) {
+ props.dispatch(actions.buyEth(address, props.buyView.amount))
+ } else if (!isValidAmountforCoinBase(amount).valid) {
+ message = isValidAmountforCoinBase(amount).message
+ return props.dispatch(actions.showWarning(message))
+ } else {
+ message = 'Receiving address is invalid.'
+ return props.dispatch(actions.showWarning(message))
+ }
+}
+
+CoinbaseForm.prototype.renderLoading = function () {
+
+ return h('img', {
+ style: {
+ width: '27px',
+ marginRight: '-27px',
+ },
+ src: 'images/loading.svg',
+ })
+}
+
+function isValidAmountforCoinBase(amount) {
+ amount = parseFloat(amount)
+
+ if (amount) {
+ if (amount <= 5 && amount > 0) {
+ return {
+ valid: true,
+ }
+ } else if (amount > 5) {
+ return {
+ valid: false,
+ message: 'The amount can not be greater then $5',
+ }
+ } else {
+ return {
+ valid: false,
+ message: 'Can not buy amounts less then $0',
+ }
+ }
+ } else {
+ return {
+ valid: false,
+ message: 'The amount entered is not a number',
+ }
+ }
+}
diff --git a/ui/app/components/drop-menu-item.js b/ui/app/components/drop-menu-item.js
index 1a0d6cbd5..0ca1988c6 100644
--- a/ui/app/components/drop-menu-item.js
+++ b/ui/app/components/drop-menu-item.js
@@ -41,9 +41,6 @@ DropMenuItem.prototype.activeNetworkRender = function () {
case 'Main Ethereum Network':
if (providerType === 'mainnet') return h('.check', '✓')
break
- case 'Ethereum Classic Network':
- if (providerType === 'classic') return h('.check', '✓')
- break
case 'Morden Test Network':
if (activeNetwork === '2') return h('.check', '✓')
break
diff --git a/ui/app/components/eth-balance.js b/ui/app/components/eth-balance.js
index 612ef7779..498873faa 100644
--- a/ui/app/components/eth-balance.js
+++ b/ui/app/components/eth-balance.js
@@ -4,6 +4,7 @@ const inherits = require('util').inherits
const formatBalance = require('../util').formatBalance
const generateBalanceObject = require('../util').generateBalanceObject
const Tooltip = require('./tooltip.js')
+
module.exports = EthBalanceComponent
inherits(EthBalanceComponent, Component)
@@ -14,29 +15,33 @@ function EthBalanceComponent () {
EthBalanceComponent.prototype.render = function () {
var state = this.props
var style = state.style
-
- const value = formatBalance(state.value, 6)
+ var needsParse = this.props.needsParse !== undefined ? this.props.needsParse : true
+ const value = formatBalance(state.value, 6, needsParse)
var width = state.width
return (
- h('.ether-balance', {
+ h('.ether-balance.ether-balance-amount', {
style: style,
}, [
- h('.ether-balance-amount', {
+ h('div', {
style: {
display: 'inline',
width: width,
},
- }, this.renderBalance(value, state)),
+ }, this.renderBalance(value)),
])
)
}
-EthBalanceComponent.prototype.renderBalance = function (value, state) {
+EthBalanceComponent.prototype.renderBalance = function (value) {
+ var state = this.props
if (value === 'None') return value
var balanceObj = generateBalanceObject(value, state.shorten ? 1 : 3)
var balance
+ var splitBalance = value.split(' ')
+ var ethNumber = splitBalance[0]
+ var ethSuffix = splitBalance[1]
if (state.shorten) {
balance = balanceObj.shortBalance
@@ -49,7 +54,7 @@ EthBalanceComponent.prototype.renderBalance = function (value, state) {
return (
h(Tooltip, {
position: 'bottom',
- title: value.split(' ')[0],
+ title: `${ethNumber} ${ethSuffix}`,
}, [
h('.flex-column', {
style: {
@@ -64,7 +69,7 @@ EthBalanceComponent.prototype.renderBalance = function (value, state) {
width: '100%',
textAlign: 'right',
},
- }, balance),
+ }, this.props.incoming ? `+${balance}` : balance),
h('div', {
style: {
color: ' #AEAEAE',
diff --git a/ui/app/components/mascot.js b/ui/app/components/mascot.js
index ddd51f8ba..f2b00262b 100644
--- a/ui/app/components/mascot.js
+++ b/ui/app/components/mascot.js
@@ -14,8 +14,9 @@ function Mascot () {
pxNotRatio: true,
width: 200,
height: 200,
+ staticImage: './images/icon-512.png',
})
- if (!this.logo) return
+ if (!this.logo.webGLSupport) return
this.refollowMouse = debounce(this.logo.setFollowMouse.bind(this.logo, true), 1000)
this.unfollowMouse = this.logo.setFollowMouse.bind(this.logo, false)
}
@@ -34,19 +35,24 @@ Mascot.prototype.render = function () {
}
Mascot.prototype.componentDidMount = function () {
- if (!this.logo) return
var targetDivId = 'metamask-mascot-container'
var container = document.getElementById(targetDivId)
- container.appendChild(this.logo.canvas)
+ if (!this.logo.webGLSupport) {
+ var staticLogo = this.logo.staticLogo
+ staticLogo.style.marginBottom = '40px'
+ container.appendChild(staticLogo)
+ } else {
+ container.appendChild(this.logo.canvas)
+ }
}
Mascot.prototype.componentWillUnmount = function () {
- if (!this.logo) return
+ if (!this.logo.webGLSupport) return
this.logo.canvas.remove()
}
Mascot.prototype.handleAnimationEvents = function () {
- if (!this.logo) return
+ if (!this.logo.webGLSupport) return
// only setup listeners once
if (this.animations) return
this.animations = this.props.animationEventEmitter
@@ -55,7 +61,7 @@ Mascot.prototype.handleAnimationEvents = function () {
}
Mascot.prototype.lookAt = function (target) {
- if (!this.logo) return
+ if (!this.logo.webGLSupport) return
this.unfollowMouse()
this.logo.lookAt(target)
this.refollowMouse()
diff --git a/ui/app/components/network.js b/ui/app/components/network.js
index 95901fe70..6826e0685 100644
--- a/ui/app/components/network.js
+++ b/ui/app/components/network.js
@@ -23,7 +23,7 @@ Network.prototype.render = function () {
if (networkNumber === 'loading') {
- return h('img', {
+ return h('img.network-indicator', {
title: 'Attempting to connect to blockchain.',
onClick: (event) => this.props.onClick(event),
style: {
@@ -36,9 +36,6 @@ Network.prototype.render = function () {
} else if (providerName === 'mainnet') {
hoverText = 'Main Ethereum Network'
iconName = 'ethereum-network'
- } else if (providerName === 'classic') {
- hoverText = 'Ethereum Classic Network'
- iconName = 'classic-network'
} else if (parseInt(networkNumber) === 2) {
hoverText = 'Morden Test Network'
iconName = 'morden-test-network'
@@ -64,16 +61,7 @@ Network.prototype.render = function () {
style: {
color: '#039396',
}},
- 'Etherum Main Net'),
- ])
- case 'classic-network':
- return h('.network-indicator', [
- h('.menu-icon.hollow-diamond'),
- h('.network-name', {
- style: {
- color: '#039396',
- }},
- 'Etherum Classic'),
+ 'Ethereum Main Net'),
])
case 'morden-test-network':
return h('.network-indicator', [
diff --git a/ui/app/components/pending-msg-details.js b/ui/app/components/pending-msg-details.js
index adcec596e..16308d121 100644
--- a/ui/app/components/pending-msg-details.js
+++ b/ui/app/components/pending-msg-details.js
@@ -3,7 +3,6 @@ const h = require('react-hyperscript')
const inherits = require('util').inherits
const AccountPanel = require('./account-panel')
-const readableDate = require('../util').readableDate
module.exports = PendingMsgDetails
@@ -24,6 +23,9 @@ PendingMsgDetails.prototype.render = function () {
return (
h('div', {
key: msgData.id,
+ style: {
+ margin: '10px 20px',
+ },
}, [
// account that will sign
@@ -37,11 +39,6 @@ PendingMsgDetails.prototype.render = function () {
// message 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),
]),
diff --git a/ui/app/components/qr-code.js b/ui/app/components/qr-code.js
new file mode 100644
index 000000000..c26b02b94
--- /dev/null
+++ b/ui/app/components/qr-code.js
@@ -0,0 +1,71 @@
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const CopyButton = require('./copyButton')
+
+module.exports = connect(mapStateToProps)(QrCodeView)
+
+function mapStateToProps (state) {
+ return {
+ Qr: state.appState.Qr,
+ buyView: state.appState.buyView,
+ warning: state.appState.warning,
+ }
+}
+
+inherits(QrCodeView, Component)
+
+function QrCodeView () {
+ Component.call(this)
+}
+
+QrCodeView.prototype.render = function () {
+ var props = this.props
+ var Qr = props.Qr
+ return h('.main-container.flex-column', {
+ key: 'qr',
+ style: {
+ justifyContent: 'center',
+ padding: '45px',
+ alignItems: 'center',
+ },
+ }, [
+ Array.isArray(Qr.message) ? h('.message-container', this.renderMultiMessage()) : h('h3', Qr.message),
+
+ this.props.warning ? this.props.warning && h('span.error.flex-center', {
+ style: {
+ textAlign: 'center',
+ width: '229px',
+ height: '82px',
+ },
+ },
+ this.props.warning) : null,
+
+ h('#qr-container.flex-column', {
+ style: {
+ marginTop: '25px',
+ marginBottom: '15px',
+ },
+ dangerouslySetInnerHTML: {
+ __html: Qr.image,
+ },
+ }),
+ h('.flex-row', [
+ h('h3.ellip-address', {
+ style: {
+ width: '247px',
+ },
+ }, Qr.data),
+ h(CopyButton, {
+ value: Qr.data,
+ }),
+ ]),
+ ])
+}
+
+QrCodeView.prototype.renderMultiMessage = function () {
+ var Qr = this.props.Qr
+ var multiMessage = Qr.message.map((message) => h('.qr-message', message))
+ return multiMessage
+}
diff --git a/ui/app/components/shapeshift-form.js b/ui/app/components/shapeshift-form.js
new file mode 100644
index 000000000..58b7942c3
--- /dev/null
+++ b/ui/app/components/shapeshift-form.js
@@ -0,0 +1,322 @@
+const PersistentForm = require('../../lib/persistent-form')
+const h = require('react-hyperscript')
+const inherits = require('util').inherits
+const connect = require('react-redux').connect
+const ReactCSSTransitionGroup = require('react-addons-css-transition-group')
+const actions = require('../actions')
+const Qr = require('./qr-code')
+const isValidAddress = require('../util').isValidAddress
+module.exports = connect(mapStateToProps)(ShapeshiftForm)
+
+function mapStateToProps(state) {
+ return {
+ selectedAccount: state.selectedAccount,
+ warning: state.appState.warning,
+ isSubLoading: state.appState.isSubLoading,
+ qrRequested: state.appState.qrRequested,
+ }
+}
+
+inherits(ShapeshiftForm, PersistentForm)
+
+function ShapeshiftForm () {
+ PersistentForm.call(this)
+ this.persistentFormParentId = 'shapeshift-buy-form'
+}
+
+ShapeshiftForm.prototype.render = function () {
+
+ return h(ReactCSSTransitionGroup, {
+ className: 'css-transition-group',
+ transitionName: 'main',
+ transitionEnterTimeout: 300,
+ transitionLeaveTimeout: 300,
+ }, [
+ this.props.qrRequested ? h(Qr, {key: 'qr'}) : this.renderMain(),
+ ])
+
+}
+
+ShapeshiftForm.prototype.renderMain = function () {
+ const marketinfo = this.props.buyView.formView.marketinfo
+ const coinOptions = this.props.buyView.formView.coinOptions
+ var coin = marketinfo.pair.split('_')[0].toUpperCase()
+
+ return h('.flex-column', {
+ style: {
+ // marginTop: '10px',
+ padding: '25px',
+ width: '100%',
+ alignItems: 'center',
+ },
+ }, [
+ h('.flex-row', {
+ style: {
+ justifyContent: 'center',
+ alignItems: 'baseline',
+ },
+ }, [
+ h('img', {
+ src: coinOptions[coin].image,
+ width: '25px',
+ height: '25px',
+ style: {
+ marginRight: '5px',
+ },
+ }),
+
+ h('.input-container', [
+ h('input#fromCoin.buy-inputs.ex-coins', {
+ type: 'text',
+ list: 'coinList',
+ dataset: {
+ persistentFormId: 'input-coin',
+ },
+ style: {
+ boxSizing: 'border-box',
+ },
+ onChange: this.handleLiveInput.bind(this),
+ defaultValue: 'BTC',
+ }),
+
+ this.renderCoinList(),
+
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '48px',
+ left: '106px',
+ },
+ }),
+ ]),
+
+ h('.icon-control', [
+ h('i.fa.fa-refresh.fa-4.orange', {
+ style: {
+ position: 'relative',
+ bottom: '5px',
+ left: '5px',
+ color: '#F7861C',
+ },
+ onClick: this.updateCoin.bind(this),
+ }),
+ h('i.fa.fa-chevron-right.fa-4.orange', {
+ style: {
+ position: 'relative',
+ bottom: '26px',
+ left: '10px',
+ color: '#F7861C',
+ },
+ onClick: this.updateCoin.bind(this),
+ }),
+ ]),
+
+ h('#toCoin.ex-coins', marketinfo.pair.split('_')[1].toUpperCase()),
+
+ h('img', {
+ src: coinOptions[marketinfo.pair.split('_')[1].toUpperCase()].image,
+ width: '25px',
+ height: '25px',
+ style: {
+ marginLeft: '5px',
+ },
+ }),
+ ]),
+
+ this.props.isSubLoading ? this.renderLoading() : null,
+ h('.flex-column', {
+ style: {
+ width: '235px',
+ alignItems: 'flex-start',
+ },
+ }, [
+ this.props.warning ? this.props.warning && h('span.error.flex-center', {
+ style: {
+ textAlign: 'center',
+ width: '229px',
+ height: '82px',
+ },
+ },
+ this.props.warning) : this.renderInfo(),
+ ]),
+
+ h('.flex-row', {
+ style: {
+ padding: '10px',
+ paddingBottom: '2px',
+ width: '100%',
+ },
+ }, [
+ h('div', 'Receiving address:'),
+ h('.ellip-address', this.props.buyView.buyAddress),
+ ]),
+
+ h(this.activeToggle('.input-container'), {
+ style: {
+ padding: '10px',
+ paddingTop: '0px',
+ width: '100%',
+ },
+ }, [
+ h('div', `${coin} Address:`),
+
+ h('input#fromCoinAddress.buy-inputs', {
+ type: 'text',
+ placeholder: `Your ${coin} Refund Address`,
+ dataset: {
+ persistentFormId: 'refund-address',
+ },
+ style: {
+ boxSizing: 'border-box',
+ width: '278px',
+ height: '20px',
+ padding: ' 5px ',
+ },
+ }),
+
+ h('i.fa.fa-pencil-square-o.edit-text', {
+ style: {
+ fontSize: '12px',
+ color: '#F7861C',
+ position: 'relative',
+ bottom: '5px',
+ right: '11px',
+ },
+ }),
+ h('.flex-row', {
+ style: {
+ justifyContent: 'flex-end',
+ },
+ }, [
+ h('button', {
+ onClick: this.shift.bind(this),
+ style: {
+ marginTop: '10px',
+ },
+ },
+ 'Submit'),
+ ]),
+ ]),
+ ])
+}
+
+ShapeshiftForm.prototype.shift = function () {
+ var props = this.props
+ var withdrawal = this.props.buyView.buyAddress
+ var returnAddress = document.getElementById('fromCoinAddress').value
+ var pair = this.props.buyView.formView.marketinfo.pair
+ var data = {
+ 'withdrawal': withdrawal,
+ 'pair': pair,
+ 'returnAddress': returnAddress,
+ // Public api key
+ 'apiKey': '803d1f5df2ed1b1476e4b9e6bcd089e34d8874595dda6a23b67d93c56ea9cc2445e98a6748b219b2b6ad654d9f075f1f1db139abfa93158c04e825db122c14b6',
+ }
+ var message = [
+ `Deposit Limit: ${props.buyView.formView.marketinfo.limit}`,
+ `Deposit Minimum:${props.buyView.formView.marketinfo.minimum}`,
+ ]
+ if (isValidAddress(withdrawal)) {
+ this.props.dispatch(actions.coinShiftRquest(data, message))
+ }
+}
+
+ShapeshiftForm.prototype.renderCoinList = function () {
+ var list = Object.keys(this.props.buyView.formView.coinOptions).map((item) => {
+ return h('option', {
+ value: item,
+ }, item)
+ })
+
+ return h('datalist#coinList', {
+ onClick: (event) => {
+ event.preventDefault()
+ },
+ }, list)
+}
+
+ShapeshiftForm.prototype.updateCoin = function (event) {
+ event.preventDefault()
+ const props = this.props
+ var coinOptions = this.props.buyView.formView.coinOptions
+ var coin = document.getElementById('fromCoin').value
+
+ if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
+ var message = 'Not a valid coin'
+ return props.dispatch(actions.showWarning(message))
+ } else {
+ return props.dispatch(actions.pairUpdate(coin))
+ }
+}
+
+ShapeshiftForm.prototype.handleLiveInput = function () {
+ const props = this.props
+ var coinOptions = this.props.buyView.formView.coinOptions
+ var coin = document.getElementById('fromCoin').value
+
+ if (!coinOptions[coin.toUpperCase()] || coin.toUpperCase() === 'ETH') {
+ return null
+ } else {
+ return props.dispatch(actions.pairUpdate(coin))
+ }
+}
+
+ShapeshiftForm.prototype.renderInfo = function () {
+ const marketinfo = this.props.buyView.formView.marketinfo
+ const coinOptions = this.props.buyView.formView.coinOptions
+ var coin = marketinfo.pair.split('_')[0].toUpperCase()
+
+ return h('span', {
+ style: {
+ marginTop: '15px',
+ marginBottom: '15px',
+ },
+ }, [
+ h('h3.flex-row.text-transform-uppercase', {
+ style: {
+ color: '#AEAEAE',
+ paddingTop: '4px',
+ justifyContent: 'space-around',
+ textAlign: 'center',
+ fontSize: '14px',
+ },
+ }, `Market Info for ${marketinfo.pair.replace('_', ' to ').toUpperCase()}:`),
+ h('.marketinfo', ['Status : ', `${coinOptions[coin].status}`]),
+ h('.marketinfo', ['Exchange Rate: ', `${marketinfo.rate}`]),
+ h('.marketinfo', ['Limit: ', `${marketinfo.limit}`]),
+ h('.marketinfo', ['Minimum : ', `${marketinfo.minimum}`]),
+ ])
+}
+
+ShapeshiftForm.prototype.handleAddress = function (event) {
+ this.props.dispatch(actions.updateBuyAddress(event.target.value))
+}
+
+ShapeshiftForm.prototype.activeToggle = function (elementType) {
+ if (!this.props.buyView.formView.response || this.props.warning) return elementType
+ return `${elementType}.inactive`
+}
+
+ShapeshiftForm.prototype.renderLoading = function () {
+ return h('span', {
+ style: {
+ position: 'absolute',
+ left: '70px',
+ bottom: '194px',
+ background: 'transparent',
+ width: '229px',
+ height: '82px',
+ display: 'flex',
+ justifyContent: 'center',
+ },
+ }, [
+ h('img', {
+ style: {
+ width: '60px',
+ },
+ src: 'images/loading.svg',
+ }),
+ ])
+}
diff --git a/ui/app/components/shift-list-item.js b/ui/app/components/shift-list-item.js
new file mode 100644
index 000000000..38c19eb28
--- /dev/null
+++ b/ui/app/components/shift-list-item.js
@@ -0,0 +1,202 @@
+const inherits = require('util').inherits
+const Component = require('react').Component
+const h = require('react-hyperscript')
+const connect = require('react-redux').connect
+const vreme = new (require('vreme'))
+const explorerLink = require('../../lib/explorer-link')
+const extension = require('../../../app/scripts/lib/extension')
+const actions = require('../actions')
+const addressSummary = require('../util').addressSummary
+
+const CopyButton = require('./copyButton')
+const EtherBalance = require('./eth-balance')
+const Tooltip = require('./tooltip')
+
+
+module.exports = connect(mapStateToProps)(ShiftListItem)
+
+function mapStateToProps (state) {
+ return {}
+}
+
+inherits(ShiftListItem, Component)
+
+function ShiftListItem () {
+ Component.call(this)
+}
+
+ShiftListItem.prototype.render = function () {
+
+ return (
+ h('.transaction-list-item.flex-row', {
+ style: {
+ paddingTop: '20px',
+ paddingBottom: '20px',
+ justifyContent: 'space-around',
+ alignItems: 'center',
+ },
+ }, [
+ h('div', {
+ style: {
+ width: '0px',
+ position: 'relative',
+ bottom: '19px',
+ },
+ }, [
+ h('img', {
+ src: 'https://info.shapeshift.io/sites/default/files/logo.png',
+ style: {
+ height: '35px',
+ width: '132px',
+ position: 'absolute',
+ clip: 'rect(0px,23px,34px,0px)',
+ },
+ }),
+ ]),
+
+ this.renderInfo(),
+ this.renderUtilComponents(),
+ ])
+ )
+}
+
+function formatDate (date) {
+ return vreme.format(new Date(date), 'March 16 2014 14:30')
+}
+
+ShiftListItem.prototype.renderUtilComponents = function () {
+ var props = this.props
+
+ switch (props.response.status) {
+ case 'no_deposits':
+ return h('.flex-row', [
+ h(CopyButton, {
+ value: this.props.depositAddress,
+ }),
+ h(Tooltip, {
+ title: 'QR Code',
+ }, [
+ h('i.fa.fa-qrcode.pointer.pop-hover', {
+ onClick: () => props.dispatch(actions.reshowQrCode(props.depositAddress, props.depositType)),
+ style: {
+ margin: '5px',
+ marginLeft: '23px',
+ marginRight: '12px',
+ fontSize: '20px',
+ color: '#F7861C',
+ },
+ }),
+ ]),
+ ])
+ case 'received':
+ return h('.flex-row')
+
+ case 'complete':
+ return h('.flex-row', [
+ h(CopyButton, {
+ value: this.props.response.transaction,
+ }),
+ h(EtherBalance, {
+ value: `${props.response.outgoingCoin}`,
+ width: '55px',
+ shorten: true,
+ needsParse: false,
+ incoming: true,
+ style: {
+ fontSize: '15px',
+ color: '#01888C',
+ },
+ }),
+ ])
+
+ case 'failed':
+ return ''
+ default:
+ return ''
+ }
+}
+
+ShiftListItem.prototype.renderInfo = function () {
+ var props = this.props
+ switch (props.response.status) {
+ case 'no_deposits':
+ return h('.flex-column', {
+ style: {
+ width: '200px',
+ overflow: 'hidden',
+ },
+ }, [
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, `${props.depositType} to ETH via ShapeShift`),
+ h('div', 'No deposits received'),
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, formatDate(props.time)),
+ ])
+ case 'received':
+ return h('.flex-column', {
+ style: {
+ width: '200px',
+ overflow: 'hidden',
+ },
+ }, [
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, `${props.depositType} to ETH via ShapeShift`),
+ h('div', 'Conversion in progress'),
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, formatDate(props.time)),
+ ])
+ case 'complete':
+ var url = explorerLink(props.response.transaction, parseInt('1'))
+
+ return h('.flex-column.pointer', {
+ style: {
+ width: '200px',
+ overflow: 'hidden',
+ },
+ onClick: () => extension.tabs.create({
+ url,
+ }),
+ }, [
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, 'From ShapeShift'),
+ h('div', formatDate(props.time)),
+ h('div', {
+ style: {
+ fontSize: 'x-small',
+ color: '#ABA9AA',
+ width: '100%',
+ },
+ }, addressSummary(props.response.transaction)),
+ ])
+
+ case 'failed':
+ return h('span.error', '(Failed)')
+ default:
+ return ''
+ }
+}
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
index 796ba61ae..1b85464e1 100644
--- a/ui/app/components/transaction-list-item.js
+++ b/ui/app/components/transaction-list-item.js
@@ -10,7 +10,7 @@ const vreme = new (require('vreme'))
const extension = require('../../../app/scripts/lib/extension')
const TransactionIcon = require('./transaction-list-item-icon')
-
+const ShiftListItem = require('./shift-list-item')
module.exports = TransactionListItem
inherits(TransactionListItem, Component)
@@ -19,8 +19,10 @@ function TransactionListItem () {
}
TransactionListItem.prototype.render = function () {
- const { transaction, i, network } = this.props
-
+ const { transaction, network } = this.props
+ if (transaction.key === 'shapeshift') {
+ if (network === '1') return h(ShiftListItem, transaction)
+ }
var date = formatDate(transaction.time)
let isLinkable = false
@@ -42,7 +44,6 @@ TransactionListItem.prototype.render = function () {
return (
h(`.transaction-list-item.flex-row.flex-space-between${isClickable ? '.pointer' : ''}`, {
- key: `tx-${transaction.id + i}`,
onClick: (event) => {
if (isPending) {
this.props.showTx(transaction.id)
diff --git a/ui/app/components/transaction-list.js b/ui/app/components/transaction-list.js
index 886aa7c00..7e1bedb05 100644
--- a/ui/app/components/transaction-list.js
+++ b/ui/app/components/transaction-list.js
@@ -14,7 +14,11 @@ function TransactionList () {
TransactionList.prototype.render = function () {
const { txsToRender, network, unconfMsgs } = this.props
- const transactions = txsToRender.concat(unconfMsgs)
+ var shapeShiftTxList
+ if (network === '1') {
+ shapeShiftTxList = this.props.shapeShiftTxList
+ }
+ const transactions = !shapeShiftTxList ? txsToRender.concat(unconfMsgs) : txsToRender.concat(unconfMsgs, shapeShiftTxList)
.sort((a, b) => b.time - a.time)
return (
@@ -39,33 +43,46 @@ TransactionList.prototype.render = function () {
paddingBottom: '4px',
},
}, [
- 'Transactions',
+ 'History',
]),
h('.tx-list', {
style: {
overflowY: 'auto',
- height: '305px',
+ height: '300px',
padding: '0 20px',
textAlign: 'center',
},
- }, (
+ }, [
transactions.length
? transactions.map((transaction, i) => {
+ let key
+ switch (transaction.key) {
+ case 'shapeshift':
+ const { depositAddress, time } = transaction
+ key = `shift-tx-${depositAddress}-${time}-${i}`
+ break
+ default:
+ key = `tx-${transaction.id}-${i}`
+ }
return h(TransactionListItem, {
- transaction, i, network,
+ transaction, i, network, key,
showTx: (txId) => {
this.props.viewPendingTx(txId)
},
})
})
- : [h('.flex-center', {
+ : h('.flex-center', {
style: {
+ flexDirection: 'column',
height: '100%',
},
- }, 'No transaction history...')]
- )),
+ }, [
+ 'No transaction history.',
+ ]),
+ ]),
])
)
}
+
diff --git a/ui/app/conf-tx.js b/ui/app/conf-tx.js
index db876dd9b..22d29383f 100644
--- a/ui/app/conf-tx.js
+++ b/ui/app/conf-tx.js
@@ -5,6 +5,7 @@ const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('./actions')
const txHelper = require('../lib/tx-helper')
+const isPopupOrNotification = require('../../app/scripts/lib/is-popup-or-notification')
const PendingTx = require('./components/pending-tx')
const PendingMsg = require('./components/pending-msg')
@@ -35,7 +36,8 @@ ConfirmTxScreen.prototype.render = function () {
var unconfMsgs = state.unconfMsgs
var unconfTxList = txHelper(unconfTxs, unconfMsgs)
var index = state.index !== undefined ? state.index : 0
- var txData = unconfTxList[index] || {}
+ var txData = unconfTxList[index] || unconfTxList[0] || {}
+ var isNotification = isPopupOrNotification() === 'notification'
return (
@@ -43,9 +45,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', {
+ !isNotification ? h('i.fa.fa-arrow-left.fa-lg.cursor-pointer', {
onClick: this.goHome.bind(this),
- }),
+ }) : null,
h('h2.page-subtitle', 'Confirm Transaction'),
]),
diff --git a/ui/app/config.js b/ui/app/config.js
index c88e7ac6e..b043a47d6 100644
--- a/ui/app/config.js
+++ b/ui/app/config.js
@@ -3,7 +3,7 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('./actions')
-
+const currencies = require('./conversion-util').availableCurrencies.rows
module.exports = connect(mapStateToProps)(ConfigScreen)
function mapStateToProps (state) {
@@ -74,6 +74,8 @@ ConfigScreen.prototype.render = function () {
}, 'Save'),
]),
h('hr.horizontal-line'),
+ currentConversionInformation(metamaskState, state),
+ h('hr.horizontal-line'),
h('div', {
style: {
@@ -97,6 +99,27 @@ ConfigScreen.prototype.render = function () {
)
}
+function currentConversionInformation (metamaskState, state) {
+ var currentFiat = metamaskState.currentFiat
+ var conversionDate = metamaskState.conversionDate
+ return h('div', [
+ h('span', {style: { fontWeight: 'bold', paddingRight: '10px'}}, 'Current Conversion'),
+ h('span', {style: { fontWeight: 'bold', paddingRight: '10px', fontSize: '13px'}}, `Updated ${Date(conversionDate)}`),
+ h('select#currentFiat', {
+ onChange (event) {
+ event.preventDefault()
+ var element = document.getElementById('currentFiat')
+ var newFiat = element.value
+ state.dispatch(actions.setCurrentFiat(newFiat))
+ },
+ defaultValue: currentFiat,
+ }, currencies.map((currency) => {
+ return h('option', {key: currency.code, value: currency.code}, `${currency.code} - ${currency.name}`)
+ })
+ ),
+ ])
+}
+
function currentProviderDisplay (metamaskState) {
var provider = metamaskState.provider
var title, value
diff --git a/ui/app/conversion-util.js b/ui/app/conversion-util.js
new file mode 100644
index 000000000..19259602a
--- /dev/null
+++ b/ui/app/conversion-util.js
@@ -0,0 +1,5 @@
+var availableCurrencies = {"rows":[{"code":"007","name":"007","statuses":["primary"]},{"code":"1337","name":"1337","statuses":["primary"]},{"code":"1CR","name":"1CR","statuses":["primary"]},{"code":"256","name":"256","statuses":["primary"]},{"code":"2FLAV","name":"2FLAV","statuses":["primary"]},{"code":"2GIVE","name":"2GIVE","statuses":["primary"]},{"code":"404","name":"404","statuses":["primary"]},{"code":"611","name":"611","statuses":["primary"]},{"code":"888","name":"888","statuses":["primary"]},{"code":"8BIT","name":"8Bit","statuses":["primary"]},{"code":"ACLR","name":"ACLR","statuses":["primary"]},{"code":"ACOIN","name":"ACOIN","statuses":["primary"]},{"code":"ACP","name":"ACP","statuses":["primary"]},{"code":"ADC","name":"ADC","statuses":["primary"]},{"code":"ADZ","name":"Adzcoin","statuses":["primary"]},{"code":"AEC","name":"AEC","statuses":["primary"]},{"code":"AEON","name":"Aeon","statuses":["primary"]},{"code":"AGRS","name":"Agoras Tokens","statuses":["primary"]},{"code":"AIB","name":"AIB","statuses":["primary"]},{"code":"ADN","name":"Aiden","statuses":["primary"]},{"code":"AIR","name":"AIR","statuses":["primary"]},{"code":"ALC","name":"ALC","statuses":["primary"]},{"code":"ALTC","name":"ALTC","statuses":["primary"]},{"code":"AM","name":"AM","statuses":["primary"]},{"code":"AMBER","name":"AMBER","statuses":["primary"]},{"code":"AMS","name":"AMS","statuses":["primary"]},{"code":"ANAL","name":"ANAL","statuses":["primary"]},{"code":"AND","name":"AND","statuses":["primary"]},{"code":"ANI","name":"ANI","statuses":["primary"]},{"code":"ANC","name":"Anoncoin","statuses":["primary"]},{"code":"ANTI","name":"AntiBitcoin","statuses":["primary"]},{"code":"APEX","name":"APEX","statuses":["primary"]},{"code":"APC","name":"Applecoin","statuses":["primary"]},{"code":"APT","name":"APT","statuses":["primary"]},{"code":"AR2","name":"AR2","statuses":["primary"]},{"code":"ARB","name":"ARB","statuses":["primary"]},{"code":"ARC","name":"ARC","statuses":["primary"]},{"code":"ARCH","name":"ARCH","statuses":["primary"]},{"code":"ABY","name":"ArtByte","statuses":["primary"]},{"code":"ARTC","name":"ARTC","statuses":["primary"]},{"code":"ADCN","name":"Asiadigicoin","statuses":["primary"]},{"code":"ATEN","name":"ATEN","statuses":["primary"]},{"code":"REP","name":"Augur","statuses":["primary"]},{"code":"AUR","name":"Auroracoin","statuses":["primary"]},{"code":"AUD","name":"Australian Dollar","statuses":["secondary"]},{"code":"AV","name":"AV","statuses":["primary"]},{"code":"BA","name":"BA","statuses":["primary"]},{"code":"BAC","name":"BAC","statuses":["primary"]},{"code":"BTA","name":"Bata","statuses":["primary"]},{"code":"BAY","name":"BAY","statuses":["primary"]},{"code":"BBCC","name":"BBCC","statuses":["primary"]},{"code":"BQC","name":"BBQCoin","statuses":["primary"]},{"code":"BDC","name":"BDC","statuses":["primary"]},{"code":"BEC","name":"BEC","statuses":["primary"]},{"code":"BEEZ","name":"BEEZ","statuses":["primary"]},{"code":"BELA","name":"BellaCoin","statuses":["primary"]},{"code":"BERN","name":"BERNcash","statuses":["primary"]},{"code":"BILL","name":"BILL","statuses":["primary"]},{"code":"BILS","name":"BILS","statuses":["primary"]},{"code":"BIOS","name":"BiosCrypto","statuses":["primary"]},{"code":"BIT","name":"BIT","statuses":["primary"]},{"code":"BIT16","name":"BIT16","statuses":["primary"]},{"code":"BITB","name":"BitBean","statuses":["primary"]},{"code":"BTC","name":"Bitcoin","statuses":["primary","secondary"]},{"code":"XBC","name":"Bitcoin Plus","statuses":["primary"]},{"code":"BTCD","name":"BitcoinDark","statuses":["primary"]},{"code":"BCY","name":"Bitcrystals","statuses":["primary"]},{"code":"BTM","name":"Bitmark","statuses":["primary"]},{"code":"BTQ","name":"BitQuark","statuses":["primary"]},{"code":"BITS","name":"BITS","statuses":["primary"]},{"code":"BSD","name":"BitSend","statuses":["primary"]},{"code":"BTS","name":"BitShares","statuses":["primary"]},{"code":"PTS","name":"BitShares PTS","statuses":["primary"]},{"code":"SWIFT","name":"BitSwift","statuses":["primary"]},{"code":"BITZ","name":"Bitz","statuses":["primary"]},{"code":"BLK","name":"Blackcoin","statuses":["primary"]},{"code":"JACK","name":"BlackJack","statuses":["primary"]},{"code":"BLC","name":"Blakecoin","statuses":["primary"]},{"code":"BLEU","name":"BLEU","statuses":["primary"]},{"code":"BLITZ","name":"Blitzcoin","statuses":["primary"]},{"code":"BLOCK","name":"Blocknet","statuses":["primary"]},{"code":"BLRY","name":"BLRY","statuses":["primary"]},{"code":"BLU","name":"BLU","statuses":["primary"]},{"code":"BM","name":"BM","statuses":["primary"]},{"code":"BNT","name":"BNT","statuses":["primary"]},{"code":"BOB","name":"BOB","statuses":["primary"]},{"code":"BON","name":"BON","statuses":["primary"]},{"code":"BBR","name":"Boolberry","statuses":["primary"]},{"code":"BOST","name":"BoostCoin","statuses":["primary"]},{"code":"BOSS","name":"BOSS","statuses":["primary"]},{"code":"BPOK","name":"BPOK","statuses":["primary"]},{"code":"BRAIN","name":"BRAIN","statuses":["primary"]},{"code":"BRC","name":"BRC","statuses":["primary"]},{"code":"BRDD","name":"BRDD","statuses":["primary"]},{"code":"BRIT","name":"BRIT","statuses":["primary"]},{"code":"GBP","name":"British Pound Sterling","statuses":["secondary"]},{"code":"BRK","name":"BRK","statuses":["primary"]},{"code":"BRX","name":"BRX","statuses":["primary"]},{"code":"BSC","name":"BSC","statuses":["primary"]},{"code":"BST","name":"BST","statuses":["primary"]},{"code":"BTCHC","name":"BTCHC","statuses":["primary"]},{"code":"BTCR","name":"BTCR","statuses":["primary"]},{"code":"BTCS","name":"BTCS","statuses":["primary"]},{"code":"BTCU","name":"BTCU","statuses":["primary"]},{"code":"BTTF","name":"BTTF","statuses":["primary"]},{"code":"BTX","name":"BTX","statuses":["primary"]},{"code":"BUCKS","name":"BUCKS","statuses":["primary"]},{"code":"BUN","name":"BUN","statuses":["primary"]},{"code":"BURST","name":"Burst","statuses":["primary"]},{"code":"BUZZ","name":"BUZZ","statuses":["primary"]},{"code":"BVC","name":"BVC","statuses":["primary"]},{"code":"BYC","name":"Bytecent","statuses":["primary"]},{"code":"BCN","name":"Bytecoin","statuses":["primary"]},{"code":"XCT","name":"C-Bit","statuses":["primary"]},{"code":"C0C0","name":"C0C0","statuses":["primary"]},{"code":"CAB","name":"Cabbage Unit","statuses":["primary"]},{"code":"CAD","name":"CAD","statuses":["primary","secondary"]},{"code":"CAGE","name":"CAGE","statuses":["primary"]},{"code":"CANN","name":"CannabisCoin","statuses":["primary"]},{"code":"CCN","name":"Cannacoin","statuses":["primary"]},{"code":"CPC","name":"Capricoin","statuses":["primary"]},{"code":"DIEM","name":"CarpeDiemCoin","statuses":["primary"]},{"code":"CASH","name":"CASH","statuses":["primary"]},{"code":"CBIT","name":"CBIT","statuses":["primary"]},{"code":"CC","name":"CC","statuses":["primary"]},{"code":"CCB","name":"CCB","statuses":["primary"]},{"code":"CD","name":"CD","statuses":["primary"]},{"code":"CDN","name":"CDN","statuses":["primary"]},{"code":"CF","name":"CF","statuses":["primary"]},{"code":"CFC","name":"CFC","statuses":["primary"]},{"code":"CGA","name":"CGA","statuses":["primary"]},{"code":"CHC","name":"CHC","statuses":["primary"]},{"code":"CKC","name":"Checkcoin","statuses":["primary"]},{"code":"CHEMX","name":"CHEMX","statuses":["primary"]},{"code":"CHESS","name":"CHESS","statuses":["primary"]},{"code":"CHF","name":"CHF","statuses":["primary","secondary"]},{"code":"CNY","name":"Chinese Yuan","statuses":["secondary"]},{"code":"CHRG","name":"CHRG","statuses":["primary"]},{"code":"CJ","name":"CJ","statuses":["primary"]},{"code":"CLAM","name":"Clams","statuses":["primary"]},{"code":"CLICK","name":"CLICK","statuses":["primary"]},{"code":"CLINT","name":"CLINT","statuses":["primary"]},{"code":"CLOAK","name":"Cloakcoin","statuses":["primary"]},{"code":"CLR","name":"CLR","statuses":["primary"]},{"code":"CLUB","name":"CLUB","statuses":["primary"]},{"code":"CLUD","name":"CLUD","statuses":["primary"]},{"code":"CMT","name":"CMT","statuses":["primary"]},{"code":"CNC","name":"CNC","statuses":["primary"]},{"code":"COXST","name":"CoExistCoin","statuses":["primary"]},{"code":"COIN","name":"COIN","statuses":["primary"]},{"code":"C2","name":"Coin2.1","statuses":["primary"]},{"code":"CNMT","name":"Coinomat","statuses":["primary"]},{"code":"CV2","name":"Colossuscoin2.0","statuses":["primary"]},{"code":"CON","name":"CON","statuses":["primary"]},{"code":"XCP","name":"Counterparty","statuses":["primary"]},{"code":"COV","name":"COV","statuses":["primary"]},{"code":"CRAFT","name":"CRAFT","statuses":["primary"]},{"code":"CRAVE","name":"CRAVE","statuses":["primary"]},{"code":"CRC","name":"CRC","statuses":["primary"]},{"code":"CRE","name":"CRE","statuses":["primary"]},{"code":"CRBIT","name":"Creditbit","statuses":["primary"]},{"code":"CREVA","name":"CrevaCoin","statuses":["primary"]},{"code":"CRIME","name":"CRIME","statuses":["primary"]},{"code":"CRT","name":"CRT","statuses":["primary"]},{"code":"CRW","name":"CRW","statuses":["primary"]},{"code":"CRY","name":"CRY","statuses":["primary"]},{"code":"XCR","name":"Crypti","statuses":["primary"]},{"code":"CBX","name":"Crypto Bullion","statuses":["primary"]},{"code":"CESC","name":"CryptoEscudo","statuses":["primary"]},{"code":"XCN","name":"Cryptonite","statuses":["primary"]},{"code":"CSMIC","name":"CSMIC","statuses":["primary"]},{"code":"CST","name":"CST","statuses":["primary"]},{"code":"CTC","name":"CTC","statuses":["primary"]},{"code":"CTO","name":"CTO","statuses":["primary"]},{"code":"CURE","name":"Curecoin","statuses":["primary"]},{"code":"CYP","name":"Cypher","statuses":["primary"]},{"code":"CZC","name":"CZC","statuses":["primary"]},{"code":"CZECO","name":"CZECO","statuses":["primary"]},{"code":"CZR","name":"CZR","statuses":["primary"]},{"code":"DAO","name":"DAO","statuses":["primary"]},{"code":"DGD","name":"DarkGoldCoin","statuses":["primary"]},{"code":"DNET","name":"Darknet","statuses":["primary"]},{"code":"DASH","name":"Dash","statuses":["primary"]},{"code":"DTC","name":"Datacoin","statuses":["primary"]},{"code":"DBG","name":"DBG","statuses":["primary"]},{"code":"DBLK","name":"DBLK","statuses":["primary"]},{"code":"DBTC","name":"DBTC","statuses":["primary"]},{"code":"DCK","name":"DCK","statuses":["primary"]},{"code":"DCR","name":"Decred","statuses":["primary"]},{"code":"DES","name":"Destiny","statuses":["primary"]},{"code":"DETH","name":"DETH","statuses":["primary"]},{"code":"DEUR","name":"DEUR","statuses":["primary"]},{"code":"DEM","name":"Deutsche eMark","statuses":["primary"]},{"code":"DVC","name":"Devcoin","statuses":["primary"]},{"code":"DGCS","name":"DGCS","statuses":["primary"]},{"code":"DGMS","name":"DGMS","statuses":["primary"]},{"code":"DGORE","name":"DGORE","statuses":["primary"]},{"code":"DMD","name":"Diamond","statuses":["primary"]},{"code":"DGB","name":"Digibyte","statuses":["primary"]},{"code":"CUBE","name":"DigiCube","statuses":["primary"]},{"code":"DGC","name":"Digitalcoin","statuses":["primary"]},{"code":"XDN","name":"DigitalNote","statuses":["primary"]},{"code":"DP","name":"DigitalPrice","statuses":["primary"]},{"code":"DIGS","name":"DIGS","statuses":["primary"]},{"code":"DIME","name":"Dimecoin","statuses":["primary"]},{"code":"DISK","name":"DISK","statuses":["primary"]},{"code":"DLISK","name":"DLISK","statuses":["primary"]},{"code":"NOTE","name":"DNotes","statuses":["primary"]},{"code":"DOGE","name":"Dogecoin","statuses":["primary","secondary"]},{"code":"DON","name":"DON","statuses":["primary"]},{"code":"DOPE","name":"DopeCoin","statuses":["primary"]},{"code":"DOX","name":"DOX","statuses":["primary"]},{"code":"DRACO","name":"DRACO","statuses":["primary"]},{"code":"DRM","name":"DRM","statuses":["primary"]},{"code":"DROP","name":"DROP","statuses":["primary"]},{"code":"DRZ","name":"DRZ","statuses":["primary"]},{"code":"DSH","name":"DSH","statuses":["primary"]},{"code":"DBIC","name":"DubaiCoin","statuses":["primary"]},{"code":"DUO","name":"DUO","statuses":["primary"]},{"code":"DUST","name":"DUST","statuses":["primary"]},{"code":"EAC","name":"Earthcoin","statuses":["primary"]},{"code":"ECCHI","name":"ECCHI","statuses":["primary"]},{"code":"ECC","name":"ECCoin","statuses":["primary"]},{"code":"ECOS","name":"ECOS","statuses":["primary"]},{"code":"EDC","name":"EDC","statuses":["primary"]},{"code":"EDRC","name":"EDRC","statuses":["primary"]},{"code":"EGG","name":"EGG","statuses":["primary"]},{"code":"EMC2","name":"Einsteinium","statuses":["primary"]},{"code":"EKO","name":"EKO","statuses":["primary"]},{"code":"EL","name":"EL","statuses":["primary"]},{"code":"ELCO","name":"ELcoin","statuses":["primary"]},{"code":"ELE","name":"ELE","statuses":["primary"]},{"code":"EFL","name":"Electronic Gulden","statuses":["primary"]},{"code":"EMC","name":"Emercoin","statuses":["primary"]},{"code":"EMIRG","name":"EMIRG","statuses":["primary"]},{"code":"ENE","name":"ENE","statuses":["primary"]},{"code":"ENRG","name":"Energycoin","statuses":["primary"]},{"code":"EPC","name":"EPC","statuses":["primary"]},{"code":"EPY","name":"EPY","statuses":["primary"]},{"code":"ERC","name":"ERC","statuses":["primary"]},{"code":"ERC3","name":"ERC3","statuses":["primary"]},{"code":"ESC","name":"ESC","statuses":["primary"]},{"code":"ETC","name":"Ethereum Classic","statuses":["primary"]},{"code":"ETHS","name":"ETHS","statuses":["primary"]},{"code":"EURC","name":"EURC","statuses":["primary"]},{"code":"EUR","name":"Euro","statuses":["primary","secondary"]},{"code":"EGC","name":"EvergreenCoin","statuses":["primary"]},{"code":"EVIL","name":"EVIL","statuses":["primary"]},{"code":"EVO","name":"EVO","statuses":["primary"]},{"code":"EXCL","name":"EXCL","statuses":["primary"]},{"code":"EXIT","name":"EXIT","statuses":["primary"]},{"code":"EXP","name":"Expanse","statuses":["primary"]},{"code":"FCT","name":"Factom","statuses":["primary"]},{"code":"FAIR","name":"Faircoin","statuses":["primary"]},{"code":"FC2","name":"FC2","statuses":["primary"]},{"code":"FCN","name":"FCN","statuses":["primary"]},{"code":"FTC","name":"Feathercoin","statuses":["primary"]},{"code":"TIPS","name":"Fedoracoin","statuses":["primary"]},{"code":"FFC","name":"FFC","statuses":["primary"]},{"code":"FIBRE","name":"Fibre","statuses":["primary"]},{"code":"FIT","name":"FIT","statuses":["primary"]},{"code":"FJC","name":"FJC","statuses":["primary"]},{"code":"FLO","name":"Florincoin","statuses":["primary"]},{"code":"FLOZ","name":"FLOZ","statuses":["primary"]},{"code":"FLT","name":"FlutterCoin","statuses":["primary"]},{"code":"FLX","name":"FLX","statuses":["primary"]},{"code":"FLY","name":"Flycoin","statuses":["primary"]},{"code":"FLDC","name":"FoldingCoin","statuses":["primary"]},{"code":"FONZ","name":"FONZ","statuses":["primary"]},{"code":"FRK","name":"Franko","statuses":["primary"]},{"code":"FRC","name":"Freicoin","statuses":["primary"]},{"code":"FRN","name":"FRN","statuses":["primary"]},{"code":"FRWC","name":"FRWC","statuses":["primary"]},{"code":"FSC2","name":"FSC2","statuses":["primary"]},{"code":"FST","name":"FST","statuses":["primary"]},{"code":"FTP","name":"FTP","statuses":["primary"]},{"code":"FUN","name":"FUN","statuses":["primary"]},{"code":"FUTC","name":"FUTC","statuses":["primary"]},{"code":"FUZZ","name":"FUZZ","statuses":["primary"]},{"code":"GAIA","name":"GAIA","statuses":["primary"]},{"code":"GAIN","name":"GAIN","statuses":["primary"]},{"code":"GAKH","name":"GAKH","statuses":["primary"]},{"code":"GAM","name":"GAM","statuses":["primary"]},{"code":"GBT","name":"GameBet Coin","statuses":["primary"]},{"code":"GAME","name":"GameCredits","statuses":["primary"]},{"code":"GAP","name":"Gapcoin","statuses":["primary"]},{"code":"GARY","name":"GARY","statuses":["primary"]},{"code":"GB","name":"GB","statuses":["primary"]},{"code":"GBC","name":"GBC","statuses":["primary"]},{"code":"GBIT","name":"GBIT","statuses":["primary"]},{"code":"GCC","name":"GCC","statuses":["primary"]},{"code":"GCN","name":"GCN","statuses":["primary"]},{"code":"GEO","name":"GeoCoin","statuses":["primary"]},{"code":"GEMZ","name":"GetGems","statuses":["primary"]},{"code":"GHOST","name":"GHOST","statuses":["primary"]},{"code":"GHS","name":"GHS","statuses":["primary"]},{"code":"GIFT","name":"GIFT","statuses":["primary"]},{"code":"GIG","name":"GIG","statuses":["primary"]},{"code":"GLC","name":"GLC","statuses":["primary"]},{"code":"BSTY","name":"GlobalBoost-Y","statuses":["primary"]},{"code":"GML","name":"GML","statuses":["primary"]},{"code":"GMX","name":"GMX","statuses":["primary"]},{"code":"GCR","name":"GoCoineR","statuses":["primary"]},{"code":"GLD","name":"GoldCoin","statuses":["primary"]},{"code":"GOON","name":"GOON","statuses":["primary"]},{"code":"GP","name":"GP","statuses":["primary"]},{"code":"GPU","name":"GPU","statuses":["primary"]},{"code":"GRAM","name":"GRAM","statuses":["primary"]},{"code":"GRT","name":"Grantcoin","statuses":["primary"]},{"code":"GRE","name":"GRE","statuses":["primary"]},{"code":"GRC","name":"Gridcoin","statuses":["primary"]},{"code":"GRN","name":"GRN","statuses":["primary"]},{"code":"GRS","name":"Groestlcoin","statuses":["primary"]},{"code":"GRW","name":"GRW","statuses":["primary"]},{"code":"GSM","name":"GSM","statuses":["primary"]},{"code":"GSX","name":"GSX","statuses":["primary"]},{"code":"GUA","name":"GUA","statuses":["primary"]},{"code":"NLG","name":"Gulden","statuses":["primary"]},{"code":"GUN","name":"GUN","statuses":["primary"]},{"code":"HAM","name":"HAM","statuses":["primary"]},{"code":"HAWK","name":"HAWK","statuses":["primary"]},{"code":"HCC","name":"HCC","statuses":["primary"]},{"code":"HEAT","name":"HEAT","statuses":["primary"]},{"code":"HMP","name":"HempCoin","statuses":["primary"]},{"code":"XHI","name":"HiCoin","statuses":["primary"]},{"code":"HIFUN","name":"HIFUN","statuses":["primary"]},{"code":"HILL","name":"HILL","statuses":["primary"]},{"code":"HIRE","name":"HIRE","statuses":["primary"]},{"code":"HNC","name":"HNC","statuses":["primary"]},{"code":"HODL","name":"HOdlcoin","statuses":["primary"]},{"code":"HKD","name":"Hong Kong Dollar","statuses":["secondary"]},{"code":"HZ","name":"Horizon","statuses":["primary"]},{"code":"HTC","name":"HTC","statuses":["primary"]},{"code":"HTML5","name":"HTMLCOIN","statuses":["primary"]},{"code":"HUC","name":"HUC","statuses":["primary"]},{"code":"HVCO","name":"HVCO","statuses":["primary"]},{"code":"HYPER","name":"Hyper","statuses":["primary"]},{"code":"HYP","name":"HyperStake","statuses":["primary"]},{"code":"I0C","name":"I0C","statuses":["primary"]},{"code":"IBANK","name":"IBANK","statuses":["primary"]},{"code":"ICASH","name":"iCash","statuses":["primary"]},{"code":"ICN","name":"ICN","statuses":["primary"]},{"code":"IEC","name":"IEC","statuses":["primary"]},{"code":"IFC","name":"Infinitecoin","statuses":["primary"]},{"code":"INFX","name":"Influxcoin","statuses":["primary"]},{"code":"INV","name":"INV","statuses":["primary"]},{"code":"IOC","name":"IO Coin","statuses":["primary"]},{"code":"ION","name":"ION","statuses":["primary"]},{"code":"IRL","name":"IRL","statuses":["primary"]},{"code":"ISL","name":"IslaCoin","statuses":["primary"]},{"code":"IVZ","name":"IVZ","statuses":["primary"]},{"code":"IXC","name":"IXC","statuses":["primary"]},{"code":"JIF","name":"JIF","statuses":["primary"]},{"code":"JPC","name":"JPC","statuses":["primary"]},{"code":"JPY","name":"JPY","statuses":["primary","secondary"]},{"code":"JBS","name":"Jumbucks","statuses":["primary"]},{"code":"KAT","name":"KAT","statuses":["primary"]},{"code":"KGC","name":"KGC","statuses":["primary"]},{"code":"KNC","name":"KhanCoin","statuses":["primary"]},{"code":"KLC","name":"KLC","statuses":["primary"]},{"code":"KOBO","name":"KOBO","statuses":["primary"]},{"code":"KORE","name":"KoreCoin","statuses":["primary"]},{"code":"KRAK","name":"KRAK","statuses":["primary"]},{"code":"KRYP","name":"KRYP","statuses":["primary"]},{"code":"KR","name":"Krypton","statuses":["primary"]},{"code":"KTK","name":"KTK","statuses":["primary"]},{"code":"KUBO","name":"KUBO","statuses":["primary"]},{"code":"LANA","name":"LANA","statuses":["primary"]},{"code":"LBC","name":"LBC","statuses":["primary"]},{"code":"LC","name":"LC","statuses":["primary"]},{"code":"LEA","name":"LeaCoin","statuses":["primary"]},{"code":"LEMON","name":"LEMON","statuses":["primary"]},{"code":"LEO","name":"LEO","statuses":["primary"]},{"code":"LFC","name":"LFC","statuses":["primary"]},{"code":"LFO","name":"LFO","statuses":["primary"]},{"code":"LFTC","name":"LFTC","statuses":["primary"]},{"code":"LQD","name":"LIQUID","statuses":["primary"]},{"code":"LIR","name":"LIR","statuses":["primary"]},{"code":"LSK","name":"Lisk","statuses":["primary"]},{"code":"LTC","name":"Litecoin","statuses":["primary","secondary"]},{"code":"LTCR","name":"Litecred","statuses":["primary"]},{"code":"LDOGE","name":"LiteDoge","statuses":["primary"]},{"code":"LKC","name":"LKC","statuses":["primary"]},{"code":"LOC","name":"LOC","statuses":["primary"]},{"code":"LOOT","name":"LOOT","statuses":["primary"]},{"code":"LTBC","name":"LTBcoin","statuses":["primary"]},{"code":"LTH","name":"LTH","statuses":["primary"]},{"code":"LTS","name":"LTS","statuses":["primary"]},{"code":"LUN","name":"LUN","statuses":["primary"]},{"code":"LXC","name":"LXC","statuses":["primary"]},{"code":"LYB","name":"LYB","statuses":["primary"]},{"code":"M1","name":"M1","statuses":["primary"]},{"code":"MAD","name":"MAD","statuses":["primary"]},{"code":"XMG","name":"Magi","statuses":["primary"]},{"code":"MAID","name":"MaidSafeCoin","statuses":["primary"]},{"code":"MXT","name":"MarteXcoin","statuses":["primary"]},{"code":"MARV","name":"MARV","statuses":["primary"]},{"code":"MARYJ","name":"MARYJ","statuses":["primary"]},{"code":"OMNI","name":"Mastercoin (Omni)","statuses":["primary"]},{"code":"MTR","name":"MasterTraderCoin","statuses":["primary"]},{"code":"MAX","name":"Maxcoin","statuses":["primary"]},{"code":"MZC","name":"Mazacoin","statuses":["primary"]},{"code":"MBL","name":"MBL","statuses":["primary"]},{"code":"MCAR","name":"MCAR","statuses":["primary"]},{"code":"MCN","name":"MCN","statuses":["primary"]},{"code":"MCZ","name":"MCZ","statuses":["primary"]},{"code":"MED","name":"MediterraneanCoin","statuses":["primary"]},{"code":"MEC","name":"Megacoin","statuses":["primary"]},{"code":"MEME","name":"Memetic","statuses":["primary"]},{"code":"METAL","name":"METAL","statuses":["primary"]},{"code":"MND","name":"MindCoin","statuses":["primary"]},{"code":"MINT","name":"Mintcoin","statuses":["primary"]},{"code":"MIS","name":"MIS","statuses":["primary"]},{"code":"MM","name":"MM","statuses":["primary"]},{"code":"MMC","name":"MMC","statuses":["primary"]},{"code":"MMNXT","name":"MMNXT","statuses":["primary"]},{"code":"MMXVI","name":"MMXVI","statuses":["primary"]},{"code":"MNM","name":"MNM","statuses":["primary"]},{"code":"MOIN","name":"MOIN","statuses":["primary"]},{"code":"MOJO","name":"MojoCoin","statuses":["primary"]},{"code":"MONA","name":"MonaCoin","statuses":["primary"]},{"code":"XMR","name":"Monero","statuses":["primary","secondary"]},{"code":"MNTA","name":"Moneta","statuses":["primary"]},{"code":"MUE","name":"MonetaryUnit","statuses":["primary"]},{"code":"MOON","name":"Mooncoin","statuses":["primary"]},{"code":"MOOND","name":"MOOND","statuses":["primary"]},{"code":"MOTO","name":"MOTO","statuses":["primary"]},{"code":"MPRO","name":"MPRO","statuses":["primary"]},{"code":"MRB","name":"MRB","statuses":["primary"]},{"code":"MRP","name":"MRP","statuses":["primary"]},{"code":"MSC","name":"MSC","statuses":["primary"]},{"code":"MYR","name":"Myriadcoin","statuses":["primary"]},{"code":"NMC","name":"Namecoin","statuses":["primary"]},{"code":"NAUT","name":"Nautiluscoin","statuses":["primary"]},{"code":"NAV","name":"NAV Coin","statuses":["primary"]},{"code":"NCS","name":"NCS","statuses":["primary"]},{"code":"XEM","name":"NEM","statuses":["primary"]},{"code":"NEOS","name":"NeosCoin","statuses":["primary"]},{"code":"NETC","name":"NETC","statuses":["primary"]},{"code":"NET","name":"NetCoin","statuses":["primary"]},{"code":"NEU","name":"NeuCoin","statuses":["primary"]},{"code":"NTRN","name":"Neutron","statuses":["primary"]},{"code":"NEVA","name":"NevaCoin","statuses":["primary"]},{"code":"NEWB","name":"NEWB","statuses":["primary"]},{"code":"NIRO","name":"Nexus","statuses":["primary"]},{"code":"NIC","name":"NIC","statuses":["primary"]},{"code":"NKA","name":"NKA","statuses":["primary"]},{"code":"NKC","name":"NKC","statuses":["primary"]},{"code":"NOBL","name":"NobleCoin","statuses":["primary"]},{"code":"NODE","name":"NODE","statuses":["primary"]},{"code":"NODES","name":"NODES","statuses":["primary"]},{"code":"NOO","name":"NOO","statuses":["primary"]},{"code":"NVC","name":"Novacoin","statuses":["primary"]},{"code":"NRC","name":"NRC","statuses":["primary"]},{"code":"NRS","name":"NRS","statuses":["primary"]},{"code":"NUBIS","name":"NUBIS","statuses":["primary"]},{"code":"NBT","name":"NuBits","statuses":["primary"]},{"code":"NUM","name":"NUM","statuses":["primary"]},{"code":"NSR","name":"NuShares","statuses":["primary"]},{"code":"NXE","name":"NXE","statuses":["primary"]},{"code":"NXT","name":"NXT","statuses":["primary"]},{"code":"NXTTY","name":"Nxttycoin","statuses":["primary"]},{"code":"NYC","name":"NYC","statuses":["primary"]},{"code":"NZC","name":"NZC","statuses":["primary"]},{"code":"NZD","name":"NZD","statuses":["primary","secondary"]},{"code":"OC","name":"OC","statuses":["primary"]},{"code":"OCOW","name":"OCOW","statuses":["primary"]},{"code":"OK","name":"OKCash","statuses":["primary"]},{"code":"OMA","name":"OMA","statuses":["primary"]},{"code":"ONE","name":"ONE","statuses":["primary"]},{"code":"ONEC","name":"ONEC","statuses":["primary"]},{"code":"OP","name":"OP","statuses":["primary"]},{"code":"OPAL","name":"OPAL","statuses":["primary"]},{"code":"OPES","name":"OPES","statuses":["primary"]},{"code":"ORB","name":"Orbitcoin","statuses":["primary"]},{"code":"ORLY","name":"Orlycoin","statuses":["primary"]},{"code":"OS76","name":"OS76","statuses":["primary"]},{"code":"OZC","name":"OZC","statuses":["primary"]},{"code":"PAC","name":"PAC","statuses":["primary"]},{"code":"PAK","name":"PAK","statuses":["primary"]},{"code":"PND","name":"Pandacoin","statuses":["primary"]},{"code":"PAPAF","name":"PAPAF","statuses":["primary"]},{"code":"XPY","name":"Paycoin","statuses":["primary"]},{"code":"PBC","name":"PBC","statuses":["primary"]},{"code":"PDC","name":"PDC","statuses":["primary"]},{"code":"XPB","name":"Pebblecoin","statuses":["primary"]},{"code":"PPC","name":"Peercoin","statuses":["primary"]},{"code":"PEN","name":"PEN","statuses":["primary"]},{"code":"PHR","name":"PHR","statuses":["primary"]},{"code":"PIGGY","name":"Piggycoin","statuses":["primary"]},{"code":"PC","name":"Pinkcoin","statuses":["primary"]},{"code":"PKB","name":"PKB","statuses":["primary"]},{"code":"PLN","name":"PLN","statuses":["primary","secondary"]},{"code":"PLNC","name":"PLNC","statuses":["primary"]},{"code":"PNC","name":"PNC","statuses":["primary"]},{"code":"PNK","name":"PNK","statuses":["primary"]},{"code":"POKE","name":"POKE","statuses":["primary"]},{"code":"PONZ2","name":"PONZ2","statuses":["primary"]},{"code":"PONZI","name":"PONZI","statuses":["primary"]},{"code":"PEX","name":"PosEx","statuses":["primary"]},{"code":"POST","name":"POST","statuses":["primary"]},{"code":"POT","name":"Potcoin","statuses":["primary"]},{"code":"PRES","name":"PRES","statuses":["primary"]},{"code":"PXI","name":"Prime-XI","statuses":["primary"]},{"code":"PRIME","name":"PrimeChain","statuses":["primary"]},{"code":"XPM","name":"Primecoin","statuses":["primary"]},{"code":"PRM","name":"PRM","statuses":["primary"]},{"code":"PRT","name":"PRT","statuses":["primary"]},{"code":"PSP","name":"PSP","statuses":["primary"]},{"code":"PTC","name":"PTC","statuses":["primary"]},{"code":"PULSE","name":"PULSE","statuses":["primary"]},{"code":"PURE","name":"PURE","statuses":["primary"]},{"code":"PUTIN","name":"PUTIN","statuses":["primary"]},{"code":"PWR","name":"PWR","statuses":["primary"]},{"code":"PXL","name":"PXL","statuses":["primary"]},{"code":"QBC","name":"QBC","statuses":["primary"]},{"code":"QBK","name":"QBK","statuses":["primary"]},{"code":"QCN","name":"QCN","statuses":["primary"]},{"code":"QORA","name":"Qora","statuses":["primary"]},{"code":"QTZ","name":"QTZ","statuses":["primary"]},{"code":"QRK","name":"Quark","statuses":["primary"]},{"code":"QTL","name":"Quatloo","statuses":["primary"]},{"code":"RADI","name":"RADI","statuses":["primary"]},{"code":"RADS","name":"Radium","statuses":["primary"]},{"code":"RED","name":"RED","statuses":["primary"]},{"code":"RDD","name":"Reddcoin","statuses":["primary"]},{"code":"REE","name":"REE","statuses":["primary"]},{"code":"REV","name":"Revenu","statuses":["primary"]},{"code":"RBR","name":"RibbitRewards","statuses":["primary"]},{"code":"RICHX","name":"RICHX","statuses":["primary"]},{"code":"RIC","name":"Riecoin","statuses":["primary"]},{"code":"RBT","name":"Rimbit","statuses":["primary"]},{"code":"RIO","name":"RIO","statuses":["primary"]},{"code":"XRP","name":"Ripple","statuses":["primary"]},{"code":"RISE","name":"RISE","statuses":["primary"]},{"code":"RMS","name":"RMS","statuses":["primary"]},{"code":"RONIN","name":"RONIN","statuses":["primary"]},{"code":"ROOT","name":"ROOT","statuses":["primary"]},{"code":"ROS","name":"RosCoin","statuses":["primary"]},{"code":"RPC","name":"RPC","statuses":["primary"]},{"code":"RBIES","name":"Rubies","statuses":["primary"]},{"code":"RUBIT","name":"RUBIT","statuses":["primary"]},{"code":"RUR","name":"Ruble","statuses":["secondary"]},{"code":"RBY","name":"Rubycoin","statuses":["primary"]},{"code":"RUST","name":"RUST","statuses":["primary"]},{"code":"SEC","name":"Safe Exchange Coin","statuses":["primary"]},{"code":"SAK","name":"SAK","statuses":["primary"]},{"code":"SAR","name":"SAR","statuses":["primary"]},{"code":"SBD","name":"SBD","statuses":["primary"]},{"code":"SBIT","name":"SBIT","statuses":["primary"]},{"code":"SCAN","name":"SCAN","statuses":["primary"]},{"code":"SCOT","name":"Scotcoin","statuses":["primary"]},{"code":"SCRPT","name":"SCRPT","statuses":["primary"]},{"code":"SCRT","name":"SCRT","statuses":["primary"]},{"code":"SRC","name":"SecureCoin","statuses":["primary"]},{"code":"SXC","name":"Sexcoin","statuses":["primary"]},{"code":"SFE","name":"SFE","statuses":["primary"]},{"code":"SFR","name":"SFR","statuses":["primary"]},{"code":"SGD","name":"SGD","statuses":["primary","secondary"]},{"code":"SDC","name":"ShadowCash","statuses":["primary"]},{"code":"SHELL","name":"SHELL","statuses":["primary"]},{"code":"SHF","name":"SHF","statuses":["primary"]},{"code":"SHI","name":"SHI","statuses":["primary"]},{"code":"SHIFT","name":"Shift","statuses":["primary"]},{"code":"SHREK","name":"SHREK","statuses":["primary"]},{"code":"SC","name":"Siacoin","statuses":["primary"]},{"code":"SIB","name":"Siberian chervonets","statuses":["primary"]},{"code":"SIC","name":"SIC","statuses":["primary"]},{"code":"SIGU","name":"SIGU","statuses":["primary"]},{"code":"SILK","name":"Silkcoin","statuses":["primary"]},{"code":"SIX","name":"SIX","statuses":["primary"]},{"code":"SLING","name":"Sling","statuses":["primary"]},{"code":"SLS","name":"SLS","statuses":["primary"]},{"code":"SMBR","name":"SMBR","statuses":["primary"]},{"code":"SMC","name":"SMC","statuses":["primary"]},{"code":"SMLY","name":"SmileyCoin","statuses":["primary"]},{"code":"SNRG","name":"SNRG","statuses":["primary"]},{"code":"SOIL","name":"SOILcoin","statuses":["primary"]},{"code":"SLR","name":"Solarcoin","statuses":["primary"]},{"code":"SOLO","name":"SOLO","statuses":["primary"]},{"code":"SONG","name":"SongCoin","statuses":["primary"]},{"code":"SOON","name":"SOON","statuses":["primary"]},{"code":"SPC","name":"SPC","statuses":["primary"]},{"code":"SPEX","name":"SPEX","statuses":["primary"]},{"code":"SPHR","name":"Sphere","statuses":["primary"]},{"code":"SPM","name":"SPM","statuses":["primary"]},{"code":"SPN","name":"SPN","statuses":["primary"]},{"code":"SPOTS","name":"SPOTS","statuses":["primary"]},{"code":"SPR","name":"SpreadCoin","statuses":["primary"]},{"code":"SPRTS","name":"Sprouts","statuses":["primary"]},{"code":"SQC","name":"SQC","statuses":["primary"]},{"code":"SSC","name":"SSC","statuses":["primary"]},{"code":"SSTC","name":"SSTC","statuses":["primary"]},{"code":"STA","name":"STA","statuses":["primary"]},{"code":"START","name":"Startcoin","statuses":["primary"]},{"code":"XST","name":"Stealthcoin","statuses":["primary"]},{"code":"STEEM","name":"Steem","statuses":["primary"]},{"code":"XLM","name":"Stellar","statuses":["primary"]},{"code":"STR","name":"Stellar","statuses":["primary"]},{"code":"STEPS","name":"Steps","statuses":["primary"]},{"code":"SLG","name":"Sterlingcoin","statuses":["primary"]},{"code":"STL","name":"STL","statuses":["primary"]},{"code":"SJCX","name":"Storjcoin X","statuses":["primary"]},{"code":"STP","name":"STP","statuses":["primary"]},{"code":"STRB","name":"STRB","statuses":["primary"]},{"code":"STS","name":"Stress","statuses":["primary"]},{"code":"STRP","name":"STRP","statuses":["primary"]},{"code":"STV","name":"STV","statuses":["primary"]},{"code":"SUB","name":"Subcriptio","statuses":["primary"]},{"code":"SUPER","name":"SUPER","statuses":["primary"]},{"code":"UNITY","name":"SuperNET","statuses":["primary"]},{"code":"SWARM","name":"Swarm","statuses":["primary"]},{"code":"SWING","name":"SWING","statuses":["primary"]},{"code":"SDP","name":"SydPak Coin","statuses":["primary"]},{"code":"SYNC","name":"SYNC","statuses":["primary"]},{"code":"AMP","name":"Synereo","statuses":["primary"]},{"code":"SYS","name":"Syscoin","statuses":["primary"]},{"code":"TAG","name":"TagCoin","statuses":["primary"]},{"code":"TAJ","name":"TAJ","statuses":["primary"]},{"code":"TAK","name":"TAK","statuses":["primary"]},{"code":"TAM","name":"TAM","statuses":["primary"]},{"code":"TAO","name":"TAO","statuses":["primary"]},{"code":"TBC","name":"TBC","statuses":["primary"]},{"code":"TBCX","name":"TBCX","statuses":["primary"]},{"code":"TCR","name":"TCR","statuses":["primary"]},{"code":"TDFB","name":"TDFB","statuses":["primary"]},{"code":"TDY","name":"TDY","statuses":["primary"]},{"code":"TEK","name":"TEKcoin","statuses":["primary"]},{"code":"TRC","name":"Terracoin","statuses":["primary"]},{"code":"TESLA","name":"TESLA","statuses":["primary"]},{"code":"TES","name":"TeslaCoin","statuses":["primary"]},{"code":"TET","name":"TET","statuses":["primary"]},{"code":"USDT","name":"Tether","statuses":["primary","secondary"]},{"code":"THC","name":"THC","statuses":["primary"]},{"code":"THS","name":"THS","statuses":["primary"]},{"code":"TIX","name":"Tickets","statuses":["primary"]},{"code":"XTC","name":"TileCoin","statuses":["primary"]},{"code":"TIT","name":"Titcoin","statuses":["primary"]},{"code":"TTC","name":"TittieCoin","statuses":["primary"]},{"code":"TMC","name":"TMC","statuses":["primary"]},{"code":"TODAY","name":"TODAY","statuses":["primary"]},{"code":"TOKEN","name":"TOKEN","statuses":["primary"]},{"code":"TP1","name":"TP1","statuses":["primary"]},{"code":"TPC","name":"TPC","statuses":["primary"]},{"code":"TPG","name":"TPG","statuses":["primary"]},{"code":"TX","name":"Transfercoin","statuses":["primary"]},{"code":"TRAP","name":"TRAP","statuses":["primary"]},{"code":"TRICK","name":"TRICK","statuses":["primary"]},{"code":"TROLL","name":"TROLL","statuses":["primary"]},{"code":"TRK","name":"Truckcoin","statuses":["primary"]},{"code":"TRUMP","name":"TrumpCoin","statuses":["primary"]},{"code":"TRUST","name":"TRUST","statuses":["primary"]},{"code":"UAE","name":"UAE","statuses":["primary"]},{"code":"UFO","name":"UFO Coin","statuses":["primary"]},{"code":"UIS","name":"UIS","statuses":["primary"]},{"code":"UTC","name":"UltraCoin","statuses":["primary"]},{"code":"UNC","name":"UNC","statuses":["primary"]},{"code":"UNIQ","name":"UNIQ","statuses":["primary"]},{"code":"UNIT","name":"Universal Currency","statuses":["primary"]},{"code":"UNO","name":"Unobtanium","statuses":["primary"]},{"code":"URO","name":"Uro","statuses":["primary"]},{"code":"USD","name":"US Dollar","statuses":["primary","secondary"]},{"code":"USDE","name":"USDE","statuses":["primary"]},{"code":"UTH","name":"UTH","statuses":["primary"]},{"code":"VAL","name":"VAL","statuses":["primary"]},{"code":"XVC","name":"Vcash","statuses":["primary"]},{"code":"VCN","name":"VCN","statuses":["primary"]},{"code":"VEG","name":"VEG","statuses":["primary"]},{"code":"VENE","name":"VENE","statuses":["primary"]},{"code":"XVG","name":"Verge","statuses":["primary"]},{"code":"VRC","name":"VeriCoin","statuses":["primary"]},{"code":"VTC","name":"Vertcoin","statuses":["primary"]},{"code":"VIA","name":"Viacoin","statuses":["primary"]},{"code":"VIOR","name":"Viorcoin","statuses":["primary"]},{"code":"VIP","name":"VIP Tokens","statuses":["primary"]},{"code":"VIRAL","name":"Viral","statuses":["primary"]},{"code":"VOOT","name":"VootCoin","statuses":["primary"]},{"code":"VOX","name":"Voxels","statuses":["primary"]},{"code":"VOYA","name":"VOYA","statuses":["primary"]},{"code":"VPN","name":"VPNCoin","statuses":["primary"]},{"code":"VPRC","name":"VPRC","statuses":["primary"]},{"code":"VTA","name":"VTA","statuses":["primary"]},{"code":"VTN","name":"VTN","statuses":["primary"]},{"code":"VTR","name":"VTR","statuses":["primary"]},{"code":"WAC","name":"WAC","statuses":["primary"]},{"code":"WARP","name":"WARP","statuses":["primary"]},{"code":"WAVES","name":"WAVES","statuses":["primary"]},{"code":"WGC","name":"WGC","statuses":["primary"]},{"code":"XWC","name":"Whitecoin","statuses":["primary"]},{"code":"WBB","name":"Wild Beast Block","statuses":["primary"]},{"code":"WLC","name":"WLC","statuses":["primary"]},{"code":"WMC","name":"WMC","statuses":["primary"]},{"code":"LOG","name":"Woodcoin","statuses":["primary"]},{"code":"WOP","name":"WOP","statuses":["primary"]},{"code":"WDC","name":"Worldcoin","statuses":["primary"]},{"code":"XAB","name":"XAB","statuses":["primary"]},{"code":"XAI","name":"XAI","statuses":["primary"]},{"code":"XAU","name":"Xaurum","statuses":["primary"]},{"code":"XBS","name":"XBS","statuses":["primary"]},{"code":"XBU","name":"XBU","statuses":["primary"]},{"code":"XCO","name":"XCO","statuses":["primary"]},{"code":"XC","name":"XCurrency","statuses":["primary"]},{"code":"XDB","name":"XDB","statuses":["primary"]},{"code":"XEMP","name":"XEMP","statuses":["primary"]},{"code":"XFC","name":"XFC","statuses":["primary"]},{"code":"MI","name":"Xiaomicoin","statuses":["primary"]},{"code":"XID","name":"XID","statuses":["primary"]},{"code":"XJO","name":"XJO","statuses":["primary"]},{"code":"XLTCG","name":"XLTCG","statuses":["primary"]},{"code":"XMS","name":"XMS","statuses":["primary"]},{"code":"XNX","name":"XNX","statuses":["primary"]},{"code":"XPD","name":"XPD","statuses":["primary"]},{"code":"XPOKE","name":"XPOKE","statuses":["primary"]},{"code":"XPRO","name":"XPRO","statuses":["primary"]},{"code":"XQN","name":"XQN","statuses":["primary"]},{"code":"XSEED","name":"XSEED","statuses":["primary"]},{"code":"XSP","name":"XSP","statuses":["primary"]},{"code":"XT","name":"XT","statuses":["primary"]},{"code":"XTP","name":"XTP","statuses":["primary"]},{"code":"XUSD","name":"XUSD","statuses":["primary"]},{"code":"YACC","name":"YACC","statuses":["primary"]},{"code":"YAC","name":"Yacoin","statuses":["primary"]},{"code":"YAY","name":"YAY","statuses":["primary"]},{"code":"YBC","name":"Ybcoin","statuses":["primary"]},{"code":"YOC","name":"YOC","statuses":["primary"]},{"code":"YOVI","name":"YOVI","statuses":["primary"]},{"code":"YUM","name":"YUM","statuses":["primary"]},{"code":"ZCC","name":"ZCC","statuses":["primary"]},{"code":"ZEIT","name":"Zeitcoin","statuses":["primary"]},{"code":"ZET","name":"Zetacoin","statuses":["primary"]},{"code":"ZRC","name":"ZiftrCOIN","statuses":["primary"]},{"code":"ZMC","name":"ZMC","statuses":["primary"]},{"code":"ZNY","name":"ZNY","statuses":["primary"]},{"code":"ZS","name":"ZS","statuses":["primary"]}]}
+
+module.exports = {
+ availableCurrencies
+}
diff --git a/ui/app/css/index.css b/ui/app/css/index.css
index 612dc9d9a..e2be0abd9 100644
--- a/ui/app/css/index.css
+++ b/ui/app/css/index.css
@@ -471,3 +471,128 @@ input.large-input {
.eth-warning{
transition: opacity 400ms ease-in, transform 400ms ease-in;
}
+
+.buy-subview{
+ transition: opacity 400ms ease-in, transform 400ms ease-in;
+}
+
+.input-container:hover .edit-text{
+ visibility: visible;
+}
+
+.buy-inputs{
+ font-family: 'Montserrat Light';
+ font-size: 13px;
+ height: 20px;
+ background: transparent;
+ box-sizing: border-box;
+ border: solid;
+ border-color: transparent;
+ border-width: 0.5px;
+ border-radius: 2px;
+
+}
+.input-container:hover .buy-inputs{
+ box-sizing: inherit;
+ border: solid;
+ border-color: #F7861C;
+ border-width: 0.5px;
+ border-radius: 2px;
+}
+
+.buy-inputs:focus{
+ border: solid;
+ border-color: #F7861C;
+ border-width: 0.5px;
+ border-radius: 2px;
+}
+
+.activeForm {
+ background: #F7F7F7;
+ border: none;
+ border-radius: 8px 8px 0px 0px;
+ width: 50%;
+ text-align: center;
+ padding-bottom: 4px;
+
+}
+
+.inactiveForm {
+ border: none;
+ border-radius: 8px 8px 0px 0px;
+ width: 50%;
+ text-align: center;
+ padding-bottom: 4px;
+}
+
+.ex-coins {
+ font-family: 'Montserrat Regular';
+ text-transform: uppercase;
+ text-align: center;
+ font-size: 33px;
+ width: 118px;
+ height: 42px;
+ padding: 1px;
+ color: #4D4D4D;
+}
+
+.marketinfo{
+ font-family: 'Montserrat light';
+ color: #AEAEAE;
+ font-size: 12px;
+ line-height: 14px;
+}
+
+#fromCoin::-webkit-calendar-picker-indicator {
+ display: none;
+}
+
+#coinList {
+ width: 400px;
+ height: 500px;
+ overflow: scroll;
+}
+
+.icon-control .fa-refresh{
+ visibility: hidden;
+}
+
+.icon-control:hover .fa-refresh{
+ visibility: visible;
+}
+
+.icon-control:hover .fa-chevron-right{
+ visibility: hidden;
+}
+
+.inactive {
+ color: #AEAEAE;
+}
+
+.inactive button{
+ background: #AEAEAE;
+ color: white;
+}
+
+.ellip-address {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ width: 5em;
+ font-size: 14px;
+ font-family: "Montserrat Light";
+ margin-left: 5px;
+}
+
+.qr-message {
+ font-size: 12px;
+ color: #F7861C;
+}
+
+div.message-container > div:first-child {
+ font-size: 15px;
+ color: #4D4D4D;
+}
+
+.pop-hover:hover {
+ transform: scale(1.1);
+}
diff --git a/ui/app/eth-store-warning.js b/ui/app/eth-store-warning.js
index 7fe54a309..55274996b 100644
--- a/ui/app/eth-store-warning.js
+++ b/ui/app/eth-store-warning.js
@@ -35,9 +35,10 @@ EthStoreWarning.prototype.render = function () {
margin: '10px 10px 10px 10px',
},
},
- `MetaMask is currently in beta -
- exercise caution while handling
- and storing your ether.
+ `The MetaMask team would like to
+ remind you that MetaMask is currently in beta - so
+ don't store large
+ amounts of ether in MetaMask.
`),
h('i.fa.fa-exclamation-triangle.fa-4', {
diff --git a/ui/app/first-time/init-menu.js b/ui/app/first-time/init-menu.js
index e63c30fc5..94a9d3df6 100644
--- a/ui/app/first-time/init-menu.js
+++ b/ui/app/first-time/init-menu.js
@@ -73,9 +73,7 @@ InitializeMenuScreen.prototype.renderMenu = function () {
margin: 12,
},
}, 'Restore Existing Vault'),
-
])
-
)
}
diff --git a/ui/app/first-time/restore-vault.js b/ui/app/first-time/restore-vault.js
index 684781e50..4c1f21008 100644
--- a/ui/app/first-time/restore-vault.js
+++ b/ui/app/first-time/restore-vault.js
@@ -1,14 +1,14 @@
const inherits = require('util').inherits
-const Component = require('react').Component
+const PersistentForm = require('../../lib/persistent-form')
const connect = require('react-redux').connect
const h = require('react-hyperscript')
const actions = require('../actions')
module.exports = connect(mapStateToProps)(RestoreVaultScreen)
-inherits(RestoreVaultScreen, Component)
+inherits(RestoreVaultScreen, PersistentForm)
function RestoreVaultScreen () {
- Component.call(this)
+ PersistentForm.call(this)
}
function mapStateToProps (state) {
@@ -19,6 +19,8 @@ function mapStateToProps (state) {
RestoreVaultScreen.prototype.render = function () {
var state = this.props
+ this.persistentFormParentId = 'restore-vault-form'
+
return (
h('.initialize-screen.flex-column.flex-center.flex-grow', [
@@ -39,6 +41,9 @@ RestoreVaultScreen.prototype.render = function () {
// wallet seed entry
h('h3', 'Wallet Seed'),
h('textarea.twelve-word-phrase.letter-spacey', {
+ dataset: {
+ persistentFormId: 'wallet-seed',
+ },
placeholder: 'Enter your secret twelve word phrase here to restore your vault.',
}),
@@ -47,6 +52,9 @@ RestoreVaultScreen.prototype.render = function () {
type: 'password',
id: 'password-box',
placeholder: 'New Password (min 8 chars)',
+ dataset: {
+ persistentFormId: 'password',
+ },
style: {
width: 260,
marginTop: 12,
@@ -59,6 +67,9 @@ RestoreVaultScreen.prototype.render = function () {
id: 'password-box-confirm',
placeholder: 'Confirm Password',
onKeyPress: this.onMaybeCreate.bind(this),
+ dataset: {
+ persistentFormId: 'password-confirmation',
+ },
style: {
width: 260,
marginTop: 16,
diff --git a/ui/app/reducers/app.js b/ui/app/reducers/app.js
index a9d6e4ff0..bad11113a 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 txHelper = require('../../lib/tx-helper')
+const notification = require('../../../app/scripts/lib/notifications')
module.exports = reduceApp
@@ -123,6 +124,7 @@ function reduceApp (state, action) {
case actions.UNLOCK_METAMASK:
return extend(appState, {
+ forgottenPassword: appState.forgottenPassword ? !appState.forgottenPassword : null,
detailView: {},
transForward: true,
isLoading: false,
@@ -136,6 +138,25 @@ function reduceApp (state, action) {
warning: null,
})
+ case actions.BACK_TO_INIT_MENU:
+ return extend(appState, {
+ warning: null,
+ transForward: false,
+ forgottenPassword: true,
+ currentView: {
+ name: 'InitMenu',
+ },
+ })
+
+ case actions.BACK_TO_UNLOCK_VIEW:
+ return extend(appState, {
+ warning: null,
+ transForward: true,
+ forgottenPassword: !appState.forgottenPassword,
+ currentView: {
+ name: 'UnlockScreen',
+ },
+ })
// reveal seed words
case actions.REVEAL_SEED_CONFIRMATION:
@@ -170,6 +191,7 @@ function reduceApp (state, action) {
case actions.SHOW_ACCOUNT_DETAIL:
return extend(appState, {
+ forgottenPassword: appState.forgottenPassword ? !appState.forgottenPassword : null,
currentView: {
name: 'accountDetail',
context: action.value,
@@ -250,6 +272,9 @@ function reduceApp (state, action) {
warning: null,
})
} else {
+
+ notification.closePopup()
+
return extend(appState, {
transForward: false,
warning: null,
@@ -317,6 +342,15 @@ function reduceApp (state, action) {
isLoading: false,
})
+ case actions.SHOW_SUB_LOADING_INDICATION:
+ return extend(appState, {
+ isSubLoading: true,
+ })
+
+ case actions.HIDE_SUB_LOADING_INDICATION:
+ return extend(appState, {
+ isSubLoading: false,
+ })
case actions.CLEAR_SEED_WORD_CACHE:
return extend(appState, {
transForward: true,
@@ -369,15 +403,116 @@ function reduceApp (state, action) {
},
})
- case actions.SHOW_ETH_WARNING:
+ case actions.BUY_ETH_VIEW:
return extend(appState, {
transForward: true,
currentView: {
- name: 'accountDetail',
+ name: 'buyEth',
context: appState.currentView.context,
},
- accountDetail: {
- subview: 'buy-eth-warning',
+ buyView: {
+ subview: 'buyForm',
+ amount: '5.00',
+ buyAddress: action.value,
+ formView: {
+ coinbase: true,
+ shapeshift: false,
+ },
+ },
+ })
+
+ case actions.UPDATE_BUY_ADDRESS:
+ return extend(appState, {
+ buyView: {
+ subview: 'buyForm',
+ formView: {
+ coinbase: appState.buyView.formView.coinbase,
+ shapeshift: appState.buyView.formView.shapeshift,
+ },
+ buyAddress: action.value,
+ amount: appState.buyView.amount,
+ },
+ })
+
+ case actions.UPDATE_COINBASE_AMOUNT:
+ return extend(appState, {
+ buyView: {
+ subview: 'buyForm',
+ formView: {
+ coinbase: true,
+ shapeshift: false,
+ },
+ buyAddress: appState.buyView.buyAddress,
+ amount: action.value,
+ },
+ })
+
+ case actions.COINBASE_SUBVIEW:
+ return extend(appState, {
+ buyView: {
+ subview: 'buyForm',
+ formView: {
+ coinbase: true,
+ shapeshift: false,
+ },
+ buyAddress: appState.buyView.buyAddress,
+ amount: appState.buyView.amount,
+ },
+ })
+
+ case actions.SHAPESHIFT_SUBVIEW:
+ return extend(appState, {
+ buyView: {
+ subview: 'buyForm',
+ formView: {
+ coinbase: false,
+ shapeshift: true,
+ marketinfo: action.value.marketinfo,
+ coinOptions: action.value.coinOptions,
+ },
+ buyAddress: appState.buyView.buyAddress,
+ amount: appState.buyView.amount,
+ },
+ })
+
+ case actions.PAIR_UPDATE:
+ return extend(appState, {
+ buyView: {
+ subview: 'buyForm',
+ formView: {
+ coinbase: false,
+ shapeshift: true,
+ marketinfo: action.value.marketinfo,
+ coinOptions: appState.buyView.formView.coinOptions,
+ },
+ buyAddress: appState.buyView.buyAddress,
+ amount: appState.buyView.amount,
+ warning: null,
+ },
+ })
+
+ case actions.SHOW_QR:
+ return extend(appState, {
+ qrRequested: true,
+ transForward: true,
+ Qr: {
+ message: action.value.message,
+ image: action.value.qr,
+ data: action.value.data,
+ },
+ })
+
+ case actions.SHOW_QR_VIEW:
+ return extend(appState, {
+ currentView: {
+ name: 'qr',
+ context: appState.currentView.context,
+ },
+ transForward: true,
+ Qr: {
+ message: action.value.message,
+ image: action.value.qr,
+ data: action.value.data,
},
})
default:
@@ -405,4 +540,3 @@ function indexForPending (state, txId) {
return idx
}
-
diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js
index 8d4520fb1..7f18480cb 100644
--- a/ui/app/reducers/metamask.js
+++ b/ui/app/reducers/metamask.js
@@ -10,10 +10,14 @@ function reduceMetamask (state, action) {
var metamaskState = extend({
isInitialized: false,
isUnlocked: false,
+ isEthConfirmed: false,
currentDomain: 'example.com',
rpcTarget: 'https://rawtestrpc.metamask.io/',
identities: {},
unconfTxs: {},
+ currentFiat: 'USD',
+ conversionRate: 0,
+ conversionDate: 'N/A',
}, state.metamask)
switch (action.type) {
@@ -33,7 +37,7 @@ function reduceMetamask (state, action) {
case actions.AGREE_TO_ETH_WARNING:
return extend(metamaskState, {
- isEthConfirmed: true,
+ isEthConfirmed: !metamaskState.isEthConfirmed,
})
case actions.UNLOCK_METAMASK:
@@ -114,6 +118,13 @@ function reduceMetamask (state, action) {
var identities = extend(metamaskState.identities, id)
return extend(metamaskState, { identities })
+ case actions.SET_CURRENT_FIAT:
+ return extend(metamaskState, {
+ currentFiat: action.value.currentFiat,
+ conversionRate: action.value.conversionRate,
+ conversionDate: action.value.conversionDate,
+ })
+
default:
return metamaskState
diff --git a/ui/app/send.js b/ui/app/send.js
index 06ea199f4..0cc3a032f 100644
--- a/ui/app/send.js
+++ b/ui/app/send.js
@@ -1,5 +1,5 @@
const inherits = require('util').inherits
-const Component = require('react').Component
+const PersistentForm = require('../lib/persistent-form')
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const Identicon = require('./components/identicon')
@@ -29,12 +29,14 @@ function mapStateToProps (state) {
return result
}
-inherits(SendTransactionScreen, Component)
+inherits(SendTransactionScreen, PersistentForm)
function SendTransactionScreen () {
- Component.call(this)
+ PersistentForm.call(this)
}
SendTransactionScreen.prototype.render = function () {
+ this.persistentFormParentId = 'send-tx-form'
+
var state = this.props
var address = state.address
var account = state.account
@@ -137,6 +139,9 @@ SendTransactionScreen.prototype.render = function () {
h('input.large-input', {
name: 'address',
placeholder: 'Recipient Address',
+ dataset: {
+ persistentFormId: 'recipient-address',
+ },
}),
]),
@@ -150,6 +155,9 @@ SendTransactionScreen.prototype.render = function () {
style: {
marginRight: 6,
},
+ dataset: {
+ persistentFormId: 'tx-amount',
+ },
}),
h('button.primary', {
@@ -185,11 +193,12 @@ SendTransactionScreen.prototype.render = function () {
width: '100%',
resize: 'none',
},
+ dataset: {
+ persistentFormId: 'tx-data',
+ },
}),
]),
-
])
-
)
}
diff --git a/ui/app/store.js b/ui/app/store.js
index ab6422e73..8d891bdc9 100644
--- a/ui/app/store.js
+++ b/ui/app/store.js
@@ -1,17 +1,20 @@
const createStore = require('redux').createStore
const applyMiddleware = require('redux').applyMiddleware
const thunkMiddleware = require('redux-thunk')
-const createLogger = require('redux-logger')
const rootReducer = require('./reducers')
+const createLogger = require('redux-logger')
+
+global.METAMASK_DEBUG = false
module.exports = configureStore
-const loggerMiddleware = createLogger()
+const loggerMiddleware = createLogger({
+ predicate: () => global.METAMASK_DEBUG,
+})
+
+const middlewares = [thunkMiddleware, loggerMiddleware]
-const createStoreWithMiddleware = applyMiddleware(
- thunkMiddleware,
- loggerMiddleware
-)(createStore)
+const createStoreWithMiddleware = applyMiddleware(...middlewares)(createStore)
function configureStore (initialState) {
return createStoreWithMiddleware(rootReducer, initialState)
diff --git a/ui/app/unlock.js b/ui/app/unlock.js
index a7896d640..b82e46d02 100644
--- a/ui/app/unlock.js
+++ b/ui/app/unlock.js
@@ -3,10 +3,11 @@ const Component = require('react').Component
const h = require('react-hyperscript')
const connect = require('react-redux').connect
const actions = require('./actions')
-const Mascot = require('./components/mascot')
const getCaretCoordinates = require('textarea-caret')
const EventEmitter = require('events').EventEmitter
+const Mascot = require('./components/mascot')
+
module.exports = connect(mapStateToProps)(UnlockScreen)
inherits(UnlockScreen, Component)
@@ -25,47 +26,46 @@ UnlockScreen.prototype.render = function () {
const state = this.props
const warning = state.warning
return (
-
- h('.unlock-screen.flex-column.flex-center.flex-grow', [
-
- h(Mascot, {
- animationEventEmitter: this.animationEventEmitter,
- }),
-
- h('h1', {
- style: {
- fontSize: '1.4em',
- textTransform: 'uppercase',
- color: '#7F8082',
- },
- }, 'MetaMask'),
-
- h('input.large-input', {
- type: 'password',
- id: 'password-box',
- placeholder: 'enter password',
- style: {
-
- },
- onKeyPress: this.onKeyPress.bind(this),
- onInput: this.inputChanged.bind(this),
- }),
-
- h('.error', {
- style: {
- display: warning ? 'block' : 'none',
- },
- }, warning),
-
- h('button.primary.cursor-pointer', {
- onClick: this.onSubmit.bind(this),
- style: {
- margin: 10,
- },
- }, 'Unlock'),
-
+ h('.flex-column.hey-im-here', [
+ h('.unlock-screen.flex-column.flex-center.flex-grow', [
+
+ h(Mascot, {
+ animationEventEmitter: this.animationEventEmitter,
+ }),
+
+ h('h1', {
+ style: {
+ fontSize: '1.4em',
+ textTransform: 'uppercase',
+ color: '#7F8082',
+ },
+ }, 'MetaMask'),
+
+ h('input.large-input', {
+ type: 'password',
+ id: 'password-box',
+ placeholder: 'enter password',
+ style: {
+
+ },
+ onKeyPress: this.onKeyPress.bind(this),
+ onInput: this.inputChanged.bind(this),
+ }),
+
+ h('.error', {
+ style: {
+ display: warning ? 'block' : 'none',
+ },
+ }, warning),
+
+ h('button.primary.cursor-pointer', {
+ onClick: this.onSubmit.bind(this),
+ style: {
+ margin: 10,
+ },
+ }, 'Unlock'),
+ ]),
])
-
)
}
diff --git a/ui/app/util.js b/ui/app/util.js
index 04ebcecdb..e4b77e2bc 100644
--- a/ui/app/util.js
+++ b/ui/app/util.js
@@ -92,8 +92,8 @@ function parseBalance (balance) {
// Takes wei hex, returns an object with three properties.
// Its "formatted" property is what we generally use to render values.
-function formatBalance (balance, decimalsToKeep) {
- var parsed = parseBalance(balance)
+function formatBalance (balance, decimalsToKeep, needsParse = true) {
+ var parsed = needsParse ? parseBalance(balance) : balance.split('.')
var beforeDecimal = parsed[0]
var afterDecimal = parsed[1]
var formatted = 'None'
@@ -141,14 +141,21 @@ function shortenBalance (balance, decimalsToKeep = 1) {
var convertedBalance = parseFloat(balance)
if (convertedBalance > 1000000) {
truncatedValue = (balance / 1000000).toFixed(decimalsToKeep)
- return `>${truncatedValue}m`
+ return `${truncatedValue}m`
} else if (convertedBalance > 1000) {
truncatedValue = (balance / 1000).toFixed(decimalsToKeep)
- return `>${truncatedValue}k`
+ return `${truncatedValue}k`
+ } else if (convertedBalance === 0) {
+ return '0'
+ } else if (convertedBalance < 0.001) {
+ return '<0.001'
} else if (convertedBalance < 1) {
- var exponent = balance.match(/\.0*/)[0].length
- truncatedValue = (convertedBalance * Math.pow(10, exponent)).toFixed(decimalsToKeep)
- return `<${truncatedValue}e-${exponent}`
+ var stringBalance = convertedBalance.toString()
+ if (stringBalance.split('.')[1].length > 3) {
+ return convertedBalance.toFixed(3)
+ } else {
+ return stringBalance
+ }
} else {
return convertedBalance.toFixed(decimalsToKeep)
}
diff --git a/ui/lib/account-link.js b/ui/lib/account-link.js
new file mode 100644
index 000000000..eb958e22d
--- /dev/null
+++ b/ui/lib/account-link.js
@@ -0,0 +1,18 @@
+module.exports = function(address, network) {
+ const net = parseInt(network)
+ let link
+
+ switch (net) {
+ case 1: // main net
+ link = `http://etherscan.io/address/${address}`
+ break
+ case 2: // morden test net
+ link = `http://testnet.etherscan.io/address/${address}`
+ break
+ default:
+ link = ''
+ break
+ }
+
+ return link
+}
diff --git a/ui/lib/persistent-form.js b/ui/lib/persistent-form.js
new file mode 100644
index 000000000..2fd7600a2
--- /dev/null
+++ b/ui/lib/persistent-form.js
@@ -0,0 +1,57 @@
+const inherits = require('util').inherits
+const Component = require('react').Component
+const defaultKey = 'persistent-form-default'
+const eventName = 'keyup'
+
+module.exports = PersistentForm
+
+function PersistentForm () {
+ Component.call(this)
+}
+
+inherits(PersistentForm, Component)
+
+PersistentForm.prototype.componentDidMount = function () {
+ const fields = document.querySelectorAll('[data-persistent-formid]')
+ const store = this.getPersistentStore()
+ fields.forEach((field) => {
+ const key = field.getAttribute('data-persistent-formid')
+ const cached = store[key]
+ if (cached !== undefined) {
+ field.value = cached
+ }
+
+ field.addEventListener(eventName, this.persistentFieldDidUpdate.bind(this))
+ })
+}
+
+PersistentForm.prototype.getPersistentStore = function () {
+ let store = window.localStorage[this.persistentFormParentId || defaultKey]
+ if (store && store !== 'null') {
+ store = JSON.parse(store)
+ } else {
+ store = {}
+ }
+ return store
+}
+
+PersistentForm.prototype.setPersistentStore = function (newStore) {
+ window.localStorage[this.persistentFormParentId || defaultKey] = JSON.stringify(newStore)
+}
+
+PersistentForm.prototype.persistentFieldDidUpdate = function (event) {
+ const field = event.target
+ const store = this.getPersistentStore()
+ const key = field.getAttribute('data-persistent-formid')
+ const val = field.value
+ store[key] = val
+ this.setPersistentStore(store)
+}
+
+PersistentForm.prototype.componentWillUnmount = function () {
+ const fields = document.querySelectorAll('[data-persistent-formid]')
+ fields.forEach((field) => {
+ field.removeEventListener(eventName, this.persistentFieldDidUpdate.bind(this))
+ })
+ this.setPersistentStore({})
+}