Skip to content

Commit e0b844a

Browse files
Refactor protocol caveats
1 parent 5c33d44 commit e0b844a

File tree

6 files changed

+37
-79
lines changed

6 files changed

+37
-79
lines changed

packages/snaps-controllers/src/multichain/MultichainRoutingController.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,10 @@ import type {
44
ControllerStateChangeEvent,
55
} from '@metamask/base-controller';
66
import { BaseController } from '@metamask/base-controller';
7-
import type {
8-
Caveat,
9-
GetPermissions,
10-
ValidPermission,
11-
} from '@metamask/permission-controller';
7+
import type { GetPermissions } from '@metamask/permission-controller';
128
import { rpcErrors } from '@metamask/rpc-errors';
139
import {
14-
getProtocolCaveatChainIds,
15-
getProtocolCaveatRpcMethods,
10+
getProtocolCaveatChains,
1611
SnapEndowments,
1712
} from '@metamask/snaps-rpc-methods';
1813
import type {
@@ -103,9 +98,9 @@ export type MultichainRoutingControllerArgs = {
10398

10499
export type MultichainRoutingControllerState = EmptyObject;
105100

106-
type SnapWithPermission = {
101+
type ProtocolSnap = {
107102
snapId: SnapId;
108-
permission: ValidPermission<string, Caveat<string, Json>>;
103+
methods: string[];
109104
};
110105

111106
const controllerName = 'MultichainRoutingController';
@@ -223,18 +218,18 @@ export class MultichainRoutingController extends BaseController<
223218
const allSnaps = this.messagingSystem.call('SnapController:getAll');
224219
const filteredSnaps = getRunnableSnaps(allSnaps);
225220

226-
return filteredSnaps.reduce<SnapWithPermission[]>((accumulator, snap) => {
221+
return filteredSnaps.reduce<ProtocolSnap[]>((accumulator, snap) => {
227222
const permissions = this.messagingSystem.call(
228223
'PermissionController:getPermissions',
229224
snap.id,
230225
);
231226
if (permissions && hasProperty(permissions, SnapEndowments.Protocol)) {
232227
const permission = permissions[SnapEndowments.Protocol];
233-
const chains = getProtocolCaveatChainIds(permission);
234-
if (chains?.includes(chainId)) {
228+
const chains = getProtocolCaveatChains(permission);
229+
if (chains && hasProperty(chains, chainId)) {
235230
accumulator.push({
236231
snapId: snap.id,
237-
permission,
232+
methods: chains[chainId].methods,
238233
});
239234
}
240235
}
@@ -276,7 +271,7 @@ export class MultichainRoutingController extends BaseController<
276271
// but has a protocol Snap available, route it there.
277272
const protocolSnaps = this.#getProtocolSnaps(chainId);
278273
const protocolSnap = protocolSnaps.find((snap) =>
279-
getProtocolCaveatRpcMethods(snap.permission)?.includes(method),
274+
snap.methods.includes(method),
280275
);
281276
if (protocolSnap) {
282277
return this.messagingSystem.call('SnapController:handleRequest', {

packages/snaps-controllers/src/test-utils/multichain.ts

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,8 @@ export const MOCK_SOLANA_SNAP_PERMISSIONS: Record<
6565
[SnapEndowments.Keyring]: {
6666
caveats: [
6767
{
68-
type: SnapCaveatType.ChainIds,
69-
value: [SOLANA_CAIP2],
70-
},
71-
{
72-
type: SnapCaveatType.SnapRpcMethods,
73-
value: ['getVersion'],
68+
type: SnapCaveatType.KeyringOrigin,
69+
value: { allowedOrigins: [] },
7470
},
7571
],
7672
date: 1664187844588,
@@ -81,12 +77,8 @@ export const MOCK_SOLANA_SNAP_PERMISSIONS: Record<
8177
[SnapEndowments.Protocol]: {
8278
caveats: [
8379
{
84-
type: SnapCaveatType.ChainIds,
85-
value: [SOLANA_CAIP2],
86-
},
87-
{
88-
type: SnapCaveatType.SnapRpcMethods,
89-
value: ['getVersion'],
80+
type: SnapCaveatType.ProtocolSnapChains,
81+
value: { [SOLANA_CAIP2]: { methods: ['getVersion'] } },
9082
},
9183
],
9284
date: 1664187844588,

packages/snaps-rpc-methods/src/endowments/index.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,4 @@ export { getChainIdsCaveat, getLookupMatchersCaveat } from './name-lookup';
128128
export { getKeyringCaveatOrigins } from './keyring';
129129
export { getMaxRequestTimeCaveat } from './caveats';
130130
export { getCronjobCaveatJobs } from './cronjob';
131-
export {
132-
getProtocolCaveatChainIds,
133-
getProtocolCaveatRpcMethods,
134-
} from './protocol';
131+
export { getProtocolCaveatChains } from './protocol';

packages/snaps-rpc-methods/src/endowments/protocol.ts

Lines changed: 16 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,8 @@ import type {
1010
} from '@metamask/permission-controller';
1111
import { PermissionType, SubjectType } from '@metamask/permission-controller';
1212
import { rpcErrors } from '@metamask/rpc-errors';
13-
import {
14-
ProtocolRpcMethodsStruct,
15-
SnapCaveatType,
16-
} from '@metamask/snaps-utils';
13+
import { ProtocolChainsStruct, SnapCaveatType } from '@metamask/snaps-utils';
14+
import type { Infer } from '@metamask/superstruct';
1715
import type { Json, NonEmptyArray } from '@metamask/utils';
1816
import {
1917
assertStruct,
@@ -51,15 +49,10 @@ const specificationBuilder: PermissionSpecificationBuilder<
5149
return {
5250
permissionType: PermissionType.Endowment,
5351
targetName: permissionName,
54-
allowedCaveats: [
55-
SnapCaveatType.ChainIds,
56-
SnapCaveatType.SnapRpcMethods,
57-
SnapCaveatType.MaxRequestTime,
58-
],
52+
allowedCaveats: [SnapCaveatType.ChainIds, SnapCaveatType.MaxRequestTime],
5953
endowmentGetter: (_getterOptions?: EndowmentGetterParams) => null,
6054
validator: createGenericPermissionValidator([
61-
{ type: SnapCaveatType.ChainIds },
62-
{ type: SnapCaveatType.SnapRpcMethods },
55+
{ type: SnapCaveatType.ProtocolSnapChains },
6356
{ type: SnapCaveatType.MaxRequestTime, optional: true },
6457
]),
6558
subjectTypes: [SubjectType.Snap],
@@ -90,51 +83,29 @@ export function getProtocolCaveatMapper(
9083

9184
if (value.chains) {
9285
caveats.push({
93-
type: SnapCaveatType.ChainIds,
86+
type: SnapCaveatType.ProtocolSnapChains,
9487
value: value.chains,
9588
});
9689
}
9790

98-
if (value.methods) {
99-
caveats.push({
100-
type: SnapCaveatType.SnapRpcMethods,
101-
value: value.methods,
102-
});
103-
}
104-
10591
return { caveats: caveats as NonEmptyArray<CaveatConstraint> };
10692
}
10793

108-
/**
109-
* Getter function to get the {@link ChainIds} caveat value from a
110-
* permission.
111-
*
112-
* @param permission - The permission to get the caveat value from.
113-
* @returns The caveat value.
114-
*/
115-
export function getProtocolCaveatChainIds(
116-
permission?: PermissionConstraint,
117-
): string[] | null {
118-
const caveat = permission?.caveats?.find(
119-
(permCaveat) => permCaveat.type === SnapCaveatType.ChainIds,
120-
) as Caveat<string, string[]> | undefined;
121-
122-
return caveat ? caveat.value : null;
123-
}
94+
export type ProtocolChains = Infer<typeof ProtocolChainsStruct>;
12495

12596
/**
126-
* Getter function to get the {@link SnapRpcMethods} caveat value from a
97+
* Getter function to get the {@link ProtocolSnapChains} caveat value from a
12798
* permission.
12899
*
129100
* @param permission - The permission to get the caveat value from.
130101
* @returns The caveat value.
131102
*/
132-
export function getProtocolCaveatRpcMethods(
103+
export function getProtocolCaveatChains(
133104
permission?: PermissionConstraint,
134-
): string[] | null {
105+
): ProtocolChains | null {
135106
const caveat = permission?.caveats?.find(
136-
(permCaveat) => permCaveat.type === SnapCaveatType.SnapRpcMethods,
137-
) as Caveat<string, string[]> | undefined;
107+
(permCaveat) => permCaveat.type === SnapCaveatType.ProtocolSnapChains,
108+
) as Caveat<string, ProtocolChains> | undefined;
138109

139110
return caveat ? caveat.value : null;
140111
}
@@ -155,18 +126,18 @@ function validateCaveat(caveat: Caveat<string, any>): void {
155126
const { value } = caveat;
156127
assertStruct(
157128
value,
158-
ProtocolRpcMethodsStruct,
159-
'Invalid RPC methods specified',
129+
ProtocolChainsStruct,
130+
'Invalid chains specified',
160131
rpcErrors.invalidParams,
161132
);
162133
}
163134

164135
export const protocolCaveatSpecifications: Record<
165-
SnapCaveatType.SnapRpcMethods,
136+
SnapCaveatType.ProtocolSnapChains,
166137
CaveatSpecificationConstraint
167138
> = {
168-
[SnapCaveatType.SnapRpcMethods]: Object.freeze({
169-
type: SnapCaveatType.SnapRpcMethods,
139+
[SnapCaveatType.ProtocolSnapChains]: Object.freeze({
140+
type: SnapCaveatType.ProtocolSnapChains,
170141
validator: (caveat: Caveat<string, any>) => validateCaveat(caveat),
171142
}),
172143
};

packages/snaps-utils/src/caveats.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,5 @@ export enum SnapCaveatType {
5757
/**
5858
* Caveat specifying a list of RPC methods serviced by an endowment.
5959
*/
60-
SnapRpcMethods = 'snapRpcMethods',
60+
ProtocolSnapChains = 'protocolSnapChains',
6161
}

packages/snaps-utils/src/manifest/validation.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
isValidSemVerRange,
2828
inMilliseconds,
2929
Duration,
30+
CaipChainIdStruct,
3031
} from '@metamask/utils';
3132

3233
import { isEqual } from '../array';
@@ -174,8 +175,10 @@ export const MaxRequestTimeStruct = size(
174175
MAXIMUM_REQUEST_TIMEOUT,
175176
);
176177

177-
// TODO: Decide on the format for this
178-
export const ProtocolRpcMethodsStruct = array(string());
178+
export const ProtocolChainsStruct = record(
179+
CaipChainIdStruct,
180+
object({ methods: array(string()) }),
181+
);
179182

180183
// Utility type to union with for all handler structs
181184
export const HandlerCaveatsStruct = object({
@@ -204,7 +207,7 @@ export const PermissionsStruct: Describe<InitialPermissions> = type({
204207
'endowment:protocol': optional(
205208
mergeStructs(
206209
HandlerCaveatsStruct,
207-
object({ chains: ChainIdsStruct, methods: ProtocolRpcMethodsStruct }),
210+
object({ chains: ProtocolChainsStruct }),
208211
),
209212
),
210213
'endowment:lifecycle-hooks': optional(HandlerCaveatsStruct),

0 commit comments

Comments
 (0)