aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/_locales/en/messages.json11
-rw-r--r--app/images/search.svg14
-rw-r--r--app/images/tokensearch.svg15
-rw-r--r--app/scripts/background.js2
-rw-r--r--app/scripts/contentscript.js3
-rw-r--r--app/scripts/controllers/address-book.js27
-rw-r--r--app/scripts/controllers/network/enums.js26
-rw-r--r--app/scripts/controllers/network/network.js121
-rw-r--r--app/scripts/controllers/network/util.js36
-rw-r--r--app/scripts/controllers/preferences.js30
-rw-r--r--app/scripts/controllers/recent-blocks.js22
-rw-r--r--app/scripts/controllers/transactions/index.js15
-rw-r--r--app/scripts/controllers/transactions/lib/tx-state-history-helper.js21
-rw-r--r--app/scripts/controllers/transactions/tx-state-manager.js2
-rw-r--r--app/scripts/first-time-state.js9
-rw-r--r--app/scripts/lib/createErrorMiddleware.js66
-rw-r--r--app/scripts/lib/inpage-provider.js2
-rw-r--r--app/scripts/lib/setupRaven.js42
-rw-r--r--app/scripts/metamask-controller.js28
-rw-r--r--app/scripts/migrations/026.js47
-rw-r--r--app/scripts/migrations/index.js1
21 files changed, 297 insertions, 243 deletions
diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json
index 90beda418..fa01fea24 100644
--- a/app/_locales/en/messages.json
+++ b/app/_locales/en/messages.json
@@ -23,6 +23,9 @@
"addTokens": {
"message": "Add Tokens"
},
+ "addAcquiredTokens": {
+ "message": "Add the tokens you've acquired using MetaMask"
+ },
"amount": {
"message": "Amount"
},
@@ -53,7 +56,7 @@
"message": "Back"
},
"balance": {
- "message": "Balance:"
+ "message": "Balance"
},
"balances": {
"message": "Token balance(s)"
@@ -717,6 +720,9 @@
"search": {
"message": "Search"
},
+ "searchResults": {
+ "message": "Search Results"
+ },
"secretPhrase": {
"message": "Enter your secret twelve word phrase here to restore your vault."
},
@@ -832,6 +838,9 @@
"message": "$1 to ETH via ShapeShift",
"description": "system will fill in deposit type in start of message"
},
+ "token": {
+ "message": "Token"
+ },
"tokenAddress": {
"message": "Token Address"
},
diff --git a/app/images/search.svg b/app/images/search.svg
new file mode 100644
index 000000000..44fea12aa
--- /dev/null
+++ b/app/images/search.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="17px" height="17px" viewBox="0 0 17 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: Sketch 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
+ <title>search</title>
+ <desc>Created with Sketch.</desc>
+ <defs></defs>
+ <g id="Add-Tokens" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Metamascara---add-from-token-list-Copy-3" transform="translate(-345.000000, -350.000000)" fill="#9B9B9B" fill-rule="nonzero">
+ <g id="search" transform="translate(345.000000, 350.000000)">
+ <path d="M2.01875,6.90625 C2.01875,4.25 4.25,2.01875 6.90625,2.01875 C9.5625,2.01875 11.6875,4.14375 11.6875,6.90625 C11.6875,9.5625 9.5625,11.6875 6.90625,11.6875 C4.14375,11.6875 2.01875,9.5625 2.01875,6.90625 Z M16.575,15.0875 L12.325,10.8375 C13.175,9.66875 13.6,8.2875 13.6,6.8 C13.70625,3.08125 10.625,0 6.90625,0 C3.08125,0 0,3.08125 0,6.90625 C0,10.73125 3.08125,13.8125 6.90625,13.8125 C8.18125,13.8125 9.45625,13.3875 10.4125,12.75 L14.6625,17 L16.575,15.0875 Z" id="Page-1"></path>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/images/tokensearch.svg b/app/images/tokensearch.svg
new file mode 100644
index 000000000..cd0b03bf2
--- /dev/null
+++ b/app/images/tokensearch.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="65px" height="58px" viewBox="0 0 65 58" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <!-- Generator: sketchtool 50.2 (55047) - http://www.bohemiancoding.com/sketch -->
+ <title>7FDB75AD-BD4D-497C-B391-69EEB31A0561</title>
+ <desc>Created with sketchtool.</desc>
+ <defs></defs>
+ <g id="Add-Tokens" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+ <g id="Add-tokens" transform="translate(-267.000000, -284.000000)" fill="#B8BAC1">
+ <g id="tokensearch" transform="translate(267.000000, 284.000000)">
+ <path d="M28.5322581,2.80645161 C42.4391613,2.80645161 54.1925806,9.22854839 54.2552581,16.8433871 C54.1925806,24.4591613 42.4391613,30.8821935 28.5322581,30.8821935 C14.6253548,30.8821935 2.87193548,24.4600968 2.80925806,16.8443226 C2.87193548,9.22854839 14.6253548,2.80645161 28.5322581,2.80645161 M28.5322581,36.7289677 C15.7432581,36.7289677 4.78125806,31.2975484 3.05154839,24.5012581 C7.70932258,29.9981613 17.2559355,33.6886452 28.5322581,33.6886452 C39.8085806,33.6886452 49.3551935,29.9981613 54.0129677,24.5012581 C52.2832581,31.2975484 41.3212581,36.7289677 28.5322581,36.7289677 M28.5322581,54.2692903 C15.7432581,54.2692903 4.78125806,48.837871 3.05154839,42.0415806 C7.70932258,47.5384839 17.2559355,51.2289677 28.5322581,51.2289677 C33.2237097,51.2289677 37.6083226,50.5844194 41.471871,49.4403226 C42.1379355,49.243871 42.5270968,48.5675161 42.4110968,47.8818065 C42.4045484,47.8453226 42.398,47.8079032 42.3923871,47.7704839 C42.2642258,46.9603548 41.439129,46.458 40.6533226,46.6946774 C37.0180323,47.792 32.8822581,48.4225161 28.5322581,48.4225161 C15.7432581,48.4225161 4.78125806,42.9910968 3.05154839,36.1948065 C7.70932258,41.6917097 17.2559355,45.3821935 28.5322581,45.3821935 C33.3649677,45.3821935 37.8730645,44.6983548 41.8217419,43.4906452 C42.2763871,43.3503226 42.6066129,42.976129 42.7422581,42.5196129 L42.7534839,42.4812581 C43.0752903,41.4082581 42.0733871,40.4063548 41.004129,40.7403226 C37.2846452,41.9040645 33.0225806,42.5757419 28.5322581,42.5757419 C15.7432581,42.5757419 4.78125806,37.1443226 3.05154839,30.3480323 C7.70932258,35.8449355 17.2559355,39.5354194 28.5322581,39.5354194 C39.8085806,39.5354194 49.3551935,35.8449355 54.0129677,30.3480323 L54.0129677,33.5492581 C54.0129677,34.3846452 54.6902581,35.0619355 55.5256452,35.0619355 C56.3610323,35.0619355 57.0383226,34.3902581 57.0392581,33.5558065 C57.0467419,26.4900968 57.0645161,16.9257097 57.0645161,16.905129 C57.0645161,16.8845484 57.0617097,16.8649032 57.0617097,16.8443226 C57.0617097,16.8237419 57.0645161,16.8031613 57.0645161,16.7825806 L57.0598387,16.7825806 C56.9513226,7.36225806 44.4616774,0 28.5322581,0 C12.6028387,0 0.113193548,7.36225806 0.00467741935,16.7825806 L0,16.7825806 C0,16.8031613 0.00280645161,16.8237419 0.00280645161,16.8443226 C0.00280645161,16.8649032 0,16.8845484 0,16.905129 C0,16.9322581 0.00467741935,19.3420645 0.0102903226,22.6293548 L0,22.6293548 C0,22.7154194 0.00841935484,22.7996129 0.0102903226,22.8838065 C0.0140322581,24.5957419 0.0177741935,26.5247097 0.0196451613,28.476129 L0,28.476129 C0,28.650129 0.0130967742,28.8222581 0.0205806452,28.9953226 C0.0243225806,30.828871 0.0280645161,32.6586774 0.0308709677,34.3229032 L0,34.3229032 C0,34.5857742 0.0140322581,34.8467742 0.0318064516,35.1059032 C0.036483871,37.3108387 0.0392903226,39.1406452 0.0411612903,40.1696774 L0,40.1696774 C0,40.4905484 0.0177741935,40.8086129 0.0458387097,41.123871 L0.0495806452,41.2033871 C0.0645483871,41.3699032 0.0935483871,41.5345484 0.116935484,41.700129 C0.130032258,41.7861935 0.137516129,41.8731935 0.152483871,41.9583226 C0.183354839,42.1416774 0.225451613,42.3240968 0.266612903,42.5055806 C0.29,42.6103548 0.308709677,42.7160645 0.334903226,42.8199032 C0.358290323,42.9078387 0.387290323,42.9939032 0.411612903,43.0818387 C2.00006452,48.7134516 8.12841935,53.3160323 16.5777097,55.5705484 C16.6010968,55.5770968 16.6254194,55.5836452 16.6488065,55.5892581 C16.9350645,55.6650323 17.2213226,55.739871 17.5122581,55.8109677 C20.9099355,56.6538387 24.6322258,57.1215806 28.5322581,57.1215806 C32.4322903,57.1215806 36.1545806,56.6538387 39.5522581,55.8109677 C39.8431935,55.739871 40.1294516,55.6650323 40.4157097,55.5892581 C40.4390968,55.5836452 40.4634194,55.5770968 40.4868065,55.5705484 C41.5766452,55.2796129 42.6253226,54.9475161 43.6319032,54.579871 C44.4682258,54.2739677 44.7675806,53.2627097 44.2652258,52.5274194 C44.2437097,52.4956129 44.2212581,52.462871 44.1997419,52.430129 C43.8423871,51.8950323 43.1688387,51.6873548 42.5645161,51.9090645 C38.4998387,53.3955484 33.6624516,54.2692903 28.5322581,54.2692903" id="Fill-1"></path>
+ <path d="M64.3227484,54.3991355 L60.4535871,50.5299742 C61.4526839,49.1566839 61.9522323,47.5345548 61.9522323,45.7880065 C62.1009742,40.5661355 56.8996839,36.4144581 51.4654581,38.2367806 C48.6131677,39.1928452 46.4821355,41.7401677 46.0611677,44.7187484 C45.3530065,49.7460387 49.205329,54.0249419 54.0894903,54.0249419 C55.5872,54.0249419 57.0849097,53.5244581 58.2074903,52.7770065 L62.0766516,56.6452323 C62.6968774,57.2654581 63.7025226,57.2654581 64.3227484,56.6452323 C64.9429742,56.0250065 64.9429742,55.0193613 64.3227484,54.3991355 M48.3484258,45.9124258 C48.3484258,42.7925871 50.9696516,40.1713613 54.0894903,40.1713613 C57.209329,40.1713613 59.7052,42.6681677 59.7052,45.9124258 C59.7052,49.0332 57.209329,51.529071 54.0894903,51.529071 C50.8452323,51.529071 48.3484258,49.0332 48.3484258,45.9124258" id="Fill-3"></path>
+ </g>
+ </g>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 69d549c85..686296329 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -322,7 +322,7 @@ function setupController (initState, initLangCode) {
/**
* A runtime.Port object, as provided by the browser:
- * @link https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/Port
+ * @see https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/Port
* @typedef Port
* @type Object
*/
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index ddf1a9432..555902ddf 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -166,7 +166,7 @@ function documentElementCheck () {
/**
* Checks if the current domain is blacklisted
- *
+ *
* @returns {boolean} {@code true} if the current domain is blacklisted
*/
function blacklistedDomainCheck () {
@@ -175,6 +175,7 @@ function blacklistedDomainCheck () {
'dropbox.com',
'webbyawards.com',
'cdn.shopify.com/s/javascripts/tricorder/xtld-read-only-frame.html',
+ 'adyen.com',
]
var currentUrl = window.location.href
var currentRegex
diff --git a/app/scripts/controllers/address-book.js b/app/scripts/controllers/address-book.js
index c91e6b2e4..4697e074c 100644
--- a/app/scripts/controllers/address-book.js
+++ b/app/scripts/controllers/address-book.js
@@ -13,19 +13,17 @@ class AddressBookController {
* @param {object} opts Overrides the defaults for the initial state of this.store
* @property {array} opts.initState initializes the the state of the AddressBookController. Can contain an
* addressBook property to initialize the addressBook array
- * @param {KeyringController} keyringController (Soon to be deprecated) The keyringController used in the current
- * MetamaskController. Contains the identities used in this AddressBookController.
+ * @property {object} opts.preferencesStore the {@code PreferencesController} store
* @property {object} store The the store of the current users address book
* @property {array} store.addressBook An array of addresses and nicknames. These are set by the user when sending
* to a new address.
*
*/
- constructor (opts = {}, keyringController) {
- const initState = extend({
+ constructor ({initState, preferencesStore}) {
+ this.store = new ObservableStore(extend({
addressBook: [],
- }, opts.initState)
- this.store = new ObservableStore(initState)
- this.keyringController = keyringController
+ }, initState))
+ this._preferencesStore = preferencesStore
}
//
@@ -62,7 +60,7 @@ class AddressBookController {
*/
_addToAddressBook (address, name) {
const addressBook = this._getAddressBook()
- const identities = this._getIdentities()
+ const {identities} = this._preferencesStore.getState()
const addressBookIndex = addressBook.findIndex((element) => { return element.address.toLowerCase() === address.toLowerCase() || element.name === name })
const identitiesIndex = Object.keys(identities).findIndex((element) => { return element.toLowerCase() === address.toLowerCase() })
@@ -95,19 +93,6 @@ class AddressBookController {
_getAddressBook () {
return this.store.getState().addressBook
}
-
- /**
- * Retrieves identities from the keyring controller in order to avoid
- * duplication
- *
- * @deprecated
- * @returns {array} Returns the identies array from the keyringContoller's state
- *
- */
- _getIdentities () {
- return this.keyringController.memStore.getState().identities
- }
-
}
module.exports = AddressBookController
diff --git a/app/scripts/controllers/network/enums.js b/app/scripts/controllers/network/enums.js
index 4f29e301b..9da7f309c 100644
--- a/app/scripts/controllers/network/enums.js
+++ b/app/scripts/controllers/network/enums.js
@@ -13,20 +13,6 @@ const RINKEBY_DISPLAY_NAME = 'Rinkeby'
const KOVAN_DISPLAY_NAME = 'Kovan'
const MAINNET_DISPLAY_NAME = 'Main Ethereum Network'
-const MAINNET_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'
-
-const MAINNET_RPC_URL_BETA = 'https://mainnet.infura.io/metamask2'
-const ROPSTEN_RPC_URL_BETA = 'https://ropsten.infura.io/metamask2'
-const KOVAN_RPC_URL_BETA = 'https://kovan.infura.io/metamask2'
-const RINKEBY_RPC_URL_BETA = 'https://rinkeby.infura.io/metamask2'
-
-const DEFAULT_NETWORK = 'rinkeby'
-const OLD_UI_NETWORK_TYPE = 'network'
-const BETA_UI_NETWORK_TYPE = 'networkBeta'
module.exports = {
ROPSTEN,
@@ -41,16 +27,4 @@ module.exports = {
RINKEBY_DISPLAY_NAME,
KOVAN_DISPLAY_NAME,
MAINNET_DISPLAY_NAME,
- MAINNET_RPC_URL,
- ROPSTEN_RPC_URL,
- KOVAN_RPC_URL,
- RINKEBY_RPC_URL,
- LOCALHOST_RPC_URL,
- MAINNET_RPC_URL_BETA,
- ROPSTEN_RPC_URL_BETA,
- KOVAN_RPC_URL_BETA,
- RINKEBY_RPC_URL_BETA,
- DEFAULT_NETWORK,
- OLD_UI_NETWORK_TYPE,
- BETA_UI_NETWORK_TYPE,
}
diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js
index 2f5b81cd2..93fde7c57 100644
--- a/app/scripts/controllers/network/network.js
+++ b/app/scripts/controllers/network/network.js
@@ -14,52 +14,40 @@ const {
RINKEBY,
KOVAN,
MAINNET,
- OLD_UI_NETWORK_TYPE,
- DEFAULT_NETWORK,
+ LOCALHOST,
} = require('./enums')
-const { getNetworkEndpoints } = require('./util')
+const LOCALHOST_RPC_URL = 'http://localhost:8545'
const INFURA_PROVIDER_TYPES = [ROPSTEN, RINKEBY, KOVAN, MAINNET]
+const env = process.env.METAMASK_ENV
+const METAMASK_DEBUG = process.env.METAMASK_DEBUG
+const testMode = (METAMASK_DEBUG || env === 'test')
+
+const defaultProviderConfig = {
+ type: testMode ? RINKEBY : MAINNET,
+}
+
module.exports = class NetworkController extends EventEmitter {
- constructor (config) {
+ constructor (opts = {}) {
super()
- this._networkEndpointVersion = OLD_UI_NETWORK_TYPE
- this._networkEndpoints = getNetworkEndpoints(OLD_UI_NETWORK_TYPE)
- this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
-
- config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
+ // parse options
+ const providerConfig = opts.provider || defaultProviderConfig
+ // create stores
+ this.providerStore = new ObservableStore(providerConfig)
this.networkStore = new ObservableStore('loading')
- this.providerStore = new ObservableStore(config.provider)
this.store = new ComposedStore({ provider: this.providerStore, network: this.networkStore })
+ // create event emitter proxy
this._proxy = createEventEmitterProxy()
this.on('networkDidChange', this.lookupNetwork)
}
- async setNetworkEndpoints (version) {
- if (version === this._networkEndpointVersion) {
- return
- }
-
- this._networkEndpointVersion = version
- this._networkEndpoints = getNetworkEndpoints(version)
- this._defaultRpc = this._networkEndpoints[DEFAULT_NETWORK]
- const { type } = this.getProviderConfig()
-
- return this.setProviderType(type, true)
- }
-
initializeProvider (_providerParams) {
this._baseProviderParams = _providerParams
const { type, rpcTarget } = this.providerStore.getState()
- // map rpcTarget to rpcUrl
- const opts = {
- type,
- rpcUrl: rpcTarget,
- }
- this._configureProvider(opts)
+ this._configureProvider({ type, rpcTarget })
this._proxy.on('block', this._logBlock.bind(this))
this._proxy.on('error', this.verifyNetwork.bind(this))
this.ethQuery = new EthQuery(this._proxy)
@@ -96,45 +84,27 @@ module.exports = class NetworkController extends EventEmitter {
})
}
- setRpcTarget (rpcUrl) {
- this.providerStore.updateState({
+ setRpcTarget (rpcTarget) {
+ const providerConfig = {
type: 'rpc',
- rpcTarget: rpcUrl,
- })
- this._switchNetwork({ rpcUrl })
- }
-
- getCurrentRpcAddress () {
- const provider = this.getProviderConfig()
- if (!provider) return null
- return this.getRpcAddressForType(provider.type)
- }
-
- async setProviderType (type, forceUpdate = false) {
- assert(type !== 'rpc', `NetworkController.setProviderType - cannot connect by type "rpc"`)
- // skip if type already matches
- if (type === this.getProviderConfig().type && !forceUpdate) {
- return
+ rpcTarget,
}
+ this.providerStore.updateState(providerConfig)
+ this._switchNetwork(providerConfig)
+ }
- const rpcTarget = this.getRpcAddressForType(type)
- assert(rpcTarget, `NetworkController - unknown rpc address for type "${type}"`)
- this.providerStore.updateState({ type, rpcTarget })
- this._switchNetwork({ type })
+ async setProviderType (type) {
+ assert.notEqual(type, 'rpc', `NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`)
+ assert(INFURA_PROVIDER_TYPES.includes(type) || type === LOCALHOST, `NetworkController - Unknown rpc type "${type}"`)
+ const providerConfig = { type }
+ this.providerStore.updateState(providerConfig)
+ this._switchNetwork(providerConfig)
}
getProviderConfig () {
return this.providerStore.getState()
}
- getRpcAddressForType (type, provider = this.getProviderConfig()) {
- if (this._networkEndpoints[type]) {
- return this._networkEndpoints[type]
- }
-
- return provider && provider.rpcTarget ? provider.rpcTarget : this._defaultRpc
- }
-
//
// Private
//
@@ -146,32 +116,27 @@ module.exports = class NetworkController extends EventEmitter {
}
_configureProvider (opts) {
- // type-based rpc endpoints
- const { type } = opts
- if (type) {
- // type-based infura rpc endpoints
- const isInfura = INFURA_PROVIDER_TYPES.includes(type)
- opts.rpcUrl = this.getRpcAddressForType(type)
- if (isInfura) {
- this._configureInfuraProvider(opts)
- // other type-based rpc endpoints
- } else {
- this._configureStandardProvider(opts)
- }
+ const { type, rpcTarget } = opts
+ // infura type-based endpoints
+ const isInfura = INFURA_PROVIDER_TYPES.includes(type)
+ if (isInfura) {
+ this._configureInfuraProvider(opts)
+ // other type-based rpc endpoints
+ } else if (type === LOCALHOST) {
+ this._configureStandardProvider({ rpcUrl: LOCALHOST_RPC_URL })
// url-based rpc endpoints
+ } else if (type === 'rpc'){
+ this._configureStandardProvider({ rpcUrl: rpcTarget })
} else {
- this._configureStandardProvider(opts)
+ throw new Error(`NetworkController - _configureProvider - unknown type "${type}"`)
}
}
- _configureInfuraProvider (opts) {
- log.info('_configureInfuraProvider', opts)
- const infuraProvider = createInfuraProvider({
- network: opts.type,
- })
+ _configureInfuraProvider ({ type }) {
+ log.info('_configureInfuraProvider', type)
+ const infuraProvider = createInfuraProvider({ network: type })
const infuraSubprovider = new SubproviderFromProvider(infuraProvider)
const providerParams = extend(this._baseProviderParams, {
- rpcUrl: opts.rpcUrl,
engineParams: {
pollingInterval: 8000,
blockTrackerProvider: infuraProvider,
diff --git a/app/scripts/controllers/network/util.js b/app/scripts/controllers/network/util.js
index 4f38ccda4..261dae721 100644
--- a/app/scripts/controllers/network/util.js
+++ b/app/scripts/controllers/network/util.js
@@ -3,7 +3,6 @@ const {
RINKEBY,
KOVAN,
MAINNET,
- LOCALHOST,
ROPSTEN_CODE,
RINKEYBY_CODE,
KOVAN_CODE,
@@ -11,17 +10,6 @@ const {
RINKEBY_DISPLAY_NAME,
KOVAN_DISPLAY_NAME,
MAINNET_DISPLAY_NAME,
- MAINNET_RPC_URL,
- ROPSTEN_RPC_URL,
- KOVAN_RPC_URL,
- RINKEBY_RPC_URL,
- LOCALHOST_RPC_URL,
- MAINNET_RPC_URL_BETA,
- ROPSTEN_RPC_URL_BETA,
- KOVAN_RPC_URL_BETA,
- RINKEBY_RPC_URL_BETA,
- OLD_UI_NETWORK_TYPE,
- BETA_UI_NETWORK_TYPE,
} = require('./enums')
const networkToNameMap = {
@@ -34,32 +22,8 @@ const networkToNameMap = {
[KOVAN_CODE]: KOVAN_DISPLAY_NAME,
}
-const networkEndpointsMap = {
- [OLD_UI_NETWORK_TYPE]: {
- [LOCALHOST]: LOCALHOST_RPC_URL,
- [MAINNET]: MAINNET_RPC_URL,
- [ROPSTEN]: ROPSTEN_RPC_URL,
- [KOVAN]: KOVAN_RPC_URL,
- [RINKEBY]: RINKEBY_RPC_URL,
- },
- [BETA_UI_NETWORK_TYPE]: {
- [LOCALHOST]: LOCALHOST_RPC_URL,
- [MAINNET]: MAINNET_RPC_URL_BETA,
- [ROPSTEN]: ROPSTEN_RPC_URL_BETA,
- [KOVAN]: KOVAN_RPC_URL_BETA,
- [RINKEBY]: RINKEBY_RPC_URL_BETA,
- },
-}
-
const getNetworkDisplayName = key => networkToNameMap[key]
-const getNetworkEndpoints = (networkType = OLD_UI_NETWORK_TYPE) => {
- return {
- ...networkEndpointsMap[networkType],
- }
-}
-
module.exports = {
getNetworkDisplayName,
- getNetworkEndpoints,
}
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index 1d3308d36..a4ff1207e 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -27,6 +27,7 @@ class PreferencesController {
useBlockie: false,
featureFlags: {},
currentLocale: opts.initLangCode,
+ identities: {},
}, opts.initState)
this.store = new ObservableStore(initState)
}
@@ -62,6 +63,16 @@ class PreferencesController {
this.store.updateState({ currentLocale: key })
}
+ setAddresses (addresses) {
+ const oldIdentities = this.store.getState().identities
+ const identities = addresses.reduce((ids, address, index) => {
+ const oldId = oldIdentities[address] || {}
+ ids[address] = {name: `Account ${index + 1}`, address, ...oldId}
+ return ids
+ }, {})
+ this.store.updateState({ identities })
+ }
+
/**
* Setter for the `selectedAddress` property
*
@@ -156,6 +167,21 @@ class PreferencesController {
}
/**
+ * Sets a custom label for an account
+ * @param {string} account the account to set a label for
+ * @param {string} label the custom label for the account
+ * @return {Promise<string>}
+ */
+ setAccountLabel (account, label) {
+ const address = normalizeAddress(account)
+ const {identities} = this.store.getState()
+ identities[address] = identities[address] || {}
+ identities[address].name = label
+ this.store.updateState({ identities })
+ return Promise.resolve(label)
+ }
+
+ /**
* Gets an updated rpc list from this.addToFrequentRpcList() and sets the `frequentRpcList` to this update list.
*
* @param {string} _url The the new rpc url to add to the updated list
@@ -189,8 +215,8 @@ class PreferencesController {
* The returned list will have a max length of 2. If the _url currently exists it the list, it will be moved to the
* end of the list. The current list is modified and returned as a promise.
*
- * @param {string} _url The rpc url to add to the frequentRpcList.
- * @returns {Promise<array>} The updated frequentRpcList.
+ * @param {string} _url The rpc url to add to the frequentRpcList.
+ * @returns {Promise<array>} The updated frequentRpcList.
*
*/
addToFrequentRpcList (_url) {
diff --git a/app/scripts/controllers/recent-blocks.js b/app/scripts/controllers/recent-blocks.js
index 1377c1ba9..033ef1d7e 100644
--- a/app/scripts/controllers/recent-blocks.js
+++ b/app/scripts/controllers/recent-blocks.js
@@ -119,29 +119,21 @@ class RecentBlocksController {
*/
async backfill() {
this.blockTracker.once('block', async (block) => {
- let blockNum = block.number
- let recentBlocks
- let state = this.store.getState()
- recentBlocks = state.recentBlocks
-
- while (recentBlocks.length < this.historyLength) {
+ const currentBlockNumber = Number.parseInt(block.number, 16)
+ const blocksToFetch = Math.min(currentBlockNumber, this.historyLength)
+ const prevBlockNumber = currentBlockNumber - 1
+ const targetBlockNumbers = Array(blocksToFetch).fill().map((_, index) => prevBlockNumber - index)
+ await Promise.all(targetBlockNumbers.map(async (targetBlockNumber) => {
try {
- let blockNumBn = new BN(blockNum.substr(2), 16)
- const newNum = blockNumBn.subn(1).toString(10)
- const newBlock = await this.getBlockByNumber(newNum)
+ const newBlock = await this.getBlockByNumber(targetBlockNumber)
if (newBlock) {
this.backfillBlock(newBlock)
- blockNum = newBlock.number
}
-
- state = this.store.getState()
- recentBlocks = state.recentBlocks
} catch (e) {
log.error(e)
}
- await this.wait()
- }
+ }))
})
}
diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js
index 3886db104..541f1db73 100644
--- a/app/scripts/controllers/transactions/index.js
+++ b/app/scripts/controllers/transactions/index.js
@@ -112,21 +112,6 @@ class TransactionController extends EventEmitter {
}
/**
- Check if a txMeta in the list with the same nonce has been confirmed in a block
- if the txParams dont have a nonce will return false
- @returns {boolean} whether the nonce has been used in a transaction confirmed in a block
- @param {object} txMeta - the txMeta object
- */
- async isNonceTaken (txMeta) {
- const { from, nonce } = txMeta.txParams
- if ('nonce' in txMeta.txParams) {
- const sameNonceTxList = this.txStateManager.getFilteredTxList({from, nonce, status: 'confirmed'})
- return (sameNonceTxList.length >= 1)
- }
- return false
- }
-
- /**
add a new unapproved transaction to the pipeline
@returns {Promise<string>} the hash of the transaction after being submitted to the network
diff --git a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
index 59a4b562c..4562568e9 100644
--- a/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
+++ b/app/scripts/controllers/transactions/lib/tx-state-history-helper.js
@@ -25,26 +25,31 @@ function migrateFromSnapshotsToDiffs (longHistory) {
}
/**
- generates an array of history objects sense the previous state.
- The object has the keys opp(the operation preformed),
- path(the key and if a nested object then each key will be seperated with a `/`)
- value
- with the first entry having the note
+ Generates an array of history objects sense the previous state.
+ The object has the keys
+ op (the operation performed),
+ path (the key and if a nested object then each key will be seperated with a `/`)
+ value
+ with the first entry having the note and a timestamp when the change took place
@param previousState {object} - the previous state of the object
@param newState {object} - the update object
@param note {string} - a optional note for the state change
- @reurns {array}
+ @returns {array}
*/
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
+ if (entry[0]) {
+ if (note) entry[0].note = note
+
+ entry[0].timestamp = Date.now()
+ }
return entry
}
/**
Recovers previous txMeta state obj
- @return {object}
+ @returns {object}
*/
function replayHistory (_shortHistory) {
const shortHistory = clone(_shortHistory)
diff --git a/app/scripts/controllers/transactions/tx-state-manager.js b/app/scripts/controllers/transactions/tx-state-manager.js
index 380214c1d..00e837571 100644
--- a/app/scripts/controllers/transactions/tx-state-manager.js
+++ b/app/scripts/controllers/transactions/tx-state-manager.js
@@ -158,7 +158,7 @@ class TransactionStateManager extends EventEmitter {
/**
updates the txMeta in the list and adds a history entry
@param txMeta {Object} - the txMeta to update
- @param [note] {string} - a not about the update for history
+ @param [note] {string} - a note about the update for history
*/
updateTx (txMeta, note) {
// validate txParams
diff --git a/app/scripts/first-time-state.js b/app/scripts/first-time-state.js
index c49d89288..13119bc04 100644
--- a/app/scripts/first-time-state.js
+++ b/app/scripts/first-time-state.js
@@ -1,7 +1,3 @@
-// test and development environment variables
-const env = process.env.METAMASK_ENV
-const METAMASK_DEBUG = process.env.METAMASK_DEBUG
-const { DEFAULT_NETWORK, MAINNET } = require('./controllers/network/enums')
/**
* @typedef {Object} FirstTimeState
@@ -14,11 +10,6 @@ const { DEFAULT_NETWORK, MAINNET } = require('./controllers/network/enums')
*/
const initialState = {
config: {},
- NetworkController: {
- provider: {
- type: (METAMASK_DEBUG || env === 'test') ? DEFAULT_NETWORK : MAINNET,
- },
- },
}
module.exports = initialState
diff --git a/app/scripts/lib/createErrorMiddleware.js b/app/scripts/lib/createErrorMiddleware.js
new file mode 100644
index 000000000..baed99e45
--- /dev/null
+++ b/app/scripts/lib/createErrorMiddleware.js
@@ -0,0 +1,66 @@
+const log = require('loglevel')
+
+/**
+ * JSON-RPC error object
+ *
+ * @typedef {Object} RpcError
+ * @property {number} code - Indicates the error type that occurred
+ * @property {Object} [data] - Contains additional information about the error
+ * @property {string} [message] - Short description of the error
+ */
+
+/**
+ * Middleware configuration object
+ *
+ * @typedef {Object} MiddlewareConfig
+ * @property {boolean} [override] - Use RPC_ERRORS message in place of provider message
+ */
+
+/**
+ * Map of standard and non-standard RPC error codes to messages
+ */
+const RPC_ERRORS = {
+ 1: 'An unauthorized action was attempted.',
+ 2: 'A disallowed action was attempted.',
+ 3: 'An execution error occurred.',
+ [-32600]: 'The JSON sent is not a valid Request object.',
+ [-32601]: 'The method does not exist / is not available.',
+ [-32602]: 'Invalid method parameter(s).',
+ [-32603]: 'Internal JSON-RPC error.',
+ [-32700]: 'Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.',
+ internal: 'Internal server error.',
+ unknown: 'Unknown JSON-RPC error.',
+}
+
+/**
+ * Modifies a JSON-RPC error object in-place to add a human-readable message,
+ * optionally overriding any provider-supplied message
+ *
+ * @param {RpcError} error - JSON-RPC error object
+ * @param {boolean} override - Use RPC_ERRORS message in place of provider message
+ */
+function sanitizeRPCError (error, override) {
+ if (error.message && !override) { return error }
+ const message = error.code > -31099 && error.code < -32100 ? RPC_ERRORS.internal : RPC_ERRORS[error.code]
+ error.message = message || RPC_ERRORS.unknown
+}
+
+/**
+ * json-rpc-engine middleware that both logs standard and non-standard error
+ * messages and ends middleware stack traversal if an error is encountered
+ *
+ * @param {MiddlewareConfig} [config={override:true}] - Middleware configuration
+ * @returns {Function} json-rpc-engine middleware function
+ */
+function createErrorMiddleware ({ override = true } = {}) {
+ return (req, res, next) => {
+ next(done => {
+ const { error } = res
+ if (!error) { return done() }
+ sanitizeRPCError(error)
+ log.error(`MetaMask - RPC Error: ${error.message}`, error)
+ })
+ }
+}
+
+module.exports = createErrorMiddleware \ No newline at end of file
diff --git a/app/scripts/lib/inpage-provider.js b/app/scripts/lib/inpage-provider.js
index 99cc5d2cf..4e65f0a23 100644
--- a/app/scripts/lib/inpage-provider.js
+++ b/app/scripts/lib/inpage-provider.js
@@ -1,5 +1,6 @@
const pump = require('pump')
const RpcEngine = require('json-rpc-engine')
+const createErrorMiddleware = require('./createErrorMiddleware')
const createIdRemapMiddleware = require('json-rpc-engine/src/idRemapMiddleware')
const createStreamMiddleware = require('json-rpc-middleware-stream')
const LocalStorageStore = require('obs-store')
@@ -44,6 +45,7 @@ function MetamaskInpageProvider (connectionStream) {
// handle sendAsync requests via dapp-side rpc engine
const rpcEngine = new RpcEngine()
rpcEngine.push(createIdRemapMiddleware())
+ rpcEngine.push(createErrorMiddleware())
rpcEngine.push(streamMiddleware)
self.rpcEngine = rpcEngine
}
diff --git a/app/scripts/lib/setupRaven.js b/app/scripts/lib/setupRaven.js
index b1b67f771..d164827ab 100644
--- a/app/scripts/lib/setupRaven.js
+++ b/app/scripts/lib/setupRaven.js
@@ -25,7 +25,7 @@ function setupRaven(opts) {
const report = opts.data
try {
// handle error-like non-error exceptions
- nonErrorException(report)
+ rewriteErrorLikeExceptions(report)
// simplify certain complex error messages (e.g. Ethjs)
simplifyErrorMessages(report)
// modify report urls
@@ -42,27 +42,35 @@ function setupRaven(opts) {
return Raven
}
-function nonErrorException(report) {
- // handle errors that lost their error-ness in serialization
- if (report.message.includes('Non-Error exception captured with keys: message')) {
- if (!(report.extra && report.extra.__serialized__)) return
- report.message = `Non-Error Exception: ${report.extra.__serialized__.message}`
- }
+function rewriteErrorLikeExceptions(report) {
+ // handle errors that lost their error-ness in serialization (e.g. dnode)
+ rewriteErrorMessages(report, (errorMessage) => {
+ if (!errorMessage.includes('Non-Error exception captured with keys:')) return errorMessage
+ if (!(report.extra && report.extra.__serialized__ && report.extra.__serialized__.message)) return errorMessage
+ return `Non-Error Exception: ${report.extra.__serialized__.message}`
+ })
}
function simplifyErrorMessages(report) {
+ rewriteErrorMessages(report, (errorMessage) => {
+ // simplify ethjs error messages
+ errorMessage = extractEthjsErrorMessage(errorMessage)
+ // simplify 'Transaction Failed: known transaction'
+ if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) {
+ // cut the hash from the error message
+ errorMessage = 'Transaction Failed: known transaction'
+ }
+ return errorMessage
+ })
+}
+
+function rewriteErrorMessages(report, rewriteFn) {
+ // rewrite top level message
+ report.message = rewriteFn(report.message)
+ // rewrite each exception message
if (report.exception && report.exception.values) {
report.exception.values.forEach(item => {
- let errorMessage = item.value
- // simplify ethjs error messages
- errorMessage = extractEthjsErrorMessage(errorMessage)
- // simplify 'Transaction Failed: known transaction'
- if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) {
- // cut the hash from the error message
- errorMessage = 'Transaction Failed: known transaction'
- }
- // finalize
- item.value = errorMessage
+ item.value = rewriteFn(item.value)
})
}
}
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index a90acb4d5..1b1d26886 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -144,7 +144,8 @@ module.exports = class MetamaskController extends EventEmitter {
// address book controller
this.addressBookController = new AddressBookController({
initState: initState.AddressBookController,
- }, this.keyringController)
+ preferencesStore: this.preferencesController.store,
+ })
// tx mgmt
this.txController = new TransactionController({
@@ -355,7 +356,6 @@ module.exports = class MetamaskController extends EventEmitter {
submitPassword: nodeify(keyringController.submitPassword, keyringController),
// network management
- setNetworkEndpoints: nodeify(networkController.setNetworkEndpoints, networkController),
setProviderType: nodeify(networkController.setProviderType, networkController),
setCustomRpc: nodeify(this.setCustomRpc, this),
@@ -364,6 +364,7 @@ module.exports = class MetamaskController extends EventEmitter {
addToken: nodeify(preferencesController.addToken, preferencesController),
removeToken: nodeify(preferencesController.removeToken, preferencesController),
setCurrentAccountTab: nodeify(preferencesController.setCurrentAccountTab, preferencesController),
+ setAccountLabel: nodeify(preferencesController.setAccountLabel, preferencesController),
setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
// AddressController
@@ -374,7 +375,6 @@ module.exports = class MetamaskController extends EventEmitter {
createNewVaultAndKeychain: nodeify(this.createNewVaultAndKeychain, this),
createNewVaultAndRestore: nodeify(this.createNewVaultAndRestore, this),
addNewKeyring: nodeify(keyringController.addNewKeyring, keyringController),
- saveAccountLabel: nodeify(keyringController.saveAccountLabel, keyringController),
exportAccount: nodeify(keyringController.exportAccount, keyringController),
// txController
@@ -382,7 +382,7 @@ module.exports = class MetamaskController extends EventEmitter {
updateTransaction: nodeify(txController.updateTransaction, txController),
updateAndApproveTransaction: nodeify(txController.updateAndApproveTransaction, txController),
retryTransaction: nodeify(this.retryTransaction, this),
- isNonceTaken: nodeify(txController.isNonceTaken, txController),
+ getFilteredTxList: nodeify(txController.getFilteredTxList, txController),
// messageManager
signMessage: nodeify(this.signMessage, this),
@@ -434,7 +434,9 @@ module.exports = class MetamaskController extends EventEmitter {
} else {
vault = await this.keyringController.createNewVaultAndKeychain(password)
- this.selectFirstIdentity(vault)
+ const accounts = await this.keyringController.getAccounts()
+ this.preferencesController.setAddresses(accounts)
+ this.selectFirstIdentity()
}
release()
} catch (err) {
@@ -454,7 +456,9 @@ module.exports = class MetamaskController extends EventEmitter {
const release = await this.createVaultMutex.acquire()
try {
const vault = await this.keyringController.createNewVaultAndRestore(password, seed)
- this.selectFirstIdentity(vault)
+ const accounts = await this.keyringController.getAccounts()
+ this.preferencesController.setAddresses(accounts)
+ this.selectFirstIdentity()
release()
return vault
} catch (err) {
@@ -472,12 +476,10 @@ module.exports = class MetamaskController extends EventEmitter {
*/
/**
- * Retrieves the first Identiy from the passed Vault and selects the related address
- *
- * @param {} vault
+ * Sets the first address in the state to the selected address
*/
- selectFirstIdentity (vault) {
- const { identities } = vault
+ selectFirstIdentity () {
+ const { identities } = this.preferencesController.store.getState()
const address = Object.keys(identities)[0]
this.preferencesController.setSelectedAddress(address)
}
@@ -503,13 +505,15 @@ module.exports = class MetamaskController extends EventEmitter {
await this.verifySeedPhrase()
+ this.preferencesController.setAddresses(newAccounts)
newAccounts.forEach((address) => {
if (!oldAccounts.includes(address)) {
this.preferencesController.setSelectedAddress(address)
}
})
- return keyState
+ const {identities} = this.preferencesController.store.getState()
+ return {...keyState, identities}
}
/**
diff --git a/app/scripts/migrations/026.js b/app/scripts/migrations/026.js
new file mode 100644
index 000000000..1b8a91a45
--- /dev/null
+++ b/app/scripts/migrations/026.js
@@ -0,0 +1,47 @@
+const version = 26
+
+/*
+
+This migration moves the identities stored in the KeyringController
+ into the PreferencesController
+
+*/
+
+const clone = require('clone')
+
+module.exports = {
+ version,
+ migrate (originalVersionedData) {
+ const versionedData = clone(originalVersionedData)
+ versionedData.meta.version = version
+ try {
+ const state = versionedData.data
+ versionedData.data = transformState(state)
+ } catch (err) {
+ console.warn(`MetaMask Migration #${version}` + err.stack)
+ return Promise.reject(err)
+ }
+ return Promise.resolve(versionedData)
+ },
+}
+
+function transformState (state) {
+ if (!state.KeyringController || !state.PreferencesController) {
+ return
+ }
+
+ if (!state.KeyringController.walletNicknames) {
+ return state
+ }
+
+ state.PreferencesController.identities = Object.keys(state.KeyringController.walletNicknames)
+ .reduce((identities, address) => {
+ identities[address] = {
+ name: state.KeyringController.walletNicknames[address],
+ address,
+ }
+ return identities
+ }, {})
+ delete state.KeyringController.walletNicknames
+ return state
+}
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 6c4a51b32..04d90bfff 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -36,4 +36,5 @@ module.exports = [
require('./023'),
require('./024'),
require('./025'),
+ require('./026'),
]