From 60fc5862e0a3fcee0318736455d365534a6855f4 Mon Sep 17 00:00:00 2001 From: Aslau Mario-Daniel Date: Mon, 26 Feb 2024 16:41:44 -0600 Subject: [PATCH 01/10] fix: #1408 Native Alert Patch for Webview (#8515) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Currently on iOS when the user is promted with an alert to grant permissions for a website that has a big domain, it will hide the entire Alert message that the website is requesting. ## **Related issues** https://github.com/MetaMask/mobile-planning/issues/1408 Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **e2e Testing** https://app.bitrise.io/app/be69d4368ee7e86d/pipelines/abb68302-f423-4084-9cd5-3fef3a0a5c7c ## **Screenshots/Recordings** Before: This is the website we can use for debugging purposes: https://nfttoks.crypto.comsssssssss.go.f-secure.com.egghunter.in/camera.html After: Screenshot 2024-02-02 at 16 10 13 ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: Cal Leung --- patches/react-native-webview+11.13.0.patch | 74 ++++++++++++++++++---- 1 file changed, 63 insertions(+), 11 deletions(-) diff --git a/patches/react-native-webview+11.13.0.patch b/patches/react-native-webview+11.13.0.patch index 6168b3ed384..81140f13f02 100644 --- a/patches/react-native-webview+11.13.0.patch +++ b/patches/react-native-webview+11.13.0.patch @@ -1171,10 +1171,10 @@ index 0000000..b9581ac +} \ No newline at end of file diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m -index 28c078a..6f7d0b7 100644 +index 28c078a..9bb5368 100644 --- a/node_modules/react-native-webview/apple/RNCWebView.m +++ b/node_modules/react-native-webview/apple/RNCWebView.m -@@ -105,6 +105,7 @@ static NSDictionary* customCertificatesForHost; +@@ -105,6 +105,7 @@ @implementation RNCWebView UIStatusBarStyle _savedStatusBarStyle; #endif // !TARGET_OS_OSX BOOL _savedStatusBarHidden; @@ -1182,7 +1182,7 @@ index 28c078a..6f7d0b7 100644 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ UIScrollViewContentInsetAdjustmentBehavior _savedContentInsetAdjustmentBehavior; -@@ -139,6 +140,7 @@ static NSDictionary* customCertificatesForHost; +@@ -139,6 +140,7 @@ - (instancetype)initWithFrame:(CGRect)frame _injectedJavaScriptForMainFrameOnly = YES; _injectedJavaScriptBeforeContentLoaded = nil; _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = YES; @@ -1190,7 +1190,7 @@ index 28c078a..6f7d0b7 100644 #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; -@@ -417,6 +419,7 @@ static NSDictionary* customCertificatesForHost; +@@ -417,6 +419,7 @@ -(void)keyboardDisplacementFix - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) { if(_onLoadingProgress){ @@ -1198,7 +1198,7 @@ index 28c078a..6f7d0b7 100644 NSMutableDictionary *event = [self baseEvent]; [event addEntriesFromDictionary:@{@"progress":[NSNumber numberWithDouble:self.webView.estimatedProgress]}]; _onLoadingProgress(event); -@@ -492,6 +495,7 @@ static NSDictionary* customCertificatesForHost; +@@ -492,6 +495,7 @@ - (void)userContentController:(WKUserContentController *)userContentController NSMutableDictionary *event = [self baseEvent]; [event addEntriesFromDictionary: @{@"navigationType": message.body}]; _onLoadingFinish(event); @@ -1206,7 +1206,7 @@ index 28c078a..6f7d0b7 100644 } } else if ([message.name isEqualToString:MessageHandlerName]) { if (_onMessage) { -@@ -851,11 +855,13 @@ static NSDictionary* customCertificatesForHost; +@@ -851,11 +855,13 @@ - (void) webView:(WKWebView *)webView - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler { #if !TARGET_OS_OSX @@ -1225,7 +1225,59 @@ index 28c078a..6f7d0b7 100644 #else NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:message]; -@@ -894,44 +900,49 @@ static NSDictionary* customCertificatesForHost; +@@ -868,6 +874,51 @@ - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSStrin + /** + * confirm + */ ++// This patch made to overridde the restrictions that webView is imposing to the native Alert, by restricting its size. ++- (void)webView:(WKWebView *)webView requestMediaCapturePermissionForOrigin:(WKSecurityOrigin *)origin initiatedByFrame:(WKFrameInfo *)frame type:(WKMediaCaptureType)type decisionHandler:(void (^)(WKPermissionDecision decision))decisionHandler API_AVAILABLE(ios(15.0)){ ++ ++ NSString *deviceType; ++ ++ switch (type) { ++ case WKMediaCaptureTypeCamera: ++ deviceType = @"camera"; ++ break; ++ case WKMediaCaptureTypeMicrophone: ++ deviceType = @"microphone"; ++ break; ++ case WKMediaCaptureTypeCameraAndMicrophone: ++ deviceType = @"camera and microphone"; ++ break; ++ default: ++ deviceType = @"unknown device"; ++ } ++ ++ NSString *message = [NSString stringWithFormat:@"The webpage %@ is requesting access to your %@. Do you want to allow this?", origin.host, deviceType]; ++ ++ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"Permission Request" ++ message:message ++ preferredStyle:UIAlertControllerStyleAlert]; ++ ++ UIAlertAction *allowAction = [UIAlertAction actionWithTitle:@"Allow" ++ style:UIAlertActionStyleDefault ++ handler:^(UIAlertAction * _Nonnull action) { ++ decisionHandler(WKPermissionDecisionGrant); ++ } ++ ]; ++ ++ UIAlertAction *denyAction = [UIAlertAction actionWithTitle:@"Deny" ++ style:UIAlertActionStyleCancel ++ handler:^(UIAlertAction * _Nonnull action) { ++ decisionHandler(WKPermissionDecisionDeny); ++ } ++ ]; ++ ++ [alertController addAction:allowAction]; ++ [alertController addAction:denyAction]; ++ ++ [[self topViewController] presentViewController:alertController animated:YES completion:NULL]; ++} ++ + - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(BOOL))completionHandler{ + #if !TARGET_OS_OSX + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; +@@ -894,44 +945,49 @@ - (void)webView:(WKWebView *)webView runJavaScriptConfirmPanelWithMessage:(NSStr * prompt */ - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler{ @@ -1247,7 +1299,7 @@ index 28c078a..6f7d0b7 100644 -#else - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:prompt]; - +- - const NSRect RCTSingleTextFieldFrame = NSMakeRect(0.0, 0.0, 275.0, 22.0); - NSTextField *textField = [[NSTextField alloc] initWithFrame:RCTSingleTextFieldFrame]; - textField.cell.scrollable = YES; @@ -1256,7 +1308,7 @@ index 28c078a..6f7d0b7 100644 - } - textField.stringValue = defaultText; - [alert setAccessoryView:textField]; -- + - [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")]; - [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")]; - [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSModalResponse response) { @@ -1310,7 +1362,7 @@ index 28c078a..6f7d0b7 100644 } #if !TARGET_OS_OSX -@@ -1157,6 +1168,7 @@ static NSDictionary* customCertificatesForHost; +@@ -1157,6 +1213,7 @@ - (void)webView:(WKWebView *)webView } if (_onLoadingFinish) { @@ -1318,7 +1370,7 @@ index 28c078a..6f7d0b7 100644 _onLoadingFinish([self baseEvent]); } } -@@ -1446,3 +1458,4 @@ static NSDictionary* customCertificatesForHost; +@@ -1446,3 +1503,4 @@ - (void)userContentController:(WKUserContentController *)userContentController d } @end From e9a1442d361f94612898c6b2c5ece8e27afc46ad Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Tue, 27 Feb 2024 00:21:43 +0000 Subject: [PATCH 02/10] feat: bump mobile snaps packages to bring new snaps architecture (#8607) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR bumps snaps packages alongside others in order to allow snaps new architecture and refactored code from snaps codebase be used into mobile as an external dependency. The current PR builds the bases to the [8369](https://github.com/MetaMask/metamask-mobile/pull/8369). **Any failing tests related to snaps can be safely ignored** since the snaps "consumer" code is/will be handled/refactored on the PR above. ## **Related issues** Fixes: N/A ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [x] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: Owen Craston --- app/core/Engine.ts | 140 +++++-- app/core/Permissions/specifications.js | 6 +- app/core/Permissions/specifications.test.js | 2 +- app/util/test/initial-background-state.json | 3 +- package.json | 13 +- patches/@metamask+base-controller+4.1.1.patch | 13 + .../@metamask+post-message-stream+8.0.0.patch | 30 ++ yarn.lock | 358 +++++++++--------- 8 files changed, 344 insertions(+), 221 deletions(-) create mode 100644 patches/@metamask+base-controller+4.1.1.patch create mode 100644 patches/@metamask+post-message-stream+8.0.0.patch diff --git a/app/core/Engine.ts b/app/core/Engine.ts index 792a6ea3d58..4232f167565 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine.ts @@ -104,12 +104,15 @@ import { SnapsRegistryState, SnapControllerEvents, SnapControllerActions, - buildSnapEndowmentSpecifications, - buildSnapRestrictedMethodSpecifications, PersistedSnapControllerState, } from '@metamask/snaps-controllers'; -import { EnumToUnion, Snap } from '@metamask/snaps-utils'; -import { DialogType, NotificationArgs } from '@metamask/snaps-rpc-methods'; +import { Snap } from '@metamask/snaps-utils'; +import { NotificationArgs } from '@metamask/snaps-rpc-methods/dist/types/restricted/notify'; +import { + buildSnapEndowmentSpecifications, + buildSnapRestrictedMethodSpecifications, +} from '@metamask/snaps-rpc-methods'; +import { EnumToUnion, DialogType } from '@metamask/snaps-sdk'; // eslint-disable-next-line import/no-nodejs-modules import { Duplex } from 'stream'; ///: END:ONLY_INCLUDE_IF @@ -133,6 +136,7 @@ import { balanceToFiatNumber, weiToFiatNumber, toHexadecimal, + addHexPrefix, } from '../util/number'; import NotificationManager from './NotificationManager'; import Logger from '../util/Logger'; @@ -342,7 +346,12 @@ class Engine { this.controllerMessenger = new ControllerMessenger(); const approvalController = new ApprovalController({ - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'ApprovalController', + never, + never + >({ name: 'ApprovalController', }), showApprovalRequest: () => undefined, @@ -372,7 +381,12 @@ class Engine { const networkControllerOpts = { infuraProjectId: process.env.MM_INFURA_PROJECT_ID || NON_EMPTY, state: initialState.NetworkController, - messenger: this.controllerMessenger.getRestricted({ + messenger: this.controllerMessenger.getRestricted< + 'NetworkController', + never, + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + 'NetworkController:networkDidChange' + >({ name: 'NetworkController', allowedEvents: ['NetworkController:networkDidChange'], allowedActions: [], @@ -383,6 +397,7 @@ class Engine { // noop }, }; + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers const networkController = new NetworkController(networkControllerOpts); networkController.initializeProvider(); @@ -407,7 +422,12 @@ class Engine { AppConstants.NETWORK_STATE_CHANGE_EVENT, listener, ), - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'NftController', + 'ApprovalController:addRequest', + never + >({ name: 'NftController', allowedActions: [`${approvalController.name}:addRequest`], }), @@ -434,7 +454,6 @@ class Engine { ), }, { - // @ts-expect-error NftController constructor config type is wrong useIPFSSubdomains: false, chainId: networkController.state.providerConfig.chainId, }, @@ -452,7 +471,12 @@ class Engine { provider: networkController.getProviderAndBlockTracker().provider, chainId: networkController.state.providerConfig.chainId, }, - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'TokensController', + 'ApprovalController:addRequest', + never + >({ name: 'TokensController', allowedActions: [`${approvalController.name}:addRequest`], }), @@ -468,13 +492,23 @@ class Engine { AppConstants.NETWORK_STATE_CHANGE_EVENT, listener, ), - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'TokenListController', + never, + 'NetworkController:stateChange' + >({ name: 'TokenListController', allowedEvents: ['NetworkController:stateChange'], }), }); const currencyRateController = new CurrencyRateController({ - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'CurrencyRateController', + never, + never + >({ name: 'CurrencyRateController', }), state: initialState.CurrencyRateController, @@ -482,7 +516,12 @@ class Engine { currencyRateController.start(); const gasFeeController = new GasFeeController({ - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'GasFeeController', + never, + 'NetworkController:stateChange' + >({ name: 'GasFeeController', allowedEvents: ['NetworkController:stateChange'], }), @@ -501,8 +540,8 @@ class Engine { const chainId = networkController.state.providerConfig.chainId; return ( isMainnetByChainId(chainId) || - chainId === swapsUtils.BSC_CHAIN_ID || - chainId === swapsUtils.POLYGON_CHAIN_ID + chainId === addHexPrefix(swapsUtils.BSC_CHAIN_ID) || + chainId === addHexPrefix(swapsUtils.POLYGON_CHAIN_ID) ); }, clientId: AppConstants.SWAPS.CLIENT_ID, @@ -547,15 +586,13 @@ class Engine { preferencesController, ), encryptor, - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'KeyringController', + never, + never + >({ name: 'KeyringController', - allowedEvents: [ - 'KeyringController:lock', - 'KeyringController:unlock', - 'KeyringController:stateChange', - 'KeyringController:accountRemoved', - ], - allowedActions: ['KeyringController:getState'], }), state: initialKeyringState || initialState.KeyringController, // @ts-expect-error To Do: Update the type of QRHardwareKeyring to Keyring @@ -619,14 +656,20 @@ class Engine { this.controllerMessenger, 'SnapController:updateSnapState', ), + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore maybeUpdatePhishingList: this.controllerMessenger.call.bind( this.controllerMessenger, 'PhishingController:maybeUpdateState', ), isOnPhishingList: (origin: string) => - this.controllerMessenger.call( + this.controllerMessenger.call<'PhishingController:testOrigin'>( 'PhishingController:testOrigin', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore origin, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore ).result, showDialog: ( origin: string, @@ -653,6 +696,8 @@ class Engine { ///: END:ONLY_INCLUDE_IF const permissionController = new PermissionController({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers messenger: this.controllerMessenger.getRestricted({ name: 'PermissionController', allowedActions: [ @@ -669,7 +714,8 @@ class Engine { }), state: initialState.PermissionController, caveatSpecifications: getCaveatSpecifications({ getIdentities }), - // @ts-expect-error Inferred permission specification type is incorrect, fix after migrating to TypeScript + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore permissionSpecifications: { ...getPermissionSpecifications({ getAllAccounts: () => keyringController.getAccounts(), @@ -683,7 +729,13 @@ class Engine { ///: BEGIN:ONLY_INCLUDE_IF(snaps) const subjectMetadataController = new SubjectMetadataController({ - messenger: this.controllerMessenger.getRestricted({ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'SubjectMetadataController', + 'PermissionController:hasPermissions', + never + >({ name: 'SubjectMetadataController', allowedActions: [`${permissionController.name}:hasPermissions`], }), @@ -762,8 +814,6 @@ class Engine { 'ExecutionService:unhandledError', 'ExecutionService:outboundRequest', 'ExecutionService:outboundResponse', - 'SnapController:snapInstalled', - 'SnapController:snapUpdated', ], allowedActions: [ `${approvalController.name}:addRequest`, @@ -790,6 +840,10 @@ class Engine { 'ExecutionService:terminateSnap', 'ExecutionService:terminateAllSnaps', 'ExecutionService:handleRpcRequest', + 'SnapsRegistry:get', + 'SnapsRegistry:getMetadata', + 'SnapsRegistry:update', + 'SnapsRegistry:resolveVersion', ], }); @@ -814,7 +868,9 @@ class Engine { }); this.controllerMessenger.subscribe( - 'SnapController:snapAdded', + 'SnapController:snapInstalled', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore (snap: Snap, svgIcon: any = null) => { const { manifest: { proposedName }, @@ -950,7 +1006,12 @@ class Engine { }, updateTransactions: true, }, - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'TransactionController', + 'ApprovalController:addRequest', + never + >({ name: 'TransactionController', allowedActions: [`${approvalController.name}:addRequest`], }), @@ -993,7 +1054,12 @@ class Engine { approvalController, permissionController, new SignatureController({ - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'SignatureController', + 'ApprovalController:addRequest', + never + >({ name: 'SignatureController', allowedActions: [`${approvalController.name}:addRequest`], }), @@ -1024,7 +1090,12 @@ class Engine { }, }), new LoggingController({ - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'LoggingController', + never, + never + >({ name: 'LoggingController', }), state: initialState.LoggingController, @@ -1041,7 +1112,12 @@ class Engine { chainId: networkController.state.providerConfig.chainId, blockaidPublicKey: process.env.BLOCKAID_PUBLIC_KEY as string, cdnBaseUrl: process.env.BLOCKAID_FILE_CDN as string, - messenger: this.controllerMessenger.getRestricted({ + // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + messenger: this.controllerMessenger.getRestricted< + 'PPOMController', + never, + 'NetworkController:stateChange' + >({ name: 'PPOMController', allowedEvents: ['NetworkController:stateChange'], }), diff --git a/app/core/Permissions/specifications.js b/app/core/Permissions/specifications.js index c525c3a4a7a..d4443768c27 100644 --- a/app/core/Permissions/specifications.js +++ b/app/core/Permissions/specifications.js @@ -1,6 +1,8 @@ ///: BEGIN:ONLY_INCLUDE_IF(snaps) -import { endowmentCaveatSpecifications as snapsEndowmentCaveatSpecifications } from '@metamask/snaps-controllers'; -import { caveatSpecifications as snapsCaveatsSpecifications } from '@metamask/snaps-rpc-methods'; +import { + caveatSpecifications as snapsCaveatsSpecifications, + endowmentCaveatSpecifications as snapsEndowmentCaveatSpecifications, +} from '@metamask/snaps-rpc-methods'; ///: END:ONLY_INCLUDE_IF import { constructPermission, diff --git a/app/core/Permissions/specifications.test.js b/app/core/Permissions/specifications.test.js index 60bfb34ec51..b10f2f778f5 100644 --- a/app/core/Permissions/specifications.test.js +++ b/app/core/Permissions/specifications.test.js @@ -9,7 +9,7 @@ describe('PermissionController specifications', () => { describe('caveat specifications', () => { it('getCaveatSpecifications returns the expected specifications object', () => { const caveatSpecifications = getCaveatSpecifications({}); - expect(Object.keys(caveatSpecifications)).toHaveLength(9); + expect(Object.keys(caveatSpecifications)).toHaveLength(12); expect( caveatSpecifications[CaveatTypes.restrictReturnedAccounts].type, ).toStrictEqual(CaveatTypes.restrictReturnedAccounts); diff --git a/app/util/test/initial-background-state.json b/app/util/test/initial-background-state.json index bd624b0b052..3411e941c18 100644 --- a/app/util/test/initial-background-state.json +++ b/app/util/test/initial-background-state.json @@ -144,7 +144,8 @@ }, "SnapController": { "snapStates": {}, - "snaps": {} + "snaps": {}, + "unencryptedSnapStates": {} }, "SubjectMetadataController": { "subjectMetadata": {} diff --git a/package.json b/package.json index 40fa6ba4bcf..26370191ac1 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "@ledgerhq/react-native-hw-transport-ble": "^6.29.5", "@metamask/address-book-controller": "^3.0.0", "@metamask/approval-controller": "^3.4.0", + "@metamask/base-controller": "^4.1.1", "@metamask/assets-controllers": "^9.0.0", - "@metamask/base-controller": "^3.0.0", "@metamask/composable-controller": "^3.0.0", "@metamask/contract-metadata": "^2.1.0", "@metamask/controller-utils": "^4.0.0", @@ -190,7 +190,7 @@ "@metamask/network-controller": "^10.0.0", "@metamask/permission-controller": "^4.0.1", "@metamask/phishing-controller": "^5.0.0", - "@metamask/post-message-stream": "7.0.0", + "@metamask/post-message-stream": "8.0.0", "@metamask/ppom-validator": "0.24.0", "@metamask/preferences-controller": "^4.0.0", "@metamask/react-native-button": "^3.0.0", @@ -198,9 +198,10 @@ "@metamask/sdk-communication-layer": "^0.12.0", "@metamask/signature-controller": "5.3.0", "@metamask/slip44": "3.1.0", - "@metamask/snaps-controllers": "^3.2.0", - "@metamask/snaps-rpc-methods": "^3.2.1", - "@metamask/snaps-utils": "^3.2.0", + "@metamask/snaps-controllers": "^5.0.0", + "@metamask/snaps-rpc-methods": "^6.0.0", + "@metamask/snaps-sdk": "^2.0.0", + "@metamask/snaps-utils": "^6.0.0", "@metamask/swappable-obj-proxy": "^2.1.0", "@metamask/swaps-controller": "^6.9.3", "@metamask/transaction-controller": "^6.1.0", @@ -292,8 +293,8 @@ "react-native-animatable": "^1.3.3", "react-native-animated-fox": "git+https://github.com/MetaMask/react-native-animated-fox.git#16e38d54d829709e497f196e31fa8ff00cdf2aa9", "react-native-background-timer": "2.1.1", - "react-native-blob-jsi-helper": "^0.3.1", "react-native-ble-plx": "3.1.1", + "react-native-blob-jsi-helper": "^0.3.1", "react-native-branch": "^5.6.2", "react-native-browser-polyfill": "0.1.2", "react-native-camera": "^3.36.0", diff --git a/patches/@metamask+base-controller+4.1.1.patch b/patches/@metamask+base-controller+4.1.1.patch new file mode 100644 index 00000000000..72680b2b9b6 --- /dev/null +++ b/patches/@metamask+base-controller+4.1.1.patch @@ -0,0 +1,13 @@ +diff --git a/node_modules/@metamask/base-controller/dist/RestrictedControllerMessenger.d.ts b/node_modules/@metamask/base-controller/dist/RestrictedControllerMessenger.d.ts +index 423c1a9..5c62cb3 100644 +--- a/node_modules/@metamask/base-controller/dist/RestrictedControllerMessenger.d.ts ++++ b/node_modules/@metamask/base-controller/dist/RestrictedControllerMessenger.d.ts +@@ -15,7 +15,7 @@ import type { ActionConstraint, ActionHandler, ControllerMessenger, EventConstra + * @template AllowedEvent - A type union of the 'type' string for any allowed events. + * This must not include internal events that are in the messenger's namespace. + */ +-export declare class RestrictedControllerMessenger { ++export declare class RestrictedControllerMessenger { + #private; + /** + * Constructs a restricted controller messenger diff --git a/patches/@metamask+post-message-stream+8.0.0.patch b/patches/@metamask+post-message-stream+8.0.0.patch new file mode 100644 index 00000000000..22d35a8aee5 --- /dev/null +++ b/patches/@metamask+post-message-stream+8.0.0.patch @@ -0,0 +1,30 @@ +diff --git a/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js b/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js +index cead325..a319ed7 100644 +--- a/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js ++++ b/node_modules/@metamask/post-message-stream/dist/window/WindowPostMessageStream.js +@@ -6,11 +6,21 @@ const utils_1 = require("@metamask/utils"); + const BasePostMessageStream_1 = require("../BasePostMessageStream"); + const utils_2 = require("../utils"); + /* istanbul ignore next */ +-const getSource = (_a = Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'source')) === null || _a === void 0 ? void 0 : _a.get; +-(0, utils_1.assert)(getSource, 'MessageEvent.prototype.source getter is not defined.'); ++/** +++ * ============================== PATCH INFORMATION ============================== +++ * This patch was added for snaps controller integration. The MessageEvent is not +++ * available in react native so we can simply return undefined here and handle the +++ * origin and source elsewhere. +++ * =============================================================================== +++ */ ++/** ++// const getSource = (_a = Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'source')) === null || _a === void 0 ? void 0 : _a.get; ++// (0, utils_1.assert)(getSource, 'MessageEvent.prototype.source getter is not defined.'); ++const getSource = () => undefined; + /* istanbul ignore next */ +-const getOrigin = (_b = Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'origin')) === null || _b === void 0 ? void 0 : _b.get; +-(0, utils_1.assert)(getOrigin, 'MessageEvent.prototype.origin getter is not defined.'); ++// const getOrigin = (_b = Object.getOwnPropertyDescriptor(MessageEvent.prototype, 'origin')) === null || _b === void 0 ? void 0 : _b.get; ++// (0, utils_1.assert)(getOrigin, 'MessageEvent.prototype.origin getter is not defined.'); ++const getOrigin = () => undefined; + /** + * A {@link Window.postMessage} stream. + */ diff --git a/yarn.lock b/yarn.lock index e56d18fe537..0eebb95a378 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1648,10 +1648,10 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@endo/env-options@^0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@endo/env-options/-/env-options-0.1.4.tgz#e516bc3864f00b154944e444fb8996a9a0c23a45" - integrity sha512-Ol8ct0aW8VK1ZaqntnUJfrYT59P6Xn36XPbHzkqQhsYkpudKDn5ILYEwGmSO/Ff+XJjv/pReNI0lhOyyrDa9mg== +"@endo/env-options@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@endo/env-options/-/env-options-1.1.1.tgz#eee630f8eff01580ec49e0dedcb1b6cef05d89a4" + integrity sha512-uCwlJ8Vkndx/VBBo36BdYHdxSoQPy7ZZpwyJNfv86Rh4B1IZfqzCRPf0u0mPgJdzOr7lShQey60SuYwoMSZ9Xg== "@es-joy/jsdoccomment@~0.36.1": version "0.36.1" @@ -3593,7 +3593,7 @@ "@metamask/controller-utils" "^6.0.0" "@metamask/utils" "^8.2.0" -"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^3.3.0", "@metamask/approval-controller@^3.4.0", "@metamask/approval-controller@^3.5.0", "@metamask/approval-controller@^3.5.2", "@metamask/approval-controller@^4.0.0": +"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^3.3.0", "@metamask/approval-controller@^3.4.0", "@metamask/approval-controller@^3.5.0", "@metamask/approval-controller@^3.5.2", "@metamask/approval-controller@^5.1.2": version "3.4.0" resolved "https://registry.yarnpkg.com/@metamask/approval-controller/-/approval-controller-3.4.0.tgz#282900361d42f785578728b45014ff8cb5e557ea" integrity sha512-DjqrhiX9+W/Fh6Crr7FPJ87Y/uhPWzBvfXGtekv1LHZNmEtUxkrA7aelddUM0fpTdURIGT4aNGBoQudFidc+Lw== @@ -3642,7 +3642,7 @@ "@metamask/utils" "^8.1.0" immer "^9.0.6" -"@metamask/base-controller@^4.0.0", "@metamask/base-controller@^4.1.1": +"@metamask/base-controller@^4.0.0", "@metamask/base-controller@^4.1.0", "@metamask/base-controller@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-4.1.1.tgz#9b411adf4822de7382fe69d07bb6b3fc3e738923" integrity sha512-sJdsd/XlyOa0kRJ16qbM+xeQ8peV1yZcYumJmHCClPK09MkAlxq7EzsrahVZXUCFwcxtSucf244pbttnVqNthw== @@ -3718,12 +3718,12 @@ fast-deep-equal "^3.1.3" "@metamask/controller-utils@^8.0.1", "@metamask/controller-utils@^8.0.2": - version "8.0.2" - resolved "https://registry.yarnpkg.com/@metamask/controller-utils/-/controller-utils-8.0.2.tgz#8e920cc6bf32cf4c918aa0ca1f6e3e56c7b79ea4" - integrity sha512-47ak3UpwlOH0cYN3x3noXXO9sQyES7U5MmyMMRY8vQwagRlaVGHWTOuLwwyVtIt09TnKqkJFfwzIWuVK6D/lxw== + version "8.0.3" + resolved "https://registry.yarnpkg.com/@metamask/controller-utils/-/controller-utils-8.0.3.tgz#b27e4ba5f579ab59bf49174aae652fec41652337" + integrity sha512-a1rxrBcu4rSqeSuH3vUIYA7fK8ZLnogxMOTk19Q86fOhuYN/p2CDwgxdr3RrZtDgyVEe5RJ38TSXiPI8Nh5g6A== dependencies: "@metamask/eth-query" "^4.0.0" - "@metamask/ethjs-unit" "^0.2.1" + "@metamask/ethjs-unit" "^0.3.0" "@metamask/utils" "^8.3.0" "@spruceid/siwe-parser" "1.1.3" eth-ens-namehash "^2.0.8" @@ -3965,6 +3965,14 @@ bn.js "4.11.6" number-to-bn "1.7.0" +"@metamask/ethjs-unit@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@metamask/ethjs-unit/-/ethjs-unit-0.3.0.tgz#d44d21d3b4ad443fb0cdd0362ea07c6f51e68ec4" + integrity sha512-HZtg69ODXYS9+ovKUYofZuIAwq4fc2/MGazD4vBQRKWMhPu4ySdmgR0EuzbxEK4uhr18KA4pbL+mCYjyjGxY7w== + dependencies: + "@metamask/number-to-bn" "^1.7.1" + bn.js "^5.2.1" + "@metamask/gas-fee-controller@6.0.0": version "6.0.0" resolved "https://registry.yarnpkg.com/@metamask/gas-fee-controller/-/gas-fee-controller-6.0.0.tgz#a0fc8233284708cd7924517ca7b4a7624dfe5c42" @@ -3982,14 +3990,14 @@ immer "^9.0.6" uuid "^8.3.2" -"@metamask/json-rpc-engine@^7.0.0", "@metamask/json-rpc-engine@^7.1.1", "@metamask/json-rpc-engine@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.0.tgz#eec5505f0ea41bd46c785c8722c5a10a3afd9850" - integrity sha512-93cOdqnpt0P9uU/aC65GZulaDh6qNFEm8IFXHbI4lisK7oebU2SLarJUBZPebjko7hzwmfV1M1h7FQAlyRkVLg== +"@metamask/json-rpc-engine@^7.0.0", "@metamask/json-rpc-engine@^7.1.1", "@metamask/json-rpc-engine@^7.3.0", "@metamask/json-rpc-engine@^7.3.2": + version "7.3.2" + resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.2.tgz#e8f0695811619eef7b7c894ba5cf782db9f1c2cb" + integrity sha512-dVjBPlni4CoiBpESVqrxh6k4OR14w6GRXKSSXHFuITjuhALE42gNCkXTpL4cjNeOBUgTba3eGe5EI8cyc2QLRg== dependencies: "@metamask/rpc-errors" "^6.1.0" "@metamask/safe-event-emitter" "^3.0.0" - "@metamask/utils" "^8.2.0" + "@metamask/utils" "^8.3.0" "@metamask/key-tree@^9.0.0": version "9.0.0" @@ -4114,7 +4122,15 @@ json-rpc-engine "^6.1.0" uuid "^8.3.2" -"@metamask/object-multiplex@^1.1.0", "@metamask/object-multiplex@^1.2.0": +"@metamask/number-to-bn@^1.7.1": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@metamask/number-to-bn/-/number-to-bn-1.7.1.tgz#a449ec8b2edba211e0dc3e1e0428ff2cc2bf7ab4" + integrity sha512-qCN+Au4amvcVii2LdOJNndYhdmk5Lk9tlStJhKpZ8tGeYQDJTghqYXJuSUVPHvfl6FUfKY1i1Or2j2EbnEerSQ== + dependencies: + bn.js "5.2.1" + strip-hex-prefix "1.0.0" + +"@metamask/object-multiplex@^1.1.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz#38fc15c142f61939391e1b9a8eed679696c7e4f4" integrity sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ== @@ -4123,6 +4139,14 @@ once "^1.4.0" readable-stream "^2.3.3" +"@metamask/object-multiplex@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-2.0.0.tgz#aa6e4aa7b4e2f457ea4bb51cd7281d931e0aa35d" + integrity sha512-+ItrieVZie3j2LfYE0QkdW3dsEMfMEp419IGx1zyeLqjRZ14iQUPRO0H6CGgfAAoC0x6k2PfCAGRwJUA9BMrqA== + dependencies: + once "^1.4.0" + readable-stream "^3.6.2" + "@metamask/obs-store@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@metamask/obs-store/-/obs-store-7.0.0.tgz#6cae5f28306bb3e83a381bc9ae22682316095bd3" @@ -4165,17 +4189,16 @@ json-rpc-engine "^6.1.0" nanoid "^3.1.31" -"@metamask/permission-controller@^5.0.0": - version "5.0.0" - resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-5.0.0.tgz#d7f8d70085f43ac676a458cec6a7eaa95814ade7" - integrity sha512-l9+oPn09qoAFdwrI2nlbgLmXI9HDXLR4ef+kLXhIYff4ISTqxxD160vueH8Ip6woBgQ8Qa0q3sdERAN7nd4FfA== +"@metamask/permission-controller@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-8.0.0.tgz#2f358e9793cab5f047cb536906b6b0a71c93d107" + integrity sha512-VwrkxKnvUSrpQeqljC/okrJG47tuLKkNrfmaj1SJ9S6/TUQjeRpsE0abKRt6pprTCbDpzJdyspexZq2aWykGLQ== dependencies: - "@metamask/approval-controller" "^4.0.0" - "@metamask/base-controller" "^3.2.3" - "@metamask/controller-utils" "^5.0.2" - "@metamask/json-rpc-engine" "^7.1.1" - "@metamask/rpc-errors" "^6.0.0" - "@metamask/utils" "^8.1.0" + "@metamask/base-controller" "^4.1.1" + "@metamask/controller-utils" "^8.0.2" + "@metamask/json-rpc-engine" "^7.3.2" + "@metamask/rpc-errors" "^6.1.0" + "@metamask/utils" "^8.3.0" "@types/deep-freeze-strict" "^1.1.0" deep-freeze-strict "^1.1.1" immer "^9.0.6" @@ -4192,23 +4215,23 @@ eth-phishing-detect "^1.2.0" punycode "^2.1.1" -"@metamask/phishing-controller@^7.0.0": - version "7.0.1" - resolved "https://registry.yarnpkg.com/@metamask/phishing-controller/-/phishing-controller-7.0.1.tgz#1544aef4d86a684bf171c76e3b1bfe13b2350b44" - integrity sha512-ONHE8EQsd2zehaOJN9UoVaZ4tMAGeOdCQkngUtcY+kO5W8gzaOS2W3EhthJ2TAS19WoJWS47004gFLtnerLmiQ== +"@metamask/phishing-controller@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@metamask/phishing-controller/-/phishing-controller-8.0.2.tgz#612d2d2d0d5e8746289fda036b0382a63ea82ffb" + integrity sha512-aRnpv+AtjqffT7hnwF1XZahWs8K99dOd8DcAAaVJyWsdt0cT3o6ryZXHMcFTUGP8Fl88LmkLm1970zfUO8AxFg== dependencies: - "@metamask/base-controller" "^3.2.3" - "@metamask/controller-utils" "^5.0.2" + "@metamask/base-controller" "^4.1.1" + "@metamask/controller-utils" "^8.0.2" "@types/punycode" "^2.1.0" eth-phishing-detect "^1.2.0" punycode "^2.1.1" -"@metamask/post-message-stream@7.0.0", "@metamask/post-message-stream@^7.0.0": - version "7.0.0" - resolved "https://registry.yarnpkg.com/@metamask/post-message-stream/-/post-message-stream-7.0.0.tgz#b7698909ec54923b6a6990b8d46cc15c2810d840" - integrity sha512-+dTUNtuNY9o4ooPiXEOqSkqQWQ9APkVx3dAkBvAsJLetAGXvmoBeIMN1DL2QU+9BTbQ9JyJ6NycQnhvwRRc1HQ== +"@metamask/post-message-stream@8.0.0", "@metamask/post-message-stream@^8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@metamask/post-message-stream/-/post-message-stream-8.0.0.tgz#101a54c2a4029879691ce83065638493d7822f48" + integrity sha512-Bk5LQRxD2IJMJWKY8Yuy+86gracExv2jpjHVWm5Ek7njtdzS0Z10ABpC+yekc8vsRaJ6+xgr64wLHWbYNUqEyg== dependencies: - "@metamask/utils" "^5.0.0" + "@metamask/utils" "^8.1.0" readable-stream "3.6.2" "@metamask/ppom-validator@0.24.0": @@ -4250,6 +4273,24 @@ json-rpc-middleware-stream "^4.2.1" webextension-polyfill "^0.10.0" +"@metamask/providers@^14.0.2": + version "14.0.2" + resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-14.0.2.tgz#683c43ed1f58075b8238b85e7c585ecefe484f0b" + integrity sha512-6KuCLQVzE/8IA1r8LkTo0FbG4fgm7ryjzleda0lMsz5XMxinNGuXAoh7Y08bX5OHVpDEjkHREPhuLw4dFK9wIQ== + dependencies: + "@metamask/json-rpc-engine" "^7.1.1" + "@metamask/object-multiplex" "^2.0.0" + "@metamask/rpc-errors" "^6.0.0" + "@metamask/safe-event-emitter" "^3.0.0" + "@metamask/utils" "^8.1.0" + detect-browser "^5.2.0" + extension-port-stream "^3.0.0" + fast-deep-equal "^3.1.3" + is-stream "^2.0.0" + json-rpc-middleware-stream "^5.0.1" + readable-stream "^3.6.2" + webextension-polyfill "^0.10.0" + "@metamask/react-native-button@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@metamask/react-native-button/-/react-native-button-3.0.0.tgz#4af8affd11e2b285cfc1b1752280797e1b33e62b" @@ -4318,85 +4359,91 @@ immer "^9.0.6" lodash "^4.17.21" -"@metamask/slip44@3.1.0": +"@metamask/slip44@3.1.0", "@metamask/slip44@^3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@metamask/slip44/-/slip44-3.1.0.tgz#f8067796f89fbbd6eaa594660bd6a1fbd6837a51" integrity sha512-bFlJ8jhTYJ4iQ0zgh2WMO2615UJ4Ne5J831EjsqKYaZs3qd6UTw/cy76hAmSxhnBluNAH5S6zZzxESLrTitCmQ== -"@metamask/snaps-controllers@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@metamask/snaps-controllers/-/snaps-controllers-3.2.0.tgz#33924bda4e7c5395e6a573d306b786c99161f6e1" - integrity sha512-TGxqzsZ3rkzJjxaFHS1ntqaDHCBSVoTUYWRxjkKzFCcMcbX2Quzm9Coong1QlQ7fQjhcCCy4NsHEZPCl8tBB7g== - dependencies: - "@metamask/approval-controller" "^4.0.0" - "@metamask/base-controller" "^3.2.0" - "@metamask/json-rpc-engine" "^7.1.1" - "@metamask/object-multiplex" "^1.2.0" - "@metamask/permission-controller" "^5.0.0" - "@metamask/phishing-controller" "^7.0.0" - "@metamask/post-message-stream" "^7.0.0" +"@metamask/snaps-controllers@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-controllers/-/snaps-controllers-5.0.0.tgz#007811ab7a7f7d9dd772e94a142c9bb8f7697c4d" + integrity sha512-LZeRFJ3alhR+yjfsoMQvX/f3w0V2eePXjEwOiB95LxhhS93aai+F1jEkM2he9lSOV+pBI6jsBEaXFotspBgudw== + dependencies: + "@metamask/approval-controller" "^5.1.2" + "@metamask/base-controller" "^4.1.0" + "@metamask/json-rpc-engine" "^7.3.2" + "@metamask/object-multiplex" "^2.0.0" + "@metamask/permission-controller" "^8.0.0" + "@metamask/phishing-controller" "^8.0.2" + "@metamask/post-message-stream" "^8.0.0" "@metamask/rpc-errors" "^6.1.0" - "@metamask/snaps-registry" "^2.1.0" - "@metamask/snaps-rpc-methods" "^3.2.0" - "@metamask/snaps-ui" "^3.1.0" - "@metamask/snaps-utils" "^3.2.0" - "@metamask/utils" "^8.1.0" + "@metamask/snaps-registry" "^3.0.0" + "@metamask/snaps-rpc-methods" "^6.0.0" + "@metamask/snaps-sdk" "^2.0.0" + "@metamask/snaps-utils" "^6.0.0" + "@metamask/utils" "^8.3.0" "@xstate/fsm" "^2.0.0" + browserify-zlib "^0.2.0" concat-stream "^2.0.0" get-npm-tarball-url "^2.0.3" - gunzip-maybe "^1.4.2" immer "^9.0.6" json-rpc-middleware-stream "^5.0.0" nanoid "^3.1.31" + readable-stream "^3.6.2" readable-web-to-node-stream "^3.0.2" - tar-stream "^3.1.6" + tar-stream "^3.1.7" -"@metamask/snaps-registry@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@metamask/snaps-registry/-/snaps-registry-2.1.0.tgz#cbcb238d108993d0d78cdb9ee97e99fe74c1284c" - integrity sha512-gypNopoqgTaiOgRdJoqKAZyQSbsIHENRQmTBikZGcKAWhyBv81mA2IcVT8Qr9FgtFVrKG/0Wj+LbWQCC7HrHCw== +"@metamask/snaps-registry@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-registry/-/snaps-registry-3.0.0.tgz#aced797608e4b415e4b9d6b6673f2bc42a02eadb" + integrity sha512-ECanoG//3H3cYGAxKx8yOUibcd4woIopzaqJqIsb7HPNYCeBtW9MoOT5C50u1eEK6mZyNIZVylb+nBboLG1HNA== dependencies: "@metamask/utils" "^8.1.0" - "@noble/secp256k1" "^1.7.1" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.2" superstruct "^1.0.3" -"@metamask/snaps-rpc-methods@^3.2.0", "@metamask/snaps-rpc-methods@^3.2.1": - version "3.2.1" - resolved "https://registry.yarnpkg.com/@metamask/snaps-rpc-methods/-/snaps-rpc-methods-3.2.1.tgz#6e18903241aed03d997da3934da8aeaec963f513" - integrity sha512-vSlCXA0NYNeYi5zNfgPwsOeDKZ7NjB1SUUYZtFODRxs81cYwXzaqTc7EGlsXVuCL6hFePsPKcoZIVWC7+4Qyfg== +"@metamask/snaps-rpc-methods@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-rpc-methods/-/snaps-rpc-methods-6.0.0.tgz#ba51260f5755ee0b2afa73bdb70f2dd4ced820bb" + integrity sha512-jwr8Uordq2FsRzglwWg4H0qsGu5BQdnSY3iCZbiQzR87fUkLyJrWDIw+ATb7xO+0Xk8eIsxsvrlYLFEUI+UouQ== dependencies: "@metamask/key-tree" "^9.0.0" - "@metamask/permission-controller" "^5.0.0" + "@metamask/permission-controller" "^8.0.0" "@metamask/rpc-errors" "^6.1.0" - "@metamask/snaps-ui" "^3.1.0" - "@metamask/snaps-utils" "^3.2.0" - "@metamask/utils" "^8.1.0" + "@metamask/snaps-sdk" "^2.0.0" + "@metamask/snaps-utils" "^6.0.0" + "@metamask/utils" "^8.3.0" "@noble/hashes" "^1.3.1" superstruct "^1.0.3" -"@metamask/snaps-ui@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@metamask/snaps-ui/-/snaps-ui-3.1.0.tgz#3011240f9a91c2113ac1a67b972ede6ab7910364" - integrity sha512-31+GstgOMIuXRc8L5xhTEl4o4ZmdSmssepKmbs3NZED4tCjce9d99ZvN/iHReqSGWulkAX26SJsoonT3+EnMiQ== +"@metamask/snaps-sdk@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-sdk/-/snaps-sdk-2.0.0.tgz#dfdc25543449e66375cfab2bd79d0ba74c6148d3" + integrity sha512-NwRSlgxVpqFEVnTe4zst3/2uMqbltvw8BdCyW7dX+aIZ9jNQXAC7ZDeJQm3WDxvSTLnv65nBJv0AaDVZK21q+w== dependencies: - "@metamask/utils" "^8.1.0" + "@metamask/key-tree" "^9.0.0" + "@metamask/providers" "^14.0.2" + "@metamask/rpc-errors" "^6.1.0" + "@metamask/utils" "^8.3.0" is-svg "^4.4.0" superstruct "^1.0.3" -"@metamask/snaps-utils@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@metamask/snaps-utils/-/snaps-utils-3.2.0.tgz#d594d735647fd6743410d65e9bd4adfe51b1c0e0" - integrity sha512-nEOJgvj4RoUUeTumwVX0dLfFk06uCJy2hPHymKcupxu1eyKqjfSWNyfp49H9zNK/TqeHi4pKcOC/Zzx8WE8RMA== +"@metamask/snaps-utils@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@metamask/snaps-utils/-/snaps-utils-6.0.0.tgz#ec9f31288e94a7a700cec6e788a2724f2b4c499a" + integrity sha512-YO8U1eTmJoRsJfFpJIOEC9cBK6JDFg+Q+xbXRDpwl5/4G40D5q1MFjgwYUN8odyeq0vUcNlc09S2/2PsZLMbRw== dependencies: "@babel/core" "^7.23.2" "@babel/types" "^7.23.0" - "@metamask/base-controller" "^3.2.0" + "@metamask/base-controller" "^4.1.0" "@metamask/key-tree" "^9.0.0" - "@metamask/permission-controller" "^5.0.0" + "@metamask/permission-controller" "^8.0.0" "@metamask/rpc-errors" "^6.1.0" - "@metamask/snaps-registry" "^2.1.0" - "@metamask/snaps-ui" "^3.1.0" - "@metamask/utils" "^8.1.0" + "@metamask/slip44" "^3.1.0" + "@metamask/snaps-registry" "^3.0.0" + "@metamask/snaps-sdk" "^2.0.0" + "@metamask/utils" "^8.3.0" "@noble/hashes" "^1.3.1" "@scure/base" "^1.1.1" chalk "^4.1.2" @@ -4406,7 +4453,7 @@ is-svg "^4.4.0" rfdc "^1.3.0" semver "^7.5.4" - ses "^0.18.8" + ses "^1.1.0" superstruct "^1.0.3" validate-npm-package-name "^5.0.0" @@ -4537,6 +4584,13 @@ dependencies: "@noble/hashes" "1.3.1" +"@noble/curves@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + "@noble/ed25519@^1.6.0": version "1.7.3" resolved "https://registry.yarnpkg.com/@noble/ed25519/-/ed25519-1.7.3.tgz#57e1677bf6885354b466c38e2b620c62f45a7123" @@ -4552,17 +4606,17 @@ resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.1.tgz#8831ef002114670c603c458ab8b11328406953a9" integrity sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA== -"@noble/hashes@^1.0.0", "@noble/hashes@^1.3.1", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": - version "1.3.2" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.2.tgz#6f26dbc8fbc7205873ce3cee2f690eba0d421b39" - integrity sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ== +"@noble/hashes@1.3.3", "@noble/hashes@^1.0.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.0", "@noble/hashes@~1.3.1": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== "@noble/hashes@~1.1.1": version "1.1.5" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.1.5.tgz#1a0377f3b9020efe2fae03290bd2a12140c95c11" integrity sha512-LTMZiiLc+V4v1Yi16TD6aX2gmtKszNye0pQgbaLqkvhIqP7nVsSaJsWloGQjJfJ8offaoP5GtX3yY5swbcJxxQ== -"@noble/secp256k1@1.7.1", "@noble/secp256k1@^1.5.5", "@noble/secp256k1@^1.7.1", "@noble/secp256k1@~1.7.0": +"@noble/secp256k1@1.7.1", "@noble/secp256k1@^1.5.5", "@noble/secp256k1@~1.7.0": version "1.7.1" resolved "https://registry.yarnpkg.com/@noble/secp256k1/-/secp256k1-1.7.1.tgz#b251c70f824ce3ca7f8dc3df08d58f005cc0507c" integrity sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw== @@ -11787,16 +11841,16 @@ bn.js@4.11.8: resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== +bn.js@5.2.1, bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.10.0, bn.js@^4.11.0, bn.js@^4.11.8, bn.js@^4.11.9, bn.js@^4.12.0: version "4.12.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== -bn.js@^5.0.0, bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - body-parser@1.20.1, body-parser@^1.18.2: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -11943,12 +11997,12 @@ browserify-unibabel@^3.0.0: resolved "https://registry.yarnpkg.com/browserify-unibabel/-/browserify-unibabel-3.0.0.tgz#5a6b8f0f704ce388d3927df47337e25830f71dda" integrity sha1-WmuPD3BM44jTkn30czfiWDD3Hdo= -browserify-zlib@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" - integrity sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ== +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: - pako "~0.2.0" + pako "~1.0.5" browserslist@^4.14.5, browserslist@^4.21.9, browserslist@^4.22.1: version "4.22.1" @@ -14361,16 +14415,6 @@ duplexer@~0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== -duplexify@^3.5.0, duplexify@^3.6.0: - version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" - integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== - dependencies: - end-of-stream "^1.0.0" - inherits "^2.0.1" - readable-stream "^2.0.0" - stream-shift "^1.0.0" - duplexify@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-4.1.2.tgz#18b4f8d28289132fa0b9573c898d9f903f81c7b0" @@ -14521,7 +14565,7 @@ encoding@^0.1.13: dependencies: iconv-lite "^0.6.2" -end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: +end-of-stream@^1.1.0, end-of-stream@^1.4.1, end-of-stream@^1.4.4: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -16092,6 +16136,14 @@ extension-port-stream@^2.1.1: dependencies: webextension-polyfill ">=0.10.0 <1.0" +extension-port-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-3.0.0.tgz#00a7185fe2322708a36ed24843c81bd754925fef" + integrity sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw== + dependencies: + readable-stream "^3.6.2 || ^4.4.2" + webextension-polyfill ">=0.10.0 <1.0" + external-editor@^3.0.3: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" @@ -17172,18 +17224,6 @@ gud@^1.0.0: resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== -gunzip-maybe@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac" - integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw== - dependencies: - browserify-zlib "^0.1.4" - is-deflate "^1.0.0" - is-gzip "^1.0.0" - peek-stream "^1.1.0" - pumpify "^1.3.3" - through2 "^2.0.3" - h3@^1.8.1, h3@^1.8.2: version "1.9.0" resolved "https://registry.yarnpkg.com/h3/-/h3-1.9.0.tgz#c5f512a93026df9837db6f30c9ef51135dd46752" @@ -18031,11 +18071,6 @@ is-decimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== -is-deflate@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" - integrity sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ== - is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" @@ -18095,11 +18130,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-gzip@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" - integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== - is-hex-prefixed@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" @@ -19215,7 +19245,7 @@ json-rpc-middleware-stream@^4.2.1: json-rpc-engine "^6.1.0" readable-stream "^2.3.3" -json-rpc-middleware-stream@^5.0.0: +json-rpc-middleware-stream@^5.0.0, json-rpc-middleware-stream@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-5.0.1.tgz#9a5984b4dfe6ccf4f51c648e9327dbe3abf88860" integrity sha512-PMrzifccjdilqU0xftUkusJq0J9O73q66YdVduEmu6vkiTh3V1akliYJGWBAbhg+vhFPC8btUSANa5FNo7a6bg== @@ -21980,16 +22010,11 @@ pad-right@^0.2.2: dependencies: repeat-string "^1.5.2" -pako@^1.0.5, pako@~1.0.2: +pako@^1.0.5, pako@~1.0.2, pako@~1.0.5: version "1.0.11" resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== -pako@~0.2.0: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== - param-case@^3.0.0, param-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" @@ -22267,15 +22292,6 @@ pbkdf2@3.1.2, pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9: safe-buffer "^5.0.1" sha.js "^2.4.8" -peek-stream@^1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" - integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== - dependencies: - buffer-from "^1.0.0" - duplexify "^3.5.0" - through2 "^2.0.3" - pegjs@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/pegjs/-/pegjs-0.10.0.tgz#cf8bafae6eddff4b5a7efb185269eaaf4610ddbd" @@ -22974,23 +22990,6 @@ pump@3.0.0, pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -pump@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" - integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -pumpify@^1.3.3: - version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" - integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== - dependencies: - duplexify "^3.6.0" - inherits "^2.0.3" - pump "^2.0.0" - punycode@1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" @@ -24303,15 +24302,16 @@ readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^4.1.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.4.0.tgz#55ce132d60a988c460d75c631e9ccf6a7229b468" - integrity sha512-kDMOq0qLtxV9f/SQv522h8cxZBqNZXuXNyjyezmfAAuribMyVXziljpQ/uQhfE1XLg2/TLTW2DsnoE4VAi/krg== +"readable-stream@^3.6.2 || ^4.4.2", readable-stream@^4.1.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" + integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== dependencies: abort-controller "^3.0.0" buffer "^6.0.3" events "^3.3.0" process "^0.11.10" + string_decoder "^1.3.0" readable-stream@~1.0.15, readable-stream@~1.0.26, readable-stream@~1.0.26-4, readable-stream@~1.0.31: version "1.0.34" @@ -25211,12 +25211,12 @@ serve-static@1.15.0, serve-static@^1.13.1: parseurl "~1.3.3" send "0.18.0" -ses@^0.18.8: - version "0.18.8" - resolved "https://registry.yarnpkg.com/ses/-/ses-0.18.8.tgz#88036511ac3b3c07e4d82dd8cfc6e5f3788205b6" - integrity sha512-kOH1AhJc6gWDXKURKeU1w7iFUdImAegAljVvBg5EUBgNqjH4bxcEsGVUadVEPtA2PVRMyQp1fiSMDwEZkQNj1g== +ses@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ses/-/ses-1.2.0.tgz#88cea67bec9c6538bcc740baa939711622457c52" + integrity sha512-+klZ2zjFPbHAkf9owGeih+ZB1lqUqvVoCeL5IpNXmIZPhI5rGE1tR729EZmfBzmPh8j+CrsLr/+cTZUmHGFr9g== dependencies: - "@endo/env-options" "^0.1.4" + "@endo/env-options" "^1.1.1" set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" @@ -26226,10 +26226,10 @@ tar-stream@^2.1.0, tar-stream@^2.1.4, tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar-stream@^3.1.5, tar-stream@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.6.tgz#6520607b55a06f4a2e2e04db360ba7d338cc5bab" - integrity sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg== +tar-stream@^3.1.5, tar-stream@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== dependencies: b4a "^1.6.4" fast-fifo "^1.2.0" From 442d9eeb50ce312f34139b91a285144d6ecf5392 Mon Sep 17 00:00:00 2001 From: Jonathan Ferreira <44679989+Jonathansoufer@users.noreply.github.com> Date: Tue, 27 Feb 2024 00:48:13 +0000 Subject: [PATCH 03/10] feat: Snaps new architecture mobile integration (#8700) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR adds a refactored Snaps Webview approach and embedded execution environment to allow mobile app consume the new mobile snaps architecture. ## **Related issues** Fixes: N/A ## **After Screenshot** https://github.com/MetaMask/metamask-mobile/assets/44679989/6e2308dd-4ad6-4f62-a875-fdd13b0c8528 ## **Manual testing steps** 1. Open the mobile app 2. Navigate to explore session and access snaps example page 3. add any snap 4. go to snaps item on settings 5. check if the installed snap is listed. ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. ## **CI Related Section: DO NOT EDIT** Flag used by Bitrise to either run or skip E2E smoke tests - Bitrise Flag:[skip ci] --------- Co-authored-by: Owen Craston --- app/components/Nav/Main/index.js | 2 +- .../SnapsExecutionWebView.tsx | 64 ------------ .../UI/SnapsExecutionWebView/index.ts | 6 -- app/core/Engine.ts | 31 +++--- app/core/Snaps/SnapDuplex.ts | 73 -------------- .../Snaps/SnapWebviewPostMessageStream.ts | 55 ----------- app/core/Snaps/SnapsState.ts | 8 -- app/core/Snaps/WebviewExecutionService.ts | 51 ---------- app/core/Snaps/WebviewPostMessageStream.ts | 80 --------------- app/core/Snaps/index.ts | 10 -- app/lib/snaps/SnapsExecutionWebView.tsx | 99 +++++++++++++++++++ app/lib/snaps/index.ts | 3 + .../snaps}/styles.ts | 0 package.json | 5 +- yarn.lock | 37 +++---- 15 files changed, 139 insertions(+), 385 deletions(-) delete mode 100644 app/components/UI/SnapsExecutionWebView/SnapsExecutionWebView.tsx delete mode 100644 app/components/UI/SnapsExecutionWebView/index.ts delete mode 100644 app/core/Snaps/SnapDuplex.ts delete mode 100644 app/core/Snaps/SnapWebviewPostMessageStream.ts delete mode 100644 app/core/Snaps/SnapsState.ts delete mode 100644 app/core/Snaps/WebviewExecutionService.ts delete mode 100644 app/core/Snaps/WebviewPostMessageStream.ts create mode 100644 app/lib/snaps/SnapsExecutionWebView.tsx create mode 100644 app/lib/snaps/index.ts rename app/{components/UI/SnapsExecutionWebView => lib/snaps}/styles.ts (100%) diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js index a497ca6e4cf..fbe5330bcbb 100644 --- a/app/components/Nav/Main/index.js +++ b/app/components/Nav/Main/index.js @@ -78,7 +78,7 @@ import { stopIncomingTransactionPolling, } from '../../../util/transaction-controller'; ///: BEGIN:ONLY_INCLUDE_IF(snaps) -import { SnapsExecutionWebView } from '../../UI/SnapsExecutionWebView'; +import { SnapsExecutionWebView } from '../../../lib/snaps'; ///: END:ONLY_INCLUDE_IF const Stack = createStackNavigator(); diff --git a/app/components/UI/SnapsExecutionWebView/SnapsExecutionWebView.tsx b/app/components/UI/SnapsExecutionWebView/SnapsExecutionWebView.tsx deleted file mode 100644 index 560e88c46f5..00000000000 --- a/app/components/UI/SnapsExecutionWebView/SnapsExecutionWebView.tsx +++ /dev/null @@ -1,64 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -import React, { useRef } from 'react'; -import { View, ScrollView } from 'react-native'; -import WebView from 'react-native-webview'; -import { snapsState, WebviewPostMessageStream } from '../../../core/Snaps'; -import { createStyles } from './styles'; - -let stream: any; - -const SnapsExecutionWebView = () => { - const styles = createStyles(); - - const webviewRef = useRef(); - - const setWebviewPostMessage = () => { - stream = new WebviewPostMessageStream({ - name: 'rnside', - target: 'webview', - targetOrigin: '*', - targetWindow: webviewRef.current, - }); - - // eslint-disable-next-line no-console - stream.on('data', (data: any) => - // eslint-disable-next-line no-console - console.log( - '[APP LOG] setWebviewPostMessage: Message from Webview ' + data, - ), - ); - - snapsState.stream = stream; - snapsState.webview = webviewRef.current; - }; - - const messageFromWebview = (data: any) => { - stream?._onMessage(data); - }; - - const envURI = { - prod: 'https://gantunesr.github.io/mobile-execution-environment/', - //localIOS: 'http://localhost:3001/mobile-execution-environment', - // localAndroid: 'http://10.0.2.2:3001/mobile-execution-environment', - }; - - return ( - - - - - - ); -}; - -export default SnapsExecutionWebView; -///: END:ONLY_INCLUDE_IF diff --git a/app/components/UI/SnapsExecutionWebView/index.ts b/app/components/UI/SnapsExecutionWebView/index.ts deleted file mode 100644 index 738fad34bbb..00000000000 --- a/app/components/UI/SnapsExecutionWebView/index.ts +++ /dev/null @@ -1,6 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -import SnapsExecutionWebView from './SnapsExecutionWebView'; - -// eslint-disable-next-line import/prefer-default-export -export { SnapsExecutionWebView }; -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Engine.ts b/app/core/Engine.ts index 4232f167565..a3957899e10 100644 --- a/app/core/Engine.ts +++ b/app/core/Engine.ts @@ -105,9 +105,11 @@ import { SnapControllerEvents, SnapControllerActions, PersistedSnapControllerState, + WebViewExecutionService, } from '@metamask/snaps-controllers'; import { Snap } from '@metamask/snaps-utils'; import { NotificationArgs } from '@metamask/snaps-rpc-methods/dist/types/restricted/notify'; +import { getSnapsWebViewPromise } from '../lib/snaps'; import { buildSnapEndowmentSpecifications, buildSnapRestrictedMethodSpecifications, @@ -149,7 +151,6 @@ import AnalyticsV2 from '../util/analyticsV2'; ///: BEGIN:ONLY_INCLUDE_IF(snaps) import { SnapBridge, - WebviewExecutionService, ExcludedSnapEndowments, ExcludedSnapPermissions, detectSnapLocation, @@ -332,7 +333,7 @@ class Engine { /** * Object that runs and manages the execution of Snaps */ - snapExecutionService: WebviewExecutionService; + snapExecutionService: WebViewExecutionService; ///: END:ONLY_INCLUDE_IF /** @@ -353,6 +354,8 @@ class Engine { never >({ name: 'ApprovalController', + allowedEvents: [], + allowedActions: [], }), showApprovalRequest: () => undefined, typesExcludedFromRateLimiting: [ @@ -384,7 +387,8 @@ class Engine { messenger: this.controllerMessenger.getRestricted< 'NetworkController', never, - // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore // TODO: fix this type mismatch after the base-controller version is updated 'NetworkController:networkDidChange' >({ name: 'NetworkController', @@ -397,7 +401,8 @@ class Engine { // noop }, }; - // @ts-expect-error TODO: Resolve/patch mismatch between base-controller versions. Before: never, never. Now: string, string, which expects 3rd and 4th args to be informed for restrictedControllerMessengers + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const networkController = new NetworkController(networkControllerOpts); networkController.initializeProvider(); @@ -634,6 +639,11 @@ class Engine { ), getMnemonic: getPrimaryKeyringMnemonic.bind(this), getUnlockPromise: getAppState.bind(this), + addSubjectMetadata: (params: any) => + this.controllerMessenger.call<'SubjectMetadataController:addSubjectMetadata'>( + 'SubjectMetadataController:addSubjectMetadata', + params, + ), getSnap: this.controllerMessenger.call.bind( this.controllerMessenger, 'SnapController:get', @@ -801,11 +811,12 @@ class Engine { '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6', }); - this.snapExecutionService = new WebviewExecutionService({ + this.snapExecutionService = new WebViewExecutionService({ messenger: this.controllerMessenger.getRestricted({ name: 'ExecutionService', }), setupSnapProvider: setupSnapProvider.bind(this), + getWebView: () => getSnapsWebViewPromise, }); const snapControllerMessenger = this.controllerMessenger.getRestricted({ @@ -831,6 +842,7 @@ class Engine { `${approvalController.name}:updateRequestState`, `${permissionController.name}:grantPermissions`, `${subjectMetadataController.name}:getSubjectMetadata`, + `${subjectMetadataController.name}:addSubjectMetadata`, `${phishingController.name}:maybeUpdateState`, `${phishingController.name}:testOrigin`, `${snapsRegistry.name}:get`, @@ -872,15 +884,12 @@ class Engine { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore (snap: Snap, svgIcon: any = null) => { - const { - manifest: { proposedName }, - version, - } = snap; + const parts = snap.id.split(/[:/]/); subjectMetadataController.addSubjectMetadata({ subjectType: SubjectType.Snap, - name: proposedName, + name: parts[parts.length - 1] || snap.id, origin: snap.id, - version, + version: snap.version, svgIcon, }); }, diff --git a/app/core/Snaps/SnapDuplex.ts b/app/core/Snaps/SnapDuplex.ts deleted file mode 100644 index 314209b2ee6..00000000000 --- a/app/core/Snaps/SnapDuplex.ts +++ /dev/null @@ -1,73 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -import { Duplex } from 'readable-stream'; -import Logger from '../../util/Logger'; - -type StreamData = number | string | Record | unknown[]; - -export interface PostMessageEvent { - origin: string; - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore This type is used inside the browser, so it's not available in react native - source: typeof window; -} - -/** - * Abstract base class for postMessage streams. - */ -export default abstract class SnapDuplex extends Duplex { - private _stream: any; - private _jobId: string; - - constructor({ stream, jobId }: { stream: any; jobId: string }) { - super({ - objectMode: true, - }); - - this._stream = stream; - this._jobId = jobId; - - this._stream.on('data', (data: any) => this._onData(data)); - } - - protected _onData(data: StreamData): void { - Logger.log( - '[SNAP DUPLEX LOG] SnapDuplex+_onData: Job', - this._jobId, - 'read data', - data, - ); - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - if (data.jobId !== this._jobId) { - return; - } - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - this.push(data.data); - } - - /** - * Child classes must implement this function. - */ - protected abstract _postMessage(_data?: unknown): void; - - _read(): void { - return undefined; - } - - _write(data: StreamData, _encoding: string | null, cb: () => void): void { - Logger.log('[SNAP DUPLEX LOG] SnapDuplex+_write: Job', this._jobId); - this._stream.write({ data, jobId: this._jobId }); - cb(); - } - - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - destroy() { - Logger.log( - '[SNAP DUPLEX LOG] SnapDuplex+destroy: Destroy stream from SnapDuplex', - ); - this._stream.destroy(); - } -} -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Snaps/SnapWebviewPostMessageStream.ts b/app/core/Snaps/SnapWebviewPostMessageStream.ts deleted file mode 100644 index b7b78b701f2..00000000000 --- a/app/core/Snaps/SnapWebviewPostMessageStream.ts +++ /dev/null @@ -1,55 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import { BasePostMessageStream } from '@metamask/post-message-stream'; - -interface WebViewPostMessageStreamArgs { - name: string; - stream: any; - jobId: string; -} - -/** - * A {@link Window.postMessage} stream. - */ -export default class SnapWebviewPostMessageStream extends BasePostMessageStream { - private _name: string; - - private _stream: string; - private _jobId: string; - /** - * Creates a stream for communicating with other streams across the same or - * different `window` objects. - * - * @param args - Options bag. - * @param args.name - The name of the stream. Used to differentiate between - * multiple streams sharing the same window object. - * @param args.target - The name of the stream to exchange messages with. - * @param args.targetOrigin - The origin of the target. Defaults to - * `location.origin`, '*' is permitted. - * @param args.targetWindow - The window object of the target stream. Defaults - * to `window`. - */ - constructor({ name, stream, jobId }: WebViewPostMessageStreamArgs) { - super(); - - this._name = name; - this._stream = stream; - this._jobId = jobId; - this._onMessage = this._onMessage.bind(this); - this._stream.on('data', (data) => this._onMessage(data)); - } - - protected _postMessage(data: unknown): void { - this._stream.write(data); - } - - private _onMessage(data: any): void { - this._onData(data); - } - - destroy(): void { - this.destroyed = true; - } -} -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Snaps/SnapsState.ts b/app/core/Snaps/SnapsState.ts deleted file mode 100644 index cd1bfadbf4a..00000000000 --- a/app/core/Snaps/SnapsState.ts +++ /dev/null @@ -1,8 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -const snapsState = { - stream: undefined, - webview: undefined, -}; - -export default snapsState; -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Snaps/WebviewExecutionService.ts b/app/core/Snaps/WebviewExecutionService.ts deleted file mode 100644 index 1b5e4657167..00000000000 --- a/app/core/Snaps/WebviewExecutionService.ts +++ /dev/null @@ -1,51 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import { - Job, - AbstractExecutionService, - ExecutionServiceArgs, -} from '@metamask/snaps-controllers'; -import snapsState from './SnapsState'; -import SnapDuplex from './SnapDuplex'; - -import { BasePostMessageStream } from '@metamask/post-message-stream'; -export default class WebviewExecutionService extends AbstractExecutionService { - #snapDuplexMap: Map; - - constructor({ messenger, setupSnapProvider }: ExecutionServiceArgs) { - super({ - messenger, - setupSnapProvider, - }); - this.#snapDuplexMap = new Map(); - } - - protected async initEnvStream(jobId: string): Promise<{ - worker: any; - stream: BasePostMessageStream; - }> { - const iframeWindow = snapsState.webview; - const stream = snapsState.stream; - - // The WebviewExecutionService wraps the stream into a Duplex - // to pass the jobId to the Proxy Service - const snapStream = new SnapDuplex({ - stream, - jobId, - }); - - this.#snapDuplexMap.set(jobId, snapStream); - - return { worker: iframeWindow, stream: snapStream }; - } - - protected terminateJob(jobWrapper: Job): void { - const snapDuplex = this.#snapDuplexMap.get(jobWrapper.id); - if (snapDuplex) { - snapDuplex.destroy(); - this.#snapDuplexMap.delete(jobWrapper.id); - } - } -} -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Snaps/WebviewPostMessageStream.ts b/app/core/Snaps/WebviewPostMessageStream.ts deleted file mode 100644 index 52d180e38f1..00000000000 --- a/app/core/Snaps/WebviewPostMessageStream.ts +++ /dev/null @@ -1,80 +0,0 @@ -///: BEGIN:ONLY_INCLUDE_IF(snaps) -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -import { - BasePostMessageStream, - PostMessageEvent, -} from '@metamask/post-message-stream'; - -interface WebViewPostMessageStreamArgs { - name: string; - target: string; - targetOrigin?: string; - targetWindow?: Window; -} - -/** - * A {@link Window.postMessage} stream. - */ -export default class WebviewPostMessageStream extends BasePostMessageStream { - private _name: string; - - private _target: string; - - private _targetOrigin: string; - - private _targetWindow: Window; - - /** - * Creates a stream for communicating with other streams across the same or - * different `window` objects. - * - * @param args - Options bag. - * @param args.name - The name of the stream. Used to differentiate between - * multiple streams sharing the same window object. - * @param args.target - The name of the stream to exchange messages with. - * @param args.targetOrigin - The origin of the target. Defaults to - * `location.origin`, '*' is permitted. - * @param args.targetWindow - The window object of the target stream. Defaults - * to `window`. - */ - constructor({ - name, - target, - targetOrigin, - targetWindow, - }: WebViewPostMessageStreamArgs) { - super(); - - this._name = name; - this._target = target; - this._targetOrigin = targetOrigin; - this._targetWindow = targetWindow; - this._onMessage = this._onMessage.bind(this); - - setTimeout(() => this._handshake(), 0); - } - - protected _postMessage(data: unknown): void { - const message = { - target: this._target, - data, - }; - this._targetWindow.injectJavaScript( - `window.postMessage(${JSON.stringify(message)})`, - ); - } - - private _onMessage(event: PostMessageEvent): void { - const message = event.nativeEvent; - const data = JSON.parse(message.data); - - this._onData(data.data); - } - - destroy(): void { - // Do nothing - // we do not want to kill the stream that communicates with the execution environment - } -} -///: END:ONLY_INCLUDE_IF diff --git a/app/core/Snaps/index.ts b/app/core/Snaps/index.ts index 8488be1e3a5..7a0b8d65356 100644 --- a/app/core/Snaps/index.ts +++ b/app/core/Snaps/index.ts @@ -1,10 +1,5 @@ ///: BEGIN:ONLY_INCLUDE_IF(snaps) import SnapBridge from './SnapBridge'; -import SnapDuplex from './SnapDuplex'; -import WebviewExecutionService from './WebviewExecutionService'; -import WebviewPostMessageStream from './WebviewPostMessageStream'; -import SnapWebviewPostMessageStream from './SnapWebviewPostMessageStream'; -import snapsState from './SnapsState'; import { ExcludedSnapPermissions, ExcludedSnapEndowments, @@ -16,12 +11,7 @@ import { } from './location'; export { - snapsState, - SnapDuplex, SnapBridge, - WebviewExecutionService, - WebviewPostMessageStream, - SnapWebviewPostMessageStream, ExcludedSnapPermissions, ExcludedSnapEndowments, fetchFunction, diff --git a/app/lib/snaps/SnapsExecutionWebView.tsx b/app/lib/snaps/SnapsExecutionWebView.tsx new file mode 100644 index 00000000000..4847ebd6614 --- /dev/null +++ b/app/lib/snaps/SnapsExecutionWebView.tsx @@ -0,0 +1,99 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-require-imports */ +/* eslint-disable import/no-commonjs */ +///: BEGIN:ONLY_INCLUDE_IF(snaps) +import React, { Component, RefObject } from 'react'; +import { View, ScrollView, NativeSyntheticEvent } from 'react-native'; +import WebView, { WebViewMessageEvent } from 'react-native-webview'; +import { createStyles } from './styles'; +import { WebViewInterface } from '@metamask/snaps-controllers/dist/types/services/webview/WebViewMessageStream'; +import { WebViewError } from 'react-native-webview/lib/WebViewTypes'; +import { PostMessageEvent } from '@metamask/post-message-stream'; + +const styles = createStyles(); + +interface SnapsExecutionWebViewProps { + injectJavaScript(js: string): void; + registerMessageListener(listener: (event: PostMessageEvent) => void): void; + unregisterMessageListener(listener: (event: PostMessageEvent) => void): void; +} +// This is a hack to allow us to asynchronously await the creation of the WebView. +let resolveGetWebView: (arg0: SnapsExecutionWebViewProps) => void; +let rejectGetWebView: (error: NativeSyntheticEvent) => void; + +const SNAPS_EE_URL = 'https://execution.metamask.io/webview/4.0.0/index.html'; + +export const getSnapsWebViewPromise = new Promise( + (resolve, reject) => { + resolveGetWebView = resolve; + rejectGetWebView = reject; + }, +); + +// This is a class component because storing the references we are don't work in functional components. +export class SnapsExecutionWebView extends Component { + webViewRef: RefObject | any = null; + listener: any = null; + + // eslint-disable-next-line @typescript-eslint/no-useless-constructor + constructor(props: any) { + super(props); + } + + setWebViewRef(ref: React.RefObject> | null) { + this.webViewRef = ref; + } + + onWebViewLoad() { + const api = { + injectJavaScript: (js: string) => { + this.webViewRef?.injectJavaScript(js); + }, + registerMessageListener: ( + listener: (event: PostMessageEvent) => void, + ) => { + this.listener = listener; + }, + unregisterMessageListener: ( + _listener: (event: PostMessageEvent) => void, + ) => { + this.listener = null; + }, + }; + + resolveGetWebView(api); + } + + onWebViewError(error: NativeSyntheticEvent) { + rejectGetWebView(error); + } + + onWebViewMessage(data: WebViewMessageEvent) { + if (this.listener) { + this.listener(data.nativeEvent); + } + } + + render() { + return ( + + + | null + } + source={{ uri: SNAPS_EE_URL }} + onMessage={this.onWebViewMessage} + onError={this.onWebViewError} + onLoadEnd={this.onWebViewLoad} + // TODO: This should probably change + originWhitelist={['*']} + javaScriptEnabled + /> + + + ); + } +} + +///: END:ONLY_INCLUDE_IF diff --git a/app/lib/snaps/index.ts b/app/lib/snaps/index.ts new file mode 100644 index 00000000000..e6450e80762 --- /dev/null +++ b/app/lib/snaps/index.ts @@ -0,0 +1,3 @@ +///: BEGIN:ONLY_INCLUDE_IF(snaps) +export * from './SnapsExecutionWebView'; +///: END:ONLY_INCLUDE_IF diff --git a/app/components/UI/SnapsExecutionWebView/styles.ts b/app/lib/snaps/styles.ts similarity index 100% rename from app/components/UI/SnapsExecutionWebView/styles.ts rename to app/lib/snaps/styles.ts diff --git a/package.json b/package.json index 26370191ac1..bbc23a4b15f 100644 --- a/package.json +++ b/package.json @@ -175,8 +175,8 @@ "@ledgerhq/react-native-hw-transport-ble": "^6.29.5", "@metamask/address-book-controller": "^3.0.0", "@metamask/approval-controller": "^3.4.0", - "@metamask/base-controller": "^4.1.1", "@metamask/assets-controllers": "^9.0.0", + "@metamask/base-controller": "^4.1.1", "@metamask/composable-controller": "^3.0.0", "@metamask/contract-metadata": "^2.1.0", "@metamask/controller-utils": "^4.0.0", @@ -188,7 +188,7 @@ "@metamask/keyring-controller": "^8.1.0", "@metamask/logging-controller": "^1.0.1", "@metamask/network-controller": "^10.0.0", - "@metamask/permission-controller": "^4.0.1", + "@metamask/permission-controller": "7.1.0", "@metamask/phishing-controller": "^5.0.0", "@metamask/post-message-stream": "8.0.0", "@metamask/ppom-validator": "0.24.0", @@ -429,7 +429,6 @@ "@types/react-native-svg-charts": "^5.0.12", "@types/react-native-vector-icons": "^6.4.13", "@types/react-native-video": "^5.0.14", - "@types/readable-stream": "^4.0.9", "@types/redux-mock-store": "^1.0.3", "@types/url-parse": "^1.4.8", "@types/valid-url": "^1.0.4", diff --git a/yarn.lock b/yarn.lock index 0eebb95a378..4f353a5d7dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3593,7 +3593,7 @@ "@metamask/controller-utils" "^6.0.0" "@metamask/utils" "^8.2.0" -"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^3.3.0", "@metamask/approval-controller@^3.4.0", "@metamask/approval-controller@^3.5.0", "@metamask/approval-controller@^3.5.2", "@metamask/approval-controller@^5.1.2": +"@metamask/approval-controller@3.4.0", "@metamask/approval-controller@^3.3.0", "@metamask/approval-controller@^3.4.0", "@metamask/approval-controller@^3.5.0", "@metamask/approval-controller@^5.1.2": version "3.4.0" resolved "https://registry.yarnpkg.com/@metamask/approval-controller/-/approval-controller-3.4.0.tgz#282900361d42f785578728b45014ff8cb5e557ea" integrity sha512-DjqrhiX9+W/Fh6Crr7FPJ87Y/uhPWzBvfXGtekv1LHZNmEtUxkrA7aelddUM0fpTdURIGT4aNGBoQudFidc+Lw== @@ -3634,7 +3634,7 @@ single-call-balance-checker-abi "^1.0.0" uuid "^8.3.2" -"@metamask/base-controller@^3.0.0", "@metamask/base-controller@^3.1.0", "@metamask/base-controller@^3.2.0", "@metamask/base-controller@^3.2.1", "@metamask/base-controller@^3.2.2", "@metamask/base-controller@^3.2.3": +"@metamask/base-controller@^3.0.0", "@metamask/base-controller@^3.1.0", "@metamask/base-controller@^3.2.0", "@metamask/base-controller@^3.2.1", "@metamask/base-controller@^3.2.3": version "3.2.3" resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-3.2.3.tgz#7436a14f6789acf0814952dabaa70ee4fb7d473c" integrity sha512-k66oZe7BOEx0D5N5X8feE/32QlrUTmiEHHAZU/yCac2+VHllJOCEQV/cTeaAtgepnEf8O7SskvYZN+eIjgS99w== @@ -3642,7 +3642,7 @@ "@metamask/utils" "^8.1.0" immer "^9.0.6" -"@metamask/base-controller@^4.0.0", "@metamask/base-controller@^4.1.0", "@metamask/base-controller@^4.1.1": +"@metamask/base-controller@^4.0.0", "@metamask/base-controller@^4.0.1", "@metamask/base-controller@^4.1.0", "@metamask/base-controller@^4.1.1": version "4.1.1" resolved "https://registry.yarnpkg.com/@metamask/base-controller/-/base-controller-4.1.1.tgz#9b411adf4822de7382fe69d07bb6b3fc3e738923" integrity sha512-sJdsd/XlyOa0kRJ16qbM+xeQ8peV1yZcYumJmHCClPK09MkAlxq7EzsrahVZXUCFwcxtSucf244pbttnVqNthw== @@ -3691,7 +3691,7 @@ ethjs-unit "^0.1.6" fast-deep-equal "^3.1.3" -"@metamask/controller-utils@^5.0.1", "@metamask/controller-utils@^5.0.2": +"@metamask/controller-utils@^5.0.2": version "5.0.2" resolved "https://registry.yarnpkg.com/@metamask/controller-utils/-/controller-utils-5.0.2.tgz#f6e848d9b80aca7943e1edae927324982305d1f8" integrity sha512-bHgyPL+Ah6OBOkjWykA1NpTZdpRhoJjCrvuFf8mFxBJLvXE9m/rw9DYp2Rw9WXonMWK17NxwQv/7bKzsGZnjVQ== @@ -3990,7 +3990,7 @@ immer "^9.0.6" uuid "^8.3.2" -"@metamask/json-rpc-engine@^7.0.0", "@metamask/json-rpc-engine@^7.1.1", "@metamask/json-rpc-engine@^7.3.0", "@metamask/json-rpc-engine@^7.3.2": +"@metamask/json-rpc-engine@^7.0.0", "@metamask/json-rpc-engine@^7.1.1", "@metamask/json-rpc-engine@^7.3.0", "@metamask/json-rpc-engine@^7.3.1", "@metamask/json-rpc-engine@^7.3.2": version "7.3.2" resolved "https://registry.yarnpkg.com/@metamask/json-rpc-engine/-/json-rpc-engine-7.3.2.tgz#e8f0695811619eef7b7c894ba5cf782db9f1c2cb" integrity sha512-dVjBPlni4CoiBpESVqrxh6k4OR14w6GRXKSSXHFuITjuhALE42gNCkXTpL4cjNeOBUgTba3eGe5EI8cyc2QLRg== @@ -4173,20 +4173,19 @@ taim "^1.1.0" yargs "^7.1.2" -"@metamask/permission-controller@^4.0.1": - version "4.1.2" - resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-4.1.2.tgz#e4e8f45d97f9420244f3dde879eda9ad9a591c26" - integrity sha512-t9QSMeArXnfsowf4BENnJXh2dGgqWMC4QpYe0muHnFSmMUiVxvb3x/WKoWfzzKsfErHRRDigV9OIejSDz3EqOA== +"@metamask/permission-controller@7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@metamask/permission-controller/-/permission-controller-7.1.0.tgz#e6a2e6c66e8b1c4a46a59eac6fdbdc20d0d7d19d" + integrity sha512-CrE+TU1MQSMgQJ3PDV3KsDD+mhRr+KQ40/XNL/Vk3ShKHqOkCpZLskIm5cawcqgwkTSoRgRY4DYgipIr1ISgpw== dependencies: - "@metamask/approval-controller" "^3.5.2" - "@metamask/base-controller" "^3.2.2" - "@metamask/controller-utils" "^5.0.1" - "@metamask/utils" "^6.2.0" + "@metamask/base-controller" "^4.0.1" + "@metamask/controller-utils" "^8.0.1" + "@metamask/json-rpc-engine" "^7.3.1" + "@metamask/rpc-errors" "^6.1.0" + "@metamask/utils" "^8.2.0" "@types/deep-freeze-strict" "^1.1.0" deep-freeze-strict "^1.1.1" - eth-rpc-errors "^4.0.2" immer "^9.0.6" - json-rpc-engine "^6.1.0" nanoid "^3.1.31" "@metamask/permission-controller@^8.0.0": @@ -8626,14 +8625,6 @@ dependencies: "@types/react" "*" -"@types/readable-stream@^4.0.9": - version "4.0.9" - resolved "https://registry.yarnpkg.com/@types/readable-stream/-/readable-stream-4.0.9.tgz#b7f84343801107b9bcf3dca01934d30dc8df0360" - integrity sha512-4cwuvrmNF96M4Nrx0Eep37RwPB1Mth+nCSezsGRv5+PsFyRvDdLd0pil6gVLcWD/bh69INNdwZ98dJwfHpLohA== - dependencies: - "@types/node" "*" - safe-buffer "~5.1.1" - "@types/readdir-glob@*": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/readdir-glob/-/readdir-glob-1.1.1.tgz#27ac2db283e6aa3d110b14ff9da44fcd1a5c38b1" From 386d9be1b0a450fef82ed06cc29a394235b5e54f Mon Sep 17 00:00:00 2001 From: abretonc7s <107169956+abretonc7s@users.noreply.github.com> Date: Tue, 27 Feb 2024 08:55:27 +0800 Subject: [PATCH 04/10] feat: sdk permissions system integration (#8531) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** Changes to include permissions system within sdk workflows (js + android). WalletConnect will require a separate PR and migrate away from persisting connection in DefaultPreferences. - new connection modal flow (allow multiple account selection) - new sessions management ui Design: https://www.figma.com/file/piME5CaTYUz07Gc7Ye7c22/Deeplinking--SDK?type=design&node-id=1633-2285&mode=design&t=egikpsEVgt3xcMNg-0 https://app.zenhub.com/workspaces/metamask-mobile-5f984938ddc0e4001d4b79cb/issues/gh/metamask/mobile-planning/868 - added online indication in connection list ## **Related issues** Fixes: ## **Manual testing steps** * See QA comments ## **Screenshots/Recordings** ### **Before** ### **After** ![image](https://github.com/MetaMask/metamask-mobile/assets/107169956/71f7e59b-8401-4974-90cf-5af9855d9877) ![image](https://github.com/MetaMask/metamask-mobile/assets/107169956/d2e09508-2154-4e68-95af-77d01322df17) ## **Pre-merge author checklist** - [x] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [x] I've clearly explained what problem this PR is solving and how it is solved. - [x] I've linked related issues - [x] I've included manual testing steps - [x] I've included screenshots/recordings if applicable - [x] I’ve included tests if applicable - [x] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [x] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [x] I’ve properly set the pull request status: - [x] In case it's not yet "ready for review", I've set it to "draft". - [x] In case it's "ready for review", I've changed it from "draft" to "non-draft". ## **Pre-merge reviewer checklist** - [x] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [x] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --- .../BottomSheets/BottomSheet/BottomSheet.tsx | 2 + .../BottomSheets/BottomSheet/README.md | 8 + .../BottomSheetDialog/BottomSheetDialog.tsx | 4 +- .../BottomSheetDialog.types.ts | 4 + .../components/Tags/TagUrl/TagUrl.styles.ts | 2 + .../TagUrl/__snapshots__/TagUrl.test.tsx.snap | 2 + app/components/Nav/App/index.js | 10 + .../Views/AccountConnect/AccountConnect.tsx | 47 +++- .../AccountConnectMultiSelector.styles.ts | 17 ++ .../AccountConnectMultiSelector.tsx | 42 ++-- .../AccountConnectMultiSelector.types.ts | 2 + .../AccountConnectSingle.styles.ts | 14 ++ .../AccountConnectSingle.tsx | 16 +- .../AccountConnectSingle.types.ts | 6 +- .../SDKDisconnectModal/SDKDisconnectModal.tsx | 138 +++++++++++ .../Views/SDKSessionModal/SDKSessionModal.tsx | 220 ++++++++++++++++++ .../SDKSessionAccountListItem.tsx | 139 +++++++++++ .../SDKSessionsManager/SDKSessionItem.tsx | 93 ++++++-- .../SDKSessionsManager/SDKSessionsManager.tsx | 193 ++++++++------- .../Sections/ClearPrivacy/ClearPrivacy.tsx | 2 + .../ApproveTransactionHeader.test.tsx.snap | 4 +- .../__snapshots__/index.test.tsx.snap | 8 +- app/constants/navigation/Routes.ts | 3 + app/core/BackgroundBridge/BackgroundBridge.js | 85 +++++-- app/core/Engine.ts | 5 +- .../RPCMethods/RPCMethodMiddleware.test.ts | 16 +- app/core/RPCMethods/RPCMethodMiddleware.ts | 151 ++++++------ .../SDKConnect/AndroidSDK/AndroidService.ts | 55 ++--- app/core/SDKConnect/Connection/Connection.ts | 1 + .../handleClientsReady.ts | 16 +- .../connectToChannel.test.ts | 1 + .../ConnectionManagement/connectToChannel.ts | 1 + .../ConnectionManagement/disapproveChannel.ts | 10 +- .../ConnectionManagement/reconnect.ts | 3 + .../ConnectionManagement/removeChannel.ts | 14 ++ .../watchConnection.test.ts | 3 + .../ConnectionManagement/watchConnection.ts | 8 + app/core/SDKConnect/SDKConnect.test.ts | 4 + app/core/SDKConnect/SDKConnect.ts | 28 ++- app/core/SDKConnect/SDKConnectConstants.ts | 2 + .../handlers/checkPermissions.test.ts | 34 ++- .../SDKConnect/handlers/checkPermissions.ts | 78 +++---- .../handlers/handleConnectionMessage.ts | 3 + .../SDKConnect/handlers/handleSendMessage.ts | 129 +++++----- .../SDKConnect/handlers/setupBridge.test.ts | 3 +- app/core/SDKConnect/handlers/setupBridge.ts | 6 +- app/core/WalletConnect/WalletConnectV2.ts | 1 + locales/languages/en.json | 19 +- 48 files changed, 1250 insertions(+), 402 deletions(-) create mode 100644 app/components/Views/SDKDisconnectModal/SDKDisconnectModal.tsx create mode 100644 app/components/Views/SDKSessionModal/SDKSessionModal.tsx create mode 100644 app/components/Views/SDKSessionsManager/SDKSessionAccountListItem.tsx diff --git a/app/component-library/components/BottomSheets/BottomSheet/BottomSheet.tsx b/app/component-library/components/BottomSheets/BottomSheet/BottomSheet.tsx index 1f70eb9e00a..ed26cfd5340 100644 --- a/app/component-library/components/BottomSheets/BottomSheet/BottomSheet.tsx +++ b/app/component-library/components/BottomSheets/BottomSheet/BottomSheet.tsx @@ -39,6 +39,7 @@ const BottomSheet = forwardRef( isInteractable = true, shouldNavigateBack = true, isFullscreen = false, + customMarginTop, ...props }, ref, @@ -105,6 +106,7 @@ const BottomSheet = forwardRef( isInteractable={isInteractable} onClose={onCloseCB} onOpen={onOpenCB} + customMarginTop={customMarginTop} ref={bottomSheetDialogRef} isFullscreen={isFullscreen} > diff --git a/app/component-library/components/BottomSheets/BottomSheet/README.md b/app/component-library/components/BottomSheets/BottomSheet/README.md index c858d5319b6..cd3f19b7748 100644 --- a/app/component-library/components/BottomSheets/BottomSheet/README.md +++ b/app/component-library/components/BottomSheets/BottomSheet/README.md @@ -22,6 +22,14 @@ Boolean that indicates if sheet is swippable. This affects whether or not tappin | :-------------------------------------------------- | :------------------------------------------------------ | :----------------------------------------------------- | | boolean | No | true | + +### `customMarginTop` + +Configure height of the modal by setting the distance between top of modal and top of screen. +| TYPE | REQUIRED | DEFAULT | +| :-------------------------------------------------- | :------------------------------------------------------ | :----------------------------------------------------- | +| number | No | 250 + ### `children` Content to wrap in sheet. diff --git a/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.tsx b/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.tsx index 126fadc098c..a5d1a69c510 100644 --- a/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.tsx +++ b/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.tsx @@ -60,6 +60,7 @@ const BottomSheetDialog = forwardRef< isInteractable = true, onClose, onOpen, + customMarginTop, ...props }, ref, @@ -68,9 +69,10 @@ const BottomSheetDialog = forwardRef< useSafeAreaInsets(); const { y: frameY } = useSafeAreaFrame(); const { height: screenHeight } = useWindowDimensions(); + const marginTop = customMarginTop ?? DEFAULT_BOTTOMSHEETDIALOG_MARGINTOP; const maxSheetHeight = isFullscreen ? screenHeight - screenTopPadding - : screenHeight - screenTopPadding - DEFAULT_BOTTOMSHEETDIALOG_MARGINTOP; + : screenHeight - screenTopPadding - marginTop; const { styles } = useStyles(styleSheet, { maxSheetHeight, screenBottomPadding, diff --git a/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.types.ts b/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.types.ts index da2ba4a6f35..244e00d0c0b 100644 --- a/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.types.ts +++ b/app/component-library/components/BottomSheets/BottomSheet/foundation/BottomSheetDialog/BottomSheetDialog.types.ts @@ -27,6 +27,10 @@ export interface BottomSheetDialogProps extends ViewProps { * Optional callback that gets triggered when sheet is opened. */ onOpen?: (hasPendingAction?: boolean) => void; + /** + * Customize the top margin of the sheet. + */ + customMarginTop?: number; } export interface BottomSheetDialogRef { diff --git a/app/component-library/components/Tags/TagUrl/TagUrl.styles.ts b/app/component-library/components/Tags/TagUrl/TagUrl.styles.ts index 41373df52b4..da586a0f21d 100644 --- a/app/component-library/components/Tags/TagUrl/TagUrl.styles.ts +++ b/app/component-library/components/Tags/TagUrl/TagUrl.styles.ts @@ -37,6 +37,8 @@ const styleSheet = (params: { theme: Theme; vars: TagUrlStyleSheetVars }) => { ) as ViewStyle, favicon: { marginRight: 8, + width: 24, + height: 24, }, label: { color: colors.text.alternative, diff --git a/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap b/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap index e70af7ccb3b..f734e43eb0b 100644 --- a/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap +++ b/app/component-library/components/Tags/TagUrl/__snapshots__/TagUrl.test.tsx.snap @@ -26,7 +26,9 @@ exports[`TagUrl should render correctly 1`] = ` size="32" style={ Object { + "height": 24, "marginRight": 8, + "width": 24, } } variant="Favicon" diff --git a/app/components/Nav/App/index.js b/app/components/Nav/App/index.js index 5ff59ed9e1f..8a5e876e7ae 100644 --- a/app/components/Nav/App/index.js +++ b/app/components/Nav/App/index.js @@ -99,6 +99,8 @@ import AsyncStorage from '../../../store/async-storage-wrapper'; import ShowIpfsGatewaySheet from '../../Views/ShowIpfsGatewaySheet/ShowIpfsGatewaySheet'; import ShowDisplayNftMediaSheet from '../../Views/ShowDisplayMediaNFTSheet/ShowDisplayNFTMediaSheet'; import AmbiguousAddressSheet from '../../../../app/components/Views/Settings/Contacts/AmbiguousAddressSheet/AmbiguousAddressSheet'; +import SDKDisconnectModal from '../../../../app/components/Views/SDKDisconnectModal/SDKDisconnectModal'; +import SDKSessionModal from '../../../../app/components/Views/SDKSessionModal/SDKSessionModal'; import { MetaMetrics } from '../../../core/Analytics'; import trackErrorAsAnalytics from '../../../util/metrics/TrackError/trackErrorAsAnalytics'; @@ -552,6 +554,14 @@ const App = ({ userLoggedIn }) => { name={Routes.SHEET.SDK_FEEDBACK} component={SDKFeedbackModal} /> + + { ? AvatarAccountType.Blockies : AvatarAccountType.JazzIcon, ); + + const { id: channelId, origin: metadataOrigin } = hostInfo.metadata as { + id: string; + origin: string; + }; + + // Extract connection info from sdk + // FIXME should be replaced by passing dynamic parameters to the PermissionController + // TODO: Retrive wallet connect connection info from channelId + const sdkConnection = SDKConnect.getInstance().getConnection({ channelId }); + const hostname = ( + sdkConnection?.originatorInfo?.url ?? metadataOrigin + ).replace(AppConstants.MM_SDK.SDK_REMOTE_ORIGIN, ''); + const origin: string = useSelector(getActiveTabUrl, isEqual); const faviconSource = useFavicon(origin); - - const hostname = hostInfo.metadata.origin; const urlWithProtocol = prefixUrlWithProtocol(hostname); const secureIcon = useMemo( @@ -117,13 +131,25 @@ const AccountConnect = (props: AccountConnectProps) => { const cancelPermissionRequest = useCallback( (requestId) => { Engine.context.PermissionController.rejectPermissionsRequest(requestId); + if (channelId && accountsLength === 0) { + // Remove Potential SDK connection + SDKConnect.getInstance().removeChannel({ + channelId, + sendTerminate: true, + }); + } trackEvent(MetaMetricsEvents.CONNECT_REQUEST_CANCELLED, { number_of_accounts: accountsLength, source: 'permission system', }); }, - [Engine.context.PermissionController, accountsLength, trackEvent], + [ + Engine.context.PermissionController, + accountsLength, + channelId, + trackEvent, + ], ); const triggerDappVisitedEvent = useCallback( @@ -141,10 +167,11 @@ const AccountConnect = (props: AccountConnectProps) => { ...hostInfo, metadata: { ...hostInfo.metadata, - origin: hostname, + origin: metadataOrigin, }, approvedAccounts: selectedAccounts, }; + const connectedAccountLength = selectedAccounts.length; const activeAddress = selectedAccounts[0].address; const activeAccountName = getAccountNameWithENS({ @@ -199,11 +226,11 @@ const AccountConnect = (props: AccountConnectProps) => { hostInfo, accounts, ensByAccountAddress, - hostname, accountAvatarType, Engine.context.PermissionController, toastRef, accountsLength, + metadataOrigin, triggerDappVisitedEvent, trackEvent, ]); @@ -318,6 +345,7 @@ const AccountConnect = (props: AccountConnectProps) => { return ( { secureIcon, urlWithProtocol, setUserIntent, + sdkConnection, ]); const renderSingleConnectSelectorScreen = useCallback( @@ -376,6 +405,7 @@ const AccountConnect = (props: AccountConnectProps) => { urlWithProtocol={urlWithProtocol} onUserAction={setUserIntent} onBack={() => setScreen(AccountConnectScreens.SingleConnect)} + connection={sdkConnection} /> ), [ @@ -388,6 +418,7 @@ const AccountConnect = (props: AccountConnectProps) => { faviconSource, urlWithProtocol, secureIcon, + sdkConnection, ], ); @@ -408,7 +439,11 @@ const AccountConnect = (props: AccountConnectProps) => { ]); return ( - + {renderConnectScreens()} ); diff --git a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.styles.ts b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.styles.ts index 0e85d288de6..d7489654983 100644 --- a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.styles.ts +++ b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.styles.ts @@ -12,6 +12,9 @@ const styleSheet = (params: { theme: Theme }) => { const { colors } = params.theme; return StyleSheet.create({ + container: { + height: '100%', + }, body: { paddingHorizontal: 16, }, @@ -32,6 +35,20 @@ const styleSheet = (params: { theme: Theme }) => { selectAllButton: { marginBottom: 16, }, + sdkInfoContainer: { + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + gap: 10, + paddingHorizontal: 16, + marginBottom: -16, + }, + sdkInfoDivier: { + borderTopWidth: 1, + borderTopColor: colors.border.muted, + height: 1, + width: '100%', + }, disabled: { opacity: 0.5, }, diff --git a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx index 1052912c313..f1f2fd88c9e 100644 --- a/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx +++ b/app/components/Views/AccountConnect/AccountConnectMultiSelector/AccountConnectMultiSelector.tsx @@ -1,32 +1,34 @@ // Third party dependencies. import React, { useCallback, useState } from 'react'; -import { View, Platform } from 'react-native'; +import { Platform, View } from 'react-native'; // External dependencies. -import SheetHeader from '../../../../component-library/components/Sheet/SheetHeader'; import { strings } from '../../../../../locales/i18n'; -import TagUrl from '../../../../component-library/components/Tags/TagUrl'; -import Text from '../../../../component-library/components/Texts/Text'; -import { useStyles } from '../../../../component-library/hooks'; +import { ACCOUNT_APPROVAL_SELECT_ALL_BUTTON } from '../../../../../wdio/screen-objects/testIDs/Components/AccountApprovalModal.testIds'; +import generateTestId from '../../../../../wdio/utils/generateTestId'; import Button, { ButtonSize, ButtonVariants, ButtonWidthTypes, } from '../../../../component-library/components/Buttons/Button'; -import AccountSelectorList from '../../../UI/AccountSelectorList'; +import SheetHeader from '../../../../component-library/components/Sheet/SheetHeader'; +import TagUrl from '../../../../component-library/components/Tags/TagUrl'; +import Text, { + TextColor, +} from '../../../../component-library/components/Texts/Text'; +import { useStyles } from '../../../../component-library/hooks'; import { USER_INTENT } from '../../../../constants/permissions'; -import generateTestId from '../../../../../wdio/utils/generateTestId'; -import { ACCOUNT_APPROVAL_SELECT_ALL_BUTTON } from '../../../../../wdio/screen-objects/testIDs/Components/AccountApprovalModal.testIds'; +import AccountSelectorList from '../../../UI/AccountSelectorList'; // Internal dependencies. +import { ConnectAccountModalSelectorsIDs } from '../../../../../e2e/selectors/Modals/ConnectAccountModal.selectors'; +import { ACCOUNT_LIST_ADD_BUTTON_ID } from '../../../../../wdio/screen-objects/testIDs/Components/AccountListComponent.testIds'; +import AddAccountActions from '../../AddAccountActions'; import styleSheet from './AccountConnectMultiSelector.styles'; import { AccountConnectMultiSelectorProps, AccountConnectMultiSelectorScreens, } from './AccountConnectMultiSelector.types'; -import AddAccountActions from '../../AddAccountActions'; -import { ACCOUNT_LIST_ADD_BUTTON_ID } from '../../../../../wdio/screen-objects/testIDs/Components/AccountListComponent.testIds'; -import { ConnectAccountModalSelectorsIDs } from '../../../../../e2e/selectors/Modals/ConnectAccountModal.selectors'; const AccountConnectMultiSelector = ({ accounts, @@ -39,6 +41,7 @@ const AccountConnectMultiSelector = ({ secureIcon, isAutoScrollEnabled = true, urlWithProtocol, + connection, onBack, }: AccountConnectMultiSelectorProps) => { const { styles } = useStyles(styleSheet, {}); @@ -147,7 +150,7 @@ const AccountConnectMultiSelector = ({ const renderAccountConnectMultiSelector = useCallback( () => ( - <> + + {connection?.originatorInfo?.apiVersion && ( + + + + SDK {connection?.originatorInfo?.platform} v + {connection?.originatorInfo?.apiVersion} + + + )}