---
eip: 7715
title: Request Permissions from Wallets
description: Adds JSON-RPC method for requesting permissions from a wallet
author: Luka Isailovic (@lukaisailovic), Derek Rein (@arein), Dan Finlay (@danfinlay), Derek Chiang (@derekchiang), Fil Makarov (@filmakarov), Pedro Gomes (@pedrouid), Conner Swenberg (@ilikesymmetry), Lukas Rosario (@lukasrosario), Idris Bowman (@V00D00-child), Jeff Smale (@jeffsmale90)
discussions-to: https://ethereum-magicians.org/t/erc-7715-grant-permissions-from-wallets/20100
status: Draft
type: Standards Track
category: ERC
created: 2024-05-24
requires: 4337, 7710
---

## Abstract

We define a new JSON-RPC method `wallet_requestExecutionPermissions` for DApp to request a Wallet to grant permissions in order to execute transactions on the user’s behalf. This enables two use cases:

- Executing transactions for users without a wallet connection.
- Executing transactions for users with a wallet connection that is scoped with permissions.

## Motivation

Currently most DApps implement a flow similar to the following:

![Wallet Approve Flow](../assets/eip-7715/approve-flow.svg)

Each interaction requires the user to sign a transaction with their wallet. The problems are:

- It can get tedious for the user to manually approve every transaction, especially in highly-interactive applications such as games.
- It’s impossible to send transactions for users without an active wallet connection. This invalidates use cases such as subscriptions, passive investments, limit orders, and more.

## Specification

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

### Permission Types, Rule Types

This ERC does not specify an exhaustive list of rule or permission types, since we expect more rule and permission types to be developed as wallets get more advanced. A permission type, or rule type is valid as long as both the DApp and the wallet are willing to support it.

However, if two permissions or two rules share the same type name, a DApp could request with one type of permission, or rule while the wallet grants another. Therefore, it’s important that no two permissions, or two rules share the same type. Furthermore, new permission types or rule types should be specified in addition ERCs. In all cases, these new types MUST inherit from the `BasePermission` or `BaseRule` scheme.

#### Permissions

`isAdjustmentAllowed` defines a boolean value that allows DApp to define whether the Wallet MAY attenuate(reduce or increase) the authority of a "permission" to meet the user’s terms for approval.

_For example, a DApp may require an allowance for a specific asset to complete a payment and does not want the user to adjust the requested allowance._

```tsx
type BasePermission = {
  type: string; // enum defined by ERCs
  isAdjustmentAllowed: boolean; // whether the wallet MAY attenuate the permission
  data: Record<string, any>; // specific to the type, structure defined by ERCs
};
```

#### Rules

```tsx
type BaseRule = {
  type: string; // enum defined by ERCs
  data: Record<string, any>; // specific to the type, structure defined by ERCs
};

// Constrains a permission so that it is only valid until a specified timestamp.
type ExpiryRule = BaseRule & {
  type: "expiry";
  data: {
    timestamp: number; // unix timestamp at which the permission becomes invalid
  };
};
```

### `wallet_requestExecutionPermissions`

We introduce a `wallet_requestExecutionPermissions` method for the DApp to request the Wallet to grant permissions.

#### Request Specification

```tsx
type PermissionRequest = {
  chainId: Hex; // hex-encoding of uint256
  from?: Address;
  to: Address;
  permission: {
    type: string; // enum defined by ERCs
    isAdjustmentAllowed: boolean; // whether the permission can be adjusted
    data: Record<string, any>; //specific to the type, structure defined by ERCs
  };
  rules?: {
    type: string; // enum defined by ERCs
    data: Record<string, any>; // specific to the type, structure defined by ERCs
  }[];
}[];
```

`chainId` defines the chain with [EIP-155](./eip-155.md) which applies to this permission request and all addresses can be found defined by other parameters.

`from` identifies the account being targeted for this permission request which is useful when a connection has been established and multiple accounts have been exposed. It is optional to let the user choose which account to grant permission for.

`to` is a field that identifies the DApp session account associated with the permission

`permission` defines the allowed behavior the `to` account can do on behalf of the `from` account. See the “Permission” section for details.

`rules` define the restrictions or conditions that a `to` account MUST abide by when using a permission to act on behalf of an account. See the “Rule” section for details.

**Request example**:

An array of `PermissionRequest` objects is the final `params` field expected by the `wallet_requestExecutionPermissions` RPC.

```tsx
[
  {
    chainId: "0x01",
    from: "0x...",
    to: "0x016562aA41A8697720ce0943F003141f5dEAe006",
    permission: {
      type: "native-token-allowance",
      isAdjustmentAllowed: false,
      data: {
        allowance: "0x1DCD6500",
      },
    },
    rules: [
      {
        type: "expiry",
        data: {
          timestamp: 1577840461,
        },
      },
    ],
  },
];
```

#### Response Specification

```tsx
type PermissionResponse = PermissionRequest & {
  context: Hex;
  dependencies: {
    factory: `0x${string}`;
    factoryData: `0x${string}`;
  }[];
  delegationManager: `0x${string}`;
};
```

First note that the response contains all of the parameters of the original request and it is not guaranteed that the values received are equivalent to those requested.

`context` is a catch-all to identify a permission for revoking permissions or redeeming permissions, and can contain non-identifying data as well. The `context` is required as defined in [ERC-7710](./eip-7710.md). See “Rationale” for details.

`dependencies` is an array of objects, each containing fields for `factory` and `factoryData` as defined in [ERC-4337](./eip-4337.md). Either both `factory` and `factoryData` must be specified in an entry, or neither. This array is used describe accounts that are not yet deployed but MUST be deployed in order for a permission to be successfully redeemed. If any of the involved accounts have not yet been deployed, the wallet MUST return the corresponding `dependencies`. If all accounts have already been deployed, the wallet MUST return an empty `dependencies` array. The DApp MUST deploy each account by calling the `factory` contract with `factoryData` as the calldata.

`delegationManager` is required as defined in [ERC-7710](./eip-7710.md).

If the request is malformed or the wallet is unable/unwilling to grant permissions, wallet MUST return an error with a code as defined in [ERC-1193](./eip-1193.md).

`wallet_requestExecutionPermissions` response example:

An array of `PermissionResponse` objects is the final `result` field expected by the `wallet_requestExecutionPermissions` RPC.

```tsx
[
  {
    // original request with modifications
    chainId: "0x01",
    from: "0x...",
    to: "0x016562aA41A8697720ce0943F003141f5dEAe006",
    permission: {
      type: "native-token-allowance",
      isAdjustmentAllowed: true,
      data: {
        allowance: "0x1DCD65000000",
      },
    },
    // response-specific fields
    context: "0x0x016562aA41A8697720ce0943F003141f5dEAe0060000771577157715",
    dependencies: [
      {
        factory: "0x...",
        factoryData: "0x...",
      },
    ],
    delegationManager: "0x...",
  },
];
```

### `wallet_revokeExecutionPermission`

Permissions can be revoked by calling this method and the wallet will respond with an empty response when successful.

#### Request Specification

```tsx
type RevokeExecutionPermissionRequestParams = {
  permissionContext: "0x{string}";
};
```

#### Response Specification

```tsx
type GetPermissionsInfoResultParams = {
  chainIds: `0x${string}`[];
};
```

### `wallet_getSupportedExecutionPermissions`

We introduce a `wallet_getSupportedExecutionPermissions` method for the Wallet to specify the permission types and rules types it supports.

#### Request Specification

**Request example**:

```tsx
window.ethereum.request({
  "method": "wallet_getSupportedExecutionPermissions",
  "params": []
}): Promise<GetSupportedExecutionPermissionsResult>
```

#### Response Specification

The wallet SHOULD include an object keyed on supported permission types including `ruleTypes` (`string[]`) that can be applied to the permission.

```tsx
type GetSupportedExecutionPermissionsResult = Record<
  "permission-type",
  {
    chainIds: `0x${string}`[];
    ruleTypes: string[];
  }
>; // Hex chain id
```

An object keyed on all permission types supported by the Wallet expected by the `wallet_getSupportedExecutionPermissions` RPC.

```json
{
  "native-token-allowance": {
    "chainIds": ["0x123", "0x345"],
    "rulesTypes": ["expiry"]
  },
  "erc20-token-allowance": {
    "chainIds": ["0x123"],
    "rulesTypes": []
  },
  "erc721-token-allowance": {
    "chainIds": ["0x123"],
    "rulesTypes": ["expiry"]
  }
}
```

### `wallet_getGrantedExecutionPermissions`

We introduce a `wallet_getGrantedExecutionPermissions` method for the DApp to retrieve previously granted permissions.

#### Request Specification

**Request example**:

```tsx
window.ethereum.request({
  "method": "wallet_getGrantedExecutionPermissions",
  "params": []
}): Promise<PermissionResponses[]>
```

#### Response Specification

The wallet MUST include all granted permissions that are not yet revoked.

```tsx
type PermissionResponses;
```

Example:

```tsx
[
  {
    chainId: "0x01",
    from: "0x...",
    to: "0x016562aA41A8697720ce0943F003141f5dEAe006",
    permission: {
      type: "native-token-allowance",
      isAdjustmentAllowed: true,
      data: {
        allowance: "0x1DCD65000000",
      },
    },
    context: "0x0x016562aA41A8697720ce0943F003141f5dEAe0060000771577157715",
    dependencies: [
      {
        factory: "0x...",
        factoryData: "0x...",
      },
    ],
    delegationManager: "0x...",
  },
];
```

### Sending transaction to redeem permissions

The permission response data will be redeemable by the `account` defined in the `to` field, using the interfaces specified in ERC-7710. This allows the recipient of the permissions to use any account type (EOA or contract) to form a transaction or UserOp using whatever payment or relay infrastructure they prefer, by sending an internal message to the returned `permissions.delegationManager` and calling its `function redeemDelegation(bytes[] calldata _permissionContexts, bytes32[] calldata _modes, bytes[] calldata _executionCallData) external;` function with the `_permissionContexts` parameter set to the returned `permissions.context`, and the `_executionCallData` data forming the message that the permissions recipient desires the user's account to emit, as defined by this struct:

```
struct Execution {
  address target;
  uint256 value;
  bytes callData;
}
```

A simple pseudocode example of using a permission in this way, where DApp wants to request a permission from `bob` might be like this:

```typescript
// Alice requests a permission from Bob
const permissionsResponse = await window.ethereum.request({
  method: 'wallet_requestExecutionPermissions',
  params: [{
    from: bob.address,
    chainId: "0x01",
    to: '0x_dapp_session_account',
    permission: {
      type: 'native-token-allowance',
      isAdjustmentAllowed: true,
      data: {
        allowance: '0x0DE0B6B3A7640000'
      },
    },
    rules: [
      {
        type: 'expiry';
        data: {
          timestamp: Math.floor(Date.now() / 1000) + 3600 // 1 hour from now
        },
      },
    ],
  }]
});

// Extract the permissionsContext and delegationManager
const permissionsContext = permissionsResponse.context;
const delegationManager = permissionsResponse.delegationManager;

// DApp forms the execution they want Bob's account to take
const execution = {
  target: bob.address,
  value: '0x06F05B59D3B20000',
  callData: '0x'
};
const encodedExecutionCalldata = encodePacked(
  ['address', 'uint256', 'bytes'],
  [execution.target, execution.value, execution.callData],
);

// Chose execution mode (SingleDefault)
const executionMode = '0x0000000000000000000000000000000000000000000000000000000000000000';

// DApp sends the transaction by calling redeemDelegation on with encode execution on Bob's account
const tx = await dapp.sendTransaction({
  to: delegationManager,
  data: encodeFunctionData({
    abi: DelegationManager.abi,
    functionName: 'redeemDelegations',
    args: [
      [permissionsContext],
      [executionMode],
      [encodedExecutionCalldata],
    ],
  })
});

```

**Example of the entire flow:**

```mermaid
sequenceDiagram
  participant DApp
  participant Provider as window.ethereum
  participant Wallet
  participant User
  participant Chain as Relay infrastructure


  Note over DApp: DApp discovers supported permission and rules types

  DApp->>Provider: request({method: "wallet_getSupportedExecutionPermissions", params: []})
  Provider->>Wallet: wallet_getSupportedExecutionPermissions

  Wallet->>DApp: Returns supported permission and rules types

  Note over DApp: DApp triggers permissions request

  DApp->>Provider: request({method: "wallet_requestExecutionPermissions", params: [ PermissionRequest[] ]})
  Provider->>Wallet: wallet_requestExecutionPermissions

  Wallet->>User: Display permission request<br/> (permissions, rules, to = account)
  User-->>Wallet: Approve or reject

  Wallet-->>Provider: PermissionResponse[]<br/>includes context,<br/>delegationManager,<br/>dependencies
  Provider-->>DApp: PermissionResponse[]

  alt Undeployed user account(s)
      DApp->>Chain: Deploy via factory using dependencies
      Chain-->>DApp: Deployment success
  end

  Note over DApp: DApp forms Action calldata<br/>to be executed by user's account

  DApp->>Chain: sendTransaction({<br/> to: delegationManager,<br/> data: redeemDelegations([context], [executionMode], [encodedAction])<br/>})

  Chain-->>DApp: tx receipt
```

## Rationale

The typical transaction flow of `suggesting transactions => approving transactions => sending transactions` is deeply limiting in several ways:

- Users must be online to send transactions. DApps cannot send transactions for users when they are offline, which makes use cases such as subscriptions or automated trading impossible.

- Users must manually approve every transaction, interrupting what could otherwise be a smooth user experience.

With this ERC, DApps can request Wallets to grant permissions and execute transactions on the user's behalf, therefore circumventing the issues above.

### `permissionsContext`

Since this ERC only specifies the interaction between the wallet and the DApp but not how the wallet enforces permissions, we need a flexible way for the wallet to pass along information to the DApp so that it can construct transactions that imbue the permissions.

The `permissionsContext` field is meant to be an opaque string that's maximally flexible and can encode arbitrary information for different permissions schemes.

DApps must submit transactions with the `account` specified in the `to` field, using the `permissionsContext` as the `_data` when interacting with the delegation manager.

### Non-exhaustive list of permissions and rules

With the advancement in wallet technologies, we expect new types of permissions and rules to be developed. We considered mandating that each permission and rule must have a UUID in order to avoid collisions, but ultimately decided to stick with the simpler approach for now of simply mandating that these types be defined in ERCs.

## **Backwards Compatibility**

Wallets that don’t support `wallet_requestExecutionPermissions` SHOULD return an error message if the JSON-RPC method is called.

## **Reference Implementation**

For a minimal reference implementation focusing on permission granting from a [EIP-1193](./eip-1193.md) Ethereum provider, please see [Example7715PermissionsRequestHandler](../assets/eip-7715/Example7715PermissionsRequestHandler.html).

For a complete reference implementation of a Permissions handler, see the MetaMask Permissions Snap, which includes features such as:

- Support for commonly used permission and rule types with ability to attenuate(reduce or increase) the requested capability to meet the user’s terms for approval.
- User encrypted storage for all permissions granted through the Wallet handler to enable revocation mechanisms.

## **Security Considerations**

### **Limited Permission Scope**

DApps should only request the permissions they need, with a reasonable expiration time.

Wallets MUST correctly enforce permissions. Ultimately, users must trust that their wallet software is implemented correctly, and permissions should be considered a part of the wallet implementation.

### **Phishing Attacks**

Malicious DApps could pose as legitimate applications and trick users into granting broad permissions. Wallets MUST clearly display the permissions to users and warn them against granting dangerous permissions.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
