From 8f31b05ac5b7d8383c720b8b0c9f7f3cecc937f5 Mon Sep 17 00:00:00 2001 From: Chi Kei Chan Date: Wed, 13 Sep 2017 01:25:39 -0700 Subject: [PATCH] Add token exchange rates --- ui/app/actions.js | 24 ++++++++++++++++++++ ui/app/components/pending-tx.js | 6 +---- ui/app/components/send-token/index.js | 27 ++++++++++++++++++----- ui/app/components/send/currency-toggle.js | 15 ++++++++++--- ui/app/components/send/gas-fee-display.js | 20 ++++++++++++++++- ui/app/css/itcss/components/send.scss | 11 +++++++++ ui/app/reducers/metamask.js | 10 +++++++++ ui/app/util.js | 1 + 8 files changed, 100 insertions(+), 14 deletions(-) diff --git a/ui/app/actions.js b/ui/app/actions.js index c04808125..1ef538845 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -163,6 +163,8 @@ var actions = { coinBaseSubview: coinBaseSubview, SHAPESHIFT_SUBVIEW: 'SHAPESHIFT_SUBVIEW', shapeShiftSubview: shapeShiftSubview, + UPDATE_TOKEN_EXCHANGE_RATE: 'UPDATE_TOKEN_EXCHANGE_RATE', + updateTokenExchangeRate, PAIR_UPDATE: 'PAIR_UPDATE', pairUpdate: pairUpdate, coinShiftRquest: coinShiftRquest, @@ -1078,6 +1080,28 @@ function shapeShiftRequest (query, options, cb) { } } +function updateTokenExchangeRate (token = '') { + const pair = `${token.toLowerCase()}_eth` + + return dispatch => { + if (!token) { + return + } + + shapeShiftRequest('marketinfo', { pair }, marketinfo => { + if (!marketinfo.error) { + dispatch({ + type: actions.UPDATE_TOKEN_EXCHANGE_RATE, + payload: { + pair, + marketinfo, + }, + }) + } + }) + } +} + // Call Background Then Update // // A function generator for a common pattern wherein: diff --git a/ui/app/components/pending-tx.js b/ui/app/components/pending-tx.js index 5b2aa253f..6ae0444e7 100644 --- a/ui/app/components/pending-tx.js +++ b/ui/app/components/pending-tx.js @@ -305,11 +305,7 @@ PendingTx.prototype.render = function () { // }, 'Reset'), // Accept Button - h('input.confirm-screen-confirm-button', { - type: 'submit', - value: 'CONFIRM', - // disabled: insufficientBalance || !this.state.valid || !isValidAddress || this.state.submitting, - }), + h('button.confirm-screen-confirm-button', ['CONFIRM']), // Cancel Button h('button.cancel.btn-light.confirm-screen-cancel-button', {}, 'CANCEL'), diff --git a/ui/app/components/send-token/index.js b/ui/app/components/send-token/index.js index 8c02ec45d..851d463eb 100644 --- a/ui/app/components/send-token/index.js +++ b/ui/app/components/send-token/index.js @@ -28,9 +28,12 @@ function mapStateToProps (state) { // const network = state.metamask.network const selectedTokenAddress = state.metamask.selectedTokenAddress const selectedAddress = state.metamask.selectedAddress || Object.keys(accounts)[0] + const selectedToken = selectors.getSelectedToken(state) + const tokenExchangeRates = state.metamask.tokenExchangeRates + const pair = `${selectedToken.symbol.toLowerCase()}_eth` + const { rate: tokenExchangeRate = 0 } = tokenExchangeRates[pair] || {} // const checksumAddress = selectedAddress && ethUtil.toChecksumAddress(selectedAddress) // const identity = identities[selectedAddress] - return { // sidebarOpen, selectedAddress, @@ -39,8 +42,9 @@ function mapStateToProps (state) { identities, addressBook, conversionRate, + tokenExchangeRate, currentBlockGasLimit, - selectedToken: selectors.getSelectedToken(state), + selectedToken, // selectedToken: selectors.getSelectedToken(state), // identity, // network, @@ -58,6 +62,7 @@ function mapDispatchToProps (dispatch) { signTokenTx: (tokenAddress, toAddress, amount, txData) => ( dispatch(actions.signTokenTx(tokenAddress, toAddress, amount, txData)) ), + updateTokenExchangeRate: token => dispatch(actions.updateTokenExchangeRate(token)), // showSidebar: () => { dispatch(actions.showSidebar()) }, // hideSidebar: () => { dispatch(actions.hideSidebar()) }, // showModal: (payload) => { dispatch(actions.showModal(payload)) }, @@ -71,7 +76,7 @@ function SendTokenScreen () { Component.call(this) this.state = { to: '', - amount: null, + amount: '', selectedCurrency: 'USD', isGasTooltipOpen: false, gasPrice: '0x5d21dba00', @@ -80,6 +85,15 @@ function SendTokenScreen () { } } +SendTokenScreen.prototype.componentWillMount = function () { + const { + updateTokenExchangeRate, + selectedToken: { symbol }, + } = this.props + + updateTokenExchangeRate(symbol) +} + SendTokenScreen.prototype.validate = function () { const { to, @@ -206,6 +220,7 @@ SendTokenScreen.prototype.renderAmountInput = function () { } = this.state const { + tokenExchangeRate, selectedToken: {symbol}, } = this.props @@ -217,8 +232,8 @@ SendTokenScreen.prototype.renderAmountInput = function () { h('div.send-screen-amount-labels', [ h('span', ['Amount']), h(CurrencyToggle, { - currentCurrency: selectedCurrency, - currencies: [ symbol, 'USD' ], + currentCurrency: tokenExchangeRate ? selectedCurrency : 'USD', + currencies: tokenExchangeRate ? [ symbol, 'USD' ] : [], onClick: currency => this.setState({ selectedCurrency: currency }), }), ]), @@ -249,6 +264,7 @@ SendTokenScreen.prototype.renderGasInput = function () { const { conversionRate, + tokenExchangeRate, currentBlockGasLimit, } = this.props @@ -274,6 +290,7 @@ SendTokenScreen.prototype.renderGasInput = function () { h('div.large-input.send-screen-gas-input', [ h(GasFeeDisplay, { conversionRate, + tokenExchangeRate, gasPrice, currentCurrency: selectedCurrency, gas: gasLimit, diff --git a/ui/app/components/send/currency-toggle.js b/ui/app/components/send/currency-toggle.js index 2b59ace4a..d777f0aea 100644 --- a/ui/app/components/send/currency-toggle.js +++ b/ui/app/components/send/currency-toggle.js @@ -12,11 +12,11 @@ function CurrencyToggle () { const defaultCurrencies = [ 'ETH', 'USD' ] -CurrencyToggle.prototype.render = function () { +CurrencyToggle.prototype.renderToggles = function () { const { onClick, currentCurrency } = this.props const [currencyA, currencyB] = this.props.currencies || defaultCurrencies - return h('span.currency-toggle', {}, [ + return [ h('span', { className: classnames('currency-toggle__item', { 'currency-toggle__item--selected': currencyA === currentCurrency, @@ -30,6 +30,15 @@ CurrencyToggle.prototype.render = function () { }), onClick: () => onClick(currencyB), }, [ currencyB ]), - ]) // holding on icon from design + ] +} + +CurrencyToggle.prototype.render = function () { + const currencies = this.props.currencies || defaultCurrencies + + return h('span.currency-toggle', currencies.length + ? this.renderToggles() + : [] + ) } diff --git a/ui/app/components/send/gas-fee-display.js b/ui/app/components/send/gas-fee-display.js index 5336be8a3..979062882 100644 --- a/ui/app/components/send/gas-fee-display.js +++ b/ui/app/components/send/gas-fee-display.js @@ -3,6 +3,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const USDFeeDisplay = require('./usd-fee-display') const EthFeeDisplay = require('./eth-fee-display') +const { getTxFeeBn, formatBalance, shortenBalance } = require('../../util') module.exports = GasFeeDisplay @@ -11,6 +12,20 @@ function GasFeeDisplay () { Component.call(this) } +GasFeeDisplay.prototype.getTokenValue = function () { + const { + tokenExchangeRate, + gas, + gasPrice, + blockGasLimit, + } = this.props + + const value = formatBalance(getTxFeeBn(gas, gasPrice, blockGasLimit), 6, true) + const [ethNumber] = value.split(' ') + + return shortenBalance(Number(ethNumber) / tokenExchangeRate, 6) +} + GasFeeDisplay.prototype.render = function () { const { currentCurrency, @@ -38,7 +53,10 @@ GasFeeDisplay.prototype.render = function () { blockGasLimit, }) default: - return h('noscript'); + return h('div.token-gas', [ + h('div.token-gas__amount', this.getTokenValue()), + h('div.token-gas__symbol', currentCurrency), + ]) } } diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index 847b893ab..55eb90047 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -229,6 +229,17 @@ padding: 1px 4px; } +.token-gas { + &__amount { + display: inline-block; + margin-right: 4px; + } + + &__symbol { + display: inline-block; + } +} + .send-token { display: flex; flex-flow: column nowrap; diff --git a/ui/app/reducers/metamask.js b/ui/app/reducers/metamask.js index 8d361195d..cdc98d05e 100644 --- a/ui/app/reducers/metamask.js +++ b/ui/app/reducers/metamask.js @@ -18,6 +18,7 @@ function reduceMetamask (state, action) { frequentRpcList: [], addressBook: [], selectedTokenAddress: null, + tokenExchangeRates: {}, }, state.metamask) switch (action.type) { @@ -136,6 +137,15 @@ function reduceMetamask (state, action) { conversionDate: action.value.conversionDate, }) + case actions.UPDATE_TOKEN_EXCHANGE_RATE: + const { payload: { pair, marketinfo } } = action + return extend(metamaskState, { + tokenExchangeRates: { + ...metamaskState.tokenExchangeRates, + [pair]: marketinfo, + }, + }) + default: return metamaskState diff --git a/ui/app/util.js b/ui/app/util.js index bea781466..e058dc92b 100644 --- a/ui/app/util.js +++ b/ui/app/util.js @@ -50,6 +50,7 @@ module.exports = { formatDate, bnMultiplyByFraction, getTxFeeBn, + shortenBalance, } function valuesFor (obj) {