diff --git a/CHANGELOG.md b/CHANGELOG.md index ef9594d51..e1a1c8ff5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,12 @@ ## Current Develop Branch +## 8.1.8 Wed Dec 09 2020 +- [#9992](https://github.com/MetaMask/metamask-extension/pull/9992): Improve transaction params validation +- [#9991](https://github.com/MetaMask/metamask-extension/pull/9991): Don't allow more than 15% slippage +- [#9994](https://github.com/MetaMask/metamask-extension/pull/9994): Prevent unwanted 'no quotes available' message when going back to build quote screen while having insufficient funds +- [#9999](https://github.com/MetaMask/metamask-extension/pull/9999): Fix missing contacts upon restart + ## 8.1.7 Tue Dec 08 2020 - Revert SES lockdown diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 16e21905a..c0a0f82cf 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -1737,7 +1737,7 @@ "message": "Quote details" }, "swapQuoteDetailsSlippageInfo": { - "message": "If the price changes between the time your order is placed and confirmed it’s called \"slippage\". Your Swap will automatically cancel if slippage exceeds your \"max slippage\" setting." + "message": "If the price changes between the time your order is placed and confirmed it’s called \"slippage\". Your Swap will automatically cancel if slippage exceeds your \"slippage tolerance\" setting." }, "swapQuoteIncludesRate": { "message": "Quote includes a $1% MetaMask fee", @@ -1853,8 +1853,11 @@ "message": "Convert $1 to about", "description": "This message is part of a quote for a swap. The $1 is the amount being converted, and the amount it is being swapped for is below this message" }, + "swapsExcessiveSlippageWarning": { + "message": "Slippage amount is too high and will result in a bad rate. Please reduce your slippage tolerance to a value below 15%." + }, "swapsMaxSlippage": { - "message": "Max slippage" + "message": "Slippage Tolerance" }, "swapsNotEnoughForTx": { "message": "Not enough $1 to complete this transaction", diff --git a/app/home.html b/app/home.html index 5c131bfc8..d952983c9 100644 --- a/app/home.html +++ b/app/home.html @@ -10,6 +10,10 @@
+ + + + diff --git a/app/manifest/_base.json b/app/manifest/_base.json index e7fcbdf37..5274261b8 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -1,7 +1,14 @@ { "author": "https://metamask.io", "background": { - "scripts": ["bg-libs.js", "background.js"], + "scripts": [ + "globalthis.js", + "initSentry.js", + "lockdown.js", + "runLockdown.js", + "bg-libs.js", + "background.js" + ], "persistent": true }, "browser_action": { @@ -30,7 +37,12 @@ "content_scripts": [ { "matches": ["file://*/*", "http://*/*", "https://*/*"], - "js": ["contentscript.js"], + "js": [ + "globalthis.js", + "lockdown.js", + "runLockdown.js", + "contentscript.js" + ], "run_at": "document_start", "all_frames": true }, @@ -65,6 +77,6 @@ "notifications" ], "short_name": "__MSG_appName__", - "version": "8.1.7", + "version": "8.1.8", "web_accessible_resources": ["inpage.js", "phishing.html"] } diff --git a/app/notification.html b/app/notification.html index 3419acdca..8d82c41b2 100644 --- a/app/notification.html +++ b/app/notification.html @@ -33,6 +33,10 @@
+ + + + diff --git a/app/phishing.html b/app/phishing.html index 583a50140..7bbc11dab 100644 --- a/app/phishing.html +++ b/app/phishing.html @@ -2,6 +2,9 @@ Ethereum Phishing Detection - MetaMask + + + diff --git a/app/popup.html b/app/popup.html index 0c3d70407..d16257992 100644 --- a/app/popup.html +++ b/app/popup.html @@ -10,6 +10,10 @@
+ + + + diff --git a/app/scripts/background.js b/app/scripts/background.js index c57710bd2..92f55319a 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -3,7 +3,6 @@ */ // 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 */ @@ -20,6 +19,7 @@ import extension from 'extensionizer' import storeTransform from 'obs-store/lib/transform' import asStream from 'obs-store/lib/asStream' import PortStream from 'extension-port-stream' +import { captureException } from '@sentry/browser' import migrations from './migrations' import Migrator from './lib/migrator' import ExtensionPlatform from './platforms/extension' @@ -29,7 +29,6 @@ import createStreamSink from './lib/createStreamSink' import NotificationManager from './lib/notification-manager' import MetamaskController from './metamask-controller' import rawFirstTimeState from './first-time-state' -import setupSentry from './lib/setupSentry' import getFirstPreferredLangCode from './lib/get-first-preferred-lang-code' import getObjStructure from './lib/getObjStructure' import setupEnsIpfsResolver from './lib/ens-ipfs/setup' @@ -41,18 +40,16 @@ import { } from './lib/enums' /* eslint-enable import/first */ +const { sentry } = global const firstTimeState = { ...rawFirstTimeState } log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn') const platform = new ExtensionPlatform() + const notificationManager = new NotificationManager() global.METAMASK_NOTIFIER = notificationManager -// setup sentry error reporting -const release = platform.getVersion() -const sentry = setupSentry({ release }) - let popupIsOpen = false let notificationIsOpen = false const openMetamaskTabsIDs = {} @@ -283,6 +280,7 @@ function setupController(initState, initLangCode) { await localStore.set(state) } catch (err) { // log error so we dont break the pipeline + captureException(err) log.error('error setting state in local store:', err) } } diff --git a/app/scripts/controllers/network/network.js b/app/scripts/controllers/network/network.js index 016331bce..9dc605cf2 100644 --- a/app/scripts/controllers/network/network.js +++ b/app/scripts/controllers/network/network.js @@ -19,6 +19,8 @@ import { MAINNET, INFURA_PROVIDER_TYPES, NETWORK_TYPE_TO_ID_MAP, + MAINNET_CHAIN_ID, + RINKEBY_CHAIN_ID, } from './enums' const env = process.env.METAMASK_ENV @@ -32,9 +34,9 @@ if (process.env.IN_TEST === 'true') { nickname: 'Localhost 8545', } } else if (process.env.METAMASK_DEBUG || env === 'test') { - defaultProviderConfigOpts = { type: RINKEBY } + defaultProviderConfigOpts = { type: RINKEBY, chainId: RINKEBY_CHAIN_ID } } else { - defaultProviderConfigOpts = { type: MAINNET } + defaultProviderConfigOpts = { type: MAINNET, chainId: MAINNET_CHAIN_ID } } const defaultProviderConfig = { diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 0c6f3c6ac..4a4488fc1 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -827,9 +827,9 @@ export default class TransactionController extends EventEmitter { ].find((methodName) => methodName === name && name.toLowerCase()) let result - if (txParams.data && tokenMethodName) { + if (data && tokenMethodName) { result = tokenMethodName - } else if (txParams.data && !to) { + } else if (data && !to) { result = TRANSACTION_CATEGORIES.DEPLOY_CONTRACT } diff --git a/app/scripts/controllers/transactions/lib/util.js b/app/scripts/controllers/transactions/lib/util.js index 758d70121..b33d3029f 100644 --- a/app/scripts/controllers/transactions/lib/util.js +++ b/app/scripts/controllers/transactions/lib/util.js @@ -1,4 +1,5 @@ import { isValidAddress } from 'ethereumjs-util' +import { ethErrors } from 'eth-json-rpc-errors' import { addHexPrefix } from '../../../lib/util' import { TRANSACTION_STATUSES } from '../../../../../shared/constants/transaction' @@ -37,19 +38,30 @@ export function normalizeTxParams(txParams, lowerCase = true) { * @throws {Error} if the tx params contains invalid fields */ export function validateTxParams(txParams) { + if (!txParams || typeof txParams !== 'object' || Array.isArray(txParams)) { + throw ethErrors.rpc.invalidParams( + 'Invalid transaction params: must be an object.', + ) + } + if (!txParams.to && !txParams.data) { + throw ethErrors.rpc.invalidParams( + 'Invalid transaction params: must specify "data" for contract deployments, or "to" (and optionally "data") for all other types of transactions.', + ) + } + validateFrom(txParams) validateRecipient(txParams) if ('value' in txParams) { const value = txParams.value.toString() if (value.includes('-')) { - throw new Error( - `Invalid transaction value of ${txParams.value} not a positive number.`, + throw ethErrors.rpc.invalidParams( + `Invalid transaction value "${txParams.value}": not a positive number.`, ) } if (value.includes('.')) { - throw new Error( - `Invalid transaction value of ${txParams.value} number must be in wei`, + throw ethErrors.rpc.invalidParams( + `Invalid transaction value of "${txParams.value}": number must be in wei.`, ) } } @@ -62,10 +74,12 @@ export function validateTxParams(txParams) { */ export function validateFrom(txParams) { if (!(typeof txParams.from === 'string')) { - throw new Error(`Invalid from address ${txParams.from} not a string`) + throw ethErrors.rpc.invalidParams( + `Invalid "from" address "${txParams.from}": not a string.`, + ) } if (!isValidAddress(txParams.from)) { - throw new Error('Invalid from address') + throw ethErrors.rpc.invalidParams('Invalid "from" address.') } } @@ -80,10 +94,10 @@ export function validateRecipient(txParams) { if (txParams.data) { delete txParams.to } else { - throw new Error('Invalid recipient address') + throw ethErrors.rpc.invalidParams('Invalid "to" address.') } } else if (txParams.to !== undefined && !isValidAddress(txParams.to)) { - throw new Error('Invalid recipient address') + throw ethErrors.rpc.invalidParams('Invalid "to" address.') } return txParams } diff --git a/app/scripts/initSentry.js b/app/scripts/initSentry.js new file mode 100644 index 000000000..70ea7b936 --- /dev/null +++ b/app/scripts/initSentry.js @@ -0,0 +1,7 @@ +import setupSentry from './lib/setupSentry' + +// setup sentry error reporting +global.sentry = setupSentry({ + release: process.env.METAMASK_VERSION, + getState: () => global.getSentryState?.() || {}, +}) diff --git a/app/scripts/lib/freezeGlobals.js b/app/scripts/lib/freezeGlobals.js deleted file mode 100644 index 08b201bee..000000000 --- a/app/scripts/lib/freezeGlobals.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Freezes the Promise global and prevents its reassignment. - */ -import deepFreeze from 'deep-freeze-strict' - -if (process.env.IN_TEST !== 'true' && process.env.METAMASK_ENV !== 'test') { - freeze(global, 'Promise') -} - -/** - * Makes a key:value pair on a target object immutable, with limitations. - * The key cannot be reassigned or deleted, and the value is recursively frozen - * using Object.freeze. - * - * Because of JavaScript language limitations, this is does not mean that the - * value is completely immutable. It is, however, better than nothing. - * - * @param {Object} target - The target object to freeze a property on. - * @param {string} key - The key to freeze. - * @param {any} [value] - The value to freeze, if different from the existing value on the target. - * @param {boolean} [enumerable=true] - If given a value, whether the property is enumerable. - */ -function freeze(target, key, value, enumerable = true) { - const opts = { - configurable: false, - writable: false, - } - - if (value === undefined) { - target[key] = deepFreeze(target[key]) - } else { - opts.value = deepFreeze(value) - opts.enumerable = enumerable - } - - Object.defineProperty(target, key, opts) -} diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index a7517c5db..b1af9cbc2 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -287,7 +287,9 @@ export default class MetamaskController extends EventEmitter { ), provider: this.provider, blockTracker: this.blockTracker, - trackMetaMetricsEvent: this.metaMetricsController.trackEvent, + trackMetaMetricsEvent: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), getParticipateInMetrics: () => this.metaMetricsController.state.participateInMetaMetrics, }) @@ -1969,7 +1971,9 @@ export default class MetamaskController extends EventEmitter { engine.push( createMethodMiddleware({ origin, - sendMetrics: this.metaMetricsController.trackEvent, + sendMetrics: this.metaMetricsController.trackEvent.bind( + this.metaMetricsController, + ), handleWatchAssetRequest: this.preferencesController.requestWatchAsset.bind( this.preferencesController, ), diff --git a/app/scripts/runLockdown.js b/app/scripts/runLockdown.js new file mode 100644 index 000000000..d8584c69c --- /dev/null +++ b/app/scripts/runLockdown.js @@ -0,0 +1,8 @@ +// Freezes all intrinsics +// eslint-disable-next-line no-undef,import/unambiguous +lockdown({ + consoleTaming: 'unsafe', + errorTaming: 'unsafe', + mathTaming: 'unsafe', + dateTaming: 'unsafe', +}) diff --git a/app/scripts/ui.js b/app/scripts/ui.js index 5b5932a50..f1f4a7b78 100644 --- a/app/scripts/ui.js +++ b/app/scripts/ui.js @@ -1,13 +1,9 @@ -// this must run before anything else -import './lib/freezeGlobals' - // polyfills import 'abortcontroller-polyfill/dist/polyfill-patch-fetch' import '@formatjs/intl-relativetimeformat/polyfill' import { EventEmitter } from 'events' import PortStream from 'extension-port-stream' - import extension from 'extensionizer' import Dnode from 'dnode' @@ -16,9 +12,8 @@ import EthQuery from 'eth-query' import StreamProvider from 'web3-stream-provider' import log from 'loglevel' import launchMetaMaskUi from '../../ui' -import { setupMultiplex } from './lib/stream-utils' -import setupSentry from './lib/setupSentry' import ExtensionPlatform from './platforms/extension' +import { setupMultiplex } from './lib/stream-utils' import { ENVIRONMENT_TYPE_FULLSCREEN, ENVIRONMENT_TYPE_POPUP, @@ -31,13 +26,6 @@ async function start() { // create platform global global.platform = new ExtensionPlatform() - // setup sentry error reporting - const release = global.platform.getVersion() - setupSentry({ - release, - getState: () => window.getSentryState?.() || {}, - }) - // identify window type (popup, notification) const windowType = getEnvironmentType() diff --git a/development/build/index.js b/development/build/index.js index cc75d8398..facf87b61 100755 --- a/development/build/index.js +++ b/development/build/index.js @@ -3,11 +3,6 @@ // // run any task with "yarn build ${taskName}" // -global.globalThis = global // eslint-disable-line node/no-unsupported-features/es-builtins -require('lavamoat-core/lib/ses.umd.js') - -lockdown() // eslint-disable-line no-undef - const livereload = require('gulp-livereload') const { createTask, diff --git a/development/build/scripts.js b/development/build/scripts.js index d1a2559a0..2f6b577e4 100644 --- a/development/build/scripts.js +++ b/development/build/scripts.js @@ -9,7 +9,7 @@ const log = require('fancy-log') const { assign } = require('lodash') const watchify = require('watchify') const browserify = require('browserify') -const envify = require('envify/custom') +const envify = require('loose-envify/custom') const sourcemaps = require('gulp-sourcemaps') const sesify = require('sesify') const terser = require('gulp-terser-js') @@ -22,6 +22,8 @@ const conf = require('rc')('metamask', { SEGMENT_LEGACY_WRITE_KEY: process.env.SEGMENT_LEGACY_WRITE_KEY, }) +const baseManifest = require('../../app/manifest/_base.json') + const packageJSON = require('../../package.json') const { createTask, @@ -96,7 +98,12 @@ function createScriptTasks({ browserPlatforms, livereload }) { } function createTasksForBuildJsExtension({ taskPrefix, devMode, testing }) { - const standardBundles = ['background', 'ui', 'phishing-detect'] + const standardBundles = [ + 'background', + 'ui', + 'phishing-detect', + 'initSentry', + ] const standardSubtasks = standardBundles.map((filename) => { return createTask( @@ -326,14 +333,6 @@ function createScriptTasks({ browserPlatforms, livereload }) { let bundler = browserify(browserifyOpts) .transform('babelify') - // Transpile any dependencies using the object spread/rest operator - // because it is incompatible with `esprima`, which is used by `envify` - // See https://github.com/jquery/esprima/issues/1927 - .transform('babelify', { - only: ['./**/node_modules/libp2p'], - global: true, - plugins: ['@babel/plugin-proposal-object-rest-spread'], - }) .transform('brfs') if (opts.buildLib) { @@ -357,6 +356,7 @@ function createScriptTasks({ browserPlatforms, livereload }) { envify({ 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, diff --git a/development/build/static.js b/development/build/static.js index f00d53d25..ee3341643 100644 --- a/development/build/static.js +++ b/development/build/static.js @@ -44,6 +44,19 @@ const copyTargets = [ pattern: `*.html`, dest: ``, }, + { + src: `./node_modules/globalthis/dist/browser.js`, + dest: `globalthis.js`, + }, + { + src: `./node_modules/ses/dist/lockdown.cjs`, + dest: `lockdown.js`, + }, + { + src: `./app/scripts/`, + pattern: `runLockdown.js`, + dest: ``, + }, ] const languageTags = new Set() diff --git a/development/build/task.js b/development/build/task.js index 553a06956..1ed252413 100644 --- a/development/build/task.js +++ b/development/build/task.js @@ -68,7 +68,9 @@ function runInChildProcess(task) { ) } return instrumentForTaskStats(taskName, async () => { - const childProcess = spawn('yarn', ['build', taskName, '--skip-stats']) + const childProcess = spawn('yarn', ['build', taskName, '--skip-stats'], { + env: process.env, + }) // forward logs to main process // skip the first stdout event (announcing the process command) childProcess.stdout.once('data', () => { @@ -85,7 +87,7 @@ function runInChildProcess(task) { if (errCode !== 0) { reject( new Error( - `MetaMask build: runInChildProcess for task "${taskName}" encountered an error`, + `MetaMask build: runInChildProcess for task "${taskName}" encountered an error ${errCode}`, ), ) return diff --git a/package.json b/package.json index d93ce8230..7260707b6 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,9 @@ "**/knex/minimist": "^1.2.5", "**/optimist/minimist": "^1.2.5", "**/socketcluster/minimist": "^1.2.5", + "**/redux/symbol-observable": "^2.0.3", + "**/redux-devtools-instrument/symbol-observable": "^2.0.3", + "**/rxjs/symbol-observable": "^2.0.3", "3box/ipfs/ipld-zcash/zcash-bitcore-lib/lodash": "^4.17.19", "3box/ipfs/ipld-zcash/zcash-bitcore-lib/elliptic": "^6.5.3", "3box/**/libp2p-crypto/node-forge": "^0.10.0", @@ -125,6 +128,7 @@ "extensionizer": "^1.0.1", "fast-json-patch": "^2.0.4", "fuse.js": "^3.2.0", + "globalthis": "^1.0.1", "human-standard-token-abi": "^2.0.0", "json-rpc-engine": "^6.1.0", "json-rpc-middleware-stream": "^2.1.1", @@ -216,7 +220,6 @@ "css-loader": "^2.1.1", "del": "^3.0.0", "deps-dump": "^1.1.0", - "envify": "^4.1.0", "enzyme": "^3.10.0", "enzyme-adapter-react-16": "^1.15.1", "eslint": "^7.7.0", @@ -252,8 +255,8 @@ "gulp-zip": "^4.0.0", "jsdom": "^11.2.0", "koa": "^2.7.0", - "lavamoat-core": "^6.1.0", "lockfile-lint": "^4.0.0", + "loose-envify": "^1.4.0", "mocha": "^7.2.0", "nock": "^9.0.14", "node-fetch": "^2.6.1", @@ -276,6 +279,7 @@ "sass-loader": "^7.0.1", "selenium-webdriver": "^4.0.0-alpha.5", "serve-handler": "^6.1.2", + "ses": "0.11.0", "sesify": "^4.2.1", "sesify-viz": "^3.0.10", "sinon": "^9.0.0", diff --git a/test/e2e/metrics.spec.js b/test/e2e/metrics.spec.js index 585a44e35..74c8f26d8 100644 --- a/test/e2e/metrics.spec.js +++ b/test/e2e/metrics.spec.js @@ -28,14 +28,16 @@ describe('Segment metrics', function () { mockSegment: true, }, async ({ driver, segmentStub }) => { - const threeSegmentEventsReceived = waitUntilCalled(segmentStub, null, 3) + const threeSegmentEventsReceived = waitUntilCalled(segmentStub, null, { + callCount: 3, + }) await driver.navigate() const passwordField = await driver.findElement(By.css('#password')) await passwordField.sendKeys('correct horse battery staple') await passwordField.sendKeys(Key.ENTER) - await threeSegmentEventsReceived + await threeSegmentEventsReceived() assert.ok(segmentStub.called, 'Segment should receive metrics') diff --git a/test/lib/wait-until-called.js b/test/lib/wait-until-called.js index 752ee7675..8252f6049 100644 --- a/test/lib/wait-until-called.js +++ b/test/lib/wait-until-called.js @@ -1,22 +1,41 @@ +const DEFAULT_TIMEOUT = 10000 + /** - * A function that wraps a sinon stubbed function and returns a Promise - * when this stub was called. + * A function that wraps a sinon stub and returns an asynchronous function + * that resolves if the stubbed function was called enough times, or throws + * if the timeout is exceeded. * * The stub that has been passed in will be setup to call the wrapped function - * directly, then trigger the returned Promise to resolve. + * directly. * * WARNING: Any existing `callsFake` behavior will be overwritten. * * @param {import('sinon').stub} stub - A sinon stub of a function - * @param {unknown} [wrappedThis] - The object the stubbed function was called on, if any (i.e. the `this` value) - * @param {number} [callCount] - The number of calls to wait for. Defaults to 1. - * @returns {Promise} A Promise that resolves when the stub has been called + * @param {unknown} [wrappedThis] - The object the stubbed function was called + * on, if any (i.e. the `this` value) + * @param {Object} [options] - Optional configuration + * @param {number} [options.callCount] - The number of calls to wait for. + * @param {number|null} [options.timeout] - The timeout, in milliseconds. Pass + * in `null` to disable the timeout. + * @returns {Function} An asynchronous function that resolves when the stub is + * called enough times, or throws if the timeout is reached. */ -function waitUntilCalled(stub, wrappedThis = null, callCount = 1) { +function waitUntilCalled( + stub, + wrappedThis = null, + { callCount = 1, timeout = DEFAULT_TIMEOUT } = {}, +) { let numCalls = 0 let resolve + let timeoutHandle const stubHasBeenCalled = new Promise((_resolve) => { resolve = _resolve + if (timeout !== null) { + timeoutHandle = setTimeout( + () => resolve(new Error('Timeout exceeded')), + timeout, + ) + } }) stub.callsFake((...args) => { try { @@ -27,12 +46,21 @@ function waitUntilCalled(stub, wrappedThis = null, callCount = 1) { if (numCalls < callCount) { numCalls += 1 if (numCalls === callCount) { + if (timeoutHandle) { + clearTimeout(timeoutHandle) + } resolve() } } } }) - return stubHasBeenCalled + + return async () => { + const error = await stubHasBeenCalled + if (error) { + throw error + } + } } module.exports = waitUntilCalled diff --git a/test/unit-global/frozenPromise.js b/test/unit-global/frozenPromise.js index 6583e1edf..1a1ca18b5 100644 --- a/test/unit-global/frozenPromise.js +++ b/test/unit-global/frozenPromise.js @@ -1,6 +1,8 @@ -import '../../app/scripts/lib/freezeGlobals' - -import assert from 'assert' +// Should occur before anything else +import './globalPatch' +import 'ses/dist/lockdown.cjs' +import '../../app/scripts/runLockdown' +import assert from 'assert' /* eslint-disable-line import/first,import/order */ describe('Promise global is immutable', function () { it('throws when reassinging promise (syntax 1)', function () { diff --git a/test/unit-global/globalPatch.js b/test/unit-global/globalPatch.js new file mode 100644 index 000000000..89d392454 --- /dev/null +++ b/test/unit-global/globalPatch.js @@ -0,0 +1,2 @@ +// eslint-disable-next-line import/unambiguous,node/no-unsupported-features/es-builtins +global.globalThis = global diff --git a/test/unit/app/controllers/incoming-transactions-test.js b/test/unit/app/controllers/incoming-transactions-test.js index 8401d7f24..61768cee8 100644 --- a/test/unit/app/controllers/incoming-transactions-test.js +++ b/test/unit/app/controllers/incoming-transactions-test.js @@ -249,7 +249,7 @@ describe('IncomingTransactionsController', function () { ) incomingTransactionsController.start() - await updateStateCalled + await updateStateCalled() const actualState = incomingTransactionsController.store.getState() const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id @@ -345,8 +345,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), @@ -412,8 +412,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), @@ -475,8 +475,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), @@ -540,8 +540,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), @@ -592,7 +592,7 @@ describe('IncomingTransactionsController', function () { // TODO: stop skipping the first event await subscription({ selectedAddress: MOCK_SELECTED_ADDRESS }) await subscription({ selectedAddress: NEW_MOCK_SELECTED_ADDRESS }) - await updateStateCalled + await updateStateCalled() const actualState = incomingTransactionsController.store.getState() const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id @@ -696,8 +696,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), @@ -746,7 +746,7 @@ describe('IncomingTransactionsController', function () { ROPSTEN_CHAIN_ID, ) await subscription(ROPSTEN) - await updateStateCalled + await updateStateCalled() const actualState = incomingTransactionsController.store.getState() const generatedTxId = actualState?.incomingTransactions?.['0xfake']?.id @@ -848,8 +848,8 @@ describe('IncomingTransactionsController', function () { try { await Promise.race([ - updateStateCalled, - putStateCalled, + updateStateCalled(), + putStateCalled(), new Promise((_, reject) => { setTimeout(() => reject(new Error('TIMEOUT')), SET_STATE_TIMEOUT) }), diff --git a/test/unit/app/controllers/metametrics-test.js b/test/unit/app/controllers/metametrics-test.js index d43f48f4f..4e66fec4a 100644 --- a/test/unit/app/controllers/metametrics-test.js +++ b/test/unit/app/controllers/metametrics-test.js @@ -400,7 +400,7 @@ describe('MetaMetricsController', function () { }, { flushImmediately: true }, ) - assert.doesNotReject(flushCalled) + assert.doesNotReject(flushCalled()) }) it('should throw if event or category not provided', function () { diff --git a/test/unit/app/controllers/transactions/tx-controller-test.js b/test/unit/app/controllers/transactions/tx-controller-test.js index f3426d5f9..0e39f791d 100644 --- a/test/unit/app/controllers/transactions/tx-controller-test.js +++ b/test/unit/app/controllers/transactions/tx-controller-test.js @@ -276,6 +276,7 @@ describe('Transaction Controller', function () { describe('#addUnapprovedTransaction', function () { const selectedAddress = '0x1678a085c290ebd122dc42cba69373b5953b831d' + const recipientAddress = '0xc42edfcc21ed14dda456aa0756c153f7985d8813' let getSelectedAddress, getPermittedAccounts beforeEach(function () { @@ -295,6 +296,7 @@ describe('Transaction Controller', function () { it('should add an unapproved transaction and return a valid txMeta', async function () { const txMeta = await txController.addUnapprovedTransaction({ from: selectedAddress, + to: recipientAddress, }) assert.ok('id' in txMeta, 'should have a id') assert.ok('time' in txMeta, 'should have a time stamp') @@ -321,7 +323,10 @@ describe('Transaction Controller', function () { done() }) txController - .addUnapprovedTransaction({ from: selectedAddress }) + .addUnapprovedTransaction({ + from: selectedAddress, + to: recipientAddress, + }) .catch(done) }) diff --git a/test/unit/app/controllers/transactions/tx-utils-test.js b/test/unit/app/controllers/transactions/tx-utils-test.js index 02c5171c7..77add3f62 100644 --- a/test/unit/app/controllers/transactions/tx-utils-test.js +++ b/test/unit/app/controllers/transactions/tx-utils-test.js @@ -6,21 +6,47 @@ describe('txUtils', function () { it('does not throw for positive values', function () { const sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', value: '0x01', } txUtils.validateTxParams(sample) }) - it('returns error for negative values', function () { + it('throws for invalid params value', function () { + assert.throws(() => txUtils.validateTxParams(), { + message: 'Invalid transaction params: must be an object.', + }) + assert.throws(() => txUtils.validateTxParams(null), { + message: 'Invalid transaction params: must be an object.', + }) + assert.throws(() => txUtils.validateTxParams(true), { + message: 'Invalid transaction params: must be an object.', + }) + assert.throws(() => txUtils.validateTxParams([]), { + message: 'Invalid transaction params: must be an object.', + }) + }) + + it('throws for missing "to" and "data"', function () { const sample = { from: '0x1678a085c290ebd122dc42cba69373b5953b831d', - value: '-0x01', + value: '0x01', } - try { - txUtils.validateTxParams(sample) - } catch (err) { - assert.ok(err, 'error') + assert.throws(() => txUtils.validateTxParams(sample), { + message: + 'Invalid transaction params: must specify "data" for contract deployments, or "to" (and optionally "data") for all other types of transactions.', + }) + }) + + it('throws for negative values', function () { + const sample = { + from: '0x1678a085c290ebd122dc42cba69373b5953b831d', + to: '0xc42edfcc21ed14dda456aa0756c153f7985d8813', + value: '-0x01', } + assert.throws(() => txUtils.validateTxParams(sample), { + message: 'Invalid transaction value "-0x01": not a positive number.', + }) }) }) diff --git a/ui/app/ducks/swaps/swaps.js b/ui/app/ducks/swaps/swaps.js index 7f4c5df96..d09afd648 100644 --- a/ui/app/ducks/swaps/swaps.js +++ b/ui/app/ducks/swaps/swaps.js @@ -325,7 +325,6 @@ export { export const navigateBackToBuildQuote = (history) => { return async (dispatch) => { // TODO: Ensure any fetch in progress is cancelled - await dispatch(resetSwapsPostFetchState()) dispatch(navigatedBackToBuildQuote()) history.push(BUILD_QUOTE_ROUTE) diff --git a/ui/app/pages/swaps/build-quote/build-quote.js b/ui/app/pages/swaps/build-quote/build-quote.js index 3aabcf82e..13d873b30 100644 --- a/ui/app/pages/swaps/build-quote/build-quote.js +++ b/ui/app/pages/swaps/build-quote/build-quote.js @@ -47,6 +47,8 @@ const fuseSearchKeys = [ { name: 'address', weight: 0.002 }, ] +const MAX_ALLOWED_SLIPPAGE = 15 + export default function BuildQuote({ inputValue, onInputChange, @@ -393,6 +395,7 @@ export default function BuildQuote({ onSelect={(newSlippage) => { setMaxSlippage(newSlippage) }} + maxAllowedSlippage={MAX_ALLOWED_SLIPPAGE} /> @@ -411,7 +414,8 @@ export default function BuildQuote({ disabled={ !Number(inputValue) || !selectedToToken?.address || - Number(maxSlippage) === 0 + Number(maxSlippage) === 0 || + Number(maxSlippage) > MAX_ALLOWED_SLIPPAGE } hideCancel /> diff --git a/ui/app/pages/swaps/slippage-buttons/slippage-buttons.js b/ui/app/pages/swaps/slippage-buttons/slippage-buttons.js index fe5daaa63..293422f0f 100644 --- a/ui/app/pages/swaps/slippage-buttons/slippage-buttons.js +++ b/ui/app/pages/swaps/slippage-buttons/slippage-buttons.js @@ -6,7 +6,7 @@ import ButtonGroup from '../../../components/ui/button-group' import Button from '../../../components/ui/button' import InfoTooltip from '../../../components/ui/info-tooltip' -export default function SlippageButtons({ onSelect }) { +export default function SlippageButtons({ onSelect, maxAllowedSlippage }) { const t = useContext(I18nContext) const [open, setOpen] = useState(false) const [customValue, setCustomValue] = useState('') @@ -15,12 +15,19 @@ export default function SlippageButtons({ onSelect }) { const [inputRef, setInputRef] = useState(null) let errorText = '' - if (customValue && Number(customValue) <= 0) { - errorText = t('swapSlippageTooLow') - } else if (customValue && Number(customValue) < 0.5) { - errorText = t('swapLowSlippageError') - } else if (customValue && Number(customValue) > 5) { - errorText = t('swapHighSlippageWarning') + if (customValue) { + if (Number(customValue) <= 0) { + errorText = t('swapSlippageTooLow') + } else if (Number(customValue) < 0.5) { + errorText = t('swapLowSlippageError') + } else if ( + Number(customValue) >= 5 && + Number(customValue) <= maxAllowedSlippage + ) { + errorText = t('swapHighSlippageWarning') + } else if (Number(customValue) > maxAllowedSlippage) { + errorText = t('swapsExcessiveSlippageWarning') + } } const customValueText = customValue || t('swapCustom') @@ -151,4 +158,5 @@ export default function SlippageButtons({ onSelect }) { SlippageButtons.propTypes = { onSelect: PropTypes.func.isRequired, + maxAllowedSlippage: PropTypes.number.isRequired, } diff --git a/ui/app/pages/swaps/swaps-gas-customization-modal/swaps-gas-customization-modal.component.js b/ui/app/pages/swaps/swaps-gas-customization-modal/swaps-gas-customization-modal.component.js index 53b4583dd..1347529dc 100644 --- a/ui/app/pages/swaps/swaps-gas-customization-modal/swaps-gas-customization-modal.component.js +++ b/ui/app/pages/swaps/swaps-gas-customization-modal/swaps-gas-customization-modal.component.js @@ -35,7 +35,7 @@ export default class GasModalPageContainer extends Component { disableSave: PropTypes.bool, customGasLimitMessage: PropTypes.string, customTotalSupplement: PropTypes.string, - usdConversionRate: PropTypes.string, + usdConversionRate: PropTypes.number, customGasPrice: PropTypes.string, customGasLimit: PropTypes.string, setSwapsCustomizationModalPrice: PropTypes.func, diff --git a/yarn.lock b/yarn.lock index c78a9c956..92a25c7bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -47,6 +47,21 @@ did-resolver "0.0.6" ipfs-did-document "^1.2.3" +"@agoric/babel-standalone@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@agoric/babel-standalone/-/babel-standalone-7.9.5.tgz#1ca0c17844924199d31e49d6b67e8b2a629b8599" + integrity sha512-1Aa23oPuRi4kywUyZODo8zey9Gq2NpD2xUnNvgJLoT8orMQRlVOtvbG3JeHq5sjJERlF/q6csg4/P8t8/5IABA== + +"@agoric/make-hardener@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@agoric/make-hardener/-/make-hardener-0.1.1.tgz#9b887da47aeec6637d9db4f0a92a4e740b8262bb" + integrity sha512-3emNc+yWJoFK5JMLoEFPs6rCzkntWQKxpR4gt3jaZYLKoUG4LrTmID3XNe8y40B6SJ3k/wLPodKa0ToQGlhrwQ== + +"@agoric/transform-module@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@agoric/transform-module/-/transform-module-0.4.1.tgz#9fb152364faf372e1bda535cb4ef89717724f57c" + integrity sha512-4TJJHXeXAWu1FCA7yXCAZmhBNoGTB/BEAe2pv+J2X8W/mJTr9b395OkDCSRMpzvmSshLfBx6wT0D7dqWIWEC1w== + "@babel/code-frame@7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.8.3.tgz#33e25903d7481181534e12ec0a25f16b6fcf419e" @@ -104,7 +119,7 @@ dependencies: eslint-rule-composer "^0.3.0" -"@babel/generator@^7.12.1", "@babel/generator@^7.12.5": +"@babel/generator@^7.12.5": version "7.12.5" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.12.5.tgz#a2c50de5c8b6d708ab95be5e6053936c1884a4de" integrity sha512-m16TQQJ8hPt7E+OS/XVQg/7U184MLXtvuGbCdA7na61vha+ImkyyNM/9DDA0unYCVZn3ZOhng+qz48/KBOT96A== @@ -332,12 +347,7 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.10.1", "@babel/parser@^7.7.5": - version "7.12.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.3.tgz#a305415ebe7a6c7023b40b5122a0662d928334cd" - integrity sha512-kFsOS0IbsuhO5ojF8Hc8z/8vEIOkylVBrjiZUbLTE3XFe0Qi+uu6HjzQixkFaqr0ZPAMZcBVxEwmsnsLPZ2Xsw== - -"@babel/parser@^7.12.1", "@babel/parser@^7.12.7": +"@babel/parser@^7.12.7", "@babel/parser@^7.7.5": version "7.12.7" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.7.tgz#fee7b39fe809d0e73e5b25eecaf5780ef3d73056" integrity sha512-oWR02Ubp4xTLCAqPRiNIuMVgNO5Aif/xpXtabhzW2HWUD47XJsAB4Zd/Rg30+XeQA3juXigV7hlquOTmwqLiwg== @@ -1064,22 +1074,7 @@ "@babel/parser" "^7.12.7" "@babel/types" "^7.12.7" -"@babel/traverse@^7.10.1", "@babel/traverse@^7.12.1", "@babel/traverse@^7.7.4": - version "7.12.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.1.tgz#941395e0c5cc86d5d3e75caa095d3924526f0c1e" - integrity sha512-MA3WPoRt1ZHo2ZmoGKNqi20YnPt0B1S0GTZEPhhd+hw2KGUzBlHuVunj6K4sNuK+reEvyiPwtp0cpaqLzJDmAw== - dependencies: - "@babel/code-frame" "^7.10.4" - "@babel/generator" "^7.12.1" - "@babel/helper-function-name" "^7.10.4" - "@babel/helper-split-export-declaration" "^7.11.0" - "@babel/parser" "^7.12.1" - "@babel/types" "^7.12.1" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - -"@babel/traverse@^7.10.4", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9": +"@babel/traverse@^7.10.4", "@babel/traverse@^7.12.1", "@babel/traverse@^7.12.5", "@babel/traverse@^7.12.9", "@babel/traverse@^7.7.4": version "7.12.9" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.12.9.tgz#fad26c972eabbc11350e0b695978de6cc8e8596f" integrity sha512-iX9ajqnLdoU1s1nHt36JDI9KG4k+vmI8WgjK5d+aDTwQbL2fUnzedNedssA645Ede3PM2ma1n8Q4h2ohwXgMXw== @@ -4412,7 +4407,7 @@ async-iterator-to-stream@^1.1.0: dependencies: readable-stream "^3.0.5" -async-limiter@~1.0.0: +async-limiter@^1.0.0, async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== @@ -5436,10 +5431,10 @@ base64-arraybuffer@0.1.5: resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" integrity sha1-c5JncZI7Whl0etZmqlzUv5xunOg= -base64-js@^1.0.2: - version "1.3.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" - integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== +base64-js@^1.0.2, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== base64id@1.0.0: version "1.0.0" @@ -6233,12 +6228,12 @@ buffer@^4.3.0: isarray "^1.0.0" buffer@^5.0.5, buffer@^5.2.1: - version "5.4.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" - integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" + base64-js "^1.3.1" + ieee754 "^1.1.13" buffer@~5.2.1: version "5.2.1" @@ -7833,11 +7828,6 @@ cyclist@~0.2.2: resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA= -cytoplasm@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/cytoplasm/-/cytoplasm-3.3.1.tgz#6d10099e536b12c642e8375b47cbffac66656a4b" - integrity sha512-38swm2Lr7cmTh0KRYtiUOCT5PT2TPp31Lpp3wcAIm3iGT4KdGGewyTydkFhBEDrKik/umgmG2hVoG5A1fKQY+g== - d64@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/d64/-/d64-1.0.0.tgz#4002a87e850cbfc9f9d9706b60fca613a3336e90" @@ -9025,14 +9015,6 @@ env-paths@^2.2.0: resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== -envify@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/envify/-/envify-4.1.0.tgz#f39ad3db9d6801b4e6b478b61028d3f0b6819f7e" - integrity sha512-IKRVVoAYr4pIx4yIWNsz9mOsboxlNXiu7TNBnem/K/uTHdkyzXWDzHCK7UTolqBbgaBz0tQHsD3YNls0uIIjiw== - dependencies: - esprima "^4.0.0" - through "~2.3.4" - enzyme-adapter-react-16@^1.15.1: version "1.15.1" resolved "https://registry.yarnpkg.com/enzyme-adapter-react-16/-/enzyme-adapter-react-16-1.15.1.tgz#8ad55332be7091dc53a25d7d38b3485fc2ba50d5" @@ -12953,9 +12935,9 @@ hi-base32@~0.5.0: integrity sha512-DDRmxSyoYuvjUb9EnXdoiMChBZ7ZcUVJsK5Frd3kqMhuBxvmZdnBeynAVfj7/ECbn++CekcoprvC/rprHPAtow== highlight.js@^10.1.1, highlight.js@~10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.0.tgz#ef3ce475e5dfa7a48484260b49ea242ddab823a0" - integrity sha512-EfrUGcQ63oLJbj0J0RI9ebX6TAITbsDBLbsjr881L/X5fMO9+oadKzEF21C7R3ULKG6Gv3uoab2HiqVJa/4+oA== + version "10.4.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.4.1.tgz#d48fbcf4a9971c4361b3f95f302747afe19dbad0" + integrity sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg== history@^4.9.0: version "4.10.1" @@ -13277,10 +13259,10 @@ idna-uts46@^1.0.1: dependencies: punycode "^2.1.0" -ieee754@^1.1.4, ieee754@^1.1.8: - version "1.1.13" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" - integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.1.8: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== iferr@^0.1.5: version "0.1.5" @@ -15779,25 +15761,6 @@ latest-version@^5.0.0: dependencies: package-json "^6.3.0" -lavamoat-core@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/lavamoat-core/-/lavamoat-core-6.2.0.tgz#ff1e39c0407f4bf5b94847c5dfaf5b09f28ac77a" - integrity sha512-sY0ddwWou2WGnpEFG/8CGguo6XKq2hc5etIDQ47TYUEJB9BaWGuWulekcrTsTQ0f7EN5r0Y2QtV5ZxxM0fMm8w== - dependencies: - cytoplasm "^3.3.1" - fromentries "^1.2.0" - json-stable-stringify "^1.0.1" - lavamoat-tofu "^5.1.1" - resolve "^1.15.1" - -lavamoat-tofu@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lavamoat-tofu/-/lavamoat-tofu-5.1.1.tgz#67d3c5775b587dd439c426f1cd86650b10443760" - integrity sha512-LIZTifbbTATA5UClVGI7YGMTOjUXjrVCBOz0DaeUicldLonLlwG81/53/vTIfPM1xV/KA85MIzGPHz4pDdiVkA== - dependencies: - "@babel/parser" "^7.10.1" - "@babel/traverse" "^7.10.1" - lazy-cache@^0.2.3: version "0.2.7" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" @@ -17973,9 +17936,9 @@ nano-json-stream-parser@^0.1.2: integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= nanoid@^2.0.0, nanoid@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.6.tgz#0665418f692e54cf44f34d4010761f3240a03314" - integrity sha512-2NDzpiuEy3+H0AVtdt8LoFi7PnqkOnIzYmJQp7xsEU6VexLluHQwKREuiz57XaQC5006seIadPrIZJhyS2n7aw== + version "2.1.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" + integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== nanoid@^3.1.12: version "3.1.16" @@ -21624,12 +21587,12 @@ redux-devtools-core@^0.2.1: remotedev-serialize "^0.1.8" redux-devtools-instrument@^1.9.4: - version "1.9.6" - resolved "https://registry.yarnpkg.com/redux-devtools-instrument/-/redux-devtools-instrument-1.9.6.tgz#6b412595f74b9d48cfd4ecc13e585b1588ed6e7e" - integrity sha512-MwvY4cLEB2tIfWWBzrUR02UM9qRG2i7daNzywRvabOSVdvAY7s9BxSwMmVRH1Y/7QWjplNtOwgT0apKhHg2Qew== + version "1.10.0" + resolved "https://registry.yarnpkg.com/redux-devtools-instrument/-/redux-devtools-instrument-1.10.0.tgz#036caf79fa1e5f25ec4bae38a9af4f08c69e323a" + integrity sha512-X8JRBCzX2ADSMp+iiV7YQ8uoTNyEm0VPFPd4T854coz6lvRiBrFSqAr9YAS2n8Kzxx8CJQotR0QF9wsMM+3DvA== dependencies: - lodash "^4.2.0" - symbol-observable "^1.0.2" + lodash "^4.17.19" + symbol-observable "^1.2.0" redux-mock-store@^1.5.4: version "1.5.4" @@ -21915,9 +21878,9 @@ remote-redux-devtools@^0.5.16: socketcluster-client "^14.2.1" remotedev-serialize@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/remotedev-serialize/-/remotedev-serialize-0.1.8.tgz#c99cb184e7f71a906162abc404be8ce33810205f" - integrity sha512-3YG/FDcOmiK22bl5oMRM8RRnbGrFEuPGjbcDG+z2xi5aQaNQNZ8lqoRnZTwXVfaZtutXuiAQOgPRrogzQk8edg== + version "0.1.9" + resolved "https://registry.yarnpkg.com/remotedev-serialize/-/remotedev-serialize-0.1.9.tgz#5e67e05cbca75d408d769d057dc59d0f56cd2c43" + integrity sha512-5tFdZg9mSaAWTv6xmQ7HtHjKMLSFQFExEZOtJe10PLsv1wb7cy7kYHtBvTYRro27/3fRGEcQBRNKSaixOpb69w== dependencies: jsan "^3.1.13" @@ -22181,7 +22144,7 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.4, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.15.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.8.1: +resolve@^1.1.4, resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.11.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.17.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.8.1: version "1.18.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== @@ -22304,9 +22267,9 @@ rlp@^2.0.0, rlp@^2.2.1, rlp@^2.2.2, rlp@^2.2.3: bn.js "^4.11.1" rn-host-detect@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.1.5.tgz#fbecb982b73932f34529e97932b9a63e58d8deb6" - integrity sha512-ufk2dFT3QeP9HyZ/xTuMtW27KnFy815CYitJMqQm+pgG3ZAtHBsrU8nXizNKkqXGy3bQmhEoloVbrfbvMJMqkg== + version "1.2.0" + resolved "https://registry.yarnpkg.com/rn-host-detect/-/rn-host-detect-1.2.0.tgz#8b0396fc05631ec60c1cb8789e5070cdb04d0da0" + integrity sha512-btNg5kzHcjZZ7t7mvvV/4wNJ9e3MPgrWivkRgWURzXL0JJ0pwWlU4zrbmdlz3HHzHOxhBhHB4D+/dbMFfu4/4A== roarr@^2.15.3: version "2.15.3" @@ -22535,6 +22498,11 @@ sc-errors@^1.4.1: resolved "https://registry.yarnpkg.com/sc-errors/-/sc-errors-1.4.1.tgz#53e80030fe647e133d73b51eaa7d2b0f7591fd5b" integrity sha512-dBn92iIonpChTxYLgKkIT/PCApvmYT6EPIbRvbQKTgY6tbEbIy8XVUv4pGyKwEK4nCmvX4TKXcN0iXC6tNW6rQ== +sc-errors@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/sc-errors/-/sc-errors-2.0.1.tgz#3af2d934dfd82116279a4b2c1552c1e021ddcb03" + integrity sha512-JoVhq3Ud+3Ujv2SIG7W0XtjRHsrNgl6iXuHHsh0s+Kdt5NwI6N2EGAZD4iteitdDv68ENBkpjtSvN597/wxPSQ== + sc-formatter@^3.0.1, sc-formatter@^3.0.2, sc-formatter@~3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/sc-formatter/-/sc-formatter-3.0.2.tgz#9abdb14e71873ce7157714d3002477bbdb33c4e6" @@ -22848,6 +22816,15 @@ servify@^0.1.12: request "^2.79.0" xhr "^2.3.3" +ses@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/ses/-/ses-0.11.0.tgz#1e470112ed320d169f0b850525858129c0be0881" + integrity sha512-3HH+23C4bijk9VegfiP+cBMqkGim/TMsj/DK5nh/pJFiNrCMfi5euvVluIV66ry202+uckg7nXKrgrEcBwU8SA== + dependencies: + "@agoric/babel-standalone" "^7.9.5" + "@agoric/make-hardener" "^0.1.0" + "@agoric/transform-module" "^0.4.1" + sesify-tofu@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/sesify-tofu/-/sesify-tofu-2.0.4.tgz#b31d4c8d67ea2d61e9c5be4948f085a849f3e632" @@ -23222,9 +23199,9 @@ socket.io@^2.1.1: socket.io-parser "~3.3.0" socketcluster-client@^14.2.1: - version "14.2.2" - resolved "https://registry.yarnpkg.com/socketcluster-client/-/socketcluster-client-14.2.2.tgz#60b31318abe6828ba7233f5a9a32540263fd23b6" - integrity sha512-vofmFcTaHaIf+MqAR0OZS7e30X4jxbDPJl+taCe8kLGJ5rVOrKeuU0sGyHyHyqW87AIR6jqc4KODl4WQJ4SsAA== + version "14.3.1" + resolved "https://registry.yarnpkg.com/socketcluster-client/-/socketcluster-client-14.3.1.tgz#bfc3591c0cad2668e7b3512a102f3844f5f2e84d" + integrity sha512-Sd/T0K/9UlqTfz+HUuFq90dshA5OBJPQbdkRzGtcKIOm52fkdsBTt0FYpiuzzxv5VrU7PWpRm6KIfNXyPwlLpw== dependencies: buffer "^5.2.1" clone "2.1.1" @@ -23232,10 +23209,10 @@ socketcluster-client@^14.2.1: linked-list "0.1.0" querystring "0.2.0" sc-channel "^1.2.0" - sc-errors "^1.4.1" + sc-errors "^2.0.1" sc-formatter "^3.0.1" uuid "3.2.1" - ws "5.1.1" + ws "7.1.0" socketcluster-server@^14.3.2: version "14.4.0" @@ -24230,15 +24207,10 @@ swarm-js@^0.1.40: tar "^4.0.2" xhr-request "^1.0.1" -symbol-observable@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.1.tgz#8340fc4702c3122df5d22288f88283f513d3fdd4" - integrity sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ= - -symbol-observable@^1.0.2, symbol-observable@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" - integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== +symbol-observable@1.0.1, symbol-observable@^1.2.0, symbol-observable@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-2.0.3.tgz#5b521d3d07a43c351055fa43b8355b62d33fd16a" + integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== symbol-tree@^3.2.1: version "3.2.2" @@ -26449,13 +26421,6 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -ws@5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.1.1.tgz#1d43704689711ac1942fd2f283e38f825c4b8b95" - integrity sha512-bOusvpCb09TOBLbpMKszd45WKC2KPtxiyiHanv+H2DE3Az+1db5a/L7sVJZVDPUC1Br8f0SKRr1KjLpD1U/IAw== - dependencies: - async-limiter "~1.0.0" - ws@6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8" @@ -26463,6 +26428,13 @@ ws@6.1.2: dependencies: async-limiter "~1.0.0" +ws@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.1.0.tgz#0395646c6fcc3ac56abf61ce1a42039637a6bd98" + integrity sha512-Swie2C4fs7CkwlHu1glMePLYJJsWjzhl1vm3ZaLplD0h7OMkZyZ6kLTB/OagiU923bZrPFXuDTeEqaEN4NWG4g== + dependencies: + async-limiter "^1.0.0" + ws@7.2.3, ws@^7: version "7.2.3" resolved "https://registry.yarnpkg.com/ws/-/ws-7.2.3.tgz#a5411e1fb04d5ed0efee76d26d5c46d830c39b46"