fix merge conflicts

feature/default_network_editable
brunobar79 6 years ago
commit 9b1df386de
  1. 22
      .eslintrc
  2. 4
      CHANGELOG.md
  3. 2
      app/manifest.json
  4. 2
      app/scripts/controllers/network/createInfuraClient.js
  5. 2
      app/scripts/controllers/transactions/index.js
  6. 2
      app/scripts/controllers/transactions/pending-tx-tracker.js
  7. 4
      app/scripts/controllers/transactions/tx-state-manager.js
  8. 16
      app/scripts/inpage.js
  9. 2
      app/scripts/lib/ens-ipfs/resolver.js
  10. 6
      app/scripts/lib/ens-ipfs/setup.js
  11. 8
      app/scripts/lib/setupFetchDebugging.js
  12. 2
      app/scripts/lib/setupSentry.js
  13. 4
      app/scripts/metamask-controller.js
  14. 27
      app/scripts/migrations/029.js
  15. 41
      app/scripts/migrations/fail-tx.js
  16. 1
      app/scripts/migrations/index.js
  17. 2
      app/scripts/ui.js
  18. 26
      auto-changelog.sh
  19. 2
      development/version-bump.js
  20. 4
      old-ui/app/config.js
  21. 16116
      package-lock.json
  22. 16
      package.json
  23. 8
      test/e2e/beta/metamask-beta-ui.spec.js
  24. 1
      test/lib/mock-tx-gen.js
  25. 1
      test/unit/app/controllers/metamask-controller-test.js
  26. 6
      test/unit/app/controllers/preferences-controller-test.js
  27. 2
      test/unit/app/controllers/transactions/pending-tx-test.js
  28. 48
      test/unit/app/controllers/transactions/tx-controller-test.js
  29. 2
      test/unit/development/sample-changelog.md
  30. 38
      test/unit/migrations/029-test.js
  31. 2
      test/unit/ui/app/reducers/metamask.spec.js
  32. 2
      test/unit/ui/app/selectors.spec.js
  33. 2
      ui/app/actions.js
  34. 19
      ui/app/components/currency-display/currency-display.container.js
  35. 2
      ui/app/components/currency-display/tests/currency-display.container.test.js
  36. 2
      ui/app/components/index.scss
  37. 2
      ui/app/components/menu-bar/menu-bar.component.js
  38. 2
      ui/app/components/pages/confirm-transaction-base/confirm-transaction-base.component.js
  39. 2
      ui/app/components/pages/create-account/connect-hardware/account-list.js
  40. 16
      ui/app/components/pages/create-account/connect-hardware/connect-screen.js
  41. 4
      ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.component.js
  42. 25
      ui/app/components/send/send-content/send-amount-row/amount-max-button/amount-max-button.utils.js
  43. 2
      ui/app/components/send/send-content/send-amount-row/amount-max-button/tests/amount-max-button-utils.test.js
  44. 5
      ui/app/components/send/send-content/send-amount-row/send-amount-row.component.js
  45. 4
      ui/app/components/send/send-content/send-amount-row/send-amount-row.container.js
  46. 1
      ui/app/components/send/send-content/send-amount-row/tests/send-amount-row-component.test.js
  47. 4
      ui/app/components/send/send-content/send-from-row/from-dropdown/from-dropdown.component.js
  48. 5
      ui/app/components/send/send-content/send-from-row/send-from-row.component.js
  49. 10
      ui/app/components/send/send-content/send-from-row/send-from-row.container.js
  50. 4
      ui/app/components/send/send-content/send-gas-row/send-gas-row.component.js
  51. 6
      ui/app/components/send/send-content/send-gas-row/send-gas-row.container.js
  52. 4
      ui/app/components/send/send-content/send-to-row/send-to-row.component.js
  53. 4
      ui/app/components/send/send-footer/send-footer.component.js
  54. 6
      ui/app/components/send/send.component.js
  55. 6
      ui/app/components/send/send.utils.js
  56. 2
      ui/app/components/send/tests/send-component.test.js
  57. 3
      ui/app/components/send/tests/send-utils.test.js
  58. 14
      ui/app/components/token-balance/index.scss
  59. 12
      ui/app/components/token-balance/token-balance.component.js
  60. 15
      ui/app/components/token-currency-display/token-currency-display.component.js
  61. 8
      ui/app/components/token-input/token-input.component.js
  62. 2
      ui/app/components/transaction-list-item/index.scss
  63. 26
      ui/app/components/transaction-view-balance/index.scss
  64. 12
      ui/app/components/transaction-view-balance/transaction-view-balance.component.js
  65. 4
      ui/app/components/unit-input/index.scss
  66. 2
      ui/app/components/unit-input/unit-input.component.js
  67. 2
      ui/app/conversion-util.js
  68. 42
      ui/app/css/itcss/components/new-account.scss
  69. 2
      ui/app/css/itcss/components/send.scss
  70. 2
      ui/app/reducers/metamask.js
  71. 9
      ui/app/selectors/confirm-transaction.js
  72. 2
      ui/app/token-util.js

@ -55,13 +55,13 @@
"constructor-super": 2, "constructor-super": 2,
"curly": [2, "multi-line"], "curly": [2, "multi-line"],
"dot-location": [2, "property"], "dot-location": [2, "property"],
"eol-last": 1, "eol-last": 2,
"eqeqeq": [2, "allow-null"], "eqeqeq": [2, "allow-null"],
"generator-star-spacing": [2, { "before": true, "after": true }], "generator-star-spacing": [2, { "before": true, "after": true }],
"handle-callback-err": [1, "^(err|error)$" ], "handle-callback-err": [2, "^(err|error)$" ],
"indent": "off", "indent": "off",
"jsx-quotes": [2, "prefer-double"], "jsx-quotes": [2, "prefer-double"],
"key-spacing": 1, "key-spacing": 2,
"keyword-spacing": [2, { "before": true, "after": true }], "keyword-spacing": [2, { "before": true, "after": true }],
"new-cap": [2, { "newIsCap": true, "capIsNew": false }], "new-cap": [2, { "newIsCap": true, "capIsNew": false }],
"new-parens": 2, "new-parens": 2,
@ -100,7 +100,7 @@
"no-mixed-spaces-and-tabs": 2, "no-mixed-spaces-and-tabs": 2,
"no-multi-spaces": 2, "no-multi-spaces": 2,
"no-multi-str": 2, "no-multi-str": 2,
"no-multiple-empty-lines": [1, { "max": 2 }], "no-multiple-empty-lines": [2, { "max": 2 }],
"no-native-reassign": 2, "no-native-reassign": 2,
"no-negated-in-lhs": 2, "no-negated-in-lhs": 2,
"no-new": 2, "no-new": 2,
@ -112,7 +112,7 @@
"no-obj-calls": 2, "no-obj-calls": 2,
"no-octal": 2, "no-octal": 2,
"no-octal-escape": 2, "no-octal-escape": 2,
"no-path-concat": 1, "no-path-concat": 2,
"no-proto": 2, "no-proto": 2,
"no-redeclare": 2, "no-redeclare": 2,
"no-regex-spaces": 2, "no-regex-spaces": 2,
@ -125,7 +125,7 @@
"no-sparse-arrays": 2, "no-sparse-arrays": 2,
"no-this-before-super": 2, "no-this-before-super": 2,
"no-throw-literal": 2, "no-throw-literal": 2,
"no-trailing-spaces": 1, "no-trailing-spaces": 2,
"no-undef": 2, "no-undef": 2,
"no-undef-init": 2, "no-undef-init": 2,
"no-unexpected-multiline": 2, "no-unexpected-multiline": 2,
@ -141,15 +141,15 @@
"no-whitespace-before-property": 2, "no-whitespace-before-property": 2,
"no-with": 2, "no-with": 2,
"one-var": [2, { "initialized": "never" }], "one-var": [2, { "initialized": "never" }],
"operator-linebreak": [1, "after", { "overrides": { "?": "ignore", ":": "ignore" } }], "operator-linebreak": [2, "after", { "overrides": { "?": "ignore", ":": "ignore" } }],
"padded-blocks": "off", "padded-blocks": "off",
"quotes": [2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}], "quotes": [2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}],
"react/no-deprecated": 0, "react/no-deprecated": 0,
"semi": [2, "never"], "semi": [2, "never"],
"semi-spacing": [2, { "before": false, "after": true }], "semi-spacing": [2, { "before": false, "after": true }],
"space-before-blocks": [1, "always"], "space-before-blocks": [2, "always"],
"space-before-function-paren": [1, "always"], "space-before-function-paren": [2, "always"],
"space-in-parens": [1, "never"], "space-in-parens": [2, "never"],
"space-infix-ops": 2, "space-infix-ops": 2,
"space-unary-ops": [2, { "words": true, "nonwords": false }], "space-unary-ops": [2, { "words": true, "nonwords": false }],
"spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","], "exceptions": ["=", "-"] } ], "spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","], "exceptions": ["=", "-"] } ],
@ -160,7 +160,7 @@
"wrap-iife": [2, "any"], "wrap-iife": [2, "any"],
"yield-star-spacing": [2, "both"], "yield-star-spacing": [2, "both"],
"yoda": [2, "never"], "yoda": [2, "never"],
"prefer-const": 1, "prefer-const": 2,
"mocha/no-exclusive-tests": "error" "mocha/no-exclusive-tests": "error"
} }
} }

@ -2,7 +2,11 @@
## Current Develop Branch ## Current Develop Branch
## 5.0.3 Mon Nov 19 2018
- [#5547](https://github.com/MetaMask/metamask-extension/pull/5547): Bundle some ui dependencies separately to limit the build size of ui.js
- Resubmit approved transactions on new block, to fix bug where an error can stick transactions in this state. - Resubmit approved transactions on new block, to fix bug where an error can stick transactions in this state.
- Fixed a bug that could cause an error when sending the max number of tokens.
## 5.0.2 Friday November 9 2018 ## 5.0.2 Friday November 9 2018

@ -1,7 +1,7 @@
{ {
"name": "__MSG_appName__", "name": "__MSG_appName__",
"short_name": "__MSG_appName__", "short_name": "__MSG_appName__",
"version": "5.0.2", "version": "5.0.3",
"manifest_version": 2, "manifest_version": 2,
"author": "https://metamask.io", "author": "https://metamask.io",
"description": "__MSG_appDescription__", "description": "__MSG_appDescription__",

@ -28,7 +28,7 @@ function createInfuraClient ({ network }) {
return { networkMiddleware, blockTracker } return { networkMiddleware, blockTracker }
} }
function createNetworkAndChainIdMiddleware({ network }) { function createNetworkAndChainIdMiddleware ({ network }) {
let chainId let chainId
let netId let netId

@ -1,4 +1,4 @@
const EventEmitter = require('events') const EventEmitter = require('safe-event-emitter')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const Transaction = require('ethereumjs-tx') const Transaction = require('ethereumjs-tx')

@ -1,4 +1,4 @@
const EventEmitter = require('events') const EventEmitter = require('safe-event-emitter')
const log = require('loglevel') const log = require('loglevel')
const EthQuery = require('ethjs-query') const EthQuery = require('ethjs-query')

@ -1,5 +1,5 @@
const extend = require('xtend') const extend = require('xtend')
const EventEmitter = require('events') const EventEmitter = require('safe-event-emitter')
const ObservableStore = require('obs-store') const ObservableStore = require('obs-store')
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
const log = require('loglevel') const log = require('loglevel')
@ -86,7 +86,7 @@ class TransactionStateManager extends EventEmitter {
@returns {array} the tx list whos status is approved if no address is provide @returns {array} the tx list whos status is approved if no address is provide
returns all txMetas who's status is approved for the current network returns all txMetas who's status is approved for the current network
*/ */
getApprovedTransactions(address) { getApprovedTransactions (address) {
const opts = { status: 'approved' } const opts = { status: 'approved' }
if (address) opts.from = address if (address) opts.from = address
return this.getFilteredTxList(opts) return this.getFilteredTxList(opts)

@ -29,7 +29,7 @@ console.warn('ATTENTION: In an effort to improve user privacy, MetaMask ' +
* @param {Function} handler - event handler * @param {Function} handler - event handler
* @param {boolean} remove - removes this handler after being triggered * @param {boolean} remove - removes this handler after being triggered
*/ */
function onMessage(messageType, handler, remove) { function onMessage (messageType, handler, remove) {
window.addEventListener('message', function ({ data }) { window.addEventListener('message', function ({ data }) {
if (!data || data.type !== messageType) { return } if (!data || data.type !== messageType) { return }
remove && window.removeEventListener('message', handler) remove && window.removeEventListener('message', handler)
@ -59,7 +59,9 @@ onMessage('metamasksetlocked', () => { isEnabled = false })
// set up a listener for privacy mode responses // set up a listener for privacy mode responses
onMessage('ethereumproviderlegacy', ({ data: { selectedAddress } }) => { onMessage('ethereumproviderlegacy', ({ data: { selectedAddress } }) => {
isEnabled = true isEnabled = true
inpageProvider.publicConfigStore.updateState({ selectedAddress }) setTimeout(() => {
inpageProvider.publicConfigStore.updateState({ selectedAddress })
}, 0)
}, true) }, true)
// augment the provider with its enable method // augment the provider with its enable method
@ -70,7 +72,9 @@ inpageProvider.enable = function ({ force } = {}) {
reject(error) reject(error)
} else { } else {
window.removeEventListener('message', providerHandle) window.removeEventListener('message', providerHandle)
inpageProvider.publicConfigStore.updateState({ selectedAddress }) setTimeout(() => {
inpageProvider.publicConfigStore.updateState({ selectedAddress })
}, 0)
// wait for the background to update with an account // wait for the background to update with an account
inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => { inpageProvider.sendAsync({ method: 'eth_accounts', params: [] }, (error, response) => {
@ -104,7 +108,7 @@ inpageProvider._metamask = new Proxy({
* *
* @returns {Promise<boolean>} - Promise resolving to true if this domain has been previously approved * @returns {Promise<boolean>} - Promise resolving to true if this domain has been previously approved
*/ */
isApproved: function() { isApproved: function () {
return new Promise((resolve) => { return new Promise((resolve) => {
isApprovedHandle = ({ data: { caching, isApproved } }) => { isApprovedHandle = ({ data: { caching, isApproved } }) => {
if (caching) { if (caching) {
@ -133,7 +137,7 @@ inpageProvider._metamask = new Proxy({
}) })
}, },
}, { }, {
get: function(obj, prop) { get: function (obj, prop) {
!warned && console.warn('Heads up! ethereum._metamask exposes methods that have ' + !warned && console.warn('Heads up! ethereum._metamask exposes methods that have ' +
'not been standardized yet. This means that these methods may not be implemented ' + 'not been standardized yet. This means that these methods may not be implemented ' +
'in other dapp browsers and may be removed from MetaMask in the future.') 'in other dapp browsers and may be removed from MetaMask in the future.')
@ -153,7 +157,7 @@ const proxiedInpageProvider = new Proxy(inpageProvider, {
window.ethereum = proxiedInpageProvider window.ethereum = proxiedInpageProvider
// detect eth_requestAccounts and pipe to enable for now // detect eth_requestAccounts and pipe to enable for now
function detectAccountRequest(method) { function detectAccountRequest (method) {
const originalMethod = inpageProvider[method] const originalMethod = inpageProvider[method]
inpageProvider[method] = function ({ method }) { inpageProvider[method] = function ({ method }) {
if (method === 'eth_requestAccounts') { if (method === 'eth_requestAccounts') {

@ -38,7 +38,7 @@ async function resolveEnsToIpfsContentId ({ provider, name }) {
return contentId return contentId
} }
function hexValueIsEmpty(value) { function hexValueIsEmpty (value) {
return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value) return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value)
} }

@ -6,7 +6,7 @@ const supportedTopLevelDomains = ['eth']
module.exports = setupEnsIpfsResolver module.exports = setupEnsIpfsResolver
function setupEnsIpfsResolver({ provider }) { function setupEnsIpfsResolver ({ provider }) {
// install listener // install listener
const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`) const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
@ -35,11 +35,11 @@ function setupEnsIpfsResolver({ provider }) {
attemptResolve({ tabId, name, path, search }) attemptResolve({ tabId, name, path, search })
} }
async function attemptResolve({ tabId, name, path, search }) { async function attemptResolve ({ tabId, name, path, search }) {
extension.tabs.update(tabId, { url: `loading.html` }) extension.tabs.update(tabId, { url: `loading.html` })
try { try {
const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name }) const ipfsContentId = await resolveEnsToIpfsContentId({ provider, name })
let url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}` const url = `https://gateway.ipfs.io/ipfs/${ipfsContentId}${path}${search || ''}`
try { try {
// check if ipfs gateway has result // check if ipfs gateway has result
const response = await fetch(url, { method: 'HEAD' }) const response = await fetch(url, { method: 'HEAD' })

@ -6,13 +6,13 @@ module.exports = setupFetchDebugging
// https://github.com/getsentry/sentry-javascript/pull/1293 // https://github.com/getsentry/sentry-javascript/pull/1293
// //
function setupFetchDebugging() { function setupFetchDebugging () {
if (!global.fetch) return if (!global.fetch) return
const originalFetch = global.fetch const originalFetch = global.fetch
global.fetch = wrappedFetch global.fetch = wrappedFetch
async function wrappedFetch(...args) { async function wrappedFetch (...args) {
const initialStack = getCurrentStack() const initialStack = getCurrentStack()
try { try {
return await originalFetch.call(window, ...args) return await originalFetch.call(window, ...args)
@ -20,14 +20,14 @@ function setupFetchDebugging() {
if (!err.stack) { if (!err.stack) {
console.warn('FetchDebugger - fetch encountered an Error without a stack', err) console.warn('FetchDebugger - fetch encountered an Error without a stack', err)
console.warn('FetchDebugger - overriding stack to point of original call') console.warn('FetchDebugger - overriding stack to point of original call')
err.stack = initialStack err.stack = initialStack
} }
throw err throw err
} }
} }
} }
function getCurrentStack() { function getCurrentStack () {
try { try {
throw new Error('Fake error for generating stack trace') throw new Error('Fake error for generating stack trace')
} catch (err) { } catch (err) {

@ -32,7 +32,7 @@ function setupSentry (opts) {
scope.setExtra('isBrave', isBrave) scope.setExtra('isBrave', isBrave)
}) })
function rewriteReport(report) { function rewriteReport (report) {
try { try {
// simplify certain complex error messages (e.g. Ethjs) // simplify certain complex error messages (e.g. Ethjs)
simplifyErrorMessages(report) simplifyErrorMessages(report)

@ -200,7 +200,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.networkController.on('networkDidChange', () => { this.networkController.on('networkDidChange', () => {
this.balancesController.updateAllBalances() this.balancesController.updateAllBalances()
var currentCurrency = this.currencyController.getCurrentCurrency() var currentCurrency = this.currencyController.getCurrentCurrency()
this.setCurrentCurrency(currentCurrency, function() {}) this.setCurrentCurrency(currentCurrency, function () {})
}) })
this.balancesController.updateAllBalances() this.balancesController.updateAllBalances()
@ -1581,7 +1581,7 @@ module.exports = class MetamaskController extends EventEmitter {
/** /**
* Locks MetaMask * Locks MetaMask
*/ */
setLocked() { setLocked () {
this.providerApprovalController.setLocked() this.providerApprovalController.setLocked()
return this.keyringController.setLocked() return this.keyringController.setLocked()
} }

@ -0,0 +1,27 @@
// next version number
const version = 29
const failTxsThat = require('./fail-tx')
// time
const seconds = 1000
const minutes = 60 * seconds
const hours = 60 * minutes
const unacceptableDelay = 12 * hours
/*
normalizes txParams on unconfirmed txs
*/
module.exports = {
version,
migrate: failTxsThat(version, 'Stuck in approved state for too long.', (txMeta) => {
const isApproved = txMeta.status === 'approved'
const createdTime = txMeta.submittedTime
const now = Date.now()
return isApproved && now - createdTime > unacceptableDelay
}),
}

@ -0,0 +1,41 @@
const clone = require('clone')
module.exports = function (version, reason, condition) {
return function (originalVersionedData) {
const versionedData = clone(originalVersionedData)
versionedData.meta.version = version
try {
const state = versionedData.data
const newState = transformState(state, condition, reason)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
}
return Promise.resolve(versionedData)
}
}
function transformState (state, condition, reason) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = TransactionController.transactions
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (!condition(txMeta)) {
return txMeta
}
txMeta.status = 'failed'
txMeta.err = {
message: reason,
note: `Tx automatically failed by migration because ${reason}`,
}
return txMeta
})
}
return newState
}

@ -39,4 +39,5 @@ module.exports = [
require('./026'), require('./026'),
require('./027'), require('./027'),
require('./028'), require('./028'),
require('./029'),
] ]

@ -23,7 +23,7 @@ async function start () {
const release = global.platform.getVersion() const release = global.platform.getVersion()
setupSentry({ release, getState }) setupSentry({ release, getState })
// provide app state to append to error logs // provide app state to append to error logs
function getState() { function getState () {
// get app state // get app state
const state = window.getCleanAppState() const state = window.getCleanAppState()
// remove unnecessary data // remove unnecessary data

@ -0,0 +1,26 @@
#! /bin/bash
# update tags
git fetch --tags
# get origin
URL='https://github.com/MetaMask/metamask-extension'
# get git logs from last tag until HEAD, pretty by 'subject::body' filtered by grep for PRs made with Github squash merge or Github regular merge
LOG=$(git log $(git describe --tags $(git rev-list --tags --max-count=1))..HEAD --pretty="%s::%b" --reverse --grep="Merge pull request #" --grep="(#");
while read -r line; do
# get git log subject
SUBJECT=$(echo $line | sed -E 's/(.*):{2}(.*)/\1/')
# get git log PR id, PR made with Github squash merge or Github regular merge
PR=$(echo $SUBJECT | sed 's/^.*(#\([^&]*\)).*/\1/' | sed 's/^.*#\([^&]*\) from.*/\1/')
# if PR made with Github squash merge, subject is the body
if [ -z "$(echo $line | sed -E 's/(.*):{2}(.*)/\2/')" ]; then
BODY=$(echo $SUBJECT | sed "s/(#$PR)//g"); else
BODY=$(echo $line | sed -E 's/(.*):{2}(.*)/\2/')
fi
# add entry to CHANGELOG
if [[ "$OSTYPE" == "linux-gnu" ]]; then
sed -i'' '/## Current Develop Branch/a\
- [#'"$PR"']('"$URL"'/pull/'"$PR"'): '"$BODY"''$'\n' CHANGELOG.md; else
sed -i '' '/## Current Develop Branch/a\
- [#'"$PR"']('"$URL"'/pull/'"$PR"'): '"$BODY"''$'\n' CHANGELOG.md;
fi
done <<< "$LOG"
echo 'CHANGELOG updated'

@ -10,7 +10,7 @@ async function versionBump (bumpType, changelog, oldManifest) {
const logHeader = `\n## ${newVersion} ${date}` const logHeader = `\n## ${newVersion} ${date}`
const logLines = changelog.split('\n') const logLines = changelog.split('\n')
for (let i = 0; i < logLines.length; i++) { for (let i = 0; i < logLines.length; i++) {
if (logLines[i].includes('Current Master')) { if (logLines[i].includes('Current Develop Branch')) {
logLines.splice(i + 1, 0, logHeader) logLines.splice(i + 1, 0, logHeader)
break break
} }

@ -222,7 +222,7 @@ ConfigScreen.prototype.render = function () {
}, },
}, 'Clear privacy data'), }, 'Clear privacy data'),
]), ]),
h('hr.horizontal-line'), h('hr.horizontal-line'),
h('div', { h('div', {
@ -253,7 +253,7 @@ ConfigScreen.prototype.render = function () {
'Enable privacy mode' 'Enable privacy mode'
), ),
]), ]),
h('hr.horizontal-line'), h('hr.horizontal-line'),
h('div', { h('div', {

16116
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -49,7 +49,8 @@
"disc": "gulp disc --debug", "disc": "gulp disc --debug",
"announce": "node development/announcer.js", "announce": "node development/announcer.js",
"version:bump": "node development/run-version-bump.js", "version:bump": "node development/run-version-bump.js",
"storybook": "start-storybook -p 6006 -c .storybook" "storybook": "start-storybook -p 6006 -c .storybook",
"update-changelog": "./auto-changelog.sh"
}, },
"browserify": { "browserify": {
"transform": [ "transform": [
@ -119,7 +120,7 @@
"eth-hd-keyring": "^1.2.2", "eth-hd-keyring": "^1.2.2",
"eth-json-rpc-filters": "^3.0.1", "eth-json-rpc-filters": "^3.0.1",
"eth-json-rpc-infura": "^3.0.0", "eth-json-rpc-infura": "^3.0.0",
"eth-keyring-controller": "^3.1.4", "eth-keyring-controller": "^3.3.1",
"eth-ledger-bridge-keyring": "^0.1.0", "eth-ledger-bridge-keyring": "^0.1.0",
"eth-method-registry": "^1.0.0", "eth-method-registry": "^1.0.0",
"eth-phishing-detect": "^1.1.4", "eth-phishing-detect": "^1.1.4",
@ -166,7 +167,7 @@
"lodash.uniqby": "^4.7.0", "lodash.uniqby": "^4.7.0",
"loglevel": "^1.4.1", "loglevel": "^1.4.1",
"metamascara": "^2.0.0", "metamascara": "^2.0.0",
"metamask-inpage-provider": "^1.2.2", "metamask-inpage-provider": "^1.3.0",
"metamask-logo": "^2.1.4", "metamask-logo": "^2.1.4",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"multihashes": "^0.4.12", "multihashes": "^0.4.12",
@ -211,6 +212,7 @@
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"request-promise": "^4.2.1", "request-promise": "^4.2.1",
"reselect": "^3.0.1", "reselect": "^3.0.1",
"safe-event-emitter": "^1.0.1",
"sandwich-expando": "^1.1.3", "sandwich-expando": "^1.1.3",
"semaphore": "^1.0.5", "semaphore": "^1.0.5",
"semver": "^5.4.1", "semver": "^5.4.1",
@ -268,14 +270,14 @@
"fs-extra": "^6.0.1", "fs-extra": "^6.0.1",
"fs-promise": "^2.0.3", "fs-promise": "^2.0.3",
"ganache-cli": "^6.1.0", "ganache-cli": "^6.1.0",
"ganache-core": "^2.1.5", "ganache-core": "^2.2.1",
"geckodriver": "^1.11.0", "geckodriver": "^1.14.1",
"gh-pages": "^1.2.0", "gh-pages": "^1.2.0",
"gifencoder": "^1.1.0", "gifencoder": "^1.1.0",
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed", "gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
"gulp-babel": "^7.0.0", "gulp-babel": "^7.0.0",
"gulp-json-editor": "^2.2.1", "gulp-json-editor": "^2.2.1",
"gulp-livereload": "^3.8.1", "gulp-livereload": "^4.0.0",
"gulp-multi-process": "^1.3.1", "gulp-multi-process": "^1.3.1",
"gulp-replace": "^0.6.1", "gulp-replace": "^0.6.1",
"gulp-sourcemaps": "^2.6.0", "gulp-sourcemaps": "^2.6.0",
@ -293,7 +295,7 @@
"jsdom": "^11.2.0", "jsdom": "^11.2.0",
"jsdom-global": "^3.0.2", "jsdom-global": "^3.0.2",
"jshint-stylish": "~2.2.1", "jshint-stylish": "~2.2.1",
"karma": "^2.0.4", "karma": "^3.1.1",
"karma-chrome-launcher": "^2.2.0", "karma-chrome-launcher": "^2.2.0",
"karma-cli": "^1.0.1", "karma-cli": "^1.0.1",
"karma-firefox-launcher": "^1.0.1", "karma-firefox-launcher": "^1.0.1",

@ -840,7 +840,7 @@ describe('MetaMask', function () {
}) })
it('renders the balance for the new token', async () => { it('renders the balance for the new token', async () => {
const balance = await findElement(driver, By.css('.transaction-view-balance .transaction-view-balance__token-balance')) const balance = await findElement(driver, By.css('.transaction-view-balance .transaction-view-balance__primary-balance'))
await driver.wait(until.elementTextMatches(balance, /^100\s*TST\s*$/)) await driver.wait(until.elementTextMatches(balance, /^100\s*TST\s*$/))
const tokenAmount = await balance.getText() const tokenAmount = await balance.getText()
assert.ok(/^100\s*TST\s*$/.test(tokenAmount)) assert.ok(/^100\s*TST\s*$/.test(tokenAmount))
@ -1019,8 +1019,8 @@ describe('MetaMask', function () {
// test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved, // test cancelled on firefox until https://github.com/mozilla/geckodriver/issues/906 is resolved,
// or possibly until we use latest version of firefox in the tests // or possibly until we use latest version of firefox in the tests
if (process.env.SELENIUM_BROWSER !== 'firefox') { if (process.env.SELENIUM_BROWSER !== 'firefox') {
const tokenBalanceAmount = await findElement(driver, By.css('.transaction-view-balance__token-balance')) const tokenBalanceAmount = await findElements(driver, By.css('.transaction-view-balance__primary-balance'))
assert.equal(await tokenBalanceAmount.getText(), '43 TST') await driver.wait(until.elementTextMatches(tokenBalanceAmount[0], /43\s*TST/))
} }
}) })
}) })
@ -1180,7 +1180,7 @@ describe('MetaMask', function () {
}) })
it('renders the balance for the chosen token', async () => { it('renders the balance for the chosen token', async () => {
const balance = await findElement(driver, By.css('.transaction-view-balance__token-balance')) const balance = await findElement(driver, By.css('.transaction-view-balance__primary-balance'))
await driver.wait(until.elementTextMatches(balance, /0\s*BAT/)) await driver.wait(until.elementTextMatches(balance, /0\s*BAT/))
await delay(regularDelayMs) await delay(regularDelayMs)
}) })

@ -2,6 +2,7 @@ const extend = require('xtend')
const BN = require('ethereumjs-util').BN const BN = require('ethereumjs-util').BN
const template = { const template = {
'status': 'submitted', 'status': 'submitted',
'history': [{}],
'txParams': { 'txParams': {
'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926', 'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
'gas': '0x30d40', 'gas': '0x30d40',

@ -58,6 +58,7 @@ describe('MetaMaskController', function () {
}, },
}, },
initState: clone(firstTimeState), initState: clone(firstTimeState),
platform: { showTransactionNotification: () => {} },
}) })
// disable diagnostics // disable diagnostics
metamaskController.diagnostics = null metamaskController.diagnostics = null

@ -515,14 +515,14 @@ describe('preferences controller', function () {
it('should add custom RPC url to state', function () { it('should add custom RPC url to state', function () {
preferencesController.addToFrequentRpcList('rpc_url', 1) preferencesController.addToFrequentRpcList('rpc_url', 1)
preferencesController.addToFrequentRpcList('http://localhost:8545', 1) preferencesController.addToFrequentRpcList('http://localhost:8545', 1)
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] ) assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }])
preferencesController.addToFrequentRpcList('rpc_url', 1) preferencesController.addToFrequentRpcList('rpc_url', 1)
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] ) assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }])
}) })
it('should remove custom RPC url from state', function () { it('should remove custom RPC url from state', function () {
preferencesController.addToFrequentRpcList('rpc_url', 1) preferencesController.addToFrequentRpcList('rpc_url', 1)
assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }] ) assert.deepEqual(preferencesController.store.getState().frequentRpcListDetail, [{ rpcUrl: 'rpc_url', chainId: 1, ticker: 'ETH', nickname: '' }])
preferencesController.removeFromFrequentRpcList('other_rpc_url') preferencesController.removeFromFrequentRpcList('other_rpc_url')
preferencesController.removeFromFrequentRpcList('http://localhost:8545') preferencesController.removeFromFrequentRpcList('http://localhost:8545')
preferencesController.removeFromFrequentRpcList('rpc_url') preferencesController.removeFromFrequentRpcList('rpc_url')

@ -20,10 +20,12 @@ describe('PendingTransactionTracker', function () {
nonce: '0x1', nonce: '0x1',
value: '0xfffff', value: '0xfffff',
}, },
history: [{}],
rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d', rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d',
} }
txMetaNoHash = { txMetaNoHash = {
id: 2, id: 2,
history: [{}],
status: 'submitted', status: 'submitted',
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'}, txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
} }

@ -52,9 +52,9 @@ describe('Transaction Controller', function () {
describe('#getUnapprovedTxCount', function () { describe('#getUnapprovedTxCount', function () {
it('should return the number of unapproved txs', function () { it('should return the number of unapproved txs', function () {
txController.txStateManager._saveTxList([ txController.txStateManager._saveTxList([
{ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
]) ])
const unapprovedTxCount = txController.getUnapprovedTxCount() const unapprovedTxCount = txController.getUnapprovedTxCount()
assert.equal(unapprovedTxCount, 3, 'should be 3') assert.equal(unapprovedTxCount, 3, 'should be 3')
@ -64,9 +64,9 @@ describe('Transaction Controller', function () {
describe('#getPendingTxCount', function () { describe('#getPendingTxCount', function () {
it('should return the number of pending txs', function () { it('should return the number of pending txs', function () {
txController.txStateManager._saveTxList([ txController.txStateManager._saveTxList([
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] }, { id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
]) ])
const pendingTxCount = txController.getPendingTxCount() const pendingTxCount = txController.getPendingTxCount()
assert.equal(pendingTxCount, 3, 'should be 3') assert.equal(pendingTxCount, 3, 'should be 3')
@ -82,15 +82,15 @@ describe('Transaction Controller', function () {
'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d', 'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d',
} }
txController.txStateManager._saveTxList([ txController.txStateManager._saveTxList([
{id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
{id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [] }, {id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
]) ])
}) })
@ -112,7 +112,7 @@ describe('Transaction Controller', function () {
id: 1, id: 1,
metamaskNetworkId: currentNetworkId, metamaskNetworkId: currentNetworkId,
txParams, txParams,
history: [], history: [{}],
} }
txController.txStateManager._saveTxList([txMeta]) txController.txStateManager._saveTxList([txMeta])
stub = sinon.stub(txController, 'addUnapprovedTransaction').callsFake(() => { stub = sinon.stub(txController, 'addUnapprovedTransaction').callsFake(() => {
@ -232,7 +232,7 @@ describe('Transaction Controller', function () {
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d', from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d', to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
}, },
history: [], history: [{}],
} }
providerResultStub.eth_gasPrice = '4a817c800' providerResultStub.eth_gasPrice = '4a817c800'
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' } providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' }
@ -423,7 +423,7 @@ describe('Transaction Controller', function () {
data: '0x0', data: '0x0',
} }
txController.txStateManager._saveTxList([ txController.txStateManager._saveTxList([
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] }, { id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
]) ])
txController.retryTransaction(1) txController.retryTransaction(1)
.then((txMeta) => { .then((txMeta) => {
@ -462,12 +462,12 @@ describe('Transaction Controller', function () {
beforeEach(function () { beforeEach(function () {
txController.txStateManager._saveTxList([ txController.txStateManager._saveTxList([
{ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} },
{ id: 2, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 2, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 3, status: 'approved', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 3, status: 'approved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 4, status: 'signed', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 4, status: 'signed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 6, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 6, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
{ id: 7, status: 'failed', metamaskNetworkId: currentNetworkId, txParams: {} }, { id: 7, status: 'failed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
]) ])
}) })
it('should show only submitted and approved transactions as pending transasction', function () { it('should show only submitted and approved transactions as pending transasction', function () {

@ -1,6 +1,6 @@
# Changelog # Changelog
## Current Master ## Current Develop Branch
## 4.1.3 2018-2-28 ## 4.1.3 2018-2-28

@ -0,0 +1,38 @@
const assert = require('assert')
const migration29 = require('../../../app/scripts/migrations/029')
const properTime = (new Date()).getTime()
const storage = {
'meta': {},
'data': {
'TransactionController': {
'transactions': [
{ 'status': 'approved', id: 1, submittedTime: 0 },
{ 'status': 'approved', id: 2, submittedTime: properTime },
{ 'status': 'confirmed', id: 3, submittedTime: properTime },
{ 'status': 'submitted', id: 4, submittedTime: properTime },
{ 'status': 'submitted', id: 5, submittedTime: 0 },
],
},
},
}
describe('storage is migrated successfully where transactions that are submitted have submittedTimes', () => {
it('should auto fail transactions more than 12 hours old', (done) => {
migration29.migrate(storage)
.then((migratedData) => {
const txs = migratedData.data.TransactionController.transactions
const [ txMeta1 ] = txs
assert.equal(migratedData.meta.version, 29)
assert.equal(txMeta1.status, 'failed', 'old tx is auto failed')
assert(txMeta1.err.message.includes('too long'), 'error message assigned')
txs.forEach((tx) => {
if (tx.id === 1) return
assert.notEqual(tx.status, 'failed', 'other tx is not auto failed')
})
done()
}).catch(done)
})
})

@ -5,7 +5,7 @@ import * as actions from '../../../../../ui/app/actions'
describe('MetaMask Reducers', () => { describe('MetaMask Reducers', () => {
it('init state', () => { it('init state', () => {
const initState = reduceMetamask({metamask:{}}, {}) const initState = reduceMetamask({metamask: {}}, {})
assert(initState) assert(initState)
}) })

@ -148,7 +148,7 @@ describe('Selectors', function () {
it('#getSelectedTokenToFiatRate', () => { it('#getSelectedTokenToFiatRate', () => {
const selectedTokenToFiatRate = selectors.getSelectedTokenToFiatRate(mockState) const selectedTokenToFiatRate = selectors.getSelectedTokenToFiatRate(mockState)
assert.equal(selectedTokenToFiatRate, '0.21880988420033493') assert.equal(selectedTokenToFiatRate, '0.21880988420033492152')
}) })
describe('#getSelectedTokenContract', () => { describe('#getSelectedTokenContract', () => {

@ -995,7 +995,7 @@ function updateSendTokenBalance ({
.then(usersToken => { .then(usersToken => {
if (usersToken) { if (usersToken) {
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken }) const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
dispatch(setSendTokenBalance(newTokenBalance.toString(10))) dispatch(setSendTokenBalance(newTokenBalance))
} }
}) })
.catch(err => { .catch(err => {

@ -20,15 +20,24 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
currency, currency,
denomination, denomination,
hideLabel, hideLabel,
displayValue: propsDisplayValue,
suffix: propsSuffix,
...restOwnProps ...restOwnProps
} = ownProps } = ownProps
const toCurrency = currency || currentCurrency const toCurrency = currency || currentCurrency
const convertedValue = getValueFromWeiHex({
value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination, const displayValue = propsDisplayValue || formatCurrency(
}) getValueFromWeiHex({
const displayValue = formatCurrency(convertedValue, toCurrency) value,
const suffix = hideLabel ? undefined : toCurrency.toUpperCase() fromCurrency: nativeCurrency,
toCurrency, conversionRate,
numberOfDecimals,
toDenomination: denomination,
}),
toCurrency
)
const suffix = propsSuffix || (hideLabel ? undefined : toCurrency.toUpperCase())
return { return {
...restStateProps, ...restStateProps,

@ -131,7 +131,7 @@ describe('CurrencyDisplay container', () => {
}, },
result: { result: {
nativeCurrency: 'ETH', nativeCurrency: 'ETH',
displayValue: '1e-9', displayValue: '0.000000001',
suffix: undefined, suffix: undefined,
}, },
}, },

@ -40,6 +40,8 @@
@import './tabs/index'; @import './tabs/index';
@import './token-balance/index';
@import './transaction-activity-log/index'; @import './transaction-activity-log/index';
@import './transaction-breakdown/index'; @import './transaction-breakdown/index';

@ -52,7 +52,7 @@ export default class MenuBar extends PureComponent {
{ {
accountDetailsMenuOpen && ( accountDetailsMenuOpen && (
<AccountDetailsDropdown <AccountDetailsDropdown
className="menu-bar__account-details-dropdown" className="menu-bar__account-details-dropdown"
onClose={() => this.setState({ accountDetailsMenuOpen: false })} onClose={() => this.setState({ accountDetailsMenuOpen: false })}
/> />
) )

@ -348,7 +348,7 @@ export default class ConfirmTransactionBase extends Component {
/> />
) )
} }
handleNextTx (txId) { handleNextTx (txId) {
const { history, clearConfirmTransaction } = this.props const { history, clearConfirmTransaction } = this.props
if (txId) { if (txId) {

@ -152,7 +152,7 @@ class AccountList extends Component {
}, [this.context.t('cancel')]), }, [this.context.t('cancel')]),
h(Button, { h(Button, {
type: 'primary', type: 'confirm',
large: true, large: true,
className: 'new-account-connect-form__button unlock', className: 'new-account-connect-form__button unlock',
disabled, disabled,

@ -45,11 +45,13 @@ class ConnectScreen extends Component {
this.renderConnectToLedgerButton(), this.renderConnectToLedgerButton(),
this.renderConnectToTrezorButton(), this.renderConnectToTrezorButton(),
]), ]),
h( h(Button, {
`button.hw-connect__connect-btn${!this.state.selectedDevice ? '.disabled' : ''}`, type: 'confirm',
{ onClick: this.connect }, large: true,
this.context.t('connect') className: 'hw-connect__connect-btn',
), onClick: this.connect,
disabled: !this.state.selectedDevice,
}, this.context.t('connect')),
]) ])
) )
} }
@ -67,9 +69,7 @@ class ConnectScreen extends Component {
onClick: () => global.platform.openWindow({ onClick: () => global.platform.openWindow({
url: 'https://google.com/chrome', url: 'https://google.com/chrome',
}), }),
}, }, this.context.t('downloadGoogleChrome')),
this.context.t('downloadGoogleChrome')
),
]) ])
) )
} }

@ -11,11 +11,11 @@ export default class AmountMaxButton extends Component {
setAmountToMax: PropTypes.func, setAmountToMax: PropTypes.func,
setMaxModeTo: PropTypes.func, setMaxModeTo: PropTypes.func,
tokenBalance: PropTypes.string, tokenBalance: PropTypes.string,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
setMaxAmount () { setMaxAmount () {
const { const {

@ -5,16 +5,23 @@ const {
const ethUtil = require('ethereumjs-util') const ethUtil = require('ethereumjs-util')
function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) { function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) {
const { decimals } = selectedToken || {} const { decimals } = selectedToken || {}
const multiplier = Math.pow(10, Number(decimals || 0)) const multiplier = Math.pow(10, Number(decimals || 0))
return selectedToken return selectedToken
? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'}) ? multiplyCurrencies(
: subtractCurrencies( tokenBalance,
ethUtil.addHexPrefix(balance), multiplier,
ethUtil.addHexPrefix(gasTotal), {
{ toNumericBase: 'hex' } toNumericBase: 'hex',
) multiplicandBase: 16,
}
)
: subtractCurrencies(
ethUtil.addHexPrefix(balance),
ethUtil.addHexPrefix(gasTotal),
{ toNumericBase: 'hex' }
)
} }
module.exports = { module.exports = {

@ -19,7 +19,7 @@ describe('amount-max-button utils', () => {
selectedToken: { selectedToken: {
decimals: 10, decimals: 10,
}, },
tokenBalance: 100, tokenBalance: '64',
}), 'e8d4a51000') }), 'e8d4a51000')
}) })
}) })

@ -26,11 +26,11 @@ export default class SendAmountRow extends Component {
updateSendAmount: PropTypes.func, updateSendAmount: PropTypes.func,
updateSendAmountError: PropTypes.func, updateSendAmountError: PropTypes.func,
updateGas: PropTypes.func, updateGas: PropTypes.func,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
validateAmount (amount) { validateAmount (amount) {
const { const {
@ -58,7 +58,6 @@ export default class SendAmountRow extends Component {
if (selectedToken) { if (selectedToken) {
updateGasFeeError({ updateGasFeeError({
amount,
amountConversionRate, amountConversionRate,
balance, balance,
conversionRate, conversionRate,

@ -45,10 +45,10 @@ function mapDispatchToProps (dispatch) {
setMaxModeTo: bool => dispatch(setMaxModeTo(bool)), setMaxModeTo: bool => dispatch(setMaxModeTo(bool)),
updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)), updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)),
updateGasFeeError: (amountDataObject) => { updateGasFeeError: (amountDataObject) => {
dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject))) dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject)))
}, },
updateSendAmountError: (amountDataObject) => { updateSendAmountError: (amountDataObject) => {
dispatch(updateSendErrors(getAmountErrorObject(amountDataObject))) dispatch(updateSendErrors(getAmountErrorObject(amountDataObject)))
}, },
} }
} }

@ -82,7 +82,6 @@ describe('SendAmountRow Component', function () {
assert.deepEqual( assert.deepEqual(
propsMethodSpies.updateGasFeeError.getCall(0).args, propsMethodSpies.updateGasFeeError.getCall(0).args,
[{ [{
amount: 'someAmount',
amountConversionRate: 'mockAmountConversionRate', amountConversionRate: 'mockAmountConversionRate',
balance: 'mockBalance', balance: 'mockBalance',
conversionRate: 7, conversionRate: 7,

@ -12,11 +12,11 @@ export default class FromDropdown extends Component {
onSelect: PropTypes.func, onSelect: PropTypes.func,
openDropdown: PropTypes.func, openDropdown: PropTypes.func,
selectedAccount: PropTypes.object, selectedAccount: PropTypes.object,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
render () { render () {
const { const {

@ -15,11 +15,11 @@ export default class SendFromRow extends Component {
tokenContract: PropTypes.object, tokenContract: PropTypes.object,
updateSendFrom: PropTypes.func, updateSendFrom: PropTypes.func,
setSendTokenBalance: PropTypes.func, setSendTokenBalance: PropTypes.func,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
async handleFromChange (newFrom) { async handleFromChange (newFrom) {
const { const {
@ -32,6 +32,7 @@ export default class SendFromRow extends Component {
const usersToken = await tokenContract.balanceOf(newFrom.address) const usersToken = await tokenContract.balanceOf(newFrom.address)
setSendTokenBalance(usersToken) setSendTokenBalance(usersToken)
} }
updateSendFrom(newFrom) updateSendFrom(newFrom)
} }

@ -10,8 +10,8 @@ import {
} from './send-from-row.selectors.js' } from './send-from-row.selectors.js'
import { calcTokenBalance } from '../../send.utils.js' import { calcTokenBalance } from '../../send.utils.js'
import { import {
updateSendFrom, updateSendFrom,
setSendTokenBalance, setSendTokenBalance,
} from '../../../../actions' } from '../../../../actions'
import { import {
closeFromDropdown, closeFromDropdown,
@ -37,10 +37,10 @@ function mapDispatchToProps (dispatch) {
openFromDropdown: () => dispatch(openFromDropdown()), openFromDropdown: () => dispatch(openFromDropdown()),
updateSendFrom: newFrom => dispatch(updateSendFrom(newFrom)), updateSendFrom: newFrom => dispatch(updateSendFrom(newFrom)),
setSendTokenBalance: (usersToken, selectedToken) => { setSendTokenBalance: (usersToken, selectedToken) => {
if (!usersToken) return if (!usersToken) return
const tokenBalance = calcTokenBalance({ usersToken, selectedToken }) const tokenBalance = calcTokenBalance({ usersToken, selectedToken })
dispatch(setSendTokenBalance(tokenBalance)) dispatch(setSendTokenBalance(tokenBalance))
}, },
} }
} }

@ -12,11 +12,11 @@ export default class SendGasRow extends Component {
gasLoadingError: PropTypes.bool, gasLoadingError: PropTypes.bool,
gasTotal: PropTypes.string, gasTotal: PropTypes.string,
showCustomizeGasModal: PropTypes.func, showCustomizeGasModal: PropTypes.func,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
render () { render () {
const { const {

@ -1,8 +1,8 @@
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { import {
getConversionRate, getConversionRate,
getCurrentCurrency, getCurrentCurrency,
getGasTotal, getGasTotal,
} from '../../send.selectors.js' } from '../../send.selectors.js'
import { getGasLoadingError, gasFeeIsInError } from './send-gas-row.selectors.js' import { getGasLoadingError, gasFeeIsInError } from './send-gas-row.selectors.js'
import { showModal } from '../../../../actions' import { showModal } from '../../../../actions'

@ -19,11 +19,11 @@ export default class SendToRow extends Component {
updateSendTo: PropTypes.func, updateSendTo: PropTypes.func,
updateSendToError: PropTypes.func, updateSendToError: PropTypes.func,
scanQrCode: PropTypes.func, scanQrCode: PropTypes.func,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
handleToChange (to, nickname = '', toError) { handleToChange (to, nickname = '', toError) {
const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props

@ -26,11 +26,11 @@ export default class SendFooter extends Component {
tokenBalance: PropTypes.string, tokenBalance: PropTypes.string,
unapprovedTxs: PropTypes.object, unapprovedTxs: PropTypes.object,
update: PropTypes.func, update: PropTypes.func,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
onCancel () { onCancel () {
this.props.clearSend() this.props.clearSend()

@ -41,11 +41,11 @@ export default class SendTransactionScreen extends PersistentForm {
scanQrCode: PropTypes.func, scanQrCode: PropTypes.func,
qrCodeDetected: PropTypes.func, qrCodeDetected: PropTypes.func,
qrCodeData: PropTypes.object, qrCodeData: PropTypes.object,
}; }
static contextTypes = { static contextTypes = {
t: PropTypes.func, t: PropTypes.func,
}; }
componentWillReceiveProps (nextProps) { componentWillReceiveProps (nextProps) {
if (nextProps.qrCodeData) { if (nextProps.qrCodeData) {
@ -138,14 +138,12 @@ export default class SendTransactionScreen extends PersistentForm {
}) })
const gasFeeErrorObject = selectedToken const gasFeeErrorObject = selectedToken
? getGasFeeErrorObject({ ? getGasFeeErrorObject({
amount,
amountConversionRate, amountConversionRate,
balance, balance,
conversionRate, conversionRate,
gasTotal, gasTotal,
primaryCurrency, primaryCurrency,
selectedToken, selectedToken,
tokenBalance,
}) })
: { gasFee: null } : { gasFee: null }
updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject)) updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject))

@ -89,11 +89,10 @@ function isTokenBalanceSufficient ({
const tokenBalanceIsSufficient = conversionGTE( const tokenBalanceIsSufficient = conversionGTE(
{ {
value: tokenBalance, value: tokenBalance,
fromNumericBase: 'dec', fromNumericBase: 'hex',
}, },
{ {
value: calcTokenAmount(amountInDec, decimals), value: calcTokenAmount(amountInDec, decimals),
fromNumericBase: 'dec',
}, },
) )
@ -151,7 +150,6 @@ function getAmountErrorObject ({
} }
function getGasFeeErrorObject ({ function getGasFeeErrorObject ({
amount,
amountConversionRate, amountConversionRate,
balance, balance,
conversionRate, conversionRate,
@ -180,7 +178,7 @@ function getGasFeeErrorObject ({
function calcTokenBalance ({ selectedToken, usersToken }) { function calcTokenBalance ({ selectedToken, usersToken }) {
const { decimals } = selectedToken || {} const { decimals } = selectedToken || {}
return calcTokenAmount(usersToken.balance.toString(), decimals) + '' return calcTokenAmount(usersToken.balance.toString(), decimals).toString(16)
} }
function doesAmountErrorRequireUpdate ({ function doesAmountErrorRequireUpdate ({

@ -158,14 +158,12 @@ describe('Send Component', function () {
assert.deepEqual( assert.deepEqual(
utilsMethodStubs.getGasFeeErrorObject.getCall(0).args[0], utilsMethodStubs.getGasFeeErrorObject.getCall(0).args[0],
{ {
amount: 'mockAmount',
amountConversionRate: 'mockAmountConversionRate', amountConversionRate: 'mockAmountConversionRate',
balance: 'mockBalance', balance: 'mockBalance',
conversionRate: 10, conversionRate: 10,
gasTotal: 'mockGasTotal', gasTotal: 'mockGasTotal',
primaryCurrency: 'mockPrimaryCurrency', primaryCurrency: 'mockPrimaryCurrency',
selectedToken: 'mockSelectedToken', selectedToken: 'mockSelectedToken',
tokenBalance: 'mockTokenBalance',
} }
) )
}) })

@ -285,11 +285,10 @@ describe('send utils', () => {
[ [
{ {
value: 123, value: 123,
fromNumericBase: 'dec', fromNumericBase: 'hex',
}, },
{ {
value: 'calc:1610', value: 'calc:1610',
fromNumericBase: 'dec',
}, },
] ]
) )

@ -0,0 +1,14 @@
.token-balance-component {
display: flex;
align-items: center;
&__text {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&__suffix {
padding-left: 4px;
}
}

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import classnames from 'classnames' import CurrencyDisplay from '../currency-display'
export default class TokenBalance extends PureComponent { export default class TokenBalance extends PureComponent {
static propTypes = { static propTypes = {
@ -12,12 +12,14 @@ export default class TokenBalance extends PureComponent {
} }
render () { render () {
const { className, string, withSymbol, symbol } = this.props const { className, string, symbol } = this.props
return ( return (
<div className={classnames('hide-text-overflow', className)}> <CurrencyDisplay
{ string + (withSymbol ? ` ${symbol}` : '') } className={className}
</div> displayValue={string}
suffix={symbol}
/>
) )
} }
} }

@ -1,6 +1,6 @@
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import PropTypes from 'prop-types' import PropTypes from 'prop-types'
import CurrencyDisplay from '../currency-display/currency-display.component' import CurrencyDisplay from '../currency-display'
import { getTokenData } from '../../helpers/transactions.util' import { getTokenData } from '../../helpers/transactions.util'
import { getTokenValue, calcTokenAmount } from '../../token-util' import { getTokenValue, calcTokenAmount } from '../../token-util'
@ -12,6 +12,7 @@ export default class TokenCurrencyDisplay extends PureComponent {
state = { state = {
displayValue: '', displayValue: '',
suffix: '',
} }
componentDidMount () { componentDidMount () {
@ -29,25 +30,27 @@ export default class TokenCurrencyDisplay extends PureComponent {
setDisplayValue () { setDisplayValue () {
const { transactionData: data, token } = this.props const { transactionData: data, token } = this.props
const { decimals = '', symbol = '' } = token const { decimals = '', symbol: suffix = '' } = token
const tokenData = getTokenData(data) const tokenData = getTokenData(data)
let displayValue let displayValue
if (tokenData.params && tokenData.params.length) { if (tokenData.params && tokenData.params.length) {
const tokenValue = getTokenValue(tokenData.params) const tokenValue = getTokenValue(tokenData.params)
const tokenAmount = calcTokenAmount(tokenValue, decimals) displayValue = calcTokenAmount(tokenValue, decimals).toString()
displayValue = `${tokenAmount} ${symbol}`
} }
this.setState({ displayValue }) this.setState({ displayValue, suffix })
} }
render () { render () {
const { displayValue, suffix } = this.state
return ( return (
<CurrencyDisplay <CurrencyDisplay
{...this.props} {...this.props}
displayValue={this.state.displayValue} displayValue={displayValue}
suffix={suffix}
/> />
) )
} }

@ -32,7 +32,7 @@ export default class TokenInput extends PureComponent {
super(props) super(props)
const { value: hexValue } = props const { value: hexValue } = props
const decimalValue = hexValue ? this.getDecimalValue(props) : 0 const decimalValue = hexValue ? this.getValue(props) : 0
this.state = { this.state = {
decimalValue, decimalValue,
@ -46,12 +46,12 @@ export default class TokenInput extends PureComponent {
const { hexValue: stateHexValue } = this.state const { hexValue: stateHexValue } = this.state
if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) { if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) {
const decimalValue = this.getDecimalValue(this.props) const decimalValue = this.getValue(this.props)
this.setState({ hexValue: propsHexValue, decimalValue }) this.setState({ hexValue: propsHexValue, decimalValue })
} }
} }
getDecimalValue (props) { getValue (props) {
const { value: hexValue, selectedToken: { decimals, symbol } = {} } = props const { value: hexValue, selectedToken: { decimals, symbol } = {} } = props
const multiplier = Math.pow(10, Number(decimals || 0)) const multiplier = Math.pow(10, Number(decimals || 0))
@ -63,7 +63,7 @@ export default class TokenInput extends PureComponent {
invertConversionRate: true, invertConversionRate: true,
}) })
return Number(decimalValueString) || 0 return Number(decimalValueString) ? decimalValueString : ''
} }
handleChange = decimalValue => { handleChange = decimalValue => {

@ -80,6 +80,8 @@
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
min-width: 0;
max-width: 100%;
&--primary { &--primary {
text-align: end; text-align: end;

@ -6,6 +6,12 @@
height: 54px; height: 54px;
min-width: 0; min-width: 0;
@media screen and (max-width: $break-small) {
flex-direction: column;
height: initial;
width: 100%;
}
&__balance { &__balance {
margin: 0 12px; margin: 0 12px;
display: flex; display: flex;
@ -15,17 +21,8 @@
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
align-items: center; align-items: center;
margin: 16px 0; margin: 16px 0;
} padding: 0 16px;
} max-width: 100%;
&__token-balance {
margin-left: 12px;
font-size: 1.5rem;
@media screen and (max-width: $break-small) {
margin: 12px 0;
margin-left: 0;
font-size: 1.75rem;
} }
} }
@ -34,6 +31,7 @@
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
font-size: 1.75rem; font-size: 1.75rem;
width: 100%;
} }
} }
@ -51,6 +49,7 @@
@media screen and (max-width: $break-small) { @media screen and (max-width: $break-small) {
flex-direction: column; flex-direction: column;
width: 100%;
} }
} }
@ -71,9 +70,4 @@
margin-right: 12px; margin-right: 12px;
} }
} }
@media screen and (max-width: $break-small) {
flex-direction: column;
height: initial
}
} }

@ -26,11 +26,13 @@ export default class TransactionViewBalance extends PureComponent {
return selectedToken return selectedToken
? ( ? (
<TokenBalance <div className="transaction-view-balance__balance">
token={selectedToken} <TokenBalance
withSymbol token={selectedToken}
className="transaction-view-balance__token-balance" withSymbol
/> className="transaction-view-balance__primary-balance"
/>
</div>
) : ( ) : (
<div className="transaction-view-balance__balance"> <div className="transaction-view-balance__balance">
<UserPreferencedCurrencyDisplay <UserPreferencedCurrencyDisplay

@ -38,6 +38,10 @@
align-items: center; align-items: center;
} }
&__suffix {
margin-left: 3px;
}
&--error { &--error {
border-color: $red; border-color: $red;
} }

@ -66,7 +66,7 @@ export default class UnitInput extends PureComponent {
const valueString = String(value) const valueString = String(value)
const valueLength = valueString.length || 1 const valueLength = valueString.length || 1
const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0 const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0
return (valueLength + decimalPointDeficit + 0.75) + 'ch' return (valueLength + decimalPointDeficit + 0.5) + 'ch'
} }
render () { render () {

@ -62,7 +62,7 @@ const toSpecifiedDenomination = {
} }
const baseChange = { const baseChange = {
hex: n => n.toString(16), hex: n => n.toString(16),
dec: n => Number(n).toString(10), dec: n => (new BigNumber(n)).toString(10),
BN: n => new BN(n.toString(16)), BN: n => new BN(n.toString(16)),
} }

@ -3,6 +3,7 @@
background-color: #FFFFFF; background-color: #FFFFFF;
box-shadow: 0 0 7px 0 rgba(0,0,0,0.08); box-shadow: 0 0 7px 0 rgba(0,0,0,0.08);
z-index: 25; z-index: 25;
height: 100%;
&__header { &__header {
display: flex; display: flex;
@ -186,22 +187,8 @@
} }
&__connect-btn { &__connect-btn {
background-color: #259De5;
color: #fff;
border: none;
width: 315px; width: 315px;
min-height: 54px; margin: 20px;
font-weight: 300;
font-size: 14px;
margin-bottom: 20px;
margin-top: 20px;
border-radius: 5px;
display: flex;
flex: 1;
margin-left: 20px;
margin-right: 20px;
justify-content: center;
text-transform: uppercase;
} }
&__connect-btn.disabled { &__connect-btn.disabled {
@ -490,29 +477,8 @@
justify-content: space-between; justify-content: space-between;
} }
&__button { &__button:not(:last-child) {
width: 150px; margin-right: 16px;
min-width: initial;
}
.btn-primary {
background-color: #259DE5;
color: #FFFFFF;
border: none;
width: 100%;
min-height: 54px;
font-weight: 300;
font-size: 14px;
margin-bottom: 20px
}
&__button.unlock {
width: 50%;
}
&__button.btn-primary--disabled {
cursor: not-allowed;
opacity: .5;
} }
} }

@ -552,6 +552,7 @@
&__form-field { &__form-field {
flex: 1 1 auto; flex: 1 1 auto;
min-width: 0;
.currency-display { .currency-display {
color: $tundora; color: $tundora;
@ -580,6 +581,7 @@
line-height: 22px; line-height: 22px;
width: 88px; width: 88px;
font-weight: 400; font-weight: 400;
flex: 0 0 auto;
} }
&__from-dropdown { &__from-dropdown {

@ -33,7 +33,7 @@ function reduceMetamask (state, action) {
gasLimit: null, gasLimit: null,
gasPrice: null, gasPrice: null,
gasTotal: null, gasTotal: null,
tokenBalance: null, tokenBalance: '0x0',
from: '', from: '',
to: '', to: '',
amount: '0x0', amount: '0x0',

@ -137,11 +137,12 @@ export const tokenAmountAndToAddressSelector = createSelector(
const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE) const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE)
toAddress = toParam ? toParam.value : params[0].value toAddress = toParam ? toParam.value : params[0].value
const value = valueParam ? Number(valueParam.value) : Number(params[1].value) const value = valueParam ? Number(valueParam.value) : Number(params[1].value)
tokenAmount = roundExponential(value)
if (tokenDecimals) { if (tokenDecimals) {
tokenAmount = calcTokenAmount(value, tokenDecimals) tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(tokenAmount)
} }
return { return {
@ -163,7 +164,7 @@ export const approveTokenAmountAndToAddressSelector = createSelector(
const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
if (tokenDecimals) { if (tokenDecimals) {
tokenAmount = calcTokenAmount(value, tokenDecimals) tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(tokenAmount) tokenAmount = roundExponential(tokenAmount)
@ -188,7 +189,7 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector(
let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value) let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
if (tokenDecimals) { if (tokenDecimals) {
value = calcTokenAmount(value, tokenDecimals) value = calcTokenAmount(value, tokenDecimals).toNumber()
} }
tokenAmount = roundExponential(value) tokenAmount = roundExponential(value)

@ -109,7 +109,7 @@ export function tokenInfoGetter () {
export function calcTokenAmount (value, decimals) { export function calcTokenAmount (value, decimals) {
const multiplier = Math.pow(10, Number(decimals || 0)) const multiplier = Math.pow(10, Number(decimals || 0))
return new BigNumber(String(value)).div(multiplier).toNumber() return new BigNumber(String(value)).div(multiplier)
} }
export function getTokenValue (tokenParams = []) { export function getTokenValue (tokenParams = []) {

Loading…
Cancel
Save