Skip to content

Commit a7fad31

Browse files
authored
chore: Update gator-permissions-controller package to comply with 7715 spec revisions (#7613)
## Explanation This PR updates the `@metamask/gator-permissions-controller` package to comply with 7715 spec revisions: - Bumps `@metamask/7715-permission-types`: `0.4.0` -> `0.5.0` - Updated core logic to resolve type compatibility issues ## References * Requires MetaMask/smart-accounts-kit#128 * Related to ERC-7715: [Simplify specification to ease wallet implementation](ethereum/ERCs#1098) ## Checklist - [x] I've updated the test suite for new or updated code as appropriate - [x] I've updated documentation (JSDoc, Markdown, etc.) for new or updated code as appropriate - [x] I've communicated my changes to consumers by [updating changelogs for packages I've changed](https://github.com/MetaMask/core/tree/main/docs/processes/updating-changelogs.md) - [ ] I've introduced [breaking changes](https://github.com/MetaMask/core/tree/main/docs/processes/breaking-changes.md) in this PR and have prepared draft pull requests for clients and consumer packages to resolve them <!-- CURSOR_SUMMARY --> --- > [!NOTE] > - **Dependency bump:** `@metamask/7715-permission-types` to `^0.5.0`. > - **BREAKING types:** Replace `address`/`signer` with `from`/`to`; rename `dependencyInfo` → `dependencies`; surface `delegationManager`. Update `PermissionRequest`, `PermissionResponse`, `StoredGatorPermission`, and `*Sanitized` (`sanitize` now removes `dependencies` and `to`). > - **Decoding changes:** `DecodedPermission` now returns `from`/`to`; `reconstructDecodedPermission` and controller `decodePermissionFromPermissionContextForOrigin` updated accordingly. > - **Controller updates:** Adjust sanitization/categorization to new shapes; add explicit return types; no behavior change beyond new field names. > - **Tests/mocks:** Updated fixtures and assertions to new fields; added expectations for sanitization. Changelog notes breaking change. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 34a21f4. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent d4c3591 commit a7fad31

File tree

12 files changed

+164
-247
lines changed

12 files changed

+164
-247
lines changed

eslint-suppressions.json

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,24 +1092,13 @@
10921092
}
10931093
},
10941094
"packages/gator-permissions-controller/src/GatorPermissionsController.test.ts": {
1095-
"@typescript-eslint/explicit-function-return-type": {
1096-
"count": 2
1097-
},
10981095
"id-denylist": {
10991096
"count": 2
1100-
},
1101-
"no-new": {
1102-
"count": 1
11031097
}
11041098
},
11051099
"packages/gator-permissions-controller/src/GatorPermissionsController.ts": {
11061100
"@typescript-eslint/explicit-function-return-type": {
1107-
"count": 16
1108-
}
1109-
},
1110-
"packages/gator-permissions-controller/src/decodePermission/decodePermission.ts": {
1111-
"@typescript-eslint/explicit-function-return-type": {
1112-
"count": 1
1101+
"count": 8
11131102
}
11141103
},
11151104
"packages/gator-permissions-controller/src/decodePermission/utils.test.ts": {
@@ -1128,11 +1117,6 @@
11281117
"count": 1
11291118
}
11301119
},
1131-
"packages/gator-permissions-controller/src/test/mocks.ts": {
1132-
"@typescript-eslint/explicit-function-return-type": {
1133-
"count": 1
1134-
}
1135-
},
11361120
"packages/logging-controller/src/LoggingController.test.ts": {
11371121
"@typescript-eslint/explicit-function-return-type": {
11381122
"count": 1

packages/gator-permissions-controller/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1414
- Bump `@metamask/snaps-utils` from `^11.0.0` to `^11.7.0` ([#7550](https://github.com/MetaMask/core/pull/7550))
1515
- Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511))
1616
- Bump `@metamask/transaction-controller` from `^62.5.0` to `^62.9.1` ([#7430](https://github.com/MetaMask/core/pull/7430), [#7494](https://github.com/MetaMask/core/pull/7494), [#7596](https://github.com/MetaMask/core/pull/7596), [#7602](https://github.com/MetaMask/core/pull/7602), [#7604](https://github.com/MetaMask/core/pull/7604))
17+
- **BREAKING:** Gator Permissions Controller and Gator Permission Decoder core types have been updated to comply with 7715 spec revisions ([#7613](https://github.com/MetaMask/core/pull/7613))
18+
- Bump `@metamask/7715-permission-type` from `^0.4.0` to `^0.5.0`
1719

1820
## [0.8.0]
1921

packages/gator-permissions-controller/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
4949
},
5050
"dependencies": {
51-
"@metamask/7715-permission-types": "^0.4.0",
51+
"@metamask/7715-permission-types": "^0.5.0",
5252
"@metamask/base-controller": "^9.0.0",
5353
"@metamask/delegation-core": "^0.2.0",
5454
"@metamask/delegation-deployments": "^0.12.0",

packages/gator-permissions-controller/src/GatorPermissionsController.test.ts

Lines changed: 51 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { AccountSigner } from '@metamask/7715-permission-types';
21
import { deriveStateFromMetadata } from '@metamask/base-controller';
32
import {
43
createTimestampTerms,
@@ -45,45 +44,43 @@ const MOCK_CHAIN_ID_1: Hex = '0xaa36a7';
4544
const MOCK_CHAIN_ID_2: Hex = '0x1';
4645
const MOCK_GATOR_PERMISSIONS_PROVIDER_SNAP_ID =
4746
'local:http://localhost:8082' as SnapId;
48-
const MOCK_GATOR_PERMISSIONS_STORAGE_ENTRIES: StoredGatorPermission<
49-
AccountSigner,
50-
PermissionTypesWithCustom
51-
>[] = mockGatorPermissionsStorageEntriesFactory({
52-
[MOCK_CHAIN_ID_1]: {
53-
nativeTokenStream: 5,
54-
nativeTokenPeriodic: 5,
55-
erc20TokenStream: 5,
56-
erc20TokenPeriodic: 5,
57-
custom: {
58-
count: 2,
59-
data: [
60-
{
61-
customData: 'customData-0',
62-
},
63-
{
64-
customData: 'customData-1',
65-
},
66-
],
47+
const MOCK_GATOR_PERMISSIONS_STORAGE_ENTRIES: StoredGatorPermission<PermissionTypesWithCustom>[] =
48+
mockGatorPermissionsStorageEntriesFactory({
49+
[MOCK_CHAIN_ID_1]: {
50+
nativeTokenStream: 5,
51+
nativeTokenPeriodic: 5,
52+
erc20TokenStream: 5,
53+
erc20TokenPeriodic: 5,
54+
custom: {
55+
count: 2,
56+
data: [
57+
{
58+
customData: 'customData-0',
59+
},
60+
{
61+
customData: 'customData-1',
62+
},
63+
],
64+
},
6765
},
68-
},
69-
[MOCK_CHAIN_ID_2]: {
70-
nativeTokenStream: 5,
71-
nativeTokenPeriodic: 5,
72-
erc20TokenStream: 5,
73-
erc20TokenPeriodic: 5,
74-
custom: {
75-
count: 2,
76-
data: [
77-
{
78-
customData: 'customData-0',
79-
},
80-
{
81-
customData: 'customData-1',
82-
},
83-
],
66+
[MOCK_CHAIN_ID_2]: {
67+
nativeTokenStream: 5,
68+
nativeTokenPeriodic: 5,
69+
erc20TokenStream: 5,
70+
erc20TokenPeriodic: 5,
71+
custom: {
72+
count: 2,
73+
data: [
74+
{
75+
customData: 'customData-0',
76+
},
77+
{
78+
customData: 'customData-1',
79+
},
80+
],
81+
},
8482
},
85-
},
86-
});
83+
});
8784

8885
describe('GatorPermissionsController', () => {
8986
describe('constructor', () => {
@@ -246,13 +243,15 @@ describe('GatorPermissionsController', () => {
246243
expect(controller.state.isFetchingGatorPermissions).toBe(false);
247244

248245
// check that the gator permissions map is sanitized
249-
const sanitizedCheck = (permissionType: keyof GatorPermissionsMap) => {
246+
const sanitizedCheck = (
247+
permissionType: keyof GatorPermissionsMap,
248+
): void => {
250249
const flattenedStoredGatorPermissions = Object.values(
251250
result[permissionType],
252251
).flat();
253252
flattenedStoredGatorPermissions.forEach((permission) => {
254-
expect(permission.permissionResponse.signer).toBeUndefined();
255-
expect(permission.permissionResponse.dependencyInfo).toBeUndefined();
253+
expect(permission.permissionResponse.to).toBeUndefined();
254+
expect(permission.permissionResponse.dependencies).toBeUndefined();
256255
});
257256
};
258257

@@ -288,11 +287,8 @@ describe('GatorPermissionsController', () => {
288287
const revocationEntry = {
289288
permissionResponse: {
290289
chainId,
291-
address: '0x0000000000000000000000000000000000000001',
292-
signer: {
293-
type: 'account',
294-
data: { address: '0x0000000000000000000000000000000000000002' },
295-
},
290+
from: '0x0000000000000000000000000000000000000001',
291+
to: '0x0000000000000000000000000000000000000002',
296292
permission: {
297293
type: 'erc20-token-revocation',
298294
isAdjustmentAllowed: false,
@@ -301,10 +297,8 @@ describe('GatorPermissionsController', () => {
301297
data: {} as any,
302298
},
303299
context: '0xdeadbeef',
304-
dependencyInfo: [],
305-
signerMeta: {
306-
delegationManager: '0x0000000000000000000000000000000000000003',
307-
},
300+
dependencies: [],
301+
delegationManager: '0x0000000000000000000000000000000000000003',
308302
},
309303
siteOrigin: 'https://example.org',
310304
} as unknown;
@@ -490,10 +484,11 @@ describe('GatorPermissionsController', () => {
490484
'registerActionHandler',
491485
);
492486

493-
new GatorPermissionsController({
487+
const controller = new GatorPermissionsController({
494488
messenger,
495489
});
496490

491+
expect(controller.state.isGatorPermissionsEnabled).toBe(false);
497492
expect(mockRegisterActionHandler).toHaveBeenCalledWith(
498493
'GatorPermissionsController:fetchAndUpdateGatorPermissions',
499494
expect.any(Function),
@@ -607,7 +602,9 @@ describe('GatorPermissionsController', () => {
607602
const delegateAddressB =
608603
'0x2222222222222222222222222222222222222222' as Hex;
609604
const metamaskOrigin = 'https://metamask.io';
610-
const buildMetadata = (justification: string) => ({
605+
const buildMetadata = (
606+
justification: string,
607+
): { justification: string; origin: string } => ({
611608
justification,
612609
origin: metamaskOrigin,
613610
});
@@ -692,11 +689,8 @@ describe('GatorPermissionsController', () => {
692689
});
693690

694691
expect(result.chainId).toBe(numberToHex(chainId));
695-
expect(result.address).toBe(delegator);
696-
expect(result.signer).toStrictEqual({
697-
type: 'account',
698-
data: { address: delegate },
699-
});
692+
expect(result.from).toBe(delegator);
693+
expect(result.to).toStrictEqual(delegate);
700694
expect(result.permission.type).toBe('native-token-stream');
701695
expect(result.expiry).toBe(timestampBeforeThreshold);
702696
// amounts are hex-encoded in decoded data; startTime is numeric

packages/gator-permissions-controller/src/GatorPermissionsController.ts

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import type { Signer } from '@metamask/7715-permission-types';
21
import type {
32
ControllerGetStateAction,
43
ControllerStateChangeEvent,
@@ -337,19 +336,19 @@ export default class GatorPermissionsController extends BaseController<
337336
this.#registerMessageHandlers();
338337
}
339338

340-
#setIsFetchingGatorPermissions(isFetchingGatorPermissions: boolean) {
339+
#setIsFetchingGatorPermissions(isFetchingGatorPermissions: boolean): void {
341340
this.update((state) => {
342341
state.isFetchingGatorPermissions = isFetchingGatorPermissions;
343342
});
344343
}
345344

346-
#setIsGatorPermissionsEnabled(isGatorPermissionsEnabled: boolean) {
345+
#setIsGatorPermissionsEnabled(isGatorPermissionsEnabled: boolean): void {
347346
this.update((state) => {
348347
state.isGatorPermissionsEnabled = isGatorPermissionsEnabled;
349348
});
350349
}
351350

352-
#addPendingRevocationToState(txId: string, permissionContext: Hex) {
351+
#addPendingRevocationToState(txId: string, permissionContext: Hex): void {
353352
this.update((state) => {
354353
state.pendingRevocations = [
355354
...state.pendingRevocations,
@@ -358,15 +357,17 @@ export default class GatorPermissionsController extends BaseController<
358357
});
359358
}
360359

361-
#removePendingRevocationFromStateByTxId(txId: string) {
360+
#removePendingRevocationFromStateByTxId(txId: string): void {
362361
this.update((state) => {
363362
state.pendingRevocations = state.pendingRevocations.filter(
364363
(pendingRevocations) => pendingRevocations.txId !== txId,
365364
);
366365
});
367366
}
368367

369-
#removePendingRevocationFromStateByPermissionContext(permissionContext: Hex) {
368+
#removePendingRevocationFromStateByPermissionContext(
369+
permissionContext: Hex,
370+
): void {
370371
this.update((state) => {
371372
state.pendingRevocations = state.pendingRevocations.filter(
372373
(pendingRevocations) =>
@@ -425,7 +426,7 @@ export default class GatorPermissionsController extends BaseController<
425426
*
426427
* @throws {GatorPermissionsNotEnabledError} If the gator permissions are not enabled.
427428
*/
428-
#assertGatorPermissionsEnabled() {
429+
#assertGatorPermissionsEnabled(): void {
429430
if (!this.state.isGatorPermissionsEnabled) {
430431
throw new GatorPermissionsNotEnabledError();
431432
}
@@ -445,9 +446,7 @@ export default class GatorPermissionsController extends BaseController<
445446
}: {
446447
snapId: SnapId;
447448
params?: Json;
448-
}): Promise<
449-
StoredGatorPermission<Signer, PermissionTypesWithCustom>[] | null
450-
> {
449+
}): Promise<StoredGatorPermission<PermissionTypesWithCustom>[] | null> {
451450
try {
452451
const response = (await this.messenger.call(
453452
'SnapController:handleRequest',
@@ -462,7 +461,7 @@ export default class GatorPermissionsController extends BaseController<
462461
...(params !== undefined && { params }),
463462
},
464463
},
465-
)) as StoredGatorPermission<Signer, PermissionTypesWithCustom>[] | null;
464+
)) as StoredGatorPermission<PermissionTypesWithCustom>[] | null;
466465

467466
return response;
468467
} catch (error) {
@@ -480,19 +479,16 @@ export default class GatorPermissionsController extends BaseController<
480479

481480
/**
482481
* Sanitizes a stored gator permission for client exposure.
483-
* Removes internal fields (dependencyInfo, signer)
482+
* Removes internal fields (dependencies, to)
484483
*
485484
* @param storedGatorPermission - The stored gator permission to sanitize.
486485
* @returns The sanitized stored gator permission.
487486
*/
488487
#sanitizeStoredGatorPermission(
489-
storedGatorPermission: StoredGatorPermission<
490-
Signer,
491-
PermissionTypesWithCustom
492-
>,
493-
): StoredGatorPermissionSanitized<Signer, PermissionTypesWithCustom> {
488+
storedGatorPermission: StoredGatorPermission<PermissionTypesWithCustom>,
489+
): StoredGatorPermissionSanitized<PermissionTypesWithCustom> {
494490
const { permissionResponse } = storedGatorPermission;
495-
const { dependencyInfo, signer, ...rest } = permissionResponse;
491+
const { dependencies, to, ...rest } = permissionResponse;
496492
return {
497493
...storedGatorPermission,
498494
permissionResponse: {
@@ -509,7 +505,7 @@ export default class GatorPermissionsController extends BaseController<
509505
*/
510506
#categorizePermissionsDataByTypeAndChainId(
511507
storedGatorPermissions:
512-
| StoredGatorPermission<Signer, PermissionTypesWithCustom>[]
508+
| StoredGatorPermission<PermissionTypesWithCustom>[]
513509
| null,
514510
): GatorPermissionsMap {
515511
const gatorPermissionsMap = createEmptyGatorPermissionsMap();
@@ -570,14 +566,14 @@ export default class GatorPermissionsController extends BaseController<
570566
/**
571567
* Enables gator permissions for the user.
572568
*/
573-
public async enableGatorPermissions() {
569+
public async enableGatorPermissions(): Promise<void> {
574570
this.#setIsGatorPermissionsEnabled(true);
575571
}
576572

577573
/**
578574
* Clears the gator permissions map and disables the feature.
579575
*/
580-
public async disableGatorPermissions() {
576+
public async disableGatorPermissions(): Promise<void> {
581577
this.update((state) => {
582578
state.isGatorPermissionsEnabled = false;
583579
state.gatorPermissionsMapSerialized = serializeGatorPermissionsMap(
@@ -641,7 +637,7 @@ export default class GatorPermissionsController extends BaseController<
641637
* This method validates the caller origin, decodes the provided `permissionContext`
642638
* into delegations, identifies the permission type from the caveat enforcers,
643639
* extracts the permission-specific data and expiry, and reconstructs a
644-
* {@link DecodedPermission} containing chainId, account addresses, signer, type and data.
640+
* {@link DecodedPermission} containing chainId, account addresses, to, type and data.
645641
*
646642
* @param args - The arguments to this function.
647643
* @param args.origin - The caller's origin; must match the configured permissions provider Snap id.

packages/gator-permissions-controller/src/decodePermission/decodePermission.test.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1204,11 +1204,8 @@ describe('decodePermission', () => {
12041204
});
12051205

12061206
expect(result.chainId).toBe(numberToHex(chainId));
1207-
expect(result.address).toBe(delegator);
1208-
expect(result.signer).toStrictEqual({
1209-
type: 'account',
1210-
data: { address: delegate },
1211-
});
1207+
expect(result.from).toBe(delegator);
1208+
expect(result.to).toStrictEqual(delegate);
12121209
expect(result.permission).toStrictEqual({
12131210
type: permissionType,
12141211
data,

packages/gator-permissions-controller/src/decodePermission/decodePermission.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,15 +321,15 @@ export const reconstructDecodedPermission = ({
321321
data: DecodedPermission['permission']['data'];
322322
justification: string;
323323
specifiedOrigin: string;
324-
}) => {
324+
}): DecodedPermission => {
325325
if (authority !== ROOT_AUTHORITY) {
326326
throw new Error('Invalid authority');
327327
}
328328

329329
const permission: DecodedPermission = {
330330
chainId: numberToHex(chainId),
331-
address: delegator,
332-
signer: { type: 'account', data: { address: delegate } },
331+
from: delegator,
332+
to: delegate,
333333
permission: {
334334
type: permissionType,
335335
data,

0 commit comments

Comments
 (0)