diff --git a/app/actions/notification/helpers/index.ts b/app/actions/notification/helpers/index.ts index 9f47da07f88..b1c4c881eb9 100644 --- a/app/actions/notification/helpers/index.ts +++ b/app/actions/notification/helpers/index.ts @@ -171,6 +171,15 @@ export const markMetamaskNotificationsAsRead = async ( return getErrorMessage(error); } }; + +export const syncInternalAccountsWithUserStorage = async () => { + try { + await Engine.context.UserStorageController.syncInternalAccountsWithUserStorage(); + } catch (error) { + return getErrorMessage(error); + } +}; + /** * Perform the deletion of the notifications storage key and the creation of on chain triggers to reset the notifications. * @@ -178,12 +187,12 @@ export const markMetamaskNotificationsAsRead = async ( */ export const performDeleteStorage = async (): Promise => { try { - await Engine.context.UserStorageController.performDeleteStorage('notifications.notification_settings'); - await Engine.context.NotificationServicesController.createOnChainTriggers( - { + await Engine.context.UserStorageController.performDeleteStorage( + 'notifications.notification_settings', + ); + await Engine.context.NotificationServicesController.createOnChainTriggers({ resetNotifications: true, - }, - ); + }); } catch (error) { return getErrorMessage(error); } diff --git a/app/components/Views/Wallet/index.test.tsx b/app/components/Views/Wallet/index.test.tsx index 9b008db9496..a02e454084c 100644 --- a/app/components/Views/Wallet/index.test.tsx +++ b/app/components/Views/Wallet/index.test.tsx @@ -1,13 +1,15 @@ import React from 'react'; import Wallet from './'; import { renderScreen } from '../../../util/test/renderWithProvider'; -import { screen } from '@testing-library/react-native'; +import { act, screen } from '@testing-library/react-native'; import ScrollableTabView from 'react-native-scrollable-tab-view'; import Routes from '../../../constants/navigation/Routes'; import { backgroundState } from '../../../util/test/initial-root-state'; import { createMockAccountsControllerState } from '../../../util/test/accountsControllerTestUtils'; import { WalletViewSelectorsIDs } from '../../../../e2e/selectors/wallet/WalletView.selectors'; import { CommonSelectorsIDs } from '../../../../e2e/selectors/Common.selectors'; +import { useAccountSyncing } from '../../../util/notifications/hooks/useAccountSyncing'; +import { AppState } from 'react-native'; const MOCK_ADDRESS = '0xc4955c0d639d99699bfd7ec54d9fafee40e4d272'; @@ -108,6 +110,13 @@ jest.mock('react-native-scrollable-tab-view', () => { return ScrollableTabViewMock; }); +jest.mock('../../../util/notifications/hooks/useAccountSyncing', () => ({ + useAccountSyncing: jest.fn().mockReturnValue({ + dispatchAccountSyncing: jest.fn(), + error: undefined, + }), +})); + const render = (Component: React.ComponentType) => renderScreen( Component, @@ -144,4 +153,36 @@ describe('Wallet', () => { const foxIcon = screen.getByTestId(CommonSelectorsIDs.FOX_ICON); expect(foxIcon).toBeDefined(); }); + it('should dispatch account syncing on mount', () => { + jest.clearAllMocks(); + //@ts-expect-error we are ignoring the navigation params on purpose because we do not want to mock setOptions to test the navbar + render(Wallet); + expect(useAccountSyncing().dispatchAccountSyncing).toHaveBeenCalledTimes(1); + }); + it('should dispatch account syncing when appState switches from inactive|background to active', () => { + jest.clearAllMocks(); + + const addEventListener = jest.spyOn(AppState, 'addEventListener'); + + //@ts-expect-error we are ignoring the navigation params on purpose because we do not want to mock setOptions to test the navbar + render(Wallet); + + expect(addEventListener).toHaveBeenCalledTimes(1); + + const handleAppStateChange = addEventListener.mock.calls[0][1]; + + act(() => { + handleAppStateChange('background'); + handleAppStateChange('active'); + }); + + expect(useAccountSyncing().dispatchAccountSyncing).toHaveBeenCalledTimes(2); + + act(() => { + handleAppStateChange('inactive'); + handleAppStateChange('active'); + }); + + expect(useAccountSyncing().dispatchAccountSyncing).toHaveBeenCalledTimes(3); + }); }); diff --git a/app/components/Views/Wallet/index.tsx b/app/components/Views/Wallet/index.tsx index e8513940f7e..dbc4a3f2907 100644 --- a/app/components/Views/Wallet/index.tsx +++ b/app/components/Views/Wallet/index.tsx @@ -103,6 +103,8 @@ import { } from '../../../selectors/notifications'; import { ButtonVariants } from '../../../component-library/components/Buttons/Button'; import { useListNotifications } from '../../../util/notifications/hooks/useNotifications'; +import { useAccountSyncing } from '../../../util/notifications/hooks/useAccountSyncing'; + import { isObject } from 'lodash'; const createStyles = ({ colors, typography }: Theme) => @@ -169,6 +171,7 @@ const Wallet = ({ const appState = useRef(AppState.currentState); const { navigate } = useNavigation(); const { listNotifications } = useListNotifications(); + const { dispatchAccountSyncing } = useAccountSyncing(); const walletRef = useRef(null); const theme = useTheme(); const { toastRef } = useContext(ToastContext); @@ -443,13 +446,17 @@ const Wallet = ({ [navigation, providerConfig.chainId], ); + // Layout effect when component/view is visible + // - fetches notifications + // - dispatches account syncing useLayoutEffect(() => { const handleAppStateChange = (nextAppState: AppStateStatus) => { if ( - appState.current.match(/inactive|background/) && + appState.current?.match(/inactive|background/) && nextAppState === 'active' ) { listNotifications(); + dispatchAccountSyncing(); } appState.current = nextAppState; @@ -459,11 +466,14 @@ const Wallet = ({ 'change', handleAppStateChange, ); + listNotifications(); + dispatchAccountSyncing(); + return () => { subscription.remove(); }; - }, [listNotifications]); + }, [listNotifications, dispatchAccountSyncing]); useEffect(() => { navigation.setOptions( diff --git a/app/core/Analytics/MetaMetrics.events.ts b/app/core/Analytics/MetaMetrics.events.ts index d15622a6aac..e31ddeb66bb 100644 --- a/app/core/Analytics/MetaMetrics.events.ts +++ b/app/core/Analytics/MetaMetrics.events.ts @@ -369,6 +369,9 @@ enum EVENT_NAME { PRIMARY_CURRENCY_TOGGLE = 'primary_currency_toggle', LOGIN_DOWNLOAD_LOGS = 'Download State Logs Button Clicked', + // Profile Syncing + ACCOUNTS_SYNC_ADDED = 'Accounts Sync Added', + ACCOUNTS_SYNC_NAME_UPDATED = 'Accounts Sync Name Updated', // network MULTI_RPC_MIGRATION_MODAL_ACCEPTED = 'multi_rpc_migration_modal_accepted', } @@ -854,6 +857,12 @@ const events = { ), PRIMARY_CURRENCY_TOGGLE: generateOpt(EVENT_NAME.PRIMARY_CURRENCY_TOGGLE), LOGIN_DOWNLOAD_LOGS: generateOpt(EVENT_NAME.LOGIN_DOWNLOAD_LOGS), + + // Profile Syncing + ACCOUNTS_SYNC_ADDED: generateOpt(EVENT_NAME.ACCOUNTS_SYNC_ADDED), + ACCOUNTS_SYNC_NAME_UPDATED: generateOpt( + EVENT_NAME.ACCOUNTS_SYNC_NAME_UPDATED, + ), }; /** diff --git a/app/core/Engine.ts b/app/core/Engine.ts index 95199c1b9eb..a3dd3117f30 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine.ts @@ -127,7 +127,7 @@ import { } from '@metamask/snaps-controllers'; import { WebViewExecutionService } from '@metamask/snaps-controllers/react-native'; -import { NotificationArgs } from '@metamask/snaps-rpc-methods/dist/types/restricted/notify'; +import { NotificationParameters } from '@metamask/snaps-rpc-methods/dist/restricted/notify.cjs'; import { getSnapsWebViewPromise } from '../lib/snaps'; import { buildSnapEndowmentSpecifications, @@ -252,6 +252,7 @@ import { HandleSnapRequestArgs } from './Snaps/types'; import { handleSnapRequest } from './Snaps/utils'; ///: END:ONLY_INCLUDE_IF import { trace } from '../util/trace'; +import { MetricsEventBuilder } from './Analytics/MetricsEventBuilder'; const NON_EMPTY = 'NON_EMPTY'; @@ -515,7 +516,7 @@ class Engine { showApprovalRequest: () => undefined, typesExcludedFromRateLimiting: [ ApprovalType.Transaction, - ApprovalType.WatchAsset + ApprovalType.WatchAsset, ], }); @@ -896,7 +897,7 @@ class Engine { type, requestData: { content, placeholder }, }), - showInAppNotification: (origin: string, args: NotificationArgs) => { + showInAppNotification: (origin: string, args: NotificationParameters) => { Logger.log( 'Snaps/ showInAppNotification called with args: ', args, @@ -1213,12 +1214,42 @@ class Engine { const userStorageController = new UserStorageController.Controller({ getMetaMetricsState: () => MetaMetrics.getInstance().isEnabled(), + env: { + isAccountSyncingEnabled: true, + }, + config: { + accountSyncing: { + onAccountAdded: (profileId) => { + MetaMetrics.getInstance().trackEvent( + MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.ACCOUNTS_SYNC_ADDED, + ) + .addProperties({ + profile_id: profileId, + }) + .build(), + ); + }, + onAccountNameUpdated: (profileId) => { + MetaMetrics.getInstance().trackEvent( + MetricsEventBuilder.createEventBuilder( + MetaMetricsEvents.ACCOUNTS_SYNC_NAME_UPDATED, + ) + .addProperties({ + profile_id: profileId, + }) + .build(), + ); + }, + }, + }, state: initialState.UserStorageController, messenger: this.controllerMessenger.getRestricted({ name: 'UserStorageController', allowedActions: [ 'SnapController:handleRequest', 'KeyringController:getState', + 'KeyringController:addNewAccount', 'AuthenticationController:getBearerToken', 'AuthenticationController:getSessionProfile', 'AuthenticationController:isSignedIn', @@ -1226,13 +1257,12 @@ class Engine { 'AuthenticationController:performSignIn', 'NotificationServicesController:disableNotificationServices', 'NotificationServicesController:selectIsNotificationServicesEnabled', - 'KeyringController:addNewAccount', 'AccountsController:listAccounts', 'AccountsController:updateAccountMetadata', ], allowedEvents: [ - 'KeyringController:lock', 'KeyringController:unlock', + 'KeyringController:lock', 'AccountsController:accountAdded', 'AccountsController:accountRenamed', ], diff --git a/app/util/notifications/hooks/useAccountSyncing.test.tsx b/app/util/notifications/hooks/useAccountSyncing.test.tsx new file mode 100644 index 00000000000..f9fdb72cb40 --- /dev/null +++ b/app/util/notifications/hooks/useAccountSyncing.test.tsx @@ -0,0 +1,102 @@ +/* eslint-disable import/no-namespace */ +/* eslint-disable react/prop-types */ +/* eslint-disable react/display-name */ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-require-imports */ +import { act, renderHook } from '@testing-library/react-hooks'; +import React from 'react'; +import { Provider } from 'react-redux'; +import createMockStore from 'redux-mock-store'; +import * as Actions from '../../../actions/notification/helpers'; +import initialRootState from '../../../util/test/initial-root-state'; +import { useAccountSyncing } from './useAccountSyncing'; + +function arrangeStore() { + const store = createMockStore()(initialRootState); + + // Ensure dispatch mocks are handled correctly + store.dispatch = jest.fn().mockImplementation((action) => { + if (typeof action === 'function') { + return action(store.dispatch, store.getState); + } + return Promise.resolve(); + }); + + return store; +} + +describe('useAccountSyncing', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + function arrangeHook() { + const store = arrangeStore(); + const hook = renderHook(() => useAccountSyncing(), { + wrapper: ({ children }) => {children}, + }); + + return hook; + } + + function arrangeActions() { + const syncInternalAccountsWithUserStorageAction = jest + .spyOn(Actions, 'syncInternalAccountsWithUserStorage') + .mockResolvedValue(undefined); + + return { + syncInternalAccountsWithUserStorageAction, + }; + } + + it('dispatches account syncing and error as undefined', async () => { + const mockActions = arrangeActions(); + + const { result } = arrangeHook(); + await act(async () => { + await result.current.dispatchAccountSyncing(); + }); + + expect( + mockActions.syncInternalAccountsWithUserStorageAction, + ).toHaveBeenCalledTimes(1); + expect(result.current.error).toBeUndefined(); + }); + + it('sets error message when syncInternalAccountsWithUserStorageAction returns an error', async () => { + const mockActions = arrangeActions(); + mockActions.syncInternalAccountsWithUserStorageAction.mockRejectedValueOnce( + new Error('MOCK - failed to sync internal account with user storage'), + ); + + const { result } = arrangeHook(); + await act(async () => { + await result.current.dispatchAccountSyncing(); + }); + + expect( + mockActions.syncInternalAccountsWithUserStorageAction, + ).toHaveBeenCalledTimes(1); + expect(result.current.error).toBeDefined(); + expect(result.current.error).toEqual( + 'MOCK - failed to sync internal account with user storage', + ); + }); + + it('sets error message when an error occurs during dispatchAccountSyncing', async () => { + const mockActions = arrangeActions(); + mockActions.syncInternalAccountsWithUserStorageAction.mockRejectedValueOnce( + new Error('MOCK - failed to sync internal account with user storage'), + ); + + const { result } = arrangeHook(); + await act(async () => { + await result.current.dispatchAccountSyncing(); + }); + + expect(result.current.error).toBeDefined(); + expect(result.current.error).toEqual( + 'MOCK - failed to sync internal account with user storage', + ); + }); +}); diff --git a/app/util/notifications/hooks/useAccountSyncing.ts b/app/util/notifications/hooks/useAccountSyncing.ts new file mode 100644 index 00000000000..7c309e81deb --- /dev/null +++ b/app/util/notifications/hooks/useAccountSyncing.ts @@ -0,0 +1,32 @@ +import { useState, useCallback } from 'react'; +import { getErrorMessage } from '../../../util/errorHandling'; +import { syncInternalAccountsWithUserStorage as syncInternalAccountsWithUserStorageAction } from '../../../actions/notification/helpers'; + +/** + * Custom hook to dispatch account syncing. + * + * @returns An object containing the `dispatchAccountSyncing` function, and error state. + */ +export const useAccountSyncing = () => { + const [error, setError] = useState(); + + const dispatchAccountSyncing = useCallback(async () => { + setError(undefined); + try { + const errorMessage = await syncInternalAccountsWithUserStorageAction(); + if (errorMessage) { + setError(getErrorMessage(errorMessage)); + return errorMessage; + } + } catch (e) { + const errorMessage = getErrorMessage(e); + setError(errorMessage); + return errorMessage; + } + }, []); + + return { + dispatchAccountSyncing, + error, + }; +}; diff --git a/app/util/notifications/hooks/useProfileSyncing.ts b/app/util/notifications/hooks/useProfileSyncing.ts index 33255b0b590..5f0d742dd22 100644 --- a/app/util/notifications/hooks/useProfileSyncing.ts +++ b/app/util/notifications/hooks/useProfileSyncing.ts @@ -1,4 +1,3 @@ -/* eslint-disable import/prefer-default-export */ import { useState, useCallback } from 'react'; import { ProfileSyncingReturn } from './types'; import { getErrorMessage } from '../../../util/errorHandling'; diff --git a/package.json b/package.json index 1b811292afe..a15a8b0008a 100644 --- a/package.json +++ b/package.json @@ -107,7 +107,6 @@ "**/xml2js": ">=0.5.0", "react-native-level-fs/**/bl": "^1.2.3", "react-native-level-fs/levelup/semver": "^5.7.2", - "@metamask/accounts-controller": "^18.1.0", "@metamask/contract-metadata": "^2.1.0", "@metamask/react-native-payments/validator": "^13.7.0", "**/minimist": "1.2.6", @@ -180,8 +179,8 @@ "@metamask/smart-transactions-controller": "^13.0.0", "@metamask/snaps-controllers": "^9.8.0", "@metamask/snaps-execution-environments": "^6.7.2", - "@metamask/snaps-rpc-methods": "^9.1.4", - "@metamask/snaps-sdk": "^6.5.0", + "@metamask/snaps-rpc-methods": "^11.1.1", + "@metamask/snaps-sdk": "^6.5.1", "@metamask/snaps-utils": "^8.1.1", "@metamask/swappable-obj-proxy": "^2.1.0", "@metamask/swaps-controller": "^9.0.12", diff --git a/yarn.lock b/yarn.lock index 4d2b39ab497..7006ca864e2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4294,7 +4294,42 @@ "@metamask/superstruct" "^3.1.0" "@metamask/utils" "^9.0.0" -"@metamask/accounts-controller@^16.0.0", "@metamask/accounts-controller@^17.2.0", "@metamask/accounts-controller@^18.1.0", "@metamask/accounts-controller@^18.2.1": +"@metamask/accounts-controller@^16.0.0": + version "16.0.0" + resolved "https://registry.yarnpkg.com/@metamask/accounts-controller/-/accounts-controller-16.0.0.tgz#796ec5266c6976dc53c585e88f8bb0d066722e86" + integrity sha512-FizBU+zuiztKylufnszaHi4uJxkN/oP0YS5LGiGpGKjRretbqJiuTAo6ol2jUAu+J67j+oQ1qfpDwz49n0FC6A== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/base-controller" "^6.0.0" + "@metamask/eth-snap-keyring" "^4.1.1" + "@metamask/keyring-api" "^6.1.1" + "@metamask/snaps-sdk" "^4.2.0" + "@metamask/snaps-utils" "^7.4.0" + "@metamask/utils" "^8.3.0" + deepmerge "^4.2.2" + ethereum-cryptography "^2.1.2" + immer "^9.0.6" + uuid "^8.3.2" + +"@metamask/accounts-controller@^17.2.0": + version "17.2.0" + resolved "https://registry.yarnpkg.com/@metamask/accounts-controller/-/accounts-controller-17.2.0.tgz#b74918444a9d8e6e69b9b761dc58e64aac6b466c" + integrity sha512-hfdfRV7mxxnyG1tri3CatV63WWtwPkUSl0zTz7Mq3psSXqOFr+08f1Elw4sX7pP1V/rCxZKeotoluIjUeu1Q9Q== + dependencies: + "@ethereumjs/util" "^8.1.0" + "@metamask/base-controller" "^6.0.0" + "@metamask/eth-snap-keyring" "^4.3.1" + "@metamask/keyring-api" "^8.0.0" + "@metamask/keyring-controller" "^17.1.0" + "@metamask/snaps-sdk" "^4.2.0" + "@metamask/snaps-utils" "^7.4.0" + "@metamask/utils" "^8.3.0" + deepmerge "^4.2.2" + ethereum-cryptography "^2.1.2" + immer "^9.0.6" + uuid "^8.3.2" + +"@metamask/accounts-controller@^18.2.1": version "18.2.1" resolved "https://registry.yarnpkg.com/@metamask/accounts-controller/-/accounts-controller-18.2.1.tgz#8e4a842316e9b7bbd0409b36129f7123ba4a4c79" integrity sha512-BEvux+ZFpTOQa6HbRl7i7Tq24ztqrZIsX+H0ePh47lU+N8RWq1q0JCItV+zbsgdcYnwhtcMZTsp4jJPQwPe2og== @@ -4653,22 +4688,20 @@ ethereum-cryptography "^2.1.2" randombytes "^2.1.0" -"@metamask/eth-snap-keyring@^4.3.3": - version "4.3.4" - resolved "https://registry.yarnpkg.com/@metamask/eth-snap-keyring/-/eth-snap-keyring-4.3.4.tgz#78308770d421f6f3c9d24dba925acf87a54012e8" - integrity sha512-y68ksrkwZJ7J5Edej+XvTDR04CwZs0BHjOVpJbnA/328P75Gs7jSHWqOE7DtziMbwpVsFlgBMTVFPsSyrh8Fmg== +"@metamask/eth-snap-keyring@^4.1.1", "@metamask/eth-snap-keyring@^4.3.1", "@metamask/eth-snap-keyring@^4.3.3": + version "4.3.6" + resolved "https://registry.yarnpkg.com/@metamask/eth-snap-keyring/-/eth-snap-keyring-4.3.6.tgz#c010c644575d1d2dd7c47953f6a1392fe17e38d9" + integrity sha512-jds0NdBDWM99FnO7WjODnRo+fnRoo11lJZlFS+cIa4ol7TMQmJ0HQdpno7R2LNfweoTioDMQd1LY1mCBq4zXnA== dependencies: "@ethereumjs/tx" "^4.2.0" "@metamask/eth-sig-util" "^7.0.3" - "@metamask/keyring-api" "^8.1.0" - "@metamask/snaps-controllers" "^9.6.0" - "@metamask/snaps-sdk" "^6.4.0" - "@metamask/snaps-utils" "^7.8.0" + "@metamask/snaps-controllers" "^9.7.0" + "@metamask/snaps-sdk" "^6.5.1" + "@metamask/snaps-utils" "^7.8.1" "@metamask/superstruct" "^3.1.0" - "@metamask/utils" "^9.1.0" - "@types/uuid" "^9.0.1" - deepmerge "^4.2.2" - uuid "^9.0.0" + "@metamask/utils" "^9.2.1" + "@types/uuid" "^9.0.8" + uuid "^9.0.1" "@metamask/etherscan-link@^2.0.0": version "2.1.0" @@ -4834,7 +4867,19 @@ "@noble/hashes" "^1.3.2" "@scure/base" "^1.0.0" -"@metamask/keyring-api@^8.1.0", "@metamask/keyring-api@^8.1.3": +"@metamask/keyring-api@^6.1.1": + version "6.4.0" + resolved "https://registry.yarnpkg.com/@metamask/keyring-api/-/keyring-api-6.4.0.tgz#8d8f0adfdddeac84ac55993c3ba424e2171d4bfe" + integrity sha512-JGkW7WCQ+M9lQXl5nAe49AaNmbK8HE6x/RupFL8Z5o8E4IVIeQbqEv+lW/Y5RBq0ekToHrxehlR/jDvL1iT8pg== + dependencies: + "@metamask/snaps-sdk" "^4.2.0" + "@metamask/utils" "^8.4.0" + "@types/uuid" "^9.0.8" + bech32 "^2.0.0" + superstruct "^1.0.3" + uuid "^9.0.1" + +"@metamask/keyring-api@^8.0.0", "@metamask/keyring-api@^8.1.0", "@metamask/keyring-api@^8.1.3": version "8.1.3" resolved "https://registry.yarnpkg.com/@metamask/keyring-api/-/keyring-api-8.1.3.tgz#53e6a68236b88592db5bd43cf7e0d7e97dfad818" integrity sha512-Ztm4G/U5hc+GKS/VOnqLWYVh2O26lFQ03bNpeufrfKq7regydIqYuHFcSowbQyj7xCZqKPsvl9jxhKdYIxvCXQ== @@ -4846,7 +4891,7 @@ bech32 "^2.0.0" uuid "^9.0.1" -"@metamask/keyring-controller@^17.0.0", "@metamask/keyring-controller@^17.2.1", "@metamask/keyring-controller@^17.2.2": +"@metamask/keyring-controller@^17.0.0", "@metamask/keyring-controller@^17.1.0", "@metamask/keyring-controller@^17.2.1", "@metamask/keyring-controller@^17.2.2": version "17.2.2" resolved "https://registry.yarnpkg.com/@metamask/keyring-controller/-/keyring-controller-17.2.2.tgz#944bc693305b4a6e4f1e73739a82c4bc6573dd9a" integrity sha512-Shqk0ybcTPrHQLlBJ1V+InuYC7nD3/a6Ws0XCcBCOfkLTXvtSooKIWBioK83XlHMHkfsM6+bySxSqXJVgJvBZw== @@ -5224,10 +5269,10 @@ readable-stream "^3.6.2" webextension-polyfill "^0.10.0" -"@metamask/providers@^17.1.2": - version "17.1.2" - resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-17.1.2.tgz#bb29c9cbf66be4c3f83d3e24ffea93f750b3db39" - integrity sha512-hACtF02yaUYThvWrRtVU4JAc+ZLCZ4PJUYBw6dK9Rze50J7zCxtss2mB7H8w76iLx//b5hjgXx6y92gPVjuYWg== +"@metamask/providers@^17.0.0", "@metamask/providers@^17.1.2": + version "17.2.1" + resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-17.2.1.tgz#e57105deddd0aab7c7a7efc44ce91f3bd9737906" + integrity sha512-xnF48ULB0uZ4mOPLMv5xzLWenMs1zbAUNP+wiBofetzIqnD/i6S8u9axIkAwEXBsb0JXtDI1lBPiTBJ5HUxRdw== dependencies: "@metamask/json-rpc-engine" "^9.0.1" "@metamask/json-rpc-middleware-stream" "^8.0.1" @@ -5366,10 +5411,10 @@ fast-json-patch "^3.1.0" lodash "^4.17.21" -"@metamask/snaps-controllers@^9.6.0", "@metamask/snaps-controllers@^9.8.0": - version "9.8.0" - resolved "https://registry.yarnpkg.com/@metamask/snaps-controllers/-/snaps-controllers-9.8.0.tgz#576de64fcaec7d393cc5c39f7d94dec068f3e2bf" - integrity sha512-Ey5bHhCsODF7NIkFvr3773ZYrxhbErLE1M12AUBIiLo7p5h/h8nWY+ilObQjTj3Au58oQ5QNYK1juvHMogFgdA== +"@metamask/snaps-controllers@^9.7.0", "@metamask/snaps-controllers@^9.8.0": + version "9.11.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-controllers/-/snaps-controllers-9.11.0.tgz#06cd0976994bfa12413c1326b60d50afe6a65640" + integrity sha512-4LrwAGnYVL125OqC7TRCFLdxtTfZLUbw/xyL0h/VWeT1+wt8uc6imN7gVyCudxM6GY2ujLaBcyp0NvmLEDDrfQ== dependencies: "@metamask/approval-controller" "^7.0.2" "@metamask/base-controller" "^6.0.2" @@ -5381,9 +5426,9 @@ "@metamask/post-message-stream" "^8.1.1" "@metamask/rpc-errors" "^6.3.1" "@metamask/snaps-registry" "^3.2.1" - "@metamask/snaps-rpc-methods" "^11.1.1" - "@metamask/snaps-sdk" "^6.5.1" - "@metamask/snaps-utils" "^8.1.1" + "@metamask/snaps-rpc-methods" "^11.4.0" + "@metamask/snaps-sdk" "^6.8.0" + "@metamask/snaps-utils" "^8.4.0" "@metamask/utils" "^9.2.1" "@xstate/fsm" "^2.0.0" browserify-zlib "^0.2.0" @@ -5423,34 +5468,20 @@ "@noble/curves" "^1.2.0" "@noble/hashes" "^1.3.2" -"@metamask/snaps-rpc-methods@^11.1.1": - version "11.1.1" - resolved "https://registry.yarnpkg.com/@metamask/snaps-rpc-methods/-/snaps-rpc-methods-11.1.1.tgz#d01a82cb1d8af60ade5f3d3da3adf8a275beda48" - integrity sha512-j4oJyMSBLTLg0RA28wgsCjdbC/YZUyRB/U6/tLCsaGXDKIPnOR17yjyeOx/IKLQR91ZC2+y4dMkgFbyOVSDI3Q== +"@metamask/snaps-rpc-methods@^11.1.1", "@metamask/snaps-rpc-methods@^11.4.0": + version "11.4.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-rpc-methods/-/snaps-rpc-methods-11.4.0.tgz#6cbf6cd6d91b65a5156882b4c10b1bdbc026e4cc" + integrity sha512-vFX4NFV1y7sj7uCDH6lJdDbRSLhELQdrv1FM0x/S8UptKYLGMhKafplhfx7KcQm0DBugSIXd42rmpgE8addunQ== dependencies: "@metamask/key-tree" "^9.1.2" "@metamask/permission-controller" "^11.0.0" "@metamask/rpc-errors" "^6.3.1" - "@metamask/snaps-sdk" "^6.5.0" - "@metamask/snaps-utils" "^8.1.1" + "@metamask/snaps-sdk" "^6.8.0" + "@metamask/snaps-utils" "^8.4.0" "@metamask/superstruct" "^3.1.0" "@metamask/utils" "^9.2.1" "@noble/hashes" "^1.3.1" -"@metamask/snaps-rpc-methods@^9.1.4": - version "9.1.4" - resolved "https://registry.yarnpkg.com/@metamask/snaps-rpc-methods/-/snaps-rpc-methods-9.1.4.tgz#d0aa695b89326eece7b23d188d8dce7d35a78d9c" - integrity sha512-eYcfJDYlXE4RqtRTyp8n7SsJ0aAQlz5H335/5jch3L3CwQwC3z8KlKm258iXPiyT7fa9VVxdZqGs/rBaivx0Iw== - dependencies: - "@metamask/key-tree" "^9.1.1" - "@metamask/permission-controller" "^10.0.0" - "@metamask/rpc-errors" "^6.2.1" - "@metamask/snaps-sdk" "^6.0.0" - "@metamask/snaps-utils" "^7.7.0" - "@metamask/utils" "^8.3.0" - "@noble/hashes" "^1.3.1" - superstruct "^1.0.3" - "@metamask/snaps-sdk@^3.1.1": version "3.2.0" resolved "https://registry.yarnpkg.com/@metamask/snaps-sdk/-/snaps-sdk-3.2.0.tgz#66d60869697a479a3484adc9532d82c3b568fc19" @@ -5463,10 +5494,22 @@ fast-xml-parser "^4.3.4" superstruct "^1.0.3" -"@metamask/snaps-sdk@^6.0.0", "@metamask/snaps-sdk@^6.1.0", "@metamask/snaps-sdk@^6.4.0", "@metamask/snaps-sdk@^6.5.0", "@metamask/snaps-sdk@^6.5.1": - version "6.5.1" - resolved "https://registry.yarnpkg.com/@metamask/snaps-sdk/-/snaps-sdk-6.5.1.tgz#527691767d98c08c802656b020d5d94d6336623e" - integrity sha512-uQEZZNjKwHZZfu9StwlmvTFle5MqiheO6AQctVhpYGJ1kjJ7Qwa+vJhMd0Ox1QI9C3qaUCqxOCDV0mpd1jPRKg== +"@metamask/snaps-sdk@^4.2.0": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@metamask/snaps-sdk/-/snaps-sdk-4.4.2.tgz#6d7654ca3ecbcda5cd8689f49721c084241a4495" + integrity sha512-V6d1kQdkCTYQ7Z3+ZVnMWjwsS2TRaKNnSRtSHgjATdSacW5d/1td2KbTs+1x1/cSe58ULKW1SBwRNy0i0c95hA== + dependencies: + "@metamask/key-tree" "^9.1.1" + "@metamask/providers" "^17.0.0" + "@metamask/rpc-errors" "^6.2.1" + "@metamask/utils" "^8.3.0" + fast-xml-parser "^4.3.4" + superstruct "^1.0.3" + +"@metamask/snaps-sdk@^6.1.0", "@metamask/snaps-sdk@^6.5.0", "@metamask/snaps-sdk@^6.5.1", "@metamask/snaps-sdk@^6.8.0": + version "6.9.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-sdk/-/snaps-sdk-6.9.0.tgz#409a36cdecf46da4825c437091c9d1541bea7bce" + integrity sha512-wPiZNvmkUXTGJ5yLIN9s+KZuB9zx4bz5LurUpufQ8geaMenQ2ZSyg8vqx7hj25q3yk3W2KncV3wnBmtixjucRA== dependencies: "@metamask/key-tree" "^9.1.2" "@metamask/providers" "^17.1.2" @@ -5474,7 +5517,7 @@ "@metamask/superstruct" "^3.1.0" "@metamask/utils" "^9.2.1" -"@metamask/snaps-utils@^7.7.0", "@metamask/snaps-utils@^7.8.0": +"@metamask/snaps-utils@^7.4.0", "@metamask/snaps-utils@^7.8.1": version "7.8.1" resolved "https://registry.yarnpkg.com/@metamask/snaps-utils/-/snaps-utils-7.8.1.tgz#d18f56ece8a1d4e9ff2e8e7645c3349cf08937bc" integrity sha512-v0xNoiWeJGHvtJqP0aU5dj+phqpV6vKCJoV5tNBXl8/AvMTaV2YL4SLO/z+PTo0RWZFplgAuuDsY254kAXi9Fw== @@ -5503,10 +5546,10 @@ ses "^1.1.0" validate-npm-package-name "^5.0.0" -"@metamask/snaps-utils@^8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@metamask/snaps-utils/-/snaps-utils-8.1.1.tgz#b32c403c0b5419dae3a22e4c6119099e9b3466ba" - integrity sha512-oKwm+0r2WIFinMo07RYAQVb2Khr/T+c8+V0m4iT9WfJHVNG8mHUMonH3ae2jksZ0/327na0mYVj804PLQ88SNA== +"@metamask/snaps-utils@^8.1.1", "@metamask/snaps-utils@^8.4.0": + version "8.4.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-utils/-/snaps-utils-8.4.0.tgz#aefedf45e6fe7b87a6b646193b7c0150caa5e51d" + integrity sha512-xxrAsxKf+l8Z3RP9oriNp6Jboh2tUB3mYZDw/kAvzBRX0tr28KgU/sKhRj4jF8GHEL7/jJmw9OIwOlhuXxD+Kg== dependencies: "@babel/core" "^7.23.2" "@babel/types" "^7.23.0" @@ -5516,7 +5559,7 @@ "@metamask/rpc-errors" "^6.3.1" "@metamask/slip44" "^4.0.0" "@metamask/snaps-registry" "^3.2.1" - "@metamask/snaps-sdk" "^6.5.0" + "@metamask/snaps-sdk" "^6.8.0" "@metamask/superstruct" "^3.1.0" "@metamask/utils" "^9.2.1" "@noble/hashes" "^1.3.1" @@ -5532,7 +5575,7 @@ ses "^1.1.0" validate-npm-package-name "^5.0.0" -"@metamask/superstruct@^3.1.0": +"@metamask/superstruct@^3.0.0", "@metamask/superstruct@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@metamask/superstruct/-/superstruct-3.1.0.tgz#148f786a674fba3ac885c1093ab718515bf7f648" integrity sha512-N08M56HdOgBfRKkrgCMZvQppkZGcArEop3kixNEtVbJKm6P9Cfg0YkI6X0s1g78sNrj2fWUwvJADdZuzJgFttA== @@ -5630,19 +5673,19 @@ semver "^7.3.8" superstruct "^1.0.3" -"@metamask/utils@^8.1.0", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0": - version "8.4.0" - resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.4.0.tgz#f44812c96467a4e1b70b2edff6ee89a9caa4e354" - integrity sha512-dbIc3C7alOe0agCuBHM1h71UaEaEqOk2W8rAtEn8QGz4haH2Qq7MoK6i7v2guzvkJVVh79c+QCzIqphC3KvrJg== +"@metamask/utils@^8.1.0", "@metamask/utils@^8.2.0", "@metamask/utils@^8.3.0", "@metamask/utils@^8.4.0": + version "8.5.0" + resolved "https://registry.yarnpkg.com/@metamask/utils/-/utils-8.5.0.tgz#ddd0d4012d5191809404c97648a837ea9962cceb" + integrity sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ== dependencies: "@ethereumjs/tx" "^4.2.0" + "@metamask/superstruct" "^3.0.0" "@noble/hashes" "^1.3.1" "@scure/base" "^1.1.3" "@types/debug" "^4.1.7" debug "^4.3.4" pony-cause "^2.1.10" semver "^7.5.4" - superstruct "^1.0.3" uuid "^9.0.1" "@metamask/utils@^9.0.0", "@metamask/utils@^9.1.0", "@metamask/utils@^9.2.1": @@ -10259,7 +10302,7 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.2.tgz#ede1d1b1e451548d44919dc226253e32a6952c4b" integrity sha512-kNnC1GFBLuhImSnV7w4njQkUiJi0ZXUycu1rUaouPqiKlXkh77JKgdRnTAp1x5eBwcIwbtI+3otwzuIDEuDoxQ== -"@types/uuid@^9.0.1", "@types/uuid@^9.0.8": +"@types/uuid@^9.0.8": version "9.0.8" resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==