diff --git a/packages/starknet-snap/src/index.test.tsx b/packages/starknet-snap/src/index.test.tsx
index 2426ddf5..236eab98 100644
--- a/packages/starknet-snap/src/index.test.tsx
+++ b/packages/starknet-snap/src/index.test.tsx
@@ -6,6 +6,12 @@ import { HomePageController } from './on-home-page';
import * as keyPairUtils from './utils/keyPair';
jest.mock('./utils/logger');
+jest.mock('./utils/snap');
+
+jest.mock('./utils', () => ({
+ ...jest.requireActual('./utils'),
+ updateRequiredMetaMaskComponent: jest.fn(),
+}));
describe('onRpcRequest', () => {
const createMockSpy = () => {
@@ -42,6 +48,7 @@ describe('onRpcRequest', () => {
});
it('throws `MethodNotFoundError` if the request method not found', async () => {
+ createMockSpy();
await expect(
onRpcRequest({
...createMockRequest(),
@@ -53,6 +60,19 @@ describe('onRpcRequest', () => {
).rejects.toThrow(MethodNotFoundError);
});
+ it('requests gets executed if MetaMask does not needs update', async () => {
+ createMockSpy();
+ expect(
+ await onRpcRequest({
+ ...createMockRequest(),
+ request: {
+ ...createMockRequest().request,
+ method: 'ping',
+ },
+ }),
+ ).toBe('pong');
+ });
+
it('throws `SnapError` if the error is an instance of SnapError', async () => {
const { createAccountSpy } = createMockSpy();
createAccountSpy.mockRejectedValue(new SnapError('error'));
@@ -69,7 +89,7 @@ describe('onRpcRequest', () => {
});
describe('onHomePage', () => {
- it('executes homePageController', async () => {
+ it('executes homePageController normally if jsxSupport is not required', async () => {
const executeSpy = jest.spyOn(HomePageController.prototype, 'execute');
executeSpy.mockResolvedValue({ content: text('test') });
diff --git a/packages/starknet-snap/src/index.tsx b/packages/starknet-snap/src/index.tsx
index 37e264df..26596246 100644
--- a/packages/starknet-snap/src/index.tsx
+++ b/packages/starknet-snap/src/index.tsx
@@ -61,6 +61,7 @@ import type {
import type { SnapState } from './types/snapState';
import { upgradeAccContract } from './upgradeAccContract';
import {
+ ensureJsxSupport,
getDappUrl,
getStateData,
isSnapRpcError,
@@ -302,40 +303,27 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
};
export const onInstall: OnInstallHandler = async () => {
- await snap.request({
- method: 'snap_dialog',
- params: {
- type: 'alert',
- content: (
-
- Your MetaMask wallet is now compatible with Starknet!
-
- To manage your Starknet account and send and receive funds, visit
- the companion dapp for Starknet.
-
-
- ),
- },
- });
+ await ensureJsxSupport(
+
+ Your MetaMask wallet is now compatible with Starknet!
+
+ To manage your Starknet account and send and receive funds, visit the{' '}
+ companion dapp for Starknet.
+
+ ,
+ );
};
export const onUpdate: OnUpdateHandler = async () => {
- await snap.request({
- method: 'snap_dialog',
- params: {
- type: 'alert',
- content: (
-
- Your Starknet Snap is now up-to-date !
-
- As usual, to manage your Starknet account and send and receive
- funds, visit the{' '}
- companion dapp for Starknet.
-
-
- ),
- },
- });
+ await ensureJsxSupport(
+
+ Your Starknet Snap is now up-to-date !
+
+ As usual, to manage your Starknet account and send and receive funds,
+ visit the companion dapp for Starknet.
+
+ ,
+ );
};
export const onHomePage: OnHomePageHandler = async () => {
diff --git a/packages/starknet-snap/src/state/state-manager.ts b/packages/starknet-snap/src/state/state-manager.ts
index 81b7a997..30bb0e75 100644
--- a/packages/starknet-snap/src/state/state-manager.ts
+++ b/packages/starknet-snap/src/state/state-manager.ts
@@ -14,6 +14,7 @@ export abstract class StateManager extends SnapStateManager {
erc20Tokens: [],
networks: [],
transactions: [],
+ requireMMUpgrade: undefined,
transactionRequests: [],
};
}
diff --git a/packages/starknet-snap/src/types/snapState.ts b/packages/starknet-snap/src/types/snapState.ts
index ceea001a..341280db 100644
--- a/packages/starknet-snap/src/types/snapState.ts
+++ b/packages/starknet-snap/src/types/snapState.ts
@@ -7,6 +7,7 @@ export type SnapState = {
networks: Network[];
transactions: Transaction[];
currentNetwork?: Network;
+ requireMMUpgrade?: boolean;
transactionRequests?: TransactionRequest[];
};
diff --git a/packages/starknet-snap/src/utils/snap-ui.ts b/packages/starknet-snap/src/utils/snap-ui.ts
index 0aaafacb..eb655ac0 100644
--- a/packages/starknet-snap/src/utils/snap-ui.ts
+++ b/packages/starknet-snap/src/utils/snap-ui.ts
@@ -1,9 +1,50 @@
-import { divider, heading, row, text } from '@metamask/snaps-sdk';
+import type { Component } from '@metamask/snaps-sdk';
+import { divider, heading, panel, row, text } from '@metamask/snaps-sdk';
import { getExplorerUrl } from './explorer';
import { toJson } from './serializer';
import { shortenAddress } from './string';
+export const updateRequiredMetaMaskComponent = () => {
+ return panel([
+ text(
+ 'You need to update your MetaMask to latest version to use this snap.',
+ ),
+ ]);
+};
+
+/**
+ * Ensures that JSX support is available in the MetaMask environment by attempting to render a component within a snap dialog.
+ * If MetaMask does not support JSX, an alert message is shown prompting the user to update MetaMask.
+ *
+ * @param component - The JSX component to display in the snap dialog.
+ *
+ * The function performs the following steps:
+ * 1. Tries to render the provided component using a `snap_dialog` method.
+ * 2. On success, it updates the `requireMMUpgrade` flag in the snap's state to `false`, indicating that JSX is supported.
+ * 3. If an error occurs (likely due to outdated MetaMask), it displays an alert dialog prompting the user to update MetaMask.
+ */
+export const ensureJsxSupport = async (component: Component): Promise => {
+ try {
+ // Try rendering the JSX component to test compatibility
+ await snap.request({
+ method: 'snap_dialog',
+ params: {
+ type: 'alert',
+ content: component,
+ },
+ });
+ } catch {
+ await snap.request({
+ method: 'snap_dialog',
+ params: {
+ type: 'alert',
+ content: updateRequiredMetaMaskComponent(),
+ },
+ });
+ }
+};
+
/**
* Build a row component.
*