Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/7715-permission-types/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- New permission type `token-approval-revocation` ([#232](https://github.com/MetaMask/smart-accounts-kit/pull/232))

## [0.6.0]

### Added
Expand Down
1 change: 1 addition & 0 deletions packages/7715-permission-types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type {
Erc20TokenPeriodicPermission,
Erc20TokenAllowancePermission,
Erc20TokenRevocationPermission,
TokenApprovalRevocationPermission,
Rule,
PermissionRequest,
PermissionResponse,
Expand Down
18 changes: 17 additions & 1 deletion packages/7715-permission-types/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,21 @@ export type Erc20TokenRevocationPermission = BasePermission & {
data: MetaMaskBasePermissionData;
};

/**
* A permission to revoke token approvals.
*/
export type TokenApprovalRevocationPermission = BasePermission & {
type: 'token-approval-revocation';
data: MetaMaskBasePermissionData & {
erc20Approve: boolean;
erc721Approve: boolean;
erc721SetApprovalForAll: boolean;
permit2ApproveZero: boolean;
permit2Lockdown: boolean;
permit2InvalidateNonces: boolean;
};
};

/**
* A custom permission.
*
Expand All @@ -198,7 +213,8 @@ export type PermissionTypes =
| Erc20TokenStreamPermission
| Erc20TokenPeriodicPermission
| Erc20TokenAllowancePermission
| Erc20TokenRevocationPermission;
| Erc20TokenRevocationPermission
| TokenApprovalRevocationPermission;

// //////////////////////////////////////////////////
// Permission Requests
Expand Down
1 change: 1 addition & 0 deletions packages/smart-accounts-kit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

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

## [1.5.0]
Expand Down
45 changes: 45 additions & 0 deletions packages/smart-accounts-kit/src/actions/erc7715Mapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import type {
PermissionRequest,
PermissionTypes as RpcPermissionTypes,
Rule,
TokenApprovalRevocationPermission as RpcTokenApprovalRevocationPermission,
} from '@metamask/7715-permission-types';
import { getAddress, hexToNumber, isAddress, toHex, type Hex } from 'viem';

Expand All @@ -27,6 +28,7 @@ import type {
PermissionTypes as DeveloperPermissionTypes,
RpcGetGrantedExecutionPermissionsResult,
RpcGetSupportedExecutionPermissionsResult,
TokenApprovalRevocationPermission,
} from './erc7715Types';

// =============================================================================
Expand Down Expand Up @@ -156,6 +158,11 @@ function getPermissionRequestToRpcConverter(
erc20TokenRevocationPermissionToRpc(
permission as Erc20TokenRevocationPermission,
);
case 'token-approval-revocation':
return (permission) =>
tokenApprovalRevocationPermissionToRpc(
permission as TokenApprovalRevocationPermission,
);
default:
throw new Error(`Unsupported permission type: ${permissionType}`);
}
Expand Down Expand Up @@ -407,6 +414,44 @@ function erc20TokenRevocationPermissionToRpc(
};
}

/**
* Convert token approval revocation permission to RPC format.
*
* @param permission the token approval revocation permission
* @returns the token approval revocation permission in RPC format
*/
function tokenApprovalRevocationPermissionToRpc(
permission: TokenApprovalRevocationPermission,
): RpcTokenApprovalRevocationPermission {
const {
data: {
erc20Approve,
erc721Approve,
erc721SetApprovalForAll,
permit2ApproveZero,
permit2Lockdown,
permit2InvalidateNonces,
justification,
},
isAdjustmentAllowed,
} = permission;

const data = {
erc20Approve,
erc721Approve,
erc721SetApprovalForAll,
permit2ApproveZero,
permit2Lockdown,
permit2InvalidateNonces,
...(justification ? { justification } : {}),
};
return {
type: 'token-approval-revocation',
data,
isAdjustmentAllowed,
};
}

// =============================================================================
// RPC → Developer friendly types (response conversion)
// =============================================================================
Expand Down
14 changes: 13 additions & 1 deletion packages/smart-accounts-kit/src/actions/erc7715Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
PermissionResponse as RpcPermissionResponse,
Rule,
} from '@metamask/7715-permission-types';
import type { ApprovalRevocationTerms } from '@metamask/delegation-core';
import type {
Client,
Account,
Expand Down Expand Up @@ -120,6 +121,16 @@ export type Erc20TokenRevocationPermission = BasePermission & {
};
};

/**
* Token approval revocation permission.
*/
export type TokenApprovalRevocationPermission = BasePermission & {
type: 'token-approval-revocation';
data: ApprovalRevocationTerms & {
justification?: string;
};
};

/**
* Permission types.
*/
Expand All @@ -130,7 +141,8 @@ export type PermissionTypes =
| Erc20TokenStreamPermission
| Erc20TokenPeriodicPermission
| Erc20TokenAllowancePermission
| Erc20TokenRevocationPermission;
| Erc20TokenRevocationPermission
| TokenApprovalRevocationPermission;

/**
* Parameters for a single permission request (input to requestExecutionPermissions).
Expand Down
1 change: 1 addition & 0 deletions packages/smart-accounts-kit/src/actions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ export {
type Erc20TokenPeriodicPermission,
type Erc20TokenAllowancePermission,
type Erc20TokenRevocationPermission,
type TokenApprovalRevocationPermission,
type RpcGetSupportedExecutionPermissionsResult,
type RpcGetGrantedExecutionPermissionsResult,
type RpcSupportedPermissionInfo,
Expand Down
73 changes: 73 additions & 0 deletions packages/smart-accounts-kit/test/actions/erc7715Mapping.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,38 @@ describe('erc7715Mapping', () => {
},
});
});

it('preserves token-approval-revocation data, including false flags', () => {
const rpcPermission = {
type: 'token-approval-revocation',
isAdjustmentAllowed: true,
data: {
erc20Approve: true,
erc721Approve: false,
erc721SetApprovalForAll: true,
permit2ApproveZero: false,
permit2Lockdown: true,
permit2InvalidateNonces: false,
justification: 'Revoke token approvals',
},
} as const;

const result = permissionTypeFromRpc(rpcPermission);

expect(result).toStrictEqual({
type: 'token-approval-revocation',
isAdjustmentAllowed: true,
data: {
erc20Approve: true,
erc721Approve: false,
erc721SetApprovalForAll: true,
permit2ApproveZero: false,
permit2Lockdown: true,
permit2InvalidateNonces: false,
justification: 'Revoke token approvals',
},
});
});
});

describe('permissionResponsesFromRpc', () => {
Expand Down Expand Up @@ -772,6 +804,47 @@ describe('erc7715Mapping', () => {
});
});

it('converts token-approval-revocation: preserves all flags', () => {
const permissionRequest = {
chainId: 1,
permission: {
type: 'token-approval-revocation',
data: {
erc20Approve: true,
erc721Approve: false,
erc721SetApprovalForAll: true,
permit2ApproveZero: false,
permit2Lockdown: true,
permit2InvalidateNonces: false,
justification: 'Revoke token approvals',
},
isAdjustmentAllowed: true,
},
to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
} as const;

const result = permissionRequestToRpc(permissionRequest);

expect(result).toStrictEqual({
chainId: '0x1',
permission: {
type: 'token-approval-revocation',
data: {
erc20Approve: true,
erc721Approve: false,
erc721SetApprovalForAll: true,
permit2ApproveZero: false,
permit2Lockdown: true,
permit2InvalidateNonces: false,
justification: 'Revoke token approvals',
},
isAdjustmentAllowed: true,
},
to: '0xabcdefabcdefabcdefabcdefabcdefabcdefabcd',
rules: [],
});
});

it('throws for unsupported permission type', () => {
const permissionRequest = {
chainId: 1,
Expand Down
Loading