1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 01:39:44 +01:00

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

* origin/develop: (29 commits)
  Reset swaps routeState in navigateBackToBuildQuote (#10166)
  Fix decrypt message confirmation UI crash (#10252)
  Fix site metadata JSON-RPC handler (#10243)
  Fix design system error constants (#10246)
  Remove unused environment variables (#10234)
  Update `yarn.lock` (#10241)
  Update postMessage structure for TrezorConnect 8 (#10192)
  Increase minimum Firefox version to v68 (#10195)
  Bump socket.io from 2.2.0 to 2.4.1 (#10232)
  Update `@reduxjs/toolkit` from v1.3.2 to v1.5.0 (#10228)
  eth-rpc-errors@4.0.2 (#10226)
  Add MAX_SAFE_CHAIN_ID and refactor chain ID validation (#10224)
  add chip component (#10199)
  add new typography component (#10197)
  @metamask/inpage-provider@8.0.3 (#10219)
  Add NETWORK_TYPE_RPC constant (#10203)
  Further improve organization of constants (#10200)
  add includePaths to sass-loader in storybook (#10213)
  Disable the swaps submit button after the first time it is clicked (#10162)
  Remove default to 18 decimals in quotesToRenderableData method (#10212)
  ...
This commit is contained in:
Mark Stacey 2021-01-22 17:12:14 -03:30
commit 74ee13f7c3
127 changed files with 1401 additions and 527 deletions

View File

@ -7,3 +7,4 @@ app/vendor/**
.nyc_output/**
.vscode/**
test/e2e/send-eth-with-private-key-test/**
*.scss

View File

@ -7,7 +7,7 @@ module.exports = {
addons: [
'@storybook/addon-knobs',
'@storybook/addon-actions',
'@storybook/addon-backgrounds'
'@storybook/addon-backgrounds',
],
webpackFinal: async (config) => {
config.module.strictExportPresence = true
@ -27,18 +27,29 @@ module.exports = {
loader: 'sass-loader',
options: {
sourceMap: true,
implementation: require('sass'),
sassOptions: {
includePaths: ['ui/app/css/'],
},
},
},
],
})
config.plugins.push(new CopyWebpackPlugin({
patterns: [
{
from: path.join('node_modules', '@fortawesome', 'fontawesome-free', 'webfonts'),
to: path.join('fonts', 'fontawesome'),
},
],
}))
config.plugins.push(
new CopyWebpackPlugin({
patterns: [
{
from: path.join(
'node_modules',
'@fortawesome',
'fontawesome-free',
'webfonts',
),
to: path.join('fonts', 'fontawesome'),
},
],
}),
)
return config
},
}

View File

@ -1,5 +1,8 @@
# MetaMask Browser Extension
Hey! We are hiring JavaScript Engineers! [Apply here](https://boards.greenhouse.io/consensys/jobs/2572388)!
---
You can find the latest version of MetaMask on [our official website](https://metamask.io/). For help using MetaMask, visit our [User Support Site](https://metamask.zendesk.com/hc/en-us).
For [general questions](https://metamask.zendesk.com/hc/en-us/community/topics/360000682532-General), [feature requests](https://metamask.zendesk.com/hc/en-us/community/topics/360000682552-Feature-Requests-Ideas), or [developer questions](https://metamask.zendesk.com/hc/en-us/community/topics/360001751291-Developer-Questions), visit our [Community Forum](https://metamask.zendesk.com/hc/en-us/community/topics).

View File

@ -845,6 +845,9 @@
"invalidBlockExplorerURL": {
"message": "Invalid Block Explorer URL"
},
"invalidChainIdTooBig": {
"message": "Invalid chain ID. The chain ID is too big."
},
"invalidCustomNetworkAlertContent1": {
"message": "The chain ID for custom network '$1' has to be re-entered.",
"description": "$1 is the name/identifier of the network."

View File

@ -2,7 +2,7 @@
"applications": {
"gecko": {
"id": "webextension@metamask.io",
"strict_min_version": "56.0"
"strict_min_version": "68.0"
}
}
}

View File

@ -19,6 +19,12 @@ import extension from 'extensionizer'
import { storeAsStream, storeTransformStream } from '@metamask/obs-store'
import PortStream from 'extension-port-stream'
import { captureException } from '@sentry/browser'
import {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
} from '../../shared/constants/app'
import migrations from './migrations'
import Migrator from './lib/migrator'
import ExtensionPlatform from './platforms/extension'
@ -31,12 +37,6 @@ import rawFirstTimeState from './first-time-state'
import getFirstPreferredLangCode from './lib/get-first-preferred-lang-code'
import getObjStructure from './lib/getObjStructure'
import setupEnsIpfsResolver from './lib/ens-ipfs/setup'
import {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
} from './lib/enums'
/* eslint-enable import/first */
const { sentry } = global

View File

@ -2,12 +2,11 @@ import Web3 from 'web3'
import contracts from '@metamask/contract-metadata'
import { warn } from 'loglevel'
import SINGLE_CALL_BALANCES_ABI from 'single-call-balance-checker-abi'
import { MAINNET_CHAIN_ID } from './network/enums'
import { MAINNET_CHAIN_ID } from '../../../shared/constants/network'
import { SINGLE_CALL_BALANCES_ADDRESS } from '../constants/contracts'
// By default, poll every 3 minutes
const DEFAULT_INTERVAL = 180 * 1000
const SINGLE_CALL_BALANCES_ADDRESS =
'0xb1f8e55c7f64d203c1400b9d8555d050f94adf39'
/**
* A controller that polls for token exchange

View File

@ -3,7 +3,7 @@ import log from 'loglevel'
import BN from 'bn.js'
import createId from '../lib/random-id'
import { bnToHex } from '../lib/util'
import fetchWithTimeout from '../lib/fetch-with-timeout'
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'
import {
TRANSACTION_CATEGORIES,
@ -22,11 +22,9 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN,
ROPSTEN_CHAIN_ID,
} from './network/enums'
} from '../../../shared/constants/network'
const fetch = fetchWithTimeout({
timeout: 30000,
})
const fetchWithTimeout = getFetchWithTimeout(30000)
/**
* This controller is responsible for retrieving incoming transactions. Etherscan is polled once every block to check
@ -227,7 +225,7 @@ export default class IncomingTransactionsController {
if (fromBlock) {
url += `&startBlock=${parseInt(fromBlock, 10)}`
}
const response = await fetch(url)
const response = await fetchWithTimeout(url)
const parsedResponse = await response.json()
return {

View File

@ -1,7 +1,7 @@
import { merge, omit } from 'lodash'
import { ObservableStore } from '@metamask/obs-store'
import { bufferToHex, sha3 } from 'ethereumjs-util'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../lib/enums'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'
import {
METAMETRICS_ANONYMOUS_ID,
METAMETRICS_BACKGROUND_PAGE_OBJECT,

View File

@ -8,7 +8,7 @@ import providerFromMiddleware from 'eth-json-rpc-middleware/providerFromMiddlewa
import createInfuraMiddleware from 'eth-json-rpc-infura'
import BlockTracker from 'eth-block-tracker'
import { NETWORK_TYPE_TO_ID_MAP } from './enums'
import { NETWORK_TYPE_TO_ID_MAP } from '../../../../shared/constants/network'
export default function createInfuraClient({ network, projectId }) {
const infuraMiddleware = createInfuraMiddleware({

View File

@ -9,25 +9,29 @@ import {
createEventEmitterProxy,
} from 'swappable-obj-proxy'
import EthQuery from 'eth-query'
import createMetamaskMiddleware from './createMetamaskMiddleware'
import createInfuraClient from './createInfuraClient'
import createJsonRpcClient from './createJsonRpcClient'
import {
RINKEBY,
MAINNET,
INFURA_PROVIDER_TYPES,
NETWORK_TYPE_RPC,
NETWORK_TYPE_TO_ID_MAP,
MAINNET_CHAIN_ID,
RINKEBY_CHAIN_ID,
} from './enums'
} from '../../../../shared/constants/network'
import {
isPrefixedFormattedHexString,
isSafeChainId,
} from '../../../../shared/modules/utils'
import createMetamaskMiddleware from './createMetamaskMiddleware'
import createInfuraClient from './createInfuraClient'
import createJsonRpcClient from './createJsonRpcClient'
const env = process.env.METAMASK_ENV
let defaultProviderConfigOpts
if (process.env.IN_TEST === 'true') {
defaultProviderConfigOpts = {
type: 'rpc',
type: NETWORK_TYPE_RPC,
rpcUrl: 'http://localhost:8545',
chainId: '0x539',
nickname: 'Localhost 8545',
@ -160,8 +164,16 @@ export default class NetworkController extends EventEmitter {
}
setRpcTarget(rpcUrl, chainId, ticker = 'ETH', nickname = '', rpcPrefs) {
assert.ok(
isPrefixedFormattedHexString(chainId),
`Invalid chain ID "${chainId}": invalid hex string.`,
)
assert.ok(
isSafeChainId(parseInt(chainId, 16)),
`Invalid chain ID "${chainId}": numerical value greater than max safe value.`,
)
this.setProviderConfig({
type: 'rpc',
type: NETWORK_TYPE_RPC,
rpcUrl,
chainId,
ticker,
@ -171,14 +183,14 @@ export default class NetworkController extends EventEmitter {
}
async setProviderType(type, rpcUrl = '', ticker = 'ETH', nickname = '') {
assert.notEqual(
assert.notStrictEqual(
type,
'rpc',
`NetworkController - cannot call "setProviderType" with type 'rpc'. use "setRpcTarget"`,
NETWORK_TYPE_RPC,
`NetworkController - cannot call "setProviderType" with type "${NETWORK_TYPE_RPC}". Use "setRpcTarget"`,
)
assert(
assert.ok(
INFURA_PROVIDER_TYPES.includes(type),
`NetworkController - Unknown rpc type "${type}"`,
`Unknown Infura provider type "${type}".`,
)
const { chainId } = NETWORK_TYPE_TO_ID_MAP[type]
this.setProviderConfig({ type, rpcUrl, chainId, ticker, nickname })
@ -209,7 +221,7 @@ export default class NetworkController extends EventEmitter {
getNetworkIdentifier() {
const provider = this.providerStore.getState()
return provider.type === 'rpc' ? provider.rpcUrl : provider.type
return provider.type === NETWORK_TYPE_RPC ? provider.rpcUrl : provider.type
}
//
@ -228,7 +240,7 @@ export default class NetworkController extends EventEmitter {
if (isInfura) {
this._configureInfuraProvider(type, this._infuraProjectId)
// url-based rpc endpoints
} else if (type === 'rpc') {
} else if (type === NETWORK_TYPE_RPC) {
this._configureStandardProvider(rpcUrl, chainId)
} else {
throw new Error(

View File

@ -1,4 +1,4 @@
import { NETWORK_TO_NAME_MAP } from './enums'
import { NETWORK_TO_NAME_MAP } from '../../../../shared/constants/network'
export const getNetworkDisplayName = (key) => NETWORK_TO_NAME_MAP[key]

View File

@ -10,11 +10,6 @@ export const METADATA_STORE_KEY = 'domainMetadata'
export const METADATA_CACHE_MAX_SIZE = 100
export const CAVEAT_NAMES = {
exposedAccounts: 'exposedAccounts',
primaryAccountOnly: 'primaryAccountOnly',
}
export const CAVEAT_TYPES = {
limitResponseLength: 'limitResponseLength',
filterResponse: 'filterResponse',

View File

@ -3,13 +3,10 @@ import { JsonRpcEngine } from 'json-rpc-engine'
import { ObservableStore } from '@metamask/obs-store'
import log from 'loglevel'
import { CapabilitiesController as RpcCap } from 'rpc-cap'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import { cloneDeep } from 'lodash'
import createPermissionsMethodMiddleware from './permissionsMethodMiddleware'
import PermissionsLogController from './permissionsLog'
// Methods that do not require any permissions to use:
import { CAVEAT_NAMES } from '../../../../shared/constants/permissions'
import {
APPROVAL_TYPE,
SAFE_METHODS, // methods that do not require any permissions to use
@ -18,11 +15,13 @@ import {
METADATA_CACHE_MAX_SIZE,
LOG_STORE_KEY,
HISTORY_STORE_KEY,
CAVEAT_NAMES,
NOTIFICATION_NAMES,
CAVEAT_TYPES,
} from './enums'
import createPermissionsMethodMiddleware from './permissionsMethodMiddleware'
import PermissionsLogController from './permissionsLog'
// instanbul ignore next
const noop = () => undefined

View File

@ -1,6 +1,6 @@
import { cloneDeep } from 'lodash'
import { CAVEAT_NAMES } from '../../../../shared/constants/permissions'
import {
CAVEAT_NAMES,
HISTORY_STORE_KEY,
LOG_IGNORE_METHODS,
LOG_LIMIT,

View File

@ -1,5 +1,5 @@
import { createAsyncMiddleware } from 'json-rpc-engine'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
/**
* Create middleware for handling certain methods and preprocessing permissions requests.

View File

@ -1,13 +1,13 @@
import { strict as assert } from 'assert'
import { ObservableStore } from '@metamask/obs-store'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import { normalize as normalizeAddress } from 'eth-sig-util'
import { isValidAddress } from 'ethereumjs-util'
import ethers from 'ethers'
import log from 'loglevel'
import { isPrefixedFormattedHexString } from '../lib/util'
import { LISTED_CONTRACT_ADDRESSES } from '../../../shared/constants/tokens'
import { NETWORK_TYPE_TO_ID_MAP } from './network/enums'
import { NETWORK_TYPE_TO_ID_MAP } from '../../../shared/constants/network'
import { isPrefixedFormattedHexString } from '../../../shared/modules/utils'
export default class PreferencesController {
/**

View File

@ -2,6 +2,9 @@ import { ObservableStore } from '@metamask/obs-store'
import log from 'loglevel'
import { normalize as normalizeAddress } from 'eth-sig-util'
import ethUtil from 'ethereumjs-util'
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'
const fetchWithTimeout = getFetchWithTimeout(30000)
// By default, poll every 3 minutes
const DEFAULT_INTERVAL = 180 * 1000
@ -34,7 +37,7 @@ export default class TokenRatesController {
const query = `contract_addresses=${pairs}&vs_currencies=${nativeCurrency}`
if (this._tokens.length > 0) {
try {
const response = await window.fetch(
const response = await fetchWithTimeout(
`https://api.coingecko.com/api/v3/simple/token_price/ethereum?${query}`,
)
const prices = await response.json()

View File

@ -3,7 +3,7 @@ import { ObservableStore } from '@metamask/obs-store'
import ethUtil from 'ethereumjs-util'
import Transaction from 'ethereumjs-tx'
import EthQuery from 'ethjs-query'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import abi from 'human-standard-token-abi'
import { ethers } from 'ethers'
import NonceTracker from 'nonce-tracker'

View File

@ -1,5 +1,5 @@
import { isValidAddress } from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import { addHexPrefix } from '../../../lib/util'
import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction'

View File

@ -19,14 +19,14 @@ import {
RINKEBY_CHAIN_ID,
ROPSTEN_CHAIN_ID,
KOVAN_CHAIN_ID,
} from '../controllers/network/enums'
} from '../../../shared/constants/network'
import {
SINGLE_CALL_BALANCES_ADDRESS,
SINGLE_CALL_BALANCES_ADDRESS_RINKEBY,
SINGLE_CALL_BALANCES_ADDRESS_ROPSTEN,
SINGLE_CALL_BALANCES_ADDRESS_KOVAN,
} from '../controllers/network/contract-addresses'
} from '../constants/contracts'
import { bnToHex } from './util'
/**

View File

@ -1,11 +1,11 @@
import EventEmitter from 'events'
import { ObservableStore } from '@metamask/obs-store'
import ethUtil from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import log from 'loglevel'
import { MESSAGE_TYPE } from '../../../shared/constants/app'
import { addHexPrefix } from './util'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/gu

View File

@ -1,9 +1,9 @@
import EventEmitter from 'events'
import { ObservableStore } from '@metamask/obs-store'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import log from 'loglevel'
import { MESSAGE_TYPE } from '../../../shared/constants/app'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
/**
* Represents, and contains data about, an 'eth_getEncryptionPublicKey' type request. These are created when

View File

@ -1,6 +1,9 @@
import extension from 'extensionizer'
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout'
import resolveEnsToIpfsContentId from './resolver'
const fetchWithTimeout = getFetchWithTimeout(30000)
const supportedTopLevelDomains = ['eth']
export default function setupEnsIpfsResolver({
@ -55,7 +58,9 @@ export default function setupEnsIpfsResolver({
)}.${ipfsGateway}${pathname}${search || ''}${fragment || ''}`
try {
// check if ipfs gateway has result
const response = await window.fetch(resolvedUrl, { method: 'HEAD' })
const response = await fetchWithTimeout(resolvedUrl, {
method: 'HEAD',
})
if (response.status === 200) {
url = resolvedUrl
}

View File

@ -1,9 +1,9 @@
import EventEmitter from 'events'
import { ObservableStore } from '@metamask/obs-store'
import ethUtil from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import { MESSAGE_TYPE } from '../../../shared/constants/app'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
/**
* Represents, and contains data about, an 'eth_sign' type signature request. These are created when a signature for

View File

@ -1,4 +1,7 @@
import log from 'loglevel'
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'
const fetchWithTimeout = getFetchWithTimeout(30000)
const FIXTURE_SERVER_HOST = 'localhost'
const FIXTURE_SERVER_PORT = 12345
@ -24,7 +27,7 @@ export default class ReadOnlyNetworkStore {
*/
async _init() {
try {
const response = await window.fetch(FIXTURE_SERVER_URL)
const response = await fetchWithTimeout(FIXTURE_SERVER_URL)
if (response.ok) {
this._state = await response.json()
}

View File

@ -1,11 +1,11 @@
import EventEmitter from 'events'
import { ObservableStore } from '@metamask/obs-store'
import ethUtil from 'ethereumjs-util'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import log from 'loglevel'
import { MESSAGE_TYPE } from '../../../shared/constants/app'
import { addHexPrefix } from './util'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
const hexRe = /^[0-9A-Fa-f]+$/gu

View File

@ -1,4 +1,4 @@
import { MESSAGE_TYPE } from '../../enums'
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'
/**
* This RPC method gets background state relevant to the provider.

View File

@ -1,4 +1,4 @@
import { MESSAGE_TYPE } from '../../enums'
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'
/**
* This RPC method is called by the inpage provider whenever it detects the

View File

@ -1,4 +1,4 @@
import { MESSAGE_TYPE } from '../../enums'
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'
const watchAsset = {
methodNames: [MESSAGE_TYPE.WATCH_ASSET, MESSAGE_TYPE.WATCH_ASSET_LEGACY],

View File

@ -1,13 +1,13 @@
import EventEmitter from 'events'
import assert from 'assert'
import { ObservableStore } from '@metamask/obs-store'
import { ethErrors } from 'eth-json-rpc-errors'
import { ethErrors } from 'eth-rpc-errors'
import { typedSignatureHash, TYPED_MESSAGE_SCHEMA } from 'eth-sig-util'
import { isValidAddress } from 'ethereumjs-util'
import log from 'loglevel'
import jsonschema from 'jsonschema'
import { MESSAGE_TYPE } from '../../../shared/constants/app'
import createId from './random-id'
import { MESSAGE_TYPE } from './enums'
/**
* Represents, and contains data about, an 'eth_signTypedData' type signature request. These are created when a

View File

@ -14,7 +14,7 @@ import {
PLATFORM_CHROME,
PLATFORM_EDGE,
PLATFORM_BRAVE,
} from './enums'
} from '../../../shared/constants/app'
/**
* @see {@link getEnvironmentType}
@ -147,21 +147,6 @@ function checkForError() {
return new Error(lastError.message)
}
/**
* Checks whether the given value is a 0x-prefixed, non-zero, non-zero-padded,
* hexadecimal string.
*
* @param {any} value - The value to check.
* @returns {boolean} True if the value is a correctly formatted hex string,
* false otherwise.
*/
function isPrefixedFormattedHexString(value) {
if (typeof value !== 'string') {
return false
}
return /^0x[1-9a-f]+[0-9a-f]*$/iu.test(value)
}
/**
* Prefixes a hex string with '0x' or '-0x' and returns it. Idempotent.
*
@ -202,7 +187,6 @@ export {
hexToBn,
BnMultiplyByFraction,
checkForError,
isPrefixedFormattedHexString,
addHexPrefix,
bnToHex,
}

View File

@ -2402,13 +2402,6 @@ export default class MetamaskController extends EventEmitter {
nickname,
rpcPrefs,
) {
await this.preferencesController.updateRpc({
rpcUrl,
chainId,
ticker,
nickname,
rpcPrefs,
})
this.networkController.setRpcTarget(
rpcUrl,
chainId,
@ -2416,6 +2409,13 @@ export default class MetamaskController extends EventEmitter {
nickname,
rpcPrefs,
)
await this.preferencesController.updateRpc({
rpcUrl,
chainId,
ticker,
nickname,
rpcPrefs,
})
return rpcUrl
}

View File

@ -1,5 +1,5 @@
import { cloneDeep } from 'lodash'
import { NETWORK_TYPE_TO_ID_MAP } from '../controllers/network/enums'
import { NETWORK_TYPE_TO_ID_MAP } from '../../../shared/constants/network'
const version = 51

View File

@ -1,7 +1,7 @@
import extension from 'extensionizer'
import { createExplorerLink as explorerLink } from '@metamask/etherscan-link'
import { getEnvironmentType, checkForError } from '../lib/util'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../lib/enums'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app'
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction'
export default class ExtensionPlatform {

View File

@ -12,12 +12,12 @@ import EthQuery from 'eth-query'
import StreamProvider from 'web3-stream-provider'
import log from 'loglevel'
import launchMetaMaskUi from '../../ui'
import ExtensionPlatform from './platforms/extension'
import { setupMultiplex } from './lib/stream-utils'
import {
ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_POPUP,
} from './lib/enums'
} from '../../shared/constants/app'
import ExtensionPlatform from './platforms/extension'
import { setupMultiplex } from './lib/stream-utils'
import { getEnvironmentType } from './lib/util'
start().catch(log.error)

View File

@ -16,6 +16,6 @@ Passing messages from popup to background script
window.addEventListener('message', event => {
if (port && event.source === window && event.data) {
port.postMessage(event.data);
port.postMessage({ data: event.data });
}
});

View File

@ -6,7 +6,7 @@ module.exports = function (api) {
'@babel/preset-env',
{
targets: {
browsers: ['chrome >= 63', 'firefox >= 56.2'],
browsers: ['chrome >= 63', 'firefox >= 68'],
},
},
],

View File

@ -375,12 +375,10 @@ function createScriptTasks({ browserPlatforms, livereload }) {
METAMASK_DEBUG: opts.devMode,
METAMASK_ENVIRONMENT: environment,
METAMASK_VERSION: baseManifest.version,
METAMETRICS_PROJECT_ID: process.env.METAMETRICS_PROJECT_ID,
NODE_ENV: opts.devMode ? 'development' : 'production',
IN_TEST: opts.testing ? 'true' : false,
PUBNUB_SUB_KEY: process.env.PUBNUB_SUB_KEY || '',
PUBNUB_PUB_KEY: process.env.PUBNUB_PUB_KEY || '',
ETH_GAS_STATION_API_KEY: process.env.ETH_GAS_STATION_API_KEY || '',
CONF: opts.devMode ? conf : {},
SENTRY_DSN: process.env.SENTRY_DSN,
INFURA_PROJECT_ID: opts.testing

View File

@ -1,7 +1,7 @@
const pify = require('pify')
const gulp = require('gulp')
const sass = require('gulp-sass')
sass.compiler = require('node-sass')
sass.compiler = require('sass')
const autoprefixer = require('gulp-autoprefixer')
const gulpStylelint = require('gulp-stylelint')
const watch = require('gulp-watch')

View File

@ -86,7 +86,7 @@
"@metamask/logo": "^2.5.0",
"@metamask/obs-store": "^5.0.0",
"@popperjs/core": "^2.4.0",
"@reduxjs/toolkit": "^1.3.2",
"@reduxjs/toolkit": "^1.5.0",
"@sentry/browser": "^5.26.0",
"@sentry/integrations": "^5.26.0",
"@zxing/library": "^0.8.0",
@ -105,7 +105,6 @@
"end-of-stream": "^1.4.4",
"eth-block-tracker": "^4.4.2",
"eth-ens-namehash": "^2.0.8",
"eth-json-rpc-errors": "^2.0.2",
"eth-json-rpc-filters": "^4.2.1",
"eth-json-rpc-infura": "^5.1.0",
"eth-json-rpc-middleware": "^6.0.0",
@ -113,8 +112,9 @@
"eth-method-registry": "^2.0.0",
"eth-phishing-detect": "^1.1.14",
"eth-query": "^2.1.2",
"eth-rpc-errors": "^4.0.2",
"eth-sig-util": "^3.0.0",
"eth-trezor-keyring": "^0.4.0",
"eth-trezor-keyring": "^0.5.2",
"ethereum-ens-network-map": "^1.0.2",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-tx": "1.3.7",
@ -246,7 +246,7 @@
"gulp-rename": "^2.0.0",
"gulp-replace": "^1.0.0",
"gulp-rtlcss": "^1.4.0",
"gulp-sass": "^4.0.0",
"gulp-sass": "^4.1.0",
"gulp-sourcemaps": "^2.6.0",
"gulp-stylelint": "^13.0.0",
"gulp-terser-js": "^5.2.2",
@ -259,7 +259,6 @@
"mocha": "^7.2.0",
"nock": "^9.0.14",
"node-fetch": "^2.6.1",
"node-sass": "^4.14.1",
"nyc": "^15.0.0",
"polyfill-crypto.getrandomvalues": "^1.0.0",
"prettier": "^2.1.1",
@ -275,7 +274,8 @@
"remote-redux-devtools": "^0.5.16",
"remotedev-server": "^0.3.1",
"resolve-url-loader": "^3.1.2",
"sass-loader": "^7.0.1",
"sass": "^1.32.4",
"sass-loader": "^10.1.1",
"selenium-webdriver": "4.0.0-alpha.7",
"serve-handler": "^6.1.2",
"ses": "0.11.0",

View File

@ -6,19 +6,18 @@
* background - The background process that powers the extension
* @typedef {'popup' | 'notification' | 'fullscreen' | 'background'} EnvironmentType
*/
export const ENVIRONMENT_TYPE_POPUP = 'popup'
export const ENVIRONMENT_TYPE_NOTIFICATION = 'notification'
export const ENVIRONMENT_TYPE_FULLSCREEN = 'fullscreen'
export const ENVIRONMENT_TYPE_BACKGROUND = 'background'
const ENVIRONMENT_TYPE_POPUP = 'popup'
const ENVIRONMENT_TYPE_NOTIFICATION = 'notification'
const ENVIRONMENT_TYPE_FULLSCREEN = 'fullscreen'
const ENVIRONMENT_TYPE_BACKGROUND = 'background'
export const PLATFORM_BRAVE = 'Brave'
export const PLATFORM_CHROME = 'Chrome'
export const PLATFORM_EDGE = 'Edge'
export const PLATFORM_FIREFOX = 'Firefox'
export const PLATFORM_OPERA = 'Opera'
const PLATFORM_BRAVE = 'Brave'
const PLATFORM_CHROME = 'Chrome'
const PLATFORM_EDGE = 'Edge'
const PLATFORM_FIREFOX = 'Firefox'
const PLATFORM_OPERA = 'Opera'
const MESSAGE_TYPE = {
export const MESSAGE_TYPE = {
ETH_DECRYPT: 'eth_decrypt',
ETH_GET_ENCRYPTION_PUBLIC_KEY: 'eth_getEncryptionPublicKey',
ETH_SIGN: 'eth_sign',
@ -29,16 +28,3 @@ const MESSAGE_TYPE = {
WATCH_ASSET: 'wallet_watchAsset',
WATCH_ASSET_LEGACY: 'metamask_watchAsset',
}
export {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_BACKGROUND,
MESSAGE_TYPE,
PLATFORM_BRAVE,
PLATFORM_CHROME,
PLATFORM_EDGE,
PLATFORM_FIREFOX,
PLATFORM_OPERA,
}

View File

@ -1,6 +1,6 @@
// Type Imports
/**
* @typedef {import('../../app/scripts/lib/enums').EnvironmentType} EnvironmentType
* @typedef {import('../../shared/constants/app').EnvironmentType} EnvironmentType
*/
// Type Declarations

View File

@ -3,6 +3,7 @@ export const RINKEBY = 'rinkeby'
export const KOVAN = 'kovan'
export const MAINNET = 'mainnet'
export const GOERLI = 'goerli'
export const NETWORK_TYPE_RPC = 'rpc'
export const MAINNET_NETWORK_ID = '1'
export const ROPSTEN_NETWORK_ID = '3'
@ -16,6 +17,12 @@ export const RINKEBY_CHAIN_ID = '0x4'
export const GOERLI_CHAIN_ID = '0x5'
export const KOVAN_CHAIN_ID = '0x2a'
/**
* The largest possible chain ID we can handle.
* Explanation: https://gist.github.com/rekmarks/a47bd5f2525936c4b8eee31a16345553
*/
export const MAX_SAFE_CHAIN_ID = 4503599627370476
export const ROPSTEN_DISPLAY_NAME = 'Ropsten'
export const RINKEBY_DISPLAY_NAME = 'Rinkeby'
export const KOVAN_DISPLAY_NAME = 'Kovan'

View File

@ -0,0 +1,4 @@
export const CAVEAT_NAMES = {
exposedAccounts: 'exposedAccounts',
primaryAccountOnly: 'primaryAccountOnly',
}

View File

@ -1,3 +0,0 @@
### Shared Modules
This folder is reserved for modules that can be used globally within both the background and ui applications.

View File

@ -1,4 +1,10 @@
const fetchWithTimeout = ({ timeout = 120000 } = {}) => {
import { memoize } from 'lodash'
const getFetchWithTimeout = memoize((timeout) => {
if (!Number.isInteger(timeout) || timeout < 1) {
throw new Error('Must specify positive integer timeout.')
}
return async function _fetch(url, opts) {
const abortController = new window.AbortController()
const { signal } = abortController
@ -18,6 +24,6 @@ const fetchWithTimeout = ({ timeout = 120000 } = {}) => {
throw e
}
}
}
})
export default fetchWithTimeout
export default getFetchWithTimeout

30
shared/modules/utils.js Normal file
View File

@ -0,0 +1,30 @@
import { MAX_SAFE_CHAIN_ID } from '../constants/network'
/**
* Checks whether the given number primitive chain ID is safe.
* Because some cryptographic libraries we use expect the chain ID to be a
* number primitive, it must not exceed a certain size.
*
* @param {number} chainId - The chain ID to check for safety.
* @returns {boolean} Whether the given chain ID is safe.
*/
export function isSafeChainId(chainId) {
return (
Number.isSafeInteger(chainId) && chainId > 0 && chainId <= MAX_SAFE_CHAIN_ID
)
}
/**
* Checks whether the given value is a 0x-prefixed, non-zero, non-zero-padded,
* hexadecimal string.
*
* @param {any} value - The value to check.
* @returns {boolean} True if the value is a correctly formatted hex string,
* false otherwise.
*/
export function isPrefixedFormattedHexString(value) {
if (typeof value !== 'string') {
return false
}
return /^0x[1-9a-f]+[0-9a-f]*$/iu.test(value)
}

View File

@ -2,6 +2,7 @@ import assert from 'assert'
import freeze from 'deep-freeze-strict'
import reducers from '../../../ui/app/ducks'
import * as actionConstants from '../../../ui/app/store/actionConstants'
import { NETWORK_TYPE_RPC } from '../../../shared/constants/network'
describe('config view actions', function () {
const initialState = {
@ -25,7 +26,7 @@ describe('config view actions', function () {
}
const result = reducers(initialState, action)
assert.equal(result.metamask.provider.type, 'rpc')
assert.equal(result.metamask.provider.type, NETWORK_TYPE_RPC)
assert.equal(result.metamask.provider.rpcUrl, 'foo')
})
})

View File

@ -7,10 +7,7 @@ import BigNumber from 'bignumber.js'
import DetectTokensController from '../../../../app/scripts/controllers/detect-tokens'
import NetworkController from '../../../../app/scripts/controllers/network/network'
import PreferencesController from '../../../../app/scripts/controllers/preferences'
import {
MAINNET,
ROPSTEN,
} from '../../../../app/scripts/controllers/network/enums'
import { MAINNET, ROPSTEN } from '../../../../shared/constants/network'
describe('DetectTokensController', function () {
const sandbox = sinon.createSandbox()

View File

@ -14,7 +14,7 @@ import {
ROPSTEN,
ROPSTEN_CHAIN_ID,
ROPSTEN_NETWORK_ID,
} from '../../../../app/scripts/controllers/network/enums'
} from '../../../../shared/constants/network'
import {
TRANSACTION_CATEGORIES,
TRANSACTION_STATUSES,

View File

@ -1,7 +1,7 @@
import { strict as assert } from 'assert'
import sinon from 'sinon'
import MetaMetricsController from '../../../../app/scripts/controllers/metametrics'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../../shared/constants/app'
import { createSegmentMock } from '../../../../app/scripts/lib/segment'
import {
METAMETRICS_ANONYMOUS_ID,

View File

@ -1,12 +1,12 @@
import { ethErrors, ERROR_CODES } from 'eth-json-rpc-errors'
import { ethErrors, errorCodes } from 'eth-rpc-errors'
import deepFreeze from 'deep-freeze-strict'
import { ApprovalController } from '@metamask/controllers'
import _getRestrictedMethods from '../../../../../app/scripts/controllers/permissions/restrictedMethods'
import { CAVEAT_NAMES } from '../../../../../shared/constants/permissions'
import {
CAVEAT_NAMES,
CAVEAT_TYPES,
NOTIFICATION_NAMES,
} from '../../../../../app/scripts/controllers/permissions/enums'
@ -336,7 +336,7 @@ export const getters = deepFreeze({
return {
// name: 'EthereumRpcError',
message: `Failed to add 'eth_accounts' to '${origin}'.`,
code: ERROR_CODES.rpc.internal,
code: errorCodes.rpc.internal,
}
},
},

View File

@ -8,7 +8,7 @@ import { ObservableStore } from '@metamask/obs-store'
import {
ROPSTEN_NETWORK_ID,
MAINNET_NETWORK_ID,
} from '../../../../app/scripts/controllers/network/enums'
} from '../../../../shared/constants/network'
import { ETH_SWAPS_TOKEN_ADDRESS } from '../../../../ui/app/helpers/constants/swaps'
import { createTestProviderTools } from '../../../stub/provider'
import SwapsController, {

View File

@ -1,14 +1,16 @@
import assert from 'assert'
import nock from 'nock'
import fetchWithTimeout from '../../../app/scripts/lib/fetch-with-timeout'
import getFetchWithTimeout from '../../../shared/modules/fetch-with-timeout'
describe('fetchWithTimeout', function () {
describe('getFetchWithTimeout', function () {
it('fetches a url', async function () {
nock('https://api.infura.io').get('/money').reply(200, '{"hodl": false}')
const fetch = fetchWithTimeout()
const response = await (await fetch('https://api.infura.io/money')).json()
const fetchWithTimeout = getFetchWithTimeout(30000)
const response = await (
await fetchWithTimeout('https://api.infura.io/money')
).json()
assert.deepEqual(response, {
hodl: false,
})
@ -20,12 +22,10 @@ describe('fetchWithTimeout', function () {
.delay(2000)
.reply(200, '{"moon": "2012-12-21T11:11:11Z"}')
const fetch = fetchWithTimeout({
timeout: 123,
})
const fetchWithTimeout = getFetchWithTimeout(123)
try {
await fetch('https://api.infura.io/moon').then((r) => r.json())
await fetchWithTimeout('https://api.infura.io/moon').then((r) => r.json())
assert.fail('Request should throw')
} catch (e) {
assert.ok(e)
@ -38,15 +38,20 @@ describe('fetchWithTimeout', function () {
.delay(2000)
.reply(200, '{"moon": "2012-12-21T11:11:11Z"}')
const fetch = fetchWithTimeout({
timeout: 123,
})
const fetchWithTimeout = getFetchWithTimeout(123)
try {
await fetch('https://api.infura.io/moon').then((r) => r.json())
await fetchWithTimeout('https://api.infura.io/moon').then((r) => r.json())
assert.fail('Request should be aborted')
} catch (e) {
assert.deepEqual(e.message, 'Aborted')
}
})
it('throws on invalid timeout', async function () {
assert.throws(() => getFetchWithTimeout(), 'should throw')
assert.throws(() => getFetchWithTimeout(-1), 'should throw')
assert.throws(() => getFetchWithTimeout({}), 'should throw')
assert.throws(() => getFetchWithTimeout(true), 'should throw')
})
})

View File

@ -2,15 +2,15 @@ import { strict as assert } from 'assert'
import {
getEnvironmentType,
sufficientBalance,
isPrefixedFormattedHexString,
} from '../../../app/scripts/lib/util'
import { isPrefixedFormattedHexString } from '../../../shared/modules/utils'
import {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_BACKGROUND,
} from '../../../app/scripts/lib/enums'
} from '../../../shared/constants/app'
describe('app utils', function () {
describe('getEnvironmentType', function () {

View File

@ -1,3 +1,5 @@
import { NETWORK_TYPE_RPC } from '../../shared/constants/network'
/**
* @typedef {Object} FirstTimeState
* @property {Object} config Initial configuration parameters
@ -11,7 +13,7 @@ const initialState = {
config: {},
NetworkController: {
provider: {
type: 'rpc',
type: NETWORK_TYPE_RPC,
rpcUrl: 'http://localhost:8545',
chainId: '0x539',
},

View File

@ -3,7 +3,7 @@ import migration51 from '../../../app/scripts/migrations/051'
import {
INFURA_PROVIDER_TYPES,
NETWORK_TYPE_TO_ID_MAP,
} from '../../../app/scripts/controllers/network/enums'
} from '../../../shared/constants/network'
describe('migration #51', function () {
it('should update the version metadata', async function () {

View File

@ -4,7 +4,7 @@ import { debounce } from 'lodash'
import Fuse from 'fuse.js'
import InputAdornment from '@material-ui/core/InputAdornment'
import classnames from 'classnames'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import Identicon from '../../ui/identicon'
import SiteIcon from '../../ui/site-icon'

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
} from '../../../../../../app/scripts/lib/enums'
} from '../../../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../../../app/scripts/lib/util'
import NetworkDisplay from '../../network-display'
import Identicon from '../../../ui/identicon'

View File

@ -9,11 +9,10 @@ import {
NETWORKS_ROUTE,
NETWORKS_FORM_ROUTE,
} from '../../../helpers/constants/routes'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums'
import {
getEnvironmentType,
isPrefixedFormattedHexString,
} from '../../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../shared/constants/app'
import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network'
import { isPrefixedFormattedHexString } from '../../../../../shared/modules/utils'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import { Dropdown, DropdownMenuItem } from './components/dropdown'
import NetworkDropdownIcon from './components/network-dropdown-icon'
@ -117,7 +116,7 @@ class NetworkDropdown extends Component {
return reversedRpcListDetail.map((entry) => {
const { rpcUrl, chainId, ticker = 'ETH', nickname = '' } = entry
const isCurrentRpcTarget =
provider.type === 'rpc' && rpcUrl === provider.rpcUrl
provider.type === NETWORK_TYPE_RPC && rpcUrl === provider.rpcUrl
return (
<DropdownMenuItem

View File

@ -1,4 +1,5 @@
import { connect } from 'react-redux'
import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network'
import * as actions from '../../../store/actions'
import { getNetworkIdentifier } from '../../../selectors'
import LoadingNetworkScreen from './loading-network-screen.component'
@ -9,7 +10,9 @@ const mapStateToProps = (state) => {
const { rpcUrl, chainId, ticker, nickname, type } = provider
const setProviderArgs =
type === 'rpc' ? [rpcUrl, chainId, ticker, nickname] : [provider.type]
type === NETWORK_TYPE_RPC
? [rpcUrl, chainId, ticker, nickname]
: [provider.type]
return {
isLoadingNetwork: network === 'loading',

View File

@ -16,7 +16,7 @@ import {
import { useI18nContext } from '../../../hooks/useI18nContext'
import { useMetricEvent } from '../../../hooks/useMetricEvent'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../shared/constants/app'
export default function AccountOptionsMenu({ anchorElement, onClose }) {
const t = useI18nContext()

View File

@ -5,7 +5,7 @@ import { useSelector } from 'react-redux'
import SelectedAccount from '../selected-account'
import ConnectedStatusIndicator from '../connected-status-indicator'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../shared/constants/app'
import { CONNECTED_ACCOUNTS_ROUTE } from '../../../helpers/constants/routes'
import { useI18nContext } from '../../../hooks/useI18nContext'
import { useMetricEvent } from '../../../hooks/useMetricEvent'

View File

@ -6,7 +6,7 @@ import * as actions from '../../../store/actions'
import { resetCustomData as resetCustomGasData } from '../../../ducks/gas/gas.duck'
import isMobileView from '../../../../lib/is-mobile-view'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_POPUP } from '../../../../../shared/constants/app'
// Modal Components
import ConfirmCustomizeGasModal from '../gas-customization/gas-modal-page-container'

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types'
import log from 'loglevel'
import { BrowserQRCodeReader } from '@zxing/library'
import { getEnvironmentType } from '../../../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_FULLSCREEN } from '../../../../../../shared/constants/app'
import Spinner from '../../../ui/spinner'
import WebcamUtils from '../../../../../lib/webcam-utils'
import PageContainerFooter from '../../../ui/page-container/page-container-footer/page-container-footer.component'

View File

@ -1,21 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import {
MAINNET_NETWORK_ID,
ROPSTEN_NETWORK_ID,
RINKEBY_NETWORK_ID,
KOVAN_NETWORK_ID,
GOERLI_NETWORK_ID,
} from '../../../../../app/scripts/controllers/network/enums'
const networkIdToTypeMap = {
[MAINNET_NETWORK_ID]: 'mainnet',
[ROPSTEN_NETWORK_ID]: 'ropsten',
[RINKEBY_NETWORK_ID]: 'rinkeby',
[GOERLI_NETWORK_ID]: 'goerli',
[KOVAN_NETWORK_ID]: 'kovan',
}
import { NETWORK_TYPE_RPC } from '../../../../../shared/constants/network'
export default class NetworkDisplay extends Component {
static defaultProps = {
@ -23,9 +9,9 @@ export default class NetworkDisplay extends Component {
}
static propTypes = {
networkNickname: PropTypes.string.isRequired,
networkType: PropTypes.string.isRequired,
colored: PropTypes.bool,
network: PropTypes.string,
provider: PropTypes.object,
}
static contextTypes = {
@ -33,12 +19,11 @@ export default class NetworkDisplay extends Component {
}
renderNetworkIcon() {
const { network } = this.props
const networkClass = networkIdToTypeMap[network]
const { networkType } = this.props
return networkClass ? (
return networkType ? (
<div
className={`network-display__icon network-display__icon--${networkClass}`}
className={`network-display__icon network-display__icon--${networkType}`}
/>
) : (
<div
@ -52,24 +37,19 @@ export default class NetworkDisplay extends Component {
}
render() {
const {
colored,
network,
provider: { type, nickname },
} = this.props
const networkClass = networkIdToTypeMap[network]
const { colored, networkNickname, networkType } = this.props
return (
<div
className={classnames('network-display__container', {
'network-display__container--colored': colored,
[`network-display__container--${networkClass}`]:
colored && networkClass,
[`network-display__container--${networkType}`]:
colored && networkType,
})}
>
{networkClass ? (
{networkType ? (
<div
className={`network-display__icon network-display__icon--${networkClass}`}
className={`network-display__icon network-display__icon--${networkType}`}
/>
) : (
<div
@ -81,7 +61,9 @@ export default class NetworkDisplay extends Component {
/>
)}
<div className="network-display__name">
{type === 'rpc' && nickname ? nickname : this.context.t(type)}
{networkType === NETWORK_TYPE_RPC && networkNickname
? networkNickname
: this.context.t(networkType)}
</div>
</div>
)

View File

@ -1,10 +1,14 @@
import { connect } from 'react-redux'
import NetworkDisplay from './network-display.component'
const mapStateToProps = ({ metamask: { network, provider } }) => {
const mapStateToProps = ({
metamask: {
provider: { nickname, type },
},
}) => {
return {
network,
provider,
networkNickname: nickname,
networkType: type,
}
}

View File

@ -7,7 +7,7 @@ import { ObjectInspector } from 'react-inspector'
import {
ENVIRONMENT_TYPE_NOTIFICATION,
MESSAGE_TYPE,
} from '../../../../../app/scripts/lib/enums'
} from '../../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../../app/scripts/lib/util'
import Identicon from '../../ui/identicon'
import AccountListItem from '../account-list-item'

View File

@ -2,7 +2,7 @@ import { connect } from 'react-redux'
import { compose } from 'redux'
import { withRouter } from 'react-router-dom'
import { MESSAGE_TYPE } from '../../../../../app/scripts/lib/enums'
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'
import { goHome } from '../../../store/actions'
import {
accountsWithSendEtherInfoSelector,

View File

@ -1,3 +1,3 @@
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../../shared/constants/app'
export { ENVIRONMENT_TYPE_NOTIFICATION }

View File

@ -2,7 +2,7 @@ import { connect } from 'react-redux'
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck'
import { accountsWithSendEtherInfoSelector } from '../../../selectors'
import { getAccountByAddress } from '../../../helpers/utils/util'
import { MESSAGE_TYPE } from '../../../../../app/scripts/lib/enums'
import { MESSAGE_TYPE } from '../../../../../shared/constants/app'
import SignatureRequest from './signature-request.component'
function mapStateToProps(state) {

View File

@ -34,7 +34,7 @@ import {
setSwapsFromToken,
} from '../../../ducks/swaps/swaps'
import IconButton from '../../ui/icon-button'
import { MAINNET_CHAIN_ID } from '../../../../../app/scripts/controllers/network/enums'
import { MAINNET_CHAIN_ID } from '../../../../../shared/constants/network'
import WalletOverview from './wallet-overview'
const EthOverview = ({ className }) => {

View File

@ -27,7 +27,7 @@ import {
getCurrentKeyring,
getCurrentChainId,
} from '../../../selectors/selectors'
import { MAINNET_CHAIN_ID } from '../../../../../app/scripts/controllers/network/enums'
import { MAINNET_CHAIN_ID } from '../../../../../shared/constants/network'
import SwapIcon from '../../ui/icon/swap-icon.component'
import SendIcon from '../../ui/icon/overview-send-icon.component'

View File

@ -0,0 +1,55 @@
import React from 'react'
import PropTypes from 'prop-types'
import classnames from 'classnames'
import { omit } from 'lodash'
import Typography from '../typography'
import { COLORS } from '../../../helpers/constants/design-system'
export default function Chip({
className,
children,
borderColor = COLORS.UI1,
label,
labelProps = {},
leftIcon,
rightIcon,
onClick,
}) {
return (
<div
onClick={onClick}
className={classnames(className, 'chip', {
'chip--with-left-icon': Boolean(leftIcon),
'chip--with-right-icon': Boolean(rightIcon),
[`chip--${borderColor}`]: true,
})}
role="button"
tabIndex={0}
>
{leftIcon && <div className="chip__left-icon">{leftIcon}</div>}
{children ?? (
<Typography
className="chip__label"
variant="h6"
tag="span"
color="UI4"
{...labelProps}
>
{label}
</Typography>
)}
{rightIcon && <div className="chip__right-icon">{rightIcon}</div>}
</div>
)
}
Chip.propTypes = {
borderColor: PropTypes.oneOf(Object.values(COLORS)),
label: PropTypes.string,
children: PropTypes.node,
labelProps: PropTypes.shape(omit(Typography.propTypes, ['className'])),
leftIcon: PropTypes.node,
rightIcon: PropTypes.node,
className: PropTypes.string,
onClick: PropTypes.func,
}

View File

@ -0,0 +1,48 @@
@use "design-system";
.chip {
$self: &;
border-radius: 100px;
border: 1px solid design-system.$ui-1;
padding: 8px 16px;
margin: 0 4px;
display: flex;
align-items: center;
width: max-content;
&__left-icon,
&__right-icon {
display: flex;
align-items: center;
}
@each $variant, $color in design-system.$color-map {
&--#{$variant} {
border-color: $color;
}
}
&--with-left-icon,
&--with-right-icon {
padding-top: 4px;
padding-bottom: 4px;
}
&--with-left-icon {
padding-left: 4px;
#{$self}__label {
margin-left: 8px;
}
}
&--with-right-icon {
padding-right: 4px;
#{$self}__label {
margin-right: 8px;
}
}
}

View File

@ -0,0 +1,82 @@
/* eslint-disable react/prop-types */
import React from 'react'
import { select, text } from '@storybook/addon-knobs'
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system'
import ApproveIcon from '../icon/approve-icon.component'
import Identicon from '../identicon/identicon.component'
import Chip from '.'
export default {
title: 'Chip',
}
export const Plain = ({
leftIcon,
rightIcon,
label = 'Hello',
borderColor = COLORS.UI1,
fontColor = COLORS.BLACK,
}) => (
<Chip
leftIcon={leftIcon}
rightIcon={rightIcon}
label={text('label', label)}
labelProps={{
color: select('color', COLORS, fontColor),
variant: select('typography', TYPOGRAPHY, TYPOGRAPHY.H6),
}}
borderColor={select('borderColor', COLORS, borderColor)}
/>
)
export const WithLeftIcon = () => (
<Plain
label="Done!"
borderColor={COLORS.SUCCESS3}
fontColor={COLORS.SUCCESS3}
leftIcon={<ApproveIcon size={24} color="#4cd964" />}
/>
)
export const WithRightIcon = () => (
<Plain
label="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
borderColor={COLORS.UI4}
fontColor={COLORS.UI4}
rightIcon={
<Identicon
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
diameter={25}
/>
}
/>
)
export const WithBothIcons = () => (
<Plain
label="Account 1"
borderColor={COLORS.UI4}
fontColor={COLORS.UI4}
rightIcon={
<svg
width="10"
height="6"
viewBox="0 0 10 6"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M9.45759 0.857142C9.45759 0.785714 9.42188 0.705357 9.3683 0.651785L8.92188 0.205357C8.8683 0.151785 8.78795 0.116071 8.71652 0.116071C8.64509 0.116071 8.56473 0.151785 8.51116 0.205357L5.00223 3.71429L1.4933 0.205357C1.43973 0.151785 1.35938 0.116071 1.28795 0.116071C1.20759 0.116071 1.13616 0.151785 1.08259 0.205357L0.636161 0.651785C0.582589 0.705357 0.546875 0.785714 0.546875 0.857142C0.546875 0.928571 0.582589 1.00893 0.636161 1.0625L4.79688 5.22321C4.85045 5.27679 4.9308 5.3125 5.00223 5.3125C5.07366 5.3125 5.15402 5.27679 5.20759 5.22321L9.3683 1.0625C9.42188 1.00893 9.45759 0.928571 9.45759 0.857142Z"
fill="#24292E"
/>
</svg>
}
leftIcon={
<Identicon
address="0x5CfE73b6021E818B776b421B1c4Db2474086a7e1"
diameter={25}
/>
}
/>
)

View File

@ -0,0 +1 @@
export { default } from './chip'

View File

@ -0,0 +1 @@
export { default } from './typography'

View File

@ -0,0 +1,58 @@
import React from 'react'
import classnames from 'classnames'
import PropTypes from 'prop-types'
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system'
const { H6, H7, H8, H9 } = TYPOGRAPHY
export default function Typography({
variant = TYPOGRAPHY.Paragraph,
className,
color = COLORS.BLACK,
tag,
children,
spacing = 1,
fontWeight = 'normal',
align,
}) {
const computedClassName = classnames(
'typography',
className,
`typography--${variant}`,
`typography--align-${align}`,
`typography--spacing-${spacing}`,
`typography--color-${color}`,
`typography--weight-${fontWeight}`,
)
let Tag = tag ?? variant
if (Tag === TYPOGRAPHY.Paragraph) {
Tag = 'p'
} else if ([H7, H8, H9].includes(Tag)) {
Tag = H6
}
return <Tag className={computedClassName}>{children}</Tag>
}
Typography.propTypes = {
variant: PropTypes.oneOf(Object.values(TYPOGRAPHY)),
children: PropTypes.node.isRequired,
color: PropTypes.oneOf(Object.values(COLORS)),
className: PropTypes.string,
align: PropTypes.oneOf(['center', 'right']),
spacing: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8]),
fontWeight: PropTypes.oneOf(['bold', 'normal']),
tag: PropTypes.oneOf([
'p',
'h1',
'h2',
'h3',
'h4',
'h5',
'h6',
'span',
'div',
]),
}

View File

@ -0,0 +1,38 @@
@use "design-system";
@use "sass:map";
.typography {
@include design-system.Paragraph;
@each $variant in map.keys(design-system.$typography-variants) {
&--#{$variant} {
@include design-system.typography($variant);
}
}
@each $variant, $color in design-system.$color-map {
&--color-#{$variant} {
color: $color;
}
}
@each $variant, $weight in design-system.$typography-font-weights {
&--weight-#{$variant} {
font-weight: $weight;
}
}
&--align-center {
text-align: center;
}
&--align-right {
text-align: right;
}
@for $i from 1 through 8 {
&--spacing-#{$i} {
margin: #{$i * 4}px auto;
}
}
}

View File

@ -0,0 +1,53 @@
import React from 'react'
import { number, select, text } from '@storybook/addon-knobs'
import { COLORS, TYPOGRAPHY } from '../../../helpers/constants/design-system'
import Typography from '.'
export default {
title: 'Typography',
}
const fontWeightOptions = {
bold: 'bold',
normal: 'normal',
}
const alignOptions = {
left: undefined,
center: 'center',
right: 'right',
}
export const list = () => (
<div style={{ width: '80%', flexDirection: 'column' }}>
{Object.values(TYPOGRAPHY).map((variant) => (
<div key={variant} style={{ width: '100%' }}>
<Typography
variant={variant}
color={select('color', COLORS, COLORS.BLACK)}
spacing={number('spacing', 1, { range: true, min: 1, max: 8 })}
align={select('align', alignOptions, undefined)}
fontWeight={select('font weight', fontWeightOptions, 'normal')}
>
{variant}
</Typography>
</div>
))}
</div>
)
export const TheQuickOrangeFox = () => (
<div style={{ width: '80%', flexDirection: 'column' }}>
<div style={{ width: '100%' }}>
<Typography
color={select('color', COLORS, COLORS.BLACK)}
variant={select('variant', TYPOGRAPHY, TYPOGRAPHY.Paragraph)}
spacing={number('spacing', 1, { range: true, min: 1, max: 8 })}
align={select('align', alignOptions, undefined)}
fontWeight={select('font weight', fontWeightOptions, 'normal')}
>
{text('content', 'The quick orange fox jumped over the lazy dog.')}
</Typography>
</div>
</div>
)

View File

@ -7,6 +7,7 @@
@import 'button/buttons';
@import 'card/index';
@import 'check-box/index';
@import 'chip/chip';
@import 'circle-icon/index';
@import 'currency-display/index';
@import 'currency-input/index';
@ -37,5 +38,6 @@
@import 'toggle-button/index';
@import 'token-balance/index';
@import 'tooltip/index';
@import 'typography/typography';
@import 'unit-input/index';
@import 'url-icon/index';

View File

@ -74,3 +74,67 @@ $accent-pink: #ff45d8;
$neutral-white: #fff;
$neutral-black: $Black-100;
$neutral-grey: $Grey-500;
// Everything below this line is part of the new color system
$primary-1: #037dd6;
$primary-2: #eaf6ff;
$primary-3: #0260a4;
$secondary-1: #f66a0a;
$secondary-2: #fef5ef;
$secondary-3: #c65507;
$error-1: #d73a49;
$error-2: #fcf2f3;
$error-3: #b92534;
$alert-1: #ffd33d;
$alert-2: #fefcde;
$alert-3: #f8c000;
$success-1: #4cd964;
$success-2: #caf4d1;
$success-3: #219e37;
$ui-black: #24292e;
$ui-white: #fff;
$ui-1: #f2f3f4;
$ui-2: #d6d9dc;
$ui-3: #bbc0c5;
$ui-4: #6a737d;
$mainnet: #29b6af;
$ropsten: #ff4a8d;
$kovan: #9064ff;
$rinkeby: #f6c343;
$goerli: #3099f2;
$color-map: (
'ui-1': $ui-1,
'ui-2': $ui-2,
'ui-3': $ui-3,
'ui-4': $ui-4,
'white': $ui-white,
'black': $ui-black,
'primary-1': $primary-1,
'primary-2': $primary-2,
'primary-3': $primary-3,
'secondary-1': $secondary-1,
'secondary-2': $secondary-2,
'secondary-3': $secondary-3,
'alert-1': $alert-1,
'alert-2': $alert-2,
'alert-3': $alert-3,
'error-1': $error-1,
'error-2': $error-2,
'error-3': $error-3,
'success-1': $success-1,
'success-2': $success-2,
'success-3': $success-3,
'mainnet': $mainnet,
'ropsten': $ropsten,
'kovan': $kovan,
'rinkeby': $rinkeby,
'goerli': $goerli,
'transparent': transparent,
);

View File

@ -1,5 +1,5 @@
@import 'breakpoints';
@import 'colors';
@import 'deprecated-colors';
@import 'typography';
@import 'z-index';
@forward 'breakpoints';
@forward 'colors';
@forward 'deprecated-colors';
@forward 'typography';
@forward 'z-index';

View File

@ -69,89 +69,80 @@ $fa-font-path: 'fonts/fontawesome';
$font-family: Euclid, Roboto, Helvetica, Arial, sans-serif;
$font-size-h1: 2.5rem;
$font-size-h2: 2rem;
$font-size-h3: 1.5rem;
$font-size-h4: 1.125rem;
$font-size-h5: 1rem;
$font-size-h6: 0.875rem;
$font-size-paragraph: 1rem;
$font-size-h7: 0.75rem;
$font-size-h8: 0.625rem;
$font-size-h9: 0.5rem;
$typography-variants: (
'h1': 2.5rem,
'h2': 2rem,
'h3': 1.5rem,
'h4': 1.125rem,
'h5': 1rem,
'h6': 0.875rem,
'paragraph': 1rem,
'h7': 0.75rem,
'h8': 0.625rem,
'h9': 0.5rem,
);
$typography-font-weights: (
'bold': 700,
'normal': 400,
);
$font-size-h1: map-get($typography-variants, 'h1');
$font-size-h2: map-get($typography-variants, 'h2');
$font-size-h3: map-get($typography-variants, 'h3');
$font-size-h4: map-get($typography-variants, 'h4');
$font-size-h5: map-get($typography-variants, 'h5');
$font-size-h6: map-get($typography-variants, 'h6');
$font-size-paragraph: map-get($typography-variants, 'paragraph');
$font-size-h7: map-get($typography-variants, 'h7');
$font-size-h8: map-get($typography-variants, 'h8');
$font-size-h9: map-get($typography-variants, 'h9');
@mixin typography($variant) {
font-size: map-get($typography-variants, $variant);
font-family: $font-family;
line-height: 140%;
font-style: normal;
font-weight: normal;
}
// Typography
@mixin H1 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h1;
font-family: $font-family;
line-height: 140%;
@include typography('h1');
}
@mixin H2 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h2;
font-family: $font-family;
line-height: 140%;
@include typography('h2');
}
@mixin H3 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h3;
font-family: $font-family;
line-height: 140%;
@include typography('h3');
}
@mixin H4 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h4;
font-family: $font-family;
line-height: 140%;
@include typography('h4');
}
@mixin H5 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h5;
line-height: 140%;
@include typography('h5');
}
@mixin H6 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h6; // 14px @default
line-height: 140%;
@include typography('h6');
}
@mixin Paragraph {
font-style: normal;
font-weight: normal;
font-size: $font-size-paragraph;
line-height: 140%;
@include typography('paragraph');
}
@mixin H7 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h7;
line-height: 140%;
@include typography('h7');
}
@mixin H8 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h8;
line-height: 140%;
@include typography('h8');
}
@mixin H9 {
font-style: normal;
font-weight: normal;
font-size: $font-size-h9;
line-height: 140%;
@include typography('h9');
}

View File

@ -1,8 +1,10 @@
import { cloneDeep } from 'lodash'
import BigNumber from 'bignumber.js'
import { getStorageItem, setStorageItem } from '../../../lib/storage-helpers'
import { decGWEIToHexWEI } from '../../helpers/utils/conversions.util'
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout'
const fetchWithTimeout = getFetchWithTimeout(30000)
// Actions
const BASIC_GAS_ESTIMATE_LOADING_FINISHED =
@ -97,7 +99,7 @@ export function basicGasEstimatesLoadingFinished() {
async function basicGasPriceQuery() {
const url = `https://api.metaswap.codefi.network/gasPrices`
return await window.fetch(url, {
return await fetchWithTimeout(url, {
headers: {},
referrer: 'https://api.metaswap.codefi.network/gasPrices',
referrerPolicy: 'no-referrer-when-downgrade',

View File

@ -1,5 +1,6 @@
import * as actionConstants from '../../store/actionConstants'
import { ALERT_TYPES } from '../../../../shared/constants/alerts'
import { NETWORK_TYPE_RPC } from '../../../../shared/constants/network'
export default function reduceMetamask(state = {}, action) {
const metamaskState = {
@ -63,7 +64,7 @@ export default function reduceMetamask(state = {}, action) {
return {
...metamaskState,
provider: {
type: 'rpc',
type: NETWORK_TYPE_RPC,
rpcUrl: action.value,
},
}

View File

@ -329,8 +329,8 @@ export {
export const navigateBackToBuildQuote = (history) => {
return async (dispatch) => {
// TODO: Ensure any fetch in progress is cancelled
await dispatch(setBackgroundSwapRouteState(''))
dispatch(navigatedBackToBuildQuote())
history.push(BUILD_QUOTE_ROUTE)
}
}

View File

@ -5,14 +5,6 @@ export const WEI = 'WEI'
export const PRIMARY = 'PRIMARY'
export const SECONDARY = 'SECONDARY'
export const NETWORK_TYPES = {
KOVAN: 'kovan',
MAINNET: 'mainnet',
RINKEBY: 'rinkeby',
ROPSTEN: 'ropsten',
GOERLI: 'goerli',
}
export const GAS_ESTIMATE_TYPES = {
SLOW: 'SLOW',
AVERAGE: 'AVERAGE',

View File

@ -0,0 +1,42 @@
export const COLORS = {
UI1: 'ui-1',
UI2: 'ui-2',
UI3: 'ui-3',
UI4: 'ui-4',
BLACK: 'black',
WHITE: 'white',
PRIMARY1: 'primary-1',
PRIMARY2: 'primary-2',
PRIMARY3: 'primary-3',
SECONDARY1: 'secondary-1',
SECONDARY2: 'secondary-2',
SECONDARY3: 'secondary-3',
SUCCESS1: 'success-1',
SUCCESS2: 'success-2',
SUCCESS3: 'success-3',
ERROR1: 'error-1',
ERROR2: 'error-2',
ERROR3: 'error-3',
ALERT1: 'alert-1',
ALERT2: 'alert-2',
ALERT3: 'alert-3',
MAINNET: 'mainnet',
ROPSTEN: 'ropsten',
KOVAN: 'kovan',
RINKEBY: 'rinkeby',
GOERLI: 'goerli',
TRANSPARENT: 'transparent',
}
export const TYPOGRAPHY = {
H1: 'h1',
H2: 'h2',
H3: 'h3',
H4: 'h4',
H5: 'h5',
H6: 'h6',
H7: 'h7',
H8: 'h8',
H9: 'h9',
Paragraph: 'paragraph',
}

View File

@ -1,5 +1,5 @@
import { getStorageItem, setStorageItem } from '../../../lib/storage-helpers'
import fetchWithTimeout from '../../../../app/scripts/lib/fetch-with-timeout'
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout'
const fetchWithCache = async (
url,
@ -29,8 +29,8 @@ const fetchWithCache = async (
return cachedResponse
}
fetchOptions.headers.set('Content-Type', 'application/json')
const _fetch = timeout ? fetchWithTimeout({ timeout }) : window.fetch
const response = await _fetch(url, {
const fetchWithTimeout = getFetchWithTimeout(timeout)
const response = await fetchWithTimeout(url, {
referrerPolicy: 'no-referrer-when-downgrade',
body: null,
method: 'GET',

View File

@ -1,9 +1,12 @@
// cross-browser connection to extension i18n API
import React from 'react'
import log from 'loglevel'
import * as Sentry from '@sentry/browser'
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout'
const fetchWithTimeout = getFetchWithTimeout(30000)
const warned = {}
const missingMessageErrors = {}
const missingSubstitutionErrors = {}
@ -95,7 +98,7 @@ export const getMessage = (localeCode, localeMessages, key, substitutions) => {
export async function fetchLocale(localeCode) {
try {
const response = await window.fetch(
const response = await fetchWithTimeout(
`./_locales/${localeCode}/messages.json`,
)
return await response.json()
@ -120,7 +123,7 @@ export async function loadRelativeTimeFormatLocaleData(localeCode) {
}
async function fetchRelativeTimeFormatData(languageTag) {
const response = await window.fetch(
const response = await fetchWithTimeout(
`./intl/${languageTag}/relative-time-format-data.json`,
)
return await response.json()

View File

@ -4,6 +4,9 @@ import BigNumber from 'bignumber.js'
import ethUtil from 'ethereumjs-util'
import { DateTime } from 'luxon'
import { addHexPrefix } from '../../../../app/scripts/lib/util'
import getFetchWithTimeout from '../../../../shared/modules/fetch-with-timeout'
const fetchWithTimeout = getFetchWithTimeout(30000)
// formatData :: ( date: <Unix Timestamp> ) -> String
export function formatDate(date, format = "M/d/y 'at' T") {
@ -478,19 +481,17 @@ export async function jsonRpcRequest(rpcUrl, rpcMethod, rpcParams = []) {
headers.Authorization = `Basic ${encodedAuth}`
fetchUrl = `${origin}${pathname}${search}`
}
const jsonRpcResponse = await window
.fetch(fetchUrl, {
method: 'POST',
body: JSON.stringify({
id: Date.now().toString(),
jsonrpc: '2.0',
method: rpcMethod,
params: rpcParams,
}),
headers,
cache: 'default',
})
.then((httpResponse) => httpResponse.json())
const jsonRpcResponse = await fetchWithTimeout(fetchUrl, {
method: 'POST',
body: JSON.stringify({
id: Date.now().toString(),
jsonrpc: '2.0',
method: rpcMethod,
params: rpcParams,
}),
headers,
cache: 'default',
}).then((httpResponse) => httpResponse.json())
if (
!jsonRpcResponse ||

View File

@ -4,7 +4,7 @@ import Button from '../../components/ui/button'
import Identicon from '../../components/ui/identicon'
import TokenBalance from '../../components/ui/token-balance'
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'
export default class ConfirmAddSuggestedToken extends Component {
static contextTypes = {

View File

@ -9,7 +9,7 @@ import Identicon from '../../components/ui/identicon'
import Tooltip from '../../components/ui/tooltip'
import Copy from '../../components/ui/icon/copy-icon.component'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
import { conversionUtil } from '../../helpers/utils/conversion-util'

View File

@ -5,7 +5,7 @@ import AccountListItem from '../../components/app/account-list-item'
import Button from '../../components/ui/button'
import Identicon from '../../components/ui/identicon'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
import { conversionUtil } from '../../helpers/utils/conversion-util'

View File

@ -1,7 +1,7 @@
import ethUtil from 'ethereumjs-util'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../app/scripts/lib/enums'
import { ENVIRONMENT_TYPE_NOTIFICATION } from '../../../../shared/constants/app'
import { getEnvironmentType } from '../../../../app/scripts/lib/util'
import ConfirmPageContainer, {
ConfirmDetailRow,

View File

@ -14,7 +14,7 @@ import {
DECRYPT_MESSAGE_REQUEST_PATH,
ENCRYPTION_PUBLIC_KEY_REQUEST_PATH,
} from '../../helpers/constants/routes'
import { MESSAGE_TYPE } from '../../../../app/scripts/lib/enums'
import { MESSAGE_TYPE } from '../../../../shared/constants/app'
import { TRANSACTION_CATEGORIES } from '../../../../shared/constants/transaction'
export default class ConfirmTransactionSwitch extends Component {

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