Skip to content

Commit a197a06

Browse files
committed
Support calling wallet_requestExecutionPermissions directly on the walletApi
1 parent a22ecb5 commit a197a06

4 files changed

Lines changed: 499 additions & 367 deletions

File tree

packages/delegation-toolkit/src/experimental/erc7715RequestExecutionPermissionsAction.ts

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type {
1111
} from '@metamask/7715-permission-types';
1212
import { isHex, toHex, type Address } from 'viem';
1313

14-
import type { SnapClient } from './snapsAuthorization.js';
14+
import type { MetaMaskExtensionClient } from './snapsAuthorization.js';
1515

1616
type PermissionParameter = {
1717
type: string;
@@ -125,38 +125,50 @@ export type RequestExecutionPermissionsReturnType = PermissionResponse<
125125
* @template Signer - The type of the signer, either an Address or Account.
126126
* @param client - The client to use for the request.
127127
* @param parameters - The permissions requests to grant.
128-
* @param kernelSnapId - The ID of the kernel snap to invoke, defaults to 'npm:@metamask/permissions-kernel-snap'.
128+
* @param kernelSnapId - The ID of the kernel snap to invoke, undefined to request via the wallet RPC method.
129129
* @returns A promise that resolves to the permission responses.
130130
* @description
131131
* This function formats the permissions requests and invokes the wallet snap to grant permissions.
132132
* It will throw an error if the permissions could not be granted.
133133
*/
134134
export async function erc7715RequestExecutionPermissionsAction(
135-
client: SnapClient,
135+
client: MetaMaskExtensionClient,
136136
parameters: RequestExecutionPermissionsParameters,
137-
kernelSnapId = 'npm:@metamask/permissions-kernel-snap',
137+
kernelSnapId: string | undefined,
138138
): Promise<RequestExecutionPermissionsReturnType> {
139-
const formattedParameters = parameters.map(formatPermissionsRequest);
140-
141-
const result = await client.request(
142-
{
143-
method: 'wallet_invokeSnap',
144-
params: {
145-
snapId: kernelSnapId,
146-
request: {
147-
method: 'wallet_requestExecutionPermissions',
148-
params: formattedParameters,
139+
const formattedPermissionRequest = parameters.map(formatPermissionsRequest);
140+
141+
let result: PermissionResponse<AccountSigner, PermissionTypes>[] | null;
142+
143+
if (kernelSnapId) {
144+
result = await client.request(
145+
{
146+
method: 'wallet_invokeSnap',
147+
params: {
148+
snapId: kernelSnapId,
149+
request: {
150+
method: 'wallet_requestExecutionPermissions',
151+
params: formattedPermissionRequest,
152+
},
149153
},
150154
},
151-
},
152-
{ retryCount: 0 },
153-
);
155+
{ retryCount: 0 },
156+
);
157+
} else {
158+
result = await client.request(
159+
{
160+
method: 'wallet_requestExecutionPermissions',
161+
params: formattedPermissionRequest,
162+
},
163+
{ retryCount: 0 },
164+
);
165+
}
154166

155-
if (result === null) {
167+
if (!result) {
156168
throw new Error('Failed to grant permissions');
157169
}
158170

159-
return result as any as RequestExecutionPermissionsReturnType;
171+
return result;
160172
}
161173

162174
/**

packages/delegation-toolkit/src/experimental/index.ts

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
import { erc7715RequestExecutionPermissionsAction } from './erc7715RequestExecutionPermissionsAction';
1313
import type { RequestExecutionPermissionsParameters } from './erc7715RequestExecutionPermissionsAction';
1414
import { ensureSnapsAuthorized } from './snapsAuthorization';
15-
import type { SnapClient } from './snapsAuthorization';
15+
import type { MetaMaskExtensionClient } from './snapsAuthorization';
1616

1717
export {
1818
erc7715RequestExecutionPermissionsAction as requestExecutionPermissions,
@@ -27,20 +27,48 @@ export {
2727
type DelegationStorageConfig,
2828
} from './delegationStorage';
2929

30+
type Erc7715ProviderConfig = {
31+
useWalletMethod: boolean;
32+
snapIds?: {
33+
kernelSnapId?: string;
34+
providerSnapId?: string;
35+
};
36+
};
37+
3038
export const erc7715ProviderActions =
31-
(snapIds?: { kernelSnapId: string; providerSnapId: string }) =>
39+
(erc7715ProviderConfig: Erc7715ProviderConfig = { useWalletMethod: false }) =>
3240
(client: Client) => ({
3341
requestExecutionPermissions: async (
3442
parameters: RequestExecutionPermissionsParameters,
3543
) => {
36-
if (!(await ensureSnapsAuthorized(client as SnapClient, snapIds))) {
37-
throw new Error('Snaps not authorized');
44+
const { useWalletMethod, snapIds } = erc7715ProviderConfig;
45+
46+
let kernelSnapId: string | undefined;
47+
48+
if (!useWalletMethod) {
49+
kernelSnapId =
50+
snapIds?.kernelSnapId ?? 'npm:@metamask/permissions-kernel-snap';
51+
52+
const snapIdsToAuthorize = {
53+
kernelSnapId,
54+
providerSnapId:
55+
snapIds?.providerSnapId ?? 'npm:@metamask/gator-permissions-snap',
56+
};
57+
58+
if (
59+
!(await ensureSnapsAuthorized(
60+
client as MetaMaskExtensionClient,
61+
snapIdsToAuthorize,
62+
))
63+
) {
64+
throw new Error('Snaps not authorized');
65+
}
3866
}
3967

4068
return erc7715RequestExecutionPermissionsAction(
41-
client as SnapClient,
69+
client as MetaMaskExtensionClient,
4270
parameters,
43-
snapIds?.kernelSnapId,
71+
kernelSnapId,
4472
);
4573
},
4674
});

packages/delegation-toolkit/src/experimental/snapsAuthorization.ts

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
import type {
2+
AccountSigner,
3+
PermissionRequest,
4+
PermissionResponse,
5+
PermissionTypes,
6+
} from '@metamask/7715-permission-types';
17
import type { Account, Chain, Client, RpcSchema, Transport } from 'viem';
28

39
/**
@@ -14,14 +20,14 @@ export type SnapAuthorizations = Record<
1420
>;
1521

1622
/**
17-
* RPC schema for MetaMask Snap-related methods.
23+
* RPC schema for MetaMask related methods.
1824
*
1925
* Extends the base RPC schema with methods specific to interacting with Snaps:
2026
* - `wallet_invokeSnap`: Invokes a method on a specific Snap.
2127
* - `wallet_getSnaps`: Retrieves all installed Snaps and their authorization status.
2228
* - `wallet_requestSnaps`: Requests permission to use specific Snaps.
2329
*/
24-
export type SnapRpcSchema = RpcSchema &
30+
export type MetaMaskExtensionSchema = RpcSchema &
2531
[
2632
{
2733
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -53,6 +59,14 @@ export type SnapRpcSchema = RpcSchema &
5359
// eslint-disable-next-line @typescript-eslint/naming-convention
5460
ReturnType: SnapAuthorizations;
5561
},
62+
{
63+
// eslint-disable-next-line @typescript-eslint/naming-convention
64+
Method: 'wallet_requestExecutionPermissions';
65+
// eslint-disable-next-line @typescript-eslint/naming-convention
66+
Params: PermissionRequest<AccountSigner, PermissionTypes>[];
67+
// eslint-disable-next-line @typescript-eslint/naming-convention
68+
ReturnType: PermissionResponse<AccountSigner, PermissionTypes>[];
69+
},
5670
];
5771

5872
/**
@@ -62,11 +76,11 @@ export type SnapRpcSchema = RpcSchema &
6276
* the standard Viem client interface, with added type safety for
6377
* Snap-specific methods.
6478
*/
65-
export type SnapClient = Client<
79+
export type MetaMaskExtensionClient = Client<
6680
Transport,
6781
Chain | undefined,
6882
Account | undefined,
69-
SnapRpcSchema
83+
MetaMaskExtensionSchema
7084
>;
7185

7286
/**
@@ -94,7 +108,7 @@ const isSnapAuthorized = (
94108
* @param snapId - The ID of the snap to re-authorize.
95109
* @returns A promise that resolves to a boolean indicating whether the snap was re-authorized.
96110
*/
97-
const reAuthorize = async (client: SnapClient, snapId: string) => {
111+
const reAuthorize = async (client: MetaMaskExtensionClient, snapId: string) => {
98112
const newAuthorizations = await client.request({
99113
method: 'wallet_requestSnaps',
100114
params: {
@@ -118,14 +132,12 @@ const reAuthorize = async (client: SnapClient, snapId: string) => {
118132
* It returns true only if both snaps are successfully authorized.
119133
*/
120134
export async function ensureSnapsAuthorized(
121-
client: SnapClient,
122-
snapIds?: { kernelSnapId: string; providerSnapId: string },
135+
client: MetaMaskExtensionClient,
136+
{
137+
kernelSnapId,
138+
providerSnapId,
139+
}: { kernelSnapId: string; providerSnapId: string },
123140
) {
124-
const kernelSnapId =
125-
snapIds?.kernelSnapId ?? 'npm:@metamask/permissions-kernel-snap';
126-
const providerSnapId =
127-
snapIds?.providerSnapId ?? 'npm:@metamask/gator-permissions-snap';
128-
129141
const existingAuthorizations = await client.request({
130142
method: 'wallet_getSnaps',
131143
params: {} as Record<string, never>,

0 commit comments

Comments
 (0)