Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion lib/delegatable-framework
8 changes: 8 additions & 0 deletions packages/7715-permission-types/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,14 @@ 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))

### Deprecated

- Deprecated `erc20-token-revocation` in favor of `token-approval-revocation`.

## [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
23 changes: 22 additions & 1 deletion packages/7715-permission-types/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,32 @@ export type Erc20TokenAllowancePermission = BasePermission & {

/**
* A permission to revoke an ERC20 token allowance.
*
* @deprecated Use {@link TokenApprovalRevocationPermission} instead.
*/
export type Erc20TokenRevocationPermission = BasePermission & {
/**
* @deprecated Use `token-approval-revocation` instead.
*/
type: 'erc20-token-revocation';
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 +218,8 @@ export type PermissionTypes =
| Erc20TokenStreamPermission
| Erc20TokenPeriodicPermission
| Erc20TokenAllowancePermission
| Erc20TokenRevocationPermission;
| Erc20TokenRevocationPermission
| TokenApprovalRevocationPermission;

// //////////////////////////////////////////////////
// Permission Requests
Expand Down
5 changes: 5 additions & 0 deletions packages/smart-accounts-kit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,13 @@ 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))

### Deprecated

- Deprecated `erc20-token-revocation` in favor of `token-approval-revocation`.

## [1.5.0]

### Added
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
19 changes: 18 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 @@ -112,14 +113,29 @@ export type Erc20TokenAllowancePermission = BasePermission & {

/**
* ERC-20 token revocation permission.
*
* @deprecated Use {@link TokenApprovalRevocationPermission} instead.
*/
export type Erc20TokenRevocationPermission = BasePermission & {
/**
* @deprecated Use `token-approval-revocation` instead.
*/
type: 'erc20-token-revocation';
data: {
justification?: string;
};
};

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

/**
* Permission types.
*/
Expand All @@ -130,7 +146,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