mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
fix merge conflicts
This commit is contained in:
commit
9b1df386de
22
.eslintrc
22
.eslintrc
@ -55,13 +55,13 @@
|
||||
"constructor-super": 2,
|
||||
"curly": [2, "multi-line"],
|
||||
"dot-location": [2, "property"],
|
||||
"eol-last": 1,
|
||||
"eol-last": 2,
|
||||
"eqeqeq": [2, "allow-null"],
|
||||
"generator-star-spacing": [2, { "before": true, "after": true }],
|
||||
"handle-callback-err": [1, "^(err|error)$" ],
|
||||
"handle-callback-err": [2, "^(err|error)$" ],
|
||||
"indent": "off",
|
||||
"jsx-quotes": [2, "prefer-double"],
|
||||
"key-spacing": 1,
|
||||
"key-spacing": 2,
|
||||
"keyword-spacing": [2, { "before": true, "after": true }],
|
||||
"new-cap": [2, { "newIsCap": true, "capIsNew": false }],
|
||||
"new-parens": 2,
|
||||
@ -100,7 +100,7 @@
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-multi-spaces": 2,
|
||||
"no-multi-str": 2,
|
||||
"no-multiple-empty-lines": [1, { "max": 2 }],
|
||||
"no-multiple-empty-lines": [2, { "max": 2 }],
|
||||
"no-native-reassign": 2,
|
||||
"no-negated-in-lhs": 2,
|
||||
"no-new": 2,
|
||||
@ -112,7 +112,7 @@
|
||||
"no-obj-calls": 2,
|
||||
"no-octal": 2,
|
||||
"no-octal-escape": 2,
|
||||
"no-path-concat": 1,
|
||||
"no-path-concat": 2,
|
||||
"no-proto": 2,
|
||||
"no-redeclare": 2,
|
||||
"no-regex-spaces": 2,
|
||||
@ -125,7 +125,7 @@
|
||||
"no-sparse-arrays": 2,
|
||||
"no-this-before-super": 2,
|
||||
"no-throw-literal": 2,
|
||||
"no-trailing-spaces": 1,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-undef": 2,
|
||||
"no-undef-init": 2,
|
||||
"no-unexpected-multiline": 2,
|
||||
@ -141,15 +141,15 @@
|
||||
"no-whitespace-before-property": 2,
|
||||
"no-with": 2,
|
||||
"one-var": [2, { "initialized": "never" }],
|
||||
"operator-linebreak": [1, "after", { "overrides": { "?": "ignore", ":": "ignore" } }],
|
||||
"operator-linebreak": [2, "after", { "overrides": { "?": "ignore", ":": "ignore" } }],
|
||||
"padded-blocks": "off",
|
||||
"quotes": [2, "single", {"avoidEscape": true, "allowTemplateLiterals": true}],
|
||||
"react/no-deprecated": 0,
|
||||
"semi": [2, "never"],
|
||||
"semi-spacing": [2, { "before": false, "after": true }],
|
||||
"space-before-blocks": [1, "always"],
|
||||
"space-before-function-paren": [1, "always"],
|
||||
"space-in-parens": [1, "never"],
|
||||
"space-before-blocks": [2, "always"],
|
||||
"space-before-function-paren": [2, "always"],
|
||||
"space-in-parens": [2, "never"],
|
||||
"space-infix-ops": 2,
|
||||
"space-unary-ops": [2, { "words": true, "nonwords": false }],
|
||||
"spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","], "exceptions": ["=", "-"] } ],
|
||||
@ -160,7 +160,7 @@
|
||||
"wrap-iife": [2, "any"],
|
||||
"yield-star-spacing": [2, "both"],
|
||||
"yoda": [2, "never"],
|
||||
"prefer-const": 1,
|
||||
"prefer-const": 2,
|
||||
"mocha/no-exclusive-tests": "error"
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,11 @@
|
||||
|
||||
## 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.
|
||||
- Fixed a bug that could cause an error when sending the max number of tokens.
|
||||
|
||||
## 5.0.2 Friday November 9 2018
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "__MSG_appName__",
|
||||
"short_name": "__MSG_appName__",
|
||||
"version": "5.0.2",
|
||||
"version": "5.0.3",
|
||||
"manifest_version": 2,
|
||||
"author": "https://metamask.io",
|
||||
"description": "__MSG_appDescription__",
|
||||
|
@ -28,7 +28,7 @@ function createInfuraClient ({ network }) {
|
||||
return { networkMiddleware, blockTracker }
|
||||
}
|
||||
|
||||
function createNetworkAndChainIdMiddleware({ network }) {
|
||||
function createNetworkAndChainIdMiddleware ({ network }) {
|
||||
let chainId
|
||||
let netId
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
const EventEmitter = require('events')
|
||||
const EventEmitter = require('safe-event-emitter')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
const Transaction = require('ethereumjs-tx')
|
||||
|
@ -1,4 +1,4 @@
|
||||
const EventEmitter = require('events')
|
||||
const EventEmitter = require('safe-event-emitter')
|
||||
const log = require('loglevel')
|
||||
const EthQuery = require('ethjs-query')
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
const extend = require('xtend')
|
||||
const EventEmitter = require('events')
|
||||
const EventEmitter = require('safe-event-emitter')
|
||||
const ObservableStore = require('obs-store')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
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 all txMetas who's status is approved for the current network
|
||||
*/
|
||||
getApprovedTransactions(address) {
|
||||
getApprovedTransactions (address) {
|
||||
const opts = { status: 'approved' }
|
||||
if (address) opts.from = address
|
||||
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 {boolean} remove - removes this handler after being triggered
|
||||
*/
|
||||
function onMessage(messageType, handler, remove) {
|
||||
function onMessage (messageType, handler, remove) {
|
||||
window.addEventListener('message', function ({ data }) {
|
||||
if (!data || data.type !== messageType) { return }
|
||||
remove && window.removeEventListener('message', handler)
|
||||
@ -59,7 +59,9 @@ onMessage('metamasksetlocked', () => { isEnabled = false })
|
||||
// set up a listener for privacy mode responses
|
||||
onMessage('ethereumproviderlegacy', ({ data: { selectedAddress } }) => {
|
||||
isEnabled = true
|
||||
inpageProvider.publicConfigStore.updateState({ selectedAddress })
|
||||
setTimeout(() => {
|
||||
inpageProvider.publicConfigStore.updateState({ selectedAddress })
|
||||
}, 0)
|
||||
}, true)
|
||||
|
||||
// augment the provider with its enable method
|
||||
@ -70,7 +72,9 @@ inpageProvider.enable = function ({ force } = {}) {
|
||||
reject(error)
|
||||
} else {
|
||||
window.removeEventListener('message', providerHandle)
|
||||
inpageProvider.publicConfigStore.updateState({ selectedAddress })
|
||||
setTimeout(() => {
|
||||
inpageProvider.publicConfigStore.updateState({ selectedAddress })
|
||||
}, 0)
|
||||
|
||||
// wait for the background to update with an account
|
||||
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
|
||||
*/
|
||||
isApproved: function() {
|
||||
isApproved: function () {
|
||||
return new Promise((resolve) => {
|
||||
isApprovedHandle = ({ data: { caching, isApproved } }) => {
|
||||
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 ' +
|
||||
'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.')
|
||||
@ -153,7 +157,7 @@ const proxiedInpageProvider = new Proxy(inpageProvider, {
|
||||
window.ethereum = proxiedInpageProvider
|
||||
|
||||
// detect eth_requestAccounts and pipe to enable for now
|
||||
function detectAccountRequest(method) {
|
||||
function detectAccountRequest (method) {
|
||||
const originalMethod = inpageProvider[method]
|
||||
inpageProvider[method] = function ({ method }) {
|
||||
if (method === 'eth_requestAccounts') {
|
||||
|
@ -38,7 +38,7 @@ async function resolveEnsToIpfsContentId ({ provider, name }) {
|
||||
return contentId
|
||||
}
|
||||
|
||||
function hexValueIsEmpty(value) {
|
||||
function hexValueIsEmpty (value) {
|
||||
return [undefined, null, '0x', '0x0', '0x0000000000000000000000000000000000000000000000000000000000000000'].includes(value)
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ const supportedTopLevelDomains = ['eth']
|
||||
|
||||
module.exports = setupEnsIpfsResolver
|
||||
|
||||
function setupEnsIpfsResolver({ provider }) {
|
||||
function setupEnsIpfsResolver ({ provider }) {
|
||||
|
||||
// install listener
|
||||
const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
|
||||
@ -35,11 +35,11 @@ function setupEnsIpfsResolver({ provider }) {
|
||||
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` })
|
||||
try {
|
||||
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 {
|
||||
// check if ipfs gateway has result
|
||||
const response = await fetch(url, { method: 'HEAD' })
|
||||
|
@ -6,13 +6,13 @@ module.exports = setupFetchDebugging
|
||||
// https://github.com/getsentry/sentry-javascript/pull/1293
|
||||
//
|
||||
|
||||
function setupFetchDebugging() {
|
||||
function setupFetchDebugging () {
|
||||
if (!global.fetch) return
|
||||
const originalFetch = global.fetch
|
||||
|
||||
global.fetch = wrappedFetch
|
||||
|
||||
async function wrappedFetch(...args) {
|
||||
async function wrappedFetch (...args) {
|
||||
const initialStack = getCurrentStack()
|
||||
try {
|
||||
return await originalFetch.call(window, ...args)
|
||||
@ -20,14 +20,14 @@ function setupFetchDebugging() {
|
||||
if (!err.stack) {
|
||||
console.warn('FetchDebugger - fetch encountered an Error without a stack', err)
|
||||
console.warn('FetchDebugger - overriding stack to point of original call')
|
||||
err.stack = initialStack
|
||||
err.stack = initialStack
|
||||
}
|
||||
throw err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentStack() {
|
||||
function getCurrentStack () {
|
||||
try {
|
||||
throw new Error('Fake error for generating stack trace')
|
||||
} catch (err) {
|
||||
|
@ -32,7 +32,7 @@ function setupSentry (opts) {
|
||||
scope.setExtra('isBrave', isBrave)
|
||||
})
|
||||
|
||||
function rewriteReport(report) {
|
||||
function rewriteReport (report) {
|
||||
try {
|
||||
// simplify certain complex error messages (e.g. Ethjs)
|
||||
simplifyErrorMessages(report)
|
||||
|
@ -200,7 +200,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
this.networkController.on('networkDidChange', () => {
|
||||
this.balancesController.updateAllBalances()
|
||||
var currentCurrency = this.currencyController.getCurrentCurrency()
|
||||
this.setCurrentCurrency(currentCurrency, function() {})
|
||||
this.setCurrentCurrency(currentCurrency, function () {})
|
||||
})
|
||||
this.balancesController.updateAllBalances()
|
||||
|
||||
@ -1581,7 +1581,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
/**
|
||||
* Locks MetaMask
|
||||
*/
|
||||
setLocked() {
|
||||
setLocked () {
|
||||
this.providerApprovalController.setLocked()
|
||||
return this.keyringController.setLocked()
|
||||
}
|
||||
|
27
app/scripts/migrations/029.js
Normal file
27
app/scripts/migrations/029.js
Normal file
@ -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
|
||||
}),
|
||||
}
|
||||
|
41
app/scripts/migrations/fail-tx.js
Normal file
41
app/scripts/migrations/fail-tx.js
Normal file
@ -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('./027'),
|
||||
require('./028'),
|
||||
require('./029'),
|
||||
]
|
||||
|
@ -23,7 +23,7 @@ async function start () {
|
||||
const release = global.platform.getVersion()
|
||||
setupSentry({ release, getState })
|
||||
// provide app state to append to error logs
|
||||
function getState() {
|
||||
function getState () {
|
||||
// get app state
|
||||
const state = window.getCleanAppState()
|
||||
// remove unnecessary data
|
||||
|
26
auto-changelog.sh
Executable file
26
auto-changelog.sh
Executable file
@ -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 logLines = changelog.split('\n')
|
||||
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)
|
||||
break
|
||||
}
|
||||
|
@ -222,7 +222,7 @@ ConfigScreen.prototype.render = function () {
|
||||
},
|
||||
}, 'Clear privacy data'),
|
||||
]),
|
||||
|
||||
|
||||
h('hr.horizontal-line'),
|
||||
|
||||
h('div', {
|
||||
@ -253,7 +253,7 @@ ConfigScreen.prototype.render = function () {
|
||||
'Enable privacy mode'
|
||||
),
|
||||
]),
|
||||
|
||||
|
||||
h('hr.horizontal-line'),
|
||||
|
||||
h('div', {
|
||||
|
16084
package-lock.json
generated
16084
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
16
package.json
16
package.json
@ -49,7 +49,8 @@
|
||||
"disc": "gulp disc --debug",
|
||||
"announce": "node development/announcer.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": {
|
||||
"transform": [
|
||||
@ -119,7 +120,7 @@
|
||||
"eth-hd-keyring": "^1.2.2",
|
||||
"eth-json-rpc-filters": "^3.0.1",
|
||||
"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-method-registry": "^1.0.0",
|
||||
"eth-phishing-detect": "^1.1.4",
|
||||
@ -166,7 +167,7 @@
|
||||
"lodash.uniqby": "^4.7.0",
|
||||
"loglevel": "^1.4.1",
|
||||
"metamascara": "^2.0.0",
|
||||
"metamask-inpage-provider": "^1.2.2",
|
||||
"metamask-inpage-provider": "^1.3.0",
|
||||
"metamask-logo": "^2.1.4",
|
||||
"mkdirp": "^0.5.1",
|
||||
"multihashes": "^0.4.12",
|
||||
@ -211,6 +212,7 @@
|
||||
"redux-thunk": "^2.2.0",
|
||||
"request-promise": "^4.2.1",
|
||||
"reselect": "^3.0.1",
|
||||
"safe-event-emitter": "^1.0.1",
|
||||
"sandwich-expando": "^1.1.3",
|
||||
"semaphore": "^1.0.5",
|
||||
"semver": "^5.4.1",
|
||||
@ -268,14 +270,14 @@
|
||||
"fs-extra": "^6.0.1",
|
||||
"fs-promise": "^2.0.3",
|
||||
"ganache-cli": "^6.1.0",
|
||||
"ganache-core": "^2.1.5",
|
||||
"geckodriver": "^1.11.0",
|
||||
"ganache-core": "^2.2.1",
|
||||
"geckodriver": "^1.14.1",
|
||||
"gh-pages": "^1.2.0",
|
||||
"gifencoder": "^1.1.0",
|
||||
"gulp": "github:gulpjs/gulp#6d71a658c61edb3090221579d8f97dbe086ba2ed",
|
||||
"gulp-babel": "^7.0.0",
|
||||
"gulp-json-editor": "^2.2.1",
|
||||
"gulp-livereload": "^3.8.1",
|
||||
"gulp-livereload": "^4.0.0",
|
||||
"gulp-multi-process": "^1.3.1",
|
||||
"gulp-replace": "^0.6.1",
|
||||
"gulp-sourcemaps": "^2.6.0",
|
||||
@ -293,7 +295,7 @@
|
||||
"jsdom": "^11.2.0",
|
||||
"jsdom-global": "^3.0.2",
|
||||
"jshint-stylish": "~2.2.1",
|
||||
"karma": "^2.0.4",
|
||||
"karma": "^3.1.1",
|
||||
"karma-chrome-launcher": "^2.2.0",
|
||||
"karma-cli": "^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 () => {
|
||||
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*$/))
|
||||
const tokenAmount = await balance.getText()
|
||||
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,
|
||||
// or possibly until we use latest version of firefox in the tests
|
||||
if (process.env.SELENIUM_BROWSER !== 'firefox') {
|
||||
const tokenBalanceAmount = await findElement(driver, By.css('.transaction-view-balance__token-balance'))
|
||||
assert.equal(await tokenBalanceAmount.getText(), '43 TST')
|
||||
const tokenBalanceAmount = await findElements(driver, By.css('.transaction-view-balance__primary-balance'))
|
||||
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 () => {
|
||||
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 delay(regularDelayMs)
|
||||
})
|
||||
|
@ -2,6 +2,7 @@ const extend = require('xtend')
|
||||
const BN = require('ethereumjs-util').BN
|
||||
const template = {
|
||||
'status': 'submitted',
|
||||
'history': [{}],
|
||||
'txParams': {
|
||||
'from': '0x7d3517b0d011698406d6e0aed8453f0be2697926',
|
||||
'gas': '0x30d40',
|
||||
|
@ -58,6 +58,7 @@ describe('MetaMaskController', function () {
|
||||
},
|
||||
},
|
||||
initState: clone(firstTimeState),
|
||||
platform: { showTransactionNotification: () => {} },
|
||||
})
|
||||
// disable diagnostics
|
||||
metamaskController.diagnostics = null
|
||||
|
@ -515,14 +515,14 @@ describe('preferences controller', function () {
|
||||
it('should add custom RPC url to state', function () {
|
||||
preferencesController.addToFrequentRpcList('rpc_url', 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)
|
||||
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 () {
|
||||
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('http://localhost:8545')
|
||||
preferencesController.removeFromFrequentRpcList('rpc_url')
|
||||
|
@ -20,10 +20,12 @@ describe('PendingTransactionTracker', function () {
|
||||
nonce: '0x1',
|
||||
value: '0xfffff',
|
||||
},
|
||||
history: [{}],
|
||||
rawTx: '0xf86c808504a817c800827b0d940c62bb85faa3311a998d3aba8098c1235c564966880de0b6b3a7640000802aa08ff665feb887a25d4099e40e11f0fef93ee9608f404bd3f853dd9e84ed3317a6a02ec9d3d1d6e176d4d2593dd760e74ccac753e6a0ea0d00cc9789d0d7ff1f471d',
|
||||
}
|
||||
txMetaNoHash = {
|
||||
id: 2,
|
||||
history: [{}],
|
||||
status: 'submitted',
|
||||
txParams: { from: '0x1678a085c290ebd122dc42cba69373b5953b831d'},
|
||||
}
|
||||
|
@ -52,9 +52,9 @@ describe('Transaction Controller', function () {
|
||||
describe('#getUnapprovedTxCount', function () {
|
||||
it('should return the number of unapproved txs', function () {
|
||||
txController.txStateManager._saveTxList([
|
||||
{ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 2, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
])
|
||||
const unapprovedTxCount = txController.getUnapprovedTxCount()
|
||||
assert.equal(unapprovedTxCount, 3, 'should be 3')
|
||||
@ -64,9 +64,9 @@ describe('Transaction Controller', function () {
|
||||
describe('#getPendingTxCount', function () {
|
||||
it('should return the number of pending txs', function () {
|
||||
txController.txStateManager._saveTxList([
|
||||
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [] },
|
||||
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 2, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 3, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
])
|
||||
const pendingTxCount = txController.getPendingTxCount()
|
||||
assert.equal(pendingTxCount, 3, 'should be 3')
|
||||
@ -82,15 +82,15 @@ describe('Transaction Controller', function () {
|
||||
'to': '0xc684832530fcbddae4b4230a47e991ddcec2831d',
|
||||
}
|
||||
txController.txStateManager._saveTxList([
|
||||
{id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{id: 0, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 1, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 2, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 3, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 4, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 5, status: 'approved', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 6, status: 'signed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 7, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
{id: 8, status: 'failed', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
])
|
||||
})
|
||||
|
||||
@ -112,7 +112,7 @@ describe('Transaction Controller', function () {
|
||||
id: 1,
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
txParams,
|
||||
history: [],
|
||||
history: [{}],
|
||||
}
|
||||
txController.txStateManager._saveTxList([txMeta])
|
||||
stub = sinon.stub(txController, 'addUnapprovedTransaction').callsFake(() => {
|
||||
@ -232,7 +232,7 @@ describe('Transaction Controller', function () {
|
||||
from: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
|
||||
to: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
|
||||
},
|
||||
history: [],
|
||||
history: [{}],
|
||||
}
|
||||
providerResultStub.eth_gasPrice = '4a817c800'
|
||||
providerResultStub.eth_getBlockByNumber = { gasLimit: '47b784' }
|
||||
@ -423,7 +423,7 @@ describe('Transaction Controller', function () {
|
||||
data: '0x0',
|
||||
}
|
||||
txController.txStateManager._saveTxList([
|
||||
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [] },
|
||||
{ id: 1, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams, history: [{}] },
|
||||
])
|
||||
txController.retryTransaction(1)
|
||||
.then((txMeta) => {
|
||||
@ -462,12 +462,12 @@ describe('Transaction Controller', function () {
|
||||
beforeEach(function () {
|
||||
txController.txStateManager._saveTxList([
|
||||
{ id: 1, status: 'unapproved', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 2, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 3, status: 'approved', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 4, status: 'signed', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 6, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 7, status: 'failed', metamaskNetworkId: currentNetworkId, txParams: {} },
|
||||
{ id: 2, status: 'rejected', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 3, status: 'approved', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 4, status: 'signed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 5, status: 'submitted', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 6, status: 'confirmed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
{ id: 7, status: 'failed', metamaskNetworkId: currentNetworkId, txParams: {}, history: [{}] },
|
||||
])
|
||||
})
|
||||
it('should show only submitted and approved transactions as pending transasction', function () {
|
||||
|
@ -1,6 +1,6 @@
|
||||
# Changelog
|
||||
|
||||
## Current Master
|
||||
## Current Develop Branch
|
||||
|
||||
## 4.1.3 2018-2-28
|
||||
|
||||
|
38
test/unit/migrations/029-test.js
Normal file
38
test/unit/migrations/029-test.js
Normal file
@ -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', () => {
|
||||
|
||||
it('init state', () => {
|
||||
const initState = reduceMetamask({metamask:{}}, {})
|
||||
const initState = reduceMetamask({metamask: {}}, {})
|
||||
assert(initState)
|
||||
})
|
||||
|
||||
|
@ -148,7 +148,7 @@ describe('Selectors', function () {
|
||||
|
||||
it('#getSelectedTokenToFiatRate', () => {
|
||||
const selectedTokenToFiatRate = selectors.getSelectedTokenToFiatRate(mockState)
|
||||
assert.equal(selectedTokenToFiatRate, '0.21880988420033493')
|
||||
assert.equal(selectedTokenToFiatRate, '0.21880988420033492152')
|
||||
})
|
||||
|
||||
describe('#getSelectedTokenContract', () => {
|
||||
|
@ -995,7 +995,7 @@ function updateSendTokenBalance ({
|
||||
.then(usersToken => {
|
||||
if (usersToken) {
|
||||
const newTokenBalance = calcTokenBalance({ selectedToken, usersToken })
|
||||
dispatch(setSendTokenBalance(newTokenBalance.toString(10)))
|
||||
dispatch(setSendTokenBalance(newTokenBalance))
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
|
@ -20,15 +20,24 @@ const mergeProps = (stateProps, dispatchProps, ownProps) => {
|
||||
currency,
|
||||
denomination,
|
||||
hideLabel,
|
||||
displayValue: propsDisplayValue,
|
||||
suffix: propsSuffix,
|
||||
...restOwnProps
|
||||
} = ownProps
|
||||
|
||||
const toCurrency = currency || currentCurrency
|
||||
const convertedValue = getValueFromWeiHex({
|
||||
value, fromCurrency: nativeCurrency, toCurrency, conversionRate, numberOfDecimals, toDenomination: denomination,
|
||||
})
|
||||
const displayValue = formatCurrency(convertedValue, toCurrency)
|
||||
const suffix = hideLabel ? undefined : toCurrency.toUpperCase()
|
||||
|
||||
const displayValue = propsDisplayValue || formatCurrency(
|
||||
getValueFromWeiHex({
|
||||
value,
|
||||
fromCurrency: nativeCurrency,
|
||||
toCurrency, conversionRate,
|
||||
numberOfDecimals,
|
||||
toDenomination: denomination,
|
||||
}),
|
||||
toCurrency
|
||||
)
|
||||
const suffix = propsSuffix || (hideLabel ? undefined : toCurrency.toUpperCase())
|
||||
|
||||
return {
|
||||
...restStateProps,
|
||||
|
@ -131,7 +131,7 @@ describe('CurrencyDisplay container', () => {
|
||||
},
|
||||
result: {
|
||||
nativeCurrency: 'ETH',
|
||||
displayValue: '1e-9',
|
||||
displayValue: '0.000000001',
|
||||
suffix: undefined,
|
||||
},
|
||||
},
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
@import './tabs/index';
|
||||
|
||||
@import './token-balance/index';
|
||||
|
||||
@import './transaction-activity-log/index';
|
||||
|
||||
@import './transaction-breakdown/index';
|
||||
|
@ -52,7 +52,7 @@ export default class MenuBar extends PureComponent {
|
||||
{
|
||||
accountDetailsMenuOpen && (
|
||||
<AccountDetailsDropdown
|
||||
className="menu-bar__account-details-dropdown"
|
||||
className="menu-bar__account-details-dropdown"
|
||||
onClose={() => this.setState({ accountDetailsMenuOpen: false })}
|
||||
/>
|
||||
)
|
||||
|
@ -348,7 +348,7 @@ export default class ConfirmTransactionBase extends Component {
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
handleNextTx (txId) {
|
||||
const { history, clearConfirmTransaction } = this.props
|
||||
if (txId) {
|
||||
|
@ -152,7 +152,7 @@ class AccountList extends Component {
|
||||
}, [this.context.t('cancel')]),
|
||||
|
||||
h(Button, {
|
||||
type: 'primary',
|
||||
type: 'confirm',
|
||||
large: true,
|
||||
className: 'new-account-connect-form__button unlock',
|
||||
disabled,
|
||||
|
@ -45,11 +45,13 @@ class ConnectScreen extends Component {
|
||||
this.renderConnectToLedgerButton(),
|
||||
this.renderConnectToTrezorButton(),
|
||||
]),
|
||||
h(
|
||||
`button.hw-connect__connect-btn${!this.state.selectedDevice ? '.disabled' : ''}`,
|
||||
{ onClick: this.connect },
|
||||
this.context.t('connect')
|
||||
),
|
||||
h(Button, {
|
||||
type: 'confirm',
|
||||
large: true,
|
||||
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({
|
||||
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,
|
||||
setMaxModeTo: PropTypes.func,
|
||||
tokenBalance: PropTypes.string,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
setMaxAmount () {
|
||||
const {
|
||||
|
@ -5,16 +5,23 @@ const {
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
|
||||
function calcMaxAmount ({ balance, gasTotal, selectedToken, tokenBalance }) {
|
||||
const { decimals } = selectedToken || {}
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
const { decimals } = selectedToken || {}
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
|
||||
return selectedToken
|
||||
? multiplyCurrencies(tokenBalance, multiplier, {toNumericBase: 'hex'})
|
||||
: subtractCurrencies(
|
||||
ethUtil.addHexPrefix(balance),
|
||||
ethUtil.addHexPrefix(gasTotal),
|
||||
{ toNumericBase: 'hex' }
|
||||
)
|
||||
return selectedToken
|
||||
? multiplyCurrencies(
|
||||
tokenBalance,
|
||||
multiplier,
|
||||
{
|
||||
toNumericBase: 'hex',
|
||||
multiplicandBase: 16,
|
||||
}
|
||||
)
|
||||
: subtractCurrencies(
|
||||
ethUtil.addHexPrefix(balance),
|
||||
ethUtil.addHexPrefix(gasTotal),
|
||||
{ toNumericBase: 'hex' }
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
@ -19,7 +19,7 @@ describe('amount-max-button utils', () => {
|
||||
selectedToken: {
|
||||
decimals: 10,
|
||||
},
|
||||
tokenBalance: 100,
|
||||
tokenBalance: '64',
|
||||
}), 'e8d4a51000')
|
||||
})
|
||||
})
|
||||
|
@ -26,11 +26,11 @@ export default class SendAmountRow extends Component {
|
||||
updateSendAmount: PropTypes.func,
|
||||
updateSendAmountError: PropTypes.func,
|
||||
updateGas: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
validateAmount (amount) {
|
||||
const {
|
||||
@ -58,7 +58,6 @@ export default class SendAmountRow extends Component {
|
||||
|
||||
if (selectedToken) {
|
||||
updateGasFeeError({
|
||||
amount,
|
||||
amountConversionRate,
|
||||
balance,
|
||||
conversionRate,
|
||||
|
@ -45,10 +45,10 @@ function mapDispatchToProps (dispatch) {
|
||||
setMaxModeTo: bool => dispatch(setMaxModeTo(bool)),
|
||||
updateSendAmount: newAmount => dispatch(updateSendAmount(newAmount)),
|
||||
updateGasFeeError: (amountDataObject) => {
|
||||
dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject)))
|
||||
dispatch(updateSendErrors(getGasFeeErrorObject(amountDataObject)))
|
||||
},
|
||||
updateSendAmountError: (amountDataObject) => {
|
||||
dispatch(updateSendErrors(getAmountErrorObject(amountDataObject)))
|
||||
dispatch(updateSendErrors(getAmountErrorObject(amountDataObject)))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,6 @@ describe('SendAmountRow Component', function () {
|
||||
assert.deepEqual(
|
||||
propsMethodSpies.updateGasFeeError.getCall(0).args,
|
||||
[{
|
||||
amount: 'someAmount',
|
||||
amountConversionRate: 'mockAmountConversionRate',
|
||||
balance: 'mockBalance',
|
||||
conversionRate: 7,
|
||||
|
@ -12,11 +12,11 @@ export default class FromDropdown extends Component {
|
||||
onSelect: PropTypes.func,
|
||||
openDropdown: PropTypes.func,
|
||||
selectedAccount: PropTypes.object,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -15,11 +15,11 @@ export default class SendFromRow extends Component {
|
||||
tokenContract: PropTypes.object,
|
||||
updateSendFrom: PropTypes.func,
|
||||
setSendTokenBalance: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
async handleFromChange (newFrom) {
|
||||
const {
|
||||
@ -32,6 +32,7 @@ export default class SendFromRow extends Component {
|
||||
const usersToken = await tokenContract.balanceOf(newFrom.address)
|
||||
setSendTokenBalance(usersToken)
|
||||
}
|
||||
|
||||
updateSendFrom(newFrom)
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ import {
|
||||
} from './send-from-row.selectors.js'
|
||||
import { calcTokenBalance } from '../../send.utils.js'
|
||||
import {
|
||||
updateSendFrom,
|
||||
setSendTokenBalance,
|
||||
updateSendFrom,
|
||||
setSendTokenBalance,
|
||||
} from '../../../../actions'
|
||||
import {
|
||||
closeFromDropdown,
|
||||
@ -37,10 +37,10 @@ function mapDispatchToProps (dispatch) {
|
||||
openFromDropdown: () => dispatch(openFromDropdown()),
|
||||
updateSendFrom: newFrom => dispatch(updateSendFrom(newFrom)),
|
||||
setSendTokenBalance: (usersToken, selectedToken) => {
|
||||
if (!usersToken) return
|
||||
if (!usersToken) return
|
||||
|
||||
const tokenBalance = calcTokenBalance({ usersToken, selectedToken })
|
||||
dispatch(setSendTokenBalance(tokenBalance))
|
||||
const tokenBalance = calcTokenBalance({ usersToken, selectedToken })
|
||||
dispatch(setSendTokenBalance(tokenBalance))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,11 @@ export default class SendGasRow extends Component {
|
||||
gasLoadingError: PropTypes.bool,
|
||||
gasTotal: PropTypes.string,
|
||||
showCustomizeGasModal: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
render () {
|
||||
const {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import { connect } from 'react-redux'
|
||||
import {
|
||||
getConversionRate,
|
||||
getCurrentCurrency,
|
||||
getGasTotal,
|
||||
getConversionRate,
|
||||
getCurrentCurrency,
|
||||
getGasTotal,
|
||||
} from '../../send.selectors.js'
|
||||
import { getGasLoadingError, gasFeeIsInError } from './send-gas-row.selectors.js'
|
||||
import { showModal } from '../../../../actions'
|
||||
|
@ -19,11 +19,11 @@ export default class SendToRow extends Component {
|
||||
updateSendTo: PropTypes.func,
|
||||
updateSendToError: PropTypes.func,
|
||||
scanQrCode: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
handleToChange (to, nickname = '', toError) {
|
||||
const { hasHexData, updateSendTo, updateSendToError, updateGas } = this.props
|
||||
|
@ -26,11 +26,11 @@ export default class SendFooter extends Component {
|
||||
tokenBalance: PropTypes.string,
|
||||
unapprovedTxs: PropTypes.object,
|
||||
update: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
onCancel () {
|
||||
this.props.clearSend()
|
||||
|
@ -41,11 +41,11 @@ export default class SendTransactionScreen extends PersistentForm {
|
||||
scanQrCode: PropTypes.func,
|
||||
qrCodeDetected: PropTypes.func,
|
||||
qrCodeData: PropTypes.object,
|
||||
};
|
||||
}
|
||||
|
||||
static contextTypes = {
|
||||
t: PropTypes.func,
|
||||
};
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.qrCodeData) {
|
||||
@ -138,14 +138,12 @@ export default class SendTransactionScreen extends PersistentForm {
|
||||
})
|
||||
const gasFeeErrorObject = selectedToken
|
||||
? getGasFeeErrorObject({
|
||||
amount,
|
||||
amountConversionRate,
|
||||
balance,
|
||||
conversionRate,
|
||||
gasTotal,
|
||||
primaryCurrency,
|
||||
selectedToken,
|
||||
tokenBalance,
|
||||
})
|
||||
: { gasFee: null }
|
||||
updateSendErrors(Object.assign(amountErrorObject, gasFeeErrorObject))
|
||||
|
@ -89,11 +89,10 @@ function isTokenBalanceSufficient ({
|
||||
const tokenBalanceIsSufficient = conversionGTE(
|
||||
{
|
||||
value: tokenBalance,
|
||||
fromNumericBase: 'dec',
|
||||
fromNumericBase: 'hex',
|
||||
},
|
||||
{
|
||||
value: calcTokenAmount(amountInDec, decimals),
|
||||
fromNumericBase: 'dec',
|
||||
},
|
||||
)
|
||||
|
||||
@ -151,7 +150,6 @@ function getAmountErrorObject ({
|
||||
}
|
||||
|
||||
function getGasFeeErrorObject ({
|
||||
amount,
|
||||
amountConversionRate,
|
||||
balance,
|
||||
conversionRate,
|
||||
@ -180,7 +178,7 @@ function getGasFeeErrorObject ({
|
||||
|
||||
function calcTokenBalance ({ selectedToken, usersToken }) {
|
||||
const { decimals } = selectedToken || {}
|
||||
return calcTokenAmount(usersToken.balance.toString(), decimals) + ''
|
||||
return calcTokenAmount(usersToken.balance.toString(), decimals).toString(16)
|
||||
}
|
||||
|
||||
function doesAmountErrorRequireUpdate ({
|
||||
|
@ -158,14 +158,12 @@ describe('Send Component', function () {
|
||||
assert.deepEqual(
|
||||
utilsMethodStubs.getGasFeeErrorObject.getCall(0).args[0],
|
||||
{
|
||||
amount: 'mockAmount',
|
||||
amountConversionRate: 'mockAmountConversionRate',
|
||||
balance: 'mockBalance',
|
||||
conversionRate: 10,
|
||||
gasTotal: 'mockGasTotal',
|
||||
primaryCurrency: 'mockPrimaryCurrency',
|
||||
selectedToken: 'mockSelectedToken',
|
||||
tokenBalance: 'mockTokenBalance',
|
||||
}
|
||||
)
|
||||
})
|
||||
|
@ -285,11 +285,10 @@ describe('send utils', () => {
|
||||
[
|
||||
{
|
||||
value: 123,
|
||||
fromNumericBase: 'dec',
|
||||
fromNumericBase: 'hex',
|
||||
},
|
||||
{
|
||||
value: 'calc:1610',
|
||||
fromNumericBase: 'dec',
|
||||
},
|
||||
]
|
||||
)
|
||||
|
14
ui/app/components/token-balance/index.scss
Normal file
14
ui/app/components/token-balance/index.scss
Normal file
@ -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 PropTypes from 'prop-types'
|
||||
import classnames from 'classnames'
|
||||
import CurrencyDisplay from '../currency-display'
|
||||
|
||||
export default class TokenBalance extends PureComponent {
|
||||
static propTypes = {
|
||||
@ -12,12 +12,14 @@ export default class TokenBalance extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { className, string, withSymbol, symbol } = this.props
|
||||
const { className, string, symbol } = this.props
|
||||
|
||||
return (
|
||||
<div className={classnames('hide-text-overflow', className)}>
|
||||
{ string + (withSymbol ? ` ${symbol}` : '') }
|
||||
</div>
|
||||
<CurrencyDisplay
|
||||
className={className}
|
||||
displayValue={string}
|
||||
suffix={symbol}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { PureComponent } from 'react'
|
||||
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 { getTokenValue, calcTokenAmount } from '../../token-util'
|
||||
|
||||
@ -12,6 +12,7 @@ export default class TokenCurrencyDisplay extends PureComponent {
|
||||
|
||||
state = {
|
||||
displayValue: '',
|
||||
suffix: '',
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
@ -29,25 +30,27 @@ export default class TokenCurrencyDisplay extends PureComponent {
|
||||
|
||||
setDisplayValue () {
|
||||
const { transactionData: data, token } = this.props
|
||||
const { decimals = '', symbol = '' } = token
|
||||
const { decimals = '', symbol: suffix = '' } = token
|
||||
const tokenData = getTokenData(data)
|
||||
|
||||
let displayValue
|
||||
|
||||
if (tokenData.params && tokenData.params.length) {
|
||||
const tokenValue = getTokenValue(tokenData.params)
|
||||
const tokenAmount = calcTokenAmount(tokenValue, decimals)
|
||||
displayValue = `${tokenAmount} ${symbol}`
|
||||
displayValue = calcTokenAmount(tokenValue, decimals).toString()
|
||||
}
|
||||
|
||||
this.setState({ displayValue })
|
||||
this.setState({ displayValue, suffix })
|
||||
}
|
||||
|
||||
render () {
|
||||
const { displayValue, suffix } = this.state
|
||||
|
||||
return (
|
||||
<CurrencyDisplay
|
||||
{...this.props}
|
||||
displayValue={this.state.displayValue}
|
||||
displayValue={displayValue}
|
||||
suffix={suffix}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ export default class TokenInput extends PureComponent {
|
||||
super(props)
|
||||
|
||||
const { value: hexValue } = props
|
||||
const decimalValue = hexValue ? this.getDecimalValue(props) : 0
|
||||
const decimalValue = hexValue ? this.getValue(props) : 0
|
||||
|
||||
this.state = {
|
||||
decimalValue,
|
||||
@ -46,12 +46,12 @@ export default class TokenInput extends PureComponent {
|
||||
const { hexValue: stateHexValue } = this.state
|
||||
|
||||
if (prevPropsHexValue !== propsHexValue && propsHexValue !== stateHexValue) {
|
||||
const decimalValue = this.getDecimalValue(this.props)
|
||||
const decimalValue = this.getValue(this.props)
|
||||
this.setState({ hexValue: propsHexValue, decimalValue })
|
||||
}
|
||||
}
|
||||
|
||||
getDecimalValue (props) {
|
||||
getValue (props) {
|
||||
const { value: hexValue, selectedToken: { decimals, symbol } = {} } = props
|
||||
|
||||
const multiplier = Math.pow(10, Number(decimals || 0))
|
||||
@ -63,7 +63,7 @@ export default class TokenInput extends PureComponent {
|
||||
invertConversionRate: true,
|
||||
})
|
||||
|
||||
return Number(decimalValueString) || 0
|
||||
return Number(decimalValueString) ? decimalValueString : ''
|
||||
}
|
||||
|
||||
handleChange = decimalValue => {
|
||||
|
@ -80,6 +80,8 @@
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
min-width: 0;
|
||||
max-width: 100%;
|
||||
|
||||
&--primary {
|
||||
text-align: end;
|
||||
|
@ -6,6 +6,12 @@
|
||||
height: 54px;
|
||||
min-width: 0;
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
flex-direction: column;
|
||||
height: initial;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&__balance {
|
||||
margin: 0 12px;
|
||||
display: flex;
|
||||
@ -15,17 +21,8 @@
|
||||
@media screen and (max-width: $break-small) {
|
||||
align-items: center;
|
||||
margin: 16px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&__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;
|
||||
padding: 0 16px;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,6 +31,7 @@
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
font-size: 1.75rem;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,6 +49,7 @@
|
||||
|
||||
@media screen and (max-width: $break-small) {
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,9 +70,4 @@
|
||||
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
|
||||
? (
|
||||
<TokenBalance
|
||||
token={selectedToken}
|
||||
withSymbol
|
||||
className="transaction-view-balance__token-balance"
|
||||
/>
|
||||
<div className="transaction-view-balance__balance">
|
||||
<TokenBalance
|
||||
token={selectedToken}
|
||||
withSymbol
|
||||
className="transaction-view-balance__primary-balance"
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="transaction-view-balance__balance">
|
||||
<UserPreferencedCurrencyDisplay
|
||||
|
@ -38,6 +38,10 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
&__suffix {
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
&--error {
|
||||
border-color: $red;
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ export default class UnitInput extends PureComponent {
|
||||
const valueString = String(value)
|
||||
const valueLength = valueString.length || 1
|
||||
const decimalPointDeficit = valueString.match(/\./) ? -0.5 : 0
|
||||
return (valueLength + decimalPointDeficit + 0.75) + 'ch'
|
||||
return (valueLength + decimalPointDeficit + 0.5) + 'ch'
|
||||
}
|
||||
|
||||
render () {
|
||||
|
@ -62,7 +62,7 @@ const toSpecifiedDenomination = {
|
||||
}
|
||||
const baseChange = {
|
||||
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)),
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
background-color: #FFFFFF;
|
||||
box-shadow: 0 0 7px 0 rgba(0,0,0,0.08);
|
||||
z-index: 25;
|
||||
height: 100%;
|
||||
|
||||
&__header {
|
||||
display: flex;
|
||||
@ -186,22 +187,8 @@
|
||||
}
|
||||
|
||||
&__connect-btn {
|
||||
background-color: #259De5;
|
||||
color: #fff;
|
||||
border: none;
|
||||
width: 315px;
|
||||
min-height: 54px;
|
||||
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;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
&__connect-btn.disabled {
|
||||
@ -490,29 +477,8 @@
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__button {
|
||||
width: 150px;
|
||||
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;
|
||||
&__button:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -552,6 +552,7 @@
|
||||
|
||||
&__form-field {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
|
||||
.currency-display {
|
||||
color: $tundora;
|
||||
@ -580,6 +581,7 @@
|
||||
line-height: 22px;
|
||||
width: 88px;
|
||||
font-weight: 400;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
&__from-dropdown {
|
||||
|
@ -33,7 +33,7 @@ function reduceMetamask (state, action) {
|
||||
gasLimit: null,
|
||||
gasPrice: null,
|
||||
gasTotal: null,
|
||||
tokenBalance: null,
|
||||
tokenBalance: '0x0',
|
||||
from: '',
|
||||
to: '',
|
||||
amount: '0x0',
|
||||
|
@ -137,11 +137,12 @@ export const tokenAmountAndToAddressSelector = createSelector(
|
||||
const valueParam = params.find(param => param.name === TOKEN_PARAM_VALUE)
|
||||
toAddress = toParam ? toParam.value : params[0].value
|
||||
const value = valueParam ? Number(valueParam.value) : Number(params[1].value)
|
||||
tokenAmount = roundExponential(value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals)
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(tokenAmount)
|
||||
}
|
||||
|
||||
return {
|
||||
@ -163,7 +164,7 @@ export const approveTokenAmountAndToAddressSelector = createSelector(
|
||||
const value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals)
|
||||
tokenAmount = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(tokenAmount)
|
||||
@ -188,7 +189,7 @@ export const sendTokenTokenAmountAndToAddressSelector = createSelector(
|
||||
let value = Number(params.find(param => param.name === TOKEN_PARAM_VALUE).value)
|
||||
|
||||
if (tokenDecimals) {
|
||||
value = calcTokenAmount(value, tokenDecimals)
|
||||
value = calcTokenAmount(value, tokenDecimals).toNumber()
|
||||
}
|
||||
|
||||
tokenAmount = roundExponential(value)
|
||||
|
@ -109,7 +109,7 @@ export function tokenInfoGetter () {
|
||||
|
||||
export function calcTokenAmount (value, decimals) {
|
||||
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 = []) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user