1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Merge remote-tracking branch 'origin/develop' into sync-master

* origin/develop: (137 commits)
  Use @metamask/eslint-config@3.1.0 (#9275)
  Standardize scss import practices (#9183)
  Update ESLint shared config to v3 (#9274)
  Add lock icon to default networks (#9269)
  Adds toPrecisionWithoutTrailingZeros utility (#9270)
  Hide gas estimate on non-main network (#9189)
  Move the mascot component to its own directory (#9272)
  Use @metamask/controllers@2.0.5 (#9266)
  Fix padding, alignment of actionable-message; add left aligned story
  Code cleanup and simplification for actionable-message component
  Adds actionable message component and stories
  Fix lint issues (#9265)
  Fix prefer-destructuring issues (#9263)
  colocate confirm-decrypt-message page styles (#9252)
  Tidy up Migrator tests (#9264)
  Adds pulse loader component (#9259)
  Fix import/order issues (#9239)
  Fix radix issues (#9247)
  New info tooltip component (#9180)
  Improve scss naming
  ...
This commit is contained in:
Mark Stacey 2020-08-19 17:53:20 -03:00
commit 0c72d0bc3d
690 changed files with 5091 additions and 6105 deletions

View File

@ -3,14 +3,9 @@
node_modules/**
dist/**
builds/**
test-builds/**
test-*/**
docs/**
coverage/
app/scripts/lib/extension-instance.js
app/scripts/chromereload.js
app/vendor/**
ui/lib/blockies.js
package-lock.json

View File

@ -41,34 +41,22 @@ module.exports = {
},
rules: {
/* TODO: Remove these when upgrading to `@metamask/eslint-config@2` */
'array-callback-return': 'error',
'callback-return': 'error',
'global-require': 'error',
'guard-for-in': 'error',
/* End v2 rules */
'arrow-parens': 'error',
'no-tabs': 'error',
'no-mixed-operators': 'error',
'import/default': 'error',
'import/export': 'error',
'import/named': 'error',
'import/namespace': 'error',
'import/newline-after-import': 'error',
'import/no-absolute-path': 'error',
'import/no-amd': 'error',
'import/no-anonymous-default-export': 'error',
'import/no-duplicates': 'error',
'import/no-dynamic-require': 'error',
'import/no-mutable-exports': 'error',
'import/no-named-as-default': 'error',
'import/no-named-as-default-member': 'error',
'import/no-named-default': 'error',
'import/no-self-import': 'error',
'import/no-unresolved': ['error', { 'commonjs': true }],
'import/no-unused-modules': 'error',
'import/no-useless-path-segments': ['error', { 'commonjs': true }],
'import/no-webpack-loader-syntax': 'error',
'default-param-last': 'off',
'require-atomic-updates': 'off',
'import/no-unassigned-import': 'off',
'prefer-destructuring': ['error', {
'VariableDeclarator': {
'array': false,
'object': true,
},
'AssignmentExpression': {
'array': false,
'object': false,
},
}, {
'enforceForRenamedProperties': false,
}],
'prefer-object-spread': 'error',
'react/no-unused-prop-types': 'error',
'react/no-unused-state': 'error',
'react/jsx-boolean-value': 'error',
@ -80,7 +68,7 @@ module.exports = {
'react/jsx-no-duplicate-props': 'error',
'react/jsx-closing-bracket-location': 'error',
'react/jsx-first-prop-new-line': ['error', 'multiline'],
'react/jsx-max-props-per-line': ['error', { 'maximum': 1, 'when': 'multiline' } ],
'react/jsx-max-props-per-line': ['error', { 'maximum': 1, 'when': 'multiline' }],
'react/jsx-tag-spacing': ['error', {
'closingSlash': 'never',
'beforeSelfClosing': 'always',
@ -95,11 +83,22 @@ module.exports = {
'logical': 'parens-new-line',
'prop': 'parens-new-line',
}],
'no-invalid-this': 'off',
'babel/no-invalid-this': 'error',
'babel/semi': ['error', 'never'],
'mocha/no-setup-in-describe': 'off',
},
overrides: [{
files: [
'test/e2e/**/*.js',
],
rules: {
'mocha/no-hooks-for-single-case': 'off',
},
}, {
files: [
'app/scripts/migrations/*.js',
'*.stories.js',
@ -114,6 +113,38 @@ module.exports = {
rules: {
'global-require': 'off',
},
}, {
files: [
'test/**/*-test.js',
'test/**/*.spec.js',
],
rules: {
// Mocha will re-assign `this` in a test context
'babel/no-invalid-this': 'off',
},
}, {
files: [
'development/**/*.js',
'test/e2e/benchmark.js',
'test/helper.js',
],
rules: {
'no-process-exit': 'off',
},
}, {
files: [
'.eslintrc.js',
'babel.config.js',
'nyc.config.js',
'stylelint.config.js',
'development/**/*.js',
'test/e2e/**/*.js',
'test/env.js',
'test/setup.js',
],
parserOptions: {
sourceType: 'script',
},
}],
settings: {

View File

@ -1,5 +1,5 @@
module.exports = {
stories: ['../ui/app/components/**/*.stories.js'],
stories: ['../ui/app/**/*.stories.js'],
addons: [
'@storybook/addon-knobs',
'@storybook/addon-actions',

View File

@ -29,11 +29,13 @@ module.exports = {
],
},
plugins: [
new CopyWebpackPlugin([
{
from: path.join('node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'),
to: path.join('fonts', 'fontawesome'),
},
]),
new CopyWebpackPlugin({
patterns: [
{
from: path.join('node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'),
to: path.join('fonts', 'fontawesome'),
},
],
}),
],
}

Binary file not shown.

Binary file not shown.

View File

@ -8,7 +8,7 @@ const accountImporter = {
importAccount (strategy, args) {
try {
const importer = this.strategies[strategy]
const privateKeyHex = importer.apply(null, args)
const privateKeyHex = importer(...args)
return Promise.resolve(privateKeyHex)
} catch (e) {
return Promise.reject(e)

View File

@ -1,11 +1,11 @@
/**
* @file The entry point for the web extension singleton process.
*/
// these need to run before anything else
/* eslint-disable import/first,import/order */
import './lib/freezeGlobals'
import setupFetchDebugging from './lib/setupFetchDebugging'
/* eslint-enable import/order */
setupFetchDebugging()
@ -17,16 +17,16 @@ import pump from 'pump'
import debounce from 'debounce-stream'
import log from 'loglevel'
import extension from 'extensionizer'
import ReadOnlyNetworkStore from './lib/network-store'
import LocalStore from './lib/local-store'
import storeTransform from 'obs-store/lib/transform'
import asStream from 'obs-store/lib/asStream'
import ExtensionPlatform from './platforms/extension'
import Migrator from './lib/migrator'
import migrations from './migrations'
import PortStream from 'extension-port-stream'
import migrations from './migrations'
import Migrator from './lib/migrator'
import ExtensionPlatform from './platforms/extension'
import LocalStore from './lib/local-store'
import ReadOnlyNetworkStore from './lib/network-store'
import createStreamSink from './lib/createStreamSink'
import NotificationManager from './lib/notification-manager.js'
import NotificationManager from './lib/notification-manager'
import MetamaskController from './metamask-controller'
import rawFirstTimeState from './first-time-state'
import setupSentry from './lib/setupSentry'
@ -39,9 +39,10 @@ import {
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
} from './lib/enums'
/* eslint-enable import/first */
// METAMASK_TEST_CONFIG is used in e2e tests to set the default network to localhost
const firstTimeState = Object.assign({}, rawFirstTimeState, global.METAMASK_TEST_CONFIG)
const firstTimeState = { ...rawFirstTimeState, ...global.METAMASK_TEST_CONFIG }
log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn')
@ -327,7 +328,7 @@ function setupController (initState, initLangCode) {
const isMetaMaskInternalProcess = metamaskInternalProcessHash[processName]
if (metamaskBlockedPorts.includes(remotePort.name)) {
return false
return
}
if (isMetaMaskInternalProcess) {
@ -406,11 +407,11 @@ function setupController (initState, initLangCode) {
function updateBadge () {
let label = ''
const unapprovedTxCount = controller.txController.getUnapprovedTxCount()
const unapprovedMsgCount = controller.messageManager.unapprovedMsgCount
const unapprovedPersonalMsgCount = controller.personalMessageManager.unapprovedPersonalMsgCount
const unapprovedDecryptMsgCount = controller.decryptMessageManager.unapprovedDecryptMsgCount
const unapprovedEncryptionPublicKeyMsgCount = controller.encryptionPublicKeyManager.unapprovedEncryptionPublicKeyMsgCount
const unapprovedTypedMessagesCount = controller.typedMessageManager.unapprovedTypedMessagesCount
const { unapprovedMsgCount } = controller.messageManager
const { unapprovedPersonalMsgCount } = controller.personalMessageManager
const { unapprovedDecryptMsgCount } = controller.decryptMessageManager
const { unapprovedEncryptionPublicKeyMsgCount } = controller.encryptionPublicKeyManager
const { unapprovedTypedMessagesCount } = controller.typedMessageManager
const pendingPermissionRequests = Object.keys(controller.permissionsController.permissions.state.permissionsRequests).length
const waitingForUnlockCount = controller.appStateController.waitingForUnlock.length
const count = unapprovedTxCount + unapprovedMsgCount + unapprovedPersonalMsgCount + unapprovedDecryptMsgCount + unapprovedEncryptionPublicKeyMsgCount +

View File

@ -1,5 +1,5 @@
import pump from 'pump'
import querystring from 'querystring'
import pump from 'pump'
import LocalMessageDuplexStream from 'post-message-stream'
import ObjectMultiplex from 'obj-multiplex'
import extension from 'extensionizer'
@ -10,7 +10,7 @@ const fs = require('fs')
const path = require('path')
const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js'), 'utf8')
const inpageSuffix = '//# sourceURL=' + extension.runtime.getURL('inpage.js') + '\n'
const inpageSuffix = `//# sourceURL=${extension.runtime.getURL('inpage.js')}\n`
const inpageBundle = inpageContent + inpageSuffix
// Eventually this streaming injection could be replaced with:
@ -115,7 +115,7 @@ function forwardTrafficBetweenMuxers (channelName, muxA, muxB) {
function logStreamDisconnectWarning (remoteLabel, err) {
let warningMsg = `MetamaskContentscript - lost connection to ${remoteLabel}`
if (err) {
warningMsg += '\n' + err.stack
warningMsg += `\n${err.stack}`
}
console.warn(warningMsg)
}
@ -136,12 +136,11 @@ function shouldInjectProvider () {
* @returns {boolean} {@code true} - if the doctype is html or if none exists
*/
function doctypeCheck () {
const doctype = window.document.doctype
const { doctype } = window.document
if (doctype) {
return doctype.name === 'html'
} else {
return true
}
return true
}
/**
@ -155,8 +154,8 @@ function doctypeCheck () {
*/
function suffixCheck () {
const prohibitedTypes = [
/\.xml$/,
/\.pdf$/,
/\.xml$/u,
/\.pdf$/u,
]
const currentUrl = window.location.pathname
for (let i = 0; i < prohibitedTypes.length; i++) {
@ -202,7 +201,7 @@ function blockedDomainCheck () {
let currentRegex
for (let i = 0; i < blockedDomains.length; i++) {
const blockedDomain = blockedDomains[i].replace('.', '\\.')
currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`)
currentRegex = new RegExp(`(?:https?:\\/\\/)(?:(?!${blockedDomain}).)*$`, 'u')
if (!currentRegex.test(currentUrl)) {
return true
}
@ -228,7 +227,7 @@ function redirectToPhishingWarning () {
async function domIsReady () {
// already loaded
if (['interactive', 'complete'].includes(document.readyState)) {
return
return undefined
}
// wait for load
return new Promise((resolve) => window.addEventListener('DOMContentLoaded', resolve, { once: true }))

View File

@ -32,24 +32,21 @@ const defaultState = {
* alert related state
*/
export default class AlertController {
/**
* @constructor
* @param {AlertControllerOptions} [opts] - Controller configuration parameters
*/
constructor (opts = {}) {
const { initState, preferencesStore } = opts
const state = Object.assign(
{},
defaultState,
initState,
{
unconnectedAccountAlertShownOrigins: {},
},
)
const state = {
...defaultState,
...initState,
unconnectedAccountAlertShownOrigins: {},
}
this.store = new ObservableStore(state)
const { selectedAddress } = preferencesStore.getState()
this.selectedAddress = selectedAddress
this.selectedAddress = preferencesStore.getState().selectedAddress
preferencesStore.subscribe(({ selectedAddress }) => {
const currentState = this.store.getState()

View File

@ -1,7 +1,8 @@
import ObservableStore from 'obs-store'
import EventEmitter from 'events'
import ObservableStore from 'obs-store'
export default class AppStateController extends EventEmitter {
/**
* @constructor
* @param opts
@ -15,16 +16,14 @@ export default class AppStateController extends EventEmitter {
showUnlockRequest,
preferencesStore,
} = opts
const { preferences } = preferencesStore.getState()
super()
this.onInactiveTimeout = onInactiveTimeout || (() => {})
this.store = new ObservableStore(Object.assign({
this.onInactiveTimeout = onInactiveTimeout || (() => undefined)
this.store = new ObservableStore({
timeoutMinutes: 0,
connectedStatusPopoverHasBeenShown: true,
defaultHomeActiveTabName: null,
}, initState))
defaultHomeActiveTabName: null, ...initState,
})
this.timer = null
this.isUnlocked = isUnlocked
@ -40,6 +39,7 @@ export default class AppStateController extends EventEmitter {
}
})
const { preferences } = preferencesStore.getState()
this._setInactiveTimeout(preferences.autoLockTimeLimit)
}

View File

@ -12,6 +12,7 @@ import ObservableStore from 'obs-store'
* a cache of account balances in local storage
*/
export default class CachedBalancesController {
/**
* Creates a new controller instance
*
@ -23,9 +24,7 @@ export default class CachedBalancesController {
this.accountTracker = accountTracker
this.getNetwork = getNetwork
const initState = Object.assign({
cachedBalances: {},
}, opts.initState)
const initState = { cachedBalances: {}, ...opts.initState }
this.store = new ObservableStore(initState)
this._registerUpdates()

View File

@ -1,17 +1,19 @@
import Web3 from 'web3'
import contracts from 'eth-contract-metadata'
import { warn } from 'loglevel'
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi'
import { MAINNET } from './network/enums'
// By default, poll every 3 minutes
const DEFAULT_INTERVAL = 180 * 1000
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi'
const SINGLE_CALL_BALANCES_ADDRESS = '0xb1f8e55c7f64d203c1400b9d8555d050f94adf39'
/**
* A controller that polls for token exchange
* rates based on a user's current token list
*/
export default class DetectTokensController {
/**
* Creates a DetectTokensController
*

View File

@ -1,6 +1,6 @@
import punycode from 'punycode'
import ethUtil from 'ethereumjs-util'
import ObservableStore from 'obs-store'
import punycode from 'punycode'
import log from 'loglevel'
import Ens from './ens'

View File

@ -40,7 +40,7 @@ export default class IncomingTransactionsController {
})
}
const initState = Object.assign({
const initState = {
incomingTransactions: {},
incomingTxLastFetchedBlocksByNetwork: {
[ROPSTEN]: null,
@ -48,8 +48,8 @@ export default class IncomingTransactionsController {
[KOVAN]: null,
[GOERLI]: null,
[MAINNET]: null,
},
}, opts.initState)
}, ...opts.initState,
}
this.store = new ObservableStore(initState)
this.preferencesController.store.subscribe(pairwise((prevState, currState) => {
@ -265,9 +265,8 @@ function pairwise (fn) {
if (first) {
first = false
return fn(value, value)
} else {
return fn(cache, value)
}
return fn(cache, value)
} finally {
cache = value
}

View File

@ -26,7 +26,6 @@ function delay (time) {
return new Promise((resolve) => setTimeout(resolve, time))
}
function createEstimateGasMiddleware () {
return createAsyncMiddleware(async (req, _, next) => {
if (req.method === 'eth_estimateGas' && inTest) {

View File

@ -1,15 +1,17 @@
import { formatTxMetaForRpcResult } from '../util'
import createAsyncMiddleware from 'json-rpc-engine/src/createAsyncMiddleware'
import { formatTxMetaForRpcResult } from '../util'
export function createPendingNonceMiddleware ({ getPendingNonce }) {
return createAsyncMiddleware(async (req, res, next) => {
const { method, params } = req
if (method !== 'eth_getTransactionCount') {
return next()
next()
return
}
const [param, blockRef] = params
if (blockRef !== 'pending') {
return next()
next()
return
}
res.result = await getPendingNonce(param)
})
@ -19,12 +21,14 @@ export function createPendingTxMiddleware ({ getPendingTransactionByHash }) {
return createAsyncMiddleware(async (req, res, next) => {
const { method, params } = req
if (method !== 'eth_getTransactionByHash') {
return next()
next()
return
}
const [hash] = params
const txMeta = getPendingTransactionByHash(hash)
if (!txMeta) {
return next()
next()
return
}
res.result = formatTxMetaForRpcResult(txMeta)
})

View File

@ -6,13 +6,11 @@ import EthQuery from 'eth-query'
import JsonRpcEngine from 'json-rpc-engine'
import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'
import log from 'loglevel'
import { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy'
import createMetamaskMiddleware from './createMetamaskMiddleware'
import createInfuraClient from './createInfuraClient'
import createJsonRpcClient from './createJsonRpcClient'
import createLocalhostClient from './createLocalhostClient'
import { createSwappableProxy, createEventEmitterProxy } from 'swappable-obj-proxy'
const networks = { networkList: {} }
import {
RINKEBY,
@ -21,8 +19,10 @@ import {
INFURA_PROVIDER_TYPES,
} from './enums'
const networks = { networkList: {} }
const env = process.env.METAMASK_ENV
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
const { METAMASK_DEBUG } = process.env
let defaultProviderConfigType
if (process.env.IN_TEST === 'true') {
@ -93,15 +93,15 @@ export default class NetworkController extends EventEmitter {
setNetworkState (network, type) {
if (network === 'loading') {
return this.networkStore.putState(network)
this.networkStore.putState(network)
return
}
// type must be defined
if (!type) {
return
}
network = networks.networkList[type]?.chainId || network
return this.networkStore.putState(network)
this.networkStore.putState(networks.networkList[type]?.chainId || network)
}
isNetworkLoading () {
@ -111,7 +111,8 @@ export default class NetworkController extends EventEmitter {
lookupNetwork () {
// Prevent firing when provider is not defined.
if (!this._provider) {
return log.warn('NetworkController - lookupNetwork aborted due to missing provider')
log.warn('NetworkController - lookupNetwork aborted due to missing provider')
return
}
const { type } = this.providerStore.getState()
const ethQuery = new EthQuery(this._provider)
@ -120,9 +121,10 @@ export default class NetworkController extends EventEmitter {
const currentNetwork = this.getNetworkState()
if (initialNetwork === currentNetwork) {
if (err) {
return this.setNetworkState('loading')
this.setNetworkState('loading')
return
}
log.info('web3.getNetwork returned ' + network)
log.info(`web3.getNetwork returned ${network}`)
this.setNetworkState(network, type)
}
})
@ -210,7 +212,7 @@ export default class NetworkController extends EventEmitter {
log.info('NetworkController - configureStandardProvider', rpcUrl)
const networkClient = createJsonRpcClient({ rpcUrl })
// hack to add a 'rpc' network with chainId
networks.networkList['rpc'] = {
networks.networkList.rpc = {
chainId,
rpcUrl,
ticker: ticker || 'ETH',
@ -220,7 +222,7 @@ export default class NetworkController extends EventEmitter {
let settings = {
network: chainId,
}
settings = Object.assign(settings, networks.networkList['rpc'])
settings = Object.assign(settings, networks.networkList.rpc)
this.networkConfig.putState(settings)
this._setNetworkClient(networkClient)
}

View File

@ -17,6 +17,7 @@ import log from 'loglevel'
* state related to onboarding
*/
export default class OnboardingController {
/**
* Creates a new controller instance
*
@ -26,13 +27,11 @@ export default class OnboardingController {
const initialTransientState = {
onboardingTabs: {},
}
const initState = Object.assign(
{
seedPhraseBackedUp: true,
},
opts.initState,
initialTransientState,
)
const initState = {
seedPhraseBackedUp: true,
...opts.initState,
...initialTransientState,
}
this.store = new ObservableStore(initState)
this.preferencesController = opts.preferencesController
this.completedOnboarding = this.preferencesController.store.getState().completedOnboarding
@ -64,7 +63,7 @@ export default class OnboardingController {
log.debug('Ignoring registerOnboarding; user already onboarded')
return
}
const onboardingTabs = Object.assign({}, this.store.getState().onboardingTabs)
const onboardingTabs = { ...this.store.getState().onboardingTabs }
if (!onboardingTabs[location] || onboardingTabs[location] !== tabId) {
log.debug(`Registering onboarding tab at location '${location}' with tabId '${tabId}'`)
onboardingTabs[location] = tabId

View File

@ -36,7 +36,8 @@ export class PermissionsController {
showPermissionRequest,
} = {},
restoredPermissions = {},
restoredState = {}) {
restoredState = {},
) {
// additional top-level store key set in _initializeMetadataStore
this.store = new ObservableStore({
@ -132,7 +133,7 @@ export class PermissionsController {
const req = { method: 'eth_accounts' }
const res = {}
this.permissions.providerMiddlewareFunction(
{ origin }, req, res, () => {}, _end,
{ origin }, req, res, () => undefined, _end,
)
function _end () {
@ -187,7 +188,7 @@ export class PermissionsController {
const res = {}
this.permissions.providerMiddlewareFunction(
domain, req, res, () => {}, _end,
domain, req, res, () => undefined, _end,
)
function _end (_err) {
@ -334,7 +335,7 @@ export class PermissionsController {
.filter((acc) => acc !== account)
if (newPermittedAccounts.length === 0) {
this.removePermissionsFor({ [origin]: [ 'eth_accounts' ] })
this.removePermissionsFor({ [origin]: ['eth_accounts'] })
} else {
this.permissions.updateCaveatFor(

View File

@ -113,10 +113,11 @@ export default class PermissionsLogController {
// eth_requestAccounts is a special case; we need to extract the accounts
// from it
activityEntry = this.logRequest(req, isInternal)
requestedMethods = [ 'eth_accounts' ]
requestedMethods = ['eth_accounts']
} else {
// no-op
return next()
next()
return
}
// call next with a return handler for capturing the response
@ -291,9 +292,9 @@ export default class PermissionsLogController {
// eth_accounts requires special handling, because of information
// we store about the accounts
const existingEthAccountsEntry = (
history[origin] && history[origin]['eth_accounts']
history[origin] && history[origin].eth_accounts
)
const newEthAccountsEntry = newEntries['eth_accounts']
const newEthAccountsEntry = newEntries.eth_accounts
if (existingEthAccountsEntry && newEthAccountsEntry) {
@ -305,7 +306,7 @@ export default class PermissionsLogController {
)
// merge old and new eth_accounts history entries
newOriginHistory['eth_accounts'] = {
newOriginHistory.eth_accounts = {
lastApproved,
accounts: {
...existingEthAccountsEntry.accounts,
@ -363,7 +364,7 @@ export default class PermissionsLogController {
}
}
}
return [ ...accounts ]
return [...accounts]
}
}

View File

@ -24,12 +24,13 @@ export default function createPermissionsMethodMiddleware ({
// Intercepting eth_accounts requests for backwards compatibility:
// The getAccounts call below wraps the rpc-cap middleware, and returns
// an empty array in case of errors (such as 4100:unauthorized)
case 'eth_accounts':
case 'eth_accounts': {
res.result = await getAccounts()
return
}
case 'eth_requestAccounts':
case 'eth_requestAccounts': {
if (isProcessingRequestAccounts) {
res.error = ethErrors.rpc.resourceUnavailable(
@ -73,19 +74,21 @@ export default function createPermissionsMethodMiddleware ({
}
return
}
// custom method for getting metadata from the requesting domain,
// sent automatically by the inpage provider when it's initialized
case 'wallet_sendDomainMetadata':
case 'wallet_sendDomainMetadata': {
if (typeof req.domainMetadata?.name === 'string') {
addDomainMetadata(req.origin, req.domainMetadata)
}
res.result = true
return
}
// register return handler to send accountsChanged notification
case 'wallet_requestPermissions':
case 'wallet_requestPermissions': {
if ('eth_accounts' in req.params?.[0]) {
@ -101,6 +104,7 @@ export default function createPermissionsMethodMiddleware ({
}
}
break
}
default:
break

View File

@ -1,7 +1,7 @@
import ObservableStore from 'obs-store'
import { addInternalMethodPrefix } from './permissions'
import { normalize as normalizeAddress } from 'eth-sig-util'
import { isValidAddress, sha3, bufferToHex } from 'ethereumjs-util'
import { addInternalMethodPrefix } from './permissions'
export default class PreferencesController {
@ -26,7 +26,7 @@ export default class PreferencesController {
*
*/
constructor (opts = {}) {
const initState = Object.assign({
const initState = {
frequentRpcListDetail: [],
accountTokens: {},
assetImages: {},
@ -61,8 +61,8 @@ export default class PreferencesController {
metaMetricsSendCount: 0,
// ENS decentralized website resolution
ipfsGateway: 'dweb.link',
}, opts.initState)
ipfsGateway: 'dweb.link', ...opts.initState,
}
this.diagnostics = opts.diagnostics
this.network = opts.network
@ -152,7 +152,6 @@ export default class PreferencesController {
this.store.updateState({ firstTimeFlowType: type })
}
getSuggestedTokens () {
return this.store.getState().suggestedTokens
}
@ -178,7 +177,7 @@ export default class PreferencesController {
* @param {string} methodData - Corresponding data method
*/
addKnownMethodData (fourBytePrefix, methodData) {
const knownMethodData = this.store.getState().knownMethodData
const { knownMethodData } = this.store.getState()
knownMethodData[fourBytePrefix] = methodData
this.store.updateState({ knownMethodData })
}
@ -198,7 +197,7 @@ export default class PreferencesController {
) {
const { type, options } = req.params
switch (type) {
case 'ERC20':
case 'ERC20': {
const result = await this._handleWatchAssetERC20(options)
if (result instanceof Error) {
end(result)
@ -207,6 +206,7 @@ export default class PreferencesController {
end()
}
return
}
default:
end(new Error(`Asset of type ${type} not supported`))
return
@ -214,7 +214,6 @@ export default class PreferencesController {
}
next()
return
}
/**
@ -227,7 +226,7 @@ export default class PreferencesController {
const textDirection = (['ar', 'dv', 'fa', 'he', 'ku'].includes(key)) ? 'rtl' : 'auto'
this.store.updateState({
currentLocale: key,
textDirection: textDirection,
textDirection,
})
return textDirection
}
@ -263,8 +262,8 @@ export default class PreferencesController {
* @returns {string} - the address that was removed
*/
removeAddress (address) {
const identities = this.store.getState().identities
const accountTokens = this.store.getState().accountTokens
const { identities } = this.store.getState()
const { accountTokens } = this.store.getState()
if (!identities[address]) {
throw new Error(`${address} can't be deleted cause it was not found`)
}
@ -281,7 +280,6 @@ export default class PreferencesController {
return address
}
/**
* Adds addresses to the identities object without removing identities
*
@ -289,8 +287,7 @@ export default class PreferencesController {
*
*/
addAddresses (addresses) {
const identities = this.store.getState().identities
const accountTokens = this.store.getState().accountTokens
const { identities, accountTokens } = this.store.getState()
addresses.forEach((address) => {
// skip if already exists
if (identities[address]) {
@ -419,7 +416,7 @@ export default class PreferencesController {
async addToken (rawAddress, symbol, decimals, image) {
const address = normalizeAddress(rawAddress)
const newEntry = { address, symbol, decimals }
const tokens = this.store.getState().tokens
const { tokens } = this.store.getState()
const assetImages = this.getAssetImages()
const previousEntry = tokens.find((token) => {
return token.address === address
@ -444,7 +441,7 @@ export default class PreferencesController {
*
*/
removeToken (rawAddress) {
const tokens = this.store.getState().tokens
const { tokens } = this.store.getState()
const assetImages = this.getAssetImages()
const updatedTokens = tokens.filter((token) => token.address !== rawAddress)
delete assetImages[rawAddress]
@ -470,7 +467,7 @@ export default class PreferencesController {
*/
setAccountLabel (account, label) {
if (!account) {
throw new Error('setAccountLabel requires a valid address, got ' + String(account))
throw new Error(`setAccountLabel requires a valid address, got ${String(account)}`)
}
const address = normalizeAddress(account)
const { identities } = this.store.getState()
@ -491,7 +488,6 @@ export default class PreferencesController {
*
*/
updateRpc (newRpcDetails) {
const rpcList = this.getFrequentRpcListDetail()
const index = rpcList.findIndex((element) => {
@ -508,6 +504,7 @@ export default class PreferencesController {
}
return Promise.resolve(rpcList)
}
/**
* Adds custom RPC url to state.
*
@ -528,7 +525,8 @@ export default class PreferencesController {
}
if (url !== 'http://localhost:8545') {
let checkedChainId
if (!!chainId && !Number.isNaN(parseInt(chainId))) {
// eslint-disable-next-line radix
if (Boolean(chainId) && !Number.isNaN(parseInt(chainId))) {
checkedChainId = chainId
}
rpcList.push({ rpcUrl: url, chainId: checkedChainId, ticker, nickname, rpcPrefs })
@ -686,8 +684,9 @@ export default class PreferencesController {
*
*/
_getTokenRelatedStates (selectedAddress) {
const accountTokens = this.store.getState().accountTokens
const { accountTokens } = this.store.getState()
if (!selectedAddress) {
// eslint-disable-next-line no-param-reassign
selectedAddress = this.store.getState().selectedAddress
}
const providerType = this.network.providerStore.getState().type

View File

@ -1,16 +1,19 @@
import ObservableStore from 'obs-store'
/* eslint-disable import/first,import/order */
const Box = process.env.IN_TEST
? require('../../../development/mock-3box')
: require('3box')
/* eslint-enable import/order */
import log from 'loglevel'
import migrations from '../migrations'
import Migrator from '../lib/migrator'
import JsonRpcEngine from 'json-rpc-engine'
import providerFromEngine from 'eth-json-rpc-middleware/providerFromEngine'
import createMetamaskMiddleware from './network/createMetamaskMiddleware'
import Migrator from '../lib/migrator'
import migrations from '../migrations'
import createOriginMiddleware from '../lib/createOriginMiddleware'
import createMetamaskMiddleware from './network/createMetamaskMiddleware'
/* eslint-enable import/first */
const SYNC_TIMEOUT = 60 * 1000 // one minute
@ -33,16 +36,15 @@ export default class ThreeBoxController {
if (origin !== '3Box') {
return []
}
const isUnlocked = getKeyringControllerState().isUnlocked
const { isUnlocked } = getKeyringControllerState()
const accounts = await this.keyringController.getAccounts()
if (isUnlocked && accounts[0]) {
const appKeyAddress = await this.keyringController.getAppKeyAddress(accounts[0], 'wallet://3box.metamask.io')
return [appKeyAddress]
} else {
return []
}
return []
},
processPersonalMessage: async (msgParams) => {
const accounts = await this.keyringController.getAccounts()
@ -123,7 +125,7 @@ export default class ThreeBoxController {
const threeBoxConfig = await Box.getConfig(this.address)
backupExists = threeBoxConfig.spaces && threeBoxConfig.spaces.metamask
} catch (e) {
if (e.message.match(/^Error: Invalid response \(404\)/)) {
if (e.message.match(/^Error: Invalid response \(404\)/u)) {
backupExists = false
} else {
throw e

View File

@ -3,7 +3,6 @@ import log from 'loglevel'
import { normalize as normalizeAddress } from 'eth-sig-util'
import ethUtil from 'ethereumjs-util'
// By default, poll every 3 minutes
const DEFAULT_INTERVAL = 180 * 1000
@ -12,6 +11,7 @@ const DEFAULT_INTERVAL = 180 * 1000
* rates based on a user's current token list
*/
export default class TokenRatesController {
/**
* Creates a TokenRatesController
*

View File

@ -6,9 +6,8 @@ import EthQuery from 'ethjs-query'
import { ethErrors } from 'eth-json-rpc-errors'
import abi from 'human-standard-token-abi'
import abiDecoder from 'abi-decoder'
abiDecoder.addABI(abi)
import NonceTracker from 'nonce-tracker'
import log from 'loglevel'
import {
TOKEN_METHOD_APPROVE,
TOKEN_METHOD_TRANSFER,
@ -16,16 +15,14 @@ import {
SEND_ETHER_ACTION_KEY,
DEPLOY_CONTRACT_ACTION_KEY,
CONTRACT_INTERACTION_KEY,
} from '../../../../ui/app/helpers/constants/transactions.js'
} from '../../../../ui/app/helpers/constants/transactions'
import cleanErrorStack from '../../lib/cleanErrorStack'
import { hexToBn, bnToHex, BnMultiplyByFraction } from '../../lib/util'
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys'
import TransactionStateManager from './tx-state-manager'
import TxGasUtil from './tx-gas-utils'
import PendingTransactionTracker from './pending-tx-tracker'
import NonceTracker from 'nonce-tracker'
import * as txUtils from './lib/util'
import cleanErrorStack from '../../lib/cleanErrorStack'
import log from 'loglevel'
import {
TRANSACTION_TYPE_CANCEL,
TRANSACTION_TYPE_RETRY,
@ -33,8 +30,7 @@ import {
TRANSACTION_STATUS_APPROVED,
} from './enums'
import { hexToBn, bnToHex, BnMultiplyByFraction } from '../../lib/util'
import { TRANSACTION_NO_CONTRACT_ERROR_KEY } from '../../../../ui/app/helpers/constants/error-keys'
abiDecoder.addABI(abi)
const SIMPLE_GAS_COST = '0x5208' // Hex for 21000, cost of a simple send.
const MAX_MEMSTORE_TX_LIST_SIZE = 100 // Number of transactions (by unique nonces) to keep in memory
@ -53,7 +49,6 @@ const MAX_MEMSTORE_TX_LIST_SIZE = 100 // Number of transactions (by unique nonce
<br>- nonceTracker
calculating nonces
@class
@param {Object} - opts
@param {Object} opts.initState - initial transaction list default is an empty array
@ -133,12 +128,12 @@ export default class TransactionController extends EventEmitter {
*/
getChainId () {
const networkState = this.networkStore.getState()
// eslint-disable-next-line radix
const integerChainId = parseInt(networkState)
if (Number.isNaN(integerChainId)) {
return 0
} else {
return integerChainId
}
return integerChainId
}
/**
@ -200,6 +195,7 @@ export default class TransactionController extends EventEmitter {
const normalizedTxParams = txUtils.normalizeTxParams(txParams)
txUtils.validateTxParams(normalizedTxParams)
/**
`generateTxMeta` adds the default txMeta properties to the passed object.
These include the tx's `id`. As we use the id for determining order of
@ -232,7 +228,7 @@ export default class TransactionController extends EventEmitter {
}
}
txMeta['origin'] = origin
txMeta.origin = origin
const { transactionCategory, getCodeResponse } = await this._determineTransactionCategory(txParams)
txMeta.transactionCategory = transactionCategory
@ -271,6 +267,7 @@ export default class TransactionController extends EventEmitter {
const defaultGasPrice = await this._getDefaultGasPrice(txMeta)
const { gasLimit: defaultGasLimit, simulationFails } = await this._getDefaultGasLimit(txMeta, getCodeResponse)
// eslint-disable-next-line no-param-reassign
txMeta = this.txStateManager.getTx(txMeta.id)
if (simulationFails) {
txMeta.simulationFails = simulationFails
@ -287,11 +284,11 @@ export default class TransactionController extends EventEmitter {
/**
* Gets default gas price, or returns `undefined` if gas price is already set
* @param {Object} txMeta - The txMeta object
* @returns {Promise<string>} The default gas price
* @returns {Promise<string|undefined>} The default gas price
*/
async _getDefaultGasPrice (txMeta) {
if (txMeta.txParams.gasPrice) {
return
return undefined
}
const gasPrice = await this.query.gasPrice()
@ -472,8 +469,8 @@ export default class TransactionController extends EventEmitter {
// this is try-catch wrapped so that we can guarantee that the nonceLock is released
try {
this.txStateManager.setTxStatusFailed(txId, err)
} catch (err) {
log.error(err)
} catch (err2) {
log.error(err2)
}
// must set transaction to submitted/failed before releasing lock
if (nonceLock) {
@ -495,7 +492,7 @@ export default class TransactionController extends EventEmitter {
const txMeta = this.txStateManager.getTx(txId)
// add network/chain id
const chainId = this.getChainId()
const txParams = Object.assign({}, txMeta.txParams, { chainId })
const txParams = { ...txMeta.txParams, chainId }
// sign tx
const fromAddress = txParams.from
const ethTx = new Transaction(txParams)
@ -560,9 +557,9 @@ export default class TransactionController extends EventEmitter {
// It seems that sometimes the numerical values being returned from
// this.query.getTransactionReceipt are BN instances and not strings.
const gasUsed = typeof txReceipt.gasUsed !== 'string'
? txReceipt.gasUsed.toString(16)
: txReceipt.gasUsed
const gasUsed = typeof txReceipt.gasUsed === 'string'
? txReceipt.gasUsed
: txReceipt.gasUsed.toString(16)
txMeta.txReceipt = {
...txReceipt,
@ -604,19 +601,25 @@ export default class TransactionController extends EventEmitter {
//
/** maps methods for convenience*/
_mapMethods () {
/** @returns {Object} - the state in transaction controller */
this.getState = () => this.memStore.getState()
/** @returns {string|number} - the network number stored in networkStore */
this.getNetwork = () => this.networkStore.getState()
/** @returns {string} - the user selected address */
this.getSelectedAddress = () => this.preferencesStore.getState().selectedAddress
/** @returns {array} - transactions whos status is unapproved */
this.getUnapprovedTxCount = () => Object.keys(this.txStateManager.getUnapprovedTxList()).length
/**
@returns {number} - number of transactions that have the status submitted
@param {string} account - hex prefixed account
*/
this.getPendingTxCount = (account) => this.txStateManager.getPendingTransactions(account).length
/** see txStateManager */
this.getFilteredTxList = (opts) => this.txStateManager.getFilteredTxList(opts)
}
@ -684,7 +687,7 @@ export default class TransactionController extends EventEmitter {
if (!('retryCount' in txMeta)) {
txMeta.retryCount = 0
}
txMeta.retryCount++
txMeta.retryCount += 1
this.txStateManager.updateTx(txMeta, 'transactions/pending-tx-tracker#event: tx:retry')
})
}
@ -700,7 +703,7 @@ export default class TransactionController extends EventEmitter {
TOKEN_METHOD_APPROVE,
TOKEN_METHOD_TRANSFER,
TOKEN_METHOD_TRANSFER_FROM,
].find((tokenMethodName) => tokenMethodName === name && name.toLowerCase())
].find((methodName) => methodName === name && name.toLowerCase())
let result
if (txParams.data && tokenMethodName) {
@ -754,8 +757,7 @@ export default class TransactionController extends EventEmitter {
_setupBlockTrackerListener () {
let listenersAreActive = false
const latestBlockHandler = this._onLatestBlock.bind(this)
const blockTracker = this.blockTracker
const txStateManager = this.txStateManager
const { blockTracker, txStateManager } = this
txStateManager.on('tx:status-update', updateSubscription)
updateSubscription()

View File

@ -15,11 +15,11 @@ import EthQuery from 'ethjs-query'
@param {function} config.getPendingTransactions a function for getting an array of transactions,
@param {function} config.publishTransaction a async function for publishing raw transactions,
@class
*/
export default class PendingTransactionTracker extends EventEmitter {
/**
* We wait this many blocks before emitting a 'tx:dropped' event
*
@ -129,7 +129,7 @@ export default class PendingTransactionTracker extends EventEmitter {
// Exponential backoff to limit retries at publishing
if (txBlockDistance <= Math.pow(2, retryCount) - 1) {
return
return undefined
}
// Only auto-submit already-signed txs:
@ -137,7 +137,7 @@ export default class PendingTransactionTracker extends EventEmitter {
return this.approveTransaction(txMeta.id)
}
const rawTx = txMeta.rawTx
const { rawTx } = txMeta
const txHash = await this.publishTransaction(rawTx)
// Increment successful tries:
@ -196,7 +196,6 @@ export default class PendingTransactionTracker extends EventEmitter {
if (await this._checkIfTxWasDropped(txMeta)) {
this.emit('tx:dropped', txId)
return
}
}
@ -239,11 +238,11 @@ export default class PendingTransactionTracker extends EventEmitter {
async _checkIfNonceIsTaken (txMeta) {
const address = txMeta.txParams.from
const completed = this.getCompletedTransactions(address)
return completed.some((other) =>
return completed.some(
// This is called while the transaction is in-flight, so it is possible that the
// list of completed transactions now includes the transaction we were looking at
// and if that is the case, don't consider the transaction to have taken its own nonce
!(other.id === txMeta.id) && other.txParams.nonce === txMeta.txParams.nonce,
(other) => !(other.id === txMeta.id) && other.txParams.nonce === txMeta.txParams.nonce,
)
}
}

View File

@ -1,6 +1,6 @@
import EthQuery from 'ethjs-query'
import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util'
import log from 'loglevel'
import { hexToBn, BnMultiplyByFraction, bnToHex } from '../../lib/util'
/**
* Result of gas analysis, including either a gas estimate for a successful analysis, or
@ -56,7 +56,7 @@ export default class TxGasUtil {
@returns {string} - the estimated gas limit as a hex string
*/
async estimateTxGas (txMeta) {
const txParams = txMeta.txParams
const { txParams } = txMeta
// estimate tx gas requirements
return await this.query.estimateGas(txParams)

View File

@ -1,9 +1,10 @@
import EventEmitter from 'safe-event-emitter'
import ObservableStore from 'obs-store'
import log from 'loglevel'
import { generateHistoryEntry, replayHistory, snapshotFromTxMeta } from './lib/tx-state-history-helpers'
import createId from '../../lib/random-id'
import { generateHistoryEntry, replayHistory, snapshotFromTxMeta } from './lib/tx-state-history-helpers'
import { getFinalStates, normalizeTxParams } from './lib/util'
/**
TransactionStateManager is responsible for the state of a transaction and
storing the transaction
@ -31,9 +32,8 @@ export default class TransactionStateManager extends EventEmitter {
super()
this.store = new ObservableStore(
Object.assign({
transactions: [],
}, initState))
{ transactions: [], ...initState },
)
this.txHistoryLimit = txHistoryLimit
this.getNetwork = getNetwork
}
@ -47,13 +47,13 @@ export default class TransactionStateManager extends EventEmitter {
if (netId === 'loading') {
throw new Error('MetaMask is having trouble connecting to the network')
}
return Object.assign({
return {
id: createId(),
time: (new Date()).getTime(),
status: 'unapproved',
metamaskNetworkId: netId,
loadingDefaults: true,
}, opts)
loadingDefaults: true, ...opts,
}
}
/**
@ -164,10 +164,10 @@ export default class TransactionStateManager extends EventEmitter {
txMeta.txParams = this.normalizeAndValidateTxParams(txMeta.txParams)
}
this.once(`${txMeta.id}:signed`, function () {
this.once(`${txMeta.id}:signed`, () => {
this.removeAllListeners(`${txMeta.id}:rejected`)
})
this.once(`${txMeta.id}:rejected`, function () {
this.once(`${txMeta.id}:rejected`, () => {
this.removeAllListeners(`${txMeta.id}:signed`)
})
// initialize history
@ -178,7 +178,7 @@ export default class TransactionStateManager extends EventEmitter {
const transactions = this.getFullTxList()
const txCount = transactions.length
const txHistoryLimit = this.txHistoryLimit
const { txHistoryLimit } = this
// checks if the length of the tx history is
// longer then desired persistence limit
@ -202,6 +202,7 @@ export default class TransactionStateManager extends EventEmitter {
this._saveTxList(transactions)
return txMeta
}
/**
@param {number} txId
@returns {Object} - the txMeta who matches the given id if none found
@ -241,7 +242,6 @@ export default class TransactionStateManager extends EventEmitter {
this._saveTxList(txList)
}
/**
merges txParams obj onto txMeta.txParams
use extend to ensure that all fields are filled
@ -262,6 +262,7 @@ export default class TransactionStateManager extends EventEmitter {
if (typeof txParams.data === 'undefined') {
delete txParams.data
}
// eslint-disable-next-line no-param-reassign
txParams = normalizeTxParams(txParams, false)
this.validateTxParams(txParams)
return txParams
@ -325,6 +326,7 @@ export default class TransactionStateManager extends EventEmitter {
})
return filteredTxList
}
/**
@param {string} key - the key to check
@ -339,9 +341,8 @@ export default class TransactionStateManager extends EventEmitter {
return txList.filter((txMeta) => {
if (key in txMeta.txParams) {
return filter(txMeta.txParams[key])
} else {
return filter(txMeta[key])
}
return filter(txMeta[key])
})
}
@ -372,6 +373,7 @@ export default class TransactionStateManager extends EventEmitter {
setTxStatusUnapproved (txId) {
this._setTxStatus(txId, 'unapproved')
}
/**
should update the status of the tx to 'approved'.
@param {number} txId - the txMeta Id
@ -416,7 +418,6 @@ export default class TransactionStateManager extends EventEmitter {
this._setTxStatus(txId, 'dropped')
}
/**
should update the status of the tx to 'failed'.
and put the error on the txMeta
@ -424,7 +425,7 @@ export default class TransactionStateManager extends EventEmitter {
@param {erroObject} err - error object
*/
setTxStatusFailed (txId, err) {
const error = !err ? new Error('Internal metamask failure') : err
const error = err || new Error('Internal metamask failure')
const txMeta = this.getTx(txId)
txMeta.err = {

View File

@ -30,12 +30,14 @@ const restoreContextAfterImports = () => {
cleanContextForImports()
/* eslint-disable import/first */
import log from 'loglevel'
import LocalMessageDuplexStream from 'post-message-stream'
import { initProvider } from '@metamask/inpage-provider'
// TODO:deprecate:2020
import setupWeb3 from './lib/setupWeb3.js'
import setupWeb3 from './lib/setupWeb3'
/* eslint-enable import/first */
restoreContextAfterImports()
@ -58,7 +60,6 @@ initProvider({
// TODO:deprecate:2020
// Setup web3
if (typeof window.web3 !== 'undefined') {
throw new Error(`MetaMask detected another web3.
MetaMask will not work reliably with another web3 extension.

View File

@ -5,6 +5,7 @@ import ObservableStore from 'obs-store'
* structure of child stores based on configuration
*/
export default class ComposableObservableStore extends ObservableStore {
/**
* Create a new store
*
@ -25,7 +26,7 @@ export default class ComposableObservableStore extends ObservableStore {
this.config = config
this.removeAllListeners()
for (const key in config) {
if (config.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(config, key)) {
config[key].subscribe((state) => {
this.updateState({ [key]: state })
})
@ -42,7 +43,7 @@ export default class ComposableObservableStore extends ObservableStore {
getFlatState () {
let flatState = {}
for (const key in this.config) {
if (this.config.hasOwnProperty(key)) {
if (Object.prototype.hasOwnProperty.call(this.config, key)) {
const controller = this.config[key]
const state = controller.getState ? controller.getState() : controller.state
flatState = { ...flatState, ...state }

View File

@ -14,7 +14,6 @@ import log from 'loglevel'
import pify from 'pify'
import Web3 from 'web3'
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi'
import { bnToHex } from './util'
import { MAINNET_NETWORK_ID, RINKEBY_NETWORK_ID, ROPSTEN_NETWORK_ID, KOVAN_NETWORK_ID } from '../controllers/network/enums'
import {
@ -23,6 +22,7 @@ import {
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
} from '../controllers/network/contract-addresses'
import { bnToHex } from './util'
export default class AccountTracker {
@ -92,7 +92,7 @@ export default class AccountTracker {
*
*/
syncWithAddresses (addresses) {
const accounts = this.store.getState().accounts
const { accounts } = this.store.getState()
const locals = Object.keys(accounts)
const accountsToAdd = []
@ -121,7 +121,7 @@ export default class AccountTracker {
*
*/
addAccounts (addresses) {
const accounts = this.store.getState().accounts
const { accounts } = this.store.getState()
// add initial state for addresses
addresses.forEach((address) => {
accounts[address] = {}
@ -142,7 +142,7 @@ export default class AccountTracker {
*
*/
removeAccount (addresses) {
const accounts = this.store.getState().accounts
const { accounts } = this.store.getState()
// remove each state object
addresses.forEach((address) => {
delete accounts[address]
@ -194,7 +194,7 @@ export default class AccountTracker {
*
*/
async _updateAccounts () {
const accounts = this.store.getState().accounts
const { accounts } = this.store.getState()
const addresses = Object.keys(accounts)
const currentNetwork = this.network.getNetworkState()
@ -248,7 +248,7 @@ export default class AccountTracker {
* @param {*} deployedContractAddress
*/
async _updateAccountsViaBalanceChecker (addresses, deployedContractAddress) {
const accounts = this.store.getState().accounts
const { accounts } = this.store.getState()
this.web3.setProvider(this._provider)
const ethContract = this.web3.eth.contract(SINGLE_CALL_BALANCES_ABI).at(deployedContractAddress)
const ethBalance = ['0x0']
@ -256,7 +256,8 @@ export default class AccountTracker {
ethContract.balances(addresses, ethBalance, (error, result) => {
if (error) {
log.warn(`MetaMask - Account Tracker single call balance fetch failed`, error)
return Promise.all(addresses.map(this._updateAccount.bind(this)))
Promise.all(addresses.map(this._updateAccount.bind(this)))
return
}
addresses.forEach((address, index) => {
const balance = bnToHex(result[index])

View File

@ -2,9 +2,6 @@ import { getBackgroundMetaMetricState } from '../../../ui/app/selectors'
import { sendMetaMetricsEvent } from '../../../ui/app/helpers/utils/metametrics.util'
export default function backgroundMetaMetricsEvent (metaMaskState, version, eventData) {
eventData.eventOpts['category'] = 'Background'
const stateEventData = getBackgroundMetaMetricState({ metamask: metaMaskState })
if (stateEventData.participateInMetaMetrics) {
sendMetaMetricsEvent({

View File

@ -11,6 +11,7 @@
export default function getBuyEthUrl ({ network, address, service }) {
// default service by network if not specified
if (!service) {
// eslint-disable-next-line no-param-reassign
service = getDefaultServiceForNetwork(network)
}

View File

@ -4,7 +4,7 @@
* @returns {Error} - Error with clean stack trace.
*/
export default function cleanErrorStack (err) {
let name = err.name
let { name } = err
name = (name === undefined) ? 'Error' : String(name)
let msg = err.message
@ -15,7 +15,7 @@ export default function cleanErrorStack (err) {
} else if (msg === '') {
err.stack = err.name
} else {
err.stack = err.name + ': ' + err.message
err.stack = `${err.name}: ${err.message}`
}
return err

View File

@ -14,7 +14,7 @@ export default function createMethodMiddleware ({ origin, sendMetrics }) {
return function methodMiddleware (req, res, next, end) {
switch (req.method) {
case 'metamask_logInjectedWeb3Usage':
case 'metamask_logInjectedWeb3Usage': {
const { action, name } = req.params[0]
@ -32,6 +32,7 @@ export default function createMethodMiddleware ({ origin, sendMetrics }) {
res.result = true
break
}
default:
return next()

View File

@ -4,7 +4,7 @@ import promiseToCallback from 'promise-to-callback'
class AsyncWritableStream extends WritableStream {
constructor (asyncWriteFn, _opts) {
const opts = Object.assign({ objectMode: true }, _opts)
const opts = { objectMode: true, ..._opts }
super(opts)
this._asyncWriteFn = asyncWriteFn
}

View File

@ -2,11 +2,11 @@ import EventEmitter from 'events'
import ObservableStore from 'obs-store'
import ethUtil from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import log from 'loglevel'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/g
import log from 'loglevel'
const hexRe = /^[0-9A-Fa-f]+$/ug
/**
* Represents, and contains data about, an 'eth_decrypt' type decryption request. These are created when a
@ -26,6 +26,7 @@ import log from 'loglevel'
*/
export default class DecryptMessageManager extends EventEmitter {
/**
* Controller in charge of managing - storing, adding, removing, updating - DecryptMessage.
*
@ -65,7 +66,8 @@ export default class DecryptMessageManager extends EventEmitter {
getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => {
result[msg.id] = msg; return result
result[msg.id] = msg
return result
}, {})
}
@ -82,19 +84,23 @@ export default class DecryptMessageManager extends EventEmitter {
addUnapprovedMessageAsync (msgParams, req) {
return new Promise((resolve, reject) => {
if (!msgParams.from) {
return reject(new Error('MetaMask Decryption: from field is required.'))
reject(new Error('MetaMask Decryption: from field is required.'))
return
}
const msgId = this.addUnapprovedMessage(msgParams, req)
this.once(`${msgId}:finished`, (data) => {
switch (data.status) {
case 'decrypted':
return resolve(data.rawData)
resolve(data.rawData)
return
case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask Decryption: User denied message decryption.'))
reject(ethErrors.provider.userRejectedRequest('MetaMask Decryption: User denied message decryption.'))
return
case 'errored':
return reject(new Error('This message cannot be decrypted'))
reject(new Error('This message cannot be decrypted'))
return
default:
return reject(new Error(`MetaMask Decryption: Unknown problem: ${JSON.stringify(msgParams)}`))
reject(new Error(`MetaMask Decryption: Unknown problem: ${JSON.stringify(msgParams)}`))
}
})
})
@ -122,8 +128,8 @@ export default class DecryptMessageManager extends EventEmitter {
const msgId = createId()
const msgData = {
id: msgId,
msgParams: msgParams,
time: time,
msgParams,
time,
status: 'unapproved',
type: MESSAGE_TYPE.ETH_DECRYPT,
}
@ -248,7 +254,7 @@ export default class DecryptMessageManager extends EventEmitter {
_setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId)
if (!msg) {
throw new Error('DecryptMessageManager - Message not found for id: "${msgId}".')
throw new Error(`DecryptMessageManager - Message not found for id: "${msgId}".`)
}
msg.status = status
this._updateMsg(msg)

View File

@ -1,8 +1,8 @@
import EventEmitter from 'events'
import ObservableStore from 'obs-store'
import { ethErrors } from 'eth-json-rpc-errors'
import createId from './random-id'
import log from 'loglevel'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
/**
@ -23,6 +23,7 @@ import { MESSAGE_TYPE } from './enums'
*/
export default class EncryptionPublicKeyManager extends EventEmitter {
/**
* Controller in charge of managing - storing, adding, removing, updating - EncryptionPublicKey.
*
@ -62,7 +63,8 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => {
result[msg.id] = msg; return result
result[msg.id] = msg
return result
}, {})
}
@ -79,17 +81,20 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
addUnapprovedMessageAsync (address, req) {
return new Promise((resolve, reject) => {
if (!address) {
return reject(new Error('MetaMask Message: address field is required.'))
reject(new Error('MetaMask Message: address field is required.'))
return
}
const msgId = this.addUnapprovedMessage(address, req)
this.once(`${msgId}:finished`, (data) => {
switch (data.status) {
case 'received':
return resolve(data.rawData)
resolve(data.rawData)
return
case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.'))
reject(ethErrors.provider.userRejectedRequest('MetaMask EncryptionPublicKey: User denied message EncryptionPublicKey.'))
return
default:
return reject(new Error(`MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify(address)}`))
reject(new Error(`MetaMask EncryptionPublicKey: Unknown problem: ${JSON.stringify(address)}`))
}
})
})
@ -113,7 +118,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
const msgData = {
id: msgId,
msgParams: address,
time: time,
time,
status: 'unapproved',
type: MESSAGE_TYPE.ETH_GET_ENCRYPTION_PUBLIC_KEY,
}
@ -243,7 +248,7 @@ export default class EncryptionPublicKeyManager extends EventEmitter {
_setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId)
if (!msg) {
throw new Error('EncryptionPublicKeyManager - Message not found for id: "${msgId}".')
throw new Error(`EncryptionPublicKeyManager - Message not found for id: "${msgId}".`)
}
msg.status = status
this._updateMsg(msg)

View File

@ -1,9 +1,9 @@
import namehash from 'eth-ens-namehash'
import Eth from 'ethjs-query'
import EthContract from 'ethjs-contract'
import contentHash from 'content-hash'
import registryAbi from './contracts/registry'
import resolverAbi from './contracts/resolver'
import contentHash from 'content-hash'
export default async function resolveEnsToIpfsContentId ({ provider, name }) {
const eth = new Eth(provider)
@ -36,7 +36,7 @@ export default async function resolveEnsToIpfsContentId ({ provider, name }) {
decodedContentHash = contentHash.helpers.cidV0ToV1Base32(decodedContentHash)
}
return { type: type, hash: decodedContentHash }
return { type, hash: decodedContentHash }
}
if (isLegacyResolver[0]) {
// lookup content id

View File

@ -1,6 +1,6 @@
import urlUtil from 'url'
import extension from 'extensionizer'
import resolveEnsToIpfsContentId from './resolver.js'
import resolveEnsToIpfsContentId from './resolver'
const supportedTopLevelDomains = ['eth']

View File

@ -19,7 +19,6 @@ export default function extractEthjsErrorMessage (errorMessage) {
const payloadAndError = errorMessage.slice(ethJsRpcSlug.length)
const originalError = payloadAndError.slice(payloadAndError.indexOf(errorLabelPrefix) + errorLabelPrefix.length)
return originalError
} else {
return errorMessage
}
return errorMessage
}

View File

@ -30,11 +30,11 @@ function freeze (target, key, value, enumerable = true) {
configurable: false, writable: false,
}
if (value !== undefined) {
if (value === undefined) {
target[key] = deepFreeze(target[key])
} else {
opts.value = deepFreeze(value)
opts.enumerable = enumerable
} else {
target[key] = deepFreeze(target[key])
}
Object.defineProperty(target, key, opts)

View File

@ -40,7 +40,7 @@ export default async function getFirstPreferredLangCode () {
const firstPreferredLangCode = userPreferredLocaleCodes
.map((code) => code.toLowerCase().replace('_', '-'))
.find((code) => existingLocaleCodes.hasOwnProperty(code))
.find((code) => Object.prototype.hasOwnProperty.call(existingLocaleCodes, code))
return existingLocaleCodes[firstPreferredLangCode] || 'en'
}

View File

@ -6,11 +6,12 @@ import { checkForError } from './util'
* A wrapper around the extension's storage local API
*/
export default class ExtensionStore {
/**
* @constructor
*/
constructor () {
this.isSupported = !!(extension.storage.local)
this.isSupported = Boolean(extension.storage.local)
if (!this.isSupported) {
log.error('Storage local API not available.')
}
@ -29,9 +30,8 @@ export default class ExtensionStore {
// if the object is empty, treat it as undefined
if (isEmpty(result)) {
return undefined
} else {
return result
}
return result
}
/**
@ -49,7 +49,7 @@ export default class ExtensionStore {
* @returns {Object} - the key-value map from local storage
*/
_get () {
const local = extension.storage.local
const { local } = extension.storage
return new Promise((resolve, reject) => {
local.get(null, (/** @type {any} */ result) => {
const err = checkForError()
@ -69,7 +69,7 @@ export default class ExtensionStore {
* @private
*/
_set (obj) {
const local = extension.storage.local
const { local } = extension.storage
return new Promise((resolve, reject) => {
local.set(obj, () => {
const err = checkForError()

View File

@ -64,7 +64,8 @@ export default class MessageManager extends EventEmitter {
getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => {
result[msg.id] = msg; return result
result[msg.id] = msg
return result
}, {})
}
@ -114,8 +115,8 @@ export default class MessageManager extends EventEmitter {
const msgId = createId()
const msgData = {
id: msgId,
msgParams: msgParams,
time: time,
msgParams,
time,
status: 'unapproved',
type: MESSAGE_TYPE.ETH_SIGN,
}
@ -225,7 +226,7 @@ export default class MessageManager extends EventEmitter {
_setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId)
if (!msg) {
throw new Error('MessageManager - Message not found for id: "${msgId}".')
throw new Error(`MessageManager - Message not found for id: "${msgId}".`)
}
msg.status = status
this._updateMsg(msg)
@ -278,8 +279,7 @@ function normalizeMsgData (data) {
if (data.slice(0, 2) === '0x') {
// data is already hex
return data
} else {
// data is unicode, convert to hex
return ethUtil.bufferToHex(Buffer.from(data, 'utf8'))
}
// data is unicode, convert to hex
return ethUtil.bufferToHex(Buffer.from(data, 'utf8'))
}

View File

@ -46,6 +46,7 @@ export default class Migrator extends EventEmitter {
throw new Error('Migrator - Migration did not update version number correctly')
}
// accept the migration as good
// eslint-disable-next-line no-param-reassign
versionedData = migratedData
} catch (err) {
// rewrite error message to add context without clobbering stack

View File

@ -15,9 +15,7 @@ const callbackNoop = function (err) {
*
*/
export default function nodeify (fn, context) {
return function () {
// parse arguments
const args = [].slice.call(arguments)
return function (...args) {
const lastArg = args[args.length - 1]
const lastArgIsCallback = typeof lastArg === 'function'
let callback

View File

@ -2,11 +2,11 @@ import EventEmitter from 'events'
import ObservableStore from 'obs-store'
import ethUtil from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import log from 'loglevel'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/g
import log from 'loglevel'
const hexRe = /^[0-9A-Fa-f]+$/ug
/**
* Represents, and contains data about, an 'personal_sign' type signature request. These are created when a
@ -28,6 +28,7 @@ import log from 'loglevel'
*/
export default class PersonalMessageManager extends EventEmitter {
/**
* Controller in charge of managing - storing, adding, removing, updating - PersonalMessage.
*
@ -68,7 +69,8 @@ export default class PersonalMessageManager extends EventEmitter {
getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => {
result[msg.id] = msg; return result
result[msg.id] = msg
return result
}, {})
}
@ -85,17 +87,20 @@ export default class PersonalMessageManager extends EventEmitter {
addUnapprovedMessageAsync (msgParams, req) {
return new Promise((resolve, reject) => {
if (!msgParams.from) {
return reject(new Error('MetaMask Message Signature: from field is required.'))
reject(new Error('MetaMask Message Signature: from field is required.'))
return
}
const msgId = this.addUnapprovedMessage(msgParams, req)
this.once(`${msgId}:finished`, (data) => {
switch (data.status) {
case 'signed':
return resolve(data.rawSig)
resolve(data.rawSig)
return
case 'rejected':
return reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.'))
reject(ethErrors.provider.userRejectedRequest('MetaMask Message Signature: User denied message signature.'))
return
default:
return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))
reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`))
}
})
})
@ -123,8 +128,8 @@ export default class PersonalMessageManager extends EventEmitter {
const msgId = createId()
const msgData = {
id: msgId,
msgParams: msgParams,
time: time,
msgParams,
time,
status: 'unapproved',
type: MESSAGE_TYPE.PERSONAL_SIGN,
}

View File

@ -2,6 +2,7 @@ const MAX = Number.MAX_SAFE_INTEGER
let idCounter = Math.round(Math.random() * MAX)
export default function createRandomId () {
idCounter = idCounter % MAX
idCounter %= MAX
// eslint-disable-next-line no-plusplus
return idCounter++
}

View File

@ -30,8 +30,8 @@ const seedPhraseVerifier = {
const keyring = new Keyring(opts)
const restoredAccounts = await keyring.getAccounts()
log.debug('Created accounts: ' + JSON.stringify(createdAccounts))
log.debug('Restored accounts: ' + JSON.stringify(restoredAccounts))
log.debug(`Created accounts: ${JSON.stringify(createdAccounts)}`)
log.debug(`Restored accounts: ${JSON.stringify(restoredAccounts)}`)
if (restoredAccounts.length !== createdAccounts.length) {
// this should not happen...
@ -40,7 +40,7 @@ const seedPhraseVerifier = {
for (let i = 0; i < restoredAccounts.length; i++) {
if (restoredAccounts[i].toLowerCase() !== createdAccounts[i].toLowerCase()) {
throw new Error('Not identical accounts! Original: ' + createdAccounts[i] + ', Restored: ' + restoredAccounts[i])
throw new Error(`Not identical accounts! Original: ${createdAccounts[i]}, Restored: ${restoredAccounts[i]}`)
}
}
},

View File

@ -3,8 +3,7 @@ import { Dedupe, ExtraErrorData } from '@sentry/integrations'
import extractEthjsErrorMessage from './extractEthjsErrorMessage'
const METAMASK_DEBUG = process.env.METAMASK_DEBUG
const METAMASK_ENVIRONMENT = process.env.METAMASK_ENVIRONMENT
const { METAMASK_DEBUG, METAMASK_ENVIRONMENT } = process.env
const SENTRY_DSN_DEV = 'https://f59f3dd640d2429d9d0e2445a87ea8e1@sentry.io/273496'
// This describes the subset of Redux state attached to errors sent to Sentry
@ -72,7 +71,7 @@ export default function setupSentry ({ release, getState }) {
let sentryTarget
if (METAMASK_DEBUG) {
return
return undefined
} else if (METAMASK_ENVIRONMENT === 'production') {
if (!process.env.SENTRY_DSN) {
throw new Error(`Missing SENTRY_DSN environment variable in production environment`)
@ -122,13 +121,13 @@ export default function setupSentry ({ release, getState }) {
function simplifyErrorMessages (report) {
rewriteErrorMessages(report, (errorMessage) => {
// simplify ethjs error messages
errorMessage = extractEthjsErrorMessage(errorMessage)
let simplifiedErrorMessage = extractEthjsErrorMessage(errorMessage)
// simplify 'Transaction Failed: known transaction'
if (errorMessage.indexOf('Transaction Failed: known transaction') === 0) {
if (simplifiedErrorMessage.indexOf('Transaction Failed: known transaction') === 0) {
// cut the hash from the error message
errorMessage = 'Transaction Failed: known transaction'
simplifiedErrorMessage = 'Transaction Failed: known transaction'
}
return errorMessage
return simplifiedErrorMessage
})
}

View File

@ -3,7 +3,7 @@
// TODO:deprecate:2020
// Delete this file
import 'web3/dist/web3.min.js'
import 'web3/dist/web3.min'
const shouldLogUsage = !([
'docs.metamask.io',

View File

@ -1,12 +1,12 @@
import EventEmitter from 'events'
import ObservableStore from 'obs-store'
import createId from './random-id'
import assert from 'assert'
import ObservableStore from 'obs-store'
import { ethErrors } from 'eth-json-rpc-errors'
import sigUtil from 'eth-sig-util'
import { isValidAddress } from 'ethereumjs-util'
import log from 'loglevel'
import jsonschema from 'jsonschema'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
/**
@ -28,6 +28,7 @@ import { MESSAGE_TYPE } from './enums'
*/
export default class TypedMessageManager extends EventEmitter {
/**
* Controller in charge of managing - storing, adding, removing, updating - TypedMessage.
*/
@ -61,7 +62,8 @@ export default class TypedMessageManager extends EventEmitter {
getUnapprovedMsgs () {
return this.messages.filter((msg) => msg.status === 'unapproved')
.reduce((result, msg) => {
result[msg.id] = msg; return result
result[msg.id] = msg
return result
}, {})
}
@ -118,8 +120,8 @@ export default class TypedMessageManager extends EventEmitter {
const msgId = createId()
const msgData = {
id: msgId,
msgParams: msgParams,
time: time,
msgParams,
time,
status: 'unapproved',
type: MESSAGE_TYPE.ETH_SIGN_TYPED_DATA,
}
@ -154,7 +156,7 @@ export default class TypedMessageManager extends EventEmitter {
}, 'Signing data must be valid EIP-712 typed data.')
break
case 'V3':
case 'V4':
case 'V4': {
assert.equal(typeof params.data, 'string', '"params.data" must be a string.')
let data
assert.doesNotThrow(() => {
@ -163,10 +165,12 @@ export default class TypedMessageManager extends EventEmitter {
const validation = jsonschema.validate(data, sigUtil.TYPED_MESSAGE_SCHEMA)
assert.ok(data.primaryType in data.types, `Primary type of "${data.primaryType}" has no type definition.`)
assert.equal(validation.errors.length, 0, 'Signing data must conform to EIP-712 schema. See https://git.io/fNtcx.')
const chainId = data.domain.chainId
const { chainId } = data.domain
// eslint-disable-next-line radix
const activeChainId = parseInt(this.networkController.getNetworkState())
chainId && assert.equal(chainId, activeChainId, `Provided chainId "${chainId}" must match the active chainId "${activeChainId}"`)
break
}
default:
assert.fail(`Unknown typed data version "${params.version}"`)
}
@ -291,7 +295,7 @@ export default class TypedMessageManager extends EventEmitter {
_setMsgStatus (msgId, status) {
const msg = this.getMsg(msgId)
if (!msg) {
throw new Error('TypedMessageManager - Message not found for id: "${msgId}".')
throw new Error(`TypedMessageManager - Message not found for id: "${msgId}".`)
}
msg.status = status
this._updateMsg(msg)

View File

@ -1,6 +1,6 @@
import assert from 'assert'
import extension from 'extensionizer'
import ethUtil from 'ethereumjs-util'
import assert from 'assert'
import BN from 'bn.js'
import { memoize } from 'lodash'
@ -27,9 +27,8 @@ const getEnvironmentTypeMemo = memoize((url) => {
return ENVIRONMENT_TYPE_FULLSCREEN
} else if (parsedUrl.pathname === '/notification.html') {
return ENVIRONMENT_TYPE_NOTIFICATION
} else {
return ENVIRONMENT_TYPE_BACKGROUND
}
return ENVIRONMENT_TYPE_BACKGROUND
})
/**
@ -55,19 +54,19 @@ const getEnvironmentType = (url = window.location.href) => getEnvironmentTypeMem
*/
const getPlatform = (_) => {
const ua = window.navigator.userAgent
if (ua.search('Firefox') !== -1) {
return PLATFORM_FIREFOX
} else {
if (ua.search('Firefox') === -1) {
if (window && window.chrome && window.chrome.ipcRenderer) {
return PLATFORM_BRAVE
} else if (ua.search('Edge') !== -1) {
return PLATFORM_EDGE
} else if (ua.search('OPR') !== -1) {
return PLATFORM_OPERA
} else {
return PLATFORM_CHROME
}
if (ua.search('Edge') !== -1) {
return PLATFORM_EDGE
}
if (ua.search('OPR') !== -1) {
return PLATFORM_OPERA
}
return PLATFORM_CHROME
}
return PLATFORM_FIREFOX
}
/**
@ -135,12 +134,12 @@ function BnMultiplyByFraction (targetBN, numerator, denominator) {
/**
* Returns an Error if extension.runtime.lastError is present
* this is a workaround for the non-standard error object that's used
* @returns {Error}
* @returns {Error|undefined}
*/
function checkForError () {
const lastError = extension.runtime.lastError
const { lastError } = extension.runtime
if (!lastError) {
return
return undefined
}
// if it quacks like an Error, its an Error
if (lastError.stack && lastError.message) {

View File

@ -10,22 +10,35 @@ import pump from 'pump'
import Dnode from 'dnode'
import extension from 'extensionizer'
import ObservableStore from 'obs-store'
import ComposableObservableStore from './lib/ComposableObservableStore'
import asStream from 'obs-store/lib/asStream'
import AccountTracker from './lib/account-tracker'
import RpcEngine from 'json-rpc-engine'
import { debounce } from 'lodash'
import createEngineStream from 'json-rpc-middleware-stream/engineStream'
import createFilterMiddleware from 'eth-json-rpc-filters'
import createSubscriptionManager from 'eth-json-rpc-filters/subscriptionManager'
import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware'
import KeyringController from 'eth-keyring-controller'
import { Mutex } from 'await-semaphore'
import ethUtil from 'ethereumjs-util'
import log from 'loglevel'
import TrezorKeyring from 'eth-trezor-keyring'
import LedgerBridgeKeyring from '@metamask/eth-ledger-bridge-keyring'
import EthQuery from 'eth-query'
import nanoid from 'nanoid'
import contractMap from 'eth-contract-metadata'
import {
AddressBookController,
CurrencyRateController,
PhishingController,
} from '@metamask/controllers'
import ComposableObservableStore from './lib/ComposableObservableStore'
import AccountTracker from './lib/account-tracker'
import createLoggerMiddleware from './lib/createLoggerMiddleware'
import createMethodMiddleware from './lib/createMethodMiddleware'
import createOriginMiddleware from './lib/createOriginMiddleware'
import createTabIdMiddleware from './lib/createTabIdMiddleware'
import createOnboardingMiddleware from './lib/createOnboardingMiddleware'
import providerAsMiddleware from 'eth-json-rpc-middleware/providerAsMiddleware'
import { setupMultiplex } from './lib/stream-utils.js'
import KeyringController from 'eth-keyring-controller'
import { setupMultiplex } from './lib/stream-utils'
import EnsController from './controllers/ens'
import NetworkController from './controllers/network'
import PreferencesController from './controllers/preferences'
@ -47,25 +60,8 @@ import { PermissionsController } from './controllers/permissions'
import getRestrictedMethods from './controllers/permissions/restrictedMethods'
import nodeify from './lib/nodeify'
import accountImporter from './account-import-strategies'
import getBuyEthUrl from './lib/buy-eth-url'
import selectChainId from './lib/select-chain-id'
import { Mutex } from 'await-semaphore'
import { version } from '../manifest/_base.json'
import ethUtil from 'ethereumjs-util'
import seedPhraseVerifier from './lib/seed-phrase-verifier'
import log from 'loglevel'
import TrezorKeyring from 'eth-trezor-keyring'
import LedgerBridgeKeyring from '@metamask/eth-ledger-bridge-keyring'
import EthQuery from 'eth-query'
import nanoid from 'nanoid'
import contractMap from 'eth-contract-metadata'
import {
AddressBookController,
CurrencyRateController,
PhishingController,
} from '@metamask/controllers'
import backgroundMetaMetricsEvent from './lib/background-metametrics'
@ -82,6 +78,7 @@ export default class MetamaskController extends EventEmitter {
this.sendUpdate = debounce(this.privateSendUpdate.bind(this), 200)
this.opts = opts
this.platform = opts.platform
const initState = opts.initState || {}
this.recordFirstTimeInfo(initState)
@ -89,9 +86,6 @@ export default class MetamaskController extends EventEmitter {
// the only thing that uses controller connections are open metamask UI instances
this.activeControllerConnections = 0
// platform-specific api
this.platform = opts.platform
this.getRequestAccountTabIds = opts.getRequestAccountTabIds
this.getOpenMetamaskTabsIds = opts.getOpenMetamaskTabsIds
@ -222,6 +216,7 @@ export default class MetamaskController extends EventEmitter {
preferencesStore: this.preferencesController.store,
})
const version = this.platform.getVersion()
this.threeBoxController = new ThreeBoxController({
preferencesController: this.preferencesController,
addressBookController: this.addressBookController,
@ -278,7 +273,6 @@ export default class MetamaskController extends EventEmitter {
this.encryptionPublicKeyManager = new EncryptionPublicKeyManager()
this.typedMessageManager = new TypedMessageManager({ networkController: this.networkController })
this.store.updateStructure({
AppStateController: this.appStateController.store,
TransactionController: this.txController.store,
@ -336,6 +330,7 @@ export default class MetamaskController extends EventEmitter {
* Constructor helper: initialize a provider.
*/
initializeProvider () {
const version = this.platform.getVersion()
const providerOpts = {
static: {
eth_syncing: false,
@ -409,8 +404,8 @@ export default class MetamaskController extends EventEmitter {
* @returns {Object} - status
*/
getState () {
const vault = this.keyringController.store.getState().vault
const isInitialized = !!vault
const { vault } = this.keyringController.store.getState()
const isInitialized = Boolean(vault)
return {
...{ isInitialized },
@ -426,14 +421,16 @@ export default class MetamaskController extends EventEmitter {
* @returns {Object} - Object containing API functions.
*/
getApi () {
const keyringController = this.keyringController
const networkController = this.networkController
const onboardingController = this.onboardingController
const alertController = this.alertController
const permissionsController = this.permissionsController
const preferencesController = this.preferencesController
const threeBoxController = this.threeBoxController
const txController = this.txController
const {
keyringController,
networkController,
onboardingController,
alertController,
permissionsController,
preferencesController,
threeBoxController,
txController,
} = this
return {
// etc
@ -449,7 +446,6 @@ export default class MetamaskController extends EventEmitter {
setCurrentLocale: this.setCurrentLocale.bind(this),
markPasswordForgotten: this.markPasswordForgotten.bind(this),
unMarkPasswordForgotten: this.unMarkPasswordForgotten.bind(this),
buyEth: this.buyEth.bind(this),
safelistPhishingDomain: this.safelistPhishingDomain.bind(this),
getRequestAccountTabIds: (cb) => cb(null, this.getRequestAccountTabIds()),
getOpenMetamaskTabsIds: (cb) => cb(null, this.getOpenMetamaskTabsIds()),
@ -596,13 +592,11 @@ export default class MetamaskController extends EventEmitter {
vault = await this.keyringController.fullUpdate()
} else {
vault = await this.keyringController.createNewVaultAndKeychain(password)
const accounts = await this.keyringController.getAccounts()
this.preferencesController.setAddresses(accounts)
const addresses = await this.keyringController.getAccounts()
this.preferencesController.setAddresses(addresses)
this.selectFirstIdentity()
}
return vault
} catch (err) {
throw err
} finally {
releaseLock()
}
@ -618,7 +612,7 @@ export default class MetamaskController extends EventEmitter {
try {
let accounts, lastBalance
const keyringController = this.keyringController
const { keyringController } = this
// clear known identities
this.preferencesController.setAddresses([])
@ -658,8 +652,6 @@ export default class MetamaskController extends EventEmitter {
this.preferencesController.setAddresses(accounts)
this.selectFirstIdentity()
return vault
} catch (err) {
throw err
} finally {
releaseLock()
}
@ -714,15 +706,16 @@ export default class MetamaskController extends EventEmitter {
Object.keys(accountTokens).forEach((address) => {
const checksummedAddress = ethUtil.toChecksumAddress(address)
filteredAccountTokens[checksummedAddress] = {}
Object.keys(accountTokens[address]).forEach(
(networkType) => (filteredAccountTokens[checksummedAddress][networkType] = networkType !== 'mainnet' ?
accountTokens[address][networkType] :
accountTokens[address][networkType].filter(({ address }) => {
const tokenAddress = ethUtil.toChecksumAddress(address)
return contractMap[tokenAddress] ? contractMap[tokenAddress].erc20 : true
})
),
)
Object.keys(accountTokens[address]).forEach((networkType) => {
filteredAccountTokens[checksummedAddress][networkType] = networkType === 'mainnet'
? (
accountTokens[address][networkType].filter(({ address: tokenAddress }) => {
const checksumAddress = ethUtil.toChecksumAddress(tokenAddress)
return contractMap[checksumAddress] ? contractMap[checksumAddress].erc20 : true
})
)
: accountTokens[address][networkType]
})
})
const preferences = {
@ -751,7 +744,7 @@ export default class MetamaskController extends EventEmitter {
// transactions
let transactions = this.txController.store.getState().transactions
let { transactions } = this.txController.store.getState()
// delete tx for other accounts that we're not importing
transactions = transactions.filter((tx) => {
const checksummedTxFrom = ethUtil.toChecksumAddress(tx.txParams.from)
@ -934,7 +927,6 @@ export default class MetamaskController extends EventEmitter {
return { ...keyState, identities }
}
//
// Account Management
//
@ -949,7 +941,7 @@ export default class MetamaskController extends EventEmitter {
if (!primaryKeyring) {
throw new Error('MetamaskController - No HD Key Tree found')
}
const keyringController = this.keyringController
const { keyringController } = this
const oldAccounts = await keyringController.getAccounts()
const keyState = await keyringController.addNewAccount(primaryKeyring)
const newAccounts = await keyringController.getAccounts()
@ -1034,7 +1026,6 @@ export default class MetamaskController extends EventEmitter {
return address
}
/**
* Imports an account with the specified import strategy.
* These are defined in app/scripts/account-import-strategies
@ -1046,7 +1037,7 @@ export default class MetamaskController extends EventEmitter {
*/
async importAccountWithStrategy (strategy, args) {
const privateKey = await accountImporter.importAccount(strategy, args)
const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [ privateKey ])
const keyring = await this.keyringController.addNewKeyring('Simple Key Pair', [privateKey])
const accounts = await keyring.getAccounts()
// update accounts in preferences controller
const allAccounts = await this.keyringController.getAccounts()
@ -1119,12 +1110,12 @@ export default class MetamaskController extends EventEmitter {
* @param {string} msgId - The id of the message to cancel.
*/
cancelMessage (msgId, cb) {
const messageManager = this.messageManager
const { messageManager } = this
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
if (!cb || typeof cb !== 'function') {
return
}
cb(null, this.getState())
}
// personal_sign methods:
@ -1180,10 +1171,10 @@ export default class MetamaskController extends EventEmitter {
cancelPersonalMessage (msgId, cb) {
const messageManager = this.personalMessageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
if (!cb || typeof cb !== 'function') {
return
}
cb(null, this.getState())
}
// eth_decrypt methods
@ -1265,10 +1256,10 @@ export default class MetamaskController extends EventEmitter {
cancelDecryptMessage (msgId, cb) {
const messageManager = this.decryptMessageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
if (!cb || typeof cb !== 'function') {
return
}
cb(null, this.getState())
}
// eth_getEncryptionPublicKey methods
@ -1323,10 +1314,10 @@ export default class MetamaskController extends EventEmitter {
cancelEncryptionPublicKey (msgId, cb) {
const messageManager = this.encryptionPublicKeyManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
if (!cb || typeof cb !== 'function') {
return
}
cb(null, this.getState())
}
// eth_signTypedData methods
@ -1349,12 +1340,12 @@ export default class MetamaskController extends EventEmitter {
* Triggers the callback in newUnsignedTypedMessage.
*
* @param {Object} msgParams - The params passed to eth_signTypedData.
* @returns {Object} - Full state update.
* @returns {Object|undefined} - Full state update.
*/
async signTypedMessage (msgParams) {
log.info('MetaMaskController - eth_signTypedData')
const msgId = msgParams.metamaskId
const version = msgParams.version
const { version } = msgParams
try {
const cleanMsgParams = await this.typedMessageManager.approveMessage(msgParams)
@ -1372,6 +1363,7 @@ export default class MetamaskController extends EventEmitter {
} catch (error) {
log.info('MetaMaskController - eth_signTypedData failed.', error)
this.typedMessageManager.errorMessage(msgId, error)
return undefined
}
}
@ -1383,10 +1375,10 @@ export default class MetamaskController extends EventEmitter {
cancelTypedMessage (msgId, cb) {
const messageManager = this.typedMessageManager
messageManager.rejectMsg(msgId)
if (cb && typeof cb === 'function') {
cb(null, this.getState())
if (!cb || typeof cb !== 'function') {
return
}
cb(null, this.getState())
}
//=============================================================================
@ -1401,13 +1393,9 @@ export default class MetamaskController extends EventEmitter {
* @returns {Object} - MetaMask state
*/
async createCancelTransaction (originalTxId, customGasPrice) {
try {
await this.txController.createCancelTransaction(originalTxId, customGasPrice)
const state = await this.getState()
return state
} catch (error) {
throw error
}
await this.txController.createCancelTransaction(originalTxId, customGasPrice)
const state = await this.getState()
return state
}
async createSpeedUpTransaction (originalTxId, customGasPrice, customGasLimit) {
@ -1470,7 +1458,7 @@ export default class MetamaskController extends EventEmitter {
*/
setupUntrustedCommunication (connectionStream, sender) {
const { usePhishDetect } = this.preferencesController.store.getState()
const hostname = (new URL(sender.url)).hostname
const { hostname } = new URL(sender.url)
// Check if new connection is blocked if phishing detection is on
if (usePhishDetect && this.phishingController.test(hostname)) {
log.debug('MetaMask - sending phishing warning for', hostname)
@ -1526,7 +1514,7 @@ export default class MetamaskController extends EventEmitter {
const api = this.getApi()
const dnode = Dnode(api)
// report new active controller connection
this.activeControllerConnections++
this.activeControllerConnections += 1
this.emit('controllerConnectionChanged', this.activeControllerConnections)
// connect dnode api to remote connection
pump(
@ -1535,7 +1523,7 @@ export default class MetamaskController extends EventEmitter {
outStream,
(err) => {
// report new active controller connection
this.activeControllerConnections--
this.activeControllerConnections -= 1
this.emit('controllerConnectionChanged', this.activeControllerConnections)
// report any error
if (err) {
@ -1609,8 +1597,7 @@ export default class MetamaskController extends EventEmitter {
setupProviderEngine ({ origin, location, extensionId, tabId, isInternal = false }) {
// setup json rpc engine stack
const engine = new RpcEngine()
const provider = this.provider
const blockTracker = this.blockTracker
const { provider, blockTracker } = this
// create filter polyfill middleware
const filterMiddleware = createFilterMiddleware({ provider, blockTracker })
@ -1850,6 +1837,7 @@ export default class MetamaskController extends EventEmitter {
customVariables,
eventOpts: {
action,
category: 'Background',
name,
},
},
@ -1880,28 +1868,11 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
/**
* A method for forwarding the user to the easiest way to obtain ether,
* or the network "gas" currency, for the current selected network.
*
* @param {string} address - The address to fund.
* @param {string} amount - The amount of ether desired, as a base 10 string.
*/
buyEth (address, amount) {
if (!amount) {
amount = '5'
}
const network = this.networkController.getNetworkState()
const url = getBuyEthUrl({ network, address, amount })
if (url) {
this.platform.openTab({ url })
}
}
// network
/**
* A method for selecting a custom URL for an ethereum RPC provider and updating it
@ -1918,7 +1889,6 @@ export default class MetamaskController extends EventEmitter {
return rpcUrl
}
/**
* A method for selecting a custom URL for an ethereum RPC provider.
* @param {string} rpcTarget - A URL for a valid Ethereum RPC API.
@ -1964,6 +1934,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -1980,6 +1951,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -1996,6 +1968,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -2012,6 +1985,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -2028,6 +2002,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -2039,6 +2014,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -2055,11 +2031,11 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
/**
* A method for setting a user's current locale, affecting the language rendered.
* @param {string} key - Locale identifier.
@ -2072,6 +2048,7 @@ export default class MetamaskController extends EventEmitter {
return
} catch (err) {
cb(err)
// eslint-disable-next-line no-useless-return
return
}
}
@ -2083,6 +2060,7 @@ export default class MetamaskController extends EventEmitter {
*/
recordFirstTimeInfo (initState) {
if (!('firstTimeInfo' in initState)) {
const version = this.platform.getVersion()
initState.firstTimeInfo = {
version,
date: Date.now(),

View File

@ -1,12 +1,11 @@
const version = 2
import { cloneDeep } from 'lodash'
const version = 2
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -14,7 +13,9 @@ export default {
versionedData.data.config.provider.type = 'rpc'
versionedData.data.config.provider.rpcTarget = 'https://rpc.metamask.io/'
}
} catch (e) {}
} catch (_) {
// empty
}
return Promise.resolve(versionedData)
},
}

View File

@ -1,20 +1,22 @@
import { cloneDeep } from 'lodash'
const version = 3
const oldTestRpc = 'https://rawtestrpc.metamask.io/'
const newTestRpc = 'https://testrpc.metamask.io/'
import { cloneDeep } from 'lodash'
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
if (versionedData.data.config.provider.rpcTarget === oldTestRpc) {
versionedData.data.config.provider.rpcTarget = newTestRpc
}
} catch (e) {}
} catch (_) {
// empty
}
return Promise.resolve(versionedData)
},
}

View File

@ -1,11 +1,11 @@
const version = 4
import { cloneDeep } from 'lodash'
const version = 4
export default {
version,
migrate: function (versionedData) {
migrate (versionedData) {
const safeVersionedData = cloneDeep(versionedData)
safeVersionedData.meta.version = version
try {
@ -25,7 +25,9 @@ export default {
break
// No default
}
} catch (_) {}
} catch (_) {
// empty
}
return Promise.resolve(safeVersionedData)
},
}

View File

@ -1,5 +1,3 @@
const version = 5
/*
This migration moves state from the flat state trie into KeyringController substate
@ -8,11 +6,12 @@ This migration moves state from the flat state trie into KeyringController subst
import { cloneDeep } from 'lodash'
const version = 5
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -20,14 +19,14 @@ export default {
const newState = selectSubstateForKeyringController(state)
versionedData.data = newState
} catch (err) {
console.warn('MetaMask Migration #5' + err.stack)
console.warn(`MetaMask Migration #5${err.stack}`)
}
return Promise.resolve(versionedData)
},
}
function selectSubstateForKeyringController (state) {
const config = state.config
const { config } = state
const newState = {
...state,
KeyringController: {

View File

@ -1,5 +1,3 @@
const version = 6
/*
This migration moves KeyringController.selectedAddress to PreferencesController.selectedAddress
@ -8,10 +6,12 @@ This migration moves KeyringController.selectedAddress to PreferencesController.
import { cloneDeep } from 'lodash'
const version = 6
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = migrateState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 7
/*
This migration breaks out the TransactionManager substate
@ -8,10 +6,12 @@ This migration breaks out the TransactionManager substate
import { cloneDeep } from 'lodash'
const version = 7
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 8
/*
This migration breaks out the NoticeController substate
@ -8,10 +6,12 @@ This migration breaks out the NoticeController substate
import { cloneDeep } from 'lodash'
const version = 8
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 9
/*
This migration breaks out the CurrencyController substate
@ -8,10 +6,12 @@ This migration breaks out the CurrencyController substate
import { cloneDeep, merge } from 'lodash'
const version = 9
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 10
/*
This migration breaks out the ShapeShiftController substate
@ -8,10 +6,12 @@ This migration breaks out the ShapeShiftController substate
import { cloneDeep, merge } from 'lodash'
const version = 10
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 11
/*
This migration removes the discaimer state from our app, which was integrated into our notices.
@ -8,10 +6,12 @@ This migration removes the discaimer state from our app, which was integrated in
import { cloneDeep } from 'lodash'
const version = 11
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 12
/*
This migration modifies our notices to delete their body after being read.
@ -8,10 +6,12 @@ This migration modifies our notices to delete their body after being read.
import { cloneDeep } from 'lodash'
const version = 12
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 13
/*
This migration modifies the network config from ambiguous 'testnet' to explicit 'ropsten'
@ -8,10 +6,12 @@ This migration modifies the network config from ambiguous 'testnet' to explicit
import { cloneDeep } from 'lodash'
const version = 13
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 14
/*
This migration removes provider from config and moves it too NetworkController.
@ -8,10 +6,12 @@ This migration removes provider from config and moves it too NetworkController.
import { cloneDeep } from 'lodash'
const version = 14
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 15
/*
This migration sets transactions with the 'Gave up submitting tx.' err message
@ -9,10 +7,12 @@ to a 'failed' stated
import { cloneDeep } from 'lodash'
const version = 15
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -20,7 +20,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -30,7 +30,7 @@ function transformState (state) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = TransactionController.transactions
const { transactions } = TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (!txMeta.err) {
return txMeta

View File

@ -1,5 +1,3 @@
const version = 16
/*
This migration sets transactions with the 'Gave up submitting tx.' err message
@ -9,10 +7,12 @@ to a 'failed' stated
import { cloneDeep } from 'lodash'
const version = 16
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -20,7 +20,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -30,7 +30,7 @@ function transformState (state) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (!txMeta.err) {

View File

@ -1,5 +1,3 @@
const version = 17
/*
This migration sets transactions who were retried and marked as failed to submitted
@ -8,10 +6,12 @@ This migration sets transactions who were retried and marked as failed to submit
import { cloneDeep } from 'lodash'
const version = 17
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -29,7 +29,7 @@ function transformState (state) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (!txMeta.status === 'failed') {
return txMeta

View File

@ -1,5 +1,3 @@
const version = 18
/*
This migration updates "transaction state history" to diffs style
@ -12,11 +10,12 @@ import {
migrateFromSnapshotsToDiffs,
} from '../controllers/transactions/lib/tx-state-history-helpers'
const version = 18
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -24,7 +23,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -34,7 +33,7 @@ function transformState (state) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
// no history: initialize
if (!txMeta.history || txMeta.history.length === 0) {

View File

@ -1,6 +1,4 @@
const version = 19
/*
This migration sets transactions as failed
@ -10,10 +8,12 @@ whos nonce is too high
import { cloneDeep } from 'lodash'
const version = 19
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -21,7 +21,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -32,7 +32,7 @@ function transformState (state) {
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta, _, txList) => {
if (txMeta.status !== 'submitted') {
@ -66,13 +66,13 @@ function transformState (state) {
function getHighestContinuousFrom (txList, startPoint) {
const nonces = txList.map((txMeta) => {
const nonce = txMeta.txParams.nonce
const { nonce } = txMeta.txParams
return parseInt(nonce, 16)
})
let highest = startPoint
while (nonces.includes(highest)) {
highest++
highest += 1
}
return highest
@ -80,7 +80,7 @@ function getHighestContinuousFrom (txList, startPoint) {
function getHighestNonce (txList) {
const nonces = txList.map((txMeta) => {
const nonce = txMeta.txParams.nonce
const { nonce } = txMeta.txParams
return parseInt(nonce || '0x0', 16)
})
const highestNonce = Math.max.apply(null, nonces)

View File

@ -1,5 +1,3 @@
const version = 20
/*
This migration ensures previous installations
@ -10,10 +8,12 @@ so that we can version notices in the future.
import { cloneDeep } from 'lodash'
const version = 20
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -21,7 +21,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,5 +1,3 @@
const version = 21
/*
This migration removes the BlackListController from disk state
@ -8,10 +6,12 @@ This migration removes the BlackListController from disk state
import { cloneDeep } from 'lodash'
const version = 21
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -19,7 +19,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},

View File

@ -1,6 +1,4 @@
const version = 22
/*
This migration adds submittedTime to the txMeta if it is not their
@ -9,10 +7,12 @@ This migration adds submittedTime to the txMeta if it is not their
import { cloneDeep } from 'lodash'
const version = 22
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -20,7 +20,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -30,7 +30,7 @@ function transformState (state) {
const newState = state
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (txMeta.status !== 'submitted' || txMeta.submittedTime) {

View File

@ -1,6 +1,4 @@
const version = 23
/*
This migration removes transactions that are no longer usefull down to 40 total
@ -9,10 +7,12 @@ This migration removes transactions that are no longer usefull down to 40 total
import { cloneDeep } from 'lodash'
const version = 23
export default {
version,
migrate: function (originalVersionedData) {
migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
try {
@ -20,7 +20,7 @@ export default {
const newState = transformState(state)
versionedData.data = newState
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
}
return Promise.resolve(versionedData)
},
@ -31,7 +31,7 @@ function transformState (state) {
const { TransactionController } = newState
if (TransactionController && TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
if (transactions.length <= 40) {
return newState

View File

@ -1,6 +1,4 @@
const version = 24
/*
This migration ensures that the from address in txParams is to lower case for
@ -10,10 +8,12 @@ all unapproved transactions
import { cloneDeep } from 'lodash'
const version = 24
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -28,7 +28,7 @@ function transformState (state) {
if (!newState.TransactionController) {
return newState
}
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta, _) => {
if (
txMeta.status === 'unapproved' &&

View File

@ -1,6 +1,4 @@
// next version number
const version = 25
/*
normalizes txParams on unconfirmed txs
@ -10,10 +8,12 @@ import ethUtil from 'ethereumjs-util'
import { cloneDeep } from 'lodash'
const version = 25
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -28,7 +28,7 @@ function transformState (state) {
if (newState.TransactionController) {
if (newState.TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.map((txMeta) => {
if (txMeta.status !== 'unapproved') {
return txMeta

View File

@ -1,5 +1,3 @@
const version = 26
/*
This migration moves the identities stored in the KeyringController
@ -9,6 +7,8 @@ This migration moves the identities stored in the KeyringController
import { cloneDeep } from 'lodash'
const version = 26
export default {
version,
migrate (originalVersionedData) {
@ -18,7 +18,7 @@ export default {
const state = versionedData.data
versionedData.data = transformState(state)
} catch (err) {
console.warn(`MetaMask Migration #${version}` + err.stack)
console.warn(`MetaMask Migration #${version}${err.stack}`)
return Promise.reject(err)
}
return Promise.resolve(versionedData)

View File

@ -1,6 +1,4 @@
// next version number
const version = 27
/*
normalizes txParams on unconfirmed txs
@ -8,10 +6,12 @@ normalizes txParams on unconfirmed txs
*/
import { cloneDeep } from 'lodash'
const version = 27
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -26,7 +26,7 @@ function transformState (state) {
if (newState.TransactionController) {
if (newState.TransactionController.transactions) {
const transactions = newState.TransactionController.transactions
const { transactions } = newState.TransactionController
newState.TransactionController.transactions = transactions.filter((txMeta) => txMeta.status !== 'rejected')
}
}

View File

@ -1,6 +1,4 @@
// next version number
const version = 28
/*
normalizes txParams on unconfirmed txs
@ -8,10 +6,12 @@ normalizes txParams on unconfirmed txs
*/
import { cloneDeep } from 'lodash'
const version = 28
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -26,8 +26,7 @@ function transformState (state) {
if (newState.PreferencesController) {
if (newState.PreferencesController.tokens && newState.PreferencesController.identities) {
const identities = newState.PreferencesController.identities
const tokens = newState.PreferencesController.tokens
const { identities, tokens } = newState.PreferencesController
newState.PreferencesController.accountTokens = {}
Object.keys(identities).forEach((identity) => {
newState.PreferencesController.accountTokens[identity] = { 'mainnet': tokens }

View File

@ -1,7 +1,8 @@
// next version number
const version = 29
import failTxsThat from './fail-tx'
const version = 29
// time
const seconds = 1000
const minutes = 60 * seconds

View File

@ -1,6 +1,4 @@
// next version number
const version = 30
/*
removes invalid chaids from preferences and networkController for custom rpcs
@ -9,10 +7,12 @@ removes invalid chaids from preferences and networkController for custom rpcs
import { cloneDeep } from 'lodash'
const version = 30
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -25,10 +25,11 @@ export default {
function transformState (state) {
const newState = state
if (state.PreferencesController) {
const frequentRpcListDetail = newState.PreferencesController.frequentRpcListDetail
const { frequentRpcListDetail } = newState.PreferencesController
if (frequentRpcListDetail) {
frequentRpcListDetail.forEach((rpc, index) => {
if (!!rpc.chainId && Number.isNaN(parseInt(rpc.chainId))) {
// eslint-disable-next-line radix
if (Boolean(rpc.chainId) && Number.isNaN(parseInt(rpc.chainId))) {
delete frequentRpcListDetail[index].chainId
}
})
@ -36,10 +37,12 @@ function transformState (state) {
}
}
if (state.NetworkController) {
// eslint-disable-next-line radix
if (newState.NetworkController.network && Number.isNaN(parseInt(newState.NetworkController.network))) {
delete newState.NetworkController.network
}
// eslint-disable-next-line radix
if (newState.NetworkController.provider && newState.NetworkController.provider.chainId && Number.isNaN(parseInt(newState.NetworkController.provider.chainId))) {
delete newState.NetworkController.provider.chainId
}

View File

@ -1,7 +1,8 @@
// next version number
const version = 31
import { cloneDeep } from 'lodash'
const version = 31
/*
* The purpose of this migration is to properly set the completedOnboarding flag based on the state
* of the KeyringController.
@ -9,7 +10,7 @@ import { cloneDeep } from 'lodash'
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,12 +1,13 @@
const version = 32
import { cloneDeep } from 'lodash'
const version = 32
/**
* The purpose of this migration is to set the {@code completedUiMigration} flag based on the user's UI preferences
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,6 +1,4 @@
// next version number
const version = 33
/*
Cleans up notices and assocated notice controller code
@ -9,10 +7,12 @@ Cleans up notices and assocated notice controller code
import { cloneDeep } from 'lodash'
const version = 33
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,13 +1,14 @@
const version = 34
import { cloneDeep } from 'lodash'
const version = 34
/**
* The purpose of this migration is to enable the {@code privacyMode} feature flag and set the user as being migrated
* if it was {@code false}.
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,6 +1,4 @@
// next version number
const version = 35
/*
Removes the deprecated 'seedWords' state
@ -9,10 +7,12 @@ Removes the deprecated 'seedWords' state
import { cloneDeep } from 'lodash'
const version = 35
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
versionedData.data = transformState(versionedData.data)

View File

@ -1,12 +1,13 @@
const version = 36
import { cloneDeep } from 'lodash'
const version = 36
/**
* The purpose of this migration is to remove the {@code privacyMode} feature flag.
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,7 +1,8 @@
const version = 37
import { cloneDeep } from 'lodash'
import { util } from '@metamask/controllers'
const version = 37
/**
* The purpose of this migration is to update the address book state
* to the new schema with chainId as a key.
@ -9,7 +10,7 @@ import { util } from '@metamask/controllers'
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,12 +1,13 @@
const version = 38
import { cloneDeep } from 'lodash'
const version = 38
/**
* The purpose of this migration is to assign all users to a test group for the fullScreenVsPopup a/b test
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data
@ -19,17 +20,18 @@ function transformState (state) {
const { ABTestController: ABTestControllerState = {} } = state
const { abTests = {} } = ABTestControllerState
if (!abTests.fullScreenVsPopup) {
state = {
...state,
ABTestController: {
...ABTestControllerState,
abTests: {
...abTests,
fullScreenVsPopup: 'control',
},
},
}
if (abTests.fullScreenVsPopup) {
return state
}
return {
...state,
ABTestController: {
...ABTestControllerState,
abTests: {
...abTests,
fullScreenVsPopup: 'control',
},
},
}
return state
}

View File

@ -1,7 +1,8 @@
const version = 39
import { cloneDeep } from 'lodash'
import ethUtil from 'ethereumjs-util'
const version = 39
const DAI_V1_CONTRACT_ADDRESS = '0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359'
const DAI_V1_TOKEN_SYMBOL = 'DAI'
const SAI_TOKEN_SYMBOL = 'SAI'
@ -21,7 +22,7 @@ function isOldDai (token = {}) {
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,6 +1,7 @@
const version = 40
import { cloneDeep } from 'lodash'
const version = 40
/**
* Site connections are now managed by the PermissionsController, and the
* ProviderApprovalController is removed. This migration deletes all
@ -8,7 +9,7 @@ import { cloneDeep } from 'lodash'
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,12 +1,13 @@
const version = 41
import { cloneDeep } from 'lodash'
const version = 41
/**
* PreferencesController.autoLogoutTimeLimit -> autoLockTimeLimit
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,13 +1,14 @@
const version = 42
import { cloneDeep } from 'lodash'
const version = 42
/**
* Initialize `connectedStatusPopoverHasBeenShown` to `false` if it hasn't yet been set,
* so that existing users are introduced to the new connected status indicator
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,12 +1,13 @@
const version = 43
import { cloneDeep } from 'lodash'
const version = 43
/**
* Remove unused 'currentAccountTab' state
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

View File

@ -1,12 +1,13 @@
const version = 44
import { cloneDeep } from 'lodash'
const version = 44
/**
* Remove unused 'mkrMigrationReminderTimestamp' state from the `AppStateController`
*/
export default {
version,
migrate: async function (originalVersionedData) {
async migrate (originalVersionedData) {
const versionedData = cloneDeep(originalVersionedData)
versionedData.meta.version = version
const state = versionedData.data

Some files were not shown because too many files have changed in this diff Show More