aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChi Kei Chan <chikeichan@gmail.com>2017-10-04 07:02:58 +0800
committerGitHub <noreply@github.com>2017-10-04 07:02:58 +0800
commitbd99bc2e88b44b13ca818fbba478bd74eef222e3 (patch)
tree8a653f7015c89305d5c1d35ffc70ab52a30ddb0c
parentac4868170f4c61d13291389d01bf1002fe240ed4 (diff)
parentf12504cd09f136fb5ac0d4dd2a6afab8fa6e6524 (diff)
downloadtangerine-wallet-browser-bd99bc2e88b44b13ca818fbba478bd74eef222e3.tar.gz
tangerine-wallet-browser-bd99bc2e88b44b13ca818fbba478bd74eef222e3.tar.zst
tangerine-wallet-browser-bd99bc2e88b44b13ca818fbba478bd74eef222e3.zip
Merge branch 'master' into NewUI-flat
-rw-r--r--CHANGELOG.md9
-rw-r--r--app/manifest.json5
-rw-r--r--app/scripts/config.js2
-rw-r--r--app/scripts/controllers/currency.js2
-rw-r--r--app/scripts/controllers/network.js49
-rw-r--r--app/scripts/controllers/transactions.js27
-rw-r--r--app/scripts/lib/pending-tx-tracker.js27
-rw-r--r--app/scripts/lib/tx-state-history-helper.js10
-rw-r--r--app/scripts/lib/tx-state-manager.js10
-rw-r--r--app/scripts/metamask-controller.js44
-rw-r--r--development/index.html84
-rw-r--r--package.json6
-rw-r--r--test/unit/pending-tx-test.js44
-rw-r--r--test/unit/tx-controller-test.js25
-rw-r--r--test/unit/tx-state-history-helper.js23
-rw-r--r--ui-dev.js51
-rw-r--r--ui/app/actions.js16
-rw-r--r--ui/app/app.js1
-rw-r--r--ui/app/components/transaction-list-item.js28
-rw-r--r--ui/app/info.js7
20 files changed, 238 insertions, 232 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0faf6fe85..069602915 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
## Current Master
+- Remove Slack link from info page, since it is a big phishing target.
+
+## 3.10.8 2017-9-28
+
+- Fixed usage of new currency fetching API.
+
+## 3.10.7 2017-9-28
+
+- Fixed bug where sometimes the current account was not correctly set and exposed to web apps.
- Added AUD, HKD, SGD, IDR, PHP to currency conversion list
## 3.10.6 2017-9-27
diff --git a/app/manifest.json b/app/manifest.json
index 639f3fb4b..0fc43c7d4 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -1,7 +1,7 @@
{
"name": "MetaMask",
"short_name": "Metamask",
- "version": "3.10.6",
+ "version": "3.10.8",
"manifest_version": 2,
"author": "https://metamask.io",
"description": "Ethereum Browser Extension",
@@ -57,7 +57,8 @@
"permissions": [
"storage",
"clipboardWrite",
- "http://localhost:8545/"
+ "http://localhost:8545/",
+ "https://*.infura.io/"
],
"web_accessible_resources": [
"scripts/inpage.js"
diff --git a/app/scripts/config.js b/app/scripts/config.js
index c5f260583..1d4ff7c0d 100644
--- a/app/scripts/config.js
+++ b/app/scripts/config.js
@@ -2,11 +2,13 @@ const MAINET_RPC_URL = 'https://mainnet.infura.io/metamask'
const ROPSTEN_RPC_URL = 'https://ropsten.infura.io/metamask'
const KOVAN_RPC_URL = 'https://kovan.infura.io/metamask'
const RINKEBY_RPC_URL = 'https://rinkeby.infura.io/metamask'
+const LOCALHOST_RPC_URL = 'http://localhost:8545'
global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
module.exports = {
network: {
+ localhost: LOCALHOST_RPC_URL,
mainnet: MAINET_RPC_URL,
ropsten: ROPSTEN_RPC_URL,
kovan: KOVAN_RPC_URL,
diff --git a/app/scripts/controllers/currency.js b/app/scripts/controllers/currency.js
index 9e696ce55..25a7a942e 100644
--- a/app/scripts/controllers/currency.js
+++ b/app/scripts/controllers/currency.js
@@ -45,7 +45,7 @@ class CurrencyController {
updateConversionRate () {
const currentCurrency = this.getCurrentCurrency()
- return fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency}`)
+ return fetch(`https://api.infura.io/v1/ticker/eth${currentCurrency.toLowerCase()}`)
.then(response => response.json())
.then((parsedResponse) => {
this.setConversionRate(Number(parsedResponse.bid))
diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js
index 2a17cdae8..0f9db4d53 100644
--- a/app/scripts/controllers/network.js
+++ b/app/scripts/controllers/network.js
@@ -1,5 +1,6 @@
+const assert = require('assert')
const EventEmitter = require('events')
-const MetaMaskProvider = require('web3-provider-engine/zero.js')
+const createMetamaskProvider = require('web3-provider-engine/zero.js')
const ObservableStore = require('obs-store')
const ComposedStore = require('obs-store/lib/composed')
const extend = require('xtend')
@@ -9,6 +10,7 @@ const RPC_ADDRESS_LIST = require('../config.js').network
const DEFAULT_RPC = RPC_ADDRESS_LIST['rinkeby']
module.exports = class NetworkController extends EventEmitter {
+
constructor (config) {
super()
config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
@@ -18,13 +20,12 @@ module.exports = class NetworkController extends EventEmitter {
this._proxy = createEventEmitterProxy()
this.on('networkDidChange', this.lookupNetwork)
- this.providerStore.subscribe((state) => this.switchNetwork({ rpcUrl: state.rpcTarget }))
}
- initializeProvider (opts, providerContructor = MetaMaskProvider) {
- this._baseProviderParams = opts
- const provider = providerContructor(opts)
- this._setProvider(provider)
+ initializeProvider (_providerParams) {
+ this._baseProviderParams = _providerParams
+ const rpcUrl = this.getCurrentRpcAddress()
+ this._configureStandardProvider({ rpcUrl })
this._proxy.on('block', this._logBlock.bind(this))
this._proxy.on('error', this.verifyNetwork.bind(this))
this.ethQuery = new EthQuery(this._proxy)
@@ -32,17 +33,8 @@ module.exports = class NetworkController extends EventEmitter {
return this._proxy
}
- switchNetwork (opts) {
- this.setNetworkState('loading')
- const providerParams = extend(this._baseProviderParams, opts)
- this._baseProviderParams = providerParams
- const provider = MetaMaskProvider(providerParams)
- this._setProvider(provider)
- this.emit('networkDidChange')
- }
-
verifyNetwork () {
- // Check network when restoring connectivity:
+ // Check network when restoring connectivity:
if (this.isNetworkLoading()) this.lookupNetwork()
}
@@ -71,6 +63,7 @@ module.exports = class NetworkController extends EventEmitter {
type: 'rpc',
rpcTarget: rpcUrl,
})
+ this._switchNetwork({ rpcUrl })
}
getCurrentRpcAddress () {
@@ -79,10 +72,14 @@ module.exports = class NetworkController extends EventEmitter {
return this.getRpcAddressForType(provider.type)
}
- setProviderType (type) {
+ async setProviderType (type) {
+ assert(type !== 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`)
+ // skip if type already matches
if (type === this.getProviderConfig().type) return
const rpcTarget = this.getRpcAddressForType(type)
- this.providerStore.updateState({type, rpcTarget})
+ assert(rpcTarget, `NetworkController - unknown rpc address for type "${type}"`)
+ this.providerStore.updateState({ type, rpcTarget })
+ this._switchNetwork({ rpcUrl: rpcTarget })
}
getProviderConfig () {
@@ -94,6 +91,22 @@ module.exports = class NetworkController extends EventEmitter {
return provider && provider.rpcTarget ? provider.rpcTarget : DEFAULT_RPC
}
+ //
+ // Private
+ //
+
+ _switchNetwork (providerParams) {
+ this.setNetworkState('loading')
+ this._configureStandardProvider(providerParams)
+ this.emit('networkDidChange')
+ }
+
+ _configureStandardProvider(_providerParams) {
+ const providerParams = extend(this._baseProviderParams, _providerParams)
+ const provider = createMetamaskProvider(providerParams)
+ this._setProvider(provider)
+ }
+
_setProvider (provider) {
// collect old block tracker events
const oldProvider = this._provider
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 4f5c94675..94e04c429 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -32,7 +32,6 @@ module.exports = class TransactionController extends EventEmitter {
this.provider = opts.provider
this.blockTracker = opts.blockTracker
this.signEthTx = opts.signTransaction
- this.accountTracker = opts.accountTracker
this.memStore = new ObservableStore({})
this.query = new EthQuery(this.provider)
@@ -61,33 +60,27 @@ module.exports = class TransactionController extends EventEmitter {
provider: this.provider,
nonceTracker: this.nonceTracker,
retryLimit: 3500, // Retry 3500 blocks, or about 1 day.
- getBalance: (address) => {
- const account = this.accountTracker.store.getState().accounts[address]
- if (!account) return
- return account.balance
- },
publishTransaction: (rawTx) => this.query.sendRawTransaction(rawTx),
getPendingTransactions: this.txStateManager.getPendingTransactions.bind(this.txStateManager),
})
this.txStateManager.store.subscribe(() => this.emit('update:badge'))
- this.pendingTxTracker.on('tx:warning', this.txStateManager.updateTx.bind(this.txStateManager))
+ this.pendingTxTracker.on('tx:warning', (txMeta) => {
+ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:warning')
+ })
this.pendingTxTracker.on('tx:failed', this.txStateManager.setTxStatusFailed.bind(this.txStateManager))
this.pendingTxTracker.on('tx:confirmed', this.txStateManager.setTxStatusConfirmed.bind(this.txStateManager))
this.pendingTxTracker.on('tx:retry', (txMeta) => {
if (!('retryCount' in txMeta)) txMeta.retryCount = 0
txMeta.retryCount++
- this.txStateManager.updateTx(txMeta)
+ this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
})
this.blockTracker.on('block', this.pendingTxTracker.checkForTxInBlock.bind(this.pendingTxTracker))
// this is a little messy but until ethstore has been either
// removed or redone this is to guard against the race condition
- // where accountTracker hasent been populated by the results yet
- this.blockTracker.once('latest', () => {
- this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
- })
+ this.blockTracker.on('latest', this.pendingTxTracker.resubmitPendingTxs.bind(this.pendingTxTracker))
this.blockTracker.on('sync', this.pendingTxTracker.queryPendingTxs.bind(this.pendingTxTracker))
// memstore is computed from a few different stores
this._updateMemstore()
@@ -177,14 +170,14 @@ module.exports = class TransactionController extends EventEmitter {
const txParams = txMeta.txParams
// ensure value
const gasPrice = txParams.gasPrice || await this.query.gasPrice()
- txParams.value = txParams.value || '0x0'
txParams.gasPrice = ethUtil.addHexPrefix(gasPrice.toString(16))
+ txParams.value = txParams.value || '0x0'
// set gasLimit
return await this.txGasUtil.analyzeGasUsage(txMeta)
}
async updateAndApproveTransaction (txMeta) {
- this.txStateManager.updateTx(txMeta)
+ this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
await this.approveTransaction(txMeta.id)
}
@@ -202,7 +195,7 @@ module.exports = class TransactionController extends EventEmitter {
txMeta.txParams.nonce = ethUtil.addHexPrefix(nonceLock.nextNonce.toString(16))
// add nonce debugging information to txMeta
txMeta.nonceDetails = nonceLock.nonceDetails
- this.txStateManager.updateTx(txMeta)
+ this.txStateManager.updateTx(txMeta, 'transactions#approveTransaction')
// sign transaction
const rawTx = await this.signTransaction(txId)
await this.publishTransaction(txId, rawTx)
@@ -233,7 +226,7 @@ module.exports = class TransactionController extends EventEmitter {
async publishTransaction (txId, rawTx) {
const txMeta = this.txStateManager.getTx(txId)
txMeta.rawTx = rawTx
- this.txStateManager.updateTx(txMeta)
+ this.txStateManager.updateTx(txMeta, 'transactions#publishTransaction')
const txHash = await this.query.sendRawTransaction(rawTx)
this.setTxHash(txId, txHash)
this.txStateManager.setTxStatusSubmitted(txId)
@@ -248,7 +241,7 @@ module.exports = class TransactionController extends EventEmitter {
// Add the tx hash to the persisted meta-tx object
const txMeta = this.txStateManager.getTx(txId)
txMeta.hash = txHash
- this.txStateManager.updateTx(txMeta)
+ this.txStateManager.updateTx(txMeta, 'transactions#setTxHash')
}
//
diff --git a/app/scripts/lib/pending-tx-tracker.js b/app/scripts/lib/pending-tx-tracker.js
index b97cec9ce..6f1601586 100644
--- a/app/scripts/lib/pending-tx-tracker.js
+++ b/app/scripts/lib/pending-tx-tracker.js
@@ -1,6 +1,5 @@
const EventEmitter = require('events')
const EthQuery = require('ethjs-query')
-const sufficientBalance = require('./util').sufficientBalance
/*
Utility class for tracking the transactions as they
@@ -12,7 +11,6 @@ const sufficientBalance = require('./util').sufficientBalance
requires a: {
provider: //,
nonceTracker: //see nonce tracker,
- getBalnce: //(address) a function for getting balances,
getPendingTransactions: //() a function for getting an array of transactions,
publishTransaction: //(rawTx) a async function for publishing raw transactions,
}
@@ -25,7 +23,6 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
this.query = new EthQuery(config.provider)
this.nonceTracker = config.nonceTracker
this.retryLimit = config.retryLimit || Infinity
- this.getBalance = config.getBalance
this.getPendingTransactions = config.getPendingTransactions
this.publishTransaction = config.publishTransaction
}
@@ -89,33 +86,24 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
// other
|| errorMessage.includes('gateway timeout')
|| errorMessage.includes('nonce too low')
- || txMeta.retryCount > 1
)
// ignore resubmit warnings, return early
if (isKnownTx) return
// encountered real error - transition to error state
- this.emit('tx:failed', txMeta.id, err)
+ txMeta.warning = {
+ error: errorMessage,
+ message: 'There was an error when resubmitting this transaction.',
+ }
+ this.emit('tx:warning', txMeta, err)
}))
}
async _resubmitTx (txMeta) {
- const address = txMeta.txParams.from
- const balance = this.getBalance(address)
- if (balance === undefined) return
-
if (txMeta.retryCount > this.retryLimit) {
const err = new Error(`Gave up submitting after ${this.retryLimit} blocks un-mined.`)
return this.emit('tx:failed', txMeta.id, err)
}
- // if the value of the transaction is greater then the balance, fail.
- if (!sufficientBalance(txMeta.txParams, balance)) {
- const insufficientFundsError = new Error('Insufficient balance during rebroadcast.')
- this.emit('tx:failed', txMeta.id, insufficientFundsError)
- log.error(insufficientFundsError)
- return
- }
-
// Only auto-submit already-signed txs:
if (!('rawTx' in txMeta)) return
@@ -148,11 +136,10 @@ module.exports = class PendingTransactionTracker extends EventEmitter {
}
} catch (err) {
txMeta.warning = {
- error: err,
+ error: err.message,
message: 'There was a problem loading this transaction.',
}
- this.emit('tx:warning', txMeta)
- throw err
+ this.emit('tx:warning', txMeta, err)
}
}
diff --git a/app/scripts/lib/tx-state-history-helper.js b/app/scripts/lib/tx-state-history-helper.js
index 304069d57..db6e3bc9f 100644
--- a/app/scripts/lib/tx-state-history-helper.js
+++ b/app/scripts/lib/tx-state-history-helper.js
@@ -20,11 +20,15 @@ function migrateFromSnapshotsToDiffs(longHistory) {
)
}
-function generateHistoryEntry(previousState, newState) {
- return jsonDiffer.compare(previousState, newState)
+function generateHistoryEntry(previousState, newState, note) {
+ const entry = jsonDiffer.compare(previousState, newState)
+ // Add a note to the first op, since it breaks if we append it to the entry
+ if (note && entry[0]) entry[0].note = note
+ return entry
}
-function replayHistory(shortHistory) {
+function replayHistory(_shortHistory) {
+ const shortHistory = clone(_shortHistory)
return shortHistory.reduce((val, entry) => jsonDiffer.applyPatch(val, entry).newDocument)
}
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index abb9d7910..cf8117864 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -82,7 +82,7 @@ module.exports = class TransactionStateManger extends EventEmitter {
return txMeta
}
- updateTx (txMeta) {
+ updateTx (txMeta, note) {
if (txMeta.txParams) {
Object.keys(txMeta.txParams).forEach((key) => {
let value = txMeta.txParams[key]
@@ -96,8 +96,8 @@ module.exports = class TransactionStateManger extends EventEmitter {
// 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)
+ const entry = txStateHistoryHelper.generateHistoryEntry(previousState, currentState, note)
+ txMeta.history.push(entry)
// commit txMeta to state
const txId = txMeta.id
@@ -113,7 +113,7 @@ module.exports = class TransactionStateManger extends EventEmitter {
updateTxParams (txId, txParams) {
const txMeta = this.getTx(txId)
txMeta.txParams = extend(txMeta.txParams, txParams)
- this.updateTx(txMeta)
+ this.updateTx(txMeta, `txStateManager#updateTxParams`)
}
/*
@@ -233,7 +233,7 @@ module.exports = class TransactionStateManger extends EventEmitter {
if (status === 'submitted' || status === 'rejected') {
this.emit(`${txMeta.id}:finished`, txMeta)
}
- this.updateTx(txMeta)
+ this.updateTx(txMeta, `txStateManager: setting status to ${status}`)
this.emit('update:badge')
}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index b5c81c348..ef37a852b 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -100,6 +100,14 @@ module.exports = class MetamaskController extends EventEmitter {
encryptor: opts.encryptor || undefined,
})
+ // If only one account exists, make sure it is selected.
+ this.keyringController.store.subscribe((state) => {
+ const addresses = Object.keys(state.walletNicknames || {})
+ if (addresses.length === 1) {
+ const address = addresses[0]
+ this.preferencesController.setSelectedAddress(address)
+ }
+ })
this.keyringController.on('newAccount', (address) => {
this.preferencesController.setSelectedAddress(address)
this.accountTracker.addAccount(address)
@@ -124,7 +132,6 @@ module.exports = class MetamaskController extends EventEmitter {
provider: this.provider,
blockTracker: this.blockTracker,
ethQuery: this.ethQuery,
- accountTracker: this.accountTracker,
})
this.txController.on('newUnaprovedTx', opts.showUnapprovedTx.bind(opts))
@@ -209,19 +216,17 @@ module.exports = class MetamaskController extends EventEmitter {
//
initializeProvider () {
- return this.networkController.initializeProvider({
+ const providerOpts = {
static: {
eth_syncing: false,
web3_clientVersion: `MetaMask/v${version}`,
},
- // rpc data source
- rpcUrl: this.networkController.getCurrentRpcAddress(),
- originHttpHeaderKey: 'X-Metamask-Origin',
// account mgmt
getAccounts: (cb) => {
const isUnlocked = this.keyringController.memStore.getState().isUnlocked
const result = []
const selectedAddress = this.preferencesController.getSelectedAddress()
+
// only show address if account is unlocked
if (isUnlocked && selectedAddress) {
result.push(selectedAddress)
@@ -234,7 +239,9 @@ module.exports = class MetamaskController extends EventEmitter {
processMessage: this.newUnsignedMessage.bind(this),
// personal_sign msg signing
processPersonalMessage: this.newUnsignedPersonalMessage.bind(this),
- })
+ }
+ const providerProxy = this.networkController.initializeProvider(providerOpts)
+ return providerProxy
}
initPublicConfigStore () {
@@ -303,13 +310,14 @@ module.exports = class MetamaskController extends EventEmitter {
const txController = this.txController
const noticeController = this.noticeController
const addressBookController = this.addressBookController
+ const networkController = this.networkController
return {
// etc
getState: (cb) => cb(null, this.getState()),
- setProviderType: this.networkController.setProviderType.bind(this.networkController),
setCurrentCurrency: this.setCurrentCurrency.bind(this),
markAccountsFound: this.markAccountsFound.bind(this),
+
// coinbase
buyEth: this.buyEth.bind(this),
// shapeshift
@@ -324,13 +332,15 @@ module.exports = class MetamaskController extends EventEmitter {
// vault management
submitPassword: this.submitPassword.bind(this),
+ // network management
+ setProviderType: nodeify(networkController.setProviderType, networkController),
+ setCustomRpc: nodeify(this.setCustomRpc, this),
+
// PreferencesController
setSelectedAddress: nodeify(preferencesController.setSelectedAddress, preferencesController),
addToken: nodeify(preferencesController.addToken, preferencesController),
removeToken: nodeify(preferencesController.removeToken, preferencesController),
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
- setDefaultRpc: nodeify(this.setDefaultRpc, this),
- setCustomRpc: nodeify(this.setCustomRpc, this),
// AddressController
setAddressBook: nodeify(addressBookController.setAddressBook, addressBookController),
@@ -681,19 +691,13 @@ module.exports = class MetamaskController extends EventEmitter {
createShapeShiftTx (depositAddress, depositType) {
this.shapeshiftController.createShapeShiftTx(depositAddress, depositType)
}
-// network
- setDefaultRpc () {
- this.networkController.setRpcTarget('http://localhost:8545')
- return Promise.resolve('http://localhost:8545')
- }
+ // network
- setCustomRpc (rpcTarget, rpcList) {
+ async setCustomRpc (rpcTarget, rpcList) {
this.networkController.setRpcTarget(rpcTarget)
-
- return this.preferencesController.updateFrequentRpcList(rpcTarget)
- .then(() => {
- return Promise.resolve(rpcTarget)
- })
+ await this.preferencesController.updateFrequentRpcList(rpcTarget)
+ return rpcTarget
}
+
}
diff --git a/development/index.html b/development/index.html
index a0814cb55..e5a027447 100644
--- a/development/index.html
+++ b/development/index.html
@@ -3,62 +3,58 @@
<head>
<meta charset="utf-8">
<title>MetaMask</title>
-
</head>
<body>
-
- <!-- app content -->
- <div id="app-content" style="height: 100%"></div>
<script src="./bundle.js" type="text/javascript" charset="utf-8"></script>
+
+ <style>
+ html, body, #test-container, .super-dev-container {
+ height: 100%;
+ width: 100%;
+ position: relative;
+ background: white;
+ }
+ #app-content {
+ background: #F7F7F7;
+ }
+ </style>
- </body>
+ <script>
+ liveReloadCode(Date.now(), 300)
+ function liveReloadCode(lastUpdate, updateRate) {
+ setTimeout(iter, updateRate)
-<style>
-html, body, #test-container, .super-dev-container {
- height: 100%;
- width: 100%;
- position: relative;
- background: white;
-}
-#app-content {
- background: #F7F7F7;
-}
-</style>
+ function iter() {
+ var xhr = new XMLHttpRequest()
-<script>
-liveReloadCode(Date.now(), 300)
-function liveReloadCode(lastUpdate, updateRate) {
- setTimeout(iter, updateRate)
+ xhr.open('GET', '/-/live-reload')
+ xhr.onreadystatechange = function() {
+ if(xhr.readyState !== 4) {
+ return
+ }
- function iter() {
- var xhr = new XMLHttpRequest()
+ try {
+ var change = JSON.parse(xhr.responseText).lastUpdate
- xhr.open('GET', '/-/live-reload')
- xhr.onreadystatechange = function() {
- if(xhr.readyState !== 4) {
- return
- }
+ if(lastUpdate < change) {
+ return reload()
+ }
+ } catch(err) {
+ }
- try {
- var change = JSON.parse(xhr.responseText).lastUpdate
+ xhr =
+ xhr.onreadystatechange = null
+ setTimeout(iter, updateRate)
+ }
- if(lastUpdate < change) {
- return reload()
+ xhr.send(null)
}
- } catch(err) {
}
- xhr =
- xhr.onreadystatechange = null
- setTimeout(iter, updateRate)
- }
-
- xhr.send(null)
- }
-}
+ function reload() {
+ window.location.reload()
+ }
+ </script>
-function reload() {
- window.location.reload()
-}
- </script>
+ </body>
</html>
diff --git a/package.json b/package.json
index 5763f6e32..20a1fa8ea 100644
--- a/package.json
+++ b/package.json
@@ -157,7 +157,7 @@
"valid-url": "^1.0.9",
"vreme": "^3.0.2",
"web3": "^0.20.1",
- "web3-provider-engine": "^13.2.12",
+ "web3-provider-engine": "^13.3.1",
"web3-stream-provider": "^3.0.1",
"xtend": "^4.0.1"
},
@@ -174,7 +174,7 @@
"brfs": "^1.4.3",
"browserify": "^14.4.0",
"chai": "^4.1.0",
- "coveralls": "^2.13.1",
+ "coveralls": "^3.0.0",
"deep-freeze-strict": "^1.1.1",
"del": "^3.0.0",
"envify": "^4.0.0",
@@ -204,7 +204,7 @@
"karma-firefox-launcher": "^1.0.1",
"karma-qunit": "^1.2.1",
"lodash.assign": "^4.0.6",
- "mocha": "^3.4.2",
+ "mocha": "^4.0.0",
"mocha-eslint": "^4.0.0",
"mocha-jsdom": "^1.1.0",
"mocha-sinon": "^2.0.0",
diff --git a/test/unit/pending-tx-test.js b/test/unit/pending-tx-test.js
index 1af464656..6b62bb5b1 100644
--- a/test/unit/pending-tx-test.js
+++ b/test/unit/pending-tx-test.js
@@ -40,14 +40,12 @@ describe('PendingTransactionTracker', function () {
pendingTxTracker = new PendingTransactionTracker({
provider,
- getBalance: () => {},
nonceTracker: {
getGlobalLock: async () => {
return { releaseLock: () => {} }
}
},
getPendingTransactions: () => {return []},
- sufficientBalance: () => {},
publishTransaction: () => {},
})
})
@@ -59,7 +57,7 @@ describe('PendingTransactionTracker', function () {
const block = Proxy.revocable({}, {}).revoke()
pendingTxTracker.checkForTxInBlock(block)
})
- it('should emit \'txFailed\' if the txMeta does not have a hash', function (done) {
+ it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
const block = Proxy.revocable({}, {}).revoke()
pendingTxTracker.getPendingTransactions = () => [txMetaNoHash]
pendingTxTracker.once('tx:failed', (txId, err) => {
@@ -107,7 +105,7 @@ describe('PendingTransactionTracker', function () {
})
describe('#_checkPendingTx', function () {
- it('should emit \'txFailed\' if the txMeta does not have a hash', function (done) {
+ it('should emit \'tx:failed\' if the txMeta does not have a hash', function (done) {
pendingTxTracker.once('tx:failed', (txId, err) => {
assert(txId, txMetaNoHash.id, 'should pass txId')
done()
@@ -174,7 +172,7 @@ describe('PendingTransactionTracker', function () {
.catch(done)
pendingTxTracker.resubmitPendingTxs()
})
- it('should not emit \'txFailed\' if the txMeta throws a known txError', function (done) {
+ it('should not emit \'tx:failed\' if the txMeta throws a known txError', function (done) {
knownErrors =[
// geth
' Replacement transaction Underpriced ',
@@ -201,8 +199,15 @@ describe('PendingTransactionTracker', function () {
pendingTxTracker.resubmitPendingTxs()
})
- it('should emit \'txFailed\' if it encountered a real error', function (done) {
- pendingTxTracker.once('tx:failed', (id, err) => err.message === 'im some real error' ? txList[id - 1].resolve() : done(err))
+ it('should emit \'tx:warning\' if it encountered a real error', function (done) {
+ pendingTxTracker.once('tx:warning', (txMeta, err) => {
+ if (err.message === 'im some real error') {
+ const matchingTx = txList.find(tx => tx.id === txMeta.id)
+ matchingTx.resolve()
+ } else {
+ done(err)
+ }
+ })
pendingTxTracker.getPendingTransactions = () => txList
pendingTxTracker._resubmitTx = async (tx) => { throw new TypeError('im some real error') }
@@ -213,30 +218,7 @@ describe('PendingTransactionTracker', function () {
pendingTxTracker.resubmitPendingTxs()
})
})
- describe('#_resubmitTx with a too-low balance', function () {
- it('should return before publishing the transaction because to low of balance', function (done) {
- const lowBalance = '0x0'
- pendingTxTracker.getBalance = (address) => {
- assert.equal(address, txMeta.txParams.from, 'Should pass the address')
- return lowBalance
- }
- pendingTxTracker.publishTransaction = async (rawTx) => {
- done(new Error('tried to publish transaction'))
- }
-
- // Stubbing out current account state:
- // Adding the fake tx:
- pendingTxTracker.once('tx:failed', (txId, err) => {
- assert(err, 'Should have a error')
- done()
- })
- pendingTxTracker._resubmitTx(txMeta)
- .catch((err) => {
- assert.ifError(err, 'should not throw an error')
- done(err)
- })
- })
-
+ describe('#_resubmitTx', function () {
it('should publishing the transaction', function (done) {
const enoughBalance = '0x100000'
pendingTxTracker.getBalance = (address) => {
diff --git a/test/unit/tx-controller-test.js b/test/unit/tx-controller-test.js
index 66772ff88..bb51ab01f 100644
--- a/test/unit/tx-controller-test.js
+++ b/test/unit/tx-controller-test.js
@@ -25,7 +25,6 @@ describe('Transaction Controller', function () {
networkStore: new ObservableStore(currentNetworkId),
txHistoryLimit: 10,
blockTracker: { getCurrentBlock: noop, on: noop, once: noop },
- accountTracker: { store: { getState: noop } },
signTransaction: (ethTx) => new Promise((resolve) => {
ethTx.sign(privKey)
resolve()
@@ -383,30 +382,6 @@ describe('Transaction Controller', function () {
})
})
- describe('#getBalance', function () {
- it('gets balance', function () {
- sinon.stub(txController.accountTracker.store, 'getState').callsFake(() => {
- return {
- accounts: {
- '0x1678a085c290ebd122dc42cba69373b5953b831d': {
- address: '0x1678a085c290ebd122dc42cba69373b5953b831d',
- balance: '0x00000000000000056bc75e2d63100000',
- code: '0x',
- nonce: '0x0',
- },
- '0xc684832530fcbddae4b4230a47e991ddcec2831d': {
- address: '0xc684832530fcbddae4b4230a47e991ddcec2831d',
- balance: '0x0',
- code: '0x',
- nonce: '0x0',
- },
- },
- }
- })
- assert.equal(txController.pendingTxTracker.getBalance('0x1678a085c290ebd122dc42cba69373b5953b831d'), '0x00000000000000056bc75e2d63100000')
- assert.equal(txController.pendingTxTracker.getBalance('0xc684832530fcbddae4b4230a47e991ddcec2831d'), '0x0')
- })
- })
describe('#getPendingTransactions', function () {
beforeEach(function () {
diff --git a/test/unit/tx-state-history-helper.js b/test/unit/tx-state-history-helper.js
index 5bb6c9bee..79ee26d6e 100644
--- a/test/unit/tx-state-history-helper.js
+++ b/test/unit/tx-state-history-helper.js
@@ -20,4 +20,27 @@ describe('tx-state-history-helper', function () {
})
})
})
+
+ it('replaying history does not mutate the original obj', function () {
+ const initialState = { test: true, message: 'hello', value: 1 }
+ const diff1 = [{
+ "op": "replace",
+ "path": "/message",
+ "value": "haay",
+ }]
+ const diff2 = [{
+ "op": "replace",
+ "path": "/value",
+ "value": 2,
+ }]
+ const history = [initialState, diff1, diff2]
+
+ const beforeStateSnapshot = JSON.stringify(initialState)
+ const latestState = txStateHistoryHelper.replayHistory(history)
+ const afterStateSnapshot = JSON.stringify(initialState)
+
+ assert.notEqual(initialState, latestState, 'initial state is not the same obj as the latest state')
+ assert.equal(beforeStateSnapshot, afterStateSnapshot, 'initial state is not modified during run')
+ })
+
})
diff --git a/ui-dev.js b/ui-dev.js
index de5dfd8ef..620d81667 100644
--- a/ui-dev.js
+++ b/ui-dev.js
@@ -61,30 +61,37 @@ const actions = {
var css = MetaMaskUiCss()
injectCss(css)
-const container = document.querySelector('#test-container')
-
// parse opts
var store = configureStore(states[selectedView])
// start app
-render(
- h('.super-dev-container', [
-
- h(Selector, { actions, selectedKey: selectedView, states, store }),
-
- h('#app-content', {
- style: {
- height: '500px',
- width: '360px',
- boxShadow: 'grey 0px 2px 9px',
- margin: '20px',
- },
- }, [
- h(Root, {
- store: store,
- }),
- ]),
-
- ]
-), container)
+startApp()
+
+function startApp(){
+ const body = document.body
+ const container = document.createElement('div')
+ container.id = 'test-container'
+ body.appendChild(container)
+
+ render(
+ h('.super-dev-container', [
+
+ h(Selector, { actions, selectedKey: selectedView, states, store }),
+
+ h('#app-content', {
+ style: {
+ height: '500px',
+ width: '360px',
+ boxShadow: 'grey 0px 2px 9px',
+ margin: '20px',
+ },
+ }, [
+ h(Root, {
+ store: store,
+ }),
+ ]),
+
+ ]
+ ), container)
+}
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 630b6390c..7b0b0d9c5 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -145,8 +145,6 @@ var actions = {
SET_RPC_TARGET: 'SET_RPC_TARGET',
SET_DEFAULT_RPC_TARGET: 'SET_DEFAULT_RPC_TARGET',
SET_PROVIDER_TYPE: 'SET_PROVIDER_TYPE',
- USE_ETHERSCAN_PROVIDER: 'USE_ETHERSCAN_PROVIDER',
- useEtherscanProvider: useEtherscanProvider,
showConfigPage,
SHOW_ADD_TOKEN_PAGE: 'SHOW_ADD_TOKEN_PAGE',
showAddTokenPage,
@@ -156,7 +154,6 @@ var actions = {
updateTokens,
UPDATE_TOKENS: 'UPDATE_TOKENS',
setRpcTarget: setRpcTarget,
- setDefaultRpcTarget: setDefaultRpcTarget,
setProviderType: setProviderType,
// loading overlay
SHOW_LOADING: 'SHOW_LOADING_INDICATION',
@@ -864,16 +861,19 @@ function markAccountsFound () {
// config
//
-// default rpc target refers to localhost:8545 in this instance.
-function setDefaultRpcTarget () {
- log.debug(`background.setDefaultRpcTarget`)
+function setProviderType (type) {
return (dispatch) => {
- background.setDefaultRpc((err, result) => {
+ log.debug(`background.setProviderType`)
+ background.setProviderType(type, (err, result) => {
if (err) {
log.error(err)
- return dispatch(self.displayWarning('Had a problem changing networks.'))
+ return dispatch(self.displayWarning('Had a problem changing networks!'))
}
})
+ return {
+ type: actions.SET_PROVIDER_TYPE,
+ value: type,
+ }
}
}
diff --git a/ui/app/app.js b/ui/app/app.js
index 583497cb3..f1a671ab1 100644
--- a/ui/app/app.js
+++ b/ui/app/app.js
@@ -254,6 +254,7 @@ App.prototype.renderAppBar = function () {
)
}
+
App.prototype.renderBackButton = function (style, justArrow = false) {
var props = this.props
return (
diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js
index a40066dc7..3ea466d24 100644
--- a/ui/app/components/transaction-list-item.js
+++ b/ui/app/components/transaction-list-item.js
@@ -133,7 +133,7 @@ function recipientField (txParams, transaction, isTx, isMsg) {
},
}, [
message,
- failIfFailed(transaction),
+ renderErrorOrWarning(transaction),
])
}
@@ -141,8 +141,11 @@ function formatDate (date) {
return vreme.format(new Date(date), 'March 16 2014 14:30')
}
-function failIfFailed (transaction) {
- if (transaction.status === 'rejected') {
+function renderErrorOrWarning (transaction) {
+ const { status, err, warning } = transaction
+
+ // show rejected
+ if (status === 'rejected') {
return h('span.error', ' (Rejected)')
}
if (transaction.err || transaction.warning) {
@@ -152,14 +155,27 @@ function failIfFailed (transaction) {
errFirst ? err.message : warning.message
+ // show error
+ if (err) {
+ const message = err.message || ''
+ return (
+ h(Tooltip, {
+ title: message,
+ position: 'bottom',
+ }, [
+ h(`span.error`, ` (Failed)`),
+ ])
+ )
+ }
+ // show warning
+ if (warning) {
+ const message = warning.message
return h(Tooltip, {
title: message,
position: 'bottom',
}, [
- h(`span.${errFirst ? 'error' : 'warning'}`,
- ` (${errFirst ? 'Failed' : 'Warning'})`
- ),
+ h(`span.warning`, ` (Warning)`),
])
}
}
diff --git a/ui/app/info.js b/ui/app/info.js
index 4c7d4cb4c..24c211c1f 100644
--- a/ui/app/info.js
+++ b/ui/app/info.js
@@ -126,13 +126,6 @@ InfoScreen.prototype.render = function () {
]),
]),
- h('div.fa.fa-slack', [
- h('a.info', {
- href: 'http://slack.metamask.io',
- target: '_blank',
- }, 'Join the conversation on Slack'),
- ]),
-
h('div', [
h('.fa.fa-twitter', [
h('a.info', {