From e175c6ab575eec3ace2b2289894d69ce456faac0 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Mon, 12 Jan 2026 13:14:35 +0100 Subject: [PATCH 01/11] add 7715 discoverability methods --- packages/eth-json-rpc-middleware/src/index.ts | 18 ++++ ...-get-granted-execution-permissions.test.ts | 85 +++++++++++++++++ ...allet-get-granted-execution-permissions.ts | 93 +++++++++++++++++++ ...et-supported-execution-permissions.test.ts | 77 +++++++++++++++ ...let-get-supported-execution-permissions.ts | 71 ++++++++++++++ .../eth-json-rpc-middleware/src/wallet.ts | 18 ++++ 6 files changed, 362 insertions(+) create mode 100644 packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts create mode 100644 packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts create mode 100644 packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts create mode 100644 packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts diff --git a/packages/eth-json-rpc-middleware/src/index.ts b/packages/eth-json-rpc-middleware/src/index.ts index d729ba2fd1c..25e6c0e9c58 100644 --- a/packages/eth-json-rpc-middleware/src/index.ts +++ b/packages/eth-json-rpc-middleware/src/index.ts @@ -14,6 +14,24 @@ export type { RevokeExecutionPermissionRequestParams, RevokeExecutionPermissionResult, } from './methods/wallet-revoke-execution-permission'; +export type { + GrantedExecutionPermission, + GetGrantedExecutionPermissionsResult, + ProcessGetGrantedExecutionPermissionsHook, +} from './methods/wallet-get-granted-execution-permissions'; +export { + GrantedExecutionPermissionStruct, + GetGrantedExecutionPermissionsResultStruct, +} from './methods/wallet-get-granted-execution-permissions'; +export type { + SupportedExecutionPermissionConfig, + GetSupportedExecutionPermissionsResult, + ProcessGetSupportedExecutionPermissionsHook, +} from './methods/wallet-get-supported-execution-permissions'; +export { + SupportedExecutionPermissionConfigStruct, + GetSupportedExecutionPermissionsResultStruct, +} from './methods/wallet-get-supported-execution-permissions'; export * from './providerAsMiddleware'; export * from './retryOnEmpty'; export * from './wallet'; diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts new file mode 100644 index 00000000000..50072a04626 --- /dev/null +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts @@ -0,0 +1,85 @@ +import type { Hex, Json, JsonRpcRequest } from '@metamask/utils'; + +import type { + GetGrantedExecutionPermissionsResult, + ProcessGetGrantedExecutionPermissionsHook, +} from './wallet-get-granted-execution-permissions'; +import { createWalletGetGrantedExecutionPermissionsHandler } from './wallet-get-granted-execution-permissions'; +import type { WalletMiddlewareParams } from '../wallet'; + +const RESULT_MOCK: GetGrantedExecutionPermissionsResult = [ + { + chainId: '0x01' as Hex, + from: '0x1234567890123456789012345678901234567890' as Hex, + to: '0x016562aA41A8697720ce0943F003141f5dEAe006' as Hex, + permission: { + type: 'native-token-allowance', + isAdjustmentAllowed: true, + data: { + allowance: '0x1DCD65000000', + }, + }, + context: '0x016562aA41A8697720ce0943F003141f5dEAe0060000771577157715' as Hex, + dependencies: [ + { + factory: '0x1234567890123456789012345678901234567890' as Hex, + factoryData: '0xabcdef' as Hex, + }, + ], + delegationManager: '0x1234567890123456789012345678901234567890' as Hex, + }, +]; + +const REQUEST_MOCK = { + params: [], +} as unknown as JsonRpcRequest; + +describe('wallet_getGrantedExecutionPermissions', () => { + let request: JsonRpcRequest; + let processGetGrantedExecutionPermissionsMock: jest.MockedFunction; + let context: WalletMiddlewareParams['context']; + + const callMethod = async (): Promise | undefined> => { + const handler = createWalletGetGrantedExecutionPermissionsHandler({ + processGetGrantedExecutionPermissions: + processGetGrantedExecutionPermissionsMock, + }); + return handler({ request, context } as WalletMiddlewareParams); + }; + + beforeEach(() => { + jest.resetAllMocks(); + + request = { ...REQUEST_MOCK }; + + context = new Map([ + ['origin', 'test-origin'], + ]) as WalletMiddlewareParams['context']; + + processGetGrantedExecutionPermissionsMock = jest.fn(); + processGetGrantedExecutionPermissionsMock.mockResolvedValue(RESULT_MOCK); + }); + + it('calls hook', async () => { + await callMethod(); + expect(processGetGrantedExecutionPermissionsMock).toHaveBeenCalledWith( + request, + context, + ); + }); + + it('returns result from hook', async () => { + const result = await callMethod(); + expect(result).toStrictEqual(RESULT_MOCK); + }); + + it('throws if no hook', async () => { + await expect( + createWalletGetGrantedExecutionPermissionsHandler({})({ + request, + } as WalletMiddlewareParams), + ).rejects.toThrow( + 'wallet_getGrantedExecutionPermissions - no middleware configured', + ); + }); +}); diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts new file mode 100644 index 00000000000..87289310c80 --- /dev/null +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts @@ -0,0 +1,93 @@ +import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine/v2'; +import { rpcErrors } from '@metamask/rpc-errors'; +import type { Infer } from '@metamask/superstruct'; +import { + array, + boolean, + object, + record, + string, + unknown, +} from '@metamask/superstruct'; +import { StrictHexStruct } from '@metamask/utils'; +import type { Json, JsonRpcRequest } from '@metamask/utils'; + +import type { WalletMiddlewareContext } from '../wallet'; + +const DependencyStruct = object({ + factory: StrictHexStruct, + factoryData: StrictHexStruct, +}); + +const PermissionStruct = object({ + type: string(), + isAdjustmentAllowed: boolean(), + data: record(string(), unknown()), +}); + +/** + * Superstruct schema for a single granted execution permission. + */ +export const GrantedExecutionPermissionStruct = object({ + chainId: StrictHexStruct, + from: StrictHexStruct, + to: StrictHexStruct, + permission: PermissionStruct, + context: StrictHexStruct, + dependencies: array(DependencyStruct), + delegationManager: StrictHexStruct, +}); + +/** + * Represents a single granted execution permission. + */ +export type GrantedExecutionPermission = Infer< + typeof GrantedExecutionPermissionStruct +>; + +/** + * Superstruct schema for the `wallet_getGrantedExecutionPermissions` result. + */ +export const GetGrantedExecutionPermissionsResultStruct = array( + GrantedExecutionPermissionStruct, +); + +/** + * Result type for the `wallet_getGrantedExecutionPermissions` JSON-RPC method. + * Returns an array of all granted permissions that are not yet revoked. + */ +export type GetGrantedExecutionPermissionsResult = Json & + Infer; + +/** + * Hook type for processing the `wallet_getGrantedExecutionPermissions` request. + */ +export type ProcessGetGrantedExecutionPermissionsHook = ( + req: JsonRpcRequest, + context: WalletMiddlewareContext, +) => Promise; + +/** + * Creates a handler for the `wallet_getGrantedExecutionPermissions` JSON-RPC method. + * + * @param options - The options for the handler. + * @param options.processGetGrantedExecutionPermissions - The function to process the + * get granted execution permissions request. + * @returns A JSON-RPC middleware function that handles the + * `wallet_getGrantedExecutionPermissions` JSON-RPC method. + */ +export function createWalletGetGrantedExecutionPermissionsHandler({ + processGetGrantedExecutionPermissions, +}: { + processGetGrantedExecutionPermissions?: ProcessGetGrantedExecutionPermissionsHook; +}): JsonRpcMiddleware { + return async ({ request, context }) => { + if (!processGetGrantedExecutionPermissions) { + throw rpcErrors.methodNotSupported( + 'wallet_getGrantedExecutionPermissions - no middleware configured', + ); + } + + return await processGetGrantedExecutionPermissions(request, context); + }; +} diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts new file mode 100644 index 00000000000..3f15b05591f --- /dev/null +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts @@ -0,0 +1,77 @@ +import type { Hex, Json, JsonRpcRequest } from '@metamask/utils'; + +import type { + GetSupportedExecutionPermissionsResult, + ProcessGetSupportedExecutionPermissionsHook, +} from './wallet-get-supported-execution-permissions'; +import { createWalletGetSupportedExecutionPermissionsHandler } from './wallet-get-supported-execution-permissions'; +import type { WalletMiddlewareParams } from '../wallet'; + +const RESULT_MOCK: GetSupportedExecutionPermissionsResult = { + 'native-token-allowance': { + chainIds: ['0x123', '0x345'] as Hex[], + ruleTypes: ['expiry'], + }, + 'erc20-token-allowance': { + chainIds: ['0x123'] as Hex[], + ruleTypes: [], + }, + 'erc721-token-allowance': { + chainIds: ['0x123'] as Hex[], + ruleTypes: ['expiry'], + }, +}; + +const REQUEST_MOCK = { + params: [], +} as unknown as JsonRpcRequest; + +describe('wallet_getSupportedExecutionPermissions', () => { + let request: JsonRpcRequest; + let processGetSupportedExecutionPermissionsMock: jest.MockedFunction; + let context: WalletMiddlewareParams['context']; + + const callMethod = async (): Promise | undefined> => { + const handler = createWalletGetSupportedExecutionPermissionsHandler({ + processGetSupportedExecutionPermissions: + processGetSupportedExecutionPermissionsMock, + }); + return handler({ request, context } as WalletMiddlewareParams); + }; + + beforeEach(() => { + jest.resetAllMocks(); + + request = { ...REQUEST_MOCK }; + + context = new Map([ + ['origin', 'test-origin'], + ]) as WalletMiddlewareParams['context']; + + processGetSupportedExecutionPermissionsMock = jest.fn(); + processGetSupportedExecutionPermissionsMock.mockResolvedValue(RESULT_MOCK); + }); + + it('calls hook', async () => { + await callMethod(); + expect(processGetSupportedExecutionPermissionsMock).toHaveBeenCalledWith( + request, + context, + ); + }); + + it('returns result from hook', async () => { + const result = await callMethod(); + expect(result).toStrictEqual(RESULT_MOCK); + }); + + it('throws if no hook', async () => { + await expect( + createWalletGetSupportedExecutionPermissionsHandler({})({ + request, + } as WalletMiddlewareParams), + ).rejects.toThrow( + 'wallet_getSupportedExecutionPermissions - no middleware configured', + ); + }); +}); diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts new file mode 100644 index 00000000000..7a3fbeb19b1 --- /dev/null +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts @@ -0,0 +1,71 @@ +import type { JsonRpcMiddleware } from '@metamask/json-rpc-engine/v2'; +import { rpcErrors } from '@metamask/rpc-errors'; +import type { Infer } from '@metamask/superstruct'; +import { array, object, record, string } from '@metamask/superstruct'; +import { StrictHexStruct } from '@metamask/utils'; +import type { Json, JsonRpcRequest } from '@metamask/utils'; + +import type { WalletMiddlewareContext } from '../wallet'; + +/** + * Superstruct schema for a supported permission type configuration. + */ +export const SupportedExecutionPermissionConfigStruct = object({ + chainIds: array(StrictHexStruct), + ruleTypes: array(string()), +}); + +/** + * Represents the supported configuration for a permission type. + */ +export type SupportedExecutionPermissionConfig = Infer< + typeof SupportedExecutionPermissionConfigStruct +>; + +/** + * Superstruct schema for the `wallet_getSupportedExecutionPermissions` result. + */ +export const GetSupportedExecutionPermissionsResultStruct = record( + string(), + SupportedExecutionPermissionConfigStruct, +); + +/** + * Result type for the `wallet_getSupportedExecutionPermissions` JSON-RPC method. + * Returns an object keyed on supported permission types with their configurations. + */ +export type GetSupportedExecutionPermissionsResult = Json & + Infer; + +/** + * Hook type for processing the `wallet_getSupportedExecutionPermissions` request. + */ +export type ProcessGetSupportedExecutionPermissionsHook = ( + req: JsonRpcRequest, + context: WalletMiddlewareContext, +) => Promise; + +/** + * Creates a handler for the `wallet_getSupportedExecutionPermissions` JSON-RPC method. + * + * @param options - The options for the handler. + * @param options.processGetSupportedExecutionPermissions - The function to process the + * get supported execution permissions request. + * @returns A JSON-RPC middleware function that handles the + * `wallet_getSupportedExecutionPermissions` JSON-RPC method. + */ +export function createWalletGetSupportedExecutionPermissionsHandler({ + processGetSupportedExecutionPermissions, +}: { + processGetSupportedExecutionPermissions?: ProcessGetSupportedExecutionPermissionsHook; +}): JsonRpcMiddleware { + return async ({ request, context }) => { + if (!processGetSupportedExecutionPermissions) { + throw rpcErrors.methodNotSupported( + 'wallet_getSupportedExecutionPermissions - no middleware configured', + ); + } + + return await processGetSupportedExecutionPermissions(request, context); + }; +} diff --git a/packages/eth-json-rpc-middleware/src/wallet.ts b/packages/eth-json-rpc-middleware/src/wallet.ts index 9f1797f367d..f5893c22c44 100644 --- a/packages/eth-json-rpc-middleware/src/wallet.ts +++ b/packages/eth-json-rpc-middleware/src/wallet.ts @@ -10,6 +10,10 @@ import { rpcErrors } from '@metamask/rpc-errors'; import { isValidHexAddress } from '@metamask/utils'; import type { JsonRpcRequest, Json, Hex } from '@metamask/utils'; +import { createWalletGetGrantedExecutionPermissionsHandler } from './methods/wallet-get-granted-execution-permissions'; +import type { ProcessGetGrantedExecutionPermissionsHook } from './methods/wallet-get-granted-execution-permissions'; +import { createWalletGetSupportedExecutionPermissionsHandler } from './methods/wallet-get-supported-execution-permissions'; +import type { ProcessGetSupportedExecutionPermissionsHook } from './methods/wallet-get-supported-execution-permissions'; import { createWalletRequestExecutionPermissionsHandler } from './methods/wallet-request-execution-permissions'; import type { ProcessRequestExecutionPermissionsHook } from './methods/wallet-request-execution-permissions'; import { createWalletRevokeExecutionPermissionHandler } from './methods/wallet-revoke-execution-permission'; @@ -83,6 +87,8 @@ export type WalletMiddlewareOptions = { ) => Promise; processRequestExecutionPermissions?: ProcessRequestExecutionPermissionsHook; processRevokeExecutionPermission?: ProcessRevokeExecutionPermissionHook; + processGetGrantedExecutionPermissions?: ProcessGetGrantedExecutionPermissionsHook; + processGetSupportedExecutionPermissions?: ProcessGetSupportedExecutionPermissionsHook; }; export type WalletMiddlewareKeyValues = { @@ -117,6 +123,8 @@ export type WalletMiddlewareParams = MiddlewareParams< * @param options.processTypedMessageV4 - The function to process the typed message v4 request. * @param options.processRequestExecutionPermissions - The function to process the request execution permissions request. * @param options.processRevokeExecutionPermission - The function to process the revoke execution permission request. + * @param options.processGetGrantedExecutionPermissions - The function to process the get granted execution permissions request. + * @param options.processGetSupportedExecutionPermissions - The function to process the get supported execution permissions request. * @returns A JSON-RPC middleware that handles wallet-related JSON-RPC methods. */ export function createWalletMiddleware({ @@ -131,6 +139,8 @@ export function createWalletMiddleware({ processTypedMessageV4, processRequestExecutionPermissions, processRevokeExecutionPermission, + processGetGrantedExecutionPermissions, + processGetSupportedExecutionPermissions, }: WalletMiddlewareOptions): JsonRpcMiddleware< JsonRpcRequest, Json, @@ -167,6 +177,14 @@ export function createWalletMiddleware({ createWalletRevokeExecutionPermissionHandler({ processRevokeExecutionPermission, }), + wallet_getGrantedExecutionPermissions: + createWalletGetGrantedExecutionPermissionsHandler({ + processGetGrantedExecutionPermissions, + }), + wallet_getSupportedExecutionPermissions: + createWalletGetSupportedExecutionPermissionsHandler({ + processGetSupportedExecutionPermissions, + }), }); // From 4f9961566be88cfe3623047a28ee9cfbd591b7bb Mon Sep 17 00:00:00 2001 From: MoMannn Date: Mon, 12 Jan 2026 13:20:51 +0100 Subject: [PATCH 02/11] update changelog --- packages/eth-json-rpc-middleware/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/eth-json-rpc-middleware/CHANGELOG.md b/packages/eth-json-rpc-middleware/CHANGELOG.md index 2f924eab481..7024944f35c 100644 --- a/packages/eth-json-rpc-middleware/CHANGELOG.md +++ b/packages/eth-json-rpc-middleware/CHANGELOG.md @@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511)) +### Added + +- Support for `wallet_getSupportedExecutionPermissions` and `wallet_getGrantedExecutionPermissions` RPC methods. + ## [22.0.1] ### Fixed From 97e7ccab5481c8da46568e19d955593ff3e30c74 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Mon, 12 Jan 2026 13:29:15 +0100 Subject: [PATCH 03/11] linter fixes --- packages/eth-json-rpc-middleware/CHANGELOG.md | 2 +- .../methods/wallet-get-granted-execution-permissions.test.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/eth-json-rpc-middleware/CHANGELOG.md b/packages/eth-json-rpc-middleware/CHANGELOG.md index 7024944f35c..ba41e7bf418 100644 --- a/packages/eth-json-rpc-middleware/CHANGELOG.md +++ b/packages/eth-json-rpc-middleware/CHANGELOG.md @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511)) -### Added +### Added - Support for `wallet_getSupportedExecutionPermissions` and `wallet_getGrantedExecutionPermissions` RPC methods. diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts index 50072a04626..49fdb33ff49 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts @@ -19,7 +19,8 @@ const RESULT_MOCK: GetGrantedExecutionPermissionsResult = [ allowance: '0x1DCD65000000', }, }, - context: '0x016562aA41A8697720ce0943F003141f5dEAe0060000771577157715' as Hex, + context: + '0x016562aA41A8697720ce0943F003141f5dEAe0060000771577157715' as Hex, dependencies: [ { factory: '0x1234567890123456789012345678901234567890' as Hex, From 3dfabd49eb985a0cccc80189e1b9e8f45245c8f4 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Mon, 12 Jan 2026 13:35:43 +0100 Subject: [PATCH 04/11] update changeloc --- packages/eth-json-rpc-middleware/CHANGELOG.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/eth-json-rpc-middleware/CHANGELOG.md b/packages/eth-json-rpc-middleware/CHANGELOG.md index ba41e7bf418..41739135d28 100644 --- a/packages/eth-json-rpc-middleware/CHANGELOG.md +++ b/packages/eth-json-rpc-middleware/CHANGELOG.md @@ -7,13 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -### Changed +### Added -- Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511)) +- Support for `wallet_getSupportedExecutionPermissions` and `wallet_getGrantedExecutionPermissions` RPC methods ([#7603](https://github.com/MetaMask/core/pull/7603)) -### Added +### Changed -- Support for `wallet_getSupportedExecutionPermissions` and `wallet_getGrantedExecutionPermissions` RPC methods. +- Upgrade `@metamask/utils` from `^11.8.1` to `^11.9.0` ([#7511](https://github.com/MetaMask/core/pull/7511)) ## [22.0.1] From 1dc77d14777bf56e78ed28988bf118bff38bb1ce Mon Sep 17 00:00:00 2001 From: MoMannn Date: Mon, 12 Jan 2026 13:46:22 +0100 Subject: [PATCH 05/11] fix tests snapshot --- .../eth-json-rpc-middleware/src/index.test.ts | 282 ++++++++++++++++++ 1 file changed, 282 insertions(+) diff --git a/packages/eth-json-rpc-middleware/src/index.test.ts b/packages/eth-json-rpc-middleware/src/index.test.ts index fdb1730d485..8dac22d37d4 100644 --- a/packages/eth-json-rpc-middleware/src/index.test.ts +++ b/packages/eth-json-rpc-middleware/src/index.test.ts @@ -4,6 +4,288 @@ describe('index module', () => { it('has expected JavaScript exports', () => { expect(indexModule).toMatchInlineSnapshot(` Object { + "GetGrantedExecutionPermissionsResultStruct": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "chainId": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "context": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "delegationManager": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "dependencies": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "factory": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "factoryData": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "type": "array", + "validator": [Function], + }, + "from": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "permission": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "data": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "record", + "validator": [Function], + }, + "isAdjustmentAllowed": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "boolean", + "validator": [Function], + }, + "type": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "to": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "type": "array", + "validator": [Function], + }, + "GetSupportedExecutionPermissionsResultStruct": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "record", + "validator": [Function], + }, + "GrantedExecutionPermissionStruct": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "chainId": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "context": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "delegationManager": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "dependencies": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "factory": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "factoryData": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "type": "array", + "validator": [Function], + }, + "from": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "permission": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "data": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "record", + "validator": [Function], + }, + "isAdjustmentAllowed": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "boolean", + "validator": [Function], + }, + "type": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "to": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, + "SupportedExecutionPermissionConfigStruct": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Object { + "chainIds": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "type": "array", + "validator": [Function], + }, + "ruleTypes": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": Struct { + "coercer": [Function], + "entries": [Function], + "refiner": [Function], + "schema": null, + "type": "string", + "validator": [Function], + }, + "type": "array", + "validator": [Function], + }, + }, + "type": "object", + "validator": [Function], + }, "createBlockCacheMiddleware": [Function], "createBlockRefMiddleware": [Function], "createBlockRefRewriteMiddleware": [Function], From 19d4a5619092d61fe6faadd809450134014703ee Mon Sep 17 00:00:00 2001 From: MoMannn Date: Tue, 13 Jan 2026 10:36:20 +0100 Subject: [PATCH 06/11] validate params --- .../wallet-get-granted-execution-permissions.ts | 11 +++++++++++ .../wallet-get-supported-execution-permissions.ts | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts index 87289310c80..29ebb88ef8a 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts @@ -12,8 +12,15 @@ import { import { StrictHexStruct } from '@metamask/utils'; import type { Json, JsonRpcRequest } from '@metamask/utils'; +import { validateParams } from '../utils/validation'; import type { WalletMiddlewareContext } from '../wallet'; +/** + * Superstruct schema for the `wallet_getGrantedExecutionPermissions` request params. + * This method expects no parameters. + */ +export const GetGrantedExecutionPermissionsParamsStruct = object({}); + const DependencyStruct = object({ factory: StrictHexStruct, factoryData: StrictHexStruct, @@ -88,6 +95,10 @@ export function createWalletGetGrantedExecutionPermissionsHandler({ ); } + const { params } = request; + + validateParams(params, GetGrantedExecutionPermissionsParamsStruct); + return await processGetGrantedExecutionPermissions(request, context); }; } diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts index 7a3fbeb19b1..78a2d15c7dc 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts @@ -5,8 +5,15 @@ import { array, object, record, string } from '@metamask/superstruct'; import { StrictHexStruct } from '@metamask/utils'; import type { Json, JsonRpcRequest } from '@metamask/utils'; +import { validateParams } from '../utils/validation'; import type { WalletMiddlewareContext } from '../wallet'; +/** + * Superstruct schema for the `wallet_getSupportedExecutionPermissions` request params. + * This method expects no parameters. + */ +export const GetSupportedExecutionPermissionsParamsStruct = object({}); + /** * Superstruct schema for a supported permission type configuration. */ @@ -66,6 +73,10 @@ export function createWalletGetSupportedExecutionPermissionsHandler({ ); } + const { params } = request; + + validateParams(params, GetSupportedExecutionPermissionsParamsStruct); + return await processGetSupportedExecutionPermissions(request, context); }; } From 9682e1ce175fdad5bc5454fe61c6b4a4542e6a18 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Tue, 13 Jan 2026 10:58:43 +0100 Subject: [PATCH 07/11] add check for empty array and undefined --- ...-get-granted-execution-permissions.test.ts | 22 ++++++++++++++++++ ...allet-get-granted-execution-permissions.ts | 7 ++++-- ...et-supported-execution-permissions.test.ts | 22 ++++++++++++++++++ ...let-get-supported-execution-permissions.ts | 7 ++++-- .../src/utils/structs.ts | 23 +++++++++++++++++++ 5 files changed, 77 insertions(+), 4 deletions(-) create mode 100644 packages/eth-json-rpc-middleware/src/utils/structs.ts diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts index 49fdb33ff49..ac0b7359741 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts @@ -83,4 +83,26 @@ describe('wallet_getGrantedExecutionPermissions', () => { 'wallet_getGrantedExecutionPermissions - no middleware configured', ); }); + + describe('params validation', () => { + it.each([ + ['undefined', undefined], + ['empty array', []], + ['empty object', {}], + ])('accepts params as %s', async (_description, params) => { + request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; + await expect(callMethod()).resolves.toStrictEqual(RESULT_MOCK); + }); + + it.each([ + ['non-empty array', [1]], + ['non-empty object', { foo: 'bar' }], + ['string', 'invalid'], + ['number', 123], + ['null', null], + ])('rejects invalid params: %s', async (_description, params) => { + request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; + await expect(callMethod()).rejects.toThrow(/Invalid params/u); + }); + }); }); diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts index 29ebb88ef8a..6a3eab95daa 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts @@ -12,14 +12,17 @@ import { import { StrictHexStruct } from '@metamask/utils'; import type { Json, JsonRpcRequest } from '@metamask/utils'; +import { NoParamsStruct } from '../utils/structs'; import { validateParams } from '../utils/validation'; import type { WalletMiddlewareContext } from '../wallet'; /** * Superstruct schema for the `wallet_getGrantedExecutionPermissions` request params. - * This method expects no parameters. + * + * This method expects no parameters. Different JSON-RPC clients may send "no params" + * in different ways (omitted, empty array, or empty object), so we accept all three. */ -export const GetGrantedExecutionPermissionsParamsStruct = object({}); +export const GetGrantedExecutionPermissionsParamsStruct = NoParamsStruct; const DependencyStruct = object({ factory: StrictHexStruct, diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts index 3f15b05591f..73f3ce13810 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts @@ -74,4 +74,26 @@ describe('wallet_getSupportedExecutionPermissions', () => { 'wallet_getSupportedExecutionPermissions - no middleware configured', ); }); + + describe('params validation', () => { + it.each([ + ['undefined', undefined], + ['empty array', []], + ['empty object', {}], + ])('accepts params as %s', async (_description, params) => { + request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; + await expect(callMethod()).resolves.toStrictEqual(RESULT_MOCK); + }); + + it.each([ + ['non-empty array', [1]], + ['non-empty object', { foo: 'bar' }], + ['string', 'invalid'], + ['number', 123], + ['null', null], + ])('rejects invalid params: %s', async (_description, params) => { + request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; + await expect(callMethod()).rejects.toThrow(/Invalid params/u); + }); + }); }); diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts index 78a2d15c7dc..120f947aae1 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.ts @@ -5,14 +5,17 @@ import { array, object, record, string } from '@metamask/superstruct'; import { StrictHexStruct } from '@metamask/utils'; import type { Json, JsonRpcRequest } from '@metamask/utils'; +import { NoParamsStruct } from '../utils/structs'; import { validateParams } from '../utils/validation'; import type { WalletMiddlewareContext } from '../wallet'; /** * Superstruct schema for the `wallet_getSupportedExecutionPermissions` request params. - * This method expects no parameters. + * + * This method expects no parameters. Different JSON-RPC clients may send "no params" + * in different ways (omitted, empty array, or empty object), so we accept all three. */ -export const GetSupportedExecutionPermissionsParamsStruct = object({}); +export const GetSupportedExecutionPermissionsParamsStruct = NoParamsStruct; /** * Superstruct schema for a supported permission type configuration. diff --git a/packages/eth-json-rpc-middleware/src/utils/structs.ts b/packages/eth-json-rpc-middleware/src/utils/structs.ts new file mode 100644 index 00000000000..2d0c23d97fd --- /dev/null +++ b/packages/eth-json-rpc-middleware/src/utils/structs.ts @@ -0,0 +1,23 @@ +import { define, object, optional, union } from '@metamask/superstruct'; + +/** + * Superstruct schema for an empty array []. + * Validates that the value is an array with zero elements. + */ +export const EmptyArrayStruct = define<[]>('EmptyArray', (value) => + Array.isArray(value) && value.length === 0 + ? true + : 'Expected an empty array', +); + +/** + * Superstruct schema for JSON-RPC methods that expect no parameters. + * + * Different JSON-RPC clients may send "no params" in different ways: + * - Omitted entirely (undefined) + * - Empty array [] + * - Empty object {} + * + * This struct accepts all three forms for maximum compatibility. + */ +export const NoParamsStruct = optional(union([object({}), EmptyArrayStruct])); From 8e94f86b2eb84817944e0ae1f0140e36b6f893c1 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Tue, 13 Jan 2026 11:02:55 +0100 Subject: [PATCH 08/11] linter fixes --- .../methods/wallet-get-granted-execution-permissions.test.ts | 2 +- .../wallet-get-supported-execution-permissions.test.ts | 2 +- packages/eth-json-rpc-middleware/src/utils/structs.ts | 4 +--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts index ac0b7359741..f11285ada1e 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts @@ -91,7 +91,7 @@ describe('wallet_getGrantedExecutionPermissions', () => { ['empty object', {}], ])('accepts params as %s', async (_description, params) => { request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; - await expect(callMethod()).resolves.toStrictEqual(RESULT_MOCK); + expect(await callMethod()).toStrictEqual(RESULT_MOCK); }); it.each([ diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts index 73f3ce13810..6f74c162ebc 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-supported-execution-permissions.test.ts @@ -82,7 +82,7 @@ describe('wallet_getSupportedExecutionPermissions', () => { ['empty object', {}], ])('accepts params as %s', async (_description, params) => { request = { ...REQUEST_MOCK, params } as unknown as JsonRpcRequest; - await expect(callMethod()).resolves.toStrictEqual(RESULT_MOCK); + expect(await callMethod()).toStrictEqual(RESULT_MOCK); }); it.each([ diff --git a/packages/eth-json-rpc-middleware/src/utils/structs.ts b/packages/eth-json-rpc-middleware/src/utils/structs.ts index 2d0c23d97fd..dccf4565573 100644 --- a/packages/eth-json-rpc-middleware/src/utils/structs.ts +++ b/packages/eth-json-rpc-middleware/src/utils/structs.ts @@ -5,9 +5,7 @@ import { define, object, optional, union } from '@metamask/superstruct'; * Validates that the value is an array with zero elements. */ export const EmptyArrayStruct = define<[]>('EmptyArray', (value) => - Array.isArray(value) && value.length === 0 - ? true - : 'Expected an empty array', + Array.isArray(value) && value.length === 0 ? true : 'Expected an empty array', ); /** From 2789a30191764f3053fb98f68a979ce054c27504 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Wed, 14 Jan 2026 10:30:50 +0100 Subject: [PATCH 09/11] align request execution permission with 7715 --- packages/eth-json-rpc-middleware/src/index.ts | 1 + ...llet-request-execution-permissions.test.ts | 53 +++++++++---------- .../wallet-request-execution-permissions.ts | 23 ++++---- 3 files changed, 36 insertions(+), 41 deletions(-) diff --git a/packages/eth-json-rpc-middleware/src/index.ts b/packages/eth-json-rpc-middleware/src/index.ts index 25e6c0e9c58..8efff9e55d6 100644 --- a/packages/eth-json-rpc-middleware/src/index.ts +++ b/packages/eth-json-rpc-middleware/src/index.ts @@ -5,6 +5,7 @@ export * from './block-tracker-inspector'; export { createFetchMiddleware } from './fetch'; export * from './inflight-cache'; export type { + PermissionDependency, RequestExecutionPermissionsRequestParams, RequestExecutionPermissionsResult, ProcessRequestExecutionPermissionsHook, diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts index 430cbff7136..5275b3e8f23 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts @@ -9,21 +9,20 @@ import type { import { createWalletRequestExecutionPermissionsHandler } from './wallet-request-execution-permissions'; import type { WalletMiddlewareParams } from '../wallet'; -const ADDRESS_MOCK = '0x123abc123abc123abc123abc123abc123abc123a'; +const FROM_ADDRESS_MOCK = '0x123abc123abc123abc123abc123abc123abc123A'; +const TO_ADDRESS_MOCK = '0x016562aA41A8697720ce0943F003141f5dEAe006'; const CHAIN_ID_MOCK = '0x1'; const CONTEXT_MOCK = '0x123abc'; +const DELEGATION_MANAGER_MOCK = '0xabc123abc123abc123abc123abc123abc123abc1'; +const FACTORY_MOCK = '0xdef456def456def456def456def456def456def4'; +const FACTORY_DATA_MOCK = '0x1234'; const REQUEST_MOCK = { params: [ { chainId: CHAIN_ID_MOCK, - address: ADDRESS_MOCK, - signer: { - type: 'account', - data: { - address: ADDRESS_MOCK, - }, - }, + from: FROM_ADDRESS_MOCK, + to: TO_ADDRESS_MOCK, permission: { type: 'test-permission', isAdjustmentAllowed: true, @@ -32,7 +31,6 @@ const REQUEST_MOCK = { rules: [ { type: 'test-rule', - isAdjustmentAllowed: false, data: { ruleKey: 'ruleValue' }, }, ], @@ -43,11 +41,8 @@ const REQUEST_MOCK = { const RESULT_MOCK: RequestExecutionPermissionsResult = [ { chainId: CHAIN_ID_MOCK, - address: ADDRESS_MOCK, - signer: { - type: 'account', - data: { address: ADDRESS_MOCK }, - }, + from: FROM_ADDRESS_MOCK, + to: TO_ADDRESS_MOCK, permission: { type: 'test-permission', isAdjustmentAllowed: true, @@ -56,11 +51,17 @@ const RESULT_MOCK: RequestExecutionPermissionsResult = [ rules: [ { type: 'test-rule', - isAdjustmentAllowed: false, data: { ruleKey: 'ruleValue' }, }, ], context: CONTEXT_MOCK, + dependencies: [ + { + factory: FACTORY_MOCK, + factoryData: FACTORY_DATA_MOCK, + }, + ], + delegationManager: DELEGATION_MANAGER_MOCK, }, ]; @@ -106,8 +107,8 @@ describe('wallet_requestExecutionPermissions', () => { expect(result).toStrictEqual(RESULT_MOCK); }); - it('supports null rules', async () => { - params[0].rules = null as never; + it('supports undefined rules', async () => { + params[0].rules = undefined; await callMethod(); @@ -118,8 +119,8 @@ describe('wallet_requestExecutionPermissions', () => { ); }); - it('supports optional address', async () => { - params[0].address = undefined as never; + it('supports optional from', async () => { + params[0].from = undefined; await callMethod(); @@ -148,7 +149,7 @@ describe('wallet_requestExecutionPermissions', () => { it('throws if missing properties', async () => { params[0].chainId = undefined as never; - params[0].signer = undefined as never; + params[0].to = undefined as never; params[0].permission = undefined as never; await expect(callMethod()).rejects.toThrow('Invalid params'); @@ -156,13 +157,9 @@ describe('wallet_requestExecutionPermissions', () => { it('throws if wrong types', async () => { params[0].chainId = 123 as never; - params[0].address = 123 as never; + params[0].from = 123 as never; + params[0].to = 123 as never; params[0].permission = '123' as never; - params[0].signer = { - // Make signer an object but invalid to ensure object-type error messages are stable - type: 123 as never, - data: '123' as never, - } as never; params[0].rules = [{} as never]; await expect(callMethod()).rejects.toThrow('Invalid params'); @@ -170,8 +167,8 @@ describe('wallet_requestExecutionPermissions', () => { it('throws if not hex', async () => { params[0].chainId = '123' as never; - params[0].address = '123' as never; - params[0].signer.data.address = '123' as never; + params[0].from = '123' as never; + params[0].to = '123' as never; await expect(callMethod()).rejects.toThrow('Invalid params'); }); diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts index cb1c0f17f53..eb38b61855f 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts @@ -4,12 +4,10 @@ import type { Infer } from '@metamask/superstruct'; import { array, boolean, - literal, object, optional, record, string, - union, unknown, } from '@metamask/superstruct'; import { HexChecksumAddressStruct, StrictHexStruct } from '@metamask/utils'; @@ -26,23 +24,15 @@ const PermissionStruct = object({ const RuleStruct = object({ type: string(), - isAdjustmentAllowed: boolean(), data: record(string(), unknown()), }); -const AccountSignerStruct = object({ - type: literal('account'), - data: object({ - address: HexChecksumAddressStruct, - }), -}); - const PermissionRequestStruct = object({ chainId: StrictHexStruct, - address: optional(HexChecksumAddressStruct), - signer: AccountSignerStruct, + from: optional(HexChecksumAddressStruct), + to: HexChecksumAddressStruct, permission: PermissionStruct, - rules: optional(union([array(RuleStruct), literal(null)])), + rules: optional(array(RuleStruct)), }); export const RequestExecutionPermissionsStruct = array(PermissionRequestStruct); @@ -52,9 +42,16 @@ export type RequestExecutionPermissionsRequestParams = Infer< typeof RequestExecutionPermissionsStruct >; +export type PermissionDependency = { + factory: Hex; + factoryData: Hex; +}; + export type RequestExecutionPermissionsResult = Json & (Infer & { context: Hex; + dependencies: PermissionDependency[]; + delegationManager: Hex; })[]; export type ProcessRequestExecutionPermissionsHook = ( From 9b722053e4f6e74f5af427b0d07cf922bd60f27c Mon Sep 17 00:00:00 2001 From: MoMannn Date: Wed, 14 Jan 2026 10:31:34 +0100 Subject: [PATCH 10/11] update types --- .../wallet-get-granted-execution-permissions.test.ts | 4 ++-- .../methods/wallet-get-granted-execution-permissions.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts index f11285ada1e..6444b5f7bbd 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.test.ts @@ -10,7 +10,7 @@ import type { WalletMiddlewareParams } from '../wallet'; const RESULT_MOCK: GetGrantedExecutionPermissionsResult = [ { chainId: '0x01' as Hex, - from: '0x1234567890123456789012345678901234567890' as Hex, + from: '0x5B38Da6a701c568545dCfcB03FcB875f56beddC4' as Hex, to: '0x016562aA41A8697720ce0943F003141f5dEAe006' as Hex, permission: { type: 'native-token-allowance', @@ -27,7 +27,7 @@ const RESULT_MOCK: GetGrantedExecutionPermissionsResult = [ factoryData: '0xabcdef' as Hex, }, ], - delegationManager: '0x1234567890123456789012345678901234567890' as Hex, + delegationManager: '0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2' as Hex, }, ]; diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts index 6a3eab95daa..d58259d8de9 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-get-granted-execution-permissions.ts @@ -9,7 +9,7 @@ import { string, unknown, } from '@metamask/superstruct'; -import { StrictHexStruct } from '@metamask/utils'; +import { HexChecksumAddressStruct, StrictHexStruct } from '@metamask/utils'; import type { Json, JsonRpcRequest } from '@metamask/utils'; import { NoParamsStruct } from '../utils/structs'; @@ -40,12 +40,12 @@ const PermissionStruct = object({ */ export const GrantedExecutionPermissionStruct = object({ chainId: StrictHexStruct, - from: StrictHexStruct, - to: StrictHexStruct, + from: HexChecksumAddressStruct, + to: HexChecksumAddressStruct, permission: PermissionStruct, context: StrictHexStruct, dependencies: array(DependencyStruct), - delegationManager: StrictHexStruct, + delegationManager: HexChecksumAddressStruct, }); /** From 8665f45e1cb7dcd041285486ec36d164a0905d40 Mon Sep 17 00:00:00 2001 From: MoMannn Date: Wed, 14 Jan 2026 10:40:04 +0100 Subject: [PATCH 11/11] revert to more inclusive rules check --- .../wallet-request-execution-permissions.test.ts | 12 ++++++++++++ .../methods/wallet-request-execution-permissions.ts | 4 +++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts index 5275b3e8f23..a2127612276 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.test.ts @@ -119,6 +119,18 @@ describe('wallet_requestExecutionPermissions', () => { ); }); + it('supports null rules', async () => { + params[0].rules = null as never; + + await callMethod(); + + expect(processRequestExecutionPermissionsMock).toHaveBeenCalledWith( + params, + request, + context, + ); + }); + it('supports optional from', async () => { params[0].from = undefined; diff --git a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts index eb38b61855f..dc2ec4027a8 100644 --- a/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts +++ b/packages/eth-json-rpc-middleware/src/methods/wallet-request-execution-permissions.ts @@ -4,10 +4,12 @@ import type { Infer } from '@metamask/superstruct'; import { array, boolean, + literal, object, optional, record, string, + union, unknown, } from '@metamask/superstruct'; import { HexChecksumAddressStruct, StrictHexStruct } from '@metamask/utils'; @@ -32,7 +34,7 @@ const PermissionRequestStruct = object({ from: optional(HexChecksumAddressStruct), to: HexChecksumAddressStruct, permission: PermissionStruct, - rules: optional(array(RuleStruct)), + rules: optional(union([array(RuleStruct), literal(null)])), }); export const RequestExecutionPermissionsStruct = array(PermissionRequestStruct);