aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts
diff options
context:
space:
mode:
authorDan Finlay <dan@danfinlay.com>2018-03-07 06:59:09 +0800
committerDan Finlay <dan@danfinlay.com>2018-03-07 06:59:09 +0800
commit423f084cb47d84e2e9063a6567454f83592f424b (patch)
treebc2f3040cd76765fa27bbfc0e3913cf5e466c063 /app/scripts
parent8ba64c657ff801425c06db166e2c9a06289047de (diff)
parent303801d2768a264a27a51916e5debf778739ee0c (diff)
downloadtangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar.gz
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar.bz2
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar.lz
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar.xz
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.tar.zst
tangerine-wallet-browser-423f084cb47d84e2e9063a6567454f83592f424b.zip
Merge branch 'master' into i3076-UseStorageLocalInstead
Diffstat (limited to 'app/scripts')
-rw-r--r--app/scripts/background.js33
-rw-r--r--app/scripts/config.js22
-rw-r--r--app/scripts/controllers/network.js40
-rw-r--r--app/scripts/controllers/preferences.js37
-rw-r--r--app/scripts/controllers/transactions.js8
-rw-r--r--app/scripts/edge-encryptor.js69
-rw-r--r--app/scripts/lib/config-manager.js11
-rw-r--r--app/scripts/lib/environment-type.js10
-rw-r--r--app/scripts/lib/is-popup-or-notification.js5
-rw-r--r--app/scripts/lib/nonce-tracker.js2
-rw-r--r--app/scripts/lib/notification-manager.js2
-rw-r--r--app/scripts/lib/reportFailedTxToSentry.js38
-rw-r--r--app/scripts/lib/setupMetamaskMeshMetrics.js9
-rw-r--r--app/scripts/lib/setupRaven.js (renamed from app/scripts/setupRaven.js)2
-rw-r--r--app/scripts/lib/tx-gas-utils.js5
-rw-r--r--app/scripts/lib/tx-state-manager.js11
-rw-r--r--app/scripts/metamask-controller.js52
-rw-r--r--app/scripts/migrations/021.js34
-rw-r--r--app/scripts/migrations/index.js1
-rw-r--r--app/scripts/platforms/extension.js5
-rw-r--r--app/scripts/popup-core.js2
-rw-r--r--app/scripts/popup.js31
22 files changed, 397 insertions, 32 deletions
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 07a260a4f..464330708 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -15,7 +15,11 @@ const PortStream = require('./lib/port-stream.js')
const NotificationManager = require('./lib/notification-manager.js')
const MetamaskController = require('./metamask-controller')
const firstTimeState = require('./first-time-state')
-const setupRaven = require('./setupRaven')
+const setupRaven = require('./lib/setupRaven')
+const reportFailedTxToSentry = require('./lib/reportFailedTxToSentry')
+const setupMetamaskMeshMetrics = require('./lib/setupMetamaskMeshMetrics')
+const EdgeEncryptor = require('./edge-encryptor')
+
const STORAGE_KEY = 'metamask-config'
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
@@ -31,7 +35,14 @@ global.METAMASK_NOTIFIER = notificationManager
const release = platform.getVersion()
const raven = setupRaven({ release })
+// browser check if it is Edge - https://stackoverflow.com/questions/9847580/how-to-detect-safari-chrome-ie-firefox-and-opera-browser
+// Internet Explorer 6-11
+const isIE = !!document.documentMode
+// Edge 20+
+const isEdge = !isIE && !!window.StyleMedia
+
let popupIsOpen = false
+let openMetamaskTabsIDs = {}
// state persistence
const diskStore = new LocalStorageStore({ storageKey: STORAGE_KEY })
@@ -41,6 +52,9 @@ let versionedData
// initialization flow
initialize().catch(log.error)
+// setup metamask mesh testing container
+setupMetamaskMeshMetrics()
+
async function initialize () {
const initState = await loadStateFromPersistence()
await setupController(initState)
@@ -98,6 +112,7 @@ function setupController (initState) {
initState,
// platform specific api
platform,
+ encryptor: isEdge ? new EdgeEncryptor() : undefined,
})
global.metamaskController = controller
@@ -105,10 +120,7 @@ function setupController (initState) {
controller.txController.on(`tx:status-update`, (txId, status) => {
if (status !== 'failed') return
const txMeta = controller.txController.txStateManager.getTx(txId)
- raven.captureMessage('Transaction Failed', {
- // "extra" key is required by Sentry
- extra: txMeta,
- })
+ reportFailedTxToSentry({ raven, txMeta })
})
// setup state persistence
@@ -151,9 +163,15 @@ function setupController (initState) {
popupIsOpen = popupIsOpen || (remotePort.name === 'popup')
controller.setupTrustedCommunication(portStream, 'MetaMask')
// record popup as closed
+ if (remotePort.sender.url.match(/home.html$/)) {
+ openMetamaskTabsIDs[remotePort.sender.tab.id] = true
+ }
if (remotePort.name === 'popup') {
endOfStream(portStream, () => {
popupIsOpen = false
+ if (remotePort.sender.url.match(/home.html$/)) {
+ openMetamaskTabsIDs[remotePort.sender.tab.id] = false
+ }
})
}
} else {
@@ -196,7 +214,10 @@ function setupController (initState) {
// popup trigger
function triggerUi () {
- if (!popupIsOpen) notificationManager.showPopup()
+ extension.tabs.query({ active: true }, (tabs) => {
+ const currentlyActiveMetamaskTab = tabs.find(tab => openMetamaskTabsIDs[tab.id])
+ if (!popupIsOpen && !currentlyActiveMetamaskTab) notificationManager.showPopup()
+ })
}
// On first install, open a window to MetaMask website to how-it-works.
diff --git a/app/scripts/config.js b/app/scripts/config.js
index 1d4ff7c0d..74c5b576e 100644
--- a/app/scripts/config.js
+++ b/app/scripts/config.js
@@ -4,6 +4,15 @@ 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 MAINET_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_RPC = 'rinkeby'
+const OLD_UI_NETWORK_TYPE = 'network'
+const BETA_UI_NETWORK_TYPE = 'networkBeta'
+
global.METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
module.exports = {
@@ -14,9 +23,22 @@ module.exports = {
kovan: KOVAN_RPC_URL,
rinkeby: RINKEBY_RPC_URL,
},
+ // Used for beta UI
+ networkBeta: {
+ localhost: LOCALHOST_RPC_URL,
+ mainnet: MAINET_RPC_URL_BETA,
+ ropsten: ROPSTEN_RPC_URL_BETA,
+ kovan: KOVAN_RPC_URL_BETA,
+ rinkeby: RINKEBY_RPC_URL_BETA,
+ },
networkNames: {
3: 'Ropsten',
4: 'Rinkeby',
42: 'Kovan',
},
+ enums: {
+ DEFAULT_RPC,
+ OLD_UI_NETWORK_TYPE,
+ BETA_UI_NETWORK_TYPE,
+ },
}
diff --git a/app/scripts/controllers/network.js b/app/scripts/controllers/network.js
index a1db8946a..617456cd7 100644
--- a/app/scripts/controllers/network.js
+++ b/app/scripts/controllers/network.js
@@ -8,14 +8,19 @@ const ComposedStore = require('obs-store/lib/composed')
const extend = require('xtend')
const EthQuery = require('eth-query')
const createEventEmitterProxy = require('../lib/events-proxy.js')
-const RPC_ADDRESS_LIST = require('../config.js').network
-const DEFAULT_RPC = RPC_ADDRESS_LIST['rinkeby']
+const networkConfig = require('../config.js')
+const { OLD_UI_NETWORK_TYPE, DEFAULT_RPC } = networkConfig.enums
const INFURA_PROVIDER_TYPES = ['ropsten', 'rinkeby', 'kovan', 'mainnet']
module.exports = class NetworkController extends EventEmitter {
constructor (config) {
super()
+
+ this._networkEndpointVersion = OLD_UI_NETWORK_TYPE
+ this._networkEndpoints = this.getNetworkEndpoints(OLD_UI_NETWORK_TYPE)
+ this._defaultRpc = this._networkEndpoints[DEFAULT_RPC]
+
config.provider.rpcTarget = this.getRpcAddressForType(config.provider.type, config.provider)
this.networkStore = new ObservableStore('loading')
this.providerStore = new ObservableStore(config.provider)
@@ -25,6 +30,23 @@ module.exports = class NetworkController extends EventEmitter {
this.on('networkDidChange', this.lookupNetwork)
}
+ async setNetworkEndpoints (version) {
+ if (version === this._networkEndpointVersion) {
+ return
+ }
+
+ this._networkEndpointVersion = version
+ this._networkEndpoints = this.getNetworkEndpoints(version)
+ this._defaultRpc = this._networkEndpoints[DEFAULT_RPC]
+ const { type } = this.getProviderConfig()
+
+ return this.setProviderType(type, true)
+ }
+
+ getNetworkEndpoints (version = OLD_UI_NETWORK_TYPE) {
+ return networkConfig[version]
+ }
+
initializeProvider (_providerParams) {
this._baseProviderParams = _providerParams
const { type, rpcTarget } = this.providerStore.getState()
@@ -84,10 +106,13 @@ module.exports = class NetworkController extends EventEmitter {
return this.getRpcAddressForType(provider.type)
}
- async setProviderType (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) return
+ if (type === this.getProviderConfig().type && !forceUpdate) {
+ return
+ }
+
const rpcTarget = this.getRpcAddressForType(type)
assert(rpcTarget, `NetworkController - unknown rpc address for type "${type}"`)
this.providerStore.updateState({ type, rpcTarget })
@@ -99,8 +124,11 @@ module.exports = class NetworkController extends EventEmitter {
}
getRpcAddressForType (type, provider = this.getProviderConfig()) {
- if (RPC_ADDRESS_LIST[type]) return RPC_ADDRESS_LIST[type]
- return provider && provider.rpcTarget ? provider.rpcTarget : DEFAULT_RPC
+ if (this._networkEndpoints[type]) {
+ return this._networkEndpoints[type]
+ }
+
+ return provider && provider.rpcTarget ? provider.rpcTarget : this._defaultRpc
}
//
diff --git a/app/scripts/controllers/preferences.js b/app/scripts/controllers/preferences.js
index c42f47037..39d15fd83 100644
--- a/app/scripts/controllers/preferences.js
+++ b/app/scripts/controllers/preferences.js
@@ -9,11 +9,21 @@ class PreferencesController {
frequentRpcList: [],
currentAccountTab: 'history',
tokens: [],
+ useBlockie: false,
+ featureFlags: {},
}, opts.initState)
this.store = new ObservableStore(initState)
}
// PUBLIC METHODS
+ setUseBlockie (val) {
+ this.store.updateState({ useBlockie: val })
+ }
+
+ getUseBlockie () {
+ return this.store.getState().useBlockie
+ }
+
setSelectedAddress (_address) {
return new Promise((resolve, reject) => {
const address = normalizeAddress(_address)
@@ -43,6 +53,17 @@ class PreferencesController {
}
this.store.updateState({ tokens })
+
+ return Promise.resolve(tokens)
+ }
+
+ removeToken (rawAddress) {
+ const tokens = this.store.getState().tokens
+
+ const updatedTokens = tokens.filter(token => token.address !== rawAddress)
+
+ this.store.updateState({ tokens: updatedTokens })
+ return Promise.resolve(updatedTokens)
}
getTokens () {
@@ -82,6 +103,22 @@ class PreferencesController {
getFrequentRpcList () {
return this.store.getState().frequentRpcList
}
+
+ setFeatureFlag (feature, activated) {
+ const currentFeatureFlags = this.store.getState().featureFlags
+ const updatedFeatureFlags = {
+ ...currentFeatureFlags,
+ [feature]: activated,
+ }
+
+ this.store.updateState({ featureFlags: updatedFeatureFlags })
+
+ return Promise.resolve(updatedFeatureFlags)
+ }
+
+ getFeatureFlags () {
+ return this.store.getState().featureFlags
+ }
//
// PRIVATE METHODS
//
diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js
index 9c3618e60..ef5578d5a 100644
--- a/app/scripts/controllers/transactions.js
+++ b/app/scripts/controllers/transactions.js
@@ -152,6 +152,10 @@ module.exports = class TransactionController extends EventEmitter {
}
}
+ wipeTransactions (address) {
+ this.txStateManager.wipeTransactions(address)
+ }
+
// Adds a tx to the txlist
addTx (txMeta) {
this.txStateManager.addTx(txMeta)
@@ -229,6 +233,10 @@ module.exports = class TransactionController extends EventEmitter {
this.txStateManager.updateTx(txMeta, 'retryTransaction: manual retry')
}
+ async updateTransaction (txMeta) {
+ this.txStateManager.updateTx(txMeta, 'confTx: user updated transaction')
+ }
+
async updateAndApproveTransaction (txMeta) {
this.txStateManager.updateTx(txMeta, 'confTx: user approved transaction')
await this.approveTransaction(txMeta.id)
diff --git a/app/scripts/edge-encryptor.js b/app/scripts/edge-encryptor.js
new file mode 100644
index 000000000..24c0c93a8
--- /dev/null
+++ b/app/scripts/edge-encryptor.js
@@ -0,0 +1,69 @@
+const asmcrypto = require('asmcrypto.js')
+const Unibabel = require('browserify-unibabel')
+
+class EdgeEncryptor {
+
+ encrypt (password, dataObject) {
+
+ var salt = this._generateSalt()
+ return this._keyFromPassword(password, salt)
+ .then(function (key) {
+
+ var data = JSON.stringify(dataObject)
+ var dataBuffer = Unibabel.utf8ToBuffer(data)
+ var vector = global.crypto.getRandomValues(new Uint8Array(16))
+ var resultbuffer = asmcrypto.AES_GCM.encrypt(dataBuffer, key, vector)
+
+ var buffer = new Uint8Array(resultbuffer)
+ var vectorStr = Unibabel.bufferToBase64(vector)
+ var vaultStr = Unibabel.bufferToBase64(buffer)
+ return JSON.stringify({
+ data: vaultStr,
+ iv: vectorStr,
+ salt: salt,
+ })
+ })
+ }
+
+ decrypt (password, text) {
+
+ const payload = JSON.parse(text)
+ const salt = payload.salt
+ return this._keyFromPassword(password, salt)
+ .then(function (key) {
+ const encryptedData = Unibabel.base64ToBuffer(payload.data)
+ const vector = Unibabel.base64ToBuffer(payload.iv)
+ return new Promise((resolve, reject) => {
+ var result
+ try {
+ result = asmcrypto.AES_GCM.decrypt(encryptedData, key, vector)
+ } catch (err) {
+ return reject(new Error('Incorrect password'))
+ }
+ const decryptedData = new Uint8Array(result)
+ const decryptedStr = Unibabel.bufferToUtf8(decryptedData)
+ const decryptedObj = JSON.parse(decryptedStr)
+ resolve(decryptedObj)
+ })
+ })
+ }
+
+ _keyFromPassword (password, salt) {
+
+ var passBuffer = Unibabel.utf8ToBuffer(password)
+ var saltBuffer = Unibabel.base64ToBuffer(salt)
+ return new Promise((resolve) => {
+ var key = asmcrypto.PBKDF2_HMAC_SHA256.bytes(passBuffer, saltBuffer, 10000)
+ resolve(key)
+ })
+ }
+
+ _generateSalt (byteCount = 32) {
+ var view = new Uint8Array(byteCount)
+ global.crypto.getRandomValues(view)
+ var b64encoded = btoa(String.fromCharCode.apply(null, view))
+ return b64encoded
+ }
+}
+
+module.exports = EdgeEncryptor
diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js
index 9c0dffe9c..34b603b96 100644
--- a/app/scripts/lib/config-manager.js
+++ b/app/scripts/lib/config-manager.js
@@ -42,6 +42,17 @@ ConfigManager.prototype.getData = function () {
return this.store.getState()
}
+ConfigManager.prototype.setPasswordForgotten = function (passwordForgottenState) {
+ const data = this.getData()
+ data.forgottenPassword = passwordForgottenState
+ this.setData(data)
+}
+
+ConfigManager.prototype.getPasswordForgotten = function (passwordForgottenState) {
+ const data = this.getData()
+ return data.forgottenPassword
+}
+
ConfigManager.prototype.setWallet = function (wallet) {
var data = this.getData()
data.wallet = wallet
diff --git a/app/scripts/lib/environment-type.js b/app/scripts/lib/environment-type.js
new file mode 100644
index 000000000..7966926eb
--- /dev/null
+++ b/app/scripts/lib/environment-type.js
@@ -0,0 +1,10 @@
+module.exports = function environmentType () {
+ const url = window.location.href
+ if (url.match(/popup.html$/)) {
+ return 'popup'
+ } else if (url.match(/home.html$/)) {
+ return 'responsive'
+ } else {
+ return 'notification'
+ }
+}
diff --git a/app/scripts/lib/is-popup-or-notification.js b/app/scripts/lib/is-popup-or-notification.js
index 693fa8751..e2999411f 100644
--- a/app/scripts/lib/is-popup-or-notification.js
+++ b/app/scripts/lib/is-popup-or-notification.js
@@ -1,6 +1,9 @@
module.exports = function isPopupOrNotification () {
const url = window.location.href
- if (url.match(/popup.html$/)) {
+ // if (url.match(/popup.html$/) || url.match(/home.html$/)) {
+ // Below regexes needed for feature toggles (e.g. see line ~340 in ui/app/app.js)
+ // Revert below regexes to above commented out regexes before merge to master
+ if (url.match(/popup.html(?:\?.+)*$/) || url.match(/home.html(?:\?.+)*$/)) {
return 'popup'
} else {
return 'notification'
diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js
index 0029ac953..ed9dd3f11 100644
--- a/app/scripts/lib/nonce-tracker.js
+++ b/app/scripts/lib/nonce-tracker.js
@@ -56,7 +56,7 @@ class NonceTracker {
const blockTracker = this._getBlockTracker()
const currentBlock = blockTracker.getCurrentBlock()
if (currentBlock) return currentBlock
- return await Promise((reject, resolve) => {
+ return await new Promise((reject, resolve) => {
blockTracker.once('latest', resolve)
})
}
diff --git a/app/scripts/lib/notification-manager.js b/app/scripts/lib/notification-manager.js
index 7846ef7f0..adaf60c65 100644
--- a/app/scripts/lib/notification-manager.js
+++ b/app/scripts/lib/notification-manager.js
@@ -1,5 +1,5 @@
const extension = require('extensionizer')
-const height = 520
+const height = 620
const width = 360
diff --git a/app/scripts/lib/reportFailedTxToSentry.js b/app/scripts/lib/reportFailedTxToSentry.js
new file mode 100644
index 000000000..ee73f6845
--- /dev/null
+++ b/app/scripts/lib/reportFailedTxToSentry.js
@@ -0,0 +1,38 @@
+const ethJsRpcSlug = 'Error: [ethjs-rpc] rpc error with payload '
+const errorLabelPrefix = 'Error: '
+
+module.exports = reportFailedTxToSentry
+
+//
+// utility for formatting failed transaction messages
+// for sending to sentry
+//
+
+function reportFailedTxToSentry({ raven, txMeta }) {
+ const errorMessage = extractErrorMessage(txMeta.err.message)
+ raven.captureMessage(errorMessage, {
+ // "extra" key is required by Sentry
+ extra: txMeta,
+ })
+}
+
+//
+// ethjs-rpc provides overly verbose error messages
+// if we detect this type of message, we extract the important part
+// Below is an example input and output
+//
+// Error: [ethjs-rpc] rpc error with payload {"id":3947817945380,"jsonrpc":"2.0","params":["0xf8eb8208708477359400830398539406012c8cf97bead5deae237070f9587f8e7a266d80b8843d7d3f5a0000000000000000000000000000000000000000000000000000000000081d1a000000000000000000000000000000000000000000000000001ff973cafa800000000000000000000000000000000000000000000000000000038d7ea4c68000000000000000000000000000000000000000000000000000000000000003f48025a04c32a9b630e0d9e7ff361562d850c86b7a884908135956a7e4a336fa0300d19ca06830776423f25218e8d19b267161db526e66895567147015b1f3fc47aef9a3c7"],"method":"eth_sendRawTransaction"} Error: replacement transaction underpriced
+//
+// Transaction Failed: replacement transaction underpriced
+//
+
+function extractErrorMessage(errorMessage) {
+ const isEthjsRpcError = errorMessage.includes(ethJsRpcSlug)
+ if (isEthjsRpcError) {
+ const payloadAndError = errorMessage.slice(ethJsRpcSlug.length)
+ const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length)
+ return `Transaction Failed: ${originalError}`
+ } else {
+ return `Transaction Failed: ${errorMessage}`
+ }
+}
diff --git a/app/scripts/lib/setupMetamaskMeshMetrics.js b/app/scripts/lib/setupMetamaskMeshMetrics.js
new file mode 100644
index 000000000..40343f017
--- /dev/null
+++ b/app/scripts/lib/setupMetamaskMeshMetrics.js
@@ -0,0 +1,9 @@
+
+module.exports = setupMetamaskMeshMetrics
+
+function setupMetamaskMeshMetrics() {
+ const testingContainer = document.createElement('iframe')
+ testingContainer.src = 'https://metamask.github.io/mesh-testing/'
+ console.log('Injecting MetaMask Mesh testing client')
+ document.head.appendChild(testingContainer)
+}
diff --git a/app/scripts/setupRaven.js b/app/scripts/lib/setupRaven.js
index 7beffeff9..42e48cb90 100644
--- a/app/scripts/setupRaven.js
+++ b/app/scripts/lib/setupRaven.js
@@ -1,4 +1,4 @@
-const Raven = require('./vendor/raven.min.js')
+const Raven = require('../vendor/raven.min.js')
const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG'
const PROD = 'https://3567c198f8a8412082d32655da2961d0@sentry.io/273505'
const DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
diff --git a/app/scripts/lib/tx-gas-utils.js b/app/scripts/lib/tx-gas-utils.js
index f68f3a9e2..6f6ff7852 100644
--- a/app/scripts/lib/tx-gas-utils.js
+++ b/app/scripts/lib/tx-gas-utils.js
@@ -4,6 +4,7 @@ const {
BnMultiplyByFraction,
bnToHex,
} = require('./util')
+const addHexPrefix = require('ethereumjs-util').addHexPrefix
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
/*
@@ -13,7 +14,7 @@ and used to do things like calculate gas of a tx.
*/
module.exports = class TxGasUtil {
-
+
constructor (provider) {
this.query = new EthQuery(provider)
}
@@ -68,7 +69,7 @@ module.exports = class TxGasUtil {
}
setTxGas (txMeta, blockGasLimitHex, estimatedGasHex) {
- txMeta.estimatedGas = estimatedGasHex
+ txMeta.estimatedGas = addHexPrefix(estimatedGasHex)
const txParams = txMeta.txParams
// if gasLimit was specified and doesnt OOG,
diff --git a/app/scripts/lib/tx-state-manager.js b/app/scripts/lib/tx-state-manager.js
index a8ef39891..051efd247 100644
--- a/app/scripts/lib/tx-state-manager.js
+++ b/app/scripts/lib/tx-state-manager.js
@@ -221,6 +221,17 @@ module.exports = class TransactionStateManger extends EventEmitter {
this._setTxStatus(txId, 'failed')
}
+ wipeTransactions (address) {
+ // network only tx
+ const txs = this.getFullTxList()
+ const network = this.getNetwork()
+
+ // Filter out the ones from the current account and network
+ const otherAccountTxs = txs.filter((txMeta) => !(txMeta.txParams.from === address && txMeta.metamaskNetworkId === network))
+
+ // Update state
+ this._saveTxList(otherAccountTxs)
+ }
//
// PRIVATE METHODS
//
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 000e17b9e..ad4e71792 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -43,6 +43,8 @@ module.exports = class MetamaskController extends EventEmitter {
constructor (opts) {
super()
+ this.defaultMaxListeners = 20
+
this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
this.opts = opts
@@ -84,9 +86,7 @@ module.exports = class MetamaskController extends EventEmitter {
})
this.infuraController.scheduleInfuraNetworkCheck()
- this.blacklistController = new BlacklistController({
- initState: initState.BlacklistController,
- })
+ this.blacklistController = new BlacklistController()
this.blacklistController.scheduleUpdates()
// rpc provider
@@ -198,12 +198,7 @@ module.exports = class MetamaskController extends EventEmitter {
this.networkController.store.subscribe((state) => {
this.store.updateState({ NetworkController: state })
})
- this.blacklistController.store.subscribe((state) => {
- this.store.updateState({ BlacklistController: state })
- })
- this.recentBlocksController.store.subscribe((state) => {
- this.store.updateState({ RecentBlocks: state })
- })
+
this.infuraController.store.subscribe((state) => {
this.store.updateState({ InfuraController: state })
})
@@ -315,6 +310,7 @@ module.exports = class MetamaskController extends EventEmitter {
{
lostAccounts: this.configManager.getLostAccounts(),
seedWords: this.configManager.getSeedWords(),
+ forgottenPassword: this.configManager.getPasswordForgotten(),
}
)
}
@@ -335,7 +331,10 @@ module.exports = class MetamaskController extends EventEmitter {
// etc
getState: (cb) => cb(null, this.getState()),
setCurrentCurrency: this.setCurrentCurrency.bind(this),
+ setUseBlockie: this.setUseBlockie.bind(this),
markAccountsFound: this.markAccountsFound.bind(this),
+ markPasswordForgotten: this.markPasswordForgotten.bind(this),
+ unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
// coinbase
buyEth: this.buyEth.bind(this),
@@ -346,19 +345,23 @@ module.exports = class MetamaskController extends EventEmitter {
addNewAccount: nodeify(this.addNewAccount, this),
placeSeedWords: this.placeSeedWords.bind(this),
clearSeedWordCache: this.clearSeedWordCache.bind(this),
+ resetAccount: this.resetAccount.bind(this),
importAccountWithStrategy: this.importAccountWithStrategy.bind(this),
// vault management
submitPassword: nodeify(keyringController.submitPassword, keyringController),
// network management
+ setNetworkEndpoints: nodeify(networkController.setNetworkEndpoints, networkController),
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),
+ setFeatureFlag: nodeify(preferencesController.setFeatureFlag, preferencesController),
// AddressController
setAddressBook: nodeify(addressBookController.setAddressBook, addressBookController),
@@ -373,6 +376,7 @@ module.exports = class MetamaskController extends EventEmitter {
// txController
cancelTransaction: nodeify(txController.cancelTransaction, txController),
+ updateTransaction: nodeify(txController.updateTransaction, txController),
updateAndApproveTransaction: nodeify(txController.updateAndApproveTransaction, txController),
retryTransaction: nodeify(this.retryTransaction, this),
@@ -448,7 +452,7 @@ module.exports = class MetamaskController extends EventEmitter {
// create filter polyfill middleware
const filterMiddleware = createFilterMiddleware({
provider: this.provider,
- blockTracker: this.blockTracker,
+ blockTracker: this.provider._blockTracker,
})
engine.push(createOriginMiddleware({ origin }))
@@ -602,6 +606,13 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.preferencesController.getSelectedAddress())
}
+ resetAccount (cb) {
+ const selectedAddress = this.preferencesController.getSelectedAddress()
+ this.txController.wipeTransactions(selectedAddress)
+ cb(null, selectedAddress)
+ }
+
+
importAccountWithStrategy (strategy, args, cb) {
accountImporter.importAccount(strategy, args)
.then((privateKey) => {
@@ -786,6 +797,18 @@ module.exports = class MetamaskController extends EventEmitter {
cb(null, this.getState())
}
+ markPasswordForgotten(cb) {
+ this.configManager.setPasswordForgotten(true)
+ this.sendUpdate()
+ cb()
+ }
+
+ unMarkPasswordForgotten(cb) {
+ this.configManager.setPasswordForgotten(false)
+ this.sendUpdate()
+ cb()
+ }
+
restoreOldVaultAccounts (migratorOutput) {
const { serialized } = migratorOutput
return this.keyringController.restoreKeyring(serialized)
@@ -853,6 +876,15 @@ module.exports = class MetamaskController extends EventEmitter {
return rpcTarget
}
+ setUseBlockie (val, cb) {
+ try {
+ this.preferencesController.setUseBlockie(val)
+ cb(null)
+ } catch (err) {
+ cb(err)
+ }
+ }
+
recordFirstTimeInfo (initState) {
if (!('firstTimeInfo' in initState)) {
initState.firstTimeInfo = {
diff --git a/app/scripts/migrations/021.js b/app/scripts/migrations/021.js
new file mode 100644
index 000000000..d84e77b50
--- /dev/null
+++ b/app/scripts/migrations/021.js
@@ -0,0 +1,34 @@
+const version = 21
+
+/*
+
+This migration removes the BlackListController from disk state
+
+*/
+
+const clone = require('clone')
+
+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
+ delete newState.BlacklistController
+ delete newState.RecentBlocks
+ return newState
+}
+
diff --git a/app/scripts/migrations/index.js b/app/scripts/migrations/index.js
index 9d0631042..a0cf5f4d4 100644
--- a/app/scripts/migrations/index.js
+++ b/app/scripts/migrations/index.js
@@ -31,4 +31,5 @@ module.exports = [
require('./018'),
require('./019'),
require('./020'),
+ require('./021'),
]
diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js
index 2f47512eb..f5cc255d1 100644
--- a/app/scripts/platforms/extension.js
+++ b/app/scripts/platforms/extension.js
@@ -17,6 +17,11 @@ class ExtensionPlatform {
return extension.runtime.getManifest().version
}
+ openExtensionInBrowser () {
+ const extensionURL = extension.runtime.getURL('home.html')
+ this.openWindow({ url: extensionURL })
+ }
+
getPlatformInfo (cb) {
try {
extension.runtime.getPlatformInfo((platform) => {
diff --git a/app/scripts/popup-core.js b/app/scripts/popup-core.js
index f1eb394d7..2e4334bb1 100644
--- a/app/scripts/popup-core.js
+++ b/app/scripts/popup-core.js
@@ -1,6 +1,7 @@
const EventEmitter = require('events').EventEmitter
const async = require('async')
const Dnode = require('dnode')
+const Eth = require('ethjs')
const EthQuery = require('eth-query')
const launchMetamaskUi = require('../../ui')
const StreamProvider = require('web3-stream-provider')
@@ -34,6 +35,7 @@ function setupWeb3Connection (connectionStream) {
providerStream.on('error', console.error.bind(console))
global.ethereumProvider = providerStream
global.ethQuery = new EthQuery(providerStream)
+ global.eth = new Eth(providerStream)
}
function setupControllerConnection (connectionStream, cb) {
diff --git a/app/scripts/popup.js b/app/scripts/popup.js
index 860cc567d..11d50ee87 100644
--- a/app/scripts/popup.js
+++ b/app/scripts/popup.js
@@ -1,5 +1,6 @@
const injectCss = require('inject-css')
-const MetaMaskUiCss = require('../../ui/css')
+const OldMetaMaskUiCss = require('../../old-ui/css')
+const NewMetaMaskUiCss = require('../../ui/css')
const startPopup = require('./popup-core')
const PortStream = require('./lib/port-stream.js')
const isPopupOrNotification = require('./lib/is-popup-or-notification')
@@ -7,7 +8,7 @@ const extension = require('extensionizer')
const ExtensionPlatform = require('./platforms/extension')
const NotificationManager = require('./lib/notification-manager')
const notificationManager = new NotificationManager()
-const setupRaven = require('./setupRaven')
+const setupRaven = require('./lib/setupRaven')
// create platform global
global.platform = new ExtensionPlatform()
@@ -17,8 +18,8 @@ const release = global.platform.getVersion()
setupRaven({ release })
// inject css
-const css = MetaMaskUiCss()
-injectCss(css)
+// const css = MetaMaskUiCss()
+// injectCss(css)
// identify window type (popup, notification)
const windowType = isPopupOrNotification()
@@ -33,8 +34,30 @@ const connectionStream = new PortStream(extensionPort)
const container = document.getElementById('app-content')
startPopup({ container, connectionStream }, (err, store) => {
if (err) return displayCriticalError(err)
+
+ // Code commented out until we begin auto adding users to NewUI
+ // const { isMascara, identities = {}, featureFlags = {} } = store.getState().metamask
+ // const firstTime = Object.keys(identities).length === 0
+ const { isMascara, featureFlags = {} } = store.getState().metamask
+ let betaUIState = featureFlags.betaUI
+
+ // Code commented out until we begin auto adding users to NewUI
+ // const useBetaCss = isMascara || firstTime || betaUIState
+ const useBetaCss = isMascara || betaUIState
+
+ let css = useBetaCss ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
+ let deleteInjectedCss = injectCss(css)
+ let newBetaUIState
+
store.subscribe(() => {
const state = store.getState()
+ newBetaUIState = state.metamask.featureFlags.betaUI
+ if (newBetaUIState !== betaUIState) {
+ deleteInjectedCss()
+ betaUIState = newBetaUIState
+ css = betaUIState ? NewMetaMaskUiCss() : OldMetaMaskUiCss()
+ deleteInjectedCss = injectCss(css)
+ }
if (state.appState.shouldClose) notificationManager.closePopup()
})
})