mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge branch 'master' into transactionControllerRefractorPt3
This commit is contained in:
commit
fbba3a1ac8
17
CHANGELOG.md
17
CHANGELOG.md
@ -2,6 +2,23 @@
|
||||
|
||||
## Current Master
|
||||
|
||||
## 3.9.9 2017-8-18
|
||||
|
||||
- Fix bug where some transaction submission errors would show an empty screen.
|
||||
- Fix bug that could mis-render token balances when very small.
|
||||
- Fix formatting of eth_sign "Sign Message" view.
|
||||
- Add deprecation warning to eth_sign "Sign Message" view.
|
||||
|
||||
## 3.9.8 2017-8-16
|
||||
|
||||
- Reenable token list.
|
||||
- Remove default tokens.
|
||||
|
||||
## 3.9.7 2017-8-15
|
||||
|
||||
- hotfix - disable token list
|
||||
- Added a deprecation warning for web3 https://github.com/ethereum/mist/releases/tag/v0.9.0
|
||||
|
||||
## 3.9.6 2017-8-09
|
||||
|
||||
- Replace account screen with an account drop-down menu.
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "MetaMask",
|
||||
"short_name": "Metamask",
|
||||
"version": "3.9.6",
|
||||
"version": "3.9.9",
|
||||
"manifest_version": 2,
|
||||
"author": "https://metamask.io",
|
||||
"description": "Ethereum Browser Extension",
|
||||
|
@ -114,6 +114,7 @@ module.exports = class TransactionController extends EventEmitter {
|
||||
// listen for tx completion (success, fail)
|
||||
return new Promise((resolve, reject) => {
|
||||
this.txStateManager.once(`${txMeta.id}:finished`, (completedTx) => {
|
||||
this.emit('updateBadge')
|
||||
switch (completedTx.status) {
|
||||
case 'submitted':
|
||||
return resolve(completedTx.hash)
|
||||
@ -136,7 +137,6 @@ module.exports = class TransactionController extends EventEmitter {
|
||||
status: 'unapproved',
|
||||
metamaskNetworkId: this.getNetwork(),
|
||||
txParams: txParams,
|
||||
history: [],
|
||||
}
|
||||
// add default tx params
|
||||
await this.addTxDefaults(txMeta)
|
||||
|
@ -5,7 +5,10 @@ function setupDappAutoReload (web3, observable) {
|
||||
global.web3 = new Proxy(web3, {
|
||||
get: (_web3, name) => {
|
||||
// get the time of use
|
||||
if (name !== '_used') _web3._used = Date.now()
|
||||
if (name !== '_used') {
|
||||
console.warn('MetaMask: web3 will be deprecated in the near future in favor of the ethereumProvider \nhttps://github.com/ethereum/mist/releases/tag/v0.9.0')
|
||||
_web3._used = Date.now()
|
||||
}
|
||||
return _web3[name]
|
||||
},
|
||||
set: (_web3, name, value) => {
|
||||
|
37
app/scripts/lib/tx-state-history-helper.js
Normal file
37
app/scripts/lib/tx-state-history-helper.js
Normal file
@ -0,0 +1,37 @@
|
||||
const jsonDiffer = require('fast-json-patch')
|
||||
const clone = require('clone')
|
||||
|
||||
module.exports = {
|
||||
generateHistoryEntry,
|
||||
replayHistory,
|
||||
snapshotFromTxMeta,
|
||||
migrateFromSnapshotsToDiffs,
|
||||
}
|
||||
|
||||
|
||||
function migrateFromSnapshotsToDiffs(longHistory) {
|
||||
return (
|
||||
longHistory
|
||||
// convert non-initial history entries into diffs
|
||||
.map((entry, index) => {
|
||||
if (index === 0) return entry
|
||||
return generateHistoryEntry(longHistory[index - 1], entry)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
function generateHistoryEntry(previousState, newState) {
|
||||
return jsonDiffer.compare(previousState, newState)
|
||||
}
|
||||
|
||||
function replayHistory(shortHistory) {
|
||||
return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument)
|
||||
}
|
||||
|
||||
function snapshotFromTxMeta(txMeta) {
|
||||
// create txMeta snapshot for history
|
||||
const snapshot = clone(txMeta)
|
||||
// dont include previous history in this snapshot
|
||||
delete snapshot.history
|
||||
return snapshot
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
const clone = require('clone')
|
||||
const extend = require('xtend')
|
||||
const ObservableStore = require('obs-store')
|
||||
const txStateHistoryHelper = require('./tx-state-history-helper')
|
||||
|
||||
module.exports = class TransactionStateManger extends ObservableStore {
|
||||
constructor ({initState, txHistoryLimit, getNetwork}) {
|
||||
@ -41,6 +41,11 @@ module.exports = class TransactionStateManger extends ObservableStore {
|
||||
this.once(`${txMeta.id}:rejected`, function (txId) {
|
||||
this.removeAllListeners(`${txMeta.id}:signed`)
|
||||
})
|
||||
// initialize history
|
||||
txMeta.history = []
|
||||
// capture initial snapshot of txMeta for history
|
||||
const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
|
||||
txMeta.history.push(snapshot)
|
||||
|
||||
const transactions = this.getFullTxList()
|
||||
const txCount = this.getTxCount()
|
||||
@ -57,6 +62,7 @@ module.exports = class TransactionStateManger extends ObservableStore {
|
||||
}
|
||||
transactions.push(txMeta)
|
||||
this._saveTxList(transactions)
|
||||
return txMeta
|
||||
}
|
||||
// gets tx by Id and returns it
|
||||
getTx (txId) {
|
||||
@ -66,19 +72,17 @@ module.exports = class TransactionStateManger extends ObservableStore {
|
||||
|
||||
updateTx (txMeta) {
|
||||
// create txMeta snapshot for history
|
||||
const txMetaForHistory = clone(txMeta)
|
||||
// dont include previous history in this snapshot
|
||||
delete txMetaForHistory.history
|
||||
// add snapshot to tx history
|
||||
if (!txMeta.history) txMeta.history = []
|
||||
txMeta.history.push(txMetaForHistory)
|
||||
const currentState = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
|
||||
// recover previous tx state obj
|
||||
const previousState = txStateHistoryHelper.replayHistory(txMeta.history)
|
||||
// generate history entry and add to history
|
||||
const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState)
|
||||
txMeta.history.push(entry)
|
||||
|
||||
// commit txMeta to state
|
||||
const txId = txMeta.id
|
||||
const txList = this.getFullTxList()
|
||||
const index = txList.findIndex(txData => txData.id === txId)
|
||||
if (!txMeta.history) txMeta.history = []
|
||||
txMeta.history.push(txMetaForHistory)
|
||||
|
||||
txList[index] = txMeta
|
||||
this._saveTxList(txList)
|
||||
}
|
||||
|
52
app/scripts/migrations/018.js
Normal file
52
app/scripts/migrations/018.js
Normal file
@ -0,0 +1,52 @@
|
||||
const version = 18
|
||||
|
||||
/*
|
||||
|
||||
This migration updates "transaction state history" to diffs style
|
||||
|
||||
*/
|
||||
|
||||
const clone = require('clone')
|
||||
const txStateHistoryHelper = require('../lib/tx-state-history-helper')
|
||||
|
||||
|
||||
module.exports = {
|
||||
version,
|
||||
|
||||
migrate: function (originalVersionedData) {
|
||||
const versionedData = clone(originalVersionedData)
|
||||
versionedData.meta.version = version
|
||||
try {
|
||||
const state = versionedData.data
|
||||
const newState = transformState(state)
|
||||
versionedData.data = newState
|
||||
} catch (err) {
|
||||
console.warn(`MetaMask Migration #${version}` + err.stack)
|
||||
}
|
||||
return Promise.resolve(versionedData)
|
||||
},
|
||||
}
|
||||
|
||||
function transformState (state) {
|
||||
const newState = state
|
||||
const transactions = newState.TransactionController.transactions
|
||||
newState.TransactionController.transactions = transactions.map((txMeta) => {
|
||||
// no history: initialize
|
||||
if (!txMeta.history || txMeta.history.length === 0) {
|
||||
const snapshot = txStateHistoryHelper.snapshotFromTxMeta(txMeta)
|
||||
txMeta.history = [snapshot]
|
||||
return txMeta
|
||||
}
|
||||
// has history: migrate
|
||||
const newHistory = (
|
||||
txStateHistoryHelper.migrateFromSnapshotsToDiffs(txMeta.history)
|
||||
// remove empty diffs
|
||||
.filter((entry) => {
|
||||
return !Array.isArray(entry) || entry.length > 0
|
||||
})
|
||||
)
|
||||
txMeta.history = newHistory
|
||||
return txMeta
|
||||
})
|
||||
return newState
|
||||
}
|
@ -28,4 +28,5 @@ module.exports = [
|
||||
require('./015'),
|
||||
require('./016'),
|
||||
require('./017'),
|
||||
require('./018'),
|
||||
]
|
||||
|
@ -73,7 +73,7 @@
|
||||
"eth-query": "^2.1.2",
|
||||
"eth-sig-util": "^1.2.2",
|
||||
"eth-simple-keyring": "^1.1.1",
|
||||
"eth-token-tracker": "^1.1.2",
|
||||
"eth-token-tracker": "^1.1.3",
|
||||
"ethereumjs-tx": "^1.3.0",
|
||||
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
|
||||
"ethereumjs-wallet": "^0.6.0",
|
||||
@ -82,6 +82,7 @@
|
||||
"express": "^4.14.0",
|
||||
"extension-link-enabler": "^1.0.0",
|
||||
"extensionizer": "^1.0.0",
|
||||
"fast-json-patch": "^2.0.4",
|
||||
"fast-levenshtein": "^2.0.6",
|
||||
"gulp": "github:gulpjs/gulp#4.0",
|
||||
"gulp-eslint": "^4.0.0",
|
||||
|
3053
test/data/v17-long-history.json
Normal file
3053
test/data/v17-long-history.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -53,7 +53,7 @@ describe('tx confirmation screen', function () {
|
||||
result = reducers(initialState, action)
|
||||
done()
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
it('should transition to the account detail view', function () {
|
||||
@ -65,91 +65,6 @@ describe('tx confirmation screen', function () {
|
||||
assert.equal(count, 0)
|
||||
})
|
||||
})
|
||||
|
||||
describe('sendTx', function () {
|
||||
var result
|
||||
|
||||
describe('when there is an error', function () {
|
||||
before(function (done) {
|
||||
actions._setBackgroundConnection({
|
||||
approveTransaction (txId, cb) { cb({message: 'An error!'}) },
|
||||
})
|
||||
|
||||
actions.sendTx({id: firstTxId})(function (action) {
|
||||
result = reducers(initialState, action)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('should stay on the page', function () {
|
||||
assert.equal(result.appState.currentView.name, 'confTx')
|
||||
})
|
||||
|
||||
it('should set errorMessage on the currentView', function () {
|
||||
assert(result.appState.currentView.errorMessage)
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there is success', function () {
|
||||
it('should complete tx and go home', function () {
|
||||
actions._setBackgroundConnection({
|
||||
approveTransaction (txId, cb) { cb() },
|
||||
})
|
||||
|
||||
var dispatchExpect = sinon.mock()
|
||||
dispatchExpect.twice()
|
||||
|
||||
actions.sendTx({id: firstTxId})(dispatchExpect)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('when there are two pending txs', function () {
|
||||
var firstTxId = 1457634084250832
|
||||
var result, initialState
|
||||
before(function (done) {
|
||||
initialState = {
|
||||
appState: {
|
||||
currentView: {
|
||||
name: 'confTx',
|
||||
},
|
||||
},
|
||||
metamask: {
|
||||
unapprovedTxs: {
|
||||
'1457634084250832': {
|
||||
id: firstTxId,
|
||||
status: 'unconfirmed',
|
||||
time: 1457634084250,
|
||||
},
|
||||
'1457634084250833': {
|
||||
id: 1457634084250833,
|
||||
status: 'unconfirmed',
|
||||
time: 1457634084255,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeze(initialState)
|
||||
|
||||
// Mocking a background connection:
|
||||
actions._setBackgroundConnection({
|
||||
approveTransaction (firstTxId, cb) { cb() },
|
||||
})
|
||||
|
||||
actions.sendTx({id: firstTxId})(function (action) {
|
||||
result = reducers(initialState, action)
|
||||
})
|
||||
done()
|
||||
})
|
||||
|
||||
it('should stay on the confTx view', function () {
|
||||
assert.equal(result.appState.currentView.name, 'confTx')
|
||||
})
|
||||
|
||||
it('should transition to the first tx', function () {
|
||||
assert.equal(result.appState.currentView.context, 0)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -6,12 +6,15 @@ const clone = require('clone')
|
||||
const sinon = require('sinon')
|
||||
const TransactionController = require('../../app/scripts/controllers/transactions')
|
||||
const TxProvideUtils = require('../../app/scripts/lib/tx-utils')
|
||||
const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
|
||||
|
||||
const noop = () => true
|
||||
const currentNetworkId = 42
|
||||
const otherNetworkId = 36
|
||||
const privKey = new Buffer('8718b9618a37d1fc78c436511fc6df3c8258d3250635bba617f33003270ec03e', 'hex')
|
||||
const { createStubedProvider } = require('../stub/provider')
|
||||
|
||||
|
||||
describe('Transaction Controller', function () {
|
||||
let txController, engine, provider, providerResultStub
|
||||
|
||||
@ -46,9 +49,10 @@ describe('Transaction Controller', function () {
|
||||
id: 1,
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
txParams,
|
||||
history: [],
|
||||
}
|
||||
txController.txStateManager._saveTxList([txMeta])
|
||||
stub = sinon.stub(txController, 'addUnapprovedTransaction').returns(Promise.resolve(txMeta))
|
||||
stub = sinon.stub(txController, 'addUnapprovedTransaction').returns(Promise.resolve(txController.txStateManager.addTx(txMeta)))
|
||||
})
|
||||
|
||||
afterEach(function () {
|
||||
@ -163,7 +167,8 @@ describe('Transaction Controller', function () {
|
||||
|
||||
describe('#addTx', function () {
|
||||
it('should emit updates', function (done) {
|
||||
txMeta = {
|
||||
const txMeta = {
|
||||
id: '1',
|
||||
status: 'unapproved',
|
||||
id: 1,
|
||||
metamaskNetworkId: currentNetworkId,
|
||||
|
23
test/unit/tx-state-history-helper.js
Normal file
23
test/unit/tx-state-history-helper.js
Normal file
@ -0,0 +1,23 @@
|
||||
const assert = require('assert')
|
||||
const txStateHistoryHelper = require('../../app/scripts/lib/tx-state-history-helper')
|
||||
const testVault = require('../data/v17-long-history.json')
|
||||
|
||||
|
||||
describe('tx-state-history-helper', function () {
|
||||
it('migrates history to diffs and can recover original values', function () {
|
||||
testVault.data.TransactionController.transactions.forEach((tx, index) => {
|
||||
const newHistory = txStateHistoryHelper.migrateFromSnapshotsToDiffs(tx.history)
|
||||
newHistory.forEach((newEntry, index) => {
|
||||
if (index === 0) {
|
||||
assert.equal(Array.isArray(newEntry), false, 'initial history item IS NOT a json patch obj')
|
||||
} else {
|
||||
assert.equal(Array.isArray(newEntry), true, 'non-initial history entry IS a json patch obj')
|
||||
}
|
||||
const oldEntry = tx.history[index]
|
||||
const historySubset = newHistory.slice(0, index + 1)
|
||||
const reconstructedValue = txStateHistoryHelper.replayHistory(historySubset)
|
||||
assert.deepEqual(oldEntry, reconstructedValue, 'was able to reconstruct old entry from diffs')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
@ -150,7 +150,7 @@ describe('TransactionStateManger', function () {
|
||||
assert.equal(result.hash, 'foo')
|
||||
})
|
||||
|
||||
it('updates gas price', function () {
|
||||
it('updates gas price and adds history items', function () {
|
||||
const originalGasPrice = '0x01'
|
||||
const desiredGasPrice = '0x02'
|
||||
|
||||
@ -166,10 +166,21 @@ describe('TransactionStateManger', function () {
|
||||
const updatedMeta = clone(txMeta)
|
||||
|
||||
txStateManager.addTx(txMeta)
|
||||
updatedMeta.txParams.gasPrice = desiredGasPrice
|
||||
txStateManager.updateTx(updatedMeta)
|
||||
let result = txStateManager.getTx('1')
|
||||
const updatedTx = txController.getTx('1')
|
||||
// verify tx was initialized correctly
|
||||
assert.equal(updatedTx.history.length, 1, 'one history item (initial)')
|
||||
assert.equal(Array.isArray(updatedTx.history[0]), false, 'first history item is initial state')
|
||||
assert.deepEqual(updatedTx.history[0], txStateHistoryHelper.snapshotFromTxMeta(updatedTx), 'first history item is initial state')
|
||||
// modify value and updateTx
|
||||
updatedTx.txParams.gasPrice = desiredGasPrice
|
||||
txController.updateTx(updatedTx)
|
||||
// check updated value
|
||||
const result = txController.getTx('1')
|
||||
assert.equal(result.txParams.gasPrice, desiredGasPrice, 'gas price updated')
|
||||
// validate history was updated
|
||||
assert.equal(result.history.length, 2, 'two history items (initial + diff)')
|
||||
const expectedEntry = { op: 'replace', path: '/txParams/gasPrice', value: desiredGasPrice }
|
||||
assert.deepEqual(result.history[1], [expectedEntry], 'two history items (initial + diff)')
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -107,14 +107,23 @@ AccountDetailScreen.prototype.render = function () {
|
||||
},
|
||||
[
|
||||
h(
|
||||
'h2.font-medium.color-forest',
|
||||
'div.font-medium.color-forest',
|
||||
{
|
||||
name: 'edit',
|
||||
style: {
|
||||
},
|
||||
},
|
||||
[
|
||||
identity && identity.name,
|
||||
h('h2', {
|
||||
style: {
|
||||
maxWidth: '180px',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
padding: '5px 0px',
|
||||
},
|
||||
}, [
|
||||
identity && identity.name,
|
||||
]),
|
||||
]
|
||||
),
|
||||
h(
|
||||
|
@ -97,7 +97,6 @@ var actions = {
|
||||
cancelMsg: cancelMsg,
|
||||
signPersonalMsg,
|
||||
cancelPersonalMsg,
|
||||
sendTx: sendTx,
|
||||
signTx: signTx,
|
||||
updateAndApproveTx,
|
||||
cancelTx: cancelTx,
|
||||
@ -397,26 +396,13 @@ function signPersonalMsg (msgData) {
|
||||
|
||||
function signTx (txData) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
global.ethQuery.sendTransaction(txData, (err, data) => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
if (err) return dispatch(actions.displayWarning(err.message))
|
||||
dispatch(actions.hideWarning())
|
||||
})
|
||||
dispatch(this.showConfTxPage())
|
||||
}
|
||||
}
|
||||
|
||||
function sendTx (txData) {
|
||||
log.info(`actions - sendTx: ${JSON.stringify(txData.txParams)}`)
|
||||
return (dispatch) => {
|
||||
log.debug(`actions calling background.approveTransaction`)
|
||||
background.approveTransaction(txData.id, (err) => {
|
||||
if (err) {
|
||||
dispatch(actions.txError(err))
|
||||
return log.error(err.message)
|
||||
}
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
if (err) dispatch(actions.displayWarning(err.message))
|
||||
dispatch(this.goHome())
|
||||
})
|
||||
dispatch(actions.showConfTxPage())
|
||||
}
|
||||
}
|
||||
|
||||
@ -428,6 +414,7 @@ function updateAndApproveTx (txData) {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
if (err) {
|
||||
dispatch(actions.txError(err))
|
||||
dispatch(actions.goHome())
|
||||
return log.error(err.message)
|
||||
}
|
||||
dispatch(actions.completedTx(txData.id))
|
||||
|
@ -185,7 +185,7 @@ App.prototype.renderAppBar = function () {
|
||||
style: {},
|
||||
enableAccountsSelector: true,
|
||||
identities: this.props.identities,
|
||||
selected: this.props.selected,
|
||||
selected: this.props.currentView.context,
|
||||
network: this.props.network,
|
||||
}, []),
|
||||
|
||||
|
@ -51,7 +51,16 @@ class AccountDropdowns extends Component {
|
||||
},
|
||||
},
|
||||
),
|
||||
h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, identity.name || ''),
|
||||
h('span', {
|
||||
style: {
|
||||
marginLeft: '20px',
|
||||
fontSize: '24px',
|
||||
maxWidth: '145px',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
},
|
||||
}, identity.name || ''),
|
||||
h('span', { style: { marginLeft: '20px', fontSize: '24px' } }, isSelected ? h('.check', '✓') : null),
|
||||
]
|
||||
)
|
||||
|
@ -38,7 +38,7 @@ PendingMsgDetails.prototype.render = function () {
|
||||
|
||||
// message data
|
||||
h('.tx-data.flex-column.flex-justify-center.flex-grow.select-none', [
|
||||
h('.flex-row.flex-space-between', [
|
||||
h('.flex-column.flex-space-between', [
|
||||
h('label.font-small', 'MESSAGE'),
|
||||
h('span.font-small', msgParams.data),
|
||||
]),
|
||||
|
@ -18,6 +18,9 @@ PendingMsg.prototype.render = function () {
|
||||
|
||||
h('div', {
|
||||
key: msgData.id,
|
||||
style: {
|
||||
maxWidth: '350px',
|
||||
},
|
||||
}, [
|
||||
|
||||
// header
|
||||
@ -35,7 +38,7 @@ PendingMsg.prototype.render = function () {
|
||||
}, `Signing this message can have
|
||||
dangerous side effects. Only sign messages from
|
||||
sites you fully trust with your entire account.
|
||||
This will be fixed in a future version.`),
|
||||
This dangerous method will be removed in a future version.`),
|
||||
|
||||
// message details
|
||||
h(PendingTxDetails, state),
|
||||
|
@ -3,17 +3,6 @@ const h = require('react-hyperscript')
|
||||
const inherits = require('util').inherits
|
||||
const TokenTracker = require('eth-token-tracker')
|
||||
const TokenCell = require('./token-cell.js')
|
||||
const normalizeAddress = require('eth-sig-util').normalize
|
||||
|
||||
const defaultTokens = []
|
||||
const contracts = require('eth-contract-metadata')
|
||||
for (const address in contracts) {
|
||||
const contract = contracts[address]
|
||||
if (contract.erc20) {
|
||||
contract.address = address
|
||||
defaultTokens.push(contract)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TokenList
|
||||
|
||||
@ -38,7 +27,24 @@ TokenList.prototype.render = function () {
|
||||
|
||||
if (error) {
|
||||
log.error(error)
|
||||
return this.message('There was a problem loading your token balances.')
|
||||
return h('.hotFix', {
|
||||
style: {
|
||||
padding: '80px',
|
||||
},
|
||||
}, [
|
||||
'We had trouble loading your token balances. You can view them ',
|
||||
h('span.hotFix', {
|
||||
style: {
|
||||
color: 'rgba(247, 134, 28, 1)',
|
||||
cursor: 'pointer',
|
||||
},
|
||||
onClick: () => {
|
||||
global.platform.openWindow({
|
||||
url: `https://ethplorer.io/address/${userAddress}`,
|
||||
})
|
||||
},
|
||||
}, 'here'),
|
||||
])
|
||||
}
|
||||
|
||||
const tokenViews = tokens.map((tokenData) => {
|
||||
@ -153,7 +159,7 @@ TokenList.prototype.createFreshTokenTracker = function () {
|
||||
this.tracker = new TokenTracker({
|
||||
userAddress,
|
||||
provider: global.ethereumProvider,
|
||||
tokens: uniqueMergeTokens(defaultTokens, this.props.tokens),
|
||||
tokens: this.props.tokens,
|
||||
pollingInterval: 8000,
|
||||
})
|
||||
|
||||
@ -199,16 +205,3 @@ TokenList.prototype.componentWillUnmount = function () {
|
||||
this.tracker.stop()
|
||||
}
|
||||
|
||||
function uniqueMergeTokens (tokensA, tokensB) {
|
||||
const uniqueAddresses = []
|
||||
const result = []
|
||||
tokensA.concat(tokensB).forEach((token) => {
|
||||
const normal = normalizeAddress(token.address)
|
||||
if (!uniqueAddresses.includes(normal)) {
|
||||
uniqueAddresses.push(normal)
|
||||
result.push(token)
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user