Skip to content

Commit

Permalink
feat: add jsx support detection (#416)
Browse files Browse the repository at this point in the history
* chore: add jsx support in snap

* chore: add jsx support in snap

* feat: jsx support management

* chore: fix test and lint

* fix: add mutex in jsx support detection mechanism

* chore: ensure test pass

* feat: new init state manager class to manage state init and support check

* fix: wait for hooks in request handler

* chore: lint

* fix: set jsx support to true before showing dialog

* chore: fix comment

* fix: moved ping pong

* chore: lint

* chore: rollback state

* chore: lint

* chore: fix comments

* fix: test suits
  • Loading branch information
khanti42 authored Nov 20, 2024
1 parent ef8076e commit 6531485
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 33 deletions.
22 changes: 21 additions & 1 deletion packages/starknet-snap/src/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 = () => {
Expand Down Expand Up @@ -42,6 +48,7 @@ describe('onRpcRequest', () => {
});

it('throws `MethodNotFoundError` if the request method not found', async () => {
createMockSpy();
await expect(
onRpcRequest({
...createMockRequest(),
Expand All @@ -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'));
Expand All @@ -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') });

Expand Down
50 changes: 19 additions & 31 deletions packages/starknet-snap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ import type {
import type { SnapState } from './types/snapState';
import { upgradeAccContract } from './upgradeAccContract';
import {
ensureJsxSupport,
getDappUrl,
getStateData,
isSnapRpcError,
Expand Down Expand Up @@ -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: (
<Box>
<Text>Your MetaMask wallet is now compatible with Starknet!</Text>
<Text>
To manage your Starknet account and send and receive funds, visit
the <Link href={getDappUrl()}>companion dapp for Starknet</Link>.
</Text>
</Box>
),
},
});
await ensureJsxSupport(
<Box>
<Text>Your MetaMask wallet is now compatible with Starknet!</Text>
<Text>
To manage your Starknet account and send and receive funds, visit the{' '}
<Link href={getDappUrl()}>companion dapp for Starknet</Link>.
</Text>
</Box>,
);
};

export const onUpdate: OnUpdateHandler = async () => {
await snap.request({
method: 'snap_dialog',
params: {
type: 'alert',
content: (
<Box>
<Text>Your Starknet Snap is now up-to-date !</Text>
<Text>
As usual, to manage your Starknet account and send and receive
funds, visit the{' '}
<Link href={getDappUrl()}>companion dapp for Starknet</Link>.
</Text>
</Box>
),
},
});
await ensureJsxSupport(
<Box>
<Text>Your Starknet Snap is now up-to-date !</Text>
<Text>
As usual, to manage your Starknet account and send and receive funds,
visit the <Link href={getDappUrl()}>companion dapp for Starknet</Link>.
</Text>
</Box>,
);
};

export const onHomePage: OnHomePageHandler = async () => {
Expand Down
1 change: 1 addition & 0 deletions packages/starknet-snap/src/state/state-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export abstract class StateManager<Entity> extends SnapStateManager<SnapState> {
erc20Tokens: [],
networks: [],
transactions: [],
requireMMUpgrade: undefined,
transactionRequests: [],
};
}
Expand Down
1 change: 1 addition & 0 deletions packages/starknet-snap/src/types/snapState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export type SnapState = {
networks: Network[];
transactions: Transaction[];
currentNetwork?: Network;
requireMMUpgrade?: boolean;
transactionRequests?: TransactionRequest[];
};

Expand Down
43 changes: 42 additions & 1 deletion packages/starknet-snap/src/utils/snap-ui.ts
Original file line number Diff line number Diff line change
@@ -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<void> => {
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.
*
Expand Down

0 comments on commit 6531485

Please sign in to comment.