diff --git a/app/components/Nav/Main/RootRPCMethodsUI.js b/app/components/Nav/Main/RootRPCMethodsUI.js
index e29aa583664..bcc6b95d45e 100644
--- a/app/components/Nav/Main/RootRPCMethodsUI.js
+++ b/app/components/Nav/Main/RootRPCMethodsUI.js
@@ -771,25 +771,25 @@ const RootRPCMethodsUI = (props) => {
console.log('Update Snap');
break;
case ApprovalTypes.REQUEST_PERMISSIONS:
- if (requestData?.permissions?.eth_accounts) {
- const {
- metadata: { id },
- } = requestData;
-
- const totalAccounts = props.accountsLength;
-
- trackEvent(MetaMetricsEvents.CONNECT_REQUEST_STARTED, {
- number_of_accounts: totalAccounts,
- source: 'PERMISSION SYSTEM',
- });
-
- props.navigation.navigate(
- ...createAccountConnectNavDetails({
- hostInfo: requestData,
- permissionRequestId: id,
- }),
- );
- }
+ // eslint-disable-next-line no-case-declarations
+ const {
+ metadata: { id },
+ } = requestData;
+
+ // eslint-disable-next-line no-case-declarations
+ const totalAccounts = props.accountsLength;
+
+ trackEvent(MetaMetricsEvents.CONNECT_REQUEST_STARTED, {
+ number_of_accounts: totalAccounts,
+ source: 'PERMISSION SYSTEM',
+ });
+
+ props.navigation.navigate(
+ ...createAccountConnectNavDetails({
+ hostInfo: requestData,
+ permissionRequestId: id,
+ }),
+ );
break;
case ApprovalTypes.CONNECT_ACCOUNTS:
setHostToApprove({ data: requestData, id: request.id });
diff --git a/app/components/Nav/Main/index.js b/app/components/Nav/Main/index.js
index c917e744195..916e41ac6e5 100644
--- a/app/components/Nav/Main/index.js
+++ b/app/components/Nav/Main/index.js
@@ -71,6 +71,7 @@ import {
selectProviderConfig,
selectProviderType,
} from '../../../selectors/networkController';
+import { SnapsExecutionWebView } from '../../UI/SnapsExecutionWebView';
const Stack = createStackNavigator();
@@ -352,6 +353,9 @@ const Main = (props) => {
) : (
renderLoader()
)}
+
+
+
diff --git a/app/components/UI/SnapsExecutionWebView/styles.ts b/app/components/UI/SnapsExecutionWebView/styles.ts
index fb9e704a369..659b2428b60 100644
--- a/app/components/UI/SnapsExecutionWebView/styles.ts
+++ b/app/components/UI/SnapsExecutionWebView/styles.ts
@@ -5,7 +5,7 @@ import { StyleSheet } from 'react-native';
export const createStyles = () =>
StyleSheet.create({
webview: {
- height: 60,
+ height: 0,
// marginBottom: 50,
// borderWidth: 1,
// borderStyle: 'dashed',
diff --git a/app/components/Views/Snaps/SnapsDev.tsx b/app/components/Views/Snaps/SnapsDev.tsx
index 531a9b9bba6..8e6e5d9169b 100644
--- a/app/components/Views/Snaps/SnapsDev.tsx
+++ b/app/components/Views/Snaps/SnapsDev.tsx
@@ -10,7 +10,6 @@ import Button, {
} from '../../../component-library/components/Buttons/Button';
import { useTheme } from '../../../util/theme';
import { getClosableNavigationOptions } from '../../UI/Navbar';
-import { SnapsExecutionWebView } from '../../UI/SnapsExecutionWebView';
import Engine from '../../../core/Engine';
import { createStyles } from './styles';
@@ -74,9 +73,6 @@ const SnapsDev = () => {
return (
-
-
-
+ new Promise((resolve, reject) => {
+ resolve('mockAppKey');
+ }),
+ getUnlockPromise: () => Promise.resolve(),
+ getSnaps: Engine.controllerMessenger.call.bind(
+ Engine.controllerMessenger,
+ 'SnapController:getPermitted',
+ origin,
+ ),
+ requestPermissions: async (requestedPermissions) => {
+ const [approvedPermissions] =
+ await Engine.context.PermissionController.requestPermissions(
+ { origin },
+ requestedPermissions,
+ );
+
+ return Object.values(approvedPermissions);
+ },
+ getPermissions: Engine.context.PermissionController.getPermissions.bind(
+ Engine.context.PermissionController,
+ origin,
+ ),
+ getAccounts: (origin) => getPermittedAccounts(origin),
+ installSnaps: Engine.controllerMessenger.call.bind(
+ Engine.controllerMessenger,
+ 'SnapController:install',
+ origin,
+ ),
+ }),
+ );
+
// user-facing RPC methods
engine.push(
this.createMiddleware({
@@ -350,7 +390,6 @@ export class BackgroundBridge extends EventEmitter {
}),
);
}
-
// forward to metamask primary provider
engine.push(providerAsMiddleware(provider));
return engine;
diff --git a/app/core/Engine.js b/app/core/Engine.js
index 37785abda8b..73911f33dcd 100644
--- a/app/core/Engine.js
+++ b/app/core/Engine.js
@@ -264,7 +264,9 @@ class Engine {
messenger: this.controllerMessenger.getRestricted({
name: 'ApprovalController',
}),
- showApprovalRequest: () => null,
+ showApprovalRequest: () => {
+ console.log('Snaps/ approvalController showApprovalRequest');
+ },
});
const phishingController = new PhishingController();
@@ -329,16 +331,16 @@ class Engine {
this.controllerMessenger,
'SnapController:getSnapState',
),
- // showConfirmation: (origin, confirmationData) =>
- // this.approvalController.addAndShowApprovalRequest({
- // origin,
- // type: MESSAGE_TYPE.SNAP_CONFIRM,
- // requestData: confirmationData,
- // }),
updateSnapState: this.controllerMessenger.call.bind(
this.controllerMessenger,
'SnapController:updateSnapState',
),
+ showConfirmation: (origin, confirmationData) =>
+ this.approvalController.addAndShowApprovalRequest({
+ origin,
+ type: 'snapConfirmation',
+ requestData: confirmationData,
+ }),
}),
});
diff --git a/app/core/Snaps/SnapsState.ts b/app/core/Snaps/SnapsState.ts
index 7d0153dddb4..d53fc6f5da8 100644
--- a/app/core/Snaps/SnapsState.ts
+++ b/app/core/Snaps/SnapsState.ts
@@ -1,6 +1,6 @@
const snapsState = {
- stream: null,
- webview: null,
+ stream: undefined,
+ webview: undefined,
};
export default snapsState;
diff --git a/app/core/Snaps/createSnapMethodMiddleware.ts b/app/core/Snaps/createSnapMethodMiddleware.ts
new file mode 100644
index 00000000000..c9fb8ad6233
--- /dev/null
+++ b/app/core/Snaps/createSnapMethodMiddleware.ts
@@ -0,0 +1,47 @@
+import { handlers as permittedSnapMethods } from '@metamask/rpc-methods/dist/permitted';
+import { selectHooks } from '@metamask/rpc-methods/dist/utils';
+import { ethErrors } from 'eth-rpc-errors';
+
+/*
+ copied form extension
+ https://github.com/MetaMask/metamask-extension/blob/develop/app/scripts/lib/rpc-method-middleware/createMethodMiddleware.js#L83
+*/
+const snapHandlerMap = permittedSnapMethods.reduce((map, handler) => {
+ for (const methodName of handler.methodNames) {
+ map.set(methodName, handler);
+ }
+ return map;
+}, new Map());
+
+// eslint-disable-next-line import/prefer-default-export
+export function createSnapMethodMiddleware(isSnap: boolean, hooks: any) {
+ return async function methodMiddleware(
+ req: unknown,
+ res: unknown,
+ next: unknown,
+ end: unknown,
+ ) {
+ const handler = snapHandlerMap.get(req.method);
+ if (handler) {
+ if (/^snap_/iu.test(req.method) && !isSnap) {
+ return end(ethErrors.rpc.methodNotFound());
+ }
+
+ const { implementation, hookNames } = handler;
+ try {
+ // Implementations may or may not be async, so we must await them.
+ return await implementation(
+ req,
+ res,
+ next,
+ end,
+ selectHooks(hooks, hookNames),
+ );
+ } catch (error) {
+ console.error(error);
+ return end(error);
+ }
+ }
+ return next();
+ };
+}
diff --git a/app/core/Snaps/location/npm.ts b/app/core/Snaps/location/npm.ts
index c117671418b..efd662f8a9e 100644
--- a/app/core/Snaps/location/npm.ts
+++ b/app/core/Snaps/location/npm.ts
@@ -99,6 +99,16 @@ const readAndParseManifest = async (path: string) => {
}
};
+const readAndParseIcon = async (path: string) => {
+ try {
+ const iconPath = `${path}/package/images/icon.svg`;
+ const data = await ReactNativeBlobUtil.fs.readFile(iconPath, 'utf8');
+ return data;
+ } catch (error) {
+ Logger.log(SNAPS_NPM_LOG_TAG, 'readAndParseManifest error', error);
+ }
+};
+
const fetchAndStoreNPMPackage = async (
inputRequest: RequestInfo,
): Promise => {
@@ -251,7 +261,7 @@ export class NpmLocation implements SnapLocation {
async #lazyInit() {
assert(this.files === undefined);
- const [manifest, sourceCode, actualVersion] = await fetchNpmTarball(
+ const [manifest, sourceCode, icon, actualVersion] = await fetchNpmTarball(
this.meta.packageName,
this.meta.requestedRange,
this.meta.registry,
@@ -286,6 +296,16 @@ export class NpmLocation implements SnapLocation {
});
this.files = new Map();
+
+ if (icon) {
+ const iconVFile = new VirtualFile({
+ value: icon,
+ path: 'images/icon.svg',
+ data: { canonicalPath: canonicalBase },
+ });
+ this.files.set('images/icon.svg', iconVFile);
+ }
+
this.files.set('snap.manifest.json', manifestVFile);
this.files.set('dist/bundle.js', sourceCodeVFile);
}
@@ -309,7 +329,7 @@ async function fetchNpmTarball(
versionRange: SemVerRange,
registryUrl: string,
fetchFunction: typeof fetch,
-): Promise<[string, string, SemVerVersion]> {
+): Promise<[string, string, string, SemVerVersion]> {
const urlToFetch = new URL(packageName, registryUrl).toString();
const packageMetadata = await (await fetchFunction(urlToFetch)).json();
@@ -360,8 +380,18 @@ async function fetchNpmTarball(
const manifest = await readAndParseManifest(npmPackageDataLocation);
const sourceCode = await readAndParseSourceCode(npmPackageDataLocation);
+ let icon;
+ try {
+ icon = await readAndParseIcon(npmPackageDataLocation);
+ } catch (error) {
+ Logger.log(
+ `Failed to fetch icon for package "${packageName}". Using default icon instead.`,
+ error,
+ );
+ }
+
if (!manifest || !sourceCode) {
throw new Error(`Failed to fetch tarball for package "${packageName}".`);
}
- return [manifest, sourceCode, targetVersion];
+ return [manifest, sourceCode, icon, targetVersion];
}
diff --git a/ios/Light-Swift-Untar-V2/Light-Swift-Untar.swift b/ios/Light-Swift-Untar-V2/Light-Swift-Untar.swift
index c0b92671301..06468a7e99f 100644
--- a/ios/Light-Swift-Untar-V2/Light-Swift-Untar.swift
+++ b/ios/Light-Swift-Untar-V2/Light-Swift-Untar.swift
@@ -102,7 +102,6 @@ public extension FileManager {
private func writeFileData(object: Any, location _loc: UInt64, length _len: UInt64,
path: String) {
-
let pathURL = URL(fileURLWithPath: path)
let directoryPathURL = pathURL.deletingLastPathComponent()
if let data = object as? Data {
diff --git a/ios/RNTar.swift b/ios/RNTar.swift
index 5ac0eb0bbae..9d06980ae5c 100644
--- a/ios/RNTar.swift
+++ b/ios/RNTar.swift
@@ -71,5 +71,4 @@ class RNTar: NSObject {
rejecter("Error uncompressing file:", error.localizedDescription, error)
}
}
-
}