Skip to content

Commit 749a38f

Browse files
committed
update example snap and test snap
1 parent b78c61c commit 749a38f

File tree

7 files changed

+181
-19
lines changed

7 files changed

+181
-19
lines changed

packages/examples/packages/settings-page/snap.manifest.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"url": "https://github.com/MetaMask/snaps.git"
88
},
99
"source": {
10-
"shasum": "9xTn79sMhMLJJgSKn/6kfI+VTEKv9J1acTVlM2Le2ac=",
10+
"shasum": "vNHZLaHQGoWJeGCfYv0fGjVYdz+aBdcPwfkcpeKK+ks=",
1111
"location": {
1212
"npm": {
1313
"filePath": "dist/bundle.js",
@@ -17,7 +17,11 @@
1717
}
1818
},
1919
"initialPermissions": {
20-
"endowment:page-settings": {}
20+
"endowment:rpc": {
21+
"dapps": true
22+
},
23+
"endowment:page-settings": {},
24+
"snap_manageState": {}
2125
},
2226
"platformVersion": "6.13.0",
2327
"manifestVersion": "0.1"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {
2+
Box,
3+
Checkbox,
4+
Dropdown,
5+
Option,
6+
Radio,
7+
RadioGroup,
8+
SettingCell,
9+
type SnapComponent,
10+
} from '@metamask/snaps-sdk/jsx';
11+
12+
export type SettingsPageProps = {
13+
setting1?: boolean;
14+
setting2?: 'option1' | 'option2';
15+
setting3?: 'option1' | 'option2';
16+
};
17+
18+
/**
19+
* A settings page component that displays three settings.
20+
*
21+
* @param param - The settings page props.
22+
* @param param.setting1 - The first setting.
23+
* @param param.setting2 - The second setting.
24+
* @param param.setting3 - The third setting.
25+
* @returns The settings page component.
26+
*/
27+
export const SettingsPage: SnapComponent<SettingsPageProps> = ({
28+
setting1,
29+
setting2,
30+
setting3,
31+
}) => (
32+
<Box>
33+
<SettingCell title="Setting 1" description="This is the first setting">
34+
<Checkbox name="setting1" variant="toggle" checked={setting1} />
35+
</SettingCell>
36+
<SettingCell title="Setting 2" description="This is the second setting">
37+
<RadioGroup name="setting2" value={setting2}>
38+
<Radio value="option1">Option 1</Radio>
39+
<Radio value="option2">Option 2</Radio>
40+
</RadioGroup>
41+
</SettingCell>
42+
<SettingCell title="Setting 3" description="This is the third setting">
43+
<Dropdown name="setting3" value={setting3}>
44+
<Option value="option1">Option 1</Option>
45+
<Option value="option2">Option 2</Option>
46+
</Dropdown>
47+
</SettingCell>
48+
</Box>
49+
);
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { describe, it } from '@jest/globals';
22
import { installSnap } from '@metamask/snaps-jest';
3-
import { Box, Heading, Text } from '@metamask/snaps-sdk/jsx';
3+
4+
import { SettingsPage } from './components/SettingsPage';
45

56
describe('onSettingsPage', () => {
67
it('returns custom UI', async () => {
@@ -10,11 +11,6 @@ describe('onSettingsPage', () => {
1011

1112
const screen = response.getInterface();
1213

13-
expect(screen).toRender(
14-
<Box>
15-
<Heading>Hello world!</Heading>
16-
<Text>Welcome to my Snap settings page!</Text>
17-
</Box>,
18-
);
14+
expect(screen).toRender(<SettingsPage />);
1915
});
2016
});
Lines changed: 88 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,47 @@
1-
import type { OnSettingsPageHandler } from '@metamask/snaps-sdk';
2-
import { Box, Heading, Text } from '@metamask/snaps-sdk/jsx';
1+
import type { OnRpcRequestHandler } from '@metamask/snaps-sdk';
2+
import {
3+
MethodNotFoundError,
4+
UserInputEventType,
5+
type OnSettingsPageHandler,
6+
type OnUserInputHandler,
7+
} from '@metamask/snaps-sdk';
8+
9+
import { SettingsPage } from './components/SettingsPage';
10+
11+
type SnapState = {
12+
setting1?: boolean;
13+
setting2?: 'option1' | 'option2';
14+
setting3?: 'option1' | 'option2';
15+
};
16+
17+
/**
18+
* Handle incoming JSON-RPC requests from the dapp, sent through the
19+
* `wallet_invokeSnap` method. This handler handles one method:
20+
*
21+
* - `getSettings`: get the settings state from the snap state.
22+
*
23+
* @param params - The request parameters.
24+
* @param params.request - The JSON-RPC request object.
25+
* @returns The JSON-RPC response.
26+
* @see https://docs.metamask.io/snaps/reference/exports/#onrpcrequest
27+
* @see https://docs.metamask.io/snaps/reference/rpc-api/#wallet_invokesnap
28+
* @see https://docs.metamask.io/snaps/reference/rpc-api/#snap_notify
29+
*/
30+
export const onRpcRequest: OnRpcRequestHandler = async ({ request }) => {
31+
switch (request.method) {
32+
case 'getSettings':
33+
return await snap.request({
34+
method: 'snap_manageState',
35+
params: {
36+
operation: 'get',
37+
encrypted: false,
38+
},
39+
});
40+
default:
41+
// eslint-disable-next-line @typescript-eslint/no-throw-literal
42+
throw new MethodNotFoundError({ method: request.method });
43+
}
44+
};
345

446
/**
547
* Handle incoming settings page requests from the MetaMask clients.
@@ -8,12 +50,52 @@ import { Box, Heading, Text } from '@metamask/snaps-sdk/jsx';
850
* @see https://docs.metamask.io/snaps/reference/exports/#onsettingspage
951
*/
1052
export const onSettingsPage: OnSettingsPageHandler = async () => {
53+
const state: SnapState | null = await snap.request({
54+
method: 'snap_manageState',
55+
params: {
56+
operation: 'get',
57+
encrypted: false,
58+
},
59+
});
60+
1161
return {
1262
content: (
13-
<Box>
14-
<Heading>Hello world!</Heading>
15-
<Text>Welcome to my Snap settings page!</Text>
16-
</Box>
63+
<SettingsPage
64+
setting1={state?.setting1}
65+
setting2={state?.setting2}
66+
setting3={state?.setting3}
67+
/>
1768
),
1869
};
1970
};
71+
72+
/**
73+
* Handle incoming user events coming from the MetaMask clients open interfaces.
74+
*
75+
* @param params - The event parameters.
76+
* @param params.event - The event object containing the event type, name and value.
77+
* @see https://docs.metamask.io/snaps/reference/exports/#onuserinput
78+
*/
79+
export const onUserInput: OnUserInputHandler = async ({ event }) => {
80+
if (event.type === UserInputEventType.InputChangeEvent) {
81+
const state = await snap.request({
82+
method: 'snap_manageState',
83+
params: {
84+
operation: 'get',
85+
encrypted: false,
86+
},
87+
});
88+
89+
await snap.request({
90+
method: 'snap_manageState',
91+
params: {
92+
operation: 'update',
93+
encrypted: false,
94+
newState: {
95+
...state,
96+
[event.name]: event.value,
97+
},
98+
},
99+
});
100+
}
101+
};

packages/snaps-rpc-methods/src/permitted/createInterface.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ describe('snap_createInterface', () => {
141141
error: {
142142
code: -32602,
143143
message:
144-
'Invalid params: At path: ui -- Expected type to be one of: "Address", "Bold", "Box", "Button", "Copyable", "Divider", "Dropdown", "RadioGroup", "Field", "FileInput", "Form", "Heading", "Input", "Image", "Italic", "Link", "Row", "Spinner", "Text", "Tooltip", "Checkbox", "Card", "Icon", "Selector", "Section", "Avatar", "Container", but received: undefined.',
144+
'Invalid params: At path: ui -- Expected type to be one of: "Address", "Bold", "Box", "Button", "Copyable", "Divider", "Dropdown", "RadioGroup", "Field", "FileInput", "Form", "Heading", "Input", "Image", "Italic", "Link", "Row", "Spinner", "Text", "Tooltip", "Checkbox", "Card", "Icon", "Selector", "Section", "Avatar", "SettingCell", "Container", but received: undefined.',
145145
stack: expect.any(String),
146146
},
147147
id: 1,

packages/test-snaps/src/features/snaps/send-flow/SendFlow.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,12 @@ export const SendFlow: FunctionComponent = () => {
3030
version={SEND_FLOW_VERSION}
3131
testId="dialogs"
3232
>
33-
<Button id="display" onClick={handleSubmitDisplay} disabled={isLoading}>
33+
<Button
34+
id="display"
35+
onClick={handleSubmitDisplay}
36+
disabled={isLoading}
37+
className="mb-3"
38+
>
3439
Custom
3540
</Button>
3641

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,46 @@
1+
import { logError } from '@metamask/snaps-utils';
12
import type { FunctionComponent } from 'react';
3+
import { Button } from 'react-bootstrap';
4+
import { useInvokeMutation } from 'src/api';
5+
import { getSnapId } from 'src/utils';
26

3-
import { Snap } from '../../../components';
7+
import { Result, Snap } from '../../../components';
48
import {
59
SETTINGS_PAGE_SNAP_ID,
610
SETTINGS_PAGE_SNAP_PORT,
711
SETTINGS_PAGE_VERSION,
812
} from './constants';
913

1014
export const SettingsPage: FunctionComponent = () => {
15+
const [invokeSnap, { isLoading, data }] = useInvokeMutation();
16+
const snapId = getSnapId(SETTINGS_PAGE_SNAP_ID, SETTINGS_PAGE_SNAP_PORT);
17+
18+
const handleSubmit = () => {
19+
invokeSnap({
20+
snapId,
21+
method: 'getSettings',
22+
}).catch(logError);
23+
};
1124
return (
1225
<Snap
1326
name="Settings Page Snap"
1427
snapId={SETTINGS_PAGE_SNAP_ID}
1528
port={SETTINGS_PAGE_SNAP_PORT}
1629
version={SETTINGS_PAGE_VERSION}
1730
testId="settingspage"
18-
/>
31+
>
32+
<Button
33+
id="settings-state"
34+
onClick={handleSubmit}
35+
disabled={isLoading}
36+
className="mb-3"
37+
>
38+
Get settings state
39+
</Button>
40+
41+
<Result>
42+
<span id="settingsResult">{JSON.stringify(data, null, 2)}</span>
43+
</Result>
44+
</Snap>
1945
);
2046
};

0 commit comments

Comments
 (0)