From 37824db4c9ff977e611769d33c976af5f36e52c6 Mon Sep 17 00:00:00 2001 From: jiexi Date: Mon, 11 Sep 2023 14:28:32 -0700 Subject: [PATCH 01/38] Migrate MetaMaskController from mocha to jest (#20696) * Converts MetaMaskController test from mocha to jest Co-authored-by: Alex Donesky --------- Co-authored-by: Alex Donesky --- .eslintrc.js | 2 + .mocharc.js | 1 + app/scripts/controllers/app-state.js | 10 +- app/scripts/controllers/metametrics.js | 15 +- app/scripts/metamask-controller.js | 1 + app/scripts/metamask-controller.test.js | 1258 ++++++++++------------- jest.config.js | 2 + 7 files changed, 586 insertions(+), 703 deletions(-) diff --git a/.eslintrc.js b/.eslintrc.js index e09e9badbac0..392547014375 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -241,6 +241,7 @@ module.exports = { 'app/scripts/controllers/permissions/**/*.test.js', 'app/scripts/controllers/preferences.test.js', 'app/scripts/lib/**/*.test.js', + 'app/scripts/metamask-controller.test.js', 'app/scripts/migrations/*.test.js', 'app/scripts/platforms/*.test.js', 'development/**/*.test.js', @@ -271,6 +272,7 @@ module.exports = { 'app/scripts/controllers/permissions/**/*.test.js', 'app/scripts/controllers/preferences.test.js', 'app/scripts/lib/**/*.test.js', + 'app/scripts/metamask-controller.test.js', 'app/scripts/migrations/*.test.js', 'app/scripts/platforms/*.test.js', 'development/**/*.test.js', diff --git a/.mocharc.js b/.mocharc.js index 5998b524ecab..8b78cbf360e3 100644 --- a/.mocharc.js +++ b/.mocharc.js @@ -10,6 +10,7 @@ module.exports = { './app/scripts/controllers/mmi-controller.test.js', './app/scripts/controllers/preferences.test.js', './app/scripts/constants/error-utils.test.js', + './app/scripts/metamask-controller.test.js', './development/fitness-functions/**/*.test.ts', './test/e2e/helpers.test.js', ], diff --git a/app/scripts/controllers/app-state.js b/app/scripts/controllers/app-state.js index 9603542dac85..4a50e61cf60b 100644 --- a/app/scripts/controllers/app-state.js +++ b/app/scripts/controllers/app-state.js @@ -28,9 +28,11 @@ export default class AppStateController extends EventEmitter { preferencesStore, qrHardwareStore, messenger, + extension, } = opts; super(); + this.extension = extension; this.onInactiveTimeout = onInactiveTimeout || (() => undefined); this.store = new ObservableStore({ timeoutMinutes: DEFAULT_AUTO_LOCK_TIME_LIMIT, @@ -249,7 +251,7 @@ export default class AppStateController extends EventEmitter { if (this.timer) { clearTimeout(this.timer); } else if (isManifestV3) { - chrome.alarms.clear(AUTO_LOCK_TIMEOUT_ALARM); + this.extension.alarms.clear(AUTO_LOCK_TIMEOUT_ALARM); } if (!timeoutMinutes) { @@ -257,14 +259,14 @@ export default class AppStateController extends EventEmitter { } if (isManifestV3) { - chrome.alarms.create(AUTO_LOCK_TIMEOUT_ALARM, { + this.extension.alarms.create(AUTO_LOCK_TIMEOUT_ALARM, { delayInMinutes: timeoutMinutes, periodInMinutes: timeoutMinutes, }); - chrome.alarms.onAlarm.addListener((alarmInfo) => { + this.extension.alarms.onAlarm.addListener((alarmInfo) => { if (alarmInfo.name === AUTO_LOCK_TIMEOUT_ALARM) { this.onInactiveTimeout(); - chrome.alarms.clear(AUTO_LOCK_TIMEOUT_ALARM); + this.extension.alarms.clear(AUTO_LOCK_TIMEOUT_ALARM); } }); } else { diff --git a/app/scripts/controllers/metametrics.js b/app/scripts/controllers/metametrics.js index 20a7cdcb5493..d92e1ce5f808 100644 --- a/app/scripts/controllers/metametrics.js +++ b/app/scripts/controllers/metametrics.js @@ -176,20 +176,23 @@ export default class MetaMetricsController { // tracked if the event isn't progressed within that amount of time. if (isManifestV3) { /* eslint-disable no-undef */ - chrome.alarms.getAll((alarms) => { + this.extension.alarms.getAll((alarms) => { const hasAlarm = checkAlarmExists( alarms, METAMETRICS_FINALIZE_EVENT_FRAGMENT_ALARM, ); if (!hasAlarm) { - chrome.alarms.create(METAMETRICS_FINALIZE_EVENT_FRAGMENT_ALARM, { - delayInMinutes: 1, - periodInMinutes: 1, - }); + this.extension.alarms.create( + METAMETRICS_FINALIZE_EVENT_FRAGMENT_ALARM, + { + delayInMinutes: 1, + periodInMinutes: 1, + }, + ); } }); - chrome.alarms.onAlarm.addListener((alarmInfo) => { + this.extension.alarms.onAlarm.addListener((alarmInfo) => { if (alarmInfo.name === METAMETRICS_FINALIZE_EVENT_FRAGMENT_ALARM) { this.finalizeAbandonedFragments(); } diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 52fc263aa53e..f2754b7e22ec 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -623,6 +623,7 @@ export default class MetamaskController extends EventEmitter { `${this.approvalController.name}:acceptRequest`, ], }), + extension: this.extension, }); const currencyRateMessenger = this.controllerMessenger.getRestricted({ diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 6e387de1d0e4..316de29bb4e6 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -1,11 +1,10 @@ -import { strict as assert } from 'assert'; -import sinon from 'sinon'; +/** + * @jest-environment node + */ import { cloneDeep } from 'lodash'; import nock from 'nock'; import { obj as createThoughStream } from 'through2'; import EthQuery from 'eth-query'; -import proxyquire from 'proxyquire'; -import browser from 'webextension-polyfill'; import { wordlist as englishWordlist } from '@metamask/scure-bip39/dist/wordlists/english'; import { ListNames, @@ -25,7 +24,7 @@ import { HardwareDeviceNames } from '../../shared/constants/hardware-wallets'; import { KeyringType } from '../../shared/constants/keyring'; import { deferredPromise } from './lib/util'; import TransactionController from './controllers/transactions'; -import PreferencesController from './controllers/preferences'; +import MetaMaskController from './metamask-controller'; const Ganache = require('../../test/e2e/ganache'); @@ -35,16 +34,24 @@ const browserPolyfillMock = { runtime: { id: 'fake-extension-id', onInstalled: { - addListener: () => undefined, + addListener: jest.fn(), }, onMessageExternal: { - addListener: () => undefined, + addListener: jest.fn(), }, - getPlatformInfo: async () => 'mac', + getPlatformInfo: jest.fn().mockResolvedValue('mac'), }, storage: { session: { - set: () => undefined, + set: jest.fn(), + }, + }, + alarms: { + getAll: jest.fn(), + create: jest.fn(), + clear: jest.fn(), + onAlarm: { + addListener: jest.fn(), }, }, }; @@ -72,42 +79,29 @@ const createLoggerMiddlewareMock = () => (req, res, next) => { next(); }; -const MOCK_TOKEN_BALANCE = '888'; - -function MockEthContract() { - return () => { - return { - at: () => { - return { - balanceOf: () => MOCK_TOKEN_BALANCE, - }; - }, - }; - }; -} - -function MockPreferencesController(...args) { - const controller = new PreferencesController(...args); - - sinon.stub(controller.store, 'subscribe'); - - return controller; -} - -// TODO, Feb 24, 2023: -// ethjs-contract is being added to proxyquire, but we might want to discontinue proxyquire -// this is for expediency as we resolve a bug for v10.26.0. The proper solution here would have -// us set up the test infrastructure for a mocked provider. Github ticket for that is: -// https://github.com/MetaMask/metamask-extension/issues/17890 -const MetaMaskController = proxyquire('./metamask-controller', { - './lib/createLoggerMiddleware': { default: createLoggerMiddlewareMock }, - 'ethjs-contract': MockEthContract, - './controllers/preferences': { default: MockPreferencesController }, -}).default; +jest.mock('./lib/createLoggerMiddleware', () => createLoggerMiddlewareMock); +jest.mock( + './controllers/preferences', + () => + function (...args) { + const PreferencesController = jest.requireActual( + './controllers/preferences', + ).default; + const controller = new PreferencesController(...args); + // jest.spyOn gets hoisted to the top of this function before controller is initialized. + // This forces us to replace the function directly with a jest stub instead. + // eslint-disable-next-line jest/prefer-spy-on + controller.store.subscribe = jest.fn(); + return controller; + }, +); -const MetaMaskControllerMV3 = proxyquire('./metamask-controller', { - '../../shared/modules/mv3.utils': { isManifestV3: true }, -}).default; +const mockIsManifestV3 = jest.fn().mockReturnValue(false); +jest.mock('../../shared/modules/mv3.utils', () => ({ + get isManifestV3() { + return mockIsManifestV3(); + }, +})); const currentNetworkId = '5'; const DEFAULT_LABEL = 'Account 1'; @@ -210,14 +204,12 @@ const firstTimeState = { const noop = () => undefined; -describe('MetaMaskController', function () { - const sandbox = sinon.createSandbox(); - - before(async function () { +describe('MetaMaskController', () => { + beforeAll(async () => { await ganacheServer.start(); }); - beforeEach(function () { + beforeEach(() => { nock('https://min-api.cryptocompare.com') .persist() .get(/.*/u) @@ -254,59 +246,54 @@ describe('MetaMaskController', function () { }, ]), ); - - sandbox.replace(browser, 'runtime', { - sendMessage: sandbox.stub().rejects(), - }); - - browserPolyfillMock.storage.session.set = sandbox.spy(); }); - afterEach(function () { + afterEach(() => { + jest.clearAllMocks(); nock.cleanAll(); - sandbox.restore(); }); - after(async function () { + afterAll(async () => { await ganacheServer.quit(); }); - describe('Phishing Detection Mock', function () { - it('should be updated to use v1 of the API', function () { + describe('Phishing Detection Mock', () => { + it('should be updated to use v1 of the API', () => { // Update the fixture above if this test fails - assert.equal( - METAMASK_STALELIST_URL, + expect(METAMASK_STALELIST_URL).toStrictEqual( 'https://phishing-detection.metafi.codefi.network/v1/stalelist', ); - assert.equal( - METAMASK_HOTLIST_DIFF_URL, + expect(METAMASK_HOTLIST_DIFF_URL).toStrictEqual( 'https://phishing-detection.metafi.codefi.network/v1/diffsSince', ); }); }); - describe('MetaMaskController Behaviour', function () { + describe('MetaMaskController Behaviour', () => { let metamaskController; - beforeEach(function () { - sandbox.spy(MetaMaskController.prototype, 'resetStates'); + beforeEach(() => { + jest.spyOn(MetaMaskController.prototype, 'resetStates'); - sandbox.stub( - TransactionController.prototype, - 'updateIncomingTransactions', - ); + jest + .spyOn(TransactionController.prototype, 'updateIncomingTransactions') + .mockReturnValue(); - sandbox.stub( - TransactionController.prototype, - 'startIncomingTransactionPolling', - ); + jest + .spyOn( + TransactionController.prototype, + 'startIncomingTransactionPolling', + ) + .mockReturnValue(); - sandbox.stub( - TransactionController.prototype, - 'stopIncomingTransactionPolling', - ); + jest + .spyOn( + TransactionController.prototype, + 'stopIncomingTransactionPolling', + ) + .mockReturnValue(); - sandbox.spy(ControllerMessenger.prototype, 'subscribe'); + jest.spyOn(ControllerMessenger.prototype, 'subscribe'); metamaskController = new MetaMaskController({ showUserConfirmation: noop, @@ -330,29 +317,28 @@ describe('MetaMaskController', function () { isFirstMetaMaskControllerSetup: true, }); - // add sinon method spies - sandbox.spy( + jest.spyOn( metamaskController.keyringController, 'createNewVaultAndKeychain', ); - sandbox.spy( + jest.spyOn( metamaskController.coreKeyringController, 'createNewVaultAndRestore', ); }); - describe('should reset states on first time profile load', function () { - it('in mv2, it should reset state without attempting to call browser storage', function () { - assert.equal(metamaskController.resetStates.callCount, 1); - assert.equal(browserPolyfillMock.storage.session.set.callCount, 0); + describe('should reset states on first time profile load', () => { + it('in mv2, it should reset state without attempting to call browser storage', () => { + expect(metamaskController.resetStates).toHaveBeenCalledTimes(1); + expect(browserPolyfillMock.storage.session.set).not.toHaveBeenCalled(); }); }); - describe('#importAccountWithStrategy', function () { + describe('#importAccountWithStrategy', () => { const importPrivkey = '4cfd3e90fc78b0f86bf7524722150bb8da9c60cd532564d7ff43f5716514f553'; - beforeEach(async function () { + beforeEach(async () => { const password = 'a-fake-password'; await metamaskController.createNewVaultAndRestore(password, TEST_SEED); await metamaskController.importAccountWithStrategy('privateKey', [ @@ -360,7 +346,7 @@ describe('MetaMaskController', function () { ]); }); - it('adds private key to keyrings in core KeyringController', async function () { + it('adds private key to keyrings in core KeyringController', async () => { const simpleKeyrings = metamaskController.coreKeyringController.getKeyringsByType( KeyringType.imported, @@ -369,25 +355,23 @@ describe('MetaMaskController', function () { const privKeyHex = await simpleKeyrings[0].exportAccount( pubAddressHexArr[0], ); - assert.equal(privKeyHex, importPrivkey); - assert.equal( - pubAddressHexArr[0], + expect(privKeyHex).toStrictEqual(importPrivkey); + expect(pubAddressHexArr[0]).toStrictEqual( '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', ); }); - it('adds 1 account', async function () { + it('adds 1 account', async () => { const keyringAccounts = await metamaskController.keyringController.getAccounts(); - assert.equal( - keyringAccounts[keyringAccounts.length - 1], + expect(keyringAccounts[keyringAccounts.length - 1]).toStrictEqual( '0xe18035bf8712672935fdb4e5e431b1a0183d2dfc', ); }); }); - describe('submitPassword', function () { - it('removes any identities that do not correspond to known accounts.', async function () { + describe('submitPassword', () => { + it('removes any identities that do not correspond to known accounts.', async () => { const password = 'password'; await metamaskController.createNewVaultAndKeychain(password); @@ -402,80 +386,62 @@ describe('MetaMaskController', function () { await metamaskController.coreKeyringController.getAccounts(); identities.forEach((identity) => { - assert.ok( - addresses.includes(identity), - `addresses should include all IDs: ${identity}`, - ); + expect(addresses).toContain(identity); }); addresses.forEach((address) => { - assert.ok( - identities.includes(address), - `identities should include all Addresses: ${address}`, - ); + expect(identities).toContain(address); }); }); }); - describe('setLocked', function () { - it('should lock KeyringController', async function () { - sandbox.spy(metamaskController.coreKeyringController, 'setLocked'); + describe('setLocked', () => { + it('should lock KeyringController', async () => { + jest.spyOn(metamaskController.coreKeyringController, 'setLocked'); await metamaskController.setLocked(); - assert(metamaskController.coreKeyringController.setLocked.called); - assert.equal( + expect( + metamaskController.coreKeyringController.setLocked, + ).toHaveBeenCalled(); + expect( metamaskController.coreKeyringController.state.isUnlocked, - false, - ); + ).toStrictEqual(false); }); }); - describe('#createNewVaultAndKeychain', function () { - it('can only create new vault on keyringController once', async function () { - const selectStub = sandbox.stub( - metamaskController, - 'selectFirstIdentity', - ); + describe('#createNewVaultAndKeychain', () => { + it('can only create new vault on keyringController once', async () => { + jest.spyOn(metamaskController, 'selectFirstIdentity').mockReturnValue(); const password = 'a-fake-password'; await metamaskController.createNewVaultAndKeychain(password); await metamaskController.createNewVaultAndKeychain(password); - assert( - metamaskController.keyringController.createNewVaultAndKeychain - .calledOnce, - ); - - selectStub.reset(); + expect( + metamaskController.keyringController.createNewVaultAndKeychain, + ).toHaveBeenCalledTimes(1); }); }); - describe('#createNewVaultAndRestore', function () { - it('should be able to call newVaultAndRestore despite a mistake.', async function () { + describe('#createNewVaultAndRestore', () => { + it('should be able to call newVaultAndRestore despite a mistake.', async () => { const password = 'what-what-what'; - sandbox.stub(metamaskController, 'getBalance'); - metamaskController.getBalance.callsFake(() => { - return Promise.resolve('0x0'); - }); + jest.spyOn(metamaskController, 'getBalance').mockResolvedValue('0x0'); await metamaskController .createNewVaultAndRestore(password, TEST_SEED.slice(0, -1)) .catch(() => null); await metamaskController.createNewVaultAndRestore(password, TEST_SEED); - assert( - metamaskController.coreKeyringController.createNewVaultAndRestore - .calledTwice, - ); + expect( + metamaskController.coreKeyringController.createNewVaultAndRestore, + ).toHaveBeenCalledTimes(2); }); - it('should clear previous identities after vault restoration', async function () { - sandbox.stub(metamaskController, 'getBalance'); - metamaskController.getBalance.callsFake(() => { - return Promise.resolve('0x0'); - }); + it('should clear previous identities after vault restoration', async () => { + jest.spyOn(metamaskController, 'getBalance').mockResolvedValue('0x0'); let startTime = Date.now(); await metamaskController.createNewVaultAndRestore( @@ -487,13 +453,12 @@ describe('MetaMaskController', function () { const firstVaultIdentities = cloneDeep( metamaskController.getState().identities, ); - assert.ok( + expect( firstVaultIdentities[TEST_ADDRESS].lastSelected >= startTime && firstVaultIdentities[TEST_ADDRESS].lastSelected <= endTime, - `'${firstVaultIdentities[TEST_ADDRESS].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, - ); + ).toStrictEqual(true); delete firstVaultIdentities[TEST_ADDRESS].lastSelected; - assert.deepEqual(firstVaultIdentities, { + expect(firstVaultIdentities).toStrictEqual({ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, }); @@ -506,7 +471,7 @@ describe('MetaMaskController', function () { metamaskController.getState().identities, ); delete labelledFirstVaultIdentities[TEST_ADDRESS].lastSelected; - assert.deepEqual(labelledFirstVaultIdentities, { + expect(labelledFirstVaultIdentities).toStrictEqual({ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: 'Account Foo' }, }); @@ -520,13 +485,12 @@ describe('MetaMaskController', function () { const secondVaultIdentities = cloneDeep( metamaskController.getState().identities, ); - assert.ok( + expect( secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected >= startTime && secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected <= endTime, - `'${secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected}' expected to be between '${startTime}' and '${endTime}'`, - ); + ).toStrictEqual(true); delete secondVaultIdentities[TEST_ADDRESS_ALT].lastSelected; - assert.deepEqual(secondVaultIdentities, { + expect(secondVaultIdentities).toStrictEqual({ [TEST_ADDRESS_ALT]: { address: TEST_ADDRESS_ALT, name: DEFAULT_LABEL, @@ -534,17 +498,22 @@ describe('MetaMaskController', function () { }); }); - it('should restore any consecutive accounts with balances without extra zero balance accounts', async function () { - sandbox.stub(metamaskController, 'getBalance'); - metamaskController.getBalance.withArgs(TEST_ADDRESS).callsFake(() => { - return Promise.resolve('0x14ced5122ce0a000'); - }); - metamaskController.getBalance.withArgs(TEST_ADDRESS_2).callsFake(() => { - return Promise.resolve('0x0'); - }); - metamaskController.getBalance.withArgs(TEST_ADDRESS_3).callsFake(() => { - return Promise.resolve('0x14ced5122ce0a000'); - }); + it('should restore any consecutive accounts with balances without extra zero balance accounts', async () => { + jest + .spyOn(metamaskController, 'getBalance') + .mockImplementation((address) => { + switch (address) { + case TEST_ADDRESS: + case TEST_ADDRESS_3: + return Promise.resolve('0x14ced5122ce0a000'); + case TEST_ADDRESS_2: + return Promise.resolve('0x0'); + default: + return Promise.reject( + new Error('unexpected argument to mocked getBalance'), + ); + } + }); const startTime = Date.now(); await metamaskController.createNewVaultAndRestore( @@ -553,19 +522,19 @@ describe('MetaMaskController', function () { ); const identities = cloneDeep(metamaskController.getState().identities); - assert.ok( + expect( identities[TEST_ADDRESS].lastSelected >= startTime && identities[TEST_ADDRESS].lastSelected <= Date.now(), - ); + ).toStrictEqual(true); delete identities[TEST_ADDRESS].lastSelected; - assert.deepEqual(identities, { + expect(identities).toStrictEqual({ [TEST_ADDRESS]: { address: TEST_ADDRESS, name: DEFAULT_LABEL }, }); }); }); - describe('#getBalance', function () { - it('should return the balance known by accountTracker', async function () { + describe('#getBalance', () => { + it('should return the balance known by accountTracker', async () => { const accounts = {}; const balance = '0x14ced5122ce0a000'; accounts[TEST_ADDRESS] = { balance }; @@ -574,14 +543,14 @@ describe('MetaMaskController', function () { const gotten = await metamaskController.getBalance(TEST_ADDRESS); - assert.equal(balance, gotten); + expect(balance).toStrictEqual(gotten); }); - it('should ask the network for a balance when not known by accountTracker', async function () { + it('should ask the network for a balance when not known by accountTracker', async () => { const accounts = {}; const balance = '0x14ced5122ce0a000'; const ethQuery = new EthQuery(); - sinon.stub(ethQuery, 'getBalance').callsFake((_, callback) => { + jest.spyOn(ethQuery, 'getBalance').mockImplementation((_, callback) => { callback(undefined, balance); }); @@ -592,22 +561,22 @@ describe('MetaMaskController', function () { ethQuery, ); - assert.equal(balance, gotten); + expect(balance).toStrictEqual(gotten); }); }); - describe('#getApi', function () { - it('getState', function () { + describe('#getApi', () => { + it('getState', () => { const getApi = metamaskController.getApi(); const state = getApi.getState(); - assert.deepEqual(state, metamaskController.getState()); + expect(state).toStrictEqual(metamaskController.getState()); }); }); - describe('#selectFirstIdentity', function () { + describe('#selectFirstIdentity', () => { let identities, address; - beforeEach(function () { + beforeEach(() => { address = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'; identities = { '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc': { @@ -625,36 +594,35 @@ describe('MetaMaskController', function () { metamaskController.selectFirstIdentity(); }); - it('changes preferences controller select address', function () { + it('changes preferences controller select address', () => { const preferenceControllerState = metamaskController.preferencesController.store.getState(); - assert.equal(preferenceControllerState.selectedAddress, address); + expect(preferenceControllerState.selectedAddress).toStrictEqual( + address, + ); }); - it('changes metamask controller selected address', function () { + it('changes metamask controller selected address', () => { const metamaskState = metamaskController.getState(); - assert.equal(metamaskState.selectedAddress, address); + expect(metamaskState.selectedAddress).toStrictEqual(address); }); }); - describe('connectHardware', function () { - it('should throw if it receives an unknown device name', async function () { - try { - await metamaskController.connectHardware( - 'Some random device name', - 0, - `m/44/0'/0'`, - ); - } catch (e) { - assert.equal( - e.message, - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - } + describe('connectHardware', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.connectHardware( + 'Some random device name', + 0, + `m/44/0'/0'`, + ); + + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); }); - it('should add the Trezor Hardware keyring', async function () { - sinon.spy(metamaskController.keyringController, 'addNewKeyring'); + it('should add the Trezor Hardware keyring', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0) .catch(() => null); @@ -662,15 +630,14 @@ describe('MetaMaskController', function () { await metamaskController.coreKeyringController.getKeyringsByType( KeyringType.trezor, ); - assert.deepEqual( - metamaskController.keyringController.addNewKeyring.getCall(0).args, - [KeyringType.trezor], - ); - assert.equal(keyrings.length, 1); + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.trezor); + expect(keyrings).toHaveLength(1); }); - it('should add the Ledger Hardware keyring', async function () { - sinon.spy(metamaskController.keyringController, 'addNewKeyring'); + it('should add the Ledger Hardware keyring', async () => { + jest.spyOn(metamaskController.keyringController, 'addNewKeyring'); await metamaskController .connectHardware(HardwareDeviceNames.ledger, 0) .catch(() => null); @@ -678,16 +645,15 @@ describe('MetaMaskController', function () { await metamaskController.coreKeyringController.getKeyringsByType( KeyringType.ledger, ); - assert.deepEqual( - metamaskController.keyringController.addNewKeyring.getCall(0).args, - [KeyringType.ledger], - ); - assert.equal(keyrings.length, 1); + expect( + metamaskController.keyringController.addNewKeyring, + ).toHaveBeenCalledWith(KeyringType.ledger); + expect(keyrings).toHaveLength(1); }); }); - describe('getPrimaryKeyringMnemonic', function () { - it('should return a mnemonic as a Uint8Array', function () { + describe('getPrimaryKeyringMnemonic', () => { + it('should return a mnemonic as a Uint8Array', () => { const mockMnemonic = 'above mercy benefit hospital call oval domain student sphere interest argue shock'; const mnemonicIndices = mockMnemonic @@ -701,56 +667,50 @@ describe('MetaMaskController', function () { type: 'HD Key Tree', mnemonic: uint8ArrayMnemonic, }; - sinon - .stub(metamaskController.coreKeyringController, 'getKeyringsByType') - .returns([mockHDKeyring]); + jest + .spyOn(metamaskController.coreKeyringController, 'getKeyringsByType') + .mockReturnValue([mockHDKeyring]); const recoveredMnemonic = metamaskController.getPrimaryKeyringMnemonic(); - assert.equal(recoveredMnemonic, uint8ArrayMnemonic); + expect(recoveredMnemonic).toStrictEqual(uint8ArrayMnemonic); }); }); - describe('checkHardwareStatus', function () { - it('should throw if it receives an unknown device name', async function () { - try { - await metamaskController.checkHardwareStatus( - 'Some random device name', - `m/44/0'/0'`, - ); - } catch (e) { - assert.equal( - e.message, - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - } + describe('checkHardwareStatus', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.checkHardwareStatus( + 'Some random device name', + `m/44/0'/0'`, + ); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); }); - it('should be locked by default', async function () { + it('should be locked by default', async () => { await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0) .catch(() => null); const status = await metamaskController.checkHardwareStatus( HardwareDeviceNames.trezor, ); - assert.equal(status, false); + expect(status).toStrictEqual(false); }); }); - describe('forgetDevice', function () { - it('should throw if it receives an unknown device name', async function () { - try { - await metamaskController.forgetDevice('Some random device name'); - } catch (e) { - assert.equal( - e.message, - 'MetamaskController:getKeyringForDevice - Unknown device', - ); - } + describe('forgetDevice', () => { + it('should throw if it receives an unknown device name', async () => { + const result = metamaskController.forgetDevice( + 'Some random device name', + ); + await expect(result).rejects.toThrow( + 'MetamaskController:getKeyringForDevice - Unknown device', + ); }); - it('should wipe all the keyring info', async function () { + it('should wipe all the keyring info', async () => { await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0) .catch(() => null); @@ -760,44 +720,35 @@ describe('MetaMaskController', function () { KeyringType.trezor, ); - assert.deepEqual(keyrings[0].accounts, []); - assert.deepEqual(keyrings[0].page, 0); - assert.deepEqual(keyrings[0].isUnlocked(), false); + expect(keyrings[0].accounts).toStrictEqual([]); + expect(keyrings[0].page).toStrictEqual(0); + expect(keyrings[0].isUnlocked()).toStrictEqual(false); }); }); - describe('unlockHardwareWalletAccount', function () { - let accountToUnlock; - let windowOpenStub; - let addNewAccountStub; - let getAccountsStub; - beforeEach(async function () { - accountToUnlock = 10; - windowOpenStub = sinon.stub(window, 'open'); - windowOpenStub.returns(noop); - - addNewAccountStub = sinon.stub( - metamaskController.keyringController, - 'addNewAccount', - ); - addNewAccountStub.returns('0x123'); + describe('unlockHardwareWalletAccount', () => { + const accountToUnlock = 10; + beforeEach(async () => { + jest.spyOn(window, 'open').mockReturnValue(); + jest + .spyOn(metamaskController.keyringController, 'addNewAccount') + .mockReturnValue('0x123'); + + jest + .spyOn(metamaskController.keyringController, 'getAccounts') + .mockResolvedValueOnce(['0x1']) + .mockResolvedValueOnce(['0x2']) + .mockResolvedValueOnce(['0x3']); + jest + .spyOn(metamaskController.preferencesController, 'setAddresses') + .mockReturnValue(); + jest + .spyOn(metamaskController.preferencesController, 'setSelectedAddress') + .mockReturnValue(); + jest + .spyOn(metamaskController.preferencesController, 'setAccountLabel') + .mockReturnValue(); - getAccountsStub = sinon.stub( - metamaskController.keyringController, - 'getAccounts', - ); - // Need to return different address to mock the behavior of - // adding a new account from the keyring - getAccountsStub.onCall(0).returns(Promise.resolve(['0x1'])); - getAccountsStub.onCall(1).returns(Promise.resolve(['0x2'])); - getAccountsStub.onCall(2).returns(Promise.resolve(['0x3'])); - getAccountsStub.onCall(3).returns(Promise.resolve(['0x4'])); - sinon.spy(metamaskController.preferencesController, 'setAddresses'); - sinon.spy( - metamaskController.preferencesController, - 'setSelectedAddress', - ); - sinon.spy(metamaskController.preferencesController, 'setAccountLabel'); await metamaskController .connectHardware(HardwareDeviceNames.trezor, 0, `m/44'/1'/0'/0`) .catch(() => null); @@ -808,97 +759,77 @@ describe('MetaMaskController', function () { ); }); - afterEach(function () { - window.open.restore(); - metamaskController.keyringController.addNewAccount.restore(); - metamaskController.keyringController.getAccounts.restore(); - metamaskController.preferencesController.setAddresses.restore(); - metamaskController.preferencesController.setSelectedAddress.restore(); - metamaskController.preferencesController.setAccountLabel.restore(); - }); - - it('should set unlockedAccount in the keyring', async function () { + it('should set unlockedAccount in the keyring', async () => { const keyrings = await metamaskController.coreKeyringController.getKeyringsByType( KeyringType.trezor, ); - assert.equal(keyrings[0].unlockedAccount, accountToUnlock); + expect(keyrings[0].unlockedAccount).toStrictEqual(accountToUnlock); }); - it('should call keyringController.addNewAccount', async function () { - assert(metamaskController.keyringController.addNewAccount.calledOnce); + it('should call keyringController.addNewAccount', async () => { + expect( + metamaskController.keyringController.addNewAccount, + ).toHaveBeenCalledTimes(1); }); - it('should call keyringController.getAccounts ', async function () { - assert(metamaskController.keyringController.getAccounts.called); + it('should call keyringController.getAccounts', async () => { + expect( + metamaskController.keyringController.getAccounts, + ).toHaveBeenCalledTimes(3); }); - it('should call preferencesController.setAddresses', async function () { - assert( - metamaskController.preferencesController.setAddresses.calledOnce, - ); + it('should call preferencesController.setAddresses', async () => { + expect( + metamaskController.preferencesController.setAddresses, + ).toHaveBeenCalledTimes(1); }); - it('should call preferencesController.setSelectedAddress', async function () { - assert( - metamaskController.preferencesController.setSelectedAddress - .calledOnce, - ); + it('should call preferencesController.setSelectedAddress', async () => { + expect( + metamaskController.preferencesController.setSelectedAddress, + ).toHaveBeenCalledTimes(1); }); - it('should call preferencesController.setAccountLabel', async function () { - assert( - metamaskController.preferencesController.setAccountLabel.calledOnce, - ); + it('should call preferencesController.setAccountLabel', async () => { + expect( + metamaskController.preferencesController.setAccountLabel, + ).toHaveBeenCalledTimes(1); }); }); - describe('#addNewAccount', function () { - it('errors when an primary keyring is does not exist', async function () { + describe('#addNewAccount', () => { + it('errors when an primary keyring is does not exist', async () => { const addNewAccount = metamaskController.addNewAccount(); - try { - await addNewAccount; - assert.fail('should throw'); - } catch (e) { - assert.equal(e.message, 'No HD keyring found'); - } + await expect(addNewAccount).rejects.toThrow('No HD keyring found'); }); }); - describe('#verifyseedPhrase', function () { - it('errors when no keying is provided', async function () { - try { - await metamaskController.verifySeedPhrase(); - } catch (error) { - assert.equal(error.message, 'No HD keyring found.'); - } + describe('#verifyseedPhrase', () => { + it('errors when no keying is provided', async () => { + await expect(metamaskController.verifySeedPhrase()).rejects.toThrow( + 'No HD keyring found', + ); }); - it('#addNewAccount', async function () { + it('#addNewAccount', async () => { await metamaskController.createNewVaultAndKeychain('password'); await metamaskController.addNewAccount(1); const getAccounts = await metamaskController.keyringController.getAccounts(); - assert.equal(getAccounts.length, 2); + expect(getAccounts).toHaveLength(2); }); }); - describe('#resetAccount', function () { - it('wipes transactions from only the correct network id and with the selected address', async function () { - const selectedAddressStub = sinon.stub( - metamaskController.preferencesController, - 'getSelectedAddress', - ); - const getNetworkIdStub = sinon.stub( - metamaskController.txController.txStateManager, - 'getNetworkId', - ); - - selectedAddressStub.returns( - '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc', - ); - getNetworkIdStub.returns(42); + describe('#resetAccount', () => { + it('wipes transactions from only the correct network id and with the selected address', async () => { + jest + .spyOn(metamaskController.preferencesController, 'getSelectedAddress') + .mockReturnValue('0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc'); + jest + .spyOn(metamaskController.txController.txStateManager, 'getNetworkId') + .mockReturnValue(42); metamaskController.txController.txStateManager._addTransactionsToState([ createTxMeta({ @@ -927,84 +858,75 @@ describe('MetaMaskController', function () { ]); await metamaskController.resetAccount(); - assert.equal( + + expect( metamaskController.txController.txStateManager.getTransaction(1), - undefined, - ); + ).toBeUndefined(); }); }); - describe('#removeAccount', function () { + describe('#removeAccount', () => { let ret; const addressToRemove = '0x1'; let mockKeyring; - beforeEach(async function () { + beforeEach(async () => { mockKeyring = { - getAccounts: sinon.stub().returns(Promise.resolve([])), - destroy: sinon.stub(), + getAccounts: jest.fn().mockResolvedValue([]), + destroy: jest.fn(), }; - sinon.stub(metamaskController.keyringController, 'removeAccount'); - sinon.stub(metamaskController, 'removeAllAccountPermissions'); - sinon - .stub( + jest + .spyOn(metamaskController.keyringController, 'removeAccount') + .mockReturnValue(); + jest + .spyOn(metamaskController, 'removeAllAccountPermissions') + .mockReturnValue(); + + jest + .spyOn( metamaskController.coreKeyringController, 'getKeyringForAccount', ) - .returns(Promise.resolve(mockKeyring)); + .mockResolvedValue(mockKeyring); ret = await metamaskController.removeAccount(addressToRemove); }); - afterEach(function () { - metamaskController.keyringController.removeAccount.restore(); - metamaskController.removeAllAccountPermissions.restore(); - - mockKeyring.getAccounts.resetHistory(); - mockKeyring.destroy.resetHistory(); - }); - - it('should call keyringController.removeAccount', async function () { - assert( - metamaskController.keyringController.removeAccount.calledWith( - addressToRemove, - ), - ); + it('should call keyringController.removeAccount', async () => { + expect( + metamaskController.keyringController.removeAccount, + ).toHaveBeenCalledWith(addressToRemove); }); - it('should call metamaskController.removeAllAccountPermissions', async function () { - assert( - metamaskController.removeAllAccountPermissions.calledWith( - addressToRemove, - ), - ); + it('should call metamaskController.removeAllAccountPermissions', async () => { + expect( + metamaskController.removeAllAccountPermissions, + ).toHaveBeenCalledWith(addressToRemove); }); - it('should return address', async function () { - assert.equal(ret, '0x1'); + it('should return address', async () => { + expect(ret).toStrictEqual('0x1'); }); - it('should call coreKeyringController.getKeyringForAccount', async function () { - assert( - metamaskController.coreKeyringController.getKeyringForAccount.calledWith( - addressToRemove, - ), - ); + it('should call coreKeyringController.getKeyringForAccount', async () => { + expect( + metamaskController.coreKeyringController.getKeyringForAccount, + ).toHaveBeenCalledWith(addressToRemove); }); - it('should call keyring.destroy', async function () { - assert(mockKeyring.destroy.calledOnce); + it('should call keyring.destroy', async () => { + expect(mockKeyring.destroy).toHaveBeenCalledTimes(1); }); }); - describe('#setupUntrustedCommunication', function () { + describe('#setupUntrustedCommunication', () => { const mockTxParams = { from: TEST_ADDRESS }; - beforeEach(function () { + beforeEach(() => { initializeMockMiddlewareLog(); }); - after(function () { + afterAll(() => { tearDownMockMiddlewareLog(); }); - it('sets up phishing stream for untrusted communication', async function () { + it('sets up phishing stream for untrusted communication', async () => { const phishingMessageSender = { url: 'http://test.metamask-phishing.io', tab: {}, @@ -1016,8 +938,7 @@ describe('MetaMaskController', function () { cb(); return; } - assert.equal( - chunk.data.hostname, + expect(chunk.data.hostname).toStrictEqual( new URL(phishingMessageSender.url).hostname, ); resolve(); @@ -1032,7 +953,7 @@ describe('MetaMaskController', function () { streamTest.end(); }); - it('adds a tabId and origin to requests', function (done) { + it('adds a tabId and origin to requests', async () => { const messageSender = { url: 'http://mycrypto.com', tab: { id: 456 }, @@ -1056,26 +977,32 @@ describe('MetaMaskController', function () { params: [{ ...mockTxParams }], method: 'eth_sendTransaction', }; - streamTest.write( - { - name: 'metamask-provider', - data: message, - }, - null, - () => { - setTimeout(() => { - assert.deepStrictEqual(loggerMiddlewareMock.requests[0], { - ...message, - origin: 'http://mycrypto.com', - tabId: 456, + + await new Promise((resolve) => { + streamTest.write( + { + name: 'metamask-provider', + data: message, + }, + null, + () => { + setTimeout(() => { + expect(loggerMiddlewareMock.requests[0]).toHaveProperty( + 'origin', + 'http://mycrypto.com', + ); + expect(loggerMiddlewareMock.requests[0]).toHaveProperty( + 'tabId', + 456, + ); + resolve(); }); - done(); - }); - }, - ); + }, + ); + }); }); - it('should add only origin to request if tabId not provided', function (done) { + it('should add only origin to request if tabId not provided', async () => { const messageSender = { url: 'http://mycrypto.com', }; @@ -1098,34 +1025,39 @@ describe('MetaMaskController', function () { params: [{ ...mockTxParams }], method: 'eth_sendTransaction', }; - streamTest.write( - { - name: 'metamask-provider', - data: message, - }, - null, - () => { - setTimeout(() => { - assert.deepStrictEqual(loggerMiddlewareMock.requests[0], { - ...message, - origin: 'http://mycrypto.com', + await new Promise((resolve) => { + streamTest.write( + { + name: 'metamask-provider', + data: message, + }, + null, + () => { + setTimeout(() => { + expect(loggerMiddlewareMock.requests[0]).not.toHaveProperty( + 'tabId', + ); + expect(loggerMiddlewareMock.requests[0]).toHaveProperty( + 'origin', + 'http://mycrypto.com', + ); + resolve(); }); - done(); - }); - }, - ); + }, + ); + }); }); }); - describe('#setupTrustedCommunication', function () { - it('sets up controller JSON-RPC api for trusted communication', async function () { + describe('#setupTrustedCommunication', () => { + it('sets up controller JSON-RPC api for trusted communication', async () => { const messageSender = { url: 'http://mycrypto.com', tab: {}, }; const { promise, resolve } = deferredPromise(); const streamTest = createThoughStream((chunk, _, cb) => { - assert.equal(chunk.name, 'controller'); + expect(chunk.name).toStrictEqual('controller'); resolve(); cb(); }); @@ -1136,50 +1068,50 @@ describe('MetaMaskController', function () { }); }); - describe('#markPasswordForgotten', function () { - it('adds and sets forgottenPassword to config data to true', function () { + describe('#markPasswordForgotten', () => { + it('adds and sets forgottenPassword to config data to true', () => { metamaskController.markPasswordForgotten(noop); const state = metamaskController.getState(); - assert.equal(state.forgottenPassword, true); + expect(state.forgottenPassword).toStrictEqual(true); }); }); - describe('#unMarkPasswordForgotten', function () { - it('adds and sets forgottenPassword to config data to false', function () { + describe('#unMarkPasswordForgotten', () => { + it('adds and sets forgottenPassword to config data to false', () => { metamaskController.unMarkPasswordForgotten(noop); const state = metamaskController.getState(); - assert.equal(state.forgottenPassword, false); + expect(state.forgottenPassword).toStrictEqual(false); }); }); - describe('#_onKeyringControllerUpdate', function () { - it('should do nothing if there are no keyrings in state', async function () { - const syncAddresses = sinon.fake(); - const syncWithAddresses = sinon.fake(); - sandbox.replace(metamaskController, 'preferencesController', { - syncAddresses, - }); - sandbox.replace(metamaskController, 'accountTracker', { - syncWithAddresses, - }); + describe('#_onKeyringControllerUpdate', () => { + it('should do nothing if there are no keyrings in state', async () => { + jest + .spyOn(metamaskController.preferencesController, 'syncAddresses') + .mockReturnValue(); + jest + .spyOn(metamaskController.accountTracker, 'syncWithAddresses') + .mockReturnValue(); const oldState = metamaskController.getState(); await metamaskController._onKeyringControllerUpdate({ keyrings: [] }); - assert.ok(syncAddresses.notCalled); - assert.ok(syncWithAddresses.notCalled); - assert.deepEqual(metamaskController.getState(), oldState); + expect( + metamaskController.preferencesController.syncAddresses, + ).not.toHaveBeenCalled(); + expect( + metamaskController.accountTracker.syncWithAddresses, + ).not.toHaveBeenCalled(); + expect(metamaskController.getState()).toStrictEqual(oldState); }); - it('should sync addresses if there are keyrings in state', async function () { - const syncAddresses = sinon.fake(); - const syncWithAddresses = sinon.fake(); - sandbox.replace(metamaskController, 'preferencesController', { - syncAddresses, - }); - sandbox.replace(metamaskController, 'accountTracker', { - syncWithAddresses, - }); + it('should sync addresses if there are keyrings in state', async () => { + jest + .spyOn(metamaskController.preferencesController, 'syncAddresses') + .mockReturnValue(); + jest + .spyOn(metamaskController.accountTracker, 'syncWithAddresses') + .mockReturnValue(); const oldState = metamaskController.getState(); await metamaskController._onKeyringControllerUpdate({ @@ -1190,20 +1122,22 @@ describe('MetaMaskController', function () { ], }); - assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]); - assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]]); - assert.deepEqual(metamaskController.getState(), oldState); + expect( + metamaskController.preferencesController.syncAddresses, + ).toHaveBeenCalledWith(['0x1', '0x2']); + expect( + metamaskController.accountTracker.syncWithAddresses, + ).toHaveBeenCalledWith(['0x1', '0x2']); + expect(metamaskController.getState()).toStrictEqual(oldState); }); - it('should NOT update selected address if already unlocked', async function () { - const syncAddresses = sinon.fake(); - const syncWithAddresses = sinon.fake(); - sandbox.replace(metamaskController, 'preferencesController', { - syncAddresses, - }); - sandbox.replace(metamaskController, 'accountTracker', { - syncWithAddresses, - }); + it('should NOT update selected address if already unlocked', async () => { + jest + .spyOn(metamaskController.preferencesController, 'syncAddresses') + .mockReturnValue(); + jest + .spyOn(metamaskController.accountTracker, 'syncWithAddresses') + .mockReturnValue(); const oldState = metamaskController.getState(); await metamaskController._onKeyringControllerUpdate({ @@ -1215,34 +1149,35 @@ describe('MetaMaskController', function () { ], }); - assert.deepEqual(syncAddresses.args, [[['0x1', '0x2']]]); - assert.deepEqual(syncWithAddresses.args, [[['0x1', '0x2']]]); - assert.deepEqual(metamaskController.getState(), oldState); + expect( + metamaskController.preferencesController.syncAddresses, + ).toHaveBeenCalledWith(['0x1', '0x2']); + expect( + metamaskController.accountTracker.syncWithAddresses, + ).toHaveBeenCalledWith(['0x1', '0x2']); + expect(metamaskController.getState()).toStrictEqual(oldState); }); }); - describe('markNotificationsAsRead', function () { - it('marks the notification as read', function () { + describe('markNotificationsAsRead', () => { + it('marks the notification as read', () => { metamaskController.markNotificationsAsRead([NOTIFICATION_ID]); const readNotification = metamaskController.getState().notifications[NOTIFICATION_ID]; - assert.notEqual(readNotification.readDate, null); + expect(readNotification.readDate).not.toBeNull(); }); }); - describe('dismissNotifications', function () { - it('deletes the notification from state', function () { + describe('dismissNotifications', () => { + it('deletes the notification from state', () => { metamaskController.dismissNotifications([NOTIFICATION_ID]); const state = metamaskController.getState().notifications; - assert.ok( - !Object.values(state).includes(NOTIFICATION_ID), - 'Object should not include the deleted notification', - ); + expect(Object.values(state)).not.toContain(NOTIFICATION_ID); }); }); - describe('getTokenStandardAndDetails', function () { - it('gets token data from the token list if available, and with a balance retrieved by fetchTokenBalance', async function () { + describe('getTokenStandardAndDetails', () => { + it('gets token data from the token list if available, and with a balance retrieved by fetchTokenBalance', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1274,25 +1209,13 @@ describe('MetaMaskController', function () { '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === 'ERC20', - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === String(tokenData.decimals), - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === tokenData.symbol, - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === '3000000000000000000', - 'tokenDetails should include a balance', - ); + expect(tokenDetails.standard).toStrictEqual('ERC20'); + expect(tokenDetails.decimals).toStrictEqual(String(tokenData.decimals)); + expect(tokenDetails.symbol).toStrictEqual(tokenData.symbol); + expect(tokenDetails.balance).toStrictEqual('3000000000000000000'); }); - it('gets token data from tokens if available, and with a balance retrieved by fetchTokenBalance', async function () { + it('gets token data from tokens if available, and with a balance retrieved by fetchTokenBalance', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1325,25 +1248,13 @@ describe('MetaMaskController', function () { '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === 'ERC20', - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === String(tokenData.decimals), - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === tokenData.symbol, - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === '3000000000000000000', - 'tokenDetails should include a balance', - ); + expect(tokenDetails.standard).toStrictEqual('ERC20'); + expect(tokenDetails.decimals).toStrictEqual(String(tokenData.decimals)); + expect(tokenDetails.symbol).toStrictEqual(tokenData.symbol); + expect(tokenDetails.balance).toStrictEqual('3000000000000000000'); }); - it('gets token data from contract-metadata if available, and with a balance retrieved by fetchTokenBalance', async function () { + it('gets token data from contract-metadata if available, and with a balance retrieved by fetchTokenBalance', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1362,25 +1273,13 @@ describe('MetaMaskController', function () { '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === 'ERC20', - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === '18', - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === 'DAI', - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === '3000000000000000000', - 'tokenDetails should include a balance', - ); + expect(tokenDetails.standard).toStrictEqual('ERC20'); + expect(tokenDetails.decimals).toStrictEqual('18'); + expect(tokenDetails.symbol).toStrictEqual('DAI'); + expect(tokenDetails.balance).toStrictEqual('3000000000000000000'); }); - it('gets token data from the blockchain, via the assetsContractController, if not available through other sources', async function () { + it('gets token data from the blockchain, via the assetsContractController, if not available through other sources', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1409,39 +1308,28 @@ describe('MetaMaskController', function () { metamaskController.provider = provider; - sandbox - .stub( + jest + .spyOn( metamaskController.assetsContractController, 'getTokenStandardAndDetails', ) - .callsFake(() => { - return tokenData; - }); + .mockReturnValue(tokenData); const tokenDetails = await metamaskController.getTokenStandardAndDetails( '0xNotInTokenList', '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === tokenData.standard.toUpperCase(), - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === String(tokenData.decimals), - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === tokenData.symbol, - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === tokenData.balance, - 'tokenDetails should include a balance', + + expect(tokenDetails.standard).toStrictEqual( + tokenData.standard.toUpperCase(), ); + expect(tokenDetails.decimals).toStrictEqual(String(tokenData.decimals)); + expect(tokenDetails.symbol).toStrictEqual(tokenData.symbol); + expect(tokenDetails.balance).toStrictEqual(tokenData.balance); }); - it('gets token data from the blockchain, via the assetsContractController, if it is in the token list but is an ERC721', async function () { + it('gets token data from the blockchain, via the assetsContractController, if it is in the token list but is an ERC721', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1470,39 +1358,28 @@ describe('MetaMaskController', function () { metamaskController.provider = provider; - sandbox - .stub( + jest + .spyOn( metamaskController.assetsContractController, 'getTokenStandardAndDetails', ) - .callsFake(() => { - return tokenData; - }); + .mockReturnValue(tokenData); const tokenDetails = await metamaskController.getTokenStandardAndDetails( '0xAAA75474e89094c44da98b954eedeac495271d0f', '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === tokenData.standard.toUpperCase(), - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === String(tokenData.decimals), - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === tokenData.symbol, - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === tokenData.balance, - 'tokenDetails should include a balance', + + expect(tokenDetails.standard).toStrictEqual( + tokenData.standard.toUpperCase(), ); + expect(tokenDetails.decimals).toStrictEqual(String(tokenData.decimals)); + expect(tokenDetails.symbol).toStrictEqual(tokenData.symbol); + expect(tokenDetails.balance).toStrictEqual(tokenData.balance); }); - it('gets token data from the blockchain, via the assetsContractController, if it is in the token list but is an ERC1155', async function () { + it('gets token data from the blockchain, via the assetsContractController, if it is in the token list but is an ERC1155', async () => { const providerResultStub = { eth_getCode: '0x123', eth_call: @@ -1531,199 +1408,195 @@ describe('MetaMaskController', function () { metamaskController.provider = provider; - sandbox - .stub( + jest + .spyOn( metamaskController.assetsContractController, 'getTokenStandardAndDetails', ) - .callsFake(() => { - return tokenData; - }); + .mockReturnValue(tokenData); const tokenDetails = await metamaskController.getTokenStandardAndDetails( '0xAAA75474e89094c44da98b954eedeac495271d0f', '0xf0d172594caedee459b89ad44c94098e474571b6', ); - assert.ok( - tokenDetails.standard === tokenData.standard.toUpperCase(), - 'tokenDetails should include token standard in upper case', - ); - assert.ok( - tokenDetails.decimals === String(tokenData.decimals), - 'tokenDetails should include token decimals as a string', - ); - assert.ok( - tokenDetails.symbol === tokenData.symbol, - 'tokenDetails should include token symbol', - ); - assert.ok( - tokenDetails.balance === tokenData.balance, - 'tokenDetails should include a balance', + expect(tokenDetails.standard).toStrictEqual( + tokenData.standard.toUpperCase(), ); + expect(tokenDetails.decimals).toStrictEqual(String(tokenData.decimals)); + expect(tokenDetails.symbol).toStrictEqual(tokenData.symbol); + expect(tokenDetails.balance).toStrictEqual(tokenData.balance); }); - describe('findNetworkConfigurationBy', function () { - it('returns null if passed an object containing a valid networkConfiguration key but no matching value is found', function () { - assert.strictEqual( + describe('findNetworkConfigurationBy', () => { + it('returns null if passed an object containing a valid networkConfiguration key but no matching value is found', () => { + expect( metamaskController.findNetworkConfigurationBy({ chainId: '0xnone', }), - null, - ); + ).toStrictEqual(null); }); - it('returns null if passed an object containing an invalid networkConfiguration key', function () { - assert.strictEqual( + it('returns null if passed an object containing an invalid networkConfiguration key', () => { + expect( metamaskController.findNetworkConfigurationBy({ invalidKey: '0xnone', }), - null, - ); + ).toStrictEqual(null); }); - it('returns matching networkConfiguration when passed a chainId that matches an existing configuration', function () { - assert.deepStrictEqual( + it('returns matching networkConfiguration when passed a chainId that matches an existing configuration', () => { + expect( metamaskController.findNetworkConfigurationBy({ chainId: MAINNET_CHAIN_ID, }), - { - chainId: MAINNET_CHAIN_ID, - nickname: 'Alt Mainnet', - id: NETWORK_CONFIGURATION_ID_1, - rpcUrl: ALT_MAINNET_RPC_URL, - ticker: ETH, - type: NETWORK_TYPES.RPC, - }, - ); + ).toStrictEqual({ + chainId: MAINNET_CHAIN_ID, + nickname: 'Alt Mainnet', + id: NETWORK_CONFIGURATION_ID_1, + rpcUrl: ALT_MAINNET_RPC_URL, + ticker: ETH, + type: NETWORK_TYPES.RPC, + }); }); - it('returns matching networkConfiguration when passed a ticker that matches an existing configuration', function () { - assert.deepStrictEqual( + it('returns matching networkConfiguration when passed a ticker that matches an existing configuration', () => { + expect( metamaskController.findNetworkConfigurationBy({ ticker: MATIC, }), - { - rpcUrl: POLYGON_RPC_URL, - type: NETWORK_TYPES.RPC, - chainId: POLYGON_CHAIN_ID, - ticker: MATIC, - nickname: 'Polygon', - id: NETWORK_CONFIGURATION_ID_2, - }, - ); + ).toStrictEqual({ + rpcUrl: POLYGON_RPC_URL, + type: NETWORK_TYPES.RPC, + chainId: POLYGON_CHAIN_ID, + ticker: MATIC, + nickname: 'Polygon', + id: NETWORK_CONFIGURATION_ID_2, + }); }); - it('returns matching networkConfiguration when passed a nickname that matches an existing configuration', function () { - assert.deepStrictEqual( + it('returns matching networkConfiguration when passed a nickname that matches an existing configuration', () => { + expect( metamaskController.findNetworkConfigurationBy({ nickname: 'Alt Mainnet', }), - { - chainId: MAINNET_CHAIN_ID, - nickname: 'Alt Mainnet', - id: NETWORK_CONFIGURATION_ID_1, - rpcUrl: ALT_MAINNET_RPC_URL, - ticker: ETH, - type: NETWORK_TYPES.RPC, - }, - ); + ).toStrictEqual({ + chainId: MAINNET_CHAIN_ID, + nickname: 'Alt Mainnet', + id: NETWORK_CONFIGURATION_ID_1, + rpcUrl: ALT_MAINNET_RPC_URL, + ticker: ETH, + type: NETWORK_TYPES.RPC, + }); }); - it('returns null if passed an object containing mismatched networkConfiguration key/value combination', function () { - assert.deepStrictEqual( + it('returns null if passed an object containing mismatched networkConfiguration key/value combination', () => { + expect( metamaskController.findNetworkConfigurationBy({ nickname: MAINNET_CHAIN_ID, }), - null, - ); + ).toStrictEqual(null); }); - it('returns the first networkConfiguration added if passed an key/value combination for which there are multiple matching configurations', function () { - assert.deepStrictEqual( + it('returns the first networkConfiguration added if passed an key/value combination for which there are multiple matching configurations', () => { + expect( metamaskController.findNetworkConfigurationBy({ chainId: POLYGON_CHAIN_ID, }), - { - rpcUrl: POLYGON_RPC_URL, - type: NETWORK_TYPES.RPC, - chainId: POLYGON_CHAIN_ID, - ticker: MATIC, - nickname: 'Polygon', - id: NETWORK_CONFIGURATION_ID_2, - }, - ); + ).toStrictEqual({ + rpcUrl: POLYGON_RPC_URL, + type: NETWORK_TYPES.RPC, + chainId: POLYGON_CHAIN_ID, + ticker: MATIC, + nickname: 'Polygon', + id: NETWORK_CONFIGURATION_ID_2, + }); }); }); }); - describe('incoming transactions', function () { - let txControllerStub, preferencesControllerSpy, controllerMessengerSpy; - - beforeEach(function () { - txControllerStub = TransactionController.prototype; - preferencesControllerSpy = metamaskController.preferencesController; - controllerMessengerSpy = ControllerMessenger.prototype; - }); - - it('starts incoming transaction polling if incomingTransactionsPreferences is enabled for that chainId', async function () { - assert(txControllerStub.startIncomingTransactionPolling.notCalled); + describe('incoming transactions', () => { + it('starts incoming transaction polling if incomingTransactionsPreferences is enabled for that chainId', async () => { + expect( + TransactionController.prototype.startIncomingTransactionPolling, + ).not.toHaveBeenCalled(); - await preferencesControllerSpy.store.subscribe.lastCall.args[0]({ - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: true, + await metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( + { + incomingTransactionsPreferences: { + [MAINNET_CHAIN_ID]: true, + }, }, - }); + ); - assert(txControllerStub.startIncomingTransactionPolling.calledOnce); + expect( + TransactionController.prototype.startIncomingTransactionPolling, + ).toHaveBeenCalledTimes(1); }); - it('stops incoming transaction polling if incomingTransactionsPreferences is disabled for that chainIdd', async function () { - assert(txControllerStub.stopIncomingTransactionPolling.notCalled); + it('stops incoming transaction polling if incomingTransactionsPreferences is disabled for that chainId', async () => { + expect( + TransactionController.prototype.stopIncomingTransactionPolling, + ).not.toHaveBeenCalled(); - await preferencesControllerSpy.store.subscribe.lastCall.args[0]({ - incomingTransactionsPreferences: { - [MAINNET_CHAIN_ID]: false, + await metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( + { + incomingTransactionsPreferences: { + [MAINNET_CHAIN_ID]: false, + }, }, - }); + ); - assert(txControllerStub.stopIncomingTransactionPolling.calledOnce); + expect( + TransactionController.prototype.stopIncomingTransactionPolling, + ).toHaveBeenCalledTimes(1); }); - it('updates incoming transactions when changing account', async function () { - assert(txControllerStub.updateIncomingTransactions.notCalled); + it('updates incoming transactions when changing account', async () => { + expect( + TransactionController.prototype.updateIncomingTransactions, + ).not.toHaveBeenCalled(); - await preferencesControllerSpy.store.subscribe.lastCall.args[0]({ - selectedAddress: 'foo', - }); + await metamaskController.preferencesController.store.subscribe.mock.lastCall[0]( + { + selectedAddress: 'foo', + }, + ); - assert(txControllerStub.updateIncomingTransactions.calledOnce); + expect( + TransactionController.prototype.updateIncomingTransactions, + ).toHaveBeenCalledTimes(1); }); - it('updates incoming transactions when changing network', async function () { - assert(txControllerStub.updateIncomingTransactions.notCalled); + it('updates incoming transactions when changing network', async () => { + expect( + TransactionController.prototype.updateIncomingTransactions, + ).not.toHaveBeenCalled(); - await controllerMessengerSpy.subscribe.args + await ControllerMessenger.prototype.subscribe.mock.calls .filter((args) => args[0] === 'NetworkController:networkDidChange') .slice(-1)[0][1](); - assert(txControllerStub.updateIncomingTransactions.calledOnce); + expect( + TransactionController.prototype.updateIncomingTransactions, + ).toHaveBeenCalledTimes(1); }); }); }); - describe('MV3 Specific behaviour', function () { - before(async function () { + describe('MV3 Specific behaviour', () => { + beforeAll(async () => { + mockIsManifestV3.mockReturnValue(true); globalThis.isFirstTimeProfileLoaded = true; }); - beforeEach(async function () { - sandbox.spy(MetaMaskControllerMV3.prototype, 'resetStates'); + beforeEach(async () => { + jest.spyOn(MetaMaskController.prototype, 'resetStates'); }); - it('it should reset state', function () { - browserPolyfillMock.storage.session.set.resetHistory(); + it('should reset state', () => { + browserPolyfillMock.storage.session.set.mockReset(); - const metamaskControllerMV3 = new MetaMaskControllerMV3({ + const metamaskController = new MetaMaskController({ showUserConfirmation: noop, encryptor: { encrypt(_, object) { @@ -1744,20 +1617,18 @@ describe('MetaMaskController', function () { infuraProjectId: 'foo', isFirstMetaMaskControllerSetup: true, }); - assert.equal(metamaskControllerMV3.resetStates.callCount, 1); - assert.equal(browserPolyfillMock.storage.session.set.callCount, 1); - assert.deepEqual( - browserPolyfillMock.storage.session.set.getCall(0).args[0], - { - isFirstMetaMaskControllerSetup: false, - }, - ); + + expect(metamaskController.resetStates).toHaveBeenCalledTimes(1); + expect(browserPolyfillMock.storage.session.set).toHaveBeenCalledTimes(1); + expect(browserPolyfillMock.storage.session.set).toHaveBeenCalledWith({ + isFirstMetaMaskControllerSetup: false, + }); }); - it('in mv3, it should not reset states if isFirstMetaMaskControllerSetup is false', function () { - browserPolyfillMock.storage.session.set.resetHistory(); + it('in mv3, it should not reset states if isFirstMetaMaskControllerSetup is false', () => { + browserPolyfillMock.storage.session.set.mockReset(); - const metamaskControllerMV3 = new MetaMaskControllerMV3({ + const metamaskController = new MetaMaskController({ showUserConfirmation: noop, encryptor: { encrypt(_, object) { @@ -1778,8 +1649,9 @@ describe('MetaMaskController', function () { infuraProjectId: 'foo', isFirstMetaMaskControllerSetup: false, }); - assert.equal(metamaskControllerMV3.resetStates.callCount, 0); - assert.equal(browserPolyfillMock.storage.session.set.callCount, 0); + + expect(metamaskController.resetStates).not.toHaveBeenCalled(); + expect(browserPolyfillMock.storage.session.set).not.toHaveBeenCalled(); }); }); }); diff --git a/jest.config.js b/jest.config.js index 72649eaf6118..f346219b0185 100644 --- a/jest.config.js +++ b/jest.config.js @@ -11,6 +11,7 @@ module.exports = { '/app/scripts/flask/**/*.js', '/app/scripts/lib/**/*.(js|ts)', '/app/scripts/lib/createRPCMethodTrackingMiddleware.js', + '/app/scripts/metamask-controller.js', '/app/scripts/migrations/*.js', '/app/scripts/migrations/*.ts', '!/app/scripts/migrations/*.test.(js|ts)', @@ -52,6 +53,7 @@ module.exports = { '/app/scripts/flask/**/*.test.js', '/app/scripts/lib/**/*.test.(js|ts)', '/app/scripts/lib/createRPCMethodTrackingMiddleware.test.js', + '/app/scripts/metamask-controller.test.js', '/app/scripts/migrations/*.test.(js|ts)', '/app/scripts/platforms/*.test.js', '/app/scripts/translate.test.ts', From 422cc4e3e6142181e387b5e7c01b25115d83da51 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 12 Sep 2023 18:33:56 +0530 Subject: [PATCH 02/38] Adding env vars for blockaid to build file (#20769) --- builds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/builds.yml b/builds.yml index 5280a34c5cf3..90689f102daf 100644 --- a/builds.yml +++ b/builds.yml @@ -123,8 +123,8 @@ features: - WEB_SOCKET_PORT: null blockaid: env: - - BLOCKAID_FILE_CDN: null - - BLOCKAID_PUBLIC_KEY: null + - BLOCKAID_FILE_CDN: static.metafi.codefi.network/api/v1/confirmations/ppom + - BLOCKAID_PUBLIC_KEY: 066ad3e8af5583385e312c156d238055215d5f25247c1e91055afa756cb98a88 ### # Build Type code extensions. Things like different support links, warning pages, banners From 2147322d526c87e3ea50b50c8a16dfc63ccb9d81 Mon Sep 17 00:00:00 2001 From: Jyoti Puri Date: Tue, 12 Sep 2023 18:38:35 +0530 Subject: [PATCH 03/38] Revert ppom.js exactly yo audited version (#20826) --- app/scripts/lib/ppom/ppom.js | 828 +++++++++++++++++++---------------- 1 file changed, 442 insertions(+), 386 deletions(-) diff --git a/app/scripts/lib/ppom/ppom.js b/app/scripts/lib/ppom/ppom.js index 1b4e70adf052..39915b3a4b6e 100644 --- a/app/scripts/lib/ppom/ppom.js +++ b/app/scripts/lib/ppom/ppom.js @@ -1,5 +1,4 @@ /* eslint-disable */ -// The contents of this file were provided by the Blockaid team and pasted verbatim let wasm; @@ -7,20 +6,22 @@ const heap = new Array(128).fill(undefined); heap.push(undefined, null, true, false); -function getObject(idx) { return heap[idx]; } +function getObject(idx) { + return heap[idx]; +} let heap_next = heap.length; function dropObject(idx) { - if (idx < 132) return; - heap[idx] = heap_next; - heap_next = idx; + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; } function takeObject(idx) { - const ret = getObject(idx); - dropObject(idx); - return ret; + const ret = getObject(idx); + dropObject(idx); + return ret; } let WASM_VECTOR_LEN = 0; @@ -28,490 +29,545 @@ let WASM_VECTOR_LEN = 0; let cachedUint8Memory0 = null; function getUint8Memory0() { - if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { - cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); - } - return cachedUint8Memory0; + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; } -const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); - -const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' +const cachedTextEncoder = + typeof TextEncoder !== 'undefined' + ? new TextEncoder('utf-8') + : { + encode: () => { + throw Error('TextEncoder not available'); + }, + }; + +const encodeString = + typeof cachedTextEncoder.encodeInto === 'function' ? function (arg, view) { - return cachedTextEncoder.encodeInto(arg, view); -} + return cachedTextEncoder.encodeInto(arg, view); + } : function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; -}); + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; function passStringToWasm0(arg, malloc, realloc) { + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } - if (realloc === undefined) { - const buf = cachedTextEncoder.encode(arg); - const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); - WASM_VECTOR_LEN = buf.length; - return ptr; - } + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; - let len = arg.length; - let ptr = malloc(len, 1) >>> 0; + const mem = getUint8Memory0(); - const mem = getUint8Memory0(); + let offset = 0; - let offset = 0; + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7f) break; + mem[ptr + offset] = code; + } - for (; offset < len; offset++) { - const code = arg.charCodeAt(offset); - if (code > 0x7F) break; - mem[ptr + offset] = code; + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); } + ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); - if (offset !== len) { - if (offset !== 0) { - arg = arg.slice(offset); - } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; - const view = getUint8Memory0().subarray(ptr + offset, ptr + len); - const ret = encodeString(arg, view); + offset += ret.written; + } - offset += ret.written; - } - - WASM_VECTOR_LEN = offset; - return ptr; + WASM_VECTOR_LEN = offset; + return ptr; } function isLikeNone(x) { - return x === undefined || x === null; + return x === undefined || x === null; } let cachedInt32Memory0 = null; function getInt32Memory0() { - if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { - cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); - } - return cachedInt32Memory0; + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; } -const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); - -if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; +const cachedTextDecoder = + typeof TextDecoder !== 'undefined' + ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) + : { + decode: () => { + throw Error('TextDecoder not available'); + }, + }; + +if (typeof TextDecoder !== 'undefined') { + cachedTextDecoder.decode(); +} function getStringFromWasm0(ptr, len) { - ptr = ptr >>> 0; - return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } function addHeapObject(obj) { - if (heap_next === heap.length) heap.push(heap.length + 1); - const idx = heap_next; - heap_next = heap[idx]; + if (heap_next === heap.length) heap.push(heap.length + 1); + const idx = heap_next; + heap_next = heap[idx]; - heap[idx] = obj; - return idx; + heap[idx] = obj; + return idx; } function debugString(val) { - // primitive types - const type = typeof val; - if (type == 'number' || type == 'boolean' || val == null) { - return `${val}`; - } - if (type == 'string') { - return `"${val}"`; - } - if (type == 'symbol') { - const description = val.description; - if (description == null) { - return 'Symbol'; - } else { - return `Symbol(${description})`; - } - } - if (type == 'function') { - const name = val.name; - if (typeof name == 'string' && name.length > 0) { - return `Function(${name})`; - } else { - return 'Function'; - } - } - // objects - if (Array.isArray(val)) { - const length = val.length; - let debug = '['; - if (length > 0) { - debug += debugString(val[0]); - } - for(let i = 1; i < length; i++) { - debug += ', ' + debugString(val[i]); - } - debug += ']'; - return debug; + // primitive types + const type = typeof val; + if (type == 'number' || type == 'boolean' || val == null) { + return `${val}`; + } + if (type == 'string') { + return `"${val}"`; + } + if (type == 'symbol') { + const description = val.description; + if (description == null) { + return 'Symbol'; + } else { + return `Symbol(${description})`; } - // Test for built-in - const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); - let className; - if (builtInMatches.length > 1) { - className = builtInMatches[1]; + } + if (type == 'function') { + const name = val.name; + if (typeof name == 'string' && name.length > 0) { + return `Function(${name})`; } else { - // Failed to match the standard '[object ClassName]' - return toString.call(val); + return 'Function'; } - if (className == 'Object') { - // we're a user defined class or Object - // JSON.stringify avoids problems with cycles, and is generally much - // easier than looping through ownProperties of `val`. - try { - return 'Object(' + JSON.stringify(val) + ')'; - } catch (_) { - return 'Object'; - } + } + // objects + if (Array.isArray(val)) { + const length = val.length; + let debug = '['; + if (length > 0) { + debug += debugString(val[0]); + } + for (let i = 1; i < length; i++) { + debug += ', ' + debugString(val[i]); } - // errors - if (val instanceof Error) { - return `${val.name}: ${val.message}\n${val.stack}`; + debug += ']'; + return debug; + } + // Test for built-in + const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); + let className; + if (builtInMatches.length > 1) { + className = builtInMatches[1]; + } else { + // Failed to match the standard '[object ClassName]' + return toString.call(val); + } + if (className == 'Object') { + // we're a user defined class or Object + // JSON.stringify avoids problems with cycles, and is generally much + // easier than looping through ownProperties of `val`. + try { + return 'Object(' + JSON.stringify(val) + ')'; + } catch (_) { + return 'Object'; } - // TODO we could test for more things here, like `Set`s and `Map`s. - return className; + } + // errors + if (val instanceof Error) { + return `${val.name}: ${val.message}\n${val.stack}`; + } + // TODO we could test for more things here, like `Set`s and `Map`s. + return className; } function makeMutClosure(arg0, arg1, dtor, f) { - const state = { a: arg0, b: arg1, cnt: 1 }; - const real = (...args) => { - // First up with a closure we increment the internal reference - // count. This ensures that the Rust closure environment won't - // be deallocated while we're invoking it. - state.cnt++; - const a = state.a; - state.a = 0; - try { - return f(a, state.b, ...args); - } finally { - if (--state.cnt === 0) { - dtor(a, state.b); - - } else { - state.a = a; - } - } - }; - real.original = state; + const state = { a: arg0, b: arg1, cnt: 1 }; + const real = (...args) => { + // First up with a closure we increment the internal reference + // count. This ensures that the Rust closure environment won't + // be deallocated while we're invoking it. + state.cnt++; + const a = state.a; + state.a = 0; + try { + return f(a, state.b, ...args); + } finally { + if (--state.cnt === 0) { + dtor(a, state.b); + } else { + state.a = a; + } + } + }; + real.original = state; - return real; + return real; } function __wbg_adapter_20(arg0, arg1, arg2) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke(arg0, arg1, addHeapObject(arg2)); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke( + arg0, + arg1, + addHeapObject(arg2), + ); } function __wbg_adapter_21(arg0, arg1) { - wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(arg0, arg1); + wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy( + arg0, + arg1, + ); } /** -*/ + */ export function main() { - wasm.main(); + wasm.main(); } let cachedUint32Memory0 = null; function getUint32Memory0() { - if (cachedUint32Memory0 === null || cachedUint32Memory0.byteLength === 0) { - cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer); - } - return cachedUint32Memory0; + if (cachedUint32Memory0 === null || cachedUint32Memory0.byteLength === 0) { + cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer); + } + return cachedUint32Memory0; } function passArrayJsValueToWasm0(array, malloc) { - const ptr = malloc(array.length * 4, 4) >>> 0; - const mem = getUint32Memory0(); - for (let i = 0; i < array.length; i++) { - mem[ptr / 4 + i] = addHeapObject(array[i]); - } - WASM_VECTOR_LEN = array.length; - return ptr; + const ptr = malloc(array.length * 4, 4) >>> 0; + const mem = getUint32Memory0(); + for (let i = 0; i < array.length; i++) { + mem[ptr / 4 + i] = addHeapObject(array[i]); + } + WASM_VECTOR_LEN = array.length; + return ptr; } function handleError(f, args) { - try { - return f.apply(this, args); - } catch (e) { - wasm.__wbindgen_exn_store(addHeapObject(e)); - } + try { + return f.apply(this, args); + } catch (e) { + wasm.__wbindgen_exn_store(addHeapObject(e)); + } } function __wbg_adapter_39(arg0, arg1, arg2, arg3) { - wasm.wasm_bindgen__convert__closures__invoke2_mut(arg0, arg1, addHeapObject(arg2), addHeapObject(arg3)); + wasm.wasm_bindgen__convert__closures__invoke2_mut( + arg0, + arg1, + addHeapObject(arg2), + addHeapObject(arg3), + ); } /** -* JavaScript wrapper for [`PPOM`] -*/ + * JavaScript wrapper for [`PPOM`] + */ export class PPOM { + static __wrap(ptr) { + ptr = ptr >>> 0; + const obj = Object.create(PPOM.prototype); + obj.__wbg_ptr = ptr; - static __wrap(ptr) { - ptr = ptr >>> 0; - const obj = Object.create(PPOM.prototype); - obj.__wbg_ptr = ptr; - - return obj; - } - - __destroy_into_raw() { - const ptr = this.__wbg_ptr; - this.__wbg_ptr = 0; + return obj; + } - return ptr; - } + __destroy_into_raw() { + const ptr = this.__wbg_ptr; + this.__wbg_ptr = 0; - free() { - const ptr = this.__destroy_into_raw(); - wasm.__wbg_ppom_free(ptr); - } - /** - * @param {Function} json_rpc_callback - * @param {any[]} files - * @returns {Promise} - */ - static new(json_rpc_callback, files) { - const ptr0 = passArrayJsValueToWasm0(files, wasm.__wbindgen_malloc); - const len0 = WASM_VECTOR_LEN; - const ret = wasm.ppom_new(addHeapObject(json_rpc_callback), ptr0, len0); - return takeObject(ret); - } - /** - * @param {any} request - * @returns {Promise} - */ - validateJsonRpc(request) { - const ret = wasm.ppom_validateJsonRpc(this.__wbg_ptr, addHeapObject(request)); - return takeObject(ret); - } + return ptr; + } + + free() { + const ptr = this.__destroy_into_raw(); + wasm.__wbg_ppom_free(ptr); + } + /** + * @param {Function} json_rpc_callback + * @param {any[]} files + * @returns {Promise} + */ + static new(json_rpc_callback, files) { + const ptr0 = passArrayJsValueToWasm0(files, wasm.__wbindgen_malloc); + const len0 = WASM_VECTOR_LEN; + const ret = wasm.ppom_new(addHeapObject(json_rpc_callback), ptr0, len0); + return takeObject(ret); + } + /** + * @param {any} request + * @returns {Promise} + */ + validateJsonRpc(request) { + const ret = wasm.ppom_validateJsonRpc( + this.__wbg_ptr, + addHeapObject(request), + ); + return takeObject(ret); + } } async function __wbg_load(module, imports) { - if (typeof Response === 'function' && module instanceof Response) { - if (typeof WebAssembly.instantiateStreaming === 'function') { - try { - return await WebAssembly.instantiateStreaming(module, imports); - - } catch (e) { - if (module.headers.get('Content-Type') != 'application/wasm') { - console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); - - } else { - throw e; - } - } + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn( + '`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n', + e, + ); + } else { + throw e; } + } + } - const bytes = await module.arrayBuffer(); - return await WebAssembly.instantiate(bytes, imports); + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + } else { + const instance = await WebAssembly.instantiate(module, imports); + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; } else { - const instance = await WebAssembly.instantiate(module, imports); - - if (instance instanceof WebAssembly.Instance) { - return { instance, module }; - - } else { - return instance; - } + return instance; } + } } function __wbg_get_imports() { - const imports = {}; - imports.wbg = {}; - imports.wbg.__wbg_buffer_085ec1f694018c4f = function(arg0) { - const ret = getObject(arg0).buffer; - return addHeapObject(ret); - }; - imports.wbg.__wbg_call_01734de55d61e11d = function() { return handleError(function (arg0, arg1, arg2) { - const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_call_4c92f6aec1e1d6e6 = function() { return handleError(function (arg0, arg1, arg2, arg3) { - const ret = getObject(arg0).call(getObject(arg1), getObject(arg2), getObject(arg3)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_from_d7c216d4616bb368 = function(arg0) { - const ret = Array.from(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_get_44be0491f933a435 = function(arg0, arg1) { - const ret = getObject(arg0)[arg1 >>> 0]; - return addHeapObject(ret); - }; - imports.wbg.__wbg_length_72e2208bbc0efc61 = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_length_d813e535247d427e = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_length_fff51ee6522a1a18 = function(arg0) { - const ret = getObject(arg0).length; - return ret; - }; - imports.wbg.__wbg_new_43f1b47c28813cbd = function(arg0, arg1) { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbg_buffer_085ec1f694018c4f = function (arg0) { + const ret = getObject(arg0).buffer; + return addHeapObject(ret); + }; + imports.wbg.__wbg_call_01734de55d61e11d = function () { + return handleError(function (arg0, arg1, arg2) { + const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_call_4c92f6aec1e1d6e6 = function () { + return handleError(function (arg0, arg1, arg2, arg3) { + const ret = getObject(arg0).call( + getObject(arg1), + getObject(arg2), + getObject(arg3), + ); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_from_d7c216d4616bb368 = function (arg0) { + const ret = Array.from(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_get_44be0491f933a435 = function (arg0, arg1) { + const ret = getObject(arg0)[arg1 >>> 0]; + return addHeapObject(ret); + }; + imports.wbg.__wbg_length_72e2208bbc0efc61 = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_length_d813e535247d427e = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_length_fff51ee6522a1a18 = function (arg0) { + const ret = getObject(arg0).length; + return ret; + }; + imports.wbg.__wbg_new_43f1b47c28813cbd = function (arg0, arg1) { + try { + var state0 = { a: arg0, b: arg1 }; + var cb0 = (arg0, arg1) => { + const a = state0.a; + state0.a = 0; try { - var state0 = {a: arg0, b: arg1}; - var cb0 = (arg0, arg1) => { - const a = state0.a; - state0.a = 0; - try { - return __wbg_adapter_39(a, state0.b, arg0, arg1); - } finally { - state0.a = a; - } - }; - const ret = new Promise(cb0); - return addHeapObject(ret); + return __wbg_adapter_39(a, state0.b, arg0, arg1); } finally { - state0.a = state0.b = 0; + state0.a = a; } + }; + const ret = new Promise(cb0); + return addHeapObject(ret); + } finally { + state0.a = state0.b = 0; + } + }; + imports.wbg.__wbg_new_8125e318e6245eed = function (arg0) { + const ret = new Uint8Array(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_parse_670c19d4e984792e = function () { + return handleError(function (arg0, arg1) { + const ret = JSON.parse(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_ppom_new = function (arg0) { + const ret = PPOM.__wrap(arg0); + return addHeapObject(ret); + }; + imports.wbg.__wbg_resolve_53698b95aaf7fcf8 = function (arg0) { + const ret = Promise.resolve(getObject(arg0)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_set_5cf90238115182c3 = function (arg0, arg1, arg2) { + getObject(arg0).set(getObject(arg1), arg2 >>> 0); + }; + imports.wbg.__wbg_stringify_e25465938f3f611f = function () { + return handleError(function (arg0) { + const ret = JSON.stringify(getObject(arg0)); + return addHeapObject(ret); + }, arguments); + }; + imports.wbg.__wbg_then_b2267541e2a73865 = function (arg0, arg1, arg2) { + const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); + return addHeapObject(ret); + }; + imports.wbg.__wbg_then_f7e06ee3c11698eb = function (arg0, arg1) { + const ret = getObject(arg0).then(getObject(arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_cb_drop = function (arg0) { + const obj = takeObject(arg0).original; + if (obj.cnt-- == 1) { + obj.a = 0; + return true; + } + const ret = false; + return ret; + }; + imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined = + function (arg0, arg1, arg2) { + const ret = makeMutClosure( + arg0, + arg1, + __wbg_adapter_21, + __wbg_adapter_20, + ); + return addHeapObject(ret); }; - imports.wbg.__wbg_new_8125e318e6245eed = function(arg0) { - const ret = new Uint8Array(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_parse_670c19d4e984792e = function() { return handleError(function (arg0, arg1) { - const ret = JSON.parse(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_ppom_new = function(arg0) { - const ret = PPOM.__wrap(arg0); - return addHeapObject(ret); - }; - imports.wbg.__wbg_resolve_53698b95aaf7fcf8 = function(arg0) { - const ret = Promise.resolve(getObject(arg0)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_set_5cf90238115182c3 = function(arg0, arg1, arg2) { - getObject(arg0).set(getObject(arg1), arg2 >>> 0); - }; - imports.wbg.__wbg_stringify_e25465938f3f611f = function() { return handleError(function (arg0) { - const ret = JSON.stringify(getObject(arg0)); - return addHeapObject(ret); - }, arguments) }; - imports.wbg.__wbg_then_b2267541e2a73865 = function(arg0, arg1, arg2) { - const ret = getObject(arg0).then(getObject(arg1), getObject(arg2)); - return addHeapObject(ret); - }; - imports.wbg.__wbg_then_f7e06ee3c11698eb = function(arg0, arg1) { - const ret = getObject(arg0).then(getObject(arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_cb_drop = function(arg0) { - const obj = takeObject(arg0).original; - if (obj.cnt-- == 1) { - obj.a = 0; - return true; - } - const ret = false; - return ret; - }; - imports.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined = function(arg0, arg1, arg2) { - const ret = makeMutClosure(arg0, arg1, __wbg_adapter_21, __wbg_adapter_20); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { - const ret = debugString(getObject(arg1)); - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - const len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbindgen_error_new = function(arg0, arg1) { - const ret = new Error(getStringFromWasm0(arg0, arg1)); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_is_undefined = function(arg0) { - const ret = getObject(arg0) === undefined; - return ret; - }; - imports.wbg.__wbindgen_memory = function() { - const ret = wasm.memory; - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_object_drop_ref = function(arg0) { - takeObject(arg0); - }; - imports.wbg.__wbindgen_string_get = function(arg0, arg1) { - const obj = getObject(arg1); - const ret = typeof(obj) === 'string' ? obj : undefined; - var ptr1 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); - var len1 = WASM_VECTOR_LEN; - getInt32Memory0()[arg0 / 4 + 1] = len1; - getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; - imports.wbg.__wbindgen_string_new = function(arg0, arg1) { - const ret = getStringFromWasm0(arg0, arg1); - return addHeapObject(ret); - }; - imports.wbg.__wbindgen_throw = function(arg0, arg1) { - throw new Error(getStringFromWasm0(arg0, arg1)); - }; - - return imports; + imports.wbg.__wbindgen_debug_string = function (arg0, arg1) { + const ret = debugString(getObject(arg1)); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); + const len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }; + imports.wbg.__wbindgen_error_new = function (arg0, arg1) { + const ret = new Error(getStringFromWasm0(arg0, arg1)); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_is_undefined = function (arg0) { + const ret = getObject(arg0) === undefined; + return ret; + }; + imports.wbg.__wbindgen_memory = function () { + const ret = wasm.memory; + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_object_drop_ref = function (arg0) { + takeObject(arg0); + }; + imports.wbg.__wbindgen_string_get = function (arg0, arg1) { + const obj = getObject(arg1); + const ret = typeof obj === 'string' ? obj : undefined; + var ptr1 = isLikeNone(ret) + ? 0 + : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + var len1 = WASM_VECTOR_LEN; + getInt32Memory0()[arg0 / 4 + 1] = len1; + getInt32Memory0()[arg0 / 4 + 0] = ptr1; + }; + imports.wbg.__wbindgen_string_new = function (arg0, arg1) { + const ret = getStringFromWasm0(arg0, arg1); + return addHeapObject(ret); + }; + imports.wbg.__wbindgen_throw = function (arg0, arg1) { + throw new Error(getStringFromWasm0(arg0, arg1)); + }; + + return imports; } -function __wbg_init_memory(imports, maybe_memory) { - -} +function __wbg_init_memory(imports, maybe_memory) {} function __wbg_finalize_init(instance, module) { - wasm = instance.exports; - __wbg_init.__wbindgen_wasm_module = module; - cachedInt32Memory0 = null; - cachedUint32Memory0 = null; - cachedUint8Memory0 = null; - - wasm.__wbindgen_start(); - return wasm; + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedInt32Memory0 = null; + cachedUint32Memory0 = null; + cachedUint8Memory0 = null; + + wasm.__wbindgen_start(); + return wasm; } function initSync(module) { - if (wasm !== undefined) return wasm; + if (wasm !== undefined) return wasm; - const imports = __wbg_get_imports(); + const imports = __wbg_get_imports(); - __wbg_init_memory(imports); + __wbg_init_memory(imports); - if (!(module instanceof WebAssembly.Module)) { - module = new WebAssembly.Module(module); - } + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } - const instance = new WebAssembly.Instance(module, imports); + const instance = new WebAssembly.Instance(module, imports); - return __wbg_finalize_init(instance, module); + return __wbg_finalize_init(instance, module); } async function __wbg_init(input) { - if (wasm !== undefined) return wasm; - + if (wasm !== undefined) return wasm; - const imports = __wbg_get_imports(); + const imports = __wbg_get_imports(); - if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { - input = fetch(input); - } + if ( + typeof input === 'string' || + (typeof Request === 'function' && input instanceof Request) || + (typeof URL === 'function' && input instanceof URL) + ) { + input = fetch(input); + } - __wbg_init_memory(imports); + __wbg_init_memory(imports); - const { instance, module } = await __wbg_load(await input, imports); + const { instance, module } = await __wbg_load(await input, imports); - return __wbg_finalize_init(instance, module); + return __wbg_finalize_init(instance, module); } -export { initSync } +export { initSync }; export default __wbg_init; From a27c5c18a30a90916cbc67f09966a231150404a4 Mon Sep 17 00:00:00 2001 From: Ariella Vu <20778143+digiwand@users.noreply.github.com> Date: Tue, 12 Sep 2023 15:51:40 +0200 Subject: [PATCH 04/38] Fix: Change style object key format kebab -> camelCase and fix title param type (#20768) * fix: style object key kebab -> camelCase * fix: disable boolean (false) title in ItemList --- ui/components/ui/metafox-logo/horizontal-logo.js | 4 ++-- ui/components/ui/review-spending-cap/review-spending-cap.js | 2 +- .../searchable-item-list/item-list/item-list.component.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/components/ui/metafox-logo/horizontal-logo.js b/ui/components/ui/metafox-logo/horizontal-logo.js index 12987024861e..ca80968bd42c 100644 --- a/ui/components/ui/metafox-logo/horizontal-logo.js +++ b/ui/components/ui/metafox-logo/horizontal-logo.js @@ -479,12 +479,12 @@ export default function MetaFoxHorizontalLogo({ d="M256.683 108.955L251.485 105.202L259.802 97.5905L253.46 92.5859L261.777 86.2258L256.267 82.0553L265 39.5158L251.901 0L167.587 31.5918H97.4127L13.0993 0L0 39.5158L8.8368 82.0553L3.22283 86.2258L11.5398 92.5859L5.19812 97.5905L13.5151 105.202L8.31699 108.955L20.2727 123.031L2.18321 179.542L18.9211 237.199L77.8678 220.934L113.111 203.731L110.231 227.044L112.903 224.583L152.097 224.479L154.696 226.773L151.889 203.731L187.132 220.934L246.079 237.199L262.921 179.542L244.727 123.031L256.683 108.955Z" fill="url(#paint13_linear)" fillOpacity="0.1" - style={{ 'mix-blend-mode': 'color-dodge' }} + style={{ mixBlendMode: 'color-dodge' }} /> )} {Number(tokenValue) === 0 && ( diff --git a/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js b/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js index b955a727d130..779d1edf58a8 100644 --- a/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js +++ b/ui/pages/swaps/searchable-item-list/item-list/item-list.component.js @@ -102,7 +102,7 @@ export default function ItemList({ onClick={onClick} onKeyUp={(e) => e.key === 'Enter' && onClick()} key={`searchable-item-list-item-${i}`} - title={blocked && t('swapTokenNotAvailable')} + title={blocked ? t('swapTokenNotAvailable') : null} > {iconUrl || primaryLabel ? ( From a399ff77c21168c9cb3e36b594daca6a0756a5de Mon Sep 17 00:00:00 2001 From: Nidhi Kumari Date: Tue, 12 Sep 2023 20:55:50 +0530 Subject: [PATCH 05/38] Migrate Import Token Link to TypeScript (#20474) * updated ImportTokenLink component to use TS * updated props * added type file * updated changes --------- Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com> --- ...ories.js => import-token-link.stories.tsx} | 7 ++- ...rt-token-link.js => import-token-link.tsx} | 47 ++++++++++--------- .../import-token-link.types.ts | 6 +++ .../import-token-link/{index.js => index.ts} | 0 4 files changed, 35 insertions(+), 25 deletions(-) rename ui/components/multichain/import-token-link/{import-token-link.stories.js => import-token-link.stories.tsx} (52%) rename ui/components/multichain/import-token-link/{import-token-link.js => import-token-link.tsx} (70%) create mode 100644 ui/components/multichain/import-token-link/import-token-link.types.ts rename ui/components/multichain/import-token-link/{index.js => index.ts} (100%) diff --git a/ui/components/multichain/import-token-link/import-token-link.stories.js b/ui/components/multichain/import-token-link/import-token-link.stories.tsx similarity index 52% rename from ui/components/multichain/import-token-link/import-token-link.stories.js rename to ui/components/multichain/import-token-link/import-token-link.stories.tsx index c03e7b2010c0..85c09e2184dd 100644 --- a/ui/components/multichain/import-token-link/import-token-link.stories.js +++ b/ui/components/multichain/import-token-link/import-token-link.stories.tsx @@ -1,11 +1,14 @@ import React from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { ImportTokenLink } from '.'; export default { title: 'Components/Multichain/ImportTokenLink', component: ImportTokenLink, -}; +} as Meta; -export const DefaultStory = () => ; +export const DefaultStory: StoryFn = () => ( + +); DefaultStory.storyName = 'Default'; diff --git a/ui/components/multichain/import-token-link/import-token-link.js b/ui/components/multichain/import-token-link/import-token-link.tsx similarity index 70% rename from ui/components/multichain/import-token-link/import-token-link.js rename to ui/components/multichain/import-token-link/import-token-link.tsx index 914e8110f667..6781329c5423 100644 --- a/ui/components/multichain/import-token-link/import-token-link.js +++ b/ui/components/multichain/import-token-link/import-token-link.tsx @@ -1,13 +1,13 @@ import React, { useContext } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import PropTypes from 'prop-types'; import classnames from 'classnames'; -import { ButtonLink, IconName, Box } from '../../component-library'; import { - AlignItems, - Display, - Size, -} from '../../../helpers/constants/design-system'; + ButtonLink, + IconName, + Box, + ButtonLinkSize, +} from '../../component-library'; +import { AlignItems, Display } from '../../../helpers/constants/design-system'; import { useI18nContext } from '../../../hooks/useI18nContext'; import { detectNewTokens, showImportTokensModal } from '../../../store/actions'; import { MetaMetricsContext } from '../../../contexts/metametrics'; @@ -19,8 +19,13 @@ import { getIsTokenDetectionSupported, getIsTokenDetectionInactiveOnMainnet, } from '../../../selectors'; +import type { BoxProps } from '../../component-library/box'; +import type { ImportTokenLinkProps } from './import-token-link.types'; -export const ImportTokenLink = ({ className, ...props }) => { +export const ImportTokenLink: React.FC = ({ + className = '', + ...props +}): JSX.Element => { const trackEvent = useContext(MetaMetricsContext); const t = useI18nContext(); const dispatch = useDispatch(); @@ -37,22 +42,25 @@ export const ImportTokenLink = ({ className, ...props }) => { return ( )} > { dispatch(showImportTokensModal()); - trackEvent({ - event: MetaMetricsEventName.TokenImportButtonClicked, - category: MetaMetricsEventCategory.Navigation, - properties: { - location: 'Home', + trackEvent( + { + event: MetaMetricsEventName.TokenImportButtonClicked, + category: MetaMetricsEventCategory.Navigation, + properties: { + location: 'Home', + }, }, - }); + {}, + ); }} > {isTokenDetectionAvailable @@ -63,7 +71,7 @@ export const ImportTokenLink = ({ className, ...props }) => { dispatch(detectNewTokens())} @@ -74,10 +82,3 @@ export const ImportTokenLink = ({ className, ...props }) => { ); }; - -ImportTokenLink.propTypes = { - /** - * An additional className to apply to the TokenList. - */ - className: PropTypes.string, -}; diff --git a/ui/components/multichain/import-token-link/import-token-link.types.ts b/ui/components/multichain/import-token-link/import-token-link.types.ts new file mode 100644 index 000000000000..ac94e3e3ad67 --- /dev/null +++ b/ui/components/multichain/import-token-link/import-token-link.types.ts @@ -0,0 +1,6 @@ +import type { StyleUtilityProps } from '../../component-library/box'; + +export interface ImportTokenLinkProps extends StyleUtilityProps { + /** * Additional class name for the ImportTokenLink component. */ + className?: string; +} diff --git a/ui/components/multichain/import-token-link/index.js b/ui/components/multichain/import-token-link/index.ts similarity index 100% rename from ui/components/multichain/import-token-link/index.js rename to ui/components/multichain/import-token-link/index.ts From a890f5ffd8e1793dcf8c9d7ec36e1a73a57f7632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ant=C3=B3nio=20Regadas?= Date: Tue, 12 Sep 2023 16:51:54 +0100 Subject: [PATCH 06/38] [MMI] Show the NFT tab content for mmi (#20830) * allow NFTs content view * prettier * Update app/_locales/en/messages.json Co-authored-by: Nidhi Kumari --------- Co-authored-by: Nidhi Kumari --- app/_locales/en/messages.json | 3 +++ .../nfts-detection-notice/nfts-detection-notice.js | 11 ++++++++++- ui/pages/home/home.component.js | 8 ++------ 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 9d87c8791019..e2b48ff16728 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -2352,6 +2352,9 @@ "mmiBuiltAroundTheWorld": { "message": "MetaMask Institutional is designed and built around the world." }, + "mmiNewNFTDetectedMessage": { + "message": "Allow MetaMask Institutional to automatically detect NFTs from OpenSea and display in your wallet." + }, "more": { "message": "more" }, diff --git a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js index 9a3c1a1fd3f0..e7a60c10d969 100644 --- a/ui/components/app/nfts-detection-notice/nfts-detection-notice.js +++ b/ui/components/app/nfts-detection-notice/nfts-detection-notice.js @@ -18,7 +18,16 @@ export default function NftsDetectionNotice() { history.push(`${SECURITY_ROUTE}#autodetect-nfts`); }} > - {t('newNFTDetectedMessage')} + { + ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) + t('newNFTDetectedMessage') + ///: END:ONLY_INCLUDE_IN + } + { + ///: BEGIN:ONLY_INCLUDE_IN(build-mmi) + t('mmiNewNFTDetectedMessage') + ///: END:ONLY_INCLUDE_IN + } ); } diff --git a/ui/pages/home/home.component.js b/ui/pages/home/home.component.js index c4aeb8d00c65..efa0acaeca70 100644 --- a/ui/pages/home/home.component.js +++ b/ui/pages/home/home.component.js @@ -9,8 +9,8 @@ import { MetaMetricsEventName, } from '../../../shared/constants/metametrics'; import AssetList from '../../components/app/asset-list'; -///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) import NftsTab from '../../components/app/nfts-tab'; +///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) import TermsOfUsePopup from '../../components/app/terms-of-use-popup'; import RecoveryPhraseReminder from '../../components/app/recovery-phrase-reminder'; ///: END:ONLY_INCLUDE_IN @@ -931,11 +931,7 @@ export default class Home extends PureComponent { name={this.context.t('nfts')} tabKey="nfts" > - { - ///: BEGIN:ONLY_INCLUDE_IN(build-main,build-beta,build-flask) - - ///: END:ONLY_INCLUDE_IN - } + { ///: BEGIN:ONLY_INCLUDE_IN(build-main) Date: Tue, 12 Sep 2023 18:28:25 +0200 Subject: [PATCH 07/38] fix: fix nft order (#20796) * fix: fix nft order * fix: use lodash * fix: fix import * Trigger Build --- .../confirm-add-suggested-nft.js | 5 ++++- .../send-asset-row/send-asset-row.component.js | 13 ++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/ui/pages/confirm-add-suggested-nft/confirm-add-suggested-nft.js b/ui/pages/confirm-add-suggested-nft/confirm-add-suggested-nft.js index 34b0d8b1176e..21cb9ad1cac6 100644 --- a/ui/pages/confirm-add-suggested-nft/confirm-add-suggested-nft.js +++ b/ui/pages/confirm-add-suggested-nft/confirm-add-suggested-nft.js @@ -65,7 +65,10 @@ const ConfirmAddSuggestedNFT = () => { const history = useHistory(); const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage); - const suggestedNfts = useSelector(getSuggestedNfts); + const suggestedNftsNotSorted = useSelector(getSuggestedNfts); + const suggestedNfts = suggestedNftsNotSorted.sort( + (a, b) => a.requestData.asset.tokenId - b.requestData.asset.tokenId, + ); const rpcPrefs = useSelector(getRpcPrefsForCurrentProvider); const chainId = useSelector(getCurrentChainId); const ipfsGateway = useSelector(getIpfsGateway); diff --git a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js index 8b8b6d165e91..15d741d04b95 100644 --- a/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js +++ b/ui/pages/send/send-content/send-asset-row/send-asset-row.component.js @@ -1,5 +1,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import { chain } from 'lodash'; import SendRowWrapper from '../send-row-wrapper'; import Identicon from '../../../../components/ui/identicon'; import TokenBalance from '../../../../components/ui/token-balance'; @@ -69,9 +70,19 @@ export default class SendAssetRow extends Component { async componentDidMount() { const sendableTokens = this.props.tokens.filter((token) => !token.isERC721); - const sendableNfts = this.props.nfts.filter( + const sendableNftsNotSorted = this.props.nfts.filter( (nft) => nft.isCurrentlyOwned && nft.standard === TokenStandard.ERC721, ); + // Group and sort the sendableNfts Array + const sendableNfts = chain(sendableNftsNotSorted) + .groupBy('address') + .mapValues((group) => { + return group.sort((a, b) => a.tokenId - b.tokenId); + }) + .values() + .flatten() + .value(); + this.setState({ sendableTokens, sendableNfts }); } From 4b23ea8c95bea9ea12336537bb6bda4568a99098 Mon Sep 17 00:00:00 2001 From: Alex Donesky Date: Tue, 12 Sep 2023 13:11:45 -0500 Subject: [PATCH 08/38] Integrate `SelectedNetworkController` (#20821) * Import SelectedNetworkController, createSelectedNetwork middleware and integrate them such that wallet_switchEthereumChain API call the setNetworkClientIdForDomain method on the new controller --- .../handlers/switch-ethereum-chain.js | 7 +- app/scripts/lib/setupSentry.js | 1 + app/scripts/metamask-controller.js | 41 ++- app/scripts/metamask-controller.test.js | 7 +- lavamoat/browserify/beta/policy.json | 5 + lavamoat/browserify/desktop/policy.json | 5 + lavamoat/browserify/flask/policy.json | 5 + lavamoat/browserify/main/policy.json | 5 + lavamoat/browserify/mmi/policy.json | 5 + package.json | 3 +- ...rs-after-init-opt-in-background-state.json | 4 + .../errors-after-init-opt-in-ui-state.json | 2 + yarn.lock | 249 +++++++++--------- 13 files changed, 213 insertions(+), 126 deletions(-) diff --git a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js index e2137da871b7..b074a3d7fde9 100644 --- a/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js +++ b/app/scripts/lib/rpc-method-middleware/handlers/switch-ethereum-chain.js @@ -20,6 +20,8 @@ const switchEthereumChain = { hookNames: { getCurrentChainId: true, findNetworkConfigurationBy: true, + findNetworkClientIdByChainId: true, + setNetworkClientIdForDomain: true, setProviderType: true, setActiveNetwork: true, requestUserApproval: true, @@ -53,6 +55,8 @@ async function switchEthereumChainHandler( { getCurrentChainId, findNetworkConfigurationBy, + findNetworkClientIdByChainId, + setNetworkClientIdForDomain, setProviderType, setActiveNetwork, requestUserApproval, @@ -99,7 +103,6 @@ async function switchEthereumChainHandler( }), ); } - const requestData = findExistingNetwork(_chainId, findNetworkConfigurationBy); if (requestData) { const currentChainId = getCurrentChainId(); @@ -122,6 +125,8 @@ async function switchEthereumChainHandler( } else { await setActiveNetwork(approvedRequestData.id); } + const networkClientId = findNetworkClientIdByChainId(_chainId); + setNetworkClientIdForDomain(req.origin, networkClientId); res.result = null; } catch (error) { return end(error); diff --git a/app/scripts/lib/setupSentry.js b/app/scripts/lib/setupSentry.js index edc7925e2220..077d0329049d 100644 --- a/app/scripts/lib/setupSentry.js +++ b/app/scripts/lib/setupSentry.js @@ -198,6 +198,7 @@ export const SENTRY_BACKGROUND_STATE = { usePhishDetect: true, useTokenDetection: true, }, + SelectedNetworkController: { domains: true, perDomainNetwork: false }, SignatureController: { unapprovedMsgCount: true, unapprovedMsgs: false, diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index f2754b7e22ec..2335fe6292ee 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -53,6 +53,11 @@ import { SubjectType, } from '@metamask/subject-metadata-controller'; import SmartTransactionsController from '@metamask/smart-transactions-controller'; +import { + SelectedNetworkController, + createSelectedNetworkMiddleware, +} from '@metamask/selected-network-controller'; + ///: BEGIN:ONLY_INCLUDE_IN(snaps) import { encrypt, decrypt } from '@metamask/browser-passworder'; import { RateLimitController } from '@metamask/rate-limit-controller'; @@ -301,6 +306,21 @@ export default class MetamaskController extends EventEmitter { // next, we will initialize the controllers // controller initialization order matters + this.selectedNetworkController = new SelectedNetworkController({ + messenger: this.controllerMessenger.getRestricted({ + name: 'SelectedNetworkController', + allowedActions: [ + 'SelectedNetworkController:getState', + 'SelectedNetworkController:getNetworkClientIdForDomain', + 'SelectedNetworkController:setNetworkClientIdForDomain', + ], + allowedEvents: [ + 'SelectedNetworkController:stateChange', + 'NetworkController:stateChange', + ], + }), + }); + this.approvalController = new ApprovalController({ messenger: this.controllerMessenger.getRestricted({ name: 'ApprovalController', @@ -1667,6 +1687,7 @@ export default class MetamaskController extends EventEmitter { SmartTransactionsController: this.smartTransactionsController, NftController: this.nftController, PhishingController: this.phishingController, + SelectedNetworkController: this.selectedNetworkController, ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -1711,6 +1732,7 @@ export default class MetamaskController extends EventEmitter { TokensController: this.tokensController, SmartTransactionsController: this.smartTransactionsController, NftController: this.nftController, + SelectedNetworkController: this.selectedNetworkController, ///: BEGIN:ONLY_INCLUDE_IN(snaps) SnapController: this.snapController, CronjobController: this.cronjobController, @@ -4045,8 +4067,15 @@ export default class MetamaskController extends EventEmitter { setupProviderEngine({ origin, subjectType, sender, tabId }) { // setup json rpc engine stack const engine = new JsonRpcEngine(); + const { blockTracker, provider } = this; + // append origin to each request + engine.push(createOriginMiddleware({ origin })); + + // append selectedNetworkClientId to each request + engine.push(createSelectedNetworkMiddleware(this.controllerMessenger)); + // create filter polyfill middleware const filterMiddleware = createFilterMiddleware({ provider, blockTracker }); @@ -4063,9 +4092,6 @@ export default class MetamaskController extends EventEmitter { engine.push(createDupeReqFilterMiddleware()); } - // append origin to each request - engine.push(createOriginMiddleware({ origin })); - // append tabId to each request if it exists if (tabId) { engine.push(createTabIdMiddleware({ tabId })); @@ -4183,7 +4209,15 @@ export default class MetamaskController extends EventEmitter { setActiveNetwork: this.networkController.setActiveNetwork.bind( this.networkController, ), + findNetworkClientIdByChainId: + this.networkController.findNetworkClientIdByChainId.bind( + this.networkController, + ), findNetworkConfigurationBy: this.findNetworkConfigurationBy.bind(this), + setNetworkClientIdForDomain: + this.selectedNetworkController.setNetworkClientIdForDomain.bind( + this.selectedNetworkController, + ), setProviderType: this.networkController.setProviderType.bind( this.networkController, ), @@ -4268,6 +4302,7 @@ export default class MetamaskController extends EventEmitter { // forward to metamask primary provider engine.push(providerAsMiddleware(provider)); + return engine; } diff --git a/app/scripts/metamask-controller.test.js b/app/scripts/metamask-controller.test.js index 316de29bb4e6..c8e6c070e14d 100644 --- a/app/scripts/metamask-controller.test.js +++ b/app/scripts/metamask-controller.test.js @@ -953,7 +953,7 @@ describe('MetaMaskController', () => { streamTest.end(); }); - it('adds a tabId and origin to requests', async () => { + it('adds a tabId, origin and networkClient to requests', async () => { const messageSender = { url: 'http://mycrypto.com', tab: { id: 456 }, @@ -977,7 +977,6 @@ describe('MetaMaskController', () => { params: [{ ...mockTxParams }], method: 'eth_sendTransaction', }; - await new Promise((resolve) => { streamTest.write( { @@ -995,6 +994,10 @@ describe('MetaMaskController', () => { 'tabId', 456, ); + expect(loggerMiddlewareMock.requests[0]).toHaveProperty( + 'networkClientId', + 'networkConfigurationId1', + ); resolve(); }); }, diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 18c7c3523c4d..61e3bee86ea4 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1917,6 +1917,11 @@ "crypto": true } }, + "@metamask/selected-network-controller": { + "packages": { + "@metamask/base-controller": true + } + }, "@metamask/signature-controller": { "globals": { "console.info": true diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index d5a883bb8a41..8b142fab3ace 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -2162,6 +2162,11 @@ "crypto": true } }, + "@metamask/selected-network-controller": { + "packages": { + "@metamask/base-controller": true + } + }, "@metamask/signature-controller": { "globals": { "console.info": true diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index 6af147aab6c4..dac657f28678 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -2178,6 +2178,11 @@ "crypto": true } }, + "@metamask/selected-network-controller": { + "packages": { + "@metamask/base-controller": true + } + }, "@metamask/signature-controller": { "globals": { "console.info": true diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index 47a5939bf129..cd968afe2c8d 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1989,6 +1989,11 @@ "crypto": true } }, + "@metamask/selected-network-controller": { + "packages": { + "@metamask/base-controller": true + } + }, "@metamask/signature-controller": { "globals": { "console.info": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 81b35a5c7bf4..019f5b3338d4 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -2058,6 +2058,11 @@ "crypto": true } }, + "@metamask/selected-network-controller": { + "packages": { + "@metamask/base-controller": true + } + }, "@metamask/signature-controller": { "globals": { "console.info": true diff --git a/package.json b/package.json index 604b5a03e123..dc733ca2beb1 100644 --- a/package.json +++ b/package.json @@ -255,7 +255,7 @@ "@metamask/logo": "^3.1.1", "@metamask/message-manager": "^7.3.0", "@metamask/metamask-eth-abis": "^3.0.0", - "@metamask/network-controller": "^12.0.0", + "@metamask/network-controller": "^12.1.1", "@metamask/notification-controller": "^3.0.0", "@metamask/obs-store": "^8.1.0", "@metamask/permission-controller": "^4.0.0", @@ -268,6 +268,7 @@ "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", + "@metamask/selected-network-controller": "^1.0.0", "@metamask/signature-controller": "^5.3.0", "@metamask/slip44": "^3.0.0", "@metamask/smart-transactions-controller": "^4.0.0", diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json index a522a1b11f93..f5a380e7413c 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-background-state.json @@ -153,6 +153,10 @@ "isLineaMainnetReleased": true, "selectedAddress": "string" }, + "SelectedNetworkController": { + "domains": {}, + "perDomainNetwork": "boolean" + }, "SignatureController": { "unapprovedMsgs": "object", "unapprovedPersonalMsgs": "object", diff --git a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json index aad4be321658..28486f27ec15 100644 --- a/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json +++ b/test/e2e/tests/state-snapshots/errors-after-init-opt-in-ui-state.json @@ -144,6 +144,8 @@ "allNftContracts": "object", "allNfts": "object", "ignoredNfts": "object", + "domains": {}, + "perDomainNetwork": "boolean", "snapErrors": "object", "snaps": "object", "snapStates": "object", diff --git a/yarn.lock b/yarn.lock index 90c1ddcaa2fb..1d02ff917a16 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3009,12 +3009,12 @@ __metadata: languageName: node linkType: hard -"@jest/expect-utils@npm:^29.1.2, @jest/expect-utils@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/expect-utils@npm:29.4.3" +"@jest/expect-utils@npm:^29.6.2": + version: 29.6.2 + resolution: "@jest/expect-utils@npm:29.6.2" dependencies: jest-get-type: "npm:^29.4.3" - checksum: 0088256933bbf6f79c1e0ac36df83d11d230ea36ccb6032b408d5e1533d2adf557b8f5c8fe81b5bcc76cfc15ec688d1b00bc8175b5593890e4d5a7f380793e55 + checksum: 5ad8884dafa9320ff454f5898d5f79d540f3cbab86aa8b0260351081094bcbcd6bb056e4fc6aac1147f0ec3dda634b8b3491abc0035cdc28a71ff9ded8aad359 languageName: node linkType: hard @@ -3029,12 +3029,12 @@ __metadata: linkType: hard "@jest/expect@npm:^29.1.2": - version: 29.1.2 - resolution: "@jest/expect@npm:29.1.2" + version: 29.6.2 + resolution: "@jest/expect@npm:29.6.2" dependencies: - expect: "npm:^29.1.2" - jest-snapshot: "npm:^29.1.2" - checksum: 7bb80bf176f39becdbd2ef54be615c3e7010f3230ccc419f22c97fa5b66e0fa14bb6b05019840d01cd1892e42be8158bea4c94487f05da1dd2b85a4ac097dd15 + expect: "npm:^29.6.2" + jest-snapshot: "npm:^29.6.2" + checksum: 2beed96e3d24945a72aa2ae4843c99f4c631564569258fdde6746fae3efcbfbff96dbf92ed28d6531299bd12b2766075bacaaae88ebf84b99316e77151b43a9f languageName: node linkType: hard @@ -3173,12 +3173,12 @@ __metadata: languageName: node linkType: hard -"@jest/schemas@npm:^29.4.3": - version: 29.4.3 - resolution: "@jest/schemas@npm:29.4.3" +"@jest/schemas@npm:^29.6.0": + version: 29.6.0 + resolution: "@jest/schemas@npm:29.6.0" dependencies: - "@sinclair/typebox": "npm:^0.25.16" - checksum: ac754e245c19dc39e10ebd41dce09040214c96a4cd8efa143b82148e383e45128f24599195ab4f01433adae4ccfbe2db6574c90db2862ccd8551a86704b5bebd + "@sinclair/typebox": "npm:^0.27.8" + checksum: c00511c69cf89138a7d974404d3a5060af375b5a52b9c87215d91873129b382ca11c1ff25bd6d605951404bb381ddce5f8091004a61e76457da35db1f5c51365 languageName: node linkType: hard @@ -3275,26 +3275,26 @@ __metadata: languageName: node linkType: hard -"@jest/transform@npm:^29.1.2, @jest/transform@npm:^29.3.1, @jest/transform@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/transform@npm:29.5.0" +"@jest/transform@npm:^29.1.2, @jest/transform@npm:^29.3.1, @jest/transform@npm:^29.5.0, @jest/transform@npm:^29.6.2": + version: 29.6.2 + resolution: "@jest/transform@npm:29.6.2" dependencies: "@babel/core": "npm:^7.11.6" - "@jest/types": "npm:^29.5.0" - "@jridgewell/trace-mapping": "npm:^0.3.15" + "@jest/types": "npm:^29.6.1" + "@jridgewell/trace-mapping": "npm:^0.3.18" babel-plugin-istanbul: "npm:^6.1.1" chalk: "npm:^4.0.0" convert-source-map: "npm:^2.0.0" fast-json-stable-stringify: "npm:^2.1.0" graceful-fs: "npm:^4.2.9" - jest-haste-map: "npm:^29.5.0" + jest-haste-map: "npm:^29.6.2" jest-regex-util: "npm:^29.4.3" - jest-util: "npm:^29.5.0" + jest-util: "npm:^29.6.2" micromatch: "npm:^4.0.4" pirates: "npm:^4.0.4" slash: "npm:^3.0.0" write-file-atomic: "npm:^4.0.2" - checksum: 5b52b11670e213e404cfee4c9a951f7eb38733f9ec5b974fdf46f3e7934af167b84c85cd7ba0e10343335b35035aaa81e9b9badf201d12731edf873c82e62fe9 + checksum: ab1759672e460bdcc2950ab6fcc2509b40c87d022164492363553ebb5efb0ce67a1721c0aaf5dd00370d20771cb234360bd03635d72354b0fd3e959355becbd7 languageName: node linkType: hard @@ -3324,17 +3324,17 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^29.1.2, @jest/types@npm:^29.3.1, @jest/types@npm:^29.5.0": - version: 29.5.0 - resolution: "@jest/types@npm:29.5.0" +"@jest/types@npm:^29.1.2, @jest/types@npm:^29.3.1, @jest/types@npm:^29.5.0, @jest/types@npm:^29.6.1": + version: 29.6.1 + resolution: "@jest/types@npm:29.6.1" dependencies: - "@jest/schemas": "npm:^29.4.3" + "@jest/schemas": "npm:^29.6.0" "@types/istanbul-lib-coverage": "npm:^2.0.0" "@types/istanbul-reports": "npm:^3.0.0" "@types/node": "npm:*" "@types/yargs": "npm:^17.0.8" chalk: "npm:^4.0.0" - checksum: 910a134cd1c2cd7d74dfcf9981c2f1a6c1d9772edecb7738947b059c4e0bb843a0d26a3c7dfff112f2fc4a473ecc18679edda498416f0048a8d181ff43a08bee + checksum: f6264fb0fc60efcb95adf3c4b30be6433aae75769b4f90d09de35fb19c65f7184d6c227a75f5b9e0054368d4fbf5cc4b397f9756d9a59eee25f3247d2e020f93 languageName: node linkType: hard @@ -3349,10 +3349,10 @@ __metadata: languageName: node linkType: hard -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: 320ceb37af56953757b28e5b90c34556157676d41e3d0a3ff88769274d62373582bb0f0276a4f2d29c3f4fdd55b82b8be5731f52d391ad2ecae9b321ee1c742d +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.1 + resolution: "@jridgewell/resolve-uri@npm:3.1.1" + checksum: 64d59df8ae1a4e74315eb1b61e012f1c7bc8aac47a3a1e683f6fe7008eab07bc512a742b7aa7c0405685d1421206de58c9c2e6adbfe23832f8bd69408ffc183e languageName: node linkType: hard @@ -3373,20 +3373,20 @@ __metadata: languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 26e768fae6045481a983e48aa23d8fcd23af5da70ebd74b0649000e815e7fbb01ea2bc088c9176b3fffeb9bec02184e58f46125ef3320b30eaa1f4094cfefa38 +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: 89960ac087781b961ad918978975bcdf2051cd1741880469783c42de64239703eab9db5230d776d8e6a09d73bb5e4cb964e07d93ee6e2e7aea5a7d726e865c09 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.13, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.18 - resolution: "@jridgewell/trace-mapping@npm:0.3.18" +"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.13, @jridgewell/trace-mapping@npm:^0.3.15, @jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.19 + resolution: "@jridgewell/trace-mapping@npm:0.3.19" dependencies: - "@jridgewell/resolve-uri": "npm:3.1.0" - "@jridgewell/sourcemap-codec": "npm:1.4.14" - checksum: f4fabdddf82398a797bcdbb51c574cd69b383db041a6cae1a6a91478681d6aab340c01af655cfd8c6e01cde97f63436a1445f08297cdd33587621cf05ffa0d55 + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 06a2a4e26e3cc369c41144fad7cbee29ba9ea6aca85acc565ec8f2110e298fdbf93986e17da815afae94539dcc03115cdbdbb575d3bea356e167da6987531e4d languageName: node linkType: hard @@ -3894,7 +3894,7 @@ __metadata: languageName: node linkType: hard -"@metamask/controller-utils@npm:^4.0.0, @metamask/controller-utils@npm:^4.0.1, @metamask/controller-utils@npm:^4.1.0, @metamask/controller-utils@npm:^4.2.0, @metamask/controller-utils@npm:^4.3.0, @metamask/controller-utils@npm:^4.3.1, @metamask/controller-utils@npm:^4.3.2": +"@metamask/controller-utils@npm:^4.0.0, @metamask/controller-utils@npm:^4.0.1, @metamask/controller-utils@npm:^4.1.0, @metamask/controller-utils@npm:^4.2.0, @metamask/controller-utils@npm:^4.3.0, @metamask/controller-utils@npm:^4.3.2": version: 4.3.2 resolution: "@metamask/controller-utils@npm:4.3.2" dependencies: @@ -4381,12 +4381,12 @@ __metadata: languageName: node linkType: hard -"@metamask/network-controller@npm:^12.0.0": - version: 12.0.0 - resolution: "@metamask/network-controller@npm:12.0.0" +"@metamask/network-controller@npm:^12.1.1, @metamask/network-controller@npm:^12.1.2": + version: 12.1.2 + resolution: "@metamask/network-controller@npm:12.1.2" dependencies: - "@metamask/base-controller": "npm:^3.2.0" - "@metamask/controller-utils": "npm:^4.3.1" + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/controller-utils": "npm:^4.3.2" "@metamask/eth-json-rpc-infura": "npm:^8.1.1" "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-json-rpc-provider": "npm:^1.0.0" @@ -4399,7 +4399,7 @@ __metadata: immer: "npm:^9.0.6" json-rpc-engine: "npm:^6.1.0" uuid: "npm:^8.3.2" - checksum: ea7c8010f1ca80c448050c7cf618598a1dabe82969fe1ff4a4952b85b3e4db677adab88d99a146cb11461d899628d3914f71e1b22d4249ccc5787a0281839afd + checksum: ec0cd25ac7851ed4b08cc6fb10bc66a83200b2d25efbf4de5a89fc5d9c845e403a59a5f226008460177cc7e2d26a35f38ca139b22e46083c5472bd86239638e5 languageName: node linkType: hard @@ -4698,6 +4698,19 @@ __metadata: languageName: node linkType: hard +"@metamask/selected-network-controller@npm:^1.0.0": + version: 1.0.0 + resolution: "@metamask/selected-network-controller@npm:1.0.0" + dependencies: + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/network-controller": "npm:^12.1.2" + json-rpc-engine: "npm:^6.1.0" + peerDependencies: + "@metamask/network-controller": ^12.1.2 + checksum: 4a004ccf426603a111e9c5d490f4a86ce4cb0143a9ff53c215e031df3d237cef0ef4fcde6c484f3ae0c5ce1a4b8d60f1faf4b1ceaf63675587480e704c26a903 + languageName: node + linkType: hard + "@metamask/signature-controller@npm:5.3.0": version: 5.3.0 resolution: "@metamask/signature-controller@npm:5.3.0" @@ -5853,10 +5866,10 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.25.16": - version: 0.25.23 - resolution: "@sinclair/typebox@npm:0.25.23" - checksum: 8503d788f6c5c60d925d8803b19a37fa879c6a9be64c216679eb6ed745212c69ed82190f2e45b220ee39cfdb24cadecdda2102b736a6df2e008778419806c26b +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 297f95ff77c82c54de8c9907f186076e715ff2621c5222ba50b8d40a170661c0c5242c763cba2a4791f0f91cb1d8ffa53ea1d7294570cf8cd4694c0e383e484d languageName: node linkType: hard @@ -16685,16 +16698,17 @@ __metadata: languageName: node linkType: hard -"expect@npm:^29.0.0, expect@npm:^29.1.2": - version: 29.4.3 - resolution: "expect@npm:29.4.3" +"expect@npm:^29.0.0, expect@npm:^29.6.2": + version: 29.6.2 + resolution: "expect@npm:29.6.2" dependencies: - "@jest/expect-utils": "npm:^29.4.3" + "@jest/expect-utils": "npm:^29.6.2" + "@types/node": "npm:*" jest-get-type: "npm:^29.4.3" - jest-matcher-utils: "npm:^29.4.3" - jest-message-util: "npm:^29.4.3" - jest-util: "npm:^29.4.3" - checksum: df1780fdb2005d99f8c48668e4ba7cbfb12f5c1edda76c4f10dbf012c466d919b8d51a3363a4c258de8bba4cb0600853023a1c05df66fdda4d62b95114804434 + jest-matcher-utils: "npm:^29.6.2" + jest-message-util: "npm:^29.6.2" + jest-util: "npm:^29.6.2" + checksum: 304472c4c63fc89accdf32a6817c62945efbcb3d536347dd49bc793dfc91f73fd9661411e0cc919f483ef309be589e33dd5bc9a27b55a5d88ae99009ad0df8f7 languageName: node linkType: hard @@ -21222,15 +21236,15 @@ __metadata: languageName: node linkType: hard -"jest-diff@npm:^29.1.2, jest-diff@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-diff@npm:29.4.3" +"jest-diff@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-diff@npm:29.6.2" dependencies: chalk: "npm:^4.0.0" diff-sequences: "npm:^29.4.3" jest-get-type: "npm:^29.4.3" - pretty-format: "npm:^29.4.3" - checksum: d43e1228e3563a46544e38c689f1d71e274efa572e22f40846a61b99251d59218370026cd39030ce9974ba1d34a3113e67e4e49b0acfb420b2613d20e2a4d18e + pretty-format: "npm:^29.6.2" + checksum: 8c66d29afbb64b4cb1c0daa7c20a7838b32ec16e989f7767f7088b466bfa64d7a501b3f8592c6ab148dde19645740cb868a18b29b992eb72517842287c03144e languageName: node linkType: hard @@ -21369,11 +21383,11 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:^29.1.2, jest-haste-map@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-haste-map@npm:29.5.0" +"jest-haste-map@npm:^29.1.2, jest-haste-map@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-haste-map@npm:29.6.2" dependencies: - "@jest/types": "npm:^29.5.0" + "@jest/types": "npm:^29.6.1" "@types/graceful-fs": "npm:^4.1.3" "@types/node": "npm:*" anymatch: "npm:^3.0.3" @@ -21381,14 +21395,14 @@ __metadata: fsevents: "npm:^2.3.2" graceful-fs: "npm:^4.2.9" jest-regex-util: "npm:^29.4.3" - jest-util: "npm:^29.5.0" - jest-worker: "npm:^29.5.0" + jest-util: "npm:^29.6.2" + jest-worker: "npm:^29.6.2" micromatch: "npm:^4.0.4" walker: "npm:^1.0.8" dependenciesMeta: fsevents: optional: true - checksum: 0f48ff383c25e657cc201139d1d430154ae2d16233f756c8707fd360c03e1424ddfcab3290f06094598d9464f2af14e63b6afa62b8a69583322183ae7692117d + checksum: 855d2c94979ad0795d5ef31cc81ccf40d2c2f6abd63de34a89e8b12e6b1cf7b9ae875f7479b783b7a2e9f55502ad1d241d483c103bed85a75c2b10eaafea3634 languageName: node linkType: hard @@ -21436,15 +21450,15 @@ __metadata: languageName: node linkType: hard -"jest-matcher-utils@npm:^29.1.2, jest-matcher-utils@npm:^29.4.3": - version: 29.4.3 - resolution: "jest-matcher-utils@npm:29.4.3" +"jest-matcher-utils@npm:^29.1.2, jest-matcher-utils@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-matcher-utils@npm:29.6.2" dependencies: chalk: "npm:^4.0.0" - jest-diff: "npm:^29.4.3" + jest-diff: "npm:^29.6.2" jest-get-type: "npm:^29.4.3" - pretty-format: "npm:^29.4.3" - checksum: 43e5509dbf9b813728b926b5a0219ef278c073ee4d86ac8057986e44dd5306d6fc4949883c998ada4fb9f20016a765e8d127c21677a8dcaaf60bf39074644f10 + pretty-format: "npm:^29.6.2" + checksum: 38dc3f71620745054246fb31e1979587fb241d3a2ecea1f325dbcba6503653d7e2482c6deffa99d661b9da2f093c7713d6977fd2a6b8f57537875745049088ed languageName: node linkType: hard @@ -21465,20 +21479,20 @@ __metadata: languageName: node linkType: hard -"jest-message-util@npm:^29.1.2, jest-message-util@npm:^29.4.3, jest-message-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-message-util@npm:29.5.0" +"jest-message-util@npm:^29.1.2, jest-message-util@npm:^29.5.0, jest-message-util@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-message-util@npm:29.6.2" dependencies: "@babel/code-frame": "npm:^7.12.13" - "@jest/types": "npm:^29.5.0" + "@jest/types": "npm:^29.6.1" "@types/stack-utils": "npm:^2.0.0" chalk: "npm:^4.0.0" graceful-fs: "npm:^4.2.9" micromatch: "npm:^4.0.4" - pretty-format: "npm:^29.5.0" + pretty-format: "npm:^29.6.2" slash: "npm:^3.0.0" stack-utils: "npm:^2.0.3" - checksum: eeb0a064e2db486428e37374422d4101a30845815a8842a0f62e77c2a82ae80837a74d5b4f58aaadfb3f19aa7d42e7d604aab1fb670cf170c46f0c46d0d725fd + checksum: a0e972367f12894dd0bcda2c2cd540607a6884315a411757b2e136eb54a53b54675f2e632b58a121e253bb456cfa564a9e10d5b7238b46de190095de78e445ba languageName: node linkType: hard @@ -21778,35 +21792,31 @@ __metadata: languageName: node linkType: hard -"jest-snapshot@npm:^29.1.2": - version: 29.1.2 - resolution: "jest-snapshot@npm:29.1.2" +"jest-snapshot@npm:^29.1.2, jest-snapshot@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-snapshot@npm:29.6.2" dependencies: "@babel/core": "npm:^7.11.6" "@babel/generator": "npm:^7.7.2" "@babel/plugin-syntax-jsx": "npm:^7.7.2" "@babel/plugin-syntax-typescript": "npm:^7.7.2" - "@babel/traverse": "npm:^7.7.2" "@babel/types": "npm:^7.3.3" - "@jest/expect-utils": "npm:^29.1.2" - "@jest/transform": "npm:^29.1.2" - "@jest/types": "npm:^29.1.2" - "@types/babel__traverse": "npm:^7.0.6" - "@types/prettier": "npm:^2.1.5" + "@jest/expect-utils": "npm:^29.6.2" + "@jest/transform": "npm:^29.6.2" + "@jest/types": "npm:^29.6.1" babel-preset-current-node-syntax: "npm:^1.0.0" chalk: "npm:^4.0.0" - expect: "npm:^29.1.2" + expect: "npm:^29.6.2" graceful-fs: "npm:^4.2.9" - jest-diff: "npm:^29.1.2" - jest-get-type: "npm:^29.0.0" - jest-haste-map: "npm:^29.1.2" - jest-matcher-utils: "npm:^29.1.2" - jest-message-util: "npm:^29.1.2" - jest-util: "npm:^29.1.2" + jest-diff: "npm:^29.6.2" + jest-get-type: "npm:^29.4.3" + jest-matcher-utils: "npm:^29.6.2" + jest-message-util: "npm:^29.6.2" + jest-util: "npm:^29.6.2" natural-compare: "npm:^1.4.0" - pretty-format: "npm:^29.1.2" - semver: "npm:^7.3.5" - checksum: 600149433e45cf5d58fb9d896dbc79b719b26e3412b70f4b4b326d162b152b2be6d9aa8f17b39a644f7a518cb60c2441106bd97c2c197491d190c78dca28b8e7 + pretty-format: "npm:^29.6.2" + semver: "npm:^7.5.3" + checksum: d9412eeea378ba070b9a67a161bb65b1b1038106dce8849c9e8266d4688dc8739063c9acd2d011f02f0f2cce2ff4e709be89c0657b03b89150fe7bdae769ec1c languageName: node linkType: hard @@ -21824,17 +21834,17 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^29.1.2, jest-util@npm:^29.3.1, jest-util@npm:^29.4.3, jest-util@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-util@npm:29.5.0" +"jest-util@npm:^29.1.2, jest-util@npm:^29.3.1, jest-util@npm:^29.5.0, jest-util@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-util@npm:29.6.2" dependencies: - "@jest/types": "npm:^29.5.0" + "@jest/types": "npm:^29.6.1" "@types/node": "npm:*" chalk: "npm:^4.0.0" ci-info: "npm:^3.2.0" graceful-fs: "npm:^4.2.9" picomatch: "npm:^2.2.3" - checksum: 27ae6fc6221d29b31df9c071f190e0e27a9caaeca04ee1ce03f5c925ec8abf594fcf0cb57bdcb93149381415ff1f8198157332b0c76f3592065b7c3fdb35fca1 + checksum: 95d510b7bbac6976c71bf9c8f2e861cdc6c47dca0a70c470ebce6fa2afef3fecd73772efdffc04e7aad89602ab388c2f1ee1cb27c505210d767f0731da65c13b languageName: node linkType: hard @@ -21937,15 +21947,15 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^29.1.2, jest-worker@npm:^29.5.0": - version: 29.5.0 - resolution: "jest-worker@npm:29.5.0" +"jest-worker@npm:^29.1.2, jest-worker@npm:^29.5.0, jest-worker@npm:^29.6.2": + version: 29.6.2 + resolution: "jest-worker@npm:29.6.2" dependencies: "@types/node": "npm:*" - jest-util: "npm:^29.5.0" + jest-util: "npm:^29.6.2" merge-stream: "npm:^2.0.0" supports-color: "npm:^8.0.0" - checksum: 3daf0a13d020985ce28d8436f3f94b0be9f8fc5f63ad753aa0779008d0a23b4e16bca38e2a2e9ae20d5d5ded8c43217b5e1bd54f25c5afe41b1be369aee30d4d + checksum: 7564896d0e61fdd202652c1ce17e1c20ef01dcbf313471dd83e687efa424e82745cc4d7ebf19ba8342327fa62971107c0e507a654e0041f310b4d53bee82584f languageName: node linkType: hard @@ -24225,7 +24235,7 @@ __metadata: "@metamask/logo": "npm:^3.1.1" "@metamask/message-manager": "npm:^7.3.0" "@metamask/metamask-eth-abis": "npm:^3.0.0" - "@metamask/network-controller": "npm:^12.0.0" + "@metamask/network-controller": "npm:^12.1.1" "@metamask/notification-controller": "npm:^3.0.0" "@metamask/obs-store": "npm:^8.1.0" "@metamask/permission-controller": "npm:^4.0.0" @@ -24239,6 +24249,7 @@ __metadata: "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1" "@metamask/safe-event-emitter": "npm:^2.0.0" "@metamask/scure-bip39": "npm:^2.0.3" + "@metamask/selected-network-controller": "npm:^1.0.0" "@metamask/signature-controller": "npm:^5.3.0" "@metamask/slip44": "npm:^3.0.0" "@metamask/smart-transactions-controller": "npm:^4.0.0" @@ -28060,14 +28071,14 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^29.0.0, pretty-format@npm:^29.1.2, pretty-format@npm:^29.4.3, pretty-format@npm:^29.5.0": - version: 29.5.0 - resolution: "pretty-format@npm:29.5.0" +"pretty-format@npm:^29.0.0, pretty-format@npm:^29.1.2, pretty-format@npm:^29.6.2": + version: 29.6.2 + resolution: "pretty-format@npm:29.6.2" dependencies: - "@jest/schemas": "npm:^29.4.3" + "@jest/schemas": "npm:^29.6.0" ansi-styles: "npm:^5.0.0" react-is: "npm:^18.0.0" - checksum: b025cb1d2bf27b8dc338792b208811b196828ccf590a87014d9ac9406eb809324ef56151ba41d489c8a67fed94cdacc94ca003380c2795233e117a5874b2566b + checksum: 5db1faf52552341e5026fd72f847d88116b08f758ef904f1635415b53ec2a193a0114fdede9f55a2c1174fa6eca896531f860db6f208c5698a52a5c354bb6f8d languageName: node linkType: hard From 28b3943a060073872231027cf070337af5a158b5 Mon Sep 17 00:00:00 2001 From: Vinicius Stevam <45455812+vinistevam@users.noreply.github.com> Date: Wed, 13 Sep 2023 09:15:26 +0100 Subject: [PATCH 09/38] fix: error during persisted transaction approval (#20626) This pull request addresses the issue that occurs when a pending transaction is present, the extension is disabled and then re-enabled, and subsequently, the user rejects the transaction. The goal is to prevent the logging of the error message "User rejected the request", while still capturing and logging any other types of errors. Fixes https://github.com/MetaMask/metamask-extension/issues/20604 --- app/scripts/controllers/transactions/index.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/scripts/controllers/transactions/index.js b/app/scripts/controllers/transactions/index.js index 58954c2ccc2b..76c7d529e43e 100644 --- a/app/scripts/controllers/transactions/index.js +++ b/app/scripts/controllers/transactions/index.js @@ -345,6 +345,9 @@ export default class TransactionController extends EventEmitter { this._requestTransactionApproval(txMeta, { shouldShowRequest: false, }).catch((error) => { + if (error.code === errorCodes.provider.userRejectedRequest) { + return; + } log.error('Error during persisted transaction approval', error); }); }); From 660d2d0d8c0fddcb8b43d6a04e8562e51f4013dd Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 13 Sep 2023 12:27:44 +0200 Subject: [PATCH 10/38] Only show enabled insight snaps on the confirmation screen (#20850) --- ui/selectors/selectors.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ui/selectors/selectors.js b/ui/selectors/selectors.js index 4d77bcec8858..cf89a648ac3d 100644 --- a/ui/selectors/selectors.js +++ b/ui/selectors/selectors.js @@ -936,8 +936,17 @@ export const getSnap = createDeepEqualSelector( }, ); +export const getEnabledSnaps = createDeepEqualSelector(getSnaps, (snaps) => { + return Object.values(snaps).reduce((acc, cur) => { + if (cur.enabled) { + acc[cur.id] = cur; + } + return acc; + }, {}); +}); + export const getInsightSnaps = createDeepEqualSelector( - getSnaps, + getEnabledSnaps, getPermissionSubjects, (snaps, subjects) => { return Object.values(snaps).filter( From b1d959ca22dd3d141aad72b84a3d6e0ba6101702 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 13 Sep 2023 13:40:56 +0200 Subject: [PATCH 11/38] Use first non-symbol character as snap fallback icon (#20851) * Skip first character in snap name if it is a @ * Simplify implementation --- ui/components/app/snaps/snap-avatar/snap-avatar.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/components/app/snaps/snap-avatar/snap-avatar.js b/ui/components/app/snaps/snap-avatar/snap-avatar.js index e7d1d507ed08..09a637ce7ca6 100644 --- a/ui/components/app/snaps/snap-avatar/snap-avatar.js +++ b/ui/components/app/snaps/snap-avatar/snap-avatar.js @@ -37,7 +37,8 @@ const SnapAvatar = ({ const iconUrl = subjectMetadata?.iconUrl; - const fallbackIcon = friendlyName && friendlyName[0] ? friendlyName[0] : '?'; + // We choose the first non-symbol char as the fallback icon. + const fallbackIcon = friendlyName?.match(/[a-z0-9]/iu)?.[0] ?? '?'; return ( Date: Wed, 13 Sep 2023 13:42:48 +0200 Subject: [PATCH 12/38] Require Flask Snaps E2E to pass for CI pass (#20740) --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8473915d8a41..1755e91b46a1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -246,6 +246,8 @@ workflows: - test-e2e-firefox - test-e2e-chrome-snaps - test-e2e-firefox-snaps + - test-e2e-chrome-snaps-flask + - test-e2e-firefox-snaps-flask - test-storybook - benchmark: requires: From 39b0832312d690e09514f01ec892449223219953 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 13 Sep 2023 14:25:32 +0200 Subject: [PATCH 13/38] Fix spacing on connected sites in the snap details page (#20854) --- .../app/connected-sites-list/connected-sites-list.component.js | 3 +-- ui/pages/settings/snaps/view-snap/index.scss | 2 +- ui/pages/settings/snaps/view-snap/view-snap.js | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/ui/components/app/connected-sites-list/connected-sites-list.component.js b/ui/components/app/connected-sites-list/connected-sites-list.component.js index 72b4cacfe946..83355bf8801f 100644 --- a/ui/components/app/connected-sites-list/connected-sites-list.component.js +++ b/ui/components/app/connected-sites-list/connected-sites-list.component.js @@ -4,7 +4,7 @@ import Button from '../../ui/button'; import { AvatarFavicon } from '../../component-library'; import { stripHttpsSchemeWithoutPort } from '../../../helpers/utils/util'; import SiteOrigin from '../../ui/site-origin'; -import { BorderColor, Size } from '../../../helpers/constants/design-system'; +import { Size } from '../../../helpers/constants/design-system'; export default class ConnectedSitesList extends Component { static contextTypes = { @@ -35,7 +35,6 @@ export default class ConnectedSitesList extends Component { >
- + {t('connectedSites')} Date: Wed, 13 Sep 2023 14:34:17 +0200 Subject: [PATCH 14/38] Make permissions modal scrollable (#20409) --- ui/components/app/connected-accounts-permissions/index.scss | 5 +++-- ui/pages/connected-accounts/index.scss | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/components/app/connected-accounts-permissions/index.scss b/ui/components/app/connected-accounts-permissions/index.scss index f93eef1db3b2..6e9ff8dc7c5b 100644 --- a/ui/components/app/connected-accounts-permissions/index.scss +++ b/ui/components/app/connected-accounts-permissions/index.scss @@ -33,7 +33,9 @@ } &__list { - padding-top: 8px; + padding-block: 8px; + height: 100%; + overflow: auto; } &__list-item { @@ -42,7 +44,6 @@ &__list-container { max-height: 0; - overflow: hidden; height: auto; transition: max-height 0.8s cubic-bezier(0.4, 0, 0.2, 1); diff --git a/ui/pages/connected-accounts/index.scss b/ui/pages/connected-accounts/index.scss index 3d1d113084be..9a884334ae52 100644 --- a/ui/pages/connected-accounts/index.scss +++ b/ui/pages/connected-accounts/index.scss @@ -1,5 +1,8 @@ .connected-accounts { &__footer { + overflow: hidden; + margin-bottom: 8px; + a, a:hover { @include H6; From f19e1f5f44b22aa7c1995b0cc3ac8b18ab1d3c71 Mon Sep 17 00:00:00 2001 From: Frederik Bolding Date: Wed, 13 Sep 2023 17:14:06 +0200 Subject: [PATCH 15/38] [FLASK] Bump snaps packages (#20567) * Bump Snaps flask packages * Add snap_getLocale support * Update LavaMoat policies * Bump iframe * Update LavaMoat policies * Bump iframe * Update permission copy * Add snap_getLocale description * Fix unit test * Move the `saveSnapKeyring` callback to the `SnapKeyring` constructor (#20786) * Move the `saveSnapKeyring` callback to the `SnapKeyring` constructor This commit removes `saveSnapKeyring` from the list of callbacks passed to the Snap Controller since this function contains business logic specific to the Snap Keyring. Instead, `saveSnapKeyring` is injected into the Snap Keyring through a new argument called `callbacks`. In the future, the `callbacks` argument can be reused to pass other callbacks. * Update the Snap Keyring dependency * chore: use release versions of `eth-snap-keyring` and `rpc-methods` * chore: update `yarn.lock` * chore: update `yarn.lock` --------- Co-authored-by: Daniel Rocha --- app/_locales/en/messages.json | 8 + app/scripts/metamask-controller.js | 22 ++- builds.yml | 4 +- lavamoat/browserify/beta/policy.json | 15 +- lavamoat/browserify/desktop/policy.json | 131 +++++++------- lavamoat/browserify/flask/policy.json | 131 +++++++------- lavamoat/browserify/main/policy.json | 15 +- lavamoat/browserify/mmi/policy.json | 15 +- package.json | 10 +- shared/constants/permissions.test.js | 6 +- shared/constants/permissions.ts | 1 + shared/constants/snaps/permissions.ts | 2 + ui/helpers/utils/permission.js | 6 + yarn.lock | 224 +++++++++++------------- 14 files changed, 314 insertions(+), 276 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index e2b48ff16728..4b4c831d4162 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -3228,6 +3228,14 @@ "message": "Allow the snap to derive arbitrary keys unique to this snap, without exposing them. These keys are separate from your MetaMask account(s) and not related to your private keys or Secret Recovery Phrase. Other snaps cannot access this information.", "description": "An extended description for the `snap_getEntropy` permission" }, + "permission_getLocale": { + "message": "View your preferred language.", + "description": "The description for the `snap_getLocale` permission" + }, + "permission_getLocaleDescription": { + "message": "Let this Snap access your preferred language from your MetaMask settings. This can be used to localize and display the Snap's content using your language.", + "description": "An extended description for the `snap_getLocale` permission" + }, "permission_lifecycleHooks": { "message": "Use lifecycle hooks.", "description": "The description for the `endowment:lifecycle-hooks` permission" diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 2335fe6292ee..54fed2ea3e70 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -847,7 +847,12 @@ export default class MetamaskController extends EventEmitter { ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) additionalKeyrings.push( (() => { - const builder = () => new SnapKeyring(this.snapController); + const builder = () => + new SnapKeyring(this.snapController, { + saveState: async () => { + await this.keyringController.persistAllKeyrings(); + }, + }); builder.type = SnapKeyring.type; return builder; })(), @@ -1910,6 +1915,17 @@ export default class MetamaskController extends EventEmitter { return this.controllerMessenger.call('SnapController:handleRequest', args); } + /** + * Gets the currently selected locale from the PreferencesController. + * + * @returns The currently selected locale. + */ + getLocale() { + const { currentLocale } = this.preferencesController.store.getState(); + + return currentLocale; + } + /** * Constructor helper for getting Snap permission specifications. */ @@ -1919,6 +1935,7 @@ export default class MetamaskController extends EventEmitter { ...buildSnapRestrictedMethodSpecifications({ encrypt, decrypt, + getLocale: this.getLocale.bind(this), clearSnapState: this.controllerMessenger.call.bind( this.controllerMessenger, 'SnapController:clearSnapState', @@ -1965,9 +1982,6 @@ export default class MetamaskController extends EventEmitter { ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) getSnapKeyring: this.getSnapKeyring.bind(this), - saveSnapKeyring: async () => { - await this.keyringController.persistAllKeyrings(); - }, ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(snaps) }), diff --git a/builds.yml b/builds.yml index 90689f102daf..5ad53a2ff993 100644 --- a/builds.yml +++ b/builds.yml @@ -57,7 +57,7 @@ buildTypes: - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.1-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.3-flask.1/index.html - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID @@ -76,7 +76,7 @@ buildTypes: - SEGMENT_FLASK_WRITE_KEY - ALLOW_LOCAL_SNAPS: true - REQUIRE_SNAPS_ALLOWLIST: false - - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.1-flask.1/index.html + - IFRAME_EXECUTION_ENVIRONMENT_URL: https://execution.consensys.io/0.38.3-flask.1/index.html - SUPPORT_LINK: https://metamask-flask.zendesk.com/hc - SUPPORT_REQUEST_LINK: https://metamask-flask.zendesk.com/hc/en-us/requests/new - INFURA_ENV_KEY_REF: INFURA_FLASK_PROJECT_ID diff --git a/lavamoat/browserify/beta/policy.json b/lavamoat/browserify/beta/policy.json index 61e3bee86ea4..0530d84fa850 100644 --- a/lavamoat/browserify/beta/policy.json +++ b/lavamoat/browserify/beta/policy.json @@ -1791,14 +1791,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/desktop/policy.json b/lavamoat/browserify/desktop/policy.json index 8b142fab3ace..bdd2ba925bb9 100644 --- a/lavamoat/browserify/desktop/policy.json +++ b/lavamoat/browserify/desktop/policy.json @@ -1949,14 +1949,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1978,52 +1991,6 @@ "eslint>optionator>fast-levenshtein": true } }, - "@metamask/post-message-stream": { - "globals": { - "MessageEvent.prototype": true, - "WorkerGlobalScope": true, - "addEventListener": true, - "browser": true, - "chrome": true, - "location.origin": true, - "postMessage": true, - "removeEventListener": true - }, - "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "@metamask/post-message-stream>readable-stream>process-nextick-args": true, - "@metamask/post-message-stream>readable-stream>safe-buffer": true, - "@metamask/post-message-stream>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>events": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>util-deprecate": true - } - }, - "@metamask/post-message-stream>readable-stream>process-nextick-args": { - "packages": { - "browserify>process": true - } - }, - "@metamask/post-message-stream>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask/post-message-stream>readable-stream>string_decoder": { - "packages": { - "@metamask/post-message-stream>readable-stream>safe-buffer": true - } - }, "@metamask/ppom-validator>elliptic": { "packages": { "@metamask/ppom-validator>elliptic>brorand": true, @@ -2084,7 +2051,20 @@ }, "@metamask/rpc-methods-flask>@metamask/snaps-ui": { "packages": { - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, "superstruct": true } }, @@ -2226,8 +2206,8 @@ "packages": { "@metamask/base-controller": true, "@metamask/permission-controller": true, - "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream": true, "@metamask/snaps-controllers-flask>@metamask/rpc-methods": true, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, @@ -2244,13 +2224,41 @@ "pump": true } }, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream": { + "globals": { + "MessageEvent.prototype": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "browser": true, + "chrome": true, + "location.origin": true, + "postMessage": true, + "removeEventListener": true + }, + "packages": { + "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true + } + }, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/snaps-controllers-flask>@metamask/rpc-methods": { "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": true, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-utils": true, + "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, "eth-rpc-errors": true, "superstruct": true @@ -2258,34 +2266,19 @@ }, "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { "packages": { - "@metamask/snaps-controllers-flask>@metamask/utils": true, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": true, "superstruct": true } }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-utils": { + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": { "globals": { "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true + "TextEncoder": true }, "packages": { - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, + "nock>debug": true, "semver": true, "superstruct": true } diff --git a/lavamoat/browserify/flask/policy.json b/lavamoat/browserify/flask/policy.json index dac657f28678..2f97fd964747 100644 --- a/lavamoat/browserify/flask/policy.json +++ b/lavamoat/browserify/flask/policy.json @@ -1949,14 +1949,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true @@ -1978,52 +1991,6 @@ "eslint>optionator>fast-levenshtein": true } }, - "@metamask/post-message-stream": { - "globals": { - "MessageEvent.prototype": true, - "WorkerGlobalScope": true, - "addEventListener": true, - "browser": true, - "chrome": true, - "location.origin": true, - "postMessage": true, - "removeEventListener": true - }, - "packages": { - "@metamask/post-message-stream>readable-stream": true, - "@metamask/utils": true - } - }, - "@metamask/post-message-stream>readable-stream": { - "packages": { - "@metamask/post-message-stream>readable-stream>process-nextick-args": true, - "@metamask/post-message-stream>readable-stream>safe-buffer": true, - "@metamask/post-message-stream>readable-stream>string_decoder": true, - "browserify>browser-resolve": true, - "browserify>events": true, - "browserify>process": true, - "browserify>timers-browserify": true, - "pumpify>inherits": true, - "readable-stream>core-util-is": true, - "readable-stream>isarray": true, - "readable-stream>util-deprecate": true - } - }, - "@metamask/post-message-stream>readable-stream>process-nextick-args": { - "packages": { - "browserify>process": true - } - }, - "@metamask/post-message-stream>readable-stream>safe-buffer": { - "packages": { - "browserify>buffer": true - } - }, - "@metamask/post-message-stream>readable-stream>string_decoder": { - "packages": { - "@metamask/post-message-stream>readable-stream>safe-buffer": true - } - }, "@metamask/ppom-validator": { "globals": { "URL": true, @@ -2100,7 +2067,20 @@ }, "@metamask/rpc-methods-flask>@metamask/snaps-ui": { "packages": { - "@metamask/rpc-methods-flask>@metamask/utils": true, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": true, + "superstruct": true + } + }, + "@metamask/rpc-methods-flask>@metamask/snaps-ui>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, "superstruct": true } }, @@ -2242,8 +2222,8 @@ "packages": { "@metamask/base-controller": true, "@metamask/permission-controller": true, - "@metamask/post-message-stream": true, "@metamask/providers>@metamask/object-multiplex": true, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream": true, "@metamask/snaps-controllers-flask>@metamask/rpc-methods": true, "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, @@ -2260,13 +2240,41 @@ "pump": true } }, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream": { + "globals": { + "MessageEvent.prototype": true, + "WorkerGlobalScope": true, + "addEventListener": true, + "browser": true, + "chrome": true, + "location.origin": true, + "postMessage": true, + "removeEventListener": true + }, + "packages": { + "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": true, + "@metamask/snaps-controllers-flask>concat-stream>readable-stream": true + } + }, + "@metamask/snaps-controllers-flask>@metamask/post-message-stream>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/snaps-controllers-flask>@metamask/rpc-methods": { "packages": { "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, "@metamask/permission-controller": true, "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": true, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-utils": true, + "@metamask/snaps-controllers-flask>@metamask/snaps-utils": true, "@metamask/snaps-controllers-flask>@metamask/utils": true, "eth-rpc-errors": true, "superstruct": true @@ -2274,34 +2282,19 @@ }, "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui": { "packages": { - "@metamask/snaps-controllers-flask>@metamask/utils": true, + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": true, "superstruct": true } }, - "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-utils": { + "@metamask/snaps-controllers-flask>@metamask/rpc-methods>@metamask/snaps-ui>@metamask/utils": { "globals": { "TextDecoder": true, - "URL": true, - "console.error": true, - "console.log": true, - "console.warn": true, - "document.body.appendChild": true, - "document.createElement": true + "TextEncoder": true }, "packages": { - "@metamask/key-tree": true, "@metamask/key-tree>@noble/hashes": true, - "@metamask/key-tree>@scure/base": true, - "@metamask/snaps-controllers-flask>@metamask/utils": true, - "@metamask/snaps-utils-flask>is-svg": true, - "@metamask/snaps-utils>cron-parser": true, - "@metamask/snaps-utils>fast-json-stable-stringify": true, - "@metamask/snaps-utils>rfdc": true, - "@metamask/snaps-utils>validate-npm-package-name": true, "browserify>buffer": true, - "browserify>path-browserify": true, - "browserify>process": true, - "chalk": true, + "nock>debug": true, "semver": true, "superstruct": true } diff --git a/lavamoat/browserify/main/policy.json b/lavamoat/browserify/main/policy.json index cd968afe2c8d..8f1f171aa469 100644 --- a/lavamoat/browserify/main/policy.json +++ b/lavamoat/browserify/main/policy.json @@ -1798,14 +1798,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/lavamoat/browserify/mmi/policy.json b/lavamoat/browserify/mmi/policy.json index 019f5b3338d4..578f541b1d3e 100644 --- a/lavamoat/browserify/mmi/policy.json +++ b/lavamoat/browserify/mmi/policy.json @@ -1932,14 +1932,27 @@ "packages": { "@metamask/base-controller": true, "@metamask/controller-utils": true, + "@metamask/permission-controller>@metamask/utils": true, "@metamask/permission-controller>nanoid": true, - "@metamask/utils": true, "deep-freeze-strict": true, "eth-rpc-errors": true, "immer": true, "json-rpc-engine": true } }, + "@metamask/permission-controller>@metamask/utils": { + "globals": { + "TextDecoder": true, + "TextEncoder": true + }, + "packages": { + "@metamask/key-tree>@noble/hashes": true, + "browserify>buffer": true, + "nock>debug": true, + "semver": true, + "superstruct": true + } + }, "@metamask/permission-controller>nanoid": { "globals": { "crypto.getRandomValues": true diff --git a/package.json b/package.json index dc733ca2beb1..dd63b9594cc8 100644 --- a/package.json +++ b/package.json @@ -244,7 +244,7 @@ "@metamask/eth-json-rpc-middleware": "^11.0.0", "@metamask/eth-keyring-controller": "^10.0.1", "@metamask/eth-ledger-bridge-keyring": "^0.15.0", - "@metamask/eth-snap-keyring": "^0.1.3", + "@metamask/eth-snap-keyring": "^0.1.4", "@metamask/eth-token-tracker": "^4.0.0", "@metamask/eth-trezor-keyring": "^1.1.0", "@metamask/etherscan-link": "^2.2.0", @@ -265,7 +265,7 @@ "@metamask/providers": "^11.1.0", "@metamask/rate-limit-controller": "^3.0.0", "@metamask/rpc-methods": "^1.0.2", - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1", + "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.38.2-flask.1", "@metamask/safe-event-emitter": "^2.0.0", "@metamask/scure-bip39": "^2.0.3", "@metamask/selected-network-controller": "^1.0.0", @@ -273,11 +273,11 @@ "@metamask/slip44": "^3.0.0", "@metamask/smart-transactions-controller": "^4.0.0", "@metamask/snaps-controllers": "^1.0.2", - "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.0-flask.1", + "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.3-flask.1", "@metamask/snaps-ui": "^1.0.2", - "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.3-flask.1", + "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.4-flask.1", "@metamask/snaps-utils": "^1.0.2", - "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.0-flask.1", + "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.3-flask.1", "@metamask/subject-metadata-controller": "^2.0.0", "@metamask/utils": "^5.0.0", "@ngraveio/bc-ur": "^1.1.6", diff --git a/shared/constants/permissions.test.js b/shared/constants/permissions.test.js index f1ef4a5563a2..0bc4e9cc37db 100644 --- a/shared/constants/permissions.test.js +++ b/shared/constants/permissions.test.js @@ -24,12 +24,14 @@ describe('EndowmentPermissions', () => { }); }); +const FlaskOnlyPermissions = ['snap_manageAccounts', 'snap_getLocale']; + describe('RestrictedMethods', () => { it('has the expected permission keys', () => { // this is done because we there is a difference between flask and stable permissions // the code fence in `shared/constants/snaps/permissions.ts` is not supported in jest const mainBuildRestrictedMethodPermissions = Object.keys(RestrictedMethods) - .filter((key) => key !== 'snap_manageAccounts') + .filter((key) => !FlaskOnlyPermissions.includes(key)) .sort(); expect(mainBuildRestrictedMethodPermissions).toStrictEqual( @@ -54,7 +56,7 @@ describe('Flask Restricted Methods', () => { it('has the expected flask permission keys', () => { const flaskExcludedSnapPermissions = Object.keys( ExcludedSnapPermissions, - ).filter((key) => key !== 'snap_manageAccounts'); + ).filter((key) => !FlaskOnlyPermissions.includes(key)); expect(Object.keys(RestrictedMethods).sort()).toStrictEqual( [ diff --git a/shared/constants/permissions.ts b/shared/constants/permissions.ts index 1d0c60ac19b8..32f91eb50ac6 100644 --- a/shared/constants/permissions.ts +++ b/shared/constants/permissions.ts @@ -12,6 +12,7 @@ export const RestrictedMethods = Object.freeze({ snap_getBip32Entropy: 'snap_getBip32Entropy', snap_getBip44Entropy: 'snap_getBip44Entropy', snap_getEntropy: 'snap_getEntropy', + snap_getLocale: 'snap_getLocale', wallet_snap: 'wallet_snap', ///: END:ONLY_INCLUDE_IN ///: BEGIN:ONLY_INCLUDE_IN(keyring-snaps) diff --git a/shared/constants/snaps/permissions.ts b/shared/constants/snaps/permissions.ts index 3642e2187166..d5e1b16c6d4f 100644 --- a/shared/constants/snaps/permissions.ts +++ b/shared/constants/snaps/permissions.ts @@ -15,6 +15,8 @@ export const EndowmentPermissions = Object.freeze({ export const ExcludedSnapPermissions = Object.freeze({ // TODO: Enable in Flask ///: BEGIN:ONLY_INCLUDE_IN(build-main) + snap_getLocale: + 'This permission is still in development and therefore not available.', snap_manageAccounts: 'This permission is still in development and therefore not available.', ///: END:ONLY_INCLUDE_IN diff --git a/ui/helpers/utils/permission.js b/ui/helpers/utils/permission.js index 26c349787d4b..932f5430594a 100644 --- a/ui/helpers/utils/permission.js +++ b/ui/helpers/utils/permission.js @@ -263,6 +263,12 @@ export const PERMISSION_DESCRIPTIONS = deepFreeze({ leftIcon: IconName.AddSquare, weight: 3, }), + [RestrictedMethods.snap_getLocale]: ({ t }) => ({ + label: t('permission_getLocale'), + description: t('permission_getLocaleDescription'), + leftIcon: IconName.Home, + weight: 3, + }), [RestrictedMethods.wallet_snap]: ({ t, permissionValue, diff --git a/yarn.lock b/yarn.lock index 1d02ff917a16..dab55013c667 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4151,9 +4151,9 @@ __metadata: languageName: node linkType: hard -"@metamask/eth-snap-keyring@npm:^0.1.3": - version: 0.1.3 - resolution: "@metamask/eth-snap-keyring@npm:0.1.3" +"@metamask/eth-snap-keyring@npm:^0.1.4": + version: 0.1.4 + resolution: "@metamask/eth-snap-keyring@npm:0.1.4" dependencies: "@ethereumjs/tx": "npm:^4.1.2" "@metamask/eth-sig-util": "npm:^5.1.0" @@ -4163,7 +4163,7 @@ __metadata: "@types/uuid": "npm:^9.0.1" superstruct: "npm:^1.0.3" uuid: "npm:^9.0.0" - checksum: df426fca165d3b22347324a4b17cefa8fc86dd3ef669ab054233c168437f567f77992b69633ec13a1d8c5b77701ba2df25b68fba246cd46ee14f97072f0ac1a6 + checksum: fe626464be4cc86665fadece8e55d55494eecaa9b86193f2381f72f8366781ff5f4faca4fb5a94e0ab4d75f8b21bb7914b22854f733bb941f6ea359ba386285e languageName: node linkType: hard @@ -4477,14 +4477,14 @@ __metadata: languageName: node linkType: hard -"@metamask/permission-controller@npm:^4.0.0": - version: 4.0.0 - resolution: "@metamask/permission-controller@npm:4.0.0" +"@metamask/permission-controller@npm:^4.0.0, @metamask/permission-controller@npm:^4.1.0": + version: 4.1.1 + resolution: "@metamask/permission-controller@npm:4.1.1" dependencies: - "@metamask/approval-controller": "npm:^3.0.0" - "@metamask/base-controller": "npm:^3.0.0" - "@metamask/controller-utils": "npm:^4.0.0" - "@metamask/utils": "npm:^5.0.2" + "@metamask/approval-controller": "npm:^3.5.1" + "@metamask/base-controller": "npm:^3.2.1" + "@metamask/controller-utils": "npm:^4.3.2" + "@metamask/utils": "npm:^6.2.0" "@types/deep-freeze-strict": "npm:^1.1.0" deep-freeze-strict: "npm:^1.1.1" eth-rpc-errors: "npm:^4.0.2" @@ -4492,8 +4492,8 @@ __metadata: json-rpc-engine: "npm:^6.1.0" nanoid: "npm:^3.1.31" peerDependencies: - "@metamask/approval-controller": ^3.0.0 - checksum: bbb915e144983d7f891858bf248a7338f5ec1076c552cb1e2485d9bba12ce69d59f52dfc6e2033c37d8111b8866334f1dfed51cfe243088d3d61661e14bb3cc8 + "@metamask/approval-controller": ^3.5.1 + checksum: 5e0d05ff1d56a9a58e031806528e6f7963227d5405ffd9c4df9623fc79ecaa703e26199066bdc77ec33e35abc25e2589d059b79f131d95e47c5e936991fdb817 languageName: node linkType: hard @@ -4537,6 +4537,16 @@ __metadata: languageName: node linkType: hard +"@metamask/post-message-stream@npm:^7.0.0": + version: 7.0.0 + resolution: "@metamask/post-message-stream@npm:7.0.0" + dependencies: + "@metamask/utils": "npm:^5.0.0" + readable-stream: "npm:3.6.2" + checksum: 626f12b28a495aeaf64fdf5ebd6175d8c4685241d241defc3e1e2b0c638fcfd3c901553aa43820d48de4cd19cf6f73c0c3d34f8a0bcb831f16f6d52d7458f79e + languageName: node + linkType: hard + "@metamask/ppom-validator@npm:^0.5.0": version: 0.5.0 resolution: "@metamask/ppom-validator@npm:0.5.0" @@ -4580,22 +4590,22 @@ __metadata: languageName: node linkType: hard -"@metamask/providers@npm:^11.0.0, @metamask/providers@npm:^11.1.0": - version: 11.1.0 - resolution: "@metamask/providers@npm:11.1.0" +"@metamask/providers@npm:^11.0.0, @metamask/providers@npm:^11.1.0, @metamask/providers@npm:^11.1.1": + version: 11.1.2 + resolution: "@metamask/providers@npm:11.1.2" dependencies: "@metamask/object-multiplex": "npm:^1.1.0" "@metamask/safe-event-emitter": "npm:^3.0.0" detect-browser: "npm:^5.2.0" eth-rpc-errors: "npm:^4.0.2" - extension-port-stream: "npm:^2.0.1" - fast-deep-equal: "npm:^2.0.1" + extension-port-stream: "npm:^2.1.1" + fast-deep-equal: "npm:^3.1.3" is-stream: "npm:^2.0.0" json-rpc-engine: "npm:^6.1.0" json-rpc-middleware-stream: "npm:^4.2.1" pump: "npm:^3.0.0" webextension-polyfill: "npm:^0.10.0" - checksum: e844e1e7b60a2b85fae973134852bd2d4de291daae1774a6f05fdc429e711ecea02710240b1b6dfe9656f712a4d9a356a6bc3f162d977f1878127a167b6a8fdf + checksum: 702399f2e21f3ce952c8a09d238ac777f33ef7fdc653793df1a833634eead27194602b9ef5ab44a4d519116b10815dc615ea7c304743eeeddae498d0973aad38 languageName: node linkType: hard @@ -4620,20 +4630,20 @@ __metadata: languageName: node linkType: hard -"@metamask/rpc-methods-flask@npm:@metamask/rpc-methods@0.37.2-flask.1, @metamask/rpc-methods@npm:^0.37.2-flask.1": - version: 0.37.2-flask.1 - resolution: "@metamask/rpc-methods@npm:0.37.2-flask.1" +"@metamask/rpc-methods-flask@npm:@metamask/rpc-methods@0.38.2-flask.1, @metamask/rpc-methods@npm:^0.38.2-flask.1": + version: 0.38.2-flask.1 + resolution: "@metamask/rpc-methods@npm:0.38.2-flask.1" dependencies: "@metamask/key-tree": "npm:^9.0.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/snaps-ui": "npm:^0.37.2-flask.1" - "@metamask/snaps-utils": "npm:^0.37.2-flask.1" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/snaps-utils": "npm:^0.38.3-flask.1" "@metamask/types": "npm:^1.1.0" - "@metamask/utils": "npm:^6.0.1" + "@metamask/utils": "npm:^7.1.0" "@noble/hashes": "npm:^1.3.1" eth-rpc-errors: "npm:^4.0.3" superstruct: "npm:^1.0.3" - checksum: 9c584fbd4465be797626c847432c2472e31ad7c85f7f90f9957197c266bb353cc30e1e4aa43cce5a1f85c98c586521887338b598efb4997747d49c7a42506452 + checksum: a9b49d49df69708cd8805909e25b67b0ff75ec8299035e2cedd1295ae17a68c3cb53cf87788da729c54135e8872e93cc901f27be6ad429db6efd66dd50488a0d languageName: node linkType: hard @@ -4773,23 +4783,22 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-controllers-flask@npm:@metamask/snaps-controllers@0.38.0-flask.1": - version: 0.38.0-flask.1 - resolution: "@metamask/snaps-controllers@npm:0.38.0-flask.1" +"@metamask/snaps-controllers-flask@npm:@metamask/snaps-controllers@0.38.3-flask.1": + version: 0.38.3-flask.1 + resolution: "@metamask/snaps-controllers@npm:0.38.3-flask.1" dependencies: - "@metamask/approval-controller": "npm:^3.0.0" - "@metamask/base-controller": "npm:^3.0.0" + "@metamask/approval-controller": "npm:^3.5.0" + "@metamask/base-controller": "npm:^3.2.0" "@metamask/object-multiplex": "npm:^1.2.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/post-message-stream": "npm:^6.1.2" - "@metamask/rpc-methods": "npm:^0.37.2-flask.1" - "@metamask/snaps-execution-environments": "npm:^0.38.0-flask.1" - "@metamask/snaps-registry": "npm:^1.2.1" - "@metamask/snaps-utils": "npm:^0.38.0-flask.1" - "@metamask/utils": "npm:^6.0.1" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/post-message-stream": "npm:^7.0.0" + "@metamask/rpc-methods": "npm:^0.38.2-flask.1" + "@metamask/snaps-execution-environments": "npm:^0.38.3-flask.1" + "@metamask/snaps-registry": "npm:^1.2.2" + "@metamask/snaps-utils": "npm:^0.38.3-flask.1" + "@metamask/utils": "npm:^7.1.0" "@xstate/fsm": "npm:^2.0.0" concat-stream: "npm:^2.0.0" - cron-parser: "npm:^4.5.0" eth-rpc-errors: "npm:^4.0.3" gunzip-maybe: "npm:^1.4.2" immer: "npm:^9.0.6" @@ -4799,7 +4808,7 @@ __metadata: pump: "npm:^3.0.0" readable-web-to-node-stream: "npm:^3.0.2" tar-stream: "npm:^2.2.0" - checksum: 242cc27ca06a137ac32c6dd85ad12282199fab3499ae0e2cb270f071636491dc6f8d21246732629856871630143797244aa9cbea5a78ab9b6dc791865c6dab42 + checksum: a6baa56d193d77d89187b461f9865517564c08f8a4b22e6c8a1373d8837816003a1dece1e69a194a022b6207a213236719d78588e925c787d948a90eeffc7a29 languageName: node linkType: hard @@ -4884,24 +4893,22 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-execution-environments@npm:^0.38.0-flask.1": - version: 0.38.0-flask.1 - resolution: "@metamask/snaps-execution-environments@npm:0.38.0-flask.1" +"@metamask/snaps-execution-environments@npm:^0.38.3-flask.1": + version: 0.38.3-flask.1 + resolution: "@metamask/snaps-execution-environments@npm:0.38.3-flask.1" dependencies: "@metamask/object-multiplex": "npm:^1.2.0" - "@metamask/post-message-stream": "npm:^6.1.2" - "@metamask/providers": "npm:^11.0.0" - "@metamask/rpc-methods": "npm:^0.37.2-flask.1" - "@metamask/snaps-utils": "npm:^0.38.0-flask.1" - "@metamask/utils": "npm:^6.0.1" + "@metamask/post-message-stream": "npm:^7.0.0" + "@metamask/providers": "npm:^11.1.1" + "@metamask/rpc-methods": "npm:^0.38.2-flask.1" + "@metamask/snaps-utils": "npm:^0.38.3-flask.1" + "@metamask/utils": "npm:^7.1.0" eth-rpc-errors: "npm:^4.0.3" json-rpc-engine: "npm:^6.1.0" nanoid: "npm:^3.1.31" pump: "npm:^3.0.0" - ses: "npm:^0.18.1" - stream-browserify: "npm:^3.0.0" superstruct: "npm:^1.0.3" - checksum: 98b3303620f6d1673fda0e18d62f3605fdc09eb3946096008398333591d1020446904e76280e2b36d47bcde93ab35a59d4a573c8578daac22a10351118e6241f + checksum: 471133c91b04f95aaba0aa4d6357ea58df231d062d7cce4b187e6ded7d7bc9018efe6416aea342e584d6f9d0d82b31fdee4f5dd8f3f4d1cd175229ed2ef903f0 languageName: node linkType: hard @@ -4925,24 +4932,24 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-registry@npm:^1.2.1": - version: 1.2.1 - resolution: "@metamask/snaps-registry@npm:1.2.1" +"@metamask/snaps-registry@npm:^1.2.1, @metamask/snaps-registry@npm:^1.2.2": + version: 1.2.2 + resolution: "@metamask/snaps-registry@npm:1.2.2" dependencies: - "@metamask/utils": "npm:^6.0.0" + "@metamask/utils": "npm:^7.1.0" "@noble/secp256k1": "npm:^1.7.1" superstruct: "npm:^1.0.3" - checksum: de16245fd26b98f9bab7764838f7911aec0ecc409dd814b3ed6fe39a1cb2ea579c3a31deafbd348082942f6aae1a82d8e2dd8fd46fb071c3d1e4974b0d07e87a + checksum: b7273d5554081749c92610c7da7d9407c7f33eef9184d8297e9f204be902f4825f8d9cee561135c5eed9b4d978ef4e3b3ec4cbdbd669ac36d9f7ad433389668f languageName: node linkType: hard -"@metamask/snaps-ui-flask@npm:@metamask/snaps-ui@0.37.3-flask.1, @metamask/snaps-ui@npm:^0.37.3-flask.1": - version: 0.37.3-flask.1 - resolution: "@metamask/snaps-ui@npm:0.37.3-flask.1" +"@metamask/snaps-ui-flask@npm:@metamask/snaps-ui@0.37.4-flask.1, @metamask/snaps-ui@npm:^0.37.4-flask.1": + version: 0.37.4-flask.1 + resolution: "@metamask/snaps-ui@npm:0.37.4-flask.1" dependencies: "@metamask/utils": "npm:^6.0.1" superstruct: "npm:^1.0.3" - checksum: 4fbcaf50cf79ce43c5c1929174ad566a7bcfc8d3bd7c21c83c295493aa510bcc93a78c02636d973f369b79887ce726fc3025a62154bf6dfd363c426ec9506e3d + checksum: e57ca1e375d0c7860f198143789226552cb449a654e97b639f90a0cb577f9d46387c7c65b5dacc05b7fa613ed8499021df286590b6c633b6f5be8578d4d9f6a9 languageName: node linkType: hard @@ -4956,16 +4963,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-ui@npm:^0.37.2-flask.1": - version: 0.37.2-flask.1 - resolution: "@metamask/snaps-ui@npm:0.37.2-flask.1" - dependencies: - "@metamask/utils": "npm:^6.0.1" - superstruct: "npm:^1.0.3" - checksum: a0db8d6aaf2c9070aedf6a7b03878a2901136c820bc2c4412d52785857f4f5302822c8e03e05ad52c46e1a9695b12e034cc7dff3ad9092af022970a4b258bc1b - languageName: node - linkType: hard - "@metamask/snaps-ui@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-ui@npm:1.0.2" @@ -4976,19 +4973,18 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-utils-flask@npm:@metamask/snaps-utils@0.38.0-flask.1, @metamask/snaps-utils@npm:^0.38.0-flask.1": - version: 0.38.0-flask.1 - resolution: "@metamask/snaps-utils@npm:0.38.0-flask.1" +"@metamask/snaps-utils-flask@npm:@metamask/snaps-utils@0.38.3-flask.1, @metamask/snaps-utils@npm:^0.38.3-flask.1": + version: 0.38.3-flask.1 + resolution: "@metamask/snaps-utils@npm:0.38.3-flask.1" dependencies: "@babel/core": "npm:^7.20.12" "@babel/types": "npm:^7.18.7" - "@metamask/base-controller": "npm:^3.0.0" + "@metamask/base-controller": "npm:^3.2.0" "@metamask/key-tree": "npm:^9.0.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/providers": "npm:^11.0.0" - "@metamask/snaps-registry": "npm:^1.2.1" - "@metamask/snaps-ui": "npm:^0.37.3-flask.1" - "@metamask/utils": "npm:^6.0.1" + "@metamask/permission-controller": "npm:^4.1.0" + "@metamask/snaps-registry": "npm:^1.2.2" + "@metamask/snaps-ui": "npm:^0.37.4-flask.1" + "@metamask/utils": "npm:^7.1.0" "@noble/hashes": "npm:^1.3.1" "@scure/base": "npm:^1.1.1" chalk: "npm:^4.1.2" @@ -4999,10 +4995,10 @@ __metadata: is-svg: "npm:^4.4.0" rfdc: "npm:^1.3.0" semver: "npm:^7.5.4" - ses: "npm:^0.18.1" + ses: "npm:^0.18.7" superstruct: "npm:^1.0.3" validate-npm-package-name: "npm:^5.0.0" - checksum: 05fc7ebf73135f42690313a62a442dd3991eedf5d5478f981f846d4a27919fb04810b50aebe6fdbb2705dabfabf258b2c3b15f1867efaadf773cdec2cf9db869 + checksum: 002a685195b433a3c3e5bb927f9f494271526998f3c44a58cce3737d35fc76f3b5317419048b68404b88508c8435e85fa0da55787ed4a4044ef319c8f1282807 languageName: node linkType: hard @@ -5035,36 +5031,6 @@ __metadata: languageName: node linkType: hard -"@metamask/snaps-utils@npm:^0.37.2-flask.1": - version: 0.37.2-flask.1 - resolution: "@metamask/snaps-utils@npm:0.37.2-flask.1" - dependencies: - "@babel/core": "npm:^7.20.12" - "@babel/types": "npm:^7.18.7" - "@metamask/base-controller": "npm:^3.0.0" - "@metamask/key-tree": "npm:^9.0.0" - "@metamask/permission-controller": "npm:^4.0.0" - "@metamask/providers": "npm:^11.0.0" - "@metamask/snaps-registry": "npm:^1.2.1" - "@metamask/snaps-ui": "npm:^0.37.2-flask.1" - "@metamask/utils": "npm:^6.0.1" - "@noble/hashes": "npm:^1.3.1" - "@scure/base": "npm:^1.1.1" - chalk: "npm:^4.1.2" - cron-parser: "npm:^4.5.0" - eth-rpc-errors: "npm:^4.0.3" - fast-deep-equal: "npm:^3.1.3" - fast-json-stable-stringify: "npm:^2.1.0" - is-svg: "npm:^4.4.0" - rfdc: "npm:^1.3.0" - semver: "npm:^7.3.7" - ses: "npm:^0.18.1" - superstruct: "npm:^1.0.3" - validate-npm-package-name: "npm:^5.0.0" - checksum: f4d63fc97a5f791550ffddb1d8cbcda2a703615b8dde8ea0d206f9ac79a1c86fe4a0e176c9b8b2a354ce2b197d3ac53621494a6f4d9e4bed5bc949aad05f2984 - languageName: node - linkType: hard - "@metamask/snaps-utils@npm:^1.0.2": version: 1.0.2 resolution: "@metamask/snaps-utils@npm:1.0.2" @@ -5163,7 +5129,7 @@ __metadata: languageName: node linkType: hard -"@metamask/utils@npm:^6.0.0, @metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.1.0, @metamask/utils@npm:^6.2.0": +"@metamask/utils@npm:^6.0.1, @metamask/utils@npm:^6.1.0, @metamask/utils@npm:^6.2.0": version: 6.2.0 resolution: "@metamask/utils@npm:6.2.0" dependencies: @@ -5177,6 +5143,20 @@ __metadata: languageName: node linkType: hard +"@metamask/utils@npm:^7.1.0": + version: 7.1.0 + resolution: "@metamask/utils@npm:7.1.0" + dependencies: + "@ethereumjs/tx": "npm:^4.1.2" + "@noble/hashes": "npm:^1.3.1" + "@types/debug": "npm:^4.1.7" + debug: "npm:^4.3.4" + semver: "npm:^7.5.4" + superstruct: "npm:^1.0.3" + checksum: 35259e67d53d7c56cd2c001a525b75baf799f1a74a357cdb3f0b23fa2be7fb3b01d3fe676c2942c0abdf23e4e4e337380c6456376f90fe69a43e7fa39097d8be + languageName: node + linkType: hard + "@multiformats/base-x@npm:^4.0.1": version: 4.0.1 resolution: "@multiformats/base-x@npm:4.0.1" @@ -24223,7 +24203,7 @@ __metadata: "@metamask/eth-json-rpc-middleware": "npm:^11.0.0" "@metamask/eth-keyring-controller": "npm:^10.0.1" "@metamask/eth-ledger-bridge-keyring": "npm:^0.15.0" - "@metamask/eth-snap-keyring": "npm:^0.1.3" + "@metamask/eth-snap-keyring": "npm:^0.1.4" "@metamask/eth-token-tracker": "npm:^4.0.0" "@metamask/eth-trezor-keyring": "npm:^1.1.0" "@metamask/etherscan-link": "npm:^2.2.0" @@ -24246,7 +24226,7 @@ __metadata: "@metamask/providers": "npm:^11.1.0" "@metamask/rate-limit-controller": "npm:^3.0.0" "@metamask/rpc-methods": "npm:^1.0.2" - "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.37.2-flask.1" + "@metamask/rpc-methods-flask": "npm:@metamask/rpc-methods@0.38.2-flask.1" "@metamask/safe-event-emitter": "npm:^2.0.0" "@metamask/scure-bip39": "npm:^2.0.3" "@metamask/selected-network-controller": "npm:^1.0.0" @@ -24254,11 +24234,11 @@ __metadata: "@metamask/slip44": "npm:^3.0.0" "@metamask/smart-transactions-controller": "npm:^4.0.0" "@metamask/snaps-controllers": "npm:^1.0.2" - "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.0-flask.1" + "@metamask/snaps-controllers-flask": "npm:@metamask/snaps-controllers@0.38.3-flask.1" "@metamask/snaps-ui": "npm:^1.0.2" - "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.3-flask.1" + "@metamask/snaps-ui-flask": "npm:@metamask/snaps-ui@0.37.4-flask.1" "@metamask/snaps-utils": "npm:^1.0.2" - "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.0-flask.1" + "@metamask/snaps-utils-flask": "npm:@metamask/snaps-utils@0.38.3-flask.1" "@metamask/subject-metadata-controller": "npm:^2.0.0" "@metamask/test-dapp": "npm:^7.1.0" "@metamask/utils": "npm:^5.0.0" @@ -29240,14 +29220,14 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:2 || 3, readable-stream@npm:3, readable-stream@npm:^3.0.2, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": - version: 3.6.0 - resolution: "readable-stream@npm:3.6.0" +"readable-stream@npm:2 || 3, readable-stream@npm:3, readable-stream@npm:3.6.2, readable-stream@npm:^3.0.2, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0": + version: 3.6.2 + resolution: "readable-stream@npm:3.6.2" dependencies: inherits: "npm:^2.0.3" string_decoder: "npm:^1.1.1" util-deprecate: "npm:^1.0.1" - checksum: b80b3e6a7fafb1c79de7db541de357f4a5ee73bd70c21672f5a7c840d27bb27bdb0151e7ba2fd82c4a888df22ce0c501b0d9f3e4dfe51688876701c437d59536 + checksum: d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048 languageName: node linkType: hard From a1287494321dff7daadc83694bc32c2593af8d2c Mon Sep 17 00:00:00 2001 From: Ariella Vu <20778143+digiwand@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:30:50 +0200 Subject: [PATCH 16/38] build: add "test:unit:jest:watch" script to package.json to run jest tests on a node server (#20683) --- docs/tests/jest.md | 58 ++++++++++++++++++++++++++++------------------ package.json | 1 + 2 files changed, 37 insertions(+), 22 deletions(-) diff --git a/docs/tests/jest.md b/docs/tests/jest.md index c4dc613aa46a..4e0d80863eb6 100644 --- a/docs/tests/jest.md +++ b/docs/tests/jest.md @@ -6,9 +6,9 @@ > yarn jest ``` -## Debugging +**note:** Breakpoints will not work in this mode. To debug, run the Jest test using a node server. -### Debugging Jest in VS Code +## Running a Jest test on a node server and inspecting in VS Code 1. Open **VS Code** 2. Open the “Run and Debug” panel (⇧⌘D) @@ -21,44 +21,58 @@ Additional methods and information to debug in VS Code can be found [here](https://jestjs.io/docs/troubleshooting#debugging-in-vs-code) -### Debugging Jest on Chrome DevTools +## Running a Jest test on a node server and inspecting in Chrome DevTools 1. Run Jest using Node with the V8 Inspector ```bash - > node --inspect ./node_modules/.bin/jest --watch -i + > yarn test:unit:jest:watch + ``` or - > node --inspect ./node_modules/.bin/jest + ```bash + > node --inspect ./node_modules/.bin/jest --watch ``` - **Options:** + **Useful options:** - ```jsx + ```bash node: - --inspect=[host:]port - Activate inspector on host:port. Default is 127.0.0.1:9229. + --inspect=[host:]port + Activate inspector on host:port. Default is 127.0.0.1:9229. - V8 Inspector integration allows attaching Chrome DevTools and IDEs - to Node.js instances for debugging and profiling. It uses the - Chrome DevTools Protocol. + V8 Inspector integration allows attaching Chrome DevTools and IDEs + to Node.js instances for debugging and profiling. It uses the + Chrome DevTools Protocol. jest: - --watch Watch files for changes and rerun tests - related to changed files. If you want to - re-run all tests when a file has changed, - use the `--watchAll` option. [boolean] - - -i, --runInBand Run all tests serially in the current - process (rather than creating a worker pool - of child processes that run tests). This is - sometimes useful for debugging, but such use - cases are pretty rare. [boolean] + -i, --runInBand + Run all tests serially in the current + process (rather than creating a worker pool + of child processes that run tests). This is + sometimes useful for debugging, but such use + cases are pretty rare. [boolean] + + -u, --updateSnapshot + Use this flag to re-record snapshots. Can be + used together with a test suite pattern or + with `--testNamePattern` to re-record + snapshot for test matching the pattern + + --watch + Watch files for changes and rerun tests + related to changed files. If you want to + re-run all tests when a file has changed, + use the `--watchAll` option. [boolean] ``` + **To view more options:** + ```bash + > ./node_modules/.bin/jest help + ``` 1. Open Chrome DevTools for Node 1. Open a **Chromium** browser diff --git a/package.json b/package.json index dd63b9594cc8..9b99189cf511 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dapp-forwarder": "concurrently -k -n forwarder,dapp -p '[{time}][{name}]' 'yarn forwarder' 'yarn dapp'", "test:unit": "node ./test/run-unit-tests.js --mocha --jestGlobal --jestDev", "test:unit:jest": "node ./test/run-unit-tests.js --jestGlobal --jestDev", + "test:unit:jest:watch": "node --inspect ./node_modules/.bin/jest --watch", "test:unit:global": "mocha test/unit-global/*.test.js", "test:unit:mocha": "node ./test/run-unit-tests.js --mocha", "test:e2e:chrome": "SELENIUM_BROWSER=chrome node test/e2e/run-all.js", From f3c1108144a1abe5407846f327b7a7239262c4b2 Mon Sep 17 00:00:00 2001 From: Ariella Vu <20778143+digiwand@users.noreply.github.com> Date: Wed, 13 Sep 2023 18:31:24 +0200 Subject: [PATCH 17/38] Fix: Unable to edit token allowance / custom spending cap (#20804) --- .../custom-spending-cap.js | 1 + .../token-allowance.test.js.snap | 11 +++- ui/pages/token-allowance/token-allowance.js | 25 ++++++++- .../token-allowance/token-allowance.test.js | 56 +++++++++++-------- 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/ui/components/app/custom-spending-cap/custom-spending-cap.js b/ui/components/app/custom-spending-cap/custom-spending-cap.js index bcca9ec7efca..b2e1ec12566f 100644 --- a/ui/components/app/custom-spending-cap/custom-spending-cap.js +++ b/ui/components/app/custom-spending-cap/custom-spending-cap.js @@ -141,6 +141,7 @@ export default function CustomSpendingCap({ setError(spendingCapError); } } + setCustomSpendingCap(String(valueInput)); dispatch(setCustomTokenAmount(String(valueInput))); diff --git a/ui/pages/token-allowance/__snapshots__/token-allowance.test.js.snap b/ui/pages/token-allowance/__snapshots__/token-allowance.test.js.snap index ba4e7cd49081..2478f5096e4e 100644 --- a/ui/pages/token-allowance/__snapshots__/token-allowance.test.js.snap +++ b/ui/pages/token-allowance/__snapshots__/token-allowance.test.js.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`TokenAllowancePage should match snapshot 1`] = ` +exports[`TokenAllowancePage when mounted should match snapshot 1`] = `
+
+
+
+
+ Unknown address +
+
+
+ +
+ +
+
+
+ + + 0xc0f...4979 + +
+
+
+

+ You are interacting with an unknown contract address. If you trust this author, set a personal display name to identify it going forward. +

+
+
+ +
+ + +
+
+ +
+ + + + +
+
+ +`; + +exports[`NameDetails renders with saved name 1`] = ` + +
+
+
+
+
+