Skip to content

Commit 086175b

Browse files
committed
Add token-approval-revocation permission type and related RPC conversion
1 parent 26f37ce commit 086175b

9 files changed

Lines changed: 156 additions & 3 deletions

File tree

lib/delegatable-framework

packages/7715-permission-types/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- New permission type `token-approval-revocation`
13+
1014
## [0.6.0]
1115

1216
### Added

packages/7715-permission-types/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export type {
1010
Erc20TokenPeriodicPermission,
1111
Erc20TokenAllowancePermission,
1212
Erc20TokenRevocationPermission,
13+
TokenApprovalRevocationPermission,
1314
Rule,
1415
PermissionRequest,
1516
PermissionResponse,

packages/7715-permission-types/src/types.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,21 @@ export type Erc20TokenRevocationPermission = BasePermission & {
177177
data: MetaMaskBasePermissionData;
178178
};
179179

180+
/**
181+
* A permission to revoke token approvals.
182+
*/
183+
export type TokenApprovalRevocationPermission = BasePermission & {
184+
type: 'token-approval-revocation';
185+
data: MetaMaskBasePermissionData & {
186+
erc20Approve: boolean;
187+
erc721Approve: boolean;
188+
erc721SetApprovalForAll: boolean;
189+
permit2ApproveZero: boolean;
190+
permit2Lockdown: boolean;
191+
permit2InvalidateNonces: boolean;
192+
};
193+
};
194+
180195
/**
181196
* A custom permission.
182197
*
@@ -198,7 +213,8 @@ export type PermissionTypes =
198213
| Erc20TokenStreamPermission
199214
| Erc20TokenPeriodicPermission
200215
| Erc20TokenAllowancePermission
201-
| Erc20TokenRevocationPermission;
216+
| Erc20TokenRevocationPermission
217+
| TokenApprovalRevocationPermission;
202218

203219
// //////////////////////////////////////////////////
204220
// Permission Requests

packages/smart-accounts-kit/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
- `CaveatBuilder` for `ApprovalRevocationEnforcer`, deployment address added to `SmartAccountsEnvironment` ([#226](https://github.com/metamask/smart-accounts-kit/pull/226))
13+
- ERC-7715 `token-approval-revocation` permission type
1314

1415
## [1.5.0]
1516

packages/smart-accounts-kit/src/actions/erc7715Mapping.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import type {
99
PermissionRequest,
1010
PermissionTypes as RpcPermissionTypes,
1111
Rule,
12+
TokenApprovalRevocationPermission as RpcTokenApprovalRevocationPermission,
1213
} from '@metamask/7715-permission-types';
1314
import { getAddress, hexToNumber, isAddress, toHex, type Hex } from 'viem';
1415

@@ -27,6 +28,7 @@ import type {
2728
PermissionTypes as DeveloperPermissionTypes,
2829
RpcGetGrantedExecutionPermissionsResult,
2930
RpcGetSupportedExecutionPermissionsResult,
31+
TokenApprovalRevocationPermission,
3032
} from './erc7715Types';
3133

3234
// =============================================================================
@@ -156,6 +158,11 @@ function getPermissionRequestToRpcConverter(
156158
erc20TokenRevocationPermissionToRpc(
157159
permission as Erc20TokenRevocationPermission,
158160
);
161+
case 'token-approval-revocation':
162+
return (permission) =>
163+
tokenApprovalRevocationPermissionToRpc(
164+
permission as TokenApprovalRevocationPermission,
165+
);
159166
default:
160167
throw new Error(`Unsupported permission type: ${permissionType}`);
161168
}
@@ -407,6 +414,44 @@ function erc20TokenRevocationPermissionToRpc(
407414
};
408415
}
409416

417+
/**
418+
* Convert token approval revocation permission to RPC format.
419+
*
420+
* @param permission the token approval revocation permission
421+
* @returns the token approval revocation permission in RPC format
422+
*/
423+
function tokenApprovalRevocationPermissionToRpc(
424+
permission: TokenApprovalRevocationPermission,
425+
): RpcTokenApprovalRevocationPermission {
426+
const {
427+
data: {
428+
erc20Approve,
429+
erc721Approve,
430+
erc721SetApprovalForAll,
431+
permit2ApproveZero,
432+
permit2Lockdown,
433+
permit2InvalidateNonces,
434+
justification,
435+
},
436+
isAdjustmentAllowed,
437+
} = permission;
438+
439+
const data = {
440+
erc20Approve,
441+
erc721Approve,
442+
erc721SetApprovalForAll,
443+
permit2ApproveZero,
444+
permit2Lockdown,
445+
permit2InvalidateNonces,
446+
...(justification ? { justification } : {}),
447+
};
448+
return {
449+
type: 'token-approval-revocation',
450+
data,
451+
isAdjustmentAllowed,
452+
};
453+
}
454+
410455
// =============================================================================
411456
// RPC → Developer friendly types (response conversion)
412457
// =============================================================================

packages/smart-accounts-kit/src/actions/erc7715Types.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
PermissionResponse as RpcPermissionResponse,
55
Rule,
66
} from '@metamask/7715-permission-types';
7+
import type { ApprovalRevocationTerms } from '@metamask/delegation-core';
78
import type {
89
Client,
910
Account,
@@ -120,6 +121,16 @@ export type Erc20TokenRevocationPermission = BasePermission & {
120121
};
121122
};
122123

124+
/**
125+
* Token approval revocation permission.
126+
*/
127+
export type TokenApprovalRevocationPermission = BasePermission & {
128+
type: 'token-approval-revocation';
129+
data: ApprovalRevocationTerms & {
130+
justification?: string;
131+
};
132+
};
133+
123134
/**
124135
* Permission types.
125136
*/
@@ -130,7 +141,8 @@ export type PermissionTypes =
130141
| Erc20TokenStreamPermission
131142
| Erc20TokenPeriodicPermission
132143
| Erc20TokenAllowancePermission
133-
| Erc20TokenRevocationPermission;
144+
| Erc20TokenRevocationPermission
145+
| TokenApprovalRevocationPermission;
134146

135147
/**
136148
* Parameters for a single permission request (input to requestExecutionPermissions).

packages/smart-accounts-kit/src/actions/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export {
9292
type Erc20TokenPeriodicPermission,
9393
type Erc20TokenAllowancePermission,
9494
type Erc20TokenRevocationPermission,
95+
type TokenApprovalRevocationPermission,
9596
type RpcGetSupportedExecutionPermissionsResult,
9697
type RpcGetGrantedExecutionPermissionsResult,
9798
type RpcSupportedPermissionInfo,

packages/smart-accounts-kit/test/actions/erc7715Mapping.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,38 @@ describe('erc7715Mapping', () => {
190190
},
191191
});
192192
});
193+
194+
it('preserves token-approval-revocation data, including false flags', () => {
195+
const rpcPermission = {
196+
type: 'token-approval-revocation',
197+
isAdjustmentAllowed: true,
198+
data: {
199+
erc20Approve: true,
200+
erc721Approve: false,
201+
erc721SetApprovalForAll: true,
202+
permit2ApproveZero: false,
203+
permit2Lockdown: true,
204+
permit2InvalidateNonces: false,
205+
justification: 'Revoke token approvals',
206+
},
207+
} as const;
208+
209+
const result = permissionTypeFromRpc(rpcPermission);
210+
211+
expect(result).toStrictEqual({
212+
type: 'token-approval-revocation',
213+
isAdjustmentAllowed: true,
214+
data: {
215+
erc20Approve: true,
216+
erc721Approve: false,
217+
erc721SetApprovalForAll: true,
218+
permit2ApproveZero: false,
219+
permit2Lockdown: true,
220+
permit2InvalidateNonces: false,
221+
justification: 'Revoke token approvals',
222+
},
223+
});
224+
});
193225
});
194226

195227
describe('permissionResponsesFromRpc', () => {
@@ -772,6 +804,47 @@ describe('erc7715Mapping', () => {
772804
});
773805
});
774806

807+
it('converts token-approval-revocation: preserves all flags', () => {
808+
const permissionRequest = {
809+
chainId: 1,
810+
permission: {
811+
type: 'token-approval-revocation',
812+
data: {
813+
erc20Approve: true,
814+
erc721Approve: false,
815+
erc721SetApprovalForAll: true,
816+
permit2ApproveZero: false,
817+
permit2Lockdown: true,
818+
permit2InvalidateNonces: false,
819+
justification: 'Revoke token approvals',
820+
},
821+
isAdjustmentAllowed: true,
822+
},
823+
to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
824+
} as const;
825+
826+
const result = permissionRequestToRpc(permissionRequest);
827+
828+
expect(result).toStrictEqual({
829+
chainId: '0x1',
830+
permission: {
831+
type: 'token-approval-revocation',
832+
data: {
833+
erc20Approve: true,
834+
erc721Approve: false,
835+
erc721SetApprovalForAll: true,
836+
permit2ApproveZero: false,
837+
permit2Lockdown: true,
838+
permit2InvalidateNonces: false,
839+
justification: 'Revoke token approvals',
840+
},
841+
isAdjustmentAllowed: true,
842+
},
843+
to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
844+
rules: [],
845+
});
846+
});
847+
775848
it('throws for unsupported permission type', () => {
776849
const permissionRequest = {
777850
chainId: 1,

0 commit comments

Comments
 (0)