# MetaMask Smart Accounts Kit documentation

> Complete documentation for MetaMask Smart Accounts Kit

This file contains all documentation content in a single document following the llmstxt.org standard.

## Advanced Permissions (ERC-7715)


The Smart Accounts Kit supports Advanced Permissions ([ERC-7715](https://eips.ethereum.org/EIPS/eip-7715)), which lets you request fine-grained permissions from a MetaMask user to execute transactions on their behalf.
For example, a user can grant your dapp permission to spend 10 USDC per day to buy ETH over the course of a month.
Once the permission is granted, your dapp can use the allocated 10 USDC each day to purchase ETH directly from the MetaMask user's account.

Advanced Permissions eliminate the need for users to approve every transaction, which is useful for highly interactive dapps.
It also enables dapps to execute transactions for users without an active wallet connection.

:::note
This feature requires [MetaMask](https://metamask.io/download) v13.23.0 or later.
See [supported Advanced Permissions](../get-started/supported-advanced-permissions.md) for the
minimum version required for each permission type.
:::

## ERC-7715 technical overview

[ERC-7715](https://eips.ethereum.org/EIPS/eip-7715) defines a JSON-RPC method `wallet_requestExecutionPermissions`.
Dapps can use this method to request a wallet to grant the dapp permission to execute transactions on a user's behalf.
`wallet_requestExecutionPermissions` requires a `signer` parameter, which identifies the entity requesting or managing the permission.
Common signer implementations include wallet signers, single key and multisig signers, and account signers.

The Smart Accounts Kit supports multiple signer types. The documentation uses [an account signer](../guides/advanced-permissions/execute-on-metamask-users-behalf.md) as a common implementation example.
When you use an account signer, a session account is created solely to request and redeem Advanced Permissions, and doesn't contain tokens.
The session account can be granted with permissions and redeem them as specified in [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710).
The session account can be a smart account or an externally owned account (EOA).

The MetaMask user that the session account requests permissions from must be upgraded to a [MetaMask smart account](smart-accounts.md).

## Advanced Permissions vs. delegations

Advanced Permissions expand on regular [delegations](delegation/overview.md) by enabling permission sharing _via the MetaMask browser extension_.

With regular delegations, the dapp constructs a delegation and requests the user to sign it.
These delegations are not human-readable, so it is the dapp's responsibility to provide context for the user.
Regular delegations cannot be signed through the MetaMask extension, because if a dapp requests a delegation without constraints, the whole wallet can be exposed to the dapp.

In contrast, Advanced Permissions enable dapps (and AI agents) to request permissions from a user directly via the MetaMask extension.
Advanced Permissions require a permission configuration which displays a human-readable confirmation for the MetaMask user.
The user can modify the permission parameters if the request is configured to allow adjustments.

For example, the following Advanced Permissions request displays a rich UI including the start time, amount, and period duration for an [ERC-20 token periodic transfer](../guides/advanced-permissions/use-permissions/erc20-token.md#erc-20-periodic-permission):

## Advanced Permissions lifecycle

The Advanced Permissions lifecycle is as follows:

1. **Set up a session account** - Set up a session account to execute transactions on behalf of the MetaMask user.
   It can be a [smart account](smart-accounts.md) or an externally owned account (EOA).

2. **Request permissions** - Request permissions from the user.
   The Smart Accounts Kit supports [ERC-20 token permissions](../guides/advanced-permissions/use-permissions/erc20-token.md) and
   [native token permissions](../guides/advanced-permissions/use-permissions/native-token.md).

3. **Redeem permissions** - Once the permission is granted, the session account can redeem the permission, executing on the user's behalf.

See [how to perform executions on a MetaMask user's behalf](../guides/advanced-permissions/execute-on-metamask-users-behalf.md) to get started with the Advanced Permissions lifecycle.

---

## Caveat enforcers


The Smart Accounts Kit provides caveat enforcers, which are smart contracts that implement rules and restrictions
on delegations. They serve as the underlying mechanism that enables conditional execution within the [Delegation Framework](./overview.md#delegation-framework).
See the [delegation flow](overview.md#delegation-flow) for how caveat enforcer hooks are called during delegation redemption.

A caveat enforcer acts as a gate that validates whether a delegation can be used for a particular execution.
When a delegate attempts to execute an action on behalf of a delegator, each caveat enforcer specified in
the delegation evaluates whether the execution meets its defined criteria.

:::warning Important

- Without caveat enforcers, a delegation has infinite and unbounded authority to make any execution the original account can make.
  We strongly recommend using caveat enforcers.
- Caveat enforcers safeguard the execution process but do not guarantee a final state post-redemption.
  Always consider the full impact of combined caveat enforcers.

:::

## Hooks

The interface consists of four key hook functions that are called at different stages of the delegation redemption process.
Each of these hooks receives comprehensive information about the execution context, including:

- The caveat terms specified by the delegator.
- Optional arguments provided by the redeemer.
- The execution mode and calldata.
- The delegation hash.
- The delegator and redeemer addresses.

| Hook            | Description                                                                                                                                       |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `beforeAllHook` | Called before any actions in a batch redemption process begin. Verifies conditions that must be true for the entire batch execution.              |
| `beforeHook`    | Called before the execution tied to a specific delegation. Allows for pre-execution validation of conditions specific to that delegation.         |
| `afterHook`     | Called after the execution tied to a specific delegation completes. Verifies post-execution state changes or effects specific to that delegation. |
| `afterAllHook`  | Called after all actions in a batch redemption process have completed. Verifies final conditions after the entire batch has executed.             |

The most important safety feature of these hooks is their ability to block executions:

- If any hook determines its conditions aren't met, it will **revert** (throw an exception).
- When a reversion occurs, the entire delegation redemption process is canceled.
- This prevents partial or invalid executions from occurring.
- No state changes from the attempted execution will be committed to the blockchain.

This "all-or-nothing" approach ensures that delegations only execute exactly as intended by their caveats.

## Available caveat enforcers

The Smart Accounts Kit provides [out-of-the-box caveat enforcers](../../reference/delegation/caveats.md)
for common restriction patterns, including:

- Limiting target addresses and methods.
- Setting time or block number constraints.
- Restricting token transfers and approvals.
- Limiting execution frequency.

For other restriction patterns, you can also [create custom caveat enforcers](/tutorials/create-custom-caveat-enforcer) by implementing the `ICaveatEnforcer` interface.

---

## Delegation Manager


The Delegation Manager is a core component of the [Delegation Framework](./overview.md#delegation-framework).
It validates delegations and triggers executions on behalf of the delegator, ensuring tasks are executed accurately,
and securely.

See the [delegation flow](./overview.md#delegation-flow) for a full overview of how delegations are created, validated, and redeemed.

## Execution modes

The Delegation Manager processes delegations based on a specified execution mode. When redeeming a delegation using [`redeemDelegations`](../../reference/delegation/index.md#redeemdelegations), you must
pass an execution mode for each delegation chain you pass to the method. The Smart Accounts Kit supports the following
execution modes, based on [ERC-7579](https://erc7579.com/):

| Execution mode  | Number of delegation chains passed to `redeemDelegations` | Processing method | Does user operation continue execution if redemption reverts? |
| --------------- | --------------------------------------------------------- | ----------------- | ------------------------------------------------------------- |
| `SingleDefault` | One                                                       | Sequential        | No                                                            |
| `SingleTry`     | One                                                       | Sequential        | Yes                                                           |
| `BatchDefault`  | Multiple                                                  | Interleaved       | No                                                            |
| `BatchTry`      | Multiple                                                  | Interleaved       | Yes                                                           |

### Sequential processing

In `Single` modes, the Delegation Manager processes delegations sequentially:

1. For each delegation in the chain, all caveats' `before` hooks are called.
2. The single redeemed action is executed.
3. For each delegation in the chain, all caveats' `after` hooks are called.

### Interleaved processing

In `Batch` modes, the Delegation Manager processes delegations in an interleaved manner:

1. For each chain in the batch, and each delegation in the chain, all caveats' `before` hooks are called.
2. Each redeemed action is executed.
3. For each chain in the batch, and each delegation in the chain, all caveats' `after` hooks are called.

`Batch` mode allows for powerful use cases, but the Delegation Framework currently does not include any `Batch` compatible caveat enforcers.

---

## Delegation scopes


When creating a delegation, you must configure a scope to define the delegation's initial authority and help prevent delegation misuse.

Scopes are not part of the [Delegation Framework](overview.md#delegation-framework) itself, but an abstraction introduced in the Smart Accounts Kit that builds on top of [caveat enforcers](caveat-enforcers.md) to provide pre-configured restriction patterns for common use cases.

## Scopes vs. caveats

Scopes and caveats work together to define and restrict a delegation's authority:

- **Scopes** define the _initial authority_ of a delegation. They determine the broad category of actions the delegate is permitted to perform, such as transferring tokens or calling specific contract functions.
- **Caveats** further _constrain_ the authority granted by the scope. They add additional restrictions on top of the scope, such as time limits or execution frequency.

For example, a spending limit scope might allow a delegate to transfer up to 100 USDC, while an additional caveat could restrict the transfers to only occur within a specific time window.

See [how to constrain a delegation's scope by adding caveats](../../guides/delegation/use-delegation-scopes/constrain-scope.md).

## Categories

The Smart Accounts Kit supports three categories of scopes:

| Scope type                                                                                      | Description                                                                                                                         |
| ----------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [Spending limit scopes](../../guides/delegation/use-delegation-scopes/spending-limit.md)        | Restricts the spending of native, ERC-20, and ERC-721 tokens based on defined conditions.                                           |
| [Function call scope](../../guides/delegation/use-delegation-scopes/function-call.md)           | Restricts the delegation to specific contract methods, contract addresses, or calldata.                                             |
| [Ownership transfer scope](../../guides/delegation/use-delegation-scopes/ownership-transfer.md) | Restricts the delegation to only allow ownership transfers, specifically the `transferOwnership` function for a specified contract. |

---

## Delegation


Delegation is the ability for a [MetaMask smart account](../smart-accounts.md) to grant permission to another smart contract
or externally owned account (EOA) to perform specific executions on its behalf.
The account that grants the permission is called the delegator account, while the account that receives the permission
is called the delegate account.

The Smart Accounts Kit follows the [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) standard for smart contract delegation.
In addition, users can use [delegation scopes](delegation-scopes.md) and [caveat enforcers](caveat-enforcers.md) to apply rules and restrictions to delegations.
For example, Alice delegates the ability to spend her USDC to Bob, limiting the amount to 100 USDC.

## Delegation types

You can create the following delegation types:

### Root delegation

A root delegation is when a delegator delegates their own authority away, as opposed to _redelegating_ permissions
they received from a previous delegation. In a chain of delegations, the first delegation is the root delegation.
For example, Alice delegates the ability to spend her USDC to Bob, limiting the amount to 100 USDC.

Use [`createDelegation`](../../reference/delegation/index.md#createdelegation) to create a root delegation.

### Open root delegation

An open root delegation is a root delegation that doesn't specify a delegate. This means that any account can
redeem the delegation. For example, Alice delegates the ability to spend 100 of her USDC to anyone.

You must create open root delegations carefully, to ensure that they are not misused.
Use [`createOpenDelegation`](../../reference/delegation/index.md#createopendelegation) to create an open root delegation.

### Redelegation

A delegate can redelegate permissions that have been granted to them, creating a chain of delegations across trusted parties.
For example, Alice delegates the ability to spend 100 of her USDC to Bob. Bob redelegates the ability to spend
50 of Alice's 100 USDC to Carol.

See [how to create a redelegation](../../guides/delegation/create-redelegation.md) guide to learn more.

### Open redelegation

An open redelegation is a redelegation that doesn't specify a delegate. This means that any account can redeem
the redelegation. For example, Alice delegates the ability to spend 100 of her USDC to Bob. Bob redelegates
the ability to spend 50 of Alice's 100 USDC to anyone.

As with open root delegations, you must create open redelegations carefully, to ensure that they are not misused.
Use [`createOpenDelegation`](../../reference/delegation/index.md#createopendelegation) to create an open redelegation.

## Attenuating authority

When creating chains of delegations via redelegations, it's important to understand how authority flows and can be restricted.

- Each delegation in the chain inherits all restrictions from its parent delegation.
- New caveats can add further restrictions, but can't remove existing ones.

This means that a delegate can only redelegate with equal or lesser authority than they received.

## Delegation flow

The delegation flow consists of the following steps:

```mermaid
%%{
  init: {
    'sequence': {
      'actorMargin': 30,
      'width': 250
    }
  }
}%%

sequenceDiagram
    participant Delegator
    participant Delegate
    participant Manager as Delegation Manager
    participant Enforcer as Caveat enforcer

    Delegator->>Delegator: Create delegation with caveat enforcers
    Delegator->>Delegator: Sign delegation
    Delegator->>Delegate: Send signed delegation
    Note right of Delegate: Hold delegation until redemption

    Delegate->>Manager: redeemDelegations() with delegation & execution details
    Manager->>Delegator: isValidSignature()
    Delegator-->>Manager: Confirm valid (or not)

    Manager->>Enforcer: beforeAllHook()
    Note right of Manager: Expect no error
    Manager->>Enforcer: beforeHook()
    Note right of Manager: Expect no error

    Manager->>Delegator: executeFromExecutor() with execution details
    Delegator->>Delegator: Perform execution
    Note right of Manager: Expect no error

    Manager->>Enforcer: afterHook()
    Note right of Manager: Expect no error
    Manager->>Enforcer: afterAllHook()
    Note right of Manager: Expect no error
```

### Step 1. Create a delegation

The delegator creates a delegation, configuring a [scope](delegation-scopes.md) and
optional [caveats](caveat-enforcers.md) that define the conditions under which the delegation can be redeemed.

### Step 2. Sign the delegation

The delegator signs the delegation, producing a verifiable signature that the [Delegation Manager](delegation-manager.md) can later validate.

### Step 3. Send the signed delegation

The delegator sends the signed delegation to the delegate. A dapp can store the delegation in the storage solution
of their choice (such as a local database, Filecoin, or other databases), enabling retrieval for future redemption.

### Step 4. Redeem the delegation

The delegate submits the signed delegation to the Delegation Manager by calling `redeemDelegations()` with the
delegation and execution details.

### Step 5. Validate the delegation

The Delegation Manager validates the input data by ensuring the lengths of `delegations`, `modes`, and
`executions` match. It also verifies delegation signatures, ensuring validity using ECDSA (for EOAs) or
`isValidSignature` (for contracts).

### Step 6. Execute `beforeHook`

If the signature validation passes, the Delegation Manager executes the `beforeHook` for each [caveat](caveat-enforcers.md)
in the delegation, passing relevant data (`terms`, `arguments`, `mode`, `execution` `calldata`, and `delegationHash`) to
the caveat enforcer.

### Step 7. Perform execution

If `beforeHook` validation passes, the Delegation Manager calls `executeFromExecutor` to perform the delegation's
execution, either by the delegator or the caller for self-authorized executions.

### Step 8. Execute `afterHook`

The Delegation Manager runs each caveat enforcer's `afterHook` and `afterAllHook` to verify post-execution conditions.

See [how to perform executions on a smart account's behalf](../../guides/delegation/execute-on-smart-accounts-behalf.md) for a step-by-step guide.

## Delegation Framework

The Smart Accounts Kit includes the Delegation Framework, a
[set of comprehensively audited smart contracts](https://github.com/MetaMask/delegation-framework) that
collectively handle smart account creation, the delegation lifecycle, and caveat enforcement.

It consists of the following components:

| Component                                   | Description                                                                                                                    |
| ------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| [Delegation Manager](delegation-manager.md) | Validates delegations and triggers executions on behalf of the delegator, ensuring tasks are executed accurately and securely. |
| [Caveat enforcers](caveat-enforcers.md)     | Manage rules and restrictions for delegations, providing fine-tuned control over delegated executions.                         |

---

## MetaMask Smart Accounts


The Smart Accounts Kit enables you to create and manage MetaMask Smart Accounts.
MetaMask Smart Accounts are [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) smart contract accounts
that support programmable account behavior and advanced features such as multi-signature approvals,
automated transaction batching, and custom security policies.
Unlike traditional wallets, which rely on private keys for every transaction, MetaMask Smart Accounts use smart contracts to govern account logic.

MetaMask Smart Accounts are referenced in the toolkit as `MetaMaskSmartAccount`.

## Account abstraction (ERC-4337)

Account abstraction, specified by [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337), is a
mechanism that enables users to manage smart contract accounts containing arbitrary verification logic.
ERC-4337 enables smart contracts to be used as primary accounts in place of traditional private key-based
accounts, or externally owned accounts (EOAs).

ERC-4337 introduces the following concepts:

- **User operation** - A package of instructions signed by a user, specifying executions for
  the smart account to perform.
  User operations are collected and submitted to the network by bundlers.

- **Bundler** - A service that collects multiple user operations, packages them into a single transaction,
  and submits them to the network, optimizing gas costs and transaction efficiency.

- **Entry point contract** - A contract that validates and processes bundled user operations, ensuring they
  adhere to the required rules and security checks.

- **Paymasters** - Entities that handle the payment of gas fees on behalf of users, often integrated
  into smart accounts to facilitate gas abstraction.

## Smart account implementation types

The toolkit supports three types of MetaMask Smart Accounts, each offering unique features and use cases.

See [Create a smart account](../guides/smart-accounts/create-smart-account.md) to learn how to use these different account types.

### Hybrid smart account

The Hybrid smart account is a flexible implementation that supports both an externally owned account (EOA) owner and any number of passkey (WebAuthn) signers.
You can configure any of these signers, and use them to sign any data, including user operations, on behalf of the smart account.

This type is referenced in the toolkit as `Implementation.Hybrid`.

### Multisig smart account

The Multisig smart account is an implementation that supports multiple signers with a configurable threshold, allowing for enhanced security and flexibility in account management.
A valid signature requires signatures from at least the number of signers specified by the threshold.

This type is referenced in the toolkit as `Implementation.Multisig`.

### Stateless 7702 smart account

The Stateless 7702 smart account implementation represents an externally owned account (EOA) upgraded to
support smart account functionality as defined by [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702). This implementation enables EOAs to perform smart account operations, including the creation and management of delegations.

This type is referenced in the toolkit as `Implementation.Stateless7702`.

## Smart account flow

The MetaMask Smart Accounts flow is as follows:

1. **Account setup** - A user creates a smart account by deploying a smart contract, and initializing it with
   ownership and security settings.
   The user can customize the smart account in the following ways:
   - **Account logic** - They can configure custom logic for actions such as multi-signature
     approvals, spending limits, and automated transaction batching.

   - **Security and recovery** - They can configure advanced security features such as two-factor
     authentication and mechanisms for account recovery involving trusted parties.

   - **Gas management** - They can configure flexible gas payment options, including alternative
     tokens or third-party sponsorship.

2. **User operation creation** - For actions such as sending transactions, a user operation is created with
   necessary details and signed by the configured signers.

3. **Bundlers and mempool** - The signed user operation is submitted to a special mempool, where bundlers
   collect and package multiple user operations into a single transaction to save on gas costs.

4. **Validation and execution** - The bundled transaction goes to an entry point contract, which
   validates each user operation and executes them if they meet the smart contract's rules.

## Delegator accounts

Delegator accounts are a type of MetaMask smart account that allows users to grant permission to other smart accounts or EOAs
to perform specific executions on their behalf, under defined rules and restrictions.
Learn more about [delegation](delegation/overview.md).

---

## Install and set up the Smart Accounts Kit


This page provides instructions to install and set up the Smart Accounts Kit in your dapp, enabling you to create and interact with <GlossaryTerm term="MetaMask smart account">MetaMask Smart Accounts</GlossaryTerm>.

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- If you plan to use any smart contracts (for example, to
  [create a custom caveat enforcer](/tutorials/create-custom-caveat-enforcer)),
  install [Foundry](https://book.getfoundry.sh/getting-started/installation).

## Steps

### 1. Install the Smart Accounts Kit

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit):

```bash npm2yarn
npm install @metamask/smart-accounts-kit
```

### 2. (Optional) Install the contracts

If you plan to extend the <GlossaryTerm term="Delegation Framework" /> smart contracts (for example, to
[create a custom caveat enforcer](/tutorials/create-custom-caveat-enforcer)), install
the contract package using Foundry's command-line tool, Forge:

```bash
forge install metamask/delegation-framework@v1.3.0
```

Add `@metamask/delegation-framework/=lib/metamask/delegation-framework/` in your `remappings.txt` file.

### 3. Get started

You're now ready to start using the Smart Accounts Kit.
See the [MetaMask Smart Accounts quickstart](smart-account-quickstart/index.md) to walk through a simple example.

---

## EIP-7702 quickstart


This quickstart demonstrates how to upgrade your <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> to support <GlossaryTerm term="MetaMask smart account" />
functionality using an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) transaction.
This enables your EOA to leverage the benefits of <GlossaryTerm term="Account abstraction">account abstraction</GlossaryTerm>, such as batch transactions, gas sponsorship, and <GlossaryTerm term="Delegation">delegation</GlossaryTerm>.

:::note
This guide is for embedded wallets. To upgrade a MetaMask account, you can [use MetaMask Connect to upgrade to a smart account](/tutorials/upgrade-eoa-to-smart-account).
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- [Install Viem](https://viem.sh/).

## Steps

### 1. Install the Smart Accounts Kit

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit):

```bash npm2yarn
npm install @metamask/smart-accounts-kit
```

### 2. Set up a Public Client

Set up a Public Client using Viem's [`createPublicClient`](https://viem.sh/docs/clients/public) function.
This client will let the EOA query the account state and interact with the blockchain network.

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

### 3. Set up a Bundler Client

Set up a Bundler Client using Viem's [`createBundlerClient`](https://viem.sh/account-abstraction/clients/bundler) function.
This lets you use the <GlossaryTerm term="Bundler">bundler</GlossaryTerm> service to estimate gas for <GlossaryTerm term="User operation">user operations</GlossaryTerm> and submit transactions to the network.

```typescript

const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://your-bundler-rpc.com'),
})
```

### 4. Set up a Wallet Client

Set up a Wallet Client using Viem's [`createWalletClient`](https://viem.sh/docs/clients/wallet) function.
This lets you sign and submit [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) authorizations.

```typescript

export const account = privateKeyToAccount('0x...')

export const walletClient = createWalletClient({
  account,
  chain,
  transport: http(),
})
```

### 5. Authorize a 7702 delegation

Create an authorization to map the contract code to an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>, and sign it
using Viem's [`signAuthorization`](https://viem.sh/docs/eip7702/signAuthorization) action. The `signAuthorization` action
does not support JSON-RPC accounts.

This example uses [`EIP7702StatelessDeleGator`](https://github.com/MetaMask/delegation-framework/blob/main/src/EIP7702/EIP7702StatelessDeleGator.sol) as the [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegator contract.
It follows a stateless design, as it does not store signer data in the contract's state. This approach
provides a lightweight and secure way to upgrade an EOA to a <GlossaryTerm term="MetaMask smart account" />.

```typescript

  Implementation,
  toMetaMaskSmartAccount,
  getSmartAccountsEnvironment,
} from '@metamask/smart-accounts-kit'

const environment = getSmartAccountsEnvironment(sepolia.id)
const contractAddress = environment.implementations.EIP7702StatelessDeleGatorImpl

const authorization = await walletClient.signAuthorization({
  account,
  contractAddress,
  executor: 'self',
})
```

### 6. Submit the authorization

Once you have signed an authorization, you can send an [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) transaction to set the EOA code.
Since the authorization cannot be sent by itself, you can include it alongside a dummy transaction.

```ts

const hash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  data: '0x',
  to: zeroAddress,
})
```

### 7. Create a MetaMask smart account

Create a <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> instance for the EOA and start
leveraging the benefits of <GlossaryTerm term="Account abstraction">account abstraction</GlossaryTerm>.

```ts

const addresses = await walletClient.getAddresses()
const address = addresses[0]

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Stateless7702,
  address,
  signer: { walletClient },
})
```

### 8. Send a user operation

Send a <GlossaryTerm term="User operation">user operation</GlossaryTerm> through the upgraded EOA, using Viem's [`sendUserOperation`](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation) method.

```ts

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: '0x1234567890123456789012345678901234567890',
      value: parseEther('1'),
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})
```

## Next steps

- To grant specific permissions to other accounts from your smart account, [create a delegation](../../guides/delegation/execute-on-smart-accounts-behalf.md).
- To quickly bootstrap a MetaMask Smart Accounts project, [use the CLI](../use-the-cli.md).

---

## MetaMask Smart Accounts quickstart


You can get started quickly with [MetaMask Smart Accounts](../../concepts/smart-accounts.md) by creating your first <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> and sending a <GlossaryTerm term="User operation">user operation</GlossaryTerm>.

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.

## Steps

### 1. Install the Smart Accounts Kit

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit):

```bash npm2yarn
npm install @metamask/smart-accounts-kit
```

### 2. Set up a Public Client

Set up a Public Client using Viem's [`createPublicClient`](https://viem.sh/docs/clients/public) function.
This client will let the smart account query the signer's account state and interact with the blockchain network.

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

### 3. Set up a Bundler Client

Set up a Bundler Client using Viem's [`createBundlerClient`](https://viem.sh/account-abstraction/clients/bundler) function.
This lets you use the <GlossaryTerm term="Bundler">bundler</GlossaryTerm> service to estimate gas for <GlossaryTerm term="User operation">user operations</GlossaryTerm> and submit transactions to the network.

```typescript

const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://your-bundler-rpc.com'),
})
```

### 4. Create a MetaMask smart account

Create a <GlossaryTerm term="MetaMask smart account" /> to send the first <GlossaryTerm term="User operation">user operation</GlossaryTerm>.

This example configures a Hybrid smart account,
which is a flexible smart account implementation that supports both an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> owner and any number of <GlossaryTerm term="Passkey">passkey</GlossaryTerm> (WebAuthn) signers:

```typescript

const account = privateKeyToAccount('0x...')

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})
```

See [Create a MetaMask smart account](../../guides/smart-accounts/create-smart-account.md) to learn how to configure different smart account types.

### 5. Send a user operation

Send a <GlossaryTerm term="User operation">user operation</GlossaryTerm> using Viem's [`sendUserOperation`](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation) method.

The smart account will remain counterfactual until the first user operation. If the smart account is not
deployed, it will be automatically deployed upon the sending first user operation.

```ts

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: '0x1234567890123456789012345678901234567890',
      value: parseEther('1'),
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})
```

See [Send a user operation](../../guides/smart-accounts/send-user-operation.md) to learn how to estimate fee per gas, and wait for the transaction receipt.

## Next steps

- To grant specific permissions to other accounts from your smart account, [create a delegation](../../guides/delegation/execute-on-smart-accounts-behalf.md).
- This quickstart example uses a Hybrid smart account.
  You can also [configure other smart account types](../../guides/smart-accounts/create-smart-account.md).
- To upgrade an EOA to a smart account, see the [EIP-7702 quickstart](eip7702.md).
- To quickly bootstrap a MetaMask Smart Accounts project, [use the CLI](../use-the-cli.md).

---

## Supported Advanced Permissions

The following table displays the <GlossaryTerm term="Advanced Permissions" /> types supported by
the Smart Accounts Kit, [MetaMask Flask](/snaps/get-started/install-flask), and MetaMask production, and the minimum version required for each.

If you don't see the Advanced Permissions type you're looking for, you can request it by
emailing [`hellogators@consensys.net`](mailto:hellogators@consensys.net).

| Permission type                                                                                                                         | Smart Accounts Kit | MetaMask Flask      | MetaMask    |
| --------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | ------------------- | ----------- |
| [ERC-20 allowance](../guides/advanced-permissions/use-permissions/erc20-token.md#erc-20-allowance-permission)                           | >= v1.4.0          | >= v13.32.1-flask.0 | >= v13.32.1 |
| [ERC-20 periodic](../guides/advanced-permissions/use-permissions/erc20-token.md#erc-20-periodic-permission)                             | >= v0.1.0          | >= v13.5.0          | >= v13.23.0 |
| [ERC-20 stream](../guides/advanced-permissions/use-permissions/erc20-token.md#erc-20-stream-permission)                                 | >= v0.1.0          | >= v13.5.0          | >= v13.23.0 |
| [Native token allowance](../guides/advanced-permissions/use-permissions/native-token.md#native-token-allowance-permission)              | >= v1.4.0          | >= v13.32.1-flask.0 | >= v13.32.1 |
| [Native token periodic](../guides/advanced-permissions/use-permissions/native-token.md#native-token-periodic-permission)                | >= v0.1.0          | >= v13.5.0          | >= v13.23.0 |
| [Native token stream](../guides/advanced-permissions/use-permissions/native-token.md#native-token-stream-permission)                    | >= v0.1.0          | >= v13.5.0          | >= v13.23.0 |
| [Token approval revocation](../guides/advanced-permissions/use-permissions/approval-revocation.md#token-approval-revocation-permission) | >= v1.6.0          | -                   | -           |

---

## Supported networks

The following tables display the networks supported by each version of the Smart Accounts Kit.

If you don't see the network you're looking for, you can request support by emailing [`hellogators@consensys.net`](mailto:hellogators@consensys.net).

## MetaMask Smart Accounts

### Mainnet networks

| Network Name        | v0.3.0 | v1.0.0 | v1.1.0 | v1.2.0 |
| ------------------- | ------ | ------ | ------ | ------ |
| Arbitrum Nova       | ✅     | ✅     | ✅     | ✅     |
| Arbitrum One        | ✅     | ✅     | ✅     | ✅     |
| Base                | ✅     | ✅     | ✅     | ✅     |
| Berachain           | ✅     | ✅     | ✅     | ✅     |
| Binance Smart Chain | ✅     | ✅     | ✅     | ✅     |
| Celo                | ❌     | ✅     | ✅     | ✅     |
| Citrea              | ❌     | ✅     | ✅     | ✅     |
| Ethereum            | ✅     | ✅     | ✅     | ✅     |
| Gnosis Chain        | ✅     | ✅     | ✅     | ✅     |
| Ink                 | ✅     | ✅     | ✅     | ✅     |
| Katana              | ❌     | ❌     | ❌     | ✅     |
| Linea               | ✅     | ✅     | ✅     | ✅     |
| Mantle              | ❌     | ❌     | ✅     | ✅     |
| MegaETH             | ❌     | ✅     | ✅     | ✅     |
| Monad               | ✅     | ✅     | ✅     | ✅     |
| Optimism            | ✅     | ✅     | ✅     | ✅     |
| Polygon             | ✅     | ✅     | ✅     | ✅     |
| Ronin               | ❌     | ✅     | ✅     | ✅     |
| Sei                 | ✅     | ✅     | ✅     | ✅     |
| Sonic               | ✅     | ✅     | ✅     | ✅     |
| Tempo               | ❌     | ✅     | ✅     | ✅     |
| Unichain            | ✅     | ✅     | ✅     | ✅     |

### Testnet networks

| Network Name        | v0.3.0 | v1.0.0 | v1.1.0 | v1.2.0 |
| ------------------- | ------ | ------ | ------ | ------ |
| Arbitrum Sepolia    | ✅     | ✅     | ✅     | ✅     |
| Base Sepolia        | ✅     | ✅     | ✅     | ✅     |
| Berachain Bepolia   | ✅     | ✅     | ✅     | ✅     |
| Binance Smart Chain | ✅     | ✅     | ✅     | ✅     |
| Celo Alfajores      | ❌     | ✅     | ✅     | ✅     |
| Citrea              | ✅     | ✅     | ✅     | ✅     |
| Ethereum Sepolia    | ✅     | ✅     | ✅     | ✅     |
| Gnosis Chiado       | ✅     | ✅     | ✅     | ✅     |
| Hoodi               | ✅     | ✅     | ✅     | ✅     |
| Ink Sepolia         | ✅     | ✅     | ✅     | ✅     |
| Bokuto              | ❌     | ❌     | ❌     | ✅     |
| Linea Sepolia       | ✅     | ✅     | ✅     | ✅     |
| Mantle Sepolia      | ❌     | ❌     | ✅     | ✅     |
| MegaETH             | ✅     | ✅     | ✅     | ✅     |
| Monad               | ✅     | ✅     | ✅     | ✅     |
| Optimism Sepolia    | ✅     | ✅     | ✅     | ✅     |
| Polygon Amoy        | ✅     | ✅     | ✅     | ✅     |
| Ronin Saigon        | ❌     | ✅     | ✅     | ✅     |
| Sei                 | ✅     | ✅     | ✅     | ✅     |
| Sonic               | ✅     | ✅     | ✅     | ✅     |
| Tempo Moderato      | ❌     | ✅     | ✅     | ✅     |
| Unichain Sepolia    | ✅     | ✅     | ✅     | ✅     |

## Advanced Permissions (ERC-7715)

### Mainnet networks

| Network Name        | v0.3.0 | v1.0.0 | v1.1.0 | v1.2.0 |
| ------------------- | ------ | ------ | ------ | ------ |
| Arbitrum Nova       | ✅     | ✅     | ✅     | ✅     |
| Arbitrum One        | ✅     | ✅     | ✅     | ✅     |
| Base                | ✅     | ✅     | ✅     | ✅     |
| Berachain           | ✅     | ✅     | ✅     | ✅     |
| Binance Smart Chain | ✅     | ✅     | ✅     | ✅     |
| Citrea              | ✅     | ✅     | ✅     | ✅     |
| Ethereum            | ✅     | ✅     | ✅     | ✅     |
| Gnosis              | ✅     | ✅     | ✅     | ✅     |
| Linea               | ✅     | ✅     | ✅     | ✅     |
| Monad               | ✅     | ✅     | ✅     | ✅     |
| Optimism            | ✅     | ✅     | ✅     | ✅     |
| Polygon             | ✅     | ✅     | ✅     | ✅     |
| Sei                 | ✅     | ✅     | ✅     | ✅     |
| Sonic               | ✅     | ✅     | ✅     | ✅     |
| Unichain            | ✅     | ✅     | ✅     | ✅     |

### Testnet networks

| Network Name        | v0.3.0 | v1.0.0 | v1.1.0 | v1.2.0 |
| ------------------- | ------ | ------ | ------ | ------ |
| Arbitrum Sepolia    | ✅     | ✅     | ✅     | ✅     |
| Base Sepolia        | ✅     | ✅     | ✅     | ✅     |
| Berachain Bepolia   | ✅     | ✅     | ✅     | ✅     |
| Binance Smart Chain | ✅     | ✅     | ✅     | ✅     |
| Chiado              | ✅     | ✅     | ✅     | ✅     |
| Citrea              | ✅     | ✅     | ✅     | ✅     |
| Hoodi               | ✅     | ✅     | ✅     | ✅     |
| Linea Sepolia       | ✅     | ✅     | ✅     | ✅     |
| MegaETH             | ✅     | ✅     | ✅     | ✅     |
| Optimism Sepolia    | ✅     | ✅     | ✅     | ✅     |
| Polygon Amoy        | ✅     | ✅     | ✅     | ✅     |
| Sei                 | ✅     | ✅     | ✅     | ✅     |
| Sepolia             | ✅     | ✅     | ✅     | ✅     |
| Sonic               | ✅     | ✅     | ✅     | ✅     |
| Unichain Sepolia    | ✅     | ✅     | ✅     | ✅     |

---

## Use Advanced Permissions with Scaffold-ETH 2


Use the [Advanced Permissions (ERC-7715) extension](https://github.com/MetaMask/erc-7715-extension) for [Scaffold-ETH 2](https://docs.scaffoldeth.io/) to bootstrap a project in
under two minutes. This extension helps you quickly generate the boilerplate code to request fine-grained permissions
from a MetaMask user, and execute transactions on their behalf.

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v20.18.3) v20.18.3 or later.
- Install [Yarn](https://yarnpkg.com/) package manager.
- Install [Git](https://git-scm.com/install/).
- [Create a Pimlico API key](https://docs.pimlico.io/guides/create-api-key#create-api-key).

### 1. Install the extension

Run the following command to install the Smart Accounts Kit extension:

```bash
npx create-eth@latest -e metamask/erc-7715-extension your-project-name
```

### 2. Set up environment variables

Navigate into the project's `nextjs` package, and create a `.env.local` file. Once created, update the
`NEXT_PUBLIC_PIMLICO_API_KEY` environment variable with your Pimlico API Key.

```bash
cd your-project-name/packages/nextjs
cp .env.example .env.local
```

### 3. Start the frontend

In the project's root directory start the development server.

```bash
yarn start
```

### 4. Complete the Advanced Permissions lifecycle

Navigate to the **Advanced Permissions (ERC-7715)** page in your Scaffold-ETH
frontend at http://localhost:3000/erc-7715-permissions, and follow the steps to request an <GlossaryTerm term="Advanced Permissions">advanced
permission</GlossaryTerm>, and execute a transaction on the user's behalf.

You can view the completed transaction on Etherscan.

    

## Next steps

Learn more about [Advanced Permissions (ERC-7715)](../../concepts/advanced-permissions.md).

---

## Use MetaMask Smart Accounts with Scaffold-ETH 2


Use the [MetaMask Smart Accounts extension](https://github.com/metamask/gator-extension) for [Scaffold-ETH 2](https://docs.scaffoldeth.io/) to bootstrap a project in
under two minutes. This extension helps you quickly generate the boilerplate code to create an embedded <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm>, and complete
the <GlossaryTerm term="Delegation">delegation</GlossaryTerm> lifecycle (create, sign, and redeem a delegation).

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v20.18.3) v20.18.3 or later.
- Install [Yarn](https://yarnpkg.com/) package manager.
- Install [Git](https://git-scm.com/install/).
- [Create a Pimlico API key](https://docs.pimlico.io/guides/create-api-key#create-api-key).

## Steps

### 1. Install the extension

Run the following command to install the Smart Accounts Kit extension:

```bash
npx create-eth@latest -e metamask/gator-extension your-project-name
```

### 2. Set up environment variables

Navigate into the project's `nextjs` package, and create a `.env.local` file. Once created, update the
`NEXT_PUBLIC_PIMLICO_API_KEY` environment variable with your Pimlico API Key.

```bash
cd your-project-name/packages/nextjs
cp .env.example .env.local
```

### 3. Start the frontend

In the project's root directory start the development server.

```bash
yarn start
```

### 4. Complete the delegation lifecycle

Navigate to the **MetaMask Smart Accounts & Delegation** page in your Scaffold-ETH
frontend at http://localhost:3000/delegations, and follow the steps to deploy a <GlossaryTerm term="Delegator account">delegator
account</GlossaryTerm>, create a <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> wallet,
and create and redeem a delegation.

You can view the completed transaction on Etherscan.

    

## Next steps

Learn more about [MetaMask Smart Accounts](../../concepts/smart-accounts.md) and [delegation](../../concepts/delegation/overview.md).

---

## Use skills


Use skills to give your agent framework context on the MetaMask Smart Accounts Kit.
Skills guide your agent through <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> creation, <GlossaryTerm term="Delegation">delegations</GlossaryTerm>, <GlossaryTerm term="Advanced Permissions" /> (ERC-7715), and [x402](../guides/x402/overview.md)
payments.

Skills are available through the open-source [`MetaMask/skills`](https://github.com/MetaMask/skills)
repository.

## Smart Accounts Kit

This skill gives your agent context on the Smart Accounts Kit and how to integrate its
capabilities into your dapp, including smart account creation, delegations, and Advanced
Permissions.

```bash
npx skills add MetaMask/smart-accounts-kit
```

### Key capabilities

| Capability           | Description                                                                                                                                                                                                          |
| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Smart accounts       | Integrate MetaMask Smart Accounts to support batch transactions, <GlossaryTerm term="Multisig smart account">multi-sig signatures</GlossaryTerm>, and <GlossaryTerm term="Paymaster">gas sponsorship</GlossaryTerm>. |
| Delegation           | Integrate delegations to execute transactions on behalf of a smart account.                                                                                                                                          |
| Advanced Permissions | Integrate Advanced Permissions to execute transactions on behalf of a MetaMask user.                                                                                                                                 |

## x402 Payments

This skill helps your agent implement [x402 HTTP-based payments](../guides/x402/overview.md) using
the Smart Accounts Kit, enabling both buyer and seller flows with delegations and Advanced
Permissions.

```bash
npx skills add MetaMask/skills/domains/web3-tools/skills/x402-payments
```

### Key capabilities

| Capability | Description                                                                 |
| ---------- | --------------------------------------------------------------------------- |
| Seller     | Set up x402 payment endpoints that accept HTTP 402-based payments.          |
| Buyer      | Pay for x402-protected resources using delegations or Advanced Permissions. |

## Next steps

- [Install the Smart Accounts Kit](./install.md)
- [Create your first smart account](./smart-account-quickstart/index.md)
- [Learn about x402 payments](../guides/x402/overview.md)

---

## Use the Smart Accounts Kit CLI


Use the `@metamask/create-gator-app` interactive CLI to bootstrap a project with the Smart Accounts Kit in under two minutes.
The CLI automatically installs the required dependencies and sets up a project structure using a selected template,
allowing you to focus on building your dapp.

## Run the CLI

Run the following command to automatically install the `@metamask/create-gator-app` package:

```bash
npx @metamask/create-gator-app@latest
```

Upon installation, you'll be asked the following prompts:

```bash
? What is your project named? (my-gator-app)
? Pick a framework: (Use arrow keys)
❯ nextjs
  vite-react
  node
? Pick a template: (Use arrow keys)
❯ MetaMask Smart Accounts Starter
  MetaMask Smart Accounts & Delegation Starter
  Farcaster Mini App Delegation Starter
  Advanced Permissions (ERC-7715) Starter
? Pick a package manager: (Use arrow keys)
❯ npm
  yarn
  pnpm
```

Once you've answered the prompts with the required configuration and selected a template, the CLI will create the
project using the specified name and settings.
See the following section to learn more about available CLI configurations.

## Options

The CLI provides the following options to display CLI details, and further customize the template configuration.

| Option              | Description                                                                                                                                                                                                                                                                                                                             |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `-v` or `--version` | Check the current version of the `@metamask/create-gator-app` CLI.                                                                                                                                                                                                                                                                      |
| `-h` or `--help`    | Display the available options.                                                                                                                                                                                                                                                                                                          |
| `--skip-install`    | Skip the installation of dependencies.                                                                                                                                                                                                                                                                                                  |
| `--add-web3auth`    | Add [MetaMask Embedded Wallets (previously Web3Auth)](/embedded-wallets) as a <GlossaryTerm term="Signer">signer</GlossaryTerm> for the <GlossaryTerm term="Delegator account">delegator account</GlossaryTerm>.Supported templates:- MetaMask Smart Accounts Starter- MetaMask Smart Accounts & Delegation Starter |

## Examples

### MetaMask Embedded Wallets configuration

To create a project that uses [MetaMask Embedded Wallets](/embedded-wallets) as the <GlossaryTerm term="Signer">signer</GlossaryTerm> for your
<GlossaryTerm term="Delegator account">delegator account</GlossaryTerm>, use the `--add-web3auth` option with `@metamask/create-gator-app`:

```bash
npx @metamask/create-gator-app --add-web3auth
```

You'll be prompted to provide additional Web3Auth configuration details:

```bash
? Which Web3Auth network do you want to use? (Use arrow keys)
❯ Sapphire Devnet
  Sapphire Mainnet
```

## Supported templates

| Template                                         | Next.js | Vite React | Node.js |
| ------------------------------------------------ | ------- | ---------- | ------- |
| MetaMask Smart Accounts Starter                  | ✅      | ✅         | ❌      |
| MetaMask Smart Accounts &amp; Delegation Starter | ✅      | ✅         | ❌      |
| Farcaster Mini App Delegation Starter            | ✅      | ❌         | ❌      |
| Advanced Permissions (ERC-7715) Starter          | ✅      | ❌         | ❌      |
| x402 Server                                      | ❌      | ❌         | ✅      |

---

## Create a redelegation


Redelegation is a core feature that sets <GlossaryTerm term="Advanced Permissions" /> apart from other permission sharing frameworks.
It allows a session account (<GlossaryTerm term="Delegate account">delegate</GlossaryTerm>) to create a delegation chain, passing on the same or reduced level of authority
from the MetaMask account (<GlossaryTerm term="Delegator account">delegator</GlossaryTerm>).

For example, if a dapp is granted permission to spend 10 USDC on a user's behalf, it can
further delegate that permission to specific agents, such as allowing a Swap agent to spend
up to 5 USDC. This creates a permission sharing chain in which the root permissions are
shared with additional parties.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Learn about Advanced Permissions.](../../concepts/advanced-permissions.md)
- [Learn how to request Advanced Permissions.](execute-on-metamask-users-behalf.md)

## Request Advanced Permissions

Request Advanced Permissions from the user with the Wallet Client's [`requestExecutionPermissions`](../../reference/advanced-permissions/wallet-client.md#requestexecutionpermissions) action.

This example uses the [ERC-20 periodic permission](./use-permissions/erc20-token.md#erc-20-periodic-permission), allowing the
user to grant dapp the ability to spend 10 USDC on their behalf.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, we need to convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress,
        // 10 USDC in wei format. Since USDC has 6 decimals, 10 * 10^6
        periodAmount: parseUnits('10', 6),
        // 1 day in seconds
        periodDuration: 86400,
        justification: 'Permission to transfer 10 USDC every day',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>

<TabItem value="config.ts">

```ts

// USDC address on Ethereum Sepolia.
export const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

export const sessionAccount = createWalletClient({
  account,
  chain,
  transport: http(),
}).extend(erc7710WalletActions())

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## Create a redelegation

Create a [redelegation](../../concepts/delegation/overview.md#redelegation) from dapp to a Swap agent.

To create a redelegation, provide the granted permission context as the `permissionContext` argument when calling [`redelegatePermissionContext`](../../reference/erc7710/wallet-client.md#redelegatepermissioncontext).
In the previous step, `sessionAccount` was extended with `erc7710WalletActions`.

When you create a redelegation, apply the toolkit's [caveats](../../reference/delegation/caveats.md)
to narrow the Swap agent's authority. In this example, we'll use [`erc20TransferAmount`](../../reference/delegation/caveats.md#erc20transferamount)
enforcer, allowing your dapp to delegate the Swap agent only the ability to spend 5 USDC on the user's behalf.

:::note
When creating a redelegation, you can only narrow the scope of the original authority, not expand it.
:::

<Tabs>
<TabItem value="redelegation.ts">

```typescript

  createDelegation,
  ScopeType,
  getSmartAccountsEnvironment,
  Caveats,
  CaveatType,
} from '@metamask/smart-accounts-kit'

const caveats: Caveats = [
  {
    type: CaveatType.Erc20TransferAmount,
    tokenAddress,
    // USDC has 6 decimal places.
    maxAmount: parseUnits('5', 6),
  },
]

const environment = getSmartAccountsEnvironment(chain.id)

const { permissionContext: signedPermissionContext } =
  await sessionAccount.redelegatePermissionContext({
    to: agentAccount.address,
    environment,
    permissionContext: grantedPermissions[0].context,
    caveats,
  })
```

</TabItem>
<TabItem value="config.ts">

```typescript
// Update the existing config to create a smart account for a Swap agent.

const agentPrivateKey = '0x...'
export const agentAccount = privateKeyToAccount(agentPrivateKey)
```

</TabItem>
</Tabs>

---

## Perform executions on a MetaMask user's behalf


[Advanced Permissions (ERC-7715)](../../concepts/advanced-permissions.md) are fine-grained permissions that your dapp can request from a MetaMask user to execute transactions on their
behalf. For example, a user can grant your dapp permission to spend 10 USDC per day to buy ETH over the course
of a month. Once the permission is granted, your dapp can use the allocated 10 USDC each day to
purchase ETH directly from the MetaMask user's account.

In this guide, you'll request an ERC-20 periodic transfer permission from a MetaMask user to transfer 1 USDC every day on their behalf.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Install MetaMask v13.23.0 or later](https://metamask.io/download)

## Steps

### 1. Set up a Wallet Client

Set up a Wallet Client using Viem's [`createWalletClient`](https://viem.sh/docs/clients/wallet) function. This client will
help you interact with MetaMask.

Then, extend the Wallet Client functionality using `erc7715ProviderActions`.
These actions enable you to request <GlossaryTerm term="Advanced Permissions" /> from the user.

```typescript

const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

### 2. Set up a Public Client

Set up a Public Client using Viem's [`createPublicClient`](https://viem.sh/docs/clients/public) function.
This client will help you query the account state and interact with the blockchain network.

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

### 3. Set up a session account

Set up a session account, which can be either a smart account or an
<GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>,
to request <GlossaryTerm term="Advanced Permissions" />. The requested permissions are granted to the session account, which
is responsible for executing transactions on behalf of the user.

<Tabs>
<TabItem value="Smart account">

```typescript

const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

const sessionAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})
```

</TabItem>
<TabItem value="EOA">

```typescript

const sessionAccount = privateKeyToAccount('0x...')
```

</TabItem>
</Tabs>

### 4. Request Advanced Permissions

Request Advanced Permissions from the user with the Wallet Client's `requestExecutionPermissions` action.
In this example, you'll request an
[ERC-20 periodic permission](use-permissions/erc20-token.md#erc-20-periodic-permission).

See the [`requestExecutionPermissions`](../../reference/advanced-permissions/wallet-client.md#requestexecutionpermissions) API reference for more information.

```typescript

// Since current time is in seconds, we need to convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress,
        // 10 USDC in WEI format. Since USDC has 6 decimals, 10 * 10^6
        periodAmount: parseUnits('10', 6),
        // 1 day in seconds
        periodDuration: 86400,
        justification: 'Permission to transfer 10 USDC every day',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

### 5. Set up a Viem client

Set up a Viem client depending on your session account type.

For a smart account, set up a Bundler Client using Viem's [`createBundlerClient`](https://viem.sh/account-abstraction/clients/bundler) function.
This lets you use the <GlossaryTerm term="Bundler">bundler</GlossaryTerm> service
to estimate gas for user operations and submit transactions to the network.

For an EOA, set up a Wallet Client using Viem's [`createWalletClient`](https://viem.sh/docs/clients/wallet) function.
This lets you send transactions directly to the network.

The toolkit provides public actions for both of the clients which can be used to redeem Advanced Permissions, and execute transactions on a user's behalf.

<Tabs>
<TabItem value="Smart account">

```typescript

const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://your-bundler-rpc.com'),
  // Allows you to use the same Bundler Client as paymaster.
  paymaster: true,
}).extend(erc7710BundlerActions())
```

</TabItem>
<TabItem value="EOA">

```typescript

const sessionAccountWalletClient = createWalletClient({
  account: sessionAccount,
  chain,
  transport: http(),
}).extend(erc7710WalletActions())
```

</TabItem>
</Tabs>

### 6. Redeem Advanced Permissions

The session account can now redeem the permissions. The redeem transaction is sent to the `DelegationManager` contract, which validates the delegation and executes actions on the user's behalf.

To redeem the permissions, use the client action based on your session account type.
A smart account uses the Bundler Client's `sendUserOperationWithDelegation` action,
and an EOA uses the Wallet Client's `sendTransactionWithDelegation` action.

See the [`sendUserOperationWithDelegation`](../../reference/erc7710/bundler-client.md#senduseroperationwithdelegation) and [`sendTransactionWithDelegation`](../../reference/erc7710/wallet-client.md#sendtransactionwithdelegation) API reference for more information.

<Tabs>
<TabItem value="Smart account">

```typescript

// These properties must be extracted from the permission response.
const permissionContext = grantedPermissions[0].context
const delegationManager = grantedPermissions[0].delegationManager

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

// Calls without permissionContext and delegationManager will be executed
// as a normal user operation.
const userOperationHash = await bundlerClient.sendUserOperationWithDelegation({
  publicClient,
  account: sessionAccount,
  calls: [
    {
      to: tokenAddress,
      data: calldata,
      permissionContext,
      delegationManager,
    },
  ],
  // Appropriate values must be used for fee-per-gas.
  maxFeePerGas: 1n,
  maxPriorityFeePerGas: 1n,
})
```

</TabItem>
<TabItem value="EOA">

```typescript

// These properties must be extracted from the permission response.
const permissionContext = grantedPermissions[0].context
const delegationManager = grantedPermissions[0].delegationManager

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const transactionHash = await sessionAccountWalletClient.sendTransactionWithDelegation({
  to: tokenAddress,
  data: calldata,
  permissionContext,
  delegationManager,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

export const calldata = encodeFunctionData({
  abi: erc20Abi,
  args: [sessionAccount.address, parseUnits('1', 6)],
  functionName: 'transfer',
})
```

</TabItem>
</Tabs>

## Next steps

- See how to [get the supported execution permissions](get-supported-permissions.md).
- See how to configure different [ERC-20 token permissions](use-permissions/erc20-token.md) and
  [native token permissions](use-permissions/native-token.md).

---

## Get granted permissions


[ERC-7715](https://eip.tools/eip/7715) defines an RPC method that returns the granted execution permissions
for a wallet. Use the method to get the granted <GlossaryTerm term="Advanced Permissions" /> for a wallet.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Learn about Advanced Permissions.](../../concepts/advanced-permissions.md)

## Request granted permissions

Request the granted Advanced Permissions for a wallet with the
Wallet Client's [`getGrantedExecutionPermissions`](../../reference/advanced-permissions/wallet-client.md#getgrantedexecutionpermissions) action.

<Tabs>
<TabItem value="response.ts">

```ts
[
  {
    chainId: 84532,
    context: "0x0000...0000",
    delegationManager: "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
    dependencies: [],
    from: "0x993fC0d346A8AfA40Da014bA8834A56cE8B17f31",
    permission: {
      type: "erc20-token-periodic",
      isAdjustmentAllowed: false,
      data: { ... },
    },
    rules: [
      { type: "expiry", data: { ... } },
    ],
    to: "0xAB57cfCDaF510594eA68D47ffBEF04Ebf73e7F1f",
  },
  // ...
]
```

</TabItem>
<TabItem value="example.ts" default>

```typescript

const grantedExecutionPermissions = await walletClient.getGrantedExecutionPermissions()
```

</TabItem>
<TabItem value="config.ts">

```ts

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

---

## Get supported permissions


[ERC-7715](https://eip.tools/eip/7715) defines an RPC method that returns the execution permissions
a wallet supports. Use the method to verify the available <GlossaryTerm term="Advanced Permissions" /> types and
rules before sending requests.

## Prerequisites

- [Install and set up the Smart Accounts Kit](../../get-started/install.md)
- [Learn about Advanced Permissions](../../concepts/advanced-permissions.md)

## Request supported permissions

Request the supported Advanced Permissions types for a wallet with the
Wallet Client's [`getSupportedExecutionPermissions`](../../reference/advanced-permissions/wallet-client.md#getsupportedexecutionpermissions) action.

<Tabs>
<TabItem value="response.ts">

```ts
{
  "native-token-stream": {
    "chainIds": [
      1,
      10,
    ],
    "ruleTypes": [
      "expiry"
    ]
  },
  // ...
}
```

</TabItem>
<TabItem value="example.ts" default>

```typescript

const supportedPermissions = await walletClient.getSupportedExecutionPermissions()
```

</TabItem>
<TabItem value="config.ts">

```ts

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

See the full list of [supported Advanced Permissions](../../get-started/supported-advanced-permissions.md).

---

## Use approval revocation permission


[Advanced Permissions (ERC-7715)](../../../concepts/advanced-permissions.md) supports the token approval
revocation permission type that allows you to request permission to revoke existing token approvals
on behalf of the user.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a session account.](../execute-on-metamask-users-behalf.md#3-set-up-a-session-account)

## Token approval revocation permission

This permission type enables revoking existing token approvals on behalf of the user.

For example, a user signs an ERC-7715 permission that lets a dapp revoke any ERC-20 token
allowances periodically, or during an ongoing exploit.

See the [token approval revocation permission API reference](../../../reference/advanced-permissions/permissions.md#token-approval-revocation-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)

// 30 days from now.
const expiry = currentTime + 60 * 60 * 24 * 30

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'token-approval-revocation',
      data: {
        erc20Approve: true,
        erc721Approve: false,
        erc721SetApprovalForAll: false,
        permit2Approve: true,
        permit2Lockdown: false,
        permit2InvalidateNonces: false,
        justification: 'Permission to revoke ERC-20 token approvals',
      },
      isAdjustmentAllowed: false,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

---

## Use ERC-20 token permissions


[Advanced Permissions (ERC-7715)](../../../concepts/advanced-permissions.md) supports ERC-20 token permission types that allow you to request fine-grained
permissions for ERC-20 token transfers with periodic, fixed allowance, or streaming conditions, depending on your use case.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a session account.](../execute-on-metamask-users-behalf.md#3-set-up-a-session-account)

## ERC-20 allowance permission

This permission type ensures a fixed ERC-20 token allowance.
It allows transfers up to a maximum total amount and doesn't reset by period.

For example, a user signs an ERC-7715 permission that lets your dapp spend up to 50 USDC in total.
After the dapp transfers 50 USDC, no additional transfers are allowed under this permission.

See the [ERC-20 allowance permission API reference](../../../reference/advanced-permissions/permissions.md#erc-20-allowance-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-allowance',
      data: {
        tokenAddress,
        // 50 USDC in WEI format. Since USDC has 6 decimals, 50 * 10^6.
        allowanceAmount: parseUnits('50', 6),
        startTime: currentTime,
        justification: 'Permission to transfer up to 50 USDC in total',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## ERC-20 periodic permission

This permission type ensures a per-period limit for ERC-20 token transfers. At the start of each new period, the allowance resets.

For example, a user signs an ERC-7715 permission that lets a dapp spend up to 10 USDC on their behalf each day. The dapp can transfer a total of
10 USDC per day; the limit resets at the beginning of the next day.

See the [ERC-20 periodic permission API reference](../../../reference/advanced-permissions/permissions.md#erc-20-periodic-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress,
        // 10 USDC in WEI format. Since USDC has 6 decimals, 10 * 10^6.
        periodAmount: parseUnits('10', 6),
        // 1 day in seconds.
        periodDuration: 86400,
        justification: 'Permission to transfer 10 USDC every day',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## ERC-20 stream permission

This permission type ensures a linear streaming transfer limit for ERC-20 tokens. Token transfers are blocked until the
defined start timestamp. At the start, a specified initial amount is released, after which tokens accrue linearly at the
configured rate, up to the maximum allowed amount.

For example, a user signs an ERC-7715 permission that allows a dapp to spend 0.1 USDC per second, starting with an initial amount
of 1 USDC, up to a maximum of 2 USDC.

See the [ERC-20 stream permission API reference](../../../reference/advanced-permissions/permissions.md#erc-20-stream-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-stream',
      data: {
        tokenAddress,
        // 0.1 USDC in WEI format. Since USDC has 6 decimals, 0.1 * 10^6.
        amountPerSecond: parseUnits('0.1', 6),
        // 1 USDC in WEI format. Since USDC has 6 decimals, 1 * 10^6.
        initialAmount: parseUnits('1', 6),
        // 2 USDC in WEI format. Since USDC has 6 decimals, 2 * 10^6.
        maxAmount: parseUnits('2', 6),
        startTime: currentTime,
        justification: 'Permission to use 0.1 USDC per second',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

---

## Use native token permissions


[Advanced Permissions (ERC-7715)](../../../concepts/advanced-permissions.md) supports native token permission types that allow you to request fine-grained
permissions for native token transfers with periodic, fixed-allowance, or streaming conditions, depending on your use case.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a session account.](../execute-on-metamask-users-behalf.md#3-set-up-a-session-account)

## Native token allowance permission

This permission type ensures a fixed native token allowance.
It allows transfers up to a maximum total amount and doesn't reset by period.

For example, a user signs an ERC-7715 permission that lets your dapp spend up to 0.05 ETH in total.
After the dapp transfers 0.05 ETH, no additional transfers are allowed under this permission.

See the [native token allowance permission API reference](../../../reference/advanced-permissions/permissions.md#native-token-allowance-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'native-token-allowance',
      data: {
        // 0.05 ETH in wei format.
        allowanceAmount: parseEther('0.05'),
        startTime: currentTime,
        justification: 'Permission to transfer up to 0.05 ETH in total',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## Native token periodic permission

This permission type ensures a per-period limit for native token transfers. At the start of each new period, the allowance resets.

For example, a user signs an ERC-7715 permission that lets a dapp spend up to 0.001 ETH on their behalf each day. The dapp can transfer a total of
0.001 ETH per day; the limit resets at the beginning of the next day.

See the [native token periodic permission API reference](../../../reference/advanced-permissions/permissions.md#native-token-periodic-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'native-token-periodic',
      data: {
        // 0.001 ETH in wei format.
        periodAmount: parseEther('0.001'),
        // 1 hour in seconds.
        periodDuration: 86400,
        startTime: currentTime,
        justification: 'Permission to use 0.001 ETH every day',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## Native token stream permission

This permission type ensures a linear streaming transfer limit for native tokens. Token transfers are blocked until the
defined start timestamp. At the start, a specified initial amount is released, after which tokens accrue linearly at the
configured rate, up to the maximum allowed amount.

For example, a user signs an ERC-7715 permission that allows a dapp to spend 0.0001 ETH per second, starting with an initial amount
of 0.1 ETH, up to a maximum of 1 ETH.

See the [native token stream permission API reference](../../../reference/advanced-permissions/permissions.md#native-token-stream-permission) for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 week from now.
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'native-token-stream',
      data: {
        // 0.0001 ETH in wei format.
        amountPerSecond: parseEther('0.0001'),
        // 0.1 ETH in wei format.
        initialAmount: parseEther('0.1'),
        // 1 ETH in wei format.
        maxAmount: parseEther('1'),
        startTime: currentTime,
        justification: 'Permission to use 0.0001 ETH per second',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value="client.ts">

```typescript

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

---

## Configure the Smart Accounts Kit


The Smart Accounts Kit is highly configurable, providing support for custom <GlossaryTerm term="Bundler">bundlers</GlossaryTerm> and <GlossaryTerm term="Paymaster">paymasters</GlossaryTerm>.
You can also configure the toolkit environment to interact with the
<GlossaryTerm term="Delegation Framework" />.

## Prerequisites

[Install and set up the Smart Accounts Kit.](../get-started/install.md)

## Configure the bundler

The toolkit uses Viem's Account Abstraction API to configure custom <GlossaryTerm term="Bundler">bundlers</GlossaryTerm> and <GlossaryTerm term="Paymaster">paymasters</GlossaryTerm>.
This provides a robust and flexible foundation for creating and managing [MetaMask Smart Accounts](../concepts/smart-accounts.md).
See Viem's [account abstraction documentation](https://viem.sh/account-abstraction) for more information on the API's features, methods, and best practices.

To use the bundler and paymaster clients with the toolkit, create instances of these clients and configure them as follows:

```typescript

// Replace these URLs with your actual bundler and paymaster endpoints.
const bundlerUrl = 'https://your-bundler-url.com'
const paymasterUrl = 'https://your-paymaster-url.com'

// The paymaster is optional.
const paymasterClient = createPaymasterClient({
  transport: http(paymasterUrl),
})

const bundlerClient = createBundlerClient({
  transport: http(bundlerUrl),
  paymaster: paymasterClient,
  chain,
})
```

Replace the bundler and paymaster URLs with your bundler and paymaster endpoints.
For example, you can use endpoints from [Pimlico](https://docs.pimlico.io/references/bundler), [Infura](https://docs.infura.io/), or [ZeroDev](https://docs.zerodev.app/meta-infra/intro).

:::note
Providing a paymaster is optional when configuring your bundler client. However, if you choose not to use a paymaster, the smart account must have enough funds to pay gas fees.
:::

## (Optional) Configure the toolkit environment

The toolkit environment (`SmartAccountsEnvironment`) defines the contract addresses necessary for interacting with the [Delegation Framework](../concepts/delegation/overview.md#delegation-framework) on a specific network.
It serves several key purposes:

- It provides a centralized configuration for all the contract addresses required by the Delegation Framework.
- It enables easy switching between different networks (for example, Mainnet and testnet) or custom deployments.
- It ensures consistency across different parts of the application that interact with the Delegation Framework.

### Resolve the environment

When you create a <GlossaryTerm term="MetaMask smart account" />, the toolkit automatically
resolves the environment based on the version it requires and the chain configured.
If no environment is found for the specified chain, it throws an error.

<Tabs>
<TabItem value="example.ts">

```typescript

const environment: SmartAccountsEnvironment = delegatorSmartAccount.environment
```

</TabItem>
<TabItem value="config.ts">

```typescript

  Implementation,
  toMetaMaskSmartAccount,
} from "@metamask/smart-accounts-kit";

const publicClient = createPublicClient({
  chain,
  transport: http(),
});

const delegatorAccount = privateKeyToAccount("0x...");

const delegatorSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: "0x",
  signer: { account: delegatorAccount },
});

export delegatorSmartAccount;
```

</TabItem>
</Tabs>

:::note
See the changelog of the toolkit version you are using (in the left sidebar) for supported chains.
:::

Alternatively, you can use the [`getSmartAccountsEnvironment`](../reference/delegation/index.md#getsmartaccountsenvironment) function to resolve the environment.
This function is especially useful if your <GlossaryTerm term="Delegator account">delegator</GlossaryTerm> is not a smart account when
creating a <GlossaryTerm term="Redelegation">redelegation</GlossaryTerm>.

```typescript

// Resolves the SmartAccountsEnvironment for Sepolia
const environment: SmartAccountsEnvironment = getSmartAccountsEnvironment(sepolia.id)
```

### Deploy a custom environment

You can deploy the contracts using any method, but the toolkit provides a convenient [`deploySmartAccountsEnvironment`](../reference/delegation/index.md#deploysmartaccountsenvironment) function. This function simplifies deploying the <GlossaryTerm term="Delegation Framework" /> contracts to your desired EVM chain.

This function requires a Viem [Public Client](https://viem.sh/docs/clients/public), [Wallet Client](https://viem.sh/docs/clients/wallet), and [Chain](https://viem.sh/docs/glossary/types#chain)
to deploy the contracts and resolve the `SmartAccountsEnvironment`.

Your wallet must have a sufficient native token balance to deploy the contracts.

<Tabs>
<TabItem value="example.ts">

```typescript

const environment = await deploySmartAccountsEnvironment(walletClient, publicClient, chain)
```

</TabItem>
<TabItem value="config.ts">

```typescript

// Your deployer wallet private key.
const privateKey = '0x123..'
const account = privateKeyToAccount(privateKey)

export const walletClient = createWalletClient({
  account,
  chain,
  transport: http(),
})

export const publicClient = createPublicClient({
  transport: http(),
  chain,
})
```

</TabItem>
</Tabs>

You can also override specific contracts when calling `deploySmartAccountsEnvironment`.
For example, if you've already deployed the `EntryPoint` contract on the target chain, you can pass the contract address to the function.

```typescript
// The config.ts is the same as in the previous example.

const environment = await deploySmartAccountsEnvironment(
  walletClient,
  publicClient,
  chain,
  // add-start
+ {
+   EntryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032"
+ }
  // add-end
);
```

Once the contracts are deployed, you can use them to override the environment.

### Override the environment

To override the environment, the toolkit provides an [`overrideDeployedEnvironment`](../reference/delegation/index.md#overridedeployedenvironment) function to resolve
`SmartAccountsEnvironment` with specified contracts for the given chain and contract version.

```typescript
// The config.ts is the same as in the previous example.

  overrideDeployedEnvironment,
  deploySmartAccountsEnvironment,
} from '@metamask/smart-accounts-kit'

const environment: SmartAccountsEnvironment = await deploySmartAccountsEnvironment(
  walletClient,
  publicClient,
  chain
)

overrideDeployedEnvironment(chain.id, '1.3.0', environment)
```

If you've already deployed the contracts using a different method, you can create a `SmartAccountsEnvironment` instance with the required contract addresses, and pass it to the function.

```typescript
// remove-start
- import { walletClient, publicClient } from "./config.ts";
- import { sepolia as chain } from "viem/chains";
// remove-end

  overrideDeployedEnvironment,
  // remove-next-line
- deploySmartAccountsEnvironment
} from "@metamask/smart-accounts-kit";

// remove-start
- const environment: SmartAccountsEnvironment = await deploySmartAccountsEnvironment(
-  walletClient,
-  publicClient,
-  chain
- );
// remove-end

// add-start
+ const environment: SmartAccountsEnvironment = {
+  SimpleFactory: "0x124..",
+  // ...
+  implementations: {
+    // ...
+  },
+ };
// add-end

overrideDeployedEnvironment(
  chain.id,
  "1.3.0",
  environment
);
```

:::note
Make sure to specify the <GlossaryTerm term="Delegation Framework" /> version required by the toolkit.
See the changelog of the toolkit version you are using (in the left sidebar) for its required Framework version.
:::

---

## Check the delegation state


When using [spending limit delegation scopes](use-delegation-scopes/spending-limit.md) or relevant [caveat enforcers](../../reference/delegation/caveats.md),
you might need to check the remaining transferrable amount in a delegation.
For example, if a delegation allows a user to spend 10 USDC per week and they have already spent 10 - n USDC in the current period,
you can determine how much of the allowance is still available for transfer.

Use the `CaveatEnforcerClient` to check the available balances for specific scopes or caveats.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a delegator account.](execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)
- [Create a delegation with an ERC-20 periodic scope.](use-delegation-scopes/spending-limit.md#erc-20-periodic-scope)

## Create a `CaveatEnforcerClient`

To check the delegation state, create a [`CaveatEnforcerClient`](../../reference/delegation/caveat-enforcer-client.md).
This client allows you to interact with the <GlossaryTerm term="Caveat enforcer">caveat enforcers</GlossaryTerm> of the delegation, and read the required state.

<Tabs>
<TabItem value="example.ts">

```typescript

const caveatEnforcerClient = createCaveatEnforcerClient({
  environment,
  client,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

export const environment = getSmartAccountsEnvironment(chain.id)

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

## Read the caveat enforcer state

This example uses the [`getErc20PeriodTransferEnforcerAvailableAmount`](../../reference/delegation/caveat-enforcer-client.md#geterc20periodtransferenforceravailableamount) method to read the state and retrieve the remaining amount for the current transfer period.

<Tabs>
<TabItem value="example.ts">

```typescript

// Returns the available amount for current period.
const { availableAmount } =
  await caveatEnforcerClient.getErc20PeriodTransferEnforcerAvailableAmount({
    delegation,
  })
```

</TabItem>
<TabItem value="config.ts">

```typescript

// startDate should be in seconds.
const startDate = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20PeriodTransfer,
    tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    periodAmount: parseUnits('10', 6),
    periodDuration: 86400,
    startDate,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

</TabItem>
</Tabs>

## Next steps

See the [Caveat Enforcer Client reference](../../reference/delegation/caveat-enforcer-client.md) for the full list of available methods.

---

## Create a redelegation(Delegation)


Redelegation is a core feature that sets delegations apart from other permission sharing frameworks.
It allows a <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> to create a delegation chain, passing on the same or reduced level of authority
from the root <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>.

For example, if Alice grants Bob permission to spend 10 USDC on her behalf, Bob can further grant Carol
permission to spend up to 5 USDC on Alice's behalf-that is, Bob can redelegate. This creates a delegation
chain where the root permissions are re-shared with additional parties.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Learn how to create a delegation.](execute-on-smart-accounts-behalf.md)

## Create a delegation

Create a [root delegation](../../concepts/delegation/overview.md#root-delegation) from Alice to Bob.

This example uses the [`erc20TransferAmount`](use-delegation-scopes/spending-limit.md#erc-20-transfer-scope) <GlossaryTerm term="Delegation scope">scope</GlossaryTerm>, allowing
Alice to delegate to Bob the ability to spend 10 USDC on her behalf.

<Tabs>
<TabItem value="delegation.ts">

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // USDC has 6 decimal places.
    maxAmount: parseUnits('10', 6),
  },
  to: bobSmartAccount.address,
  from: aliceSmartAccount.address,
  environment: aliceSmartAccount.environment,
})

const signedDelegation = aliceSmartAccount.signDelegation({ delegation })
```

</TabItem>
<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const aliceAccount = privateKeyToAccount('0x...')
const bobAccount = privateKeyToAccount('0x...')

export const aliceSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [aliceAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: aliceAccount },
})

export const bobSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [bobAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: bobAccount },
})
```

</TabItem>
</Tabs>

## Create a redelegation

Create a [redelegation](../../concepts/delegation/overview.md#redelegation) from Bob to Carol. When creating a redelegation, you can only narrow the scope of the original authority, not expand it.

To create a redelegation, provide the signed delegation as the `parentDelegation` argument when calling [`createDelegation`](../../reference/delegation/index.md#createdelegation).
This example uses the [`erc20TransferAmount`](use-delegation-scopes/spending-limit.md#erc-20-transfer-scope) <GlossaryTerm term="Delegation scope">scope</GlossaryTerm>, allowing
Bob to delegate to Carol the ability to spend 5 USDC on Alice's behalf.

<Tabs>
<TabItem value="redelegation.ts">

```typescript

const redelegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // USDC has 6 decimal places.
    maxAmount: parseUnits('5', 6),
  },
  to: carolSmartAccount.address,
  from: bobSmartAccount.address,
  // Signed root delegation from previous step.
  parentDelegation: signedDelegation,
  environment: bobSmartAccount.environment,
})

const signedRedelegation = bobSmartAccount.signDelegation({ delegation: redelegation })
```

</TabItem>
<TabItem value="config.ts">

```typescript
// Update the existing config to create a smart account for Carol.

const carolAccount = privateKeyToAccount('0x...')

export const carolSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [carolAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: carolAccount },
})
```

</TabItem>
</Tabs>

### Limit redelegation using caveats

When you create a redelegation, apply the toolkit's [caveats](../../reference/delegation/caveats.md) to narrow the Carol's authority. For example, you can limit the authority so Carol can use the delegation only once.

To apply caveats, create the `Delegation` object and use [`createCaveatBuilder`](../../reference/delegation/index.md#createcaveatbuilder). Use [`hashDelegation`](../../reference/delegation/index.md#hashdelegation) to get the delegation hash, then provide it as the `authority` field.

This example uses the [`limitedCalls`](../../reference/delegation/caveats.md#limitedcalls) caveat with a limit of `1`.

```ts
// Use the config from previous step.

const caveatBuilder = createCaveatBuilder(bobSmartAccount.environment)

const caveats = caveatBuilder.addCaveat(CaveatType.LimitedCalls, { limit: 1 })

const redelegation: Delegation = {
  delegate: carolSmartAccount.address,
  delegator: bobSmartAccount.address,
  authority: hashDelegation(rootDelegation),
  caveats: caveats.build(),
  salt: '0x',
}

const signedRedelegation = await bobSmartAccount.signDelegation({ delegation: redelegation })
```

## Next steps

See [how to disable a delegation](disable-delegation.md) to revoke permissions.

---

## Disable a delegation


Delegations are created offchain and can be stored anywhere, but you can disable a delegation onchain using the
toolkit. When a delegation is disabled, any attempt to redeem it will revert, effectively revoking the permissions
that were previously granted.

For example, if Alice has given permission to Bob to spend 10 USDC on her behalf, and after a week she wants to
revoke that permission, Alice can disable the delegation she created for Bob. If Bob tries to redeem the disabled
delegation, the transaction will revert, preventing him from spending Alice's USDC.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a delegator account.](execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)

## Disable a delegation

To disable a delegation, you can use the [`disableDelegation`](../../reference/delegation/index.md#disabledelegation) utility function from the
toolkit to generate calldata. Once the calldata is prepared, you can send it to the
<GlossaryTerm term="Delegation Manager" /> to disable the delegation.

<Tabs>
<TabItem value="example.ts">

```typescript

const disableDelegationData = DelegationManager.encode.disableDelegation({
  delegation,
})

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: delegatorAccount,
  calls: [
    {
      to: environment.DelegationManager,
      data: disableDelegationData,
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

  getSmartAccountsEnvironment,
  createDelegation,
  ScopeType,
} from '@metamask/smart-accounts-kit'

export const environment = getSmartAccountsEnvironment(chain.id)

const currentTime = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenPeriodTransfer,
    periodAmount: parseEther('0.01'),
    periodDuration: 86400,
    startDate: currentTime,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>'),
})
```

</TabItem>
</Tabs>

---

## Perform executions on a smart account's behalf


[Delegation](../../concepts/delegation/overview.md) is the ability for a [MetaMask smart account](../../concepts/smart-accounts.md) to grant permission to another account to perform executions on its behalf.

In this guide, you'll create a delegator account (Alice) and a delegate account (Bob), and grant Bob permission to perform executions on Alice's behalf.
You'll complete the delegation lifecycle (create, sign, and redeem a delegation).

## Prerequisites

[Install and set up the Smart Accounts Kit.](../../get-started/install.md)

## Steps

### 1. Set up a Public Client

Set up a Public Client using Viem's [`createPublicClient`](https://viem.sh/docs/clients/public) function.
You will configure Alice's account (the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>) and the Bundler Client with the Public Client, which you can use to query the signer's account state and interact with smart contracts.

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

### 2. Set up a Bundler Client

Set up a Bundler Client using Viem's [`createBundlerClient`](https://viem.sh/account-abstraction/clients/bundler) function.
You can use the <GlossaryTerm term="Bundler">bundler</GlossaryTerm> service to estimate gas for <GlossaryTerm term="User operation">user operations</GlossaryTerm> and submit transactions to the network.

```typescript

const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://your-bundler-rpc.com'),
})
```

### 3. Create a delegator account

Create an account to represent Alice, the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm> who will create a delegation.
The delegator must be a <GlossaryTerm term="MetaMask smart account" />; use the toolkit's [`toMetaMaskSmartAccount`](../../reference/smart-account.md#tometamasksmartaccount) method to create the delegator account.

This example configures a Hybrid smart account,
which is a flexible smart account implementation that supports both an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> owner and any number of <GlossaryTerm term="Passkey">passkey</GlossaryTerm> (WebAuthn) signers:

```typescript

const delegatorAccount = privateKeyToAccount('0x...')

const delegatorSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegatorAccount },
})
```

:::note
See [how to configure other smart account types](../smart-accounts/create-smart-account.md).
:::

### 4. Create a delegate account

Create an account to represent Bob, the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> who will receive the delegation. The delegate can be a <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> or an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>:

<Tabs>
<TabItem value="Smart account">

```typescript

const delegateAccount = privateKeyToAccount('0x...')

const delegateSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid, // Hybrid smart account
  deployParams: [delegateAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegateAccount },
})
```

</TabItem>
<TabItem value="EOA">

```typescript

const delegateAccount = privateKeyToAccount('0x...')

export const delegateWalletClient = createWalletClient({
  account: delegateAccount,
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

### 5. Create a delegation

Create a [root delegation](../../concepts/delegation/overview.md#root-delegation) from Alice to Bob.
With a root delegation, Alice is delegating her own authority away, as opposed to _redelegating_ permissions she received from a previous delegation.

Use the toolkit's [`createDelegation`](../../reference/delegation/index.md#createdelegation) method to create a root delegation. When creating
delegation, you need to configure the scope of the delegation to define the initial authority.

This example uses the [`erc20TransferAmount`](use-delegation-scopes/spending-limit.md#erc-20-transfer-scope) scope, allowing Alice to delegate to Bob the ability to spend her USDC, with a
specified limit on the total amount.

:::warning Important

Before creating a delegation, ensure that the delegator account (in this example, Alice's account) has been deployed. If the account is not deployed, redeeming the delegation will fail.

:::

```typescript

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  to: delegateSmartAccount.address, // This example uses a delegate smart account
  from: delegatorSmartAccount.address,
  environment: delegatorSmartAccount.environment,
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress,
    // 10 USDC
    maxAmount: parseUnits('10', 6),
  },
})
```

### 6. Sign the delegation

Sign the delegation with Alice's account, using the [`signDelegation`](../../reference/smart-account.md#signdelegation) method from `MetaMaskSmartAccount`. Alternatively, you can use the toolkit's [`signDelegation`](../../reference/delegation/index.md#signdelegation) utility method. Bob will later use the signed delegation to perform actions on Alice's behalf.

```typescript
const signature = await delegatorSmartAccount.signDelegation({
  delegation,
})

const signedDelegation = {
  ...delegation,
  signature,
}
```

### 7. Redeem the delegation

Bob can now redeem the delegation. The redeem transaction is sent to the `DelegationManager` contract, which validates the delegation and executes actions on Alice's behalf.

To prepare the calldata for the redeem transaction, use the [`redeemDelegations`](../../reference/delegation/index.md#redeemdelegations) method from `DelegationManager`.
Since Bob is redeeming a single delegation chain, use the [`SingleDefault`](../../concepts/delegation/delegation-manager.md#execution-modes) execution mode.

Bob can redeem the delegation by submitting a <GlossaryTerm term="User operation">user operation</GlossaryTerm> if his account is a smart account, or a regular transaction if his account is an EOA. In this example, Bob transfers 1 USDC from Alice's account to his own.

<Tabs>
<TabItem value="Redeem with a smart account">

```typescript

const delegations = [signedDelegation]

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const executions = [createExecution({ target: tokenAddress, callData })]

const redeemDelegationCalldata = DelegationManager.encode.redeemDelegations({
  delegations: [delegations],
  modes: [ExecutionMode.SingleDefault],
  executions: [executions],
})

const userOperationHash = await bundlerClient.sendUserOperation({
  account: delegateSmartAccount,
  calls: [
    {
      to: delegateSmartAccount.address,
      data: redeemDelegationCalldata,
    },
  ],
  maxFeePerGas: 1n,
  maxPriorityFeePerGas: 1n,
})
```

</TabItem>
<TabItem value="Redeem with an EOA">

```typescript

  createExecution,
  getSmartAccountsEnvironment,
  ExecutionMode,
} from '@metamask/smart-accounts-kit'

const delegations = [signedDelegation]

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const executions = [createExecution({ target: tokenAddress, callData })]

const redeemDelegationCalldata = DelegationManager.encode.redeemDelegations({
  delegations: [delegations],
  modes: [ExecutionMode.SingleDefault],
  executions: [executions],
})

const transactionHash = await delegateWalletClient.sendTransaction({
  to: getSmartAccountsEnvironment(chain.id).DelegationManager,
  data: redeemDelegationCalldata,
  chain,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

// calldata to transfer 1 USDC to delegate address.
export const callData = encodeFunctionData({
  abi: erc20Abi,
  args: [delegateSmartAccount.address, parseUnits('1', 6)],
  functionName: 'transfer',
})
```

</TabItem>
</Tabs>

## Next steps

- See [how to configure different scopes](use-delegation-scopes/index.md) to define the initial authority of a delegation.
- See [how to further refine the authority of a delegation](use-delegation-scopes/constrain-scope.md) using caveat enforcers.
- See [how to disable a delegation](disable-delegation.md) to revoke permissions.

---

## Constrain a delegation scope


[Delegation scopes](index.md) define the delegation's initial authority and help prevent delegation misuse.
You can further constrain these scopes and limit the delegation's authority by applying [caveat enforcers](../../../concepts/delegation/caveat-enforcers.md).

## Prerequisites

[Configure a delegation scope.](index.md)

## Apply a caveat enforcer

For example, Alice creates a delegation with an [ERC-20 transfer scope](spending-limit.md#erc-20-transfer-scope) that allows Bob to spend up to 10 USDC.
If Alice wants to further restrict the scope to limit Bob's delegation to be valid for only seven days,
she can apply the [`timestamp`](../../../reference/delegation/caveats.md#timestamp) caveat enforcer.

The following example creates a delegation using [`createDelegation`](../../../reference/delegation/index.md#createdelegation), applies the ERC-20 transfer scope with a spending limit of 10 USDC, and applies the `timestamp` caveat enforcer to restrict the delegation's validity to a seven-day period:

```typescript

// Convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)

// Seven days after current time.
const beforeThreshold = currentTime + 604800

const caveats = [
  {
    type: CaveatType.Timestamp,
    afterThreshold: currentTime,
    beforeThreshold,
  },
]

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    maxAmount: 10000n,
  },
  // Apply caveats to the delegation.
  caveats,
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Next steps

- See the [caveats reference](../../../reference/delegation/caveats.md) for the full list of caveat types and their parameters.
- For more specific or custom control, you can also [create custom caveat enforcers](/tutorials/create-custom-caveat-enforcer)
  and apply them to delegations.

---

## Use the function call scope


The function call scope defines the specific methods, contract addresses, and calldata that are allowed for the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>.
For example, Alice delegates to Bob the ability to call the `approve` function on the USDC contract, with the approval amount set to `0`.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a delegator account.](../execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](../execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)

## Function call scope

This scope requires `targets`, which specifies the permitted contract addresses, and `selectors`, which specifies the allowed methods.

Internally, this scope uses the [`allowedTargets`](../../../reference/delegation/caveats.md#allowedtargets), [`allowedMethods`](../../../reference/delegation/caveats.md#allowedmethods), and [`valueLte`](../../../reference/delegation/caveats.md#valuelte) <GlossaryTerm term="Caveat enforcer">caveat enforcers</GlossaryTerm>, and
optionally uses the [`allowedCalldata`](../../../reference/delegation/caveats.md#allowedcalldata) or [`exactCalldata`](../../../reference/delegation/caveats.md#exactcalldata) caveat enforcers when those parameters are specified.
See the [function call scope reference](../../../reference/delegation/delegation-scopes.md#function-call-scope) for more details.

The following example sets the delegation scope to allow the delegate to call the `approve` function on the USDC token contract:

```typescript

// USDC address on Sepolia.
const USDC_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  scope: {
    type: ScopeType.FunctionCall,
    targets: [USDC_ADDRESS],
    selectors: ['approve(address, uint256)'],
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

### Define allowed calldata

You can further restrict the scope by defining the `allowedCalldata`. For example, you can set
`allowedCalldata` so the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is only permitted to call the `approve` function on the
USDC token contract with an allowance value of `0`. This effectively limits the delegate to
revoking ERC-20 approvals.

:::important Usage
The `allowedCalldata` doesn't support multiple selectors. Each entry in the
list represents a portion of calldata corresponding to the same function signature.

You can include or exclude specific parameters to precisely define what parts of the calldata are valid.
:::

```typescript

// USDC address on Sepolia.
const USDC_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  scope: {
    type: ScopeType.FunctionCall,
    targets: [USDC_ADDRESS],
    selectors: ['approve(address, uint256)'],
    allowedCalldata: [
      {
        // Limits the allowance amount to be 0.
        value: encodeAbiParameters([{ name: 'amount', type: 'uint256' }], [0n]),
        // The first 4 bytes are for selector, and next 32 bytes
        // are for spender address.
        startIndex: 36,
      },
    ],
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

### Define exact calldata

You can define the `exactCalldata` instead of the `allowedCalldata`. For example, you can
set `exactCalldata` so the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is permitted to call only the `approve` function on the USDC token
contract, with a specific spender address and an allowance value of 0. This effectively limits the delegate to
revoking ERC-20 approvals for a specific spender.

```typescript

// USDC address on Sepolia.
const USDC_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  scope: {
    type: ScopeType.FunctionCall,
    targets: [USDC_ADDRESS],
    selectors: ['approve(address, uint256)'],
    exactCalldata: {
      calldata: encodeFunctionData({
        abi: erc20Abi,
        args: ['0x0227628f3F023bb0B980b67D528571c95c6DaC1c', 0n],
        functionName: 'approve',
      }),
    },
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

### Allow native token transfer

You can set `valueLte` to allow native token transfer up to a specified amount per call. By default, this value is set to `0`. For example, Alice can allow Bob
to take `0.00001` ETH as a fee each time he revokes a token approval on her behalf.

```ts

// USDC address on Sepolia.
const USDC_ADDRESS = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  scope: {
    type: ScopeType.FunctionCall,
    targets: [USDC_ADDRESS],
    selectors: ['approve(address, uint256)'],
    valueLte: { maxValue: parseEther('0.00001') },
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Next steps

See [how to further constrain the authority of a delegation](constrain-scope.md) using caveat enforcers.

---

## Use delegation scopes


When [creating a delegation](../execute-on-smart-accounts-behalf.md), you must configure a scope to define the delegation's initial authority and help prevent delegation misuse.
You can further constrain this initial authority by [adding caveats to a delegation](constrain-scope.md).

The Smart Accounts Kit currently supports three categories of scopes:

| Scope type                                        | Description                                                                                                                         |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| [Spending limit scopes](spending-limit.md)        | Restricts the spending of native, ERC-20, and ERC-721 tokens based on defined conditions.                                           |
| [Function call scope](function-call.md)           | Restricts the delegation to specific contract methods, contract addresses, or calldata.                                             |
| [Ownership transfer scope](ownership-transfer.md) | Restricts the delegation to only allow ownership transfers, specifically the `transferOwnership` function for a specified contract. |

---

## Use the ownership transfer scope


The ownership transfer scope restricts a delegation to ownership transfer calls only.
For example, Alice has deployed a smart contract, and she delegates to Bob the ability to transfer ownership of that contract.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a delegator account.](../execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](../execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)

## Ownership transfer scope

This scope requires a `contractAddress`, which represents the address of the deployed contract.

Internally, this scope uses the [`ownershipTransfer`](../../../reference/delegation/caveats.md#ownershiptransfer) <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>.
See the [ownership transfer scope reference](../../../reference/delegation/delegation-scopes.md#ownership-transfer-scope) for more details.

```typescript

const contractAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

const delegation = createDelegation({
  scope: {
    type: ScopeType.OwnershipTransfer,
    contractAddress,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Next steps

See [how to further constrain the authority of a delegation](constrain-scope.md) using caveat enforcers.

---

## Use spending limit scopes


Spending limit scopes define how much a <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can spend in native, ERC-20, or ERC-721 tokens.
You can set transfer limits with or without time-based (periodic) or streaming conditions, depending on your use case.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)
- [Configure the Smart Accounts Kit.](../../configure-toolkit.md)
- [Create a delegator account.](../execute-on-smart-accounts-behalf.md#3-create-a-delegator-account)
- [Create a delegate account.](../execute-on-smart-accounts-behalf.md#4-create-a-delegate-account)

## ERC-20 periodic scope

This scope ensures a per-period limit for ERC-20 token transfers.
You set the amount, period, and start data.
At the start of each new period, the allowance resets.
For example, Alice creates a delegation that lets Bob spend up to 10 USDC on her behalf each day.
Bob can transfer a total of 10 USDC per day; the limit resets at the beginning of the next day.

When this scope is applied, the toolkit automatically disallows native token transfers (sets the native token transfer limit to `0`).

Internally, this scope uses the [`erc20PeriodTransfer`](../../../reference/delegation/caveats.md#erc20periodtransfer) and [`valueLte`](../../../reference/delegation/caveats.md#valuelte) <GlossaryTerm term="Caveat enforcer">caveat enforcers</GlossaryTerm>.
See the [ERC-20 periodic scope reference](../../../reference/delegation/delegation-scopes.md#erc-20-periodic-scope) for more details.

```typescript

// startDate should be in seconds.
const startDate = Math.floor(Date.now() / 1000)

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20PeriodTransfer,
    tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    // USDC has 6 decimal places.
    periodAmount: parseUnits('10', 6),
    periodDuration: 86400,
    startDate,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## ERC-20 streaming scope

This scopes ensures a linear streaming transfer limit for ERC-20 tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.
For example, Alice creates a delegation that allows Bob to spend 0.1 USDC per second, starting with an initial amount of 10 USDC, up to a maximum of 100 USDC.

When this scope is applied, the toolkit automatically disallows native token transfers (sets the native token transfer limit to `0`).

Internally, this scope uses the [`erc20Streaming`](../../../reference/delegation/caveats.md#erc20streaming) and [`valueLte`](../../../reference/delegation/caveats.md#valuelte) <GlossaryTerm term="Caveat enforcer">caveat enforcers</GlossaryTerm>.
See the [ERC-20 streaming scope reference](../../../reference/delegation/delegation-scopes.md#erc-20-streaming-scope) for more details.

```typescript

// startTime should be in seconds.
const startTime = Math.floor(Date.now() / 1000)

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20Streaming,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // USDC has 6 decimal places.
    amountPerSecond: parseUnits('0.1', 6),
    initialAmount: parseUnits('10', 6),
    maxAmount: parseUnits('100', 6),
    startTime,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## ERC-20 transfer scope

This scope ensures that ERC-20 token transfers are limited to a predefined maximum amount.
This scope is useful for setting simple, fixed transfer limits without any time-based or streaming conditions.
For example, Alice creates a delegation that allows Bob to spend up to 10 USDC without any conditions.
Bob may use the 10 USDC in a single transaction or make multiple transactions, as long as the total does not exceed 10 USDC.

When this scope is applied, the toolkit automatically disallows native token transfers (sets the native token transfer limit to `0`).

Internally, this scope uses the [`erc20TransferAmount`](../../../reference/delegation/caveats.md#erc20transferamount) and [`valueLte`](../../../reference/delegation/caveats.md#valuelte) <GlossaryTerm term="Caveat enforcer">caveat enforcers</GlossaryTerm>.
See the [ERC-20 transfer scope reference](../../../reference/delegation/delegation-scopes.md#erc-20-transfer-scope) for more details.

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // USDC has 6 decimal places.
    maxAmount: parseUnits('10', 6),
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## ERC-721 scope

This scope limits the delegation to ERC-721 token transfers only.
For example, Alice creates a delegation that allows Bob to transfer an NFT she owns on her behalf.

Internally, this scope uses the [`erc721Transfer`](../../../reference/delegation/caveats.md#erc721transfer) <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>.
See the [ERC-721 scope reference](../../../reference/delegation/delegation-scopes.md#erc-721-scope) for more details.

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc721Transfer,
    tokenAddress: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    tokenId: 1n,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Native token periodic scope

This scope ensures a per-period limit for native token transfers.
You set the amount, period, and start date.
At the start of each new period, the allowance resets.
For example, Alice creates a delegation that lets Bob spend up to 0.01 ETH on her behalf each day.
Bob can transfer a total of 0.01 ETH per day; the limit resets at the beginning of the next day.

When this scope is applied, the toolkit disallows ERC-20 and ERC-721 token transfers by default (sets `exactCalldata` to `0x`).
You can optionally configure `exactCalldata` to restrict transactions to a specific operation, or configure
`allowedCalldata` to allow transactions that match certain patterns or ranges.

Internally, this scope uses the [`nativeTokenPeriodTransfer`](../../../reference/delegation/caveats.md#nativetokenperiodtransfer) <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>, and
optionally uses the [`allowedCalldata`](../../../reference/delegation/caveats.md#allowedcalldata) or [`exactCalldata`](../../../reference/delegation/caveats.md#exactcalldata) caveat enforcers when those parameters are specified.
See the [native token periodic scope reference](../../../reference/delegation/delegation-scopes.md#native-token-periodic-scope) for more details.

```typescript

// startDate should be in seconds.
const startDate = Math.floor(Date.now() / 1000)

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenPeriodTransfer,
    periodAmount: parseEther('0.01'),
    periodDuration: 86400,
    startDate,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Native token streaming scope

This scopes ensures a linear streaming transfer limit for native tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.
For example, Alice creates delegation that allows Bob to spend 0.001 ETH per second, starting with an initial amount of 0.01 ETH, up to a maximum of 0.1 ETH.

When this scope is applied, the toolkit disallows ERC-20 and ERC-721 token transfers by default (sets `exactCalldata` to `0x`).
You can optionally configure `exactCalldata` to restrict transactions to a specific operation, or configure
`allowedCalldata` to allow transactions that match certain patterns or ranges.

Internally, this scope uses the [`nativeTokenStreaming`](../../../reference/delegation/caveats.md#nativetokenstreaming) <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>, and
optionally uses the [`allowedCalldata`](../../../reference/delegation/caveats.md#allowedcalldata) or [`exactCalldata`](../../../reference/delegation/caveats.md#exactcalldata) caveat enforcers when those parameters are specified.
See the [native token streaming scope reference](../../../reference/delegation/delegation-scopes.md#native-token-streaming-scope) for more details.

```typescript

// startTime should be in seconds.
const startTime = Math.floor(Date.now() / 1000)

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenStreaming,
    amountPerSecond: parseEther('0.001'),
    initialAmount: parseEther('0.01'),
    maxAmount: parseEther('0.1'),
    startTime,
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Native token transfer scope

This scope ensures that native token transfers are limited to a predefined maximum amount.
This scope is useful for setting simple, fixed transfer limits without any time-based or streaming conditions.
For example, Alice creates a delegation that allows Bob to spend up to 0.1 ETH without any conditions.
Bob may use the 0.1 ETH in a single transaction or make multiple transactions, as long as the total does not exceed 0.1 ETH.

When this scope is applied, the toolkit disallows ERC-20 and ERC-721 token transfers by default (sets `exactCalldata` to `0x`).
You can optionally configure `exactCalldata` to restrict transactions to a specific operation, or configure
`allowedCalldata` to allow transactions that match certain patterns or ranges.

Internally, this scope uses the [`nativeTokenTransferAmount`](../../../reference/delegation/caveats.md#nativetokentransferamount) <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>, and
optionally uses the [`allowedCalldata`](../../../reference/delegation/caveats.md#allowedcalldata) or [`exactCalldata`](../../../reference/delegation/caveats.md#exactcalldata) caveat enforcers when those parameters are specified.
See the [native token transfer scope reference](../../../reference/delegation/delegation-scopes.md#native-token-transfer-scope) for more details.

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    maxAmount: parseEther('0.001'),
  },
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

## Next steps

See [how to further constrain the authority of a delegation](constrain-scope.md) using caveat enforcers.

---

## Create a smart account


You can enable users to create a [MetaMask smart account](../../concepts/smart-accounts.md) directly
in your dapp. Use [`toMetaMaskSmartAccount`](../../reference/smart-account.md#tometamasksmartaccount)
to create different types of smart accounts with different signature schemes.

## Prerequisites

[Install and set up the Smart Accounts Kit.](../../get-started/install.md)

## Hybrid smart account

A [Hybrid smart account](../../concepts/smart-accounts.md#hybrid-smart-account) supports both an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> owner and any number of <GlossaryTerm term="Passkey">passkey</GlossaryTerm> (WebAuthn) <GlossaryTerm term="Signer">signers</GlossaryTerm>.

This example uses `toMetaMaskSmartAccount` and Viem's [Wallet Client](https://viem.sh/docs/clients/wallet)
to create a Hybrid smart account. The `signer` parameter also accepts Viem's [Local Account](https://viem.sh/docs/accounts/local) and [WebAuthnAccount](https://viem.sh/account-abstraction/accounts/webauthn#webauthn-account).

See the [`toMetaMaskSmartAccount`](../../reference/smart-account.md#tometamasksmartaccount) API reference for more information.

<Tabs>
<TabItem value="example.ts">

```typescript

// Some wallets like MetaMask may require you to request access to
// account addresses using walletClient.requestAddresses() first.
const [address] = await walletClient.getAddresses()

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})
```

</TabItem>

<TabItem value="client.ts">

```typescript

const transport = http()
export const publicClient = createPublicClient({
  transport,
  chain,
})
```

</TabItem>

<TabItem value="signer.ts">

```typescript

export const walletClient = createWalletClient({
  chain,
  transport: custom(window.ethereum!),
})
```

</TabItem>
</Tabs>

## Multisig smart account

A [Multisig smart account](../../concepts/smart-accounts.md#multisig-smart-account) supports multiple <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> <GlossaryTerm term="Signer">signers</GlossaryTerm> with a configurable threshold for execution.

This example uses [`toMetaMaskSmartAccount`](../../reference/smart-account.md#tometamasksmartaccount) to create a
Multisig smart account with a combination of account signers and Wallet Client signers.

<Tabs>
<TabItem value="example.ts">

```typescript

const owners = [account.address, walletClient.address]
const signer = [{ account }, { walletClient }]
const threshold = 2n

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [owners, threshold],
  deploySalt: '0x',
  signer,
})
```

</TabItem>

<TabItem value="client.ts">

```typescript

const transport = http()
export const publicClient = createPublicClient({
  transport,
  chain,
})
```

</TabItem>

<TabItem value="signers.ts">

```typescript

// This private key will be used to generate the first signer.
const privateKey = generatePrivateKey()
export const account = privateKeyToAccount(privateKey)

// This private key will be used to generate the second signer.
const walletClientPrivateKey = generatePrivateKey()
const walletClientAccount = privateKeyToAccount(walletClientPrivateKey)

export const walletClient = createWalletClient({
  account: walletClientAccount,
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

:::note
The number of signers must be at least equal to the threshold to generate a valid signature.
:::

## EIP-7702 smart account

An [EIP-7702 smart account](../../concepts/smart-accounts.md#stateless-7702-smart-account) represents an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> that has been upgraded
to support <GlossaryTerm term="MetaMask smart account">MetaMask Smart Accounts</GlossaryTerm> functionality as defined by [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).

This example uses [`toMetaMaskSmartAccount`](../../reference/smart-account.md#tometamasksmartaccount)
and Viem's [`privateKeyToAccount`](https://viem.sh/docs/accounts/local/privateKeyToAccount) to
create an EIP-7702 smart account. This example doesn't handle the upgrade process; see the
[EIP-7702 quickstart](../../get-started/smart-account-quickstart/eip7702.md) to learn how to upgrade.

:::note Important
The EIP-7702 implementation only works with Viem's [Local Accounts](https://viem.sh/docs/accounts/local). It doesn't work with a [JSON-RPC Account](https://viem.sh/docs/accounts/jsonRpc) like MetaMask.

See the [Upgrade a MetaMask EOA to a smart account](https://docs.metamask.io/tutorials/upgrade-eoa-to-smart-account/) tutorial.
:::

<Tabs>
<TabItem value="example.ts">

```typescript

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Stateless7702,
  address: account.address,
  signer: { account },
})
```

</TabItem>

<TabItem value="client.ts">

```typescript

const transport = http()
export const publicClient = createPublicClient({
  transport,
  chain,
})
```

</TabItem>

<TabItem value="signer.ts">

```typescript

const privateKey = generatePrivateKey()
export const account = privateKeyToAccount(privateKey)
```

</TabItem>
</Tabs>

## Next steps

- [Configure signers](./signers/index.mdx) to use a signer that fits your needs.
- [Deploy the smart account](deploy-smart-account.md) and [send user operations](send-user-operation.md) using [Viem Account Abstraction clients](../configure-toolkit.md).
- [Create delegations](../delegation/execute-on-smart-accounts-behalf.md) to grant scoped permissions to other accounts.

---

## Deploy a smart account


You can deploy [MetaMask Smart Accounts](../../concepts/smart-accounts.md) in two different ways. You can either deploy a smart account automatically when sending
the first <GlossaryTerm term="User operation">user operation</GlossaryTerm>, or manually deploy the account.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a MetaMask smart account.](create-smart-account.md)

## Deploy with the first user operation

When you send the first user operation from a smart account, the Smart Accounts Kit checks whether the account is already deployed. If the account
is not deployed, the toolkit adds the `initCode` to the user operation to deploy the account within the
same operation. Internally, the `initCode` is encoded using the `factory` and `factoryData`.

<Tabs>
<TabItem value="example.ts">

```typescript

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: '0x1234567890123456789012345678901234567890',
      value: parseEther('0.001'),
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://public.pimlico.io/v2/11155111/rpc'),
})
```

</TabItem>
</Tabs>

## Deploy manually

To deploy a smart account manually, call the [`getFactoryArgs`](../../reference/smart-account.md#getfactoryargs)
method from the smart account to retrieve the `factory` and `factoryData`. This allows you to use a relay account to sponsor the deployment without needing a paymaster.

The `factory` represents the contract address responsible for deploying the smart account, while `factoryData` contains the
calldata that will be executed by the `factory` to deploy the smart account.

The relay account can be either an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> or another smart account. This example uses an EOA.

<Tabs>
<TabItem value="example.ts">

```typescript

const { factory, factoryData } = await smartAccount.getFactoryArgs()

// Deploy smart account using relay account.
const hash = await walletClient.sendTransaction({
  to: factory,
  data: factoryData,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})

const relayAccountPrivateKey = '0x121..'
const relayAccount = privateKeyToAccount(relayAccountPrivateKey)

export const walletClient = createWalletClient({
  account: relayAccount,
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

## Next steps

- Learn more about [sending user operations](send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](send-gasless-transaction.md).

---

## Generate a multisig signature


The Smart Accounts Kit supports [Multisig smart accounts](../../concepts/smart-accounts.md#multisig-smart-account),
allowing you to add multiple <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>
<GlossaryTerm term="Signer">signers</GlossaryTerm> with a configurable execution threshold. When the threshold
is greater than 1, you can collect signatures from the required signers
and use the [`aggregateSignature`](../../reference/smart-account.md#aggregatesignature) function to combine them
into a single aggregated signature.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a Multisig smart account.](create-smart-account.md#multisig-smart-account)

## Generate a multisig signature

The following example configures a Multisig smart account with two different signers: Alice
and Bob. The account has a threshold of 2, meaning that signatures from
both parties are required for any execution.

<Tabs>
<TabItem value="example.ts">

```typescript

  bundlerClient,
  aliceSmartAccount,
  bobSmartAccount,
  aliceAccount,
  bobAccount,
} from './config.ts'

const userOperation = await bundlerClient.prepareUserOperation({
  account: aliceSmartAccount,
  calls: [
    {
      target: zeroAddress,
      value: 0n,
      data: '0x',
    },
  ],
})

const aliceSignature = await aliceSmartAccount.signUserOperation(userOperation)
const bobSignature = await bobSmartAccount.signUserOperation(userOperation)

const aggregatedSignature = aggregateSignature({
  signatures: [
    {
      signer: aliceAccount.address,
      signature: aliceSignature,
      type: 'ECDSA',
    },
    {
      signer: bobAccount.address,
      signature: bobSignature,
      type: 'ECDSA',
    },
  ],
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const alicePrivateKey = generatePrivateKey()
export const aliceAccount = privateKeyToAccount(alicePrivateKey)

const bobPrivateKey = generatePrivateKey()
export const bobAccount = privateKeyToAccount(bobPrivateKey)

const signers = [aliceAccount.address, bobAccount.address]
const threshold = 2n

export const aliceSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [signers, threshold],
  deploySalt: '0x',
  signer: [{ account: aliceAccount }],
})

export const bobSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [signers, threshold],
  deploySalt: '0x',
  signer: [{ account: bobAccount }],
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://public.pimlico.io/v2/rpc'),
})
```

</TabItem>
</Tabs>

---

## Send a gasless transaction


[MetaMask Smart Accounts](../../concepts/smart-accounts.md) support gas sponsorship, which simplifies onboarding by abstracting gas fees away from end users.
You can use any <GlossaryTerm term="Paymaster">paymaster</GlossaryTerm> service provider, such as [Pimlico](https://docs.pimlico.io/references/paymaster) or [ZeroDev](https://docs.zerodev.app/meta-infra/rpcs), or plug in your own custom paymaster.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a MetaMask smart account.](create-smart-account.md)

## Send a gasless transaction

The following example demonstrates how to use Viem's [Paymaster Client](https://viem.sh/account-abstraction/clients/paymaster) to send gasless transactions.
You can provide the paymaster client using the paymaster property in the [`sendUserOperation`](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation#paymaster-optional) method, or in the [Bundler Client](https://viem.sh/account-abstraction/clients/bundler#paymaster-optional).

In this example, the paymaster client is passed to the `sendUserOperation` method.

<Tabs>
<TabItem value="example.ts">

```typescript

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: '0x1234567890123456789012345678901234567890',
      value: parseEther('0.001'),
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
  paymaster: paymasterClient,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>'),
})

export const paymasterClient = createPaymasterClient({
  // You can use the paymaster of your choice
  transport: http('https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>'),
})
```

</TabItem>
</Tabs>

---

## Send a user operation


User operations are the [ERC-4337](https://eips.ethereum.org/EIPS/eip-4337) counterpart to traditional blockchain transactions.
They incorporate significant enhancements that improve user experience and provide greater
flexibility in account management and transaction execution.

Viem's Account Abstraction API allows a developer to specify an array of `Calls` that will be executed as a user operation via Viem's [`sendUserOperation`](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation) method.
The Smart Accounts Kit encodes and executes the provided calls.

User operations are not directly sent to the network.
Instead, they are sent to a bundler, which validates, optimizes, and aggregates them before network submission.
See [Viem's Bundler Client](https://viem.sh/account-abstraction/clients/bundler) for details on how to interact with the bundler.

:::note
If a user operation is sent from a MetaMask smart account that has not been deployed, the toolkit configures the user operation to automatically deploy the account.
:::

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../get-started/install.md)
- [Create a MetaMask smart account.](create-smart-account.md)

## Send a user operation

The following is a simplified example of sending a <GlossaryTerm term="User operation">user operation</GlossaryTerm> using Viem Core SDK. Viem Core SDK offers more granular control for developers who require it.

In the example, a user operation is created with the necessary gas limits.

This user operation is passed to a <GlossaryTerm term="Bundler">bundler</GlossaryTerm> instance, and the `EntryPoint` address is retrieved from the client.

<Tabs>
<TabItem value="example.ts">

```typescript

// Appropriate fee per gas must be determined for the specific bundler being used.
const maxFeePerGas = 1n
const maxPriorityFeePerGas = 1n

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: '0x1234567890123456789012345678901234567890',
      value: parseEther('0.001'),
    },
  ],
  maxFeePerGas,
  maxPriorityFeePerGas,
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const privateKey = generatePrivateKey()
const account = privateKeyToAccount(privateKey)

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://public.pimlico.io/v2/11155111/rpc'),
})
```

</TabItem>
</Tabs>

### Estimate fee per gas

Different bundlers have different ways to estimate `maxFeePerGas` and `maxPriorityFeePerGas`, and can reject requests with insufficient values.
The following example updates the previous example to estimate the fees.

This example uses constant values, but the [Hello Gator example](https://github.com/MetaMask/hello-gator) uses Pimlico's Alto bundler,
which fetches user operation gas price using the RPC method [`pimlico_getUserOperationPrice`](https://docs.pimlico.io/infra/bundler/endpoints/pimlico_getUserOperationGasPrice).

:::info Installation required

To estimate the gas fee for Pimlico's bundler, install the [permissionless.js SDK](https://docs.pimlico.io/references/permissionless/).

:::

```typescript title="example.ts"
// add-next-line
+ import { createPimlicoClient } from "permissionless/clients/pimlico";

// remove-start
- const maxFeePerGas = 1n;
- const maxPriorityFeePerGas = 1n;
// remove-end

// add-start
+ const pimlicoClient = createPimlicoClient({
+   transport: http("https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>"), // You can get the API Key from the Pimlico dashboard.
+ });
+
+ const { fast: fee } = await pimlicoClient.getUserOperationGasPrice();
// add-end

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: "0x1234567890123456789012345678901234567890",
      value: parseEther("1")
    }
  ],
  // remove-start
-  maxFeePerGas,
-  maxPriorityFeePerGas
  // remove-end
  // add-next-line
+  ...fee
});
```

### Wait for the transaction receipt

After submitting the user operation, it's crucial to wait for the receipt to ensure that it has been successfully included in the blockchain. Use the `waitForUserOperationReceipt` method provided by the bundler client.

```typescript title="example.ts"

const pimlicoClient = createPimlicoClient({
  transport: http("https://api.pimlico.io/v2/11155111/rpc?apikey=<YOUR-API-KEY>"), // You can get the API Key from the Pimlico dashboard.
});

const { fast: fee } = await pimlicoClient.getUserOperationGasPrice();

const userOperationHash = await bundlerClient.sendUserOperation({
  account: smartAccount,
  calls: [
    {
      to: "0x1234567890123456789012345678901234567890",
      value: parseEther("1")
    }
  ],
  ...fee
});

// add-start
+ const { receipt } = await bundlerClient.waitForUserOperationReceipt({
+   hash: userOperationHash
+ });
+
+ console.log(receipt.transactionHash);
// add-end
```

## Next steps

To sponsor gas for end users, see how to [send a gasless transaction](send-gasless-transaction.md).

---

## Use Dynamic with MetaMask Smart Accounts


[Dynamic](https://www.dynamic.xyz/) is an embedded wallet solution that enables seamless social sign-in and passkey based
wallets, making user onboarding easier. MetaMask Smart Accounts is a signer-agnostic implementation
that allows you to use Dynamic's EOA wallet as a signer for <GlossaryTerm term="MetaMask smart account">smart accounts</GlossaryTerm>.

<!--
View the complete code for this guide in the [`gator-examples`](https://github.com/MetaMask/gator-examples/tree/main/examples/smart-accounts/signers/dynamic) repository.
-->

:::info
This guide supports React and React-based frameworks.
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- Create a [Dynamic Environment ID](https://www.dynamic.xyz/docs/developer-dashboard/tokens-api-keys#environment-id).

## Steps

### 1. Install dependencies

Install the following dependencies:

```bash npm2yarn
npm install @dynamic-labs/ethereum @dynamic-labs/sdk-react-core @dynamic-labs/wagmi-connector @metamask/smart-accounts-kit @tanstack/react-query wagmi viem
```

### 2. Create the Dynamic provider

In this step, you'll configure the [`DynamicContextProvider`](https://www.dynamic.xyz/docs/react-sdk/providers/providers-introduction#dynamic-context-provider) component to provide Dynamic's context
to your application. You'll also use the [`DynamicWagmiConnector`](https://www.dynamic.xyz/docs/react-sdk/providers/providers-introduction#dynamic-wagmi-connector) to integrate Dynamic with Wagmi. This
connector enables you to use Wagmi hooks with Dynamic.

Once you have created the `DynamicProvider`, you must wrap it at the root of your application so
that the rest of your application has access to the Dynamic's context.

For an advanced configuration, see how to [configure Dynamic and Wagmi](https://www.dynamic.xyz/docs/react-sdk/using-wagmi).

<Tabs>
<TabItem value = "provider.ts">

```ts

export function DynamicProvider({ children }: { children: ReactNode }) {
  return (
    <DynamicContextProvider
      settings={{
        // Get your environment id at https://app.dynamic.xyz/dashboard/developer
        environmentId: "<YOUR_DYNAMIC_ENVIRONMENT_ID>",
        walletConnectors: [EthereumWalletConnectors],
      }}
    >
      <QueryClientProvider client={queryClient}>
        <WagmiProvider config={wagmiConfig}>
          <DynamicWagmiConnector>
            {children}
          </DynamicWagmiConnector>
        </WagmiProvider>
      </QueryClientProvider>
    </DynamicContextProvider >
  );
}
```

</TabItem>

<TabItem value = "config.ts">

```ts

export const queryClient = new QueryClient()

export const wagmiConfig = createConfig({
  chains: [sepolia],
  ssr: true,
  transports: {
    [sepolia.id]: http(),
  },
})
```

</TabItem>
</Tabs>

### 3. Create a smart account

Once the user has connected their wallet, use the [Wallet Client](https://viem.sh/docs/clients/wallet) from Wagmi as the signer to create a
<GlossaryTerm term="MetaMask smart account" />.

```ts

const { address } = useConnection()
const publicClient = usePublicClient()
const { data: walletClient } = useWalletClient()

// Additional check to make sure the Dyanmic is connected
// and values are available.
if (!address || !walletClient || !publicClient) {
  // Handle the error case
}

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})
```

## Next steps

- See how to [send a user operation](../send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](../send-gasless-transaction.md).

---

## Use MetaMask Embedded Wallets with MetaMask Smart Accounts


[MetaMask Embedded Wallets (Web3Auth)](/embedded-wallets/) provides a pluggable embedded wallet
infrastructure to simplify Web3 wallet integration and user onboarding. It supports social sign-ins allowing
users to access Web3 applications through familiar authentication methods in under a minute.

MetaMask Smart Accounts is a signer-agnostic implementation that allows you to use Embedded Wallets as a signer for <GlossaryTerm term="MetaMask smart account">smart accounts</GlossaryTerm>.

:::info
This guide supports React and React-based frameworks.
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- Create an [Embedded Wallets Client ID](/embedded-wallets/dashboard).

## Steps

### 1. Install dependencies

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit) and other dependencies in your project:

```bash npm2yarn
npm install @metamask/smart-accounts-kit @web3auth/modal wagmi @tanstack/react-query viem
```

### 2. Create the Web3Auth provider

Configure the `Web3AuthProvider` component to provide the Embedded Wallets context to your application.
You'll also use the `WagmiProvider` to integrate Embedded Wallets with Wagmi.
This provider enables you to use Wagmi hooks with Embedded Wallets.

Once you've created the `Web3AuthAppProvider`, wrap it at the root of your application so
the rest of your application has access to the Embedded Wallets context.

For an advanced configuration, see the [Embedded Wallets guide](/embedded-wallets/sdk/react/advanced/).

<Tabs>
<TabItem value = "provider.ts">

```ts

// Make sure to import `WagmiProvider` from `@web3auth/modal/react/wagmi`, not `wagmi`

const queryClient = new QueryClient();

export function Web3AuthAppProvider({ children }: { children: ReactNode }) {
  return (
    <Web3AuthProvider config={web3authConfig}>
      <QueryClientProvider client={queryClient}>
        <WagmiProvider>{children}</WagmiProvider>
      </QueryClientProvider>
    </Web3AuthProvider>
  );
}
```

</TabItem>

<TabItem value = "config.ts">

```ts

const web3AuthOptions: Web3AuthOptions = {
  clientId: '<YOUR_WEB3AUTH_CLIENT_ID>',
  web3AuthNetwork: '<YOUR_WEB3AUTH_NETWORK>',
}

export const web3authConfig = {
  web3AuthOptions,
}
```

</TabItem>
</Tabs>

### 3. Create a smart account

Once the user has connected their wallet, use the [Wallet Client](https://viem.sh/docs/clients/wallet) from Wagmi as the signer to create a
<GlossaryTerm term="MetaMask smart account" />.

```ts

const { address } = useConnection()
const publicClient = usePublicClient()
const { data: walletClient } = useWalletClient()

// Additional check to make sure the Embedded Wallets is connected
// and values are available.
if (!address || !walletClient || !publicClient) {
  // Handle the error case
}

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})
```

## Next steps

- See how to [send a user operations](../send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](../send-gasless-transaction.md).

---

## Use an EOA with MetaMask Smart Accounts


Externally owned accounts (EOAs) are accounts controlled by a user's private key (paired with a public address) and are typically accessed through wallet apps like MetaMask. MetaMask Smart Accounts is signer-agnostic, so
you can use an EOA as the signer.

:::info
This guide supports React and React-based frameworks. For Vue, see [Wagmi docs](https://wagmi.sh/vue/getting-started).
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.

## Steps

### 1. Install dependencies

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit) and other dependencies in your project:

```bash npm2yarn
npm install @metamask/smart-accounts-kit wagmi @metamask/connect-evm @tanstack/react-query viem
```

### 2. Create the App provider

Once you've created the `AppProvider`, wrap it at the root of your application so
that the rest of your application has access to the Wagmi's and TanStack's context.
This will allow every component inside the provider to use the Wagmi hooks.

The example uses the [MetaMask Connect](https://wagmi.sh/react/api/connectors/metaMask) connector.
For an advanced configuration, see Wagmi's [`createConfig`](https://wagmi.sh/react/api/createConfig) API reference.

<Tabs>
<TabItem value = "provider.ts">

```ts

const queryClient = new QueryClient();

export function AppProvider({ children }: { children: ReactNode }) {
  return (
    <WagmiProvider config={config}>
      <QueryClientProvider client={queryClient}>
        {children}
      </QueryClientProvider>
    </WagmiProvider>
  );
}
```

</TabItem>

<TabItem value = "config.ts">

```ts

export const config = createConfig({
  chains: [sepolia],
  connectors: [metaMask()],
  transports: {
    [sepolia.id]: http(),
  },
})
```

</TabItem>
</Tabs>

### 3. Create a smart account

Once the user has connected their wallet, use the [Wallet Client](https://viem.sh/docs/clients/wallet) from Wagmi as the signer to create a
<GlossaryTerm term="MetaMask smart account" />.

```ts

const { address } = useConnection()
const publicClient = usePublicClient()
const { data: walletClient } = useWalletClient()

// Additional check to make sure the EOA wallet is connected
// and values are available.
if (!address || !walletClient || !publicClient) {
  // Handle the error case
}

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})
```

## Next steps

- See how to use [MetaMask Embedded Wallets as a signer](./eoa-wallets.md) to make the user onboarding journey easier.
- See how to [send a user operation](../send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](../send-gasless-transaction.md).

---

## Configure a signer


When [creating a smart account](../create-smart-account.md), you must specify a signer. The signer owns the smart account and is responsible for
generating the signatures required to submit <GlossaryTerm term="User operation">user operations</GlossaryTerm>. MetaMask Smart Accounts is signer-agnostic, allowing you
to use any signer you prefer, such as Embedded Wallets, <GlossaryTerm term="Passkey">passkeys</GlossaryTerm>, <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> wallets, or a custom signer.

MetaMask Smart Accounts has a native integration with [MetaMask Embedded Wallets](/embedded-wallets/), making user onboarding easier. In addition to the native integration, you can use
third-party wallet providers as Privy, Dynamic, or Para as the signer for your smart account.

See the following guides to learn how to configure different signers:

## Recommended

<CardList
  items={[
    {
      href: '/smart-accounts-kit/development/guides/smart-accounts/signers/embedded-wallets/',
      title: 'MetaMask Embedded Wallets',
      description:
        'Learn how to use MetaMask Embedded Wallets (Web3Auth) with MetaMask Smart Accounts.',
    },
  ]}
/>

## Other signers

<CardList
  items={[
    {
      href: '/smart-accounts-kit/development/guides/smart-accounts/signers/dynamic',
      title: 'Dynamic',
      description: 'Learn how to use Dynamic with MetaMask Smart Accounts.',
    },
    {
      href: '/smart-accounts-kit/development/guides/smart-accounts/signers/eoa-wallets',
      title: 'EOA (e.g. MetaMask)',
      description: 'Learn how to use EOAs like MetaMask with MetaMask Smart Accounts.',
    },
    {
      href: '/smart-accounts-kit/development/guides/smart-accounts/signers/passkey',
      title: 'Passkey',
      description: 'Learn how to use a passkey with MetaMask Smart Accounts.',
    },
    {
      href: '/smart-accounts-kit/development/guides/smart-accounts/signers/privy',
      title: 'Privy',
      description: 'Learn how to use Privy with MetaMask Smart Accounts.',
    },
  ]}
/>

---

## Use a passkey with MetaMask Smart Accounts


Passkeys eliminate the need for traditional seed phrases that are difficult to remember, enabling a more seamless
and secure way for users to access their <GlossaryTerm term="Externally owned account (EOA)">EOAs</GlossaryTerm>. Compared to traditional EOAs which use
secp256k1 elliptic curve to generate key pairs and signatures, a passkey-based EOA uses the
secp256r1 (P-256) elliptic curve.

MetaMask Smart Accounts is signer-agnostic and natively supports passkeys (P-256 elliptic curve signatures), so you can use a passkey as the signer.

:::note
Unlike EOA ECDSA signatures, passkey (WebAuthn) signatures are non-deterministic.
Signing the same message twice produces different signatures, because the authenticator includes
fresh data such as counter in each assertion.
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.

## Steps

### 1. Install dependencies

Install the [Smart Accounts Kit](https://www.npmjs.com/package/@metamask/smart-accounts-kit) and other dependencies in your project:

```bash npm2yarn
npm install @metamask/smart-accounts-kit ox
```

### 2. Create a passkey

To create a passkey signer, use Viem's [`createWebAuthnCredential`](https://viem.sh/account-abstraction/accounts/webauthn/createWebAuthnCredential) function to securely register the passkey (WebAuthn credential).

```ts

const credential = await createWebAuthnCredential({
  name: 'MetaMask Smart Account',
})
```

### 3. Create a smart account

Once the passkey is created, use the [Viem WebAuthn Account](https://viem.sh/account-abstraction/accounts/webauthn) to configure your passkey as a <GlossaryTerm term="MetaMask smart account" /> signer.

The `deployParams` parameter needs the X and Y coordinates of the P-256 public key. Since WebAuthn credentials store
a compressed public key, you need to deserialize it, and extract the X and Y coordinates.

<Tabs>
<TabItem value="example.ts">

```typescript

const webAuthnAccount = toWebAuthnAccount({ credential })

// Deserialize compressed public key
const publicKey = PublicKey.fromHex(credential.publicKey)

// Convert public key to address
const owner = Address.fromPublicKey(publicKey)

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [owner, [toHex(credential.id)], [publicKey.x], [publicKey.y]],
  deploySalt: '0x',
  signer: { webAuthnAccount, keyId: toHex(credential.id) },
})
```

</TabItem>

<TabItem value="config.ts">

```typescript

const transport = http()
export const publicClient = createPublicClient({
  transport,
  chain,
})
```

</TabItem>
</Tabs>

## Next steps

- See how to [send a user operation](../send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](../send-gasless-transaction.md).

---

## Use Privy with MetaMask Smart Accounts


[Privy](https://docs.privy.io/welcome) provides an embedded wallet solution that enables seamless social sign-in for Web3 applications making user onboarding easier. MetaMask Smart Accounts is a signer-agnostic implementation
that allows you to use Privy's <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> wallet as a signer for <GlossaryTerm term="MetaMask smart account">smart accounts</GlossaryTerm>.

:::info
This guide supports React and React-based frameworks.
:::

## Prerequisites

- Install [Node.js](https://nodejs.org/en/blog/release/v18.18.0) v18 or later.
- Install [Yarn](https://yarnpkg.com/),
  [npm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm), or another package manager.
- Create a [Privy App ID](https://docs.privy.io/basics/get-started/dashboard/create-new-app#get-api-credentials).

## Steps

### 1. Install dependencies

Install the following dependencies:

```bash npm2yarn
npm install @privy-io/react-auth @privy-io/wagmi @metamask/smart-accounts-kit @tanstack/react-query wagmi viem
```

### 2. Create the Privy provider

In this step, you'll configure the `PrivyProvider` component to provide the Privy's context
to your application. You'll also use the Privy's `WagmiProvider` component to integrate Privy with Wagmi. This
provider enables you to use Wagmi hooks with Privy.

Once you have created the `PrivyAppProvider`, you must wrap it at the root of your application so
that the rest of your application has access to the Privy's context.

For an advanced configuration, see Privy's [configuring appearance](https://docs.privy.io/basics/get-started/dashboard/configuring-appearance) and [configuring login methods](https://docs.privy.io/basics/get-started/dashboard/configure-login-methods) guides.

<Tabs>
<TabItem value = "provider.ts">

```ts

// Make sure to import `WagmiProvider` from `@privy-io/wagmi`, not `wagmi`

export function PrivyAppProvider({ children }: { children: ReactNode }) {
  return (
    <PrivyProvider appId="<YOUR_PRIVY_APP_ID>">
      <QueryClientProvider client={queryClient}>
        <WagmiProvider config={wagmiConfig}>
          {children}
        </WagmiProvider>
      </QueryClientProvider>
    </PrivyProvider>
  );
}
```

</TabItem>

<TabItem value = "config.ts">

```ts

export const queryClient = new QueryClient()

export const wagmiConfig = createConfig({
  chains: [sepolia],
  ssr: true,
  transports: {
    [sepolia.id]: http(),
  },
})
```

</TabItem>
</Tabs>

### 3. Create a smart account

Once the user has connected their wallet, use the [Wallet Client](https://viem.sh/docs/clients/wallet) from Wagmi as the signer to create a
<GlossaryTerm term="MetaMask smart account" />.

```ts

const { address } = useConnection()
const publicClient = usePublicClient()
const { data: walletClient } = useWalletClient()

// Additional check to make sure the Privy is connected
// and values are available.
if (!address || !walletClient || !publicClient) {
  // Handle the error case
}

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [address, [], [], []],
  deploySalt: '0x',
  signer: { walletClient },
})
```

## Next steps

- See how to [send a user operation](../send-user-operation.md).
- To sponsor gas for end users, see how to [send a gasless transaction](../send-gasless-transaction.md).

---

## Pay for an x402 API with Advanced Permissions


In this guide, you request <GlossaryTerm term="Advanced Permissions" /> with a fixed ERC-20 allowance
to pay for a specific x402-protected resource.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)

## Steps

### 1. Set up a Wallet Client

Set up a Wallet Client using Viem's [`createWalletClient`](https://viem.sh/docs/clients/wallet) function. Use this client to interact with MetaMask.

Extend the Wallet Client with `erc7715ProviderActions` to enable <GlossaryTerm term="Advanced Permissions" /> requests.

```typescript

const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

### 2. Set up a session account

Set up a session account. The requested permissions are granted to the session account, which is responsible for making x402 API calls.

The session account can be either a <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> or an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>.
This example uses an EOA as the session account.

```typescript

const sessionAccount = privateKeyToAccount('0x...')
```

### 3. Get payment requirements

Call the protected API route once without the `PAYMENT-SIGNATURE` header.

The server returns `402` with the payment terms (`PAYMENT-REQUIRED`) in the response, which you use
to build the payment payload.

<Tabs>
<TabItem value="example.ts">

```ts

// Update the URL
const challengeResponse = await fetch('https://api.example.com/paid-endpoint')
if (challengeResponse.status !== 402) {
  console.error('Expected 402 challenge from protected route')
  // Handle error
}

const paymentRequiredHeader = challengeResponse.headers.get('PAYMENT-REQUIRED')
if (!paymentRequiredHeader) {
  console.error('PAYMENT-REQUIRED header is missing')
  // Handle error
}

const decodedPaymentRequired = Buffer.from(paymentRequiredHeader, 'base64').toString('utf-8')
const paymentRequired = JSON.parse(decodedPaymentRequired) as {
  accepts: PaymentRequirements[]
}

const accepted = paymentRequired.accepts[0]
if (!accepted) {
  console.error('Server did not provide accepted payment requirements')
  // Handle error
}

if (accepted.extra.assetTransferMethod !== 'erc7710') {
  console.error('Server does not support ERC-7710 delegation payments')
  // Handle error
}
```

</TabItem>
<TabItem value="types.ts">

```ts

export type PaymentRequirements = {
  scheme: string
  network: string
  amount: string
  asset: Address
  payTo: Address
  maxTimeoutSeconds: number
  extra: {
    assetTransferMethod: string
    facilitators?: Address[]
  }
}
```

</TabItem>
</Tabs>

### 4. Request Advanced Permissions

Request Advanced Permissions from the user with the Wallet Client's `requestExecutionPermissions` action.

In this example, you request an ERC-20 allowance permission with a fixed allowance equal to the
resource cost. Use the [`redeemer`](../../../reference/advanced-permissions/rules.md#redeemer) rule
to restrict redemption to facilitator addresses from the payment requirements.

See the [`requestExecutionPermissions`](../../../reference/advanced-permissions/wallet-client.md#requestexecutionpermissions) API reference for more information.

```ts

const facilitators = accepted.extra.facilitators
if (!facilitators || facilitators.length === 0) {
  console.error('No facilitators found in PAYMENT-REQUIRED')
  // Handle error
}

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 3600

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-allowance',
      data: {
        tokenAddress: accepted.asset,
        // Fixed allowance for this resource.
        allowanceAmount: BigInt(accepted.amount),
        justification: 'Permission to pay for a specific x402-protected API resource',
      },
      isAdjustmentAllowed: false,
    },
    rules: [
      {
        type: 'redeemer',
        data: {
          addresses: facilitators!,
        },
      },
    ],
  },
])
```

### 5. Create a redelegation

The granted advanced permission is delegated to the session account. To let facilitator addresses
redeem this permission context for x402 settlement, create an <GlossaryTerm term="Open redelegation">open redelegation</GlossaryTerm> from the session account.

Use the Wallet Client's [`redelegatePermissionContextOpen`](../../../reference/erc7710/wallet-client.md#redelegatepermissioncontextopen)
action to create a redelegated permission context. The granted permission already includes
a [redeemer enforcer](../../../reference/delegation/caveats.md#redeemer), so you do not add extra caveats here.

<Tabs>
<TabItem value="example.ts">

```ts

const permission = grantedPermissions[0]
if (!permission) {
  console.error('No permission response returned by requestExecutionPermissions')
  // Handle error
}

const { permissionContext: redelegatedPermissionContext } =
  await sessionAccountWalletClient.redelegatePermissionContextOpen({
    environment,
    permissionContext: permission!.context,
  })
```

</TabItem>
<TabItem value="config.ts">

```ts

export const environment = getSmartAccountsEnvironment(chain.id)

export const sessionAccountWalletClient = createWalletClient({
  account: sessionAccount,
  chain,
  transport: http(),
}).extend(erc7710WalletActions())
```

</TabItem>
</Tabs>

### 6. Create the payment payload

Create a payment payload using the redelegated permission context and accepted requirements.
For ERC-7710 (Smart Contract Delegation), x402 requires the payload fields `delegationManager`,
`permissionContext`, and `delegator`. The facilitator uses `permissionContext` to simulate
during verification and then settle the payment.

Encode the full x402 payment payload as base64, then send it in the `PAYMENT-SIGNATURE` header.

<Tabs>
<TabItem value="example.ts">

```ts

const permission = grantedPermissions[0]

const paymentPayload: PaymentPayload = {
  x402Version: 2,
  accepted,
  payload: {
    delegationManager: permission.delegationManager,
    permissionContext: redelegatedPermissionContext,
    delegator: permission.from,
  },
}

const encodedPayment = Buffer.from(JSON.stringify(paymentPayload)).toString('base64')
```

</TabItem>
<TabItem value="types.ts">

```ts

export type PaymentPayload = {
  x402Version: 2
  accepted: PaymentRequirements
  payload: {
    delegationManager: Address
    permissionContext: Hex
    delegator: Address
  }
}
```

</TabItem>
</Tabs>

### 7. Make the paid request

Send the base64-encoded x402 payment payload in the `PAYMENT-SIGNATURE` header.
If verification succeeds, the server returns the protected data.

```ts
const apiResponse = await fetch('https://api.example.com/paid-endpoint', {
  headers: {
    'PAYMENT-SIGNATURE': encodedPayment,
  },
})

if (!apiResponse.ok) {
  const errorBody = await apiResponse.json()
  console.error(errorBody.error ?? 'API request failed')
  // Handle error
}

const data = await apiResponse.json()
console.log('Protected API response:', data)
```

---

## Pay for an x402 API with delegation


In this guide, you use a buyer account to access API data from an x402 server by creating
a <GlossaryTerm term="Delegation">delegation</GlossaryTerm> that authorizes token transfers
on your behalf.

You use [`createx402DelegationProvider`](../../../reference/x402.md#createx402delegationprovider)
to set up an `x402Erc7710Client` with a delegation provider, register it with the x402 client,
and use `wrapFetchWithPayment` to automatically handle payment when calling a protected API route.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)

## Steps

### 1. Install the dependencies

```bash npm2yarn
npm install @x402/core @x402/fetch @metamask/x402
```

### 2. Create a buyer account

Create an account to represent the buyer, the
<GlossaryTerm term="Delegator account">delegator</GlossaryTerm> who creates a delegation.

The delegator must be a <GlossaryTerm term="MetaMask smart account" />.
Use the toolkit's
[`toMetaMaskSmartAccount`](../../../reference/smart-account.md#tometamasksmartaccount) method to
create the buyer account.

:::note Important
Fund the smart account with USDC for the requested payment.
:::

<Tabs>
<TabItem value="example.ts">

```ts

export const buyerSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [buyerAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: buyerAccount },
})
```

</TabItem>
<TabItem value="config.ts">

```ts

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})

export const buyerAccount = privateKeyToAccount('0x<BUYER_PRIVATE_KEY>')
```

</TabItem>
</Tabs>

### 3. Create an x402 ERC-7710 client

Create an `x402Erc7710Client` using
[`createx402DelegationProvider`](../../../reference/x402.md#createx402delegationprovider).
The provider creates an <GlossaryTerm term="Open delegation">open</GlossaryTerm>
<GlossaryTerm term="Root delegation">root delegation</GlossaryTerm>, signs it, and returns an ABI-encoded delegation chain
when the x402 client needs to pay for a request.

The provider appends [`redeemer`](../../../reference/delegation/caveats.md#redeemer),
[`allowedTargets`](../../../reference/delegation/caveats.md#allowedtargets), and
[`timestamp`](../../../reference/delegation/caveats.md#timestamp)
<GlossaryTerm term="Caveat">caveats</GlossaryTerm> if not already present.

```ts

const erc7710Client = new x402Erc7710Client({
  delegationProvider: createx402DelegationProvider({
    account: buyerSmartAccount,
  }),
})
```

### 4. Register the client

Register the ERC-7710 client with the x402 core client for all EVM networks.
Create an HTTP client and a payment-aware `fetch` function using `wrapFetchWithPayment`.

```ts

const coreClient = new x402Client().register('eip155:*', erc7710Client)
const httpClient = new x402HTTPClient(coreClient)

const fetchWithPayment = wrapFetchWithPayment(fetch, httpClient)
```

### 5. Make the paid request

Call the protected endpoint using `fetchWithPayment`.
It handles the x402 payment flow, calling your delegation provider
to create an <GlossaryTerm term="Open delegation">open delegation</GlossaryTerm> when the server returns a `402` response.

```ts
const paidResponse = await fetchWithPayment('https://api.example.com/paid-endpoint', {
  method: 'GET',
})
```

---

## Recurring x402 payments


In this guide, you set up recurring x402 payments by requesting an ERC-20 periodic
<GlossaryTerm term="Advanced Permissions" /> permission from a user.

For example, a user gives your agent permission to spend up to 10 USDC per week.
Later, when the agent calls an x402 endpoint, it checks the price, uses the granted permission,
and pays.

## Prerequisites

- [Install and set up the Smart Accounts Kit.](../../../get-started/install.md)

## Steps

### 1. Install the dependencies

```bash npm2yarn
npm install @x402/core @x402/fetch @metamask/x402
```

### 2. Set up a Wallet Client

Set up a Wallet Client using Viem's
[`createWalletClient`](https://viem.sh/docs/clients/wallet) function.
Use this client to interact with MetaMask.

Extend the Wallet Client with `erc7715ProviderActions` to enable
<GlossaryTerm term="Advanced Permissions" /> requests.

```typescript

const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

### 3. Set up an agent account

The session account can be either a
<GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> or an
<GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm>.
This example uses an EOA as the session account.

```typescript

const sessionAccount = privateKeyToAccount('0x...')
```

### 4. Request Advanced Permissions

Request Advanced Permissions from the user with the Wallet Client's
`requestExecutionPermissions` action.

In this example, you request an
[ERC-20 periodic permission](../../advanced-permissions/use-permissions/erc20-token.md#erc-20-periodic-permission)
with a weekly allowance of 10 USDC.
This creates a recurring payment budget that your agent can store and reuse for x402 API calls.

See the
[`requestExecutionPermissions`](../../../reference/advanced-permissions/wallet-client.md#requestexecutionpermissions)
API reference for more information.

```ts

// USDC address on Base.
const tokenAddress = '0x...'

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 60 * 60 * 24 * 30 // Permission expires in 30 days.

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress,
        periodAmount: parseUnits('10', 6),
        periodDuration: 604800,
        startTime: currentTime,
        justification:
          'Permission for agent to spend up to 10 USDC every week for making x402 API calls',
      },
      isAdjustmentAllowed: false,
    },
  },
])
```

### 5. Create an x402 ERC-7710 client

Create an `x402Erc7710Client` using
[`createx402DelegationProvider`](../../../reference/x402.md#createx402delegationprovider).

The provider creates an <GlossaryTerm term="Open redelegation">open redelegation</GlossaryTerm>
from the session account using the granted permission. The facilitator can then redeem the redelegated
permission context for x402 settlement.

```ts

const permission = grantedPermissions[0]

const erc7710Client = new x402Erc7710Client({
  delegationProvider: createx402DelegationProvider({
    account: sessionAccount,
    parentPermissionContext: permission.context,
    from: permission.from,
  }),
})
```

### 6. Register the client

Register the ERC-7710 client with the x402 core client for all EVM networks,
then create an HTTP client and a payment-aware `fetch` function using `wrapFetchWithPayment`.

```ts

const coreClient = new x402Client().register('eip155:*', erc7710Client)
const httpClient = new x402HTTPClient(coreClient)

const fetchWithPayment = wrapFetchWithPayment(fetch, httpClient)
```

### 7. Make the paid request

Call the protected endpoint using `fetchWithPayment`.
The x402 payment flow calls your delegation provider to create an open redelegation
when the server returns a `402` response.

```ts
const paidResponse = await fetchWithPayment('https://api.example.com/paid-endpoint', {
  method: 'GET',
})
```

You can reuse the same weekly granted permission for additional protected routes and providers
in your agent flow.
Your agent continues paying until the weekly cap is reached, then resumes after the next
weekly period starts.

---

## x402 Payments


[x402](https://www.x402.org/) is an open payment protocol that uses the HTTP `402` status code to enable programmatic, machine-to-machine payments over HTTP. It allows servers to charge for API access without requiring buyer accounts, API keys, or traditional payment infrastructure.

For example, an AI agent can pay 0.01 USDC per request to access a weather API, or a
dapp can charge users a micro-payment to retrieve premium onchain analytics data.

## ERC-7710 payments

The standard x402 protocol supports direct token transfers (using ERC-20 Permit2 or EIP-3009).
[ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) extends this by enabling <GlossaryTerm term="Delegation">delegation</GlossaryTerm>-based
payments from <GlossaryTerm term="MetaMask smart account">MetaMask smart accounts</GlossaryTerm>.

With ERC-7710, a buyer's smart account creates a delegation that authorizes the facilitator
to transfer tokens on their behalf. The buyer doesn't sign a direct token approval.
Instead, they sign a delegation that the facilitator redeems during settlement.

This approach enables buyers to pay from MetaMask wallet.
Buyers can restrict delegations to specific facilitator addresses, amounts, and time windows
using <GlossaryTerm term="Delegation scope">delegation scopes</GlossaryTerm>.
They can also create long lived delegations that allow recurring payments without re-signing
for each request.

Learn more [ERC-7710 delegations](../../concepts/delegation/overview.md).

## Guides

Get started with x402 payments in Smart Accounts Kit.
These guides walk you through seller endpoint setup and buyer payment flows.

<CardList
items={[
{
href: '/smart-accounts-kit/development/guides/x402/seller',
title: 'Set up a seller endpoint',
description:
'Configure a resource server that returns x402 payment requirements and settles requests.',
},
{
href: '/smart-accounts-kit/development/guides/x402/buyer/delegations',
title: 'Pay using a delegation',
description: 'Create an ERC-7710 delegation and use it as the x402 payment payload.',
},
{
href: '/smart-accounts-kit/development/guides/x402/buyer/advanced-permissions',
title: 'Pay using Advanced Permissions',
description:
'Request ERC-7715 Advanced Permissions for x402 payments with a fixed allowance.',
},
{
href: '/smart-accounts-kit/development/guides/x402/buyer/recurring-payments',
title: 'Set up recurring payments',
description:
'Grant a periodic budget permission for recurring x402 payments.',
},
]}
/>

---

## Create an x402 server with ERC-7710


In this guide, you build a Node.js server that charges for HTTP API access using
[x402](https://www.x402.org/) and accepts [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) delegation
payments verified through the MetaMask facilitator.

You use the official [`@x402/express`](https://www.npmjs.com/package/@x402/express) middleware with the
[`@metamask/x402`](https://www.npmjs.com/package/@metamask/x402)
package, which provides an ERC-7710 server scheme that routes verification and settlement
through the MetaMask facilitator.

## Prerequisites

- [Node.js 18](https://nodejs.org/en) or later.
- A [Node.js Express server](https://expressjs.com/en/starter/installing.html).
- A seller payout address to receive funds (for example, a
  [MetaMask wallet](https://metamask.io/download) address).

## Facilitator URLs

The following table lists the available MetaMask facilitator endpoints:

| Name         | ID             | URL                                                                         |
| ------------ | -------------- | --------------------------------------------------------------------------- |
| Base         | `eip155:8453`  | `https://tx-sentinel-base-mainnet.dev-api.cx.metamask.io/platform/v2/x402`  |
| Base Sepolia | `eip155:84532` | `https://tx-sentinel-base-sepolia.dev-api.cx.metamask.io/platform/v2/x402`  |
| Monad        | `eip155:143`   | `https://tx-sentinel-monad-mainnet.dev-api.cx.metamask.io/platform/v2/x402` |

## Steps

### 1. Install the dependencies

```bash npm2yarn
npm install @metamask/x402 @x402/core @x402/express cors express
```

### 2. Configure middleware

Set up the Express server with the x402 `paymentMiddleware` and the `x402ExactEvmErc7710ServerScheme`
from `@metamask/x402`.
The scheme automatically adds payment requirements with ERC-7710 fields when
`assetTransferMethod` is set to `erc7710` in the route configuration.

The `paymentMiddleware` intercepts requests to protected routes and handles the full x402 payment
flow, including requirements advertisement, verification, and settlement.

In this example, you create a protected `GET /api/hello` endpoint that charges 0.01 USDC on
Base Sepolia.
Replace the payout address in `src/config.ts` with your own seller wallet address.

<Tabs>
<TabItem value="src/index.ts">

```ts

const app = express()
app.use(cors({ exposedHeaders: ['PAYMENT-REQUIRED', 'PAYMENT-RESPONSE'] }))

app.use(
  paymentMiddleware(
    {
      'GET /api/hello': {
        accepts: [
          {
            scheme: 'exact',
            price: '$0.01',
            network: NETWORK_ID,
            payTo: payToAddress,
            extra: {
              assetTransferMethod: 'erc7710',
            },
          },
        ],
        description: 'Access to protected resource',
        mimeType: 'application/json',
      },
    },
    new x402ResourceServer(facilitatorClient).register(
      NETWORK_ID,
      new x402ExactEvmErc7710ServerScheme()
    )
  )
)

app.get('/api/hello', (_req: Request, res: Response) => {
  res.json({ message: 'Hello!' })
})

app.listen(PORT, () => {
  console.log(`[seller] Server running on http://localhost:${PORT}`)
})
```

</TabItem>

<TabItem value="src/config.ts">

```ts

export const NETWORK_ID = 'eip155:84532'
export const PORT = 4402

// Replace with your seller payout address.
export const payToAddress = '0x<PAY_TO_ADDRESS>'

// MetaMask facilitator base URL for x402 on Base Sepolia.
export const facilitatorClient = new HTTPFacilitatorClient({
  url: 'https://tx-sentinel-base-sepolia.api.cx.metamask.io/platform/v2/x402',
})
```

</TabItem>
</Tabs>

## Next steps

- Learn more about [ERC-7710 delegation](../../concepts/delegation/overview.md).
- See the [x402 ERC-7710 specification](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md#3-assettransfermethod-erc-7710).

---

## MetaMask Smart Accounts Kit introduction

# MetaMask Smart Accounts Kit

The MetaMask Smart Accounts Kit enables developers to create new experiences based on programmable account behavior and granular permission sharing.
It offers a suite of contracts, libraries, and services designed for maximum composability, allowing developers to build and extend their dapps with ease.

## Build on MetaMask Smart Accounts

The toolkit enables embedding [MetaMask Smart Accounts](concepts/smart-accounts.md) into dapps.
Smart accounts support programmable account behavior and advanced features like delegated permissions, multi-signature approvals, and gas abstraction.

[Delegation](concepts/delegation/overview.md) is a core feature of smart accounts, enabling secure, rule-based permission sharing.
Delegation is powered by the [Delegation Framework](https://github.com/metamask/delegation-framework), which defines how permissions are created, shared, and enforced.

<CardList
  items={[
    {
      href: '/smart-accounts-kit/development/get-started/smart-account-quickstart',
      title: 'Smart account quickstart',
      description: 'Create a MetaMask smart account and send a user operation.',
    },
    {
      href: '/smart-accounts-kit/development/guides/delegation/execute-on-smart-accounts-behalf',
      title: 'Delegation guide',
      description: 'Execute on the behalf of MetaMask Smart Accounts.',
    },
  ]}
/>

## Request Advanced Permissions (ERC-7715)

The toolkit supports [Advanced Permissions (ERC-7715)](concepts/advanced-permissions.md), which are fine-grained permissions dapps can request from users directly via the MetaMask browser extension.
Advanced Permissions allow you to perform executions on the behalf of MetaMask users.

<CardList
  items={[
    {
      href: '/smart-accounts-kit/development/guides/advanced-permissions/execute-on-metamask-users-behalf',
      title: 'Advanced Permissions (ERC-7715) guide',
      description: 'Execute on the behalf of MetaMask users.',
    },
  ]}
/>

## Partner integrations

The Smart Accounts Kit is integrated with multiple ecosystem partners.
Check out the following documentation from these partners:

<CardList
  items={[
    {
      href: '/smart-accounts-kit/development/get-started/use-scaffold-eth/smart-accounts',
      title: 'Smart Accounts with Scaffold-ETH 2',
      description: 'Install the MetaMask Smart Accounts extension for Scaffold-ETH 2.',
    },
    {
      href: '/smart-accounts-kit/development/get-started/use-scaffold-eth/advanced-permissions',
      title: 'Advanced Permissions with Scaffold-ETH 2',
      description:
        'Install the MetaMask Advanced Permissions (ERC-7715) extension for Scaffold-ETH 2.',
    },
    {
      href: 'https://viem.sh/account-abstraction/accounts/smart/toMetaMaskSmartAccount',
      title: 'Viem',
      description: 'Use MetaMask Smart Accounts with Viem.',
      buttonIcon: 'external-arrow',
    },
    {
      href: 'https://docs.arbitrum.io/for-devs/third-party-docs/MetaMask',
      title: 'Arbitrum',
      description: 'Use MetaMask Smart Accounts with Arbitrum.',
      buttonIcon: 'external-arrow',
    },
    {
      href: 'https://docs.pimlico.io/guides/how-to/accounts/use-metamask-account',
      title: 'permissionless.js',
      description: 'Use MetaMask Smart Accounts with permissionless.js.',
      buttonIcon: 'external-arrow',
    },
    {
      href: 'https://docs.monad.xyz/tooling-and-infra/account-abstraction/wallet-providers#metamask-delegation-toolkit',
      title: 'Monad',
      description: 'Use MetaMask Smart Accounts with Monad Testnet.',
      buttonIcon: 'external-arrow',
    },
  ]}
/>

---

## Advanced Permissions reference


When [executing on a MetaMask user's behalf](../../guides/advanced-permissions/execute-on-metamask-users-behalf.md), you can request the following permission types.
Learn [how to use Advanced Permissions types](../../guides/advanced-permissions/use-permissions/erc20-token.md).

## ERC-20 token permissions

### ERC-20 allowance permission

Ensures a fixed ERC-20 token allowance.
Transfers are allowed until the total transferred amount reaches the allowance amount.

#### Parameters

| Name              | Type      | Required | Description                                                            |
| ----------------- | --------- | -------- | ---------------------------------------------------------------------- |
| `tokenAddress`    | `Address` | Yes      | The ERC-20 token contract address.                                     |
| `allowanceAmount` | `bigint`  | Yes      | The maximum total amount of tokens that can be transferred.            |
| `startTime`       | `number`  | No       | The start timestamp in seconds. The default is the current time.       |
| `justification`   | `string`  | No       | A human-readable explanation of why the permission is being requested. |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'erc20-token-allowance',
  data: {
    tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
    allowanceAmount: parseUnits('50', 6),
    startTime: currentTime,
    justification: 'Permission to transfer up to 50 USDC in total',
  },
  isAdjustmentAllowed: true,
}
```

### ERC-20 periodic permission

Ensures a per-period limit for ERC-20 token transfers.
At the start of each new period, the allowance resets.

#### Parameters

| Name             | Type      | Required | Description                                                            |
| ---------------- | --------- | -------- | ---------------------------------------------------------------------- |
| `tokenAddress`   | `Address` | Yes      | The ERC-20 token contract address as a hex string.                     |
| `periodAmount`   | `bigint`  | Yes      | The maximum amount of tokens that can be transferred per period.       |
| `periodDuration` | `number`  | Yes      | The duration of each period in seconds.                                |
| `startTime`      | `number`  | No       | The start timestamp in seconds. The default is the current time.       |
| `justification`  | `string`  | No       | A human-readable explanation of why the permission is being requested. |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'erc20-token-periodic',
  data: {
    tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
    periodAmount: parseUnits('10', 6),
    periodDuration: 86400,
    justification: 'Permission to transfer 10 USDC every day',
  },
  isAdjustmentAllowed: true,
}
```

### ERC-20 stream permission

Ensures a linear streaming transfer limit for ERC-20 tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.

#### Parameters

| Name              | Type      | Required | Description                                                                   |
| ----------------- | --------- | -------- | ----------------------------------------------------------------------------- |
| `tokenAddress`    | `Address` | Yes      | The ERC-20 token contract address.                                            |
| `initialAmount`   | `bigint`  | No       | The initial amount that can be transferred at start time. The default is `0`. |
| `maxAmount`       | `bigint`  | No       | The maximum total amount that can be unlocked. The default is no limit.       |
| `amountPerSecond` | `bigint`  | Yes      | The rate at which tokens accrue per second.                                   |
| `startTime`       | `number`  | No       | The start timestamp in seconds. The default is the current time.              |
| `justification`   | `string`  | No       | A human-readable explanation of why the permission is being requested.        |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'erc20-token-stream',
  data: {
    tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
    amountPerSecond: parseUnits('0.1', 6),
    initialAmount: parseUnits('1', 6),
    maxAmount: parseUnits('2', 6),
    startTime: currentTime,
    justification: 'Permission to use 0.1 USDC per second',
  },
  isAdjustmentAllowed: true,
}
```

## Native token permissions

### Native token allowance permission

Ensures a fixed native token allowance.
Transfers are allowed until the total transferred amount reaches the allowance amount.

#### Parameters

| Name              | Type     | Required | Description                                                            |
| ----------------- | -------- | -------- | ---------------------------------------------------------------------- |
| `allowanceAmount` | `bigint` | Yes      | The maximum total amount of tokens that can be transferred.            |
| `startTime`       | `number` | No       | The start timestamp in seconds. The default is the current time.       |
| `justification`   | `string` | No       | A human-readable explanation of why the permission is being requested. |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'native-token-allowance',
  data: {
    allowanceAmount: parseEther('0.05'),
    startTime: currentTime,
    justification: 'Permission to transfer up to 0.05 ETH in total',
  },
  isAdjustmentAllowed: true,
}
```

### Native token periodic permission

Ensures a per-period limit for native token transfers.
At the start of each new period, the allowance resets.

#### Parameters

| Name             | Type     | Required | Description                                                            |
| ---------------- | -------- | -------- | ---------------------------------------------------------------------- |
| `periodAmount`   | `bigint` | Yes      | The maximum amount of tokens that can be transferred per period.       |
| `periodDuration` | `number` | Yes      | The duration of each period in seconds.                                |
| `startTime`      | `number` | No       | The start timestamp in seconds. The default is the current time.       |
| `justification`  | `string` | No       | A human-readable explanation of why the permission is being requested. |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'native-token-periodic',
  data: {
    periodAmount: parseEther('0.001'),
    periodDuration: 86400,
    startTime: currentTime,
    justification: 'Permission to use 0.001 ETH every day',
  },
  isAdjustmentAllowed: true,
}
```

### Native token stream permission

Ensures a linear streaming transfer limit for native tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.

#### Parameters

| Name              | Type     | Required | Description                                                                   |
| ----------------- | -------- | -------- | ----------------------------------------------------------------------------- |
| `initialAmount`   | `bigint` | No       | The initial amount that can be transferred at start time. The default is `0`. |
| `maxAmount`       | `bigint` | No       | The maximum total amount that can be unlocked. The default is no limit.       |
| `amountPerSecond` | `bigint` | Yes      | The rate at which tokens accrue per second.                                   |
| `startTime`       | `number` | No       | The start timestamp in seconds. The default is the current time.              |
| `justification`   | `string` | No       | A human-readable explanation of why the permission is being requested.        |

#### Example

```typescript

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const permission = {
  type: 'native-token-stream',
  data: {
    amountPerSecond: parseEther('0.0001'),
    initialAmount: parseEther('0.1'),
    maxAmount: parseEther('1'),
    startTime: currentTime,
    justification: 'Permission to use 0.0001 ETH per second',
  },
  isAdjustmentAllowed: true,
}
```

## Token approval revocation permission

Enables revoking an existing token approvals on behalf of the user.

#### Parameters

| Name                      | Type      | Required | Description                                                            |
| ------------------------- | --------- | -------- | ---------------------------------------------------------------------- |
| `erc20Approve`            | `boolean` | Yes      | Whether to allow revoking ERC-20 allowances.                           |
| `erc721Approve`           | `boolean` | Yes      | Whether to allow revoking ERC-721 per-token approvals.                 |
| `erc721SetApprovalForAll` | `boolean` | Yes      | Whether to allow revoking ERC-721 and ERC-1155 operator approvals.     |
| `permit2Approve`          | `boolean` | Yes      | Whether to allow revoking Permit2 approvals.                           |
| `permit2Lockdown`         | `boolean` | Yes      | Whether to allow locking down Permit2.                                 |
| `permit2InvalidateNonces` | `boolean` | Yes      | Whether to allow invalidating Permit2.                                 |
| `justification`           | `string`  | No       | A human-readable explanation of why the permission is being requested. |

#### Example

```typescript
const permission = {
  type: 'token-approval-revocation',
  data: {
    erc20Approve: true,
    erc721Approve: true,
    erc721SetApprovalForAll: true,
    permit2Approve: false,
    permit2Lockdown: false,
    permit2InvalidateNonces: false,
    justification: 'Permission to revoke ERC-20, ERC-721, and ERC-115 token approvals',
  },
  isAdjustmentAllowed: false,
}
```

---

## Advanced Permissions rules reference


When [executing on a MetaMask user's behalf](../../guides/advanced-permissions/execute-on-metamask-users-behalf.md), you can add the
following rule types for the supported permission types.

Use [`getSupportedExecutionPermissions`](./wallet-client.md#getsupportedexecutionpermissions) to
check which rule types are available for each permission type on each chain.

## Expiry

Sets an expiration timestamp for the permission.

### Parameters

| Name        | Type     | Required | Description                           |
| ----------- | -------- | -------- | ------------------------------------- |
| `timestamp` | `number` | Yes      | Expiration timestamp in Unix seconds. |

### Example

```ts
const currentTime = Math.floor(Date.now() / 1000)

const rules = [
  {
    type: 'expiry',
    data: {
      timestamp: currentTime + 604800,
    },
  },
]
```

## Redeemer

Restricts permission redemption to specific addresses.

### Parameters

| Name        | Type        | Required | Description                                          |
| ----------- | ----------- | -------- | ---------------------------------------------------- |
| `addresses` | `Address[]` | Yes      | Addresses that are allowed to redeem the permission. |

### Example

```ts
const rules = [
  {
    type: 'redeemer',
    data: {
      addresses: ['0x...', '0x...'],
    },
  },
]
```

## Payee

Restricts payments to specific receiver addresses.

### Parameters

| Name        | Type        | Required | Description                                       |
| ----------- | ----------- | -------- | ------------------------------------------------- |
| `addresses` | `Address[]` | Yes      | Addresses that are allowed as payment recipients. |

### Example

```ts
const rules = [
  {
    type: 'payee',
    data: {
      addresses: ['0x...'],
    },
  },
]
```

---

## Wallet Client actions reference


The following actions are related to the [Viem Wallet Client](https://viem.sh/docs/clients/wallet) used to [execute on a MetaMask user's behalf](../../guides/advanced-permissions/execute-on-metamask-users-behalf.md).

:::info
To use Advanced Permissions (ERC-7715) actions, the Viem Wallet Client must be extended with `erc7715ProviderActions`.
:::

## `requestExecutionPermissions`

Requests <GlossaryTerm term="Advanced Permissions" /> from the MetaMask extension account according to the [ERC-7715](https://eips.ethereum.org/EIPS/eip-7715) specification. Returns a [`RequestExecutionPermissionsReturnType`](../types.md#requestexecutionpermissionsreturntype).

### Parameters

| Name         | Type                        | Required | Description                                                                                                                                                                                      |
| ------------ | --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `chainId`    | `number`                    | Yes      | The chain ID on which the permission is being requested.                                                                                                                                         |
| `from`       | `Address`                   | No       | The wallet address to request the permission from.                                                                                                                                               |
| `expiry`     | `number`                    | Yes      | The timestamp (in seconds) by which the permission must expire.                                                                                                                                  |
| `permission` | `SupportedPermissionParams` | Yes      | The permission to request. The toolkit supports multiple [Advanced Permissions types](permissions.md). Set `isAdjustmentAllowed` to define whether the user can modify the requested permission. |
| `to`         | `Address`                   | Yes      | The account to which the permission will be assigned.                                                                                                                                            |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const currentTime = Math.floor(Date.now() / 1000)
const expiry = currentTime + 604800

const grantedPermissions = await walletClient.requestExecutionPermissions([
  {
    chainId: chain.id,
    expiry,
    // The requested permissions will be granted to the
    // session account.
    to: sessionAccount.address,
    permission: {
      type: 'erc20-token-periodic',
      data: {
        tokenAddress: '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238',
        periodAmount: parseUnits('10', 6),
        periodDuration: 86400,
        justification: 'Permission to transfer 10 USDC every day',
      },
      isAdjustmentAllowed: true,
    },
  },
])
```

</TabItem>
<TabItem value ="client.ts">

```ts

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## `getSupportedExecutionPermissions`

Returns the <GlossaryTerm term="Advanced Permissions" /> types that the wallet supports, according to the
[ERC-7715](https://eips.ethereum.org/EIPS/eip-7715)
specification. Use this to verify the available permission types and supported
chains before requesting permissions.

This action takes no parameters and returns a [`GetSupportedExecutionPermissionsResult`](../types.md#getsupportedexecutionpermissionsresult).

### Example

<Tabs defaultValue="example.ts">
<TabItem value="response.ts">

```ts
{
  "native-token-stream": {
    "chainIds": [1, 10],
    "ruleTypes": ["expiry"]
  },
  "erc20-token-periodic": {
    "chainIds": [1, 137],
    "ruleTypes": ["expiry"]
  },
// ...
}
```

</TabItem>
<TabItem value="example.ts">

```ts

const supportedPermissions = await walletClient.getSupportedExecutionPermissions()
```

</TabItem>
<TabItem value="client.ts">

```ts

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

## `getGrantedExecutionPermissions`

Returns all previously granted permissions for the connected wallet, according to the
[ERC-7715](https://eips.ethereum.org/EIPS/eip-7715) specification.

This action takes no parameters and returns a [`GetGrantedExecutionPermissionsResult`](../types.md#getgrantedexecutionpermissionsresult).

### Example

<Tabs defaultValue="example.ts">
<TabItem value="response.ts">

```ts
[
  {
    chainId: 84532,
    context: "0x0000...0000",
    delegationManager: "0xdb9B...7dB3",
    dependencies: [],
    from: "0x993f...7f31",
    permission: {
      type: "erc20-token-periodic",
      isAdjustmentAllowed: false,
      data: { ... },
    },
    rules: [
      { type: "expiry", data: { ... } },
    ],
    to: "0xAB57...7F1f",
  },
// ...
]
```

</TabItem>

<TabItem value="example.ts">

```ts

const grantedPermissions = await walletClient.getGrantedExecutionPermissions()
```

</TabItem>
<TabItem value="client.ts">

```ts

export const walletClient = createWalletClient({
  transport: custom(window.ethereum),
}).extend(erc7715ProviderActions())
```

</TabItem>
</Tabs>

---

## Caveat Enforcer Client reference


The following API methods are related to `CaveatEnforcerClient` used to [check the delegation state](../../guides/delegation/check-delegation-state.md).

## `createCaveatEnforcerClient`

Create a Viem Client extended with caveat enforcer actions. This client allows you to interact with the caveat enforcers of the
delegation, and read the required state.

### Parameters

| Name          | Type                                                               | Required | Description                                                                          |
| ------------- | ------------------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------ |
| `client`      | `Client`                                                           | Yes      | The Viem Client to interact with the caveat enforcer contracts and read their state. |
| `environment` | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | Environment to resolve the smart contracts for the current chain.                    |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

const caveatEnforcerClient = createCaveatEnforcerClient({
  environment,
  client,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

export const environment = getSmartAccountsEnvironment(chain.id)

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

## `getErc20PeriodTransferEnforcerAvailableAmount`

Returns the available amount from the ERC-20 period transfer enforcer for the current period.

### Parameters

| Name         | Type                                   | Required | Description                                                             |
| ------------ | -------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object for which you want to check the available amount. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

// Returns the available amount for current period.
const { availableAmount } = await caveatEnforcerClient.getErc20PeriodTransferEnforcerAvailableAmount({
  delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

const environment = getSmartAccountsEnvironment(chain.id)

// Since current time is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20PeriodTransfer,
    tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    periodAmount: parseUnits('10', 6),
    periodDuration: 86400,
    startDate,
  },
  to: 'DELEGATE_ADDRESS',
  from: 'DELEGATOR_ADDRESS',
  environment,
})
```

</TabItem>
</Tabs>

## `getErc20StreamingEnforcerAvailableAmount`

Returns the available amount from the ERC-20 streaming enforcer.

### Parameters

| Name         | Type                                   | Required | Description                                                             |
| ------------ | -------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object for which you want to check the available amount. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

// Returns the available amount
const { availableAmount } = await caveatEnforcerClient.getErc20StreamingEnforcerAvailableAmount({
  delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

const environment = getSmartAccountsEnvironment(chain.id)

// Since current time is in seconds, we need to convert milliseconds to seconds.
const startTime = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20Streaming,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    amountPerSecond: parseUnits('0.1', 6),
    initialAmount: parseUnits('1', 6),
    maxAmount: parseUnits('10', 6),
    startTime,
  },
  to: 'DELEGATE_ADDRESS',
  from: 'DELEGATOR_ADDRESS',
  environment,
})
```

</TabItem>
</Tabs>

## `getNativeTokenPeriodTransferEnforcerAvailableAmount`

Returns the available amount from the native token period enforcer for the current period.

### Parameters

| Name         | Type                                   | Required | Description                                                             |
| ------------ | -------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object for which you want to check the available amount. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

// Returns the available amount for current period.
const { availableAmount } = await caveatEnforcerClient.getNativeTokenPeriodTransferEnforcerAvailableAmount({
  delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

const environment = getSmartAccountsEnvironment(chain.id)

// Since current time is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenPeriodTransfer,
    periodAmount: parseEther('0.01'),
    periodDuration: 86400,
    startDate,
  },
  to: 'DELEGATE_ADDRESS',
  from: 'DELEGATOR_ADDRESS',
  environment,
})
```

</TabItem>
</Tabs>

## `getNativeTokenStreamingEnforcerAvailableAmount`

Returns the available amount from the native streaming enforcer.

### Parameters

| Name         | Type                                   | Required | Description                                                             |
| ------------ | -------------------------------------- | -------- | ----------------------------------------------------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object for which you want to check the available amount. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

// Returns the available amount
const { availableAmount } = await caveatEnforcerClient.getNativeTokenStreamingEnforcerAvailableAmount({
  delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

const environment = getSmartAccountsEnvironment(chain.id)

// Since current time is in seconds, we need to convert milliseconds to seconds.
const startTime = Math.floor(Date.now() / 1000)

export const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenStreaming,
    amountPerSecond: parseEther('0.001'),
    initialAmount: parseEther('0.01'),
    maxAmount: parseEther('0.1'),
    startTime,
  },
  to: 'DELEGATE_ADDRESS',
  from: 'DELEGATOR_ADDRESS',
  environment,
})
```

</TabItem>
</Tabs>

## `getMultiTokenPeriodEnforcerAvailableAmount`

Returns the available amount from the multi token period transfer enforcer for the current period. You'll need to
encode the arguments for the token index you want to check the available amount.

### Parameters

| Name         | Type                                   | Required | Description                                                                              |
| ------------ | -------------------------------------- | -------- | ---------------------------------------------------------------------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object with token index for which you want to check the available amount. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

// Encode the args for the multiTokenPeriod enforcer.
const args = encodePacked(['uint256'], [BigInt(0)]);

// Ensure the index is correct when working with multiple enforcers.
delegation.caveats[0].args = args

// Returns the available amount for the first token in the list.
const { availableAmount } = await caveatEnforcerClient.getMultiTokenPeriodEnforcerAvailableAmount({
  delegation,
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

  createDelegation,
  getSmartAccountsEnvironment,
  ROOT_AUTHORITY,
  CaveatType,
} from '@metamask/smart-accounts-kit'

const environment = getSmartAccountsEnvironment(chain.id)
const caveatBuilder = createCaveatBuilder(environment)

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

const tokenConfigs = [
  {
    token: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    // 1 token with 6 decimals.
    periodAmount: parseUnits('1', 6),
    // 1 day in seconds.
    periodDuration: 86400,
    startDate,
  },
  {
    // For native token use zeroAddress
    token: zeroAddress,
    // 0.01 ETH in wei.
    periodAmount: parseEther('0.01'),
    // 1 hour in seconds.
    periodDuration: 3600,
    startDate,
  },
]

const caveats = caveatBuilder.addCaveat(CaveatType.MultiTokenPeriod, tokenConfigs)

export const delegation: Delegation = {
  delegate: 'DELEGATE_ADDRESS',
  delegator: 'DELEGATOR_ADDRESS',
  authority: ROOT_AUTHORITY,
  caveats: caveats.build(),
  salt: '0x',
}
```

</TabItem>
</Tabs>

---

## Caveats reference


When [constraining a delegation scope](../../guides/delegation/use-delegation-scopes/constrain-scope.md), you can specify the following caveat types.

You can use either a string literal or the [`CaveatType`](../types.md#caveattype) enum to define the caveat type.

## `approvalRevocation`

Restricts the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> to revoking token approvals.
Set each flag to `true` to enable the corresponding revocation type.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ApprovalRevocationEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ApprovalRevocationEnforcer.sol)

### Parameters

| Name                      | Type      | Required | Description                                                        |
| ------------------------- | --------- | -------- | ------------------------------------------------------------------ |
| `erc20Approve`            | `boolean` | Yes      | Whether to allow revoking ERC-20 allowances.                       |
| `erc721Approve`           | `boolean` | Yes      | Whether to allow revoking ERC-721 per-token approvals.             |
| `erc721SetApprovalForAll` | `boolean` | Yes      | Whether to allow revoking ERC-721 and ERC-1155 operator approvals. |
| `permit2Approve`          | `boolean` | Yes      | Whether to allow revoking Permit2 approvals.                       |
| `permit2Lockdown`         | `boolean` | Yes      | Whether to allow locking down Permit2.                             |
| `permit2InvalidateNonces` | `boolean` | Yes      | Whether to allow invalidating Permit2.                             |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.ApprovalRevocation,
    erc20Approve: true,
    erc721Approve: false,
    erc721SetApprovalForAll: false,
    permit2Approve: false,
    permit2Lockdown: false,
    permit2InvalidateNonces: false,
  },
]
```

## `allowedCalldata`

Limits the calldata that is executed.

You can use this caveat to enforce function parameters.
We strongly recommend using this caveat to validate static types and not dynamic types.
You can validate dynamic types through a series of `allowedCalldata` terms, but this is tedious and error-prone.

<GlossaryTerm term="Caveat enforcer" /> contract: [`AllowedCalldataEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/AllowedCalldataEnforcer.sol)

### Parameters

| Name         | Type     | Required | Description                                                                                                     |
| ------------ | -------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `startIndex` | `number` | Yes      | The index in the calldata byte array (including the 4-byte method selector) where the expected calldata starts. |
| `value`      | `Hex`    | Yes      | The expected calldata that must match at the specified index.                                                   |

### Example

```typescript

const value = encodeAbiParameters(
  [{ type: 'string' }, { type: 'uint256' }],
  ['Hello Gator', 12345n]
)

const caveats = [
  {
    type: CaveatType.AllowedCalldata,
    startIndex: 4,
    value,
  },
]
```

:::note
This example uses Viem's [`encodeAbiParameters`](https://viem.sh/docs/abi/encodeAbiParameters) utility to encode the parameters as ABI-encoded hex strings.
:::

## `allowedMethods`

Limits what methods the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can call.

<GlossaryTerm term="Caveat enforcer" /> contract: [`AllowedMethodsEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/AllowedMethodsEnforcer.sol)

### Parameters

| Name        | Type               | Required | Description                                                                                                                                                     |
| ----------- | ------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `selectors` | `MethodSelector[]` | Yes      | The list of method selectors that the delegate is allowed to call. The selector value can be 4-byte hex string, ABI function signature, or ABI function object. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.AllowedMethods,
    selectors: [
      // 4-byte Hex string.
      '0xa9059cbb',
      // ABI function signature.
      'transfer(address,uint256)',
      // ABI function object.
      {
        name: 'transfer',
        type: 'function',
        inputs: [
          { name: 'recipient', type: 'address' },
          { name: 'amount', type: 'uint256' },
        ],
        outputs: [],
        stateMutability: 'nonpayable',
      },
    ],
  },
]
```

:::note
This example adds the `transfer` function to the allowed methods in three different ways - as the 4-byte function selector, the ABI function signature, and the `ABIFunction` object.
:::

## `allowedTargets`

Limits what addresses the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can call.

<GlossaryTerm term="Caveat enforcer" /> contract: [`AllowedTargetsEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/AllowedTargetsEnforcer.sol)

### Parameters

| Name      | Type        | Required | Description                                                 |
| --------- | ----------- | -------- | ----------------------------------------------------------- |
| `targets` | `Address[]` | Yes      | The list of addresses that the delegate is allowed to call. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.AllowedTargets,
    targets: [
      '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
      '0xB2880E3862f1024cAC05E66095148C0a9251718b',
    ],
  },
]
```

## `argsEqualityCheck`

Ensures that the `args` provided when redeeming the delegation are equal to the terms specified on the caveat.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ArgsEqualityCheckEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ArgsEqualityCheckEnforcer.sol)

### Parameters

| Name   | Type  | Required | Description                                                                   |
| ------ | ----- | -------- | ----------------------------------------------------------------------------- |
| `args` | `Hex` | Yes      | The expected arguments that must match exactly when redeeming the delegation. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.ArgsEqualityCheck,
    args: '0xf2bef872456302645b7c0bb59dcd96ffe6d4a844f311ebf95e7cf439c9393de2',
  },
]
```

## `blockNumber`

Specifies a range of blocks through which the delegation will be valid.

<GlossaryTerm term="Caveat enforcer" /> contract: [`BlockNumberEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/BlockNumberEnforcer.sol)

### Parameters

| Name              | Type     | Required | Description                                                                                             |
| ----------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `afterThreshold`  | `bigint` | Yes      | The block number after which the delegation is valid. Set the value to `0n` to disable this threshold.  |
| `beforeThreshold` | `bigint` | Yes      | The block number before which the delegation is valid. Set the value to `0n` to disable this threshold. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.BlockNumber,
    afterThreshold: 19426587n,
    beforeThreshold: 0n,
  },
]
```

## `deployed`

Ensures a contract is deployed, and if not, deploys the contract.

<GlossaryTerm term="Caveat enforcer" /> contract: [`DeployedEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/DeployedEnforcer.sol)

### Parameters

| Name              | Type      | Required | Description                          |
| ----------------- | --------- | -------- | ------------------------------------ |
| `contractAddress` | `Address` | Yes      | The contract address.                |
| `salt`            | `Hex`     | Yes      | The salt to use with the deployment. |
| `bytecode`        | `Hex`     | Yes      | The bytecode of the contract.        |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Deployed,
    contractAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    salt: '0x0e3e8e2381fde0e8515ed47ec9caec8ba2bc12603bc2b36133fa3e3fa4d88587',
    bytecode: '0x...', // The deploy bytecode for the contract at 0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92
  },
]
```

## `erc1155BalanceChange`

Ensures that the recipient's ERC-1155 token balance has changed within the allowed bounds
(either increased by a minimum or decreased by a maximum specified amount).

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC1155BalanceChangeEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC1155BalanceChangeEnforcer.sol)

### Parameters

| Name           | Type                | Required | Description                                                                                                                                                                                           |
| -------------- | ------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address`           | Yes      | The ERC-1155 token contract address.                                                                                                                                                                  |
| `recipient`    | `Address`           | Yes      | The address on which the checks will be applied.                                                                                                                                                      |
| `tokenId`      | `bigint`            | Yes      | The ID of the ERC-1155 token.                                                                                                                                                                         |
| `balance`      | `bigint`            | Yes      | The amount by which the balance must be changed.                                                                                                                                                      |
| `changeType`   | `BalanceChangeType` | Yes      | The balance change type for the ERC-1155 token. Specifies whether the balance should have increased or decreased. Valid parameters are `BalanceChangeType.Increase` and `BalanceChangeType.Decrease`. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Erc1155BalanceChange,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    recipient: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    tokenId: 1n,
    balance: 1000000n,
    changeType: BalanceChangeType.Increase,
  },
]
```

## `erc20BalanceChange`

Ensures that the recipient's ERC-20 token balance has changed within the allowed bounds
(either increased by a minimum or decreased by a maximum specified amount).

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC20BalanceChangeEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC20BalanceChangeEnforcer.sol)

### Parameters

| Name           | Type                | Required | Description                                                                                                                                                                                         |
| -------------- | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address`           | Yes      | The ERC-20 token contract address.                                                                                                                                                                  |
| `recipient`    | `Address`           | Yes      | The address on which the checks will be applied.                                                                                                                                                    |
| `balance`      | `bigint`            | Yes      | The amount by which the balance must be changed.                                                                                                                                                    |
| `changeType`   | `BalanceChangeType` | Yes      | The balance change type for the ERC-20 token. Specifies whether the balance should have increased or decreased. Valid parameters are `BalanceChangeType.Increase` and `BalanceChangeType.Decrease`. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Erc20BalanceChange,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    recipient: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    balance: 1000000n,
    changeType: BalanceChangeType.Increase,
  },
]
```

## `erc20PeriodTransfer`

Ensures that ERC-20 token transfers remain within a predefined limit during a
specified time window. At the start of each new period, the allowed transfer
amount resets. Any unused transfer allowance from the previous period does not
carry over and is forfeited.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC20PeriodTransferEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC20PeriodTransferEnforcer.sol)

### Parameters

| Name             | Type      | Required | Description                                                      |
| ---------------- | --------- | -------- | ---------------------------------------------------------------- |
| `tokenAddress`   | `Address` | Yes      | The ERC-20 token contract address as a hex string.               |
| `periodAmount`   | `bigint`  | Yes      | The maximum amount of tokens that can be transferred per period. |
| `periodDuration` | `number`  | Yes      | The duration of each period in seconds.                          |
| `startDate`      | `number`  | Yes      | The timestamp when the first period begins in seconds.           |

### Example

```typescript

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

const caveats = [
  {
    type: CaveatType.Erc20PeriodTransfer,
    // Address of the ERC-20 token.
    tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    // 1 ERC-20 token - 18 decimals, in wei.
    periodAmount: 1000000000000000000n,
    // 1 day in seconds.
    periodDuration: 86400,
    startDate,
  },
]
```

## `erc20Streaming`

Enforces a linear streaming transfer limit for ERC-20 tokens. Block token access until the specified start timestamp. At the start timestamp, immediately release the specified initial amount. Afterward, accrue tokens linearly at the specified rate, up to the specified maximum.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC20StreamingEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC20StreamingEnforcer.sol)

### Parameters

| Name              | Type      | Required | Description                                               |
| ----------------- | --------- | -------- | --------------------------------------------------------- |
| `tokenAddress`    | `Address` | Yes      | The ERC-20 token contract address.                        |
| `initialAmount`   | `bigint`  | Yes      | The initial amount that can be transferred at start time. |
| `maxAmount`       | `bigint`  | Yes      | The maximum total amount that can be unlocked.            |
| `amountPerSecond` | `bigint`  | Yes      | The rate at which tokens accrue per second.               |
| `startTime`       | `number`  | Yes      | The start timestamp in seconds.                           |

### Example

```typescript

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000);

const caveats = [{
  type: CaveatType.Erc20Streaming,
  // Address of the ERC-20 token.
  tokenAddress: "0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92",
  // 1 ERC-20 token - 18 decimals, in wei.
  initialAmount: 1000000000000000000n,
  // 10 ERC-20 token - 18 decimals, in wei.
  maxAmount: 10000000000000000000n
  // 0.00001 ERC-20 token - 18 decimals, in wei.
  amountPerSecond: 10000000000000n,
  startDate,
}];
```

## `erc20TransferAmount`

Limits the transfer of ERC-20 tokens.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC20TransferAmountEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC20TransferAmountEnforcer.sol)

### Parameters

| Name           | Type      | Required | Description                                                       |
| -------------- | --------- | -------- | ----------------------------------------------------------------- |
| `tokenAddress` | `Address` | Yes      | The ERC-20 token contract address.                                |
| `maxAmount`    | `bigint`  | Yes      | The maximum amount of tokens that can be transferred by delegate. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // 1 ERC-20 token - 18 decimals, in wei.
    maxAmount: 1000000000000000000n,
  },
]
```

## `erc721BalanceChange`

Ensures that the recipient's ERC-721 token balance has changed within the allowed bounds (either increased by a minimum or decreased by a maximum specified amount).

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC721BalanceChangeEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC721BalanceChangeEnforcer.sol)

### Parameters

| Name           | Type                | Required | Description                                                                                                                                                                                          |
| -------------- | ------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address`           | Yes      | The ERC-721 token contract address.                                                                                                                                                                  |
| `recipient`    | `Address`           | Yes      | The address on which the checks will be applied.                                                                                                                                                     |
| `balance`      | `bigint`            | Yes      | The amount by which the balance must be changed.                                                                                                                                                     |
| `changeType`   | `BalanceChangeType` | Yes      | The balance change type for the ERC-721 token. Specifies whether the balance should have increased or decreased. Valid parameters are `BalanceChangeType.Increase` and `BalanceChangeType.Decrease`. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Erc721BalanceChange,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    recipient: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    balance: 1000000n,
    changeType: BalanceChangeType.Increase,
  },
]
```

## `erc721Transfer`

Restricts the execution to only allow ERC-721 token transfers, specifically the `transferFrom(from, to, tokenId)` function, for a specified token ID and contract.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ERC721TransferEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ERC721TransferEnforcer.sol)

### Parameters

| Name           | Type      | Required | Description                                                                                                           |
| -------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address` | Yes      | The ERC-721 token contract address.                                                                                   |
| `tokenId`      | `bigint`  | Yes      | The ID of the ERC-721 token that can be transferred by <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Erc721Transfer,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    tokenId: 1n,
  },
]
```

## `exactCalldata`

Verifies that the transaction calldata matches the expected calldata. For batch transactions,
see [`exactCalldataBatch`](#exactcalldatabatch).

<GlossaryTerm term="Caveat enforcer" /> contract: [`ExactCalldataEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ExactCalldataEnforcer.sol)

### Parameters

| Name       | Type  | Required | Description                                                                                             |
| ---------- | ----- | -------- | ------------------------------------------------------------------------------------------------------- |
| `calldata` | `Hex` | Yes      | The calldata that the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is allowed to call. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.ExactCalldata,
    calldata: '0x1234567890abcdef',
  },
]
```

## `exactCalldataBatch`

Verifies that the provided batch execution calldata matches
the expected calldata for each individual execution in the batch.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ExactCalldataBatchEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ExactCalldataBatchEnforcer.sol)

### Parameters

| Name         | Type                | Required | Description                                                                                                                       |
| ------------ | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `executions` | `ExecutionStruct[]` | Yes      | The list of executions that must be matched exactly in the batch. Each execution specifies a target address, value, and calldata. |

### Example

```typescript

const executions = [
  {
    target: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    value: 1000000000000000000n, // 1 ETH
    callData: '0x',
  },
  {
    target: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    value: 0n,
    callData: '0x',
  },
]

const caveats = [
  {
    type: CaveatType.ExactCalldataBatch,
    executions,
  },
]
```

## `exactExecution`

Verifies that the provided execution matches the expected execution. For batch transactions,
see [`exactExecutionBatch`](#exactexecutionbatch).

<GlossaryTerm term="Caveat enforcer" /> contract: [`ExactExecutionEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ExactExecutionEnforcer.sol)

### Parameters

| Name        | Type              | Required | Description                                                                                    |
| ----------- | ----------------- | -------- | ---------------------------------------------------------------------------------------------- |
| `execution` | `ExecutionStruct` | Yes      | The execution that must be matched exactly. Specifies the target address, value, and calldata. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.ExactExecution,
    target: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    value: 1000000000000000000n,
    callData: '0x',
  },
]
```

## `exactExecutionBatch`

Verifies that each execution in the batch matches the expected
execution parameters, including target, value, and calldata.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ExactExecutionBatchEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ExactExecutionBatchEnforcer.sol)

### Parameters

| Name         | Type                | Required | Description                                                                                                                       |
| ------------ | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `executions` | `ExecutionStruct[]` | Yes      | The list of executions that must be matched exactly in the batch. Each execution specifies a target address, value, and calldata. |

### Example

```typescript

const executions = [
  {
    target: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    value: 1000000000000000000n, // 1 ETH
    callData: '0x',
  },
  {
    target: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    value: 0n,
    callData: '0x',
  },
]

const caveats = [
  {
    type: CaveatType.ExactExecutionBatch,
    executions,
  },
]
```

## `id`

Specifies an ID for multiple delegations. Once one of them is redeemed, the other delegations with the same ID are revoked.

<GlossaryTerm term="Caveat enforcer" /> contract: [`IdEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/IdEnforcer.sol)

### Parameters

| Name | Type     | Required | Description |
| ---- | -------- | -------- | ----------- | -------------------------------------------------------------------------------- |
| `id` | `bigint` | `number` | Yes         | An ID for the delegation. Only one delegation may be redeemed with any given ID. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Id,
    id: 123456,
  },
]
```

## `limitedCalls`

Limits the number of times the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can perform executions on the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>'s behalf.

<GlossaryTerm term="Caveat enforcer" /> contract: [`LimitedCallsEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/LimitedCallsEnforcer.sol)

### Parameters

| Name    | Type     | Required | Description                                                  |
| ------- | -------- | -------- | ------------------------------------------------------------ |
| `limit` | `number` | Yes      | The maximum number of times this delegation may be redeemed. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.LimitedCalls,
    limit: 1,
  },
]
```

## `multiTokenPeriod`

Ensures that token transfers for multiple tokens stay within the specified limits for the defined periods.
At the start of each new period, the allowed transfer amount for each token resets. Any unused transfer allowance from the previous period expires and does not carry over.

When redeeming the delegation, the index of the relevant token configuration must be specified
as the `args` of this caveat (encoded as `uint256` hex value).

<GlossaryTerm term="Caveat enforcer" /> contract: [`MultiTokenPeriodEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/MultiTokenPeriodEnforcer.sol)

### Parameters

The list of `TokenPeriodConfig` objects, where each object contains:

| Name             | Type      | Required | Description                                                      |
| ---------------- | --------- | -------- | ---------------------------------------------------------------- |
| `token`          | `Address` | Yes      | The ERC-20 token contract address as a hex string.               |
| `periodAmount`   | `bigint`  | Yes      | The maximum amount of tokens that can be transferred per period. |
| `periodDuration` | `number`  | Yes      | The duration of each period in seconds.                          |
| `startDate`      | `number`  | Yes      | The timestamp when the first period begins in seconds.           |

### Example

```typescript

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

const tokenPeriodConfigs = [
  {
    token: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    // 1 token with 18 decimals.
    periodAmount: 1000000000000000000n,
    // 1 day in seconds.
    periodDuration: 86400,
    startDate,
  },
  {
    // For native token use zeroAddress
    token: zeroAddress,
    // 0.01 ETH in wei.
    periodAmount: 10000000000000000n,
    // 1 hour in seconds.
    periodDuration: 3600,
    startDate,
  },
]

const caveats = [
  {
    type: CaveatType.MultiTokenPeriod,
    tokenPeriodConfigs,
  },
]
```

## `nativeBalanceChange`

Ensures that the recipient's native token balance has changed within the allowed bounds (either increased by a minimum or decreased by a maximum specified amount).

<GlossaryTerm term="Caveat enforcer" /> contract: [`NativeBalanceChangeEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NativeBalanceChangeEnforcer.sol)

### Parameters

| Name         | Type                | Required | Description                                                                                                                                                                                         |
| ------------ | ------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recipient`  | `Address`           | Yes      | The address on which the checks will be applied.                                                                                                                                                    |
| `balance`    | `bigint`            | Yes      | The amount by which the balance must be changed.                                                                                                                                                    |
| `changeType` | `BalanceChangeType` | Yes      | The balance change type for the native token. Specifies whether the balance should have increased or decreased. Valid parameters are `BalanceChangeType.Increase` and `BalanceChangeType.Decrease`. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.NativeBalanceChange,
    recipient: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    balance: 1000000n,
    changeType: BalanceChangeType.Increase,
  },
]
```

## `nativeTokenPayment`

Enforces payment in native token (for example, ETH) for the right to use the delegation.
A permissions context allowing payment must be provided as the `args` when
redeeming the delegation.

<GlossaryTerm term="Caveat enforcer" /> contract: [`NativeTokenPaymentEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NativeTokenPaymentEnforcer.sol)

### Parameters

| Name        | Type      | Required | Description                                     |
| ----------- | --------- | -------- | ----------------------------------------------- |
| `recipient` | `Address` | Yes      | The recipient address who receives the payment. |
| `amount`    | `bigint`  | Yes      | The amount that must be paid.                   |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.NativeTokenPayment,
    recipient: '0x3fF528De37cd95b67845C1c55303e7685c72F319',
    amount: 1000000n,
  },
]
```

## `nativeTokenPeriodTransfer`

Ensures that native token transfers remain within a predefined limit during a
specified time window. At the start of each new period, the allowed transfer
amount resets. Any unused transfer allowance from the previous period does not
carry over and is forfeited.

<GlossaryTerm term="Caveat enforcer" /> contract: [`NativeTokenPeriodTransferEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NativeTokenPeriodTransferEnforcer.sol)

### Parameters

| Name             | Type     | Required | Description                                                      |
| ---------------- | -------- | -------- | ---------------------------------------------------------------- |
| `periodAmount`   | `bigint` | Yes      | The maximum amount of tokens that can be transferred per period. |
| `periodDuration` | `number` | Yes      | The duration of each period in seconds.                          |
| `startDate`      | `number` | Yes      | The timestamp when the first period begins in seconds.           |

### Example

```typescript

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000)

const caveats = [
  {
    type: CaveatType.NativeTokenPeriodTransfer,
    // 1 ETH in wei.
    periodAmount: 1000000000000000000n,
    // 1 day in seconds.
    periodDuration: 86400,
    startDate,
  },
]
```

## `nativeTokenStreaming`

Enforces a linear streaming limit for native tokens (for example, ETH). Nothing is available before the specified start timestamp. At the start timestamp, the specified initial amount becomes immediately available. After that, tokens accrue linearly at the specified rate, capped by the specified maximum.

<GlossaryTerm term="Caveat enforcer" /> contract: [`NativeTokenStreamingEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NativeTokenStreamingEnforcer.sol)

### Parameters

| Name              | Type     | Required | Description                                               |
| ----------------- | -------- | -------- | --------------------------------------------------------- |
| `initialAmount`   | `bigint` | Yes      | The initial amount that can be transferred at start time. |
| `maxAmount`       | `bigint` | Yes      | The maximum total amount that can be unlocked.            |
| `amountPerSecond` | `bigint` | Yes      | The rate at which tokens accrue per second.               |
| `startTime`       | `number` | Yes      | The start timestamp in seconds.                           |

### Example

```typescript

// Current time as start date.
// Since startDate is in seconds, we need to convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000);

const caveats = [{
  type: CaveatType.NativeTokenStreaming,
  // 0.01 ETH in wei.
  initialAmount: 10000000000000000,
  // 0.5 ETH in wei.
  maxAmount: 500000000000000000n
  // 0.00001 ETH in wei.
  amountPerSecond: 10000000000000n,
  startDate,
}];
```

## `nativeTokenTransferAmount`

Enforces an allowance of native currency (for example, ETH).

<GlossaryTerm term="Caveat enforcer" /> contract: [`NativeTokenTransferAmountEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NativeTokenTransferAmountEnforcer.sol)

### Parameters

| Name        | Type     | Required | Description                                                                                                                |
| ----------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `maxAmount` | `bigint` | Yes      | The maximum amount of tokens that can be transferred by the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.NativeTokenTransferAmount,
    // 0.00001 ETH in wei.
    maxAmount: 10000000000000000n,
  },
]
```

## `nonce`

Adds a nonce to a delegation, and revokes previous delegations by incrementing the current nonce by calling `incrementNonce(address _delegationManager)`.

<GlossaryTerm term="Caveat enforcer" /> contract: [`NonceEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/NonceEnforcer.sol)

### Parameters

| Name    | Type  | Required | Description                                        |
| ------- | ----- | -------- | -------------------------------------------------- |
| `nonce` | `Hex` | Yes      | The nonce to allow bulk revocation of delegations. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Nonce,
    nonce: '0x1',
  },
]
```

## `ownershipTransfer`

Restricts the execution to only allow ownership transfers, specifically the `transferOwnership(address _newOwner)` function, for a specified contract.

<GlossaryTerm term="Caveat enforcer" /> contract: [`OwnershipTransferEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/OwnershipTransferEnforcer.sol)

### Parameters

| Name              | Type      | Required | Description                                                            |
| ----------------- | --------- | -------- | ---------------------------------------------------------------------- |
| `contractAddress` | `Address` | Yes      | The target contract address for which ownership transfers are allowed. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.OwnershipTransfer,
    contractAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
  },
]
```

## `redeemer`

Limits the addresses that can redeem the delegation.
This caveat is designed to restrict smart contracts or EOAs lacking delegation support,
and can be placed anywhere in the delegation chain to restrict the redeemer.

:::note
Delegator accounts with delegation functionalities can bypass these restrictions by delegating to
other addresses.
For example, Alice makes Bob the redeemer.
This condition is enforced, but if Bob is a delegator he can create a separate delegation to Carol
that allows her to redeem Alice's delegation through Bob.
:::

<GlossaryTerm term="Caveat enforcer" /> contract: [`RedeemerEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/RedeemerEnforcer.sol)

### Parameters

| Name        | Type        | Required | Description                                                      |
| ----------- | ----------- | -------- | ---------------------------------------------------------------- |
| `redeemers` | `Address[]` | Yes      | The list of addresses that are allowed to redeem the delegation. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.Redeemer,
    redeemers: [
      '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
      '0x6be97c23596ECed7170fdFb28e8dA1Ca5cdc54C5',
    ],
  },
]
```

## `specificActionERC20TransferBatch`

Ensures validation of a batch consisting of exactly two transactions:

1. The first transaction must call a specific target contract with predefined calldata.
2. The second transaction must be an ERC-20 token transfer that matches specified
   parameters, including the ERC-20 token contract address, amount, and recipient.

<GlossaryTerm term="Caveat enforcer" /> contract: [`SpecificActionERC20TransferBatchEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/SpecificActionERC20TransferBatchEnforcer.sol)

### Parameters

| Name           | Type      | Required | Description                                   |
| -------------- | --------- | -------- | --------------------------------------------- |
| `tokenAddress` | `Address` | Yes      | The ERC-20 token contract address.            |
| `recipient`    | `Address` | Yes      | The address that will receive the tokens.     |
| `amount`       | `bigint`  | Yes      | The amount of tokens to transfer.             |
| `target`       | `Address` | Yes      | The target address for the first transaction. |
| `calldata`     | `Hex`     | Yes      | The `calldata` for the first transaction.     |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.SpecificActionERC20TransferBatch,
    tokenAddress: '0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da',
    recipient: '0x027aeAFF3E5C33c4018FDD302c20a1B83aDCD96C',
    // 1 ERC-20 token - 18 decimals, in wei
    amount: 1000000000000000000n,
    target: '0xb49830091403f1Aa990859832767B39c25a8006B',
    calldata: '0x1234567890abcdef',
  },
]
```

## `timestamp`

Specifies a range of timestamps through which the delegation will be valid.

<GlossaryTerm term="Caveat enforcer" /> contract: [`TimestampEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/TimestampEnforcer.sol)

### Parameters

| Name              | Type     | Required | Description                                                                                                    |
| ----------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------------- |
| `afterThreshold`  | `number` | Yes      | The timestamp after which the delegation is valid in seconds. Set the value to `0` to disable this threshold.  |
| `beforeThreshold` | `number` | Yes      | The timestamp before which the delegation is valid in seconds. Set the value to `0` to disable this threshold. |

### Example

```typescript

// We need to convert milliseconds to seconds.
const currentTime = Math.floor(Date.now() / 1000)
// 1 hour after current time.
const afterThreshold = currentTime + 3600
// 1 day after afterThreshold
const beforeThreshold = afterThreshold + 86400

const caveats = [
  {
    type: CaveatType.Timestamp,
    afterThreshold,
    beforeThreshold,
  },
]
```

## `valueLte`

Limits the value of native tokens that the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can spend.

<GlossaryTerm term="Caveat enforcer" /> contract: [`ValueLteEnforcer.sol`](https://github.com/MetaMask/delegation-framework/blob/main/src/enforcers/ValueLteEnforcer.sol)

### Parameters

| Name       | Type     | Required | Description                                                             |
| ---------- | -------- | -------- | ----------------------------------------------------------------------- |
| `maxValue` | `bigint` | Yes      | The maximum value that may be specified when redeeming this delegation. |

### Example

```typescript

const caveats = [
  {
    type: CaveatType.ValueLte,
    // 0.01 ETH in wei.
    maxValue: 10000000000000000n,
  },
]
```

---

## Delegation scopes(Delegation)


When [creating a delegation](../../guides/delegation/execute-on-smart-accounts-behalf.md), you can configure the following scopes to define the delegation's initial authority.
Learn [how to use delegation scopes](../../guides/delegation/use-delegation-scopes/index.md).

## Spending limit scopes

### ERC-20 periodic scope

Ensures a per-period limit for ERC-20 token transfers.
At the start of each new period, the allowance resets.

#### Parameters

| Name             | Type      | Required | Description                                                      |
| ---------------- | --------- | -------- | ---------------------------------------------------------------- |
| `tokenAddress`   | `Address` | Yes      | The ERC-20 token contract address as a hex string.               |
| `periodAmount`   | `bigint`  | Yes      | The maximum amount of tokens that can be transferred per period. |
| `periodDuration` | `number`  | Yes      | The duration of each period in seconds.                          |
| `startDate`      | `number`  | Yes      | The timestamp when the first period begins in seconds.           |

#### Example

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000);

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20PeriodTransfer,
    tokenAddress: "0xb4aE654Aca577781Ca1c5DE8FbE60c2F423f37da",
    // 10 ERC-20 token with 6 decimals
    periodAmount: parseUnits("10", 6),
    periodDuration: 86400,
    startDate,
  },
  // Address that is granting the delegation
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### ERC-20 streaming scope

Ensures a linear streaming transfer limit for ERC-20 tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.

#### Parameters

| Name              | Type      | Required | Description                                               |
| ----------------- | --------- | -------- | --------------------------------------------------------- |
| `tokenAddress`    | `Address` | Yes      | The ERC-20 token contract address.                        |
| `initialAmount`   | `bigint`  | Yes      | The initial amount that can be transferred at start time. |
| `maxAmount`       | `bigint`  | Yes      | The maximum total amount that can be unlocked.            |
| `amountPerSecond` | `bigint`  | Yes      | The rate at which tokens accrue per second.               |
| `startTime`       | `number`  | Yes      | The start timestamp in seconds.                           |

#### Example

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const startTime = Math.floor(Date.now() / 1000);

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20Streaming,
    tokenAddress: "0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92",
    // 0.1 ERC-20 token with 6 decimals
    amountPerSecond: parseUnits("0.1", 6),
    // 1 ERC-20 token with 6 decimals
    initialAmount: parseUnits("1", 6),
    // 10 ERC-20 token with 6 decimals
    maxAmount: parseUnits("10", 6),
    startTime,
  },
  // Address that is granting the delegation
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### ERC-20 transfer scope

Ensures that ERC-20 token transfers are limited to a predefined maximum amount.
This scope is useful for setting simple, fixed transfer limits without any time-based or streaming conditions.

#### Parameters

| Name           | Type      | Required | Description                                                                                                            |
| -------------- | --------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address` | Yes      | The ERC-20 token contract address.                                                                                     |
| `maxAmount`    | `bigint`  | Yes      | The maximum amount of tokens that can be transferred by <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>. |

#### Example

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: "0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92",
    // 1 ERC-20 token with 6 decimals
    maxAmount: parseUnits("1", 6),
  },
  // Address that is granting the delegation
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### ERC-721 scope

Limits the delegation to ERC-721 token (NFT) transfers only.

#### Parameters

| Name           | Type      | Required | Description                                                                                                           |
| -------------- | --------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
| `tokenAddress` | `Address` | Yes      | The ERC-721 token contract address.                                                                                   |
| `tokenId`      | `bigint`  | Yes      | The ID of the ERC-721 token that can be transferred by <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>. |

#### Example

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc721Transfer,
    tokenAddress: "0x3fF528De37cd95b67845C1c55303e7685c72F319",
    tokenId: 1n,
  },
  // Address that is granting the delegation
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### Native token periodic scope

Ensures a per-period limit for native token transfers.
At the start of each new period, the allowance resets.

#### Parameters

| Name              | Type                                                                           | Required | Description                                                                                                                                                                                                                                                                                                                                                                                          |
| ----------------- | ------------------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `periodAmount`    | `bigint`                                                                       | Yes      | The maximum amount of tokens that can be transferred per period.                                                                                                                                                                                                                                                                                                                                     |
| `periodDuration`  | `number`                                                                       | Yes      | The duration of each period in seconds.                                                                                                                                                                                                                                                                                                                                                              |
| `startDate`       | `number`                                                                       | Yes      | The timestamp when the first period begins in seconds.                                                                                                                                                                                                                                                                                                                                               |
| `allowedCalldata` | [`AllowedCalldataBuilderConfig`](../types.md#allowedcalldatabuilderconfig)`[]` | No       | The list of calldata the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is allowed to call. It doesn't support multiple selectors. Each entry in the list represents a portion of calldata corresponding to the same function signature. You can include or exclude specific parameters to define what parts of the calldata are valid. Cannot be used together with `exactCalldata`. |
| `exactCalldata`   | [`ExactCalldataBuilderConfig`](../types.md#exactcalldatabuilderconfig)         | No       | The calldata the delegate is allowed to call. The default is `0x` to disallow ERC-20 and ERC-721 token transfers. Cannot be used together with `allowedCalldata`.                                                                                                                                                                                                                                    |

#### Example

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const startDate = Math.floor(Date.now() / 1000);

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenPeriodTransfer,
    periodAmount: parseEther("0.01"),
    periodDuration: 86400,
    startDate,
  },
  // Address that is granting the delegation.
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted.
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### Native token streaming scope

Ensures a linear streaming transfer limit for native tokens.
Token transfers are blocked until the defined start timestamp.
At the start, a specified initial amount is released, after which tokens accrue linearly at the configured rate, up to the maximum allowed amount.

#### Parameters

| Name              | Type                                                                           | Required | Description                                                                                                                                                                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `initialAmount`   | `bigint`                                                                       | Yes      | The initial amount that can be transferred at start time.                                                                                                                                                                                                                                                                                       |
| `maxAmount`       | `bigint`                                                                       | Yes      | The maximum total amount that can be unlocked.                                                                                                                                                                                                                                                                                                  |
| `amountPerSecond` | `bigint`                                                                       | Yes      | The rate at which tokens accrue per second.                                                                                                                                                                                                                                                                                                     |
| `startTime`       | `number`                                                                       | Yes      | The start timestamp in seconds.                                                                                                                                                                                                                                                                                                                 |
| `allowedCalldata` | [`AllowedCalldataBuilderConfig`](../types.md#allowedcalldatabuilderconfig)`[]` | No       | The list of calldata the delegate is allowed to call. It doesn't support multiple selectors. Each entry in the list represents a portion of calldata corresponding to the same function signature. You can include or exclude specific parameters to define what parts of the calldata are valid. Cannot be used together with `exactCalldata`. |
| `exactCalldata`   | [`ExactCalldataBuilderConfig`](../types.md#exactcalldatabuilderconfig)         | No       | The calldata the delegate is allowed to call. The default is `0x` to disallow ERC-20 and ERC-721 token transfers. Cannot be used together with `allowedCalldata`.                                                                                                                                                                               |

#### Example

```typescript

// Since current time is in seconds, convert milliseconds to seconds.
const startTime = Math.floor(Date.now() / 1000);

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenStreaming,
    amountPerSecond: parseEther("0.0001"),
    initialAmount: parseEther("0.01"),
    maxAmount: parseEther("0.1"),
    startTime,
  },
  // Address that is granting the delegation.
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted.
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

### Native token transfer scope

Ensures that native token transfers are limited to a predefined maximum amount.
This scope is useful for setting simple, fixed transfer limits without any time based or streaming conditions.

#### Parameters

| Name              | Type                                                                           | Required | Description                                                                                                                                                                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `maxAmount`       | `bigint`                                                                       | Yes      | The maximum amount of tokens that can be transferred by <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>.                                                                                                                                                                                                                          |
| `allowedCalldata` | [`AllowedCalldataBuilderConfig`](../types.md#allowedcalldatabuilderconfig)`[]` | No       | The list of calldata the delegate is allowed to call. It doesn't support multiple selectors. Each entry in the list represents a portion of calldata corresponding to the same function signature. You can include or exclude specific parameters to define what parts of the calldata are valid. Cannot be used together with `exactCalldata`. |
| `exactCalldata`   | [`ExactCalldataBuilderConfig`](../types.md#exactcalldatabuilderconfig)         | No       | The calldata the delegate is allowed to call. The default is `0x` to disallow ERC-20 and ERC-721 token transfers. Cannot be used together with `allowedCalldata`.                                                                                                                                                                               |

#### Example

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther("0.001"),
  },
  // Address that is granting the delegation.
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted.
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

## Function call scope

Defines the specific methods, contract addresses, and calldata that are allowed for the delegation.

#### Parameters

| Name              | Type                                                                           | Required | Description                                                                                                                                                                                                                                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `targets`         | `Address[]`                                                                    | Yes      | The list of addresses that the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is allowed to call.                                                                                                                                                                                                                                |
| `selectors`       | `MethodSelector[]`                                                             | Yes      | The list of method selectors that the delegate is allowed to call. The selector value can be 4-byte hex string, ABI function signature, or ABI function object.                                                                                                                                                                                 |
| `allowedCalldata` | [`AllowedCalldataBuilderConfig`](../types.md#allowedcalldatabuilderconfig)`[]` | No       | The list of calldata the delegate is allowed to call. It doesn't support multiple selectors. Each entry in the list represents a portion of calldata corresponding to the same function signature. You can include or exclude specific parameters to define what parts of the calldata are valid. Cannot be used together with `exactCalldata`. |
| `exactCalldata`   | [`ExactCalldataBuilderConfig`](../types.md#exactcalldatabuilderconfig)         | No       | The calldata the delegate is allowed to call. Cannot be used together with `allowedCalldata`.                                                                                                                                                                                                                                                   |
| `valueLte`        | [`ValueLteBuilderConfig`](../types.md#valueltebuilderconfig)                   | No       | The maximum native token amount the delegate can transfer. By default, the amount is set to `0`.                                                                                                                                                                                                                                                |

#### Example

This example sets the delegation scope to allow the delegate to call the `approve` function on the USDC token contract:

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.FunctionCall,
    targets: ["0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"], // USDC address on Sepolia.
    selectors: ["approve(address, uint256)"]
  },
  // Address that is granting the delegation.
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted.
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

## Ownership transfer scope

Restricts a delegation to ownership transfer calls only.

#### Parameters

| Name              | Type      | Required | Description                                                            |
| ----------------- | --------- | -------- | ---------------------------------------------------------------------- |
| `contractAddress` | `Address` | Yes      | The target contract address for which ownership transfers are allowed. |

#### Example

```typescript

const contractAddress = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238"

const delegation = createDelegation({
  scope: {
    type: ScopeType.OwnershipTransfer,
    contractAddress,
  },
  // Address that is granting the delegation.
  from: "0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1",
  // Address to which the delegation is being granted.
  to: "0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488",
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id);
});
```

---

## Delegation API reference


The following API methods are related to creating and managing [delegations](../../concepts/delegation/overview.md).

## `createCaveatBuilder`

Builds an array of <GlossaryTerm term="Caveat">caveats</GlossaryTerm>.

### Parameters

| Name          | Type                                                               | Required | Description                                                       |
| ------------- | ------------------------------------------------------------------ | -------- | ----------------------------------------------------------------- |
| `environment` | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | Environment to resolve the smart contracts for the current chain. |
| `config`      | [`CaveatBuilderConfig`](../types.md#caveatbuilderconfig)           | No       | Configuration for `CoreCaveatBuilder`.                            |

### Example

```ts

const environment = getSmartAccountsEnvironment(sepolia.id)
const caveatBuilder = createCaveatBuilder(environment)
```

### Allow empty caveats

To create an empty caveat collection, set the `CaveatBuilderConfig.allowInsecureUnrestrictedDelegation` to `true`.

```ts title="example.ts"

const environment = getSmartAccountsEnvironment(sepolia.id)
const caveatBuilder = createCaveatBuilder(environment, {
  // add-next-line
  allowInsecureUnrestrictedDelegation: true,
})
```

## `createDelegation`

Creates a delegation with a specific <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>.

### Parameters

| Name                      | Type                                                               | Required | Description                                                                                                                                                            |
| ------------------------- | ------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `from`                    | `Hex`                                                              | Yes      | The address that is granting the delegation.                                                                                                                           |
| `to`                      | `Hex`                                                              | Yes      | The address to which the delegation is being granted.                                                                                                                  |
| `scope`                   | `ScopeConfig`                                                      | Yes      | The scope of the delegation that defines the initial authority. See [delegation scopes](./delegation-scopes.md) for the full list of scope types and their parameters. |
| `environment`             | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | The environment used by the toolkit to define contract addresses for interacting with the <GlossaryTerm term="Delegation Framework" /> contracts.                      |
| `caveats`                 | `Caveats`                                                          | No       | Caveats that further refine the authority granted by the `scope`. See [caveats reference](./caveats.md) for the full list of caveat types and their parameters.        |
| `parentDelegation`        | [`Delegation`](../types.md#delegation) \| `Hex`                    | No       | The parent delegation or its corresponding hex to create a delegation chain. Mutually exclusive with `parentPermissionContext`.                                        |
| `parentPermissionContext` | `PermissionContext`                                                | No       | Parent chain as `Hex` or as decoded [`Delegation`](../types.md#delegation) values (leaf first). Mutually exclusive with `parentDelegation`.                            |
| `salt`                    | `Hex`                                                              | No       | The salt for generating the delegation hash. This helps prevent hash collisions when creating identical delegations.                                                   |

### Example

```typescript

  createDelegation,
  getSmartAccountsEnvironment,
  ScopeType,
} from '@metamask/smart-accounts-kit'

const delegation = createDelegation({
  // Address that is granting the delegation
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  // Address to which the delegation is being granted
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

## `createOpenDelegation`

Creates an <GlossaryTerm term="Open delegation">open delegation</GlossaryTerm> that can be redeemed by any delegate.

### Parameters

| Name                      | Type                                                               | Required    | Description                                                                                                                                                                                                                                                                                       |
| ------------------------- | ------------------------------------------------------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `from`                    | `Hex`                                                              | Yes         | The address that is granting the delegation.                                                                                                                                                                                                                                                      |
| `scope`                   | `ScopeConfig`                                                      | Conditional | Defines the delegation authority. See [delegation scopes](./delegation-scopes.md) for supported types and parameters. Required for a root open delegation. Optional when either `parentDelegation` or `parentPermissionContext` is set; if omitted, authority is inherited from the parent chain. |
| `environment`             | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes         | The environment used by the toolkit to define contract addresses for interacting with the <GlossaryTerm term="Delegation Framework" /> contracts.                                                                                                                                                 |
| `caveats`                 | `Caveats`                                                          | No          | Caveats that further refine the authority granted by the `scope`. See [caveats reference](./caveats.md) for the full list of caveat types and their parameters.                                                                                                                                   |
| `parentDelegation`        | [`Delegation`](../types.md#delegation) \| `Hex`                    | No          | The parent delegation or its corresponding hex to create a delegation chain. Mutually exclusive with `parentPermissionContext`.                                                                                                                                                                   |
| `parentPermissionContext` | `PermissionContext`                                                | No          | Parent chain as `Hex` or as decoded [`Delegation`](../types.md#delegation) values (leaf first). Mutually exclusive with `parentDelegation`.                                                                                                                                                       |
| `salt`                    | `Hex`                                                              | No          | The salt for generating the delegation hash. This helps prevent hash collisions when creating identical delegations.                                                                                                                                                                              |

### Example

```typescript

  createOpenDelegation,
  getSmartAccountsEnvironment,
  ScopeType,
} from '@metamask/smart-accounts-kit'

const delegation = createOpenDelegation({
  // Address that is granting the delegation
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  // Alternatively you can use environment property of MetaMask smart account.
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

## `createExecution`

Creates an `ExecutionStruct` instance.

### Parameters

| Name       | Type      | Required | Description                                                            |
| ---------- | --------- | -------- | ---------------------------------------------------------------------- |
| `target`   | `Address` | No       | Address of the contract or recipient that the call is directed to.     |
| `value`    | `bigint`  | No       | Value of native tokens to send along with the call in wei.             |
| `callData` | `Hex`     | No       | Encoded function data or payload to be executed on the target address. |

### Example

```ts

// Creates an ExecutionStruct to transfer 0.01 ETH to
// 0xe3C818389583fDD5cAC32f548140fE26BcEaE907 address.
const execution = createExecution({
  target: '0xe3C818389583fDD5cAC32f548140fE26BcEaE907',
  // 0.01 ETH in wei
  value: parseEther('0.01'),
  callData: '0x',
})
```

## `decodeDelegations`

Decodes an ABI-encoded hex string to an array of delegations.

Use `decodeDelegations` when working with a permission context that contains a delegation
chain, such as the `context` property returned by [`requestExecutionPermissions`](../advanced-permissions/wallet-client.md#requestexecutionpermissions) response.

### Parameters

| Name      | Type  | Required | Description                           |
| --------- | ----- | -------- | ------------------------------------- |
| `encoded` | `Hex` | Yes      | The ABI encoded hex string to decode. |

### Example

```ts

const delegations = decodeDelegations('0x7f0db33d..c06aeeac')
```

## `decodeDelegation`

Decodes an ABI-encoded hex string to a single delegation.

Use `decodeDelegation` when you have a single encoded delegation rather than an encoded delegation chain.

### Parameters

| Name      | Type  | Required | Description                           |
| --------- | ----- | -------- | ------------------------------------- |
| `encoded` | `Hex` | Yes      | The ABI-encoded hex string to decode. |

### Example

```ts

const delegation = decodeDelegation('0x7f0db33d..c06aeeac')
```

## `decodeCaveat`

Decodes a caveat's encoded `terms`.

Throws an error if the caveat enforcer is not a known enforcer in [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment).

### Parameters

| Name          | Type                                                               | Required | Description                                                                                                            |
| ------------- | ------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `caveat`      | [`Caveat`](../types.md#caveat)                                     | Yes      | The <GlossaryTerm term="Caveat">caveat</GlossaryTerm> object containing an `enforcer` address and ABI-encoded `terms`. |
| `environment` | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | Environment to resolve the <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm> addresses.              |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const environment = delegation.environment

// Decode the first caveat from the delegation.
const decodedCaveat = decodeCaveat({
  caveat: delegation.caveats[0],
  environment,
})

// Output:
// {
//   type: 'erc20TransferAmount',
//   tokenAddress: '0x1c7D...7238',
//   maxAmount: 10000000n,
// }
```

</TabItem>
<TabItem value="config.ts">

```ts

  createDelegation,
  getSmartAccountsEnvironment,
  ScopeType,
} from '@metamask/smart-accounts-kit'

const environment = getSmartAccountsEnvironment(sepolia.id)

// USDC address on Ethereum Sepolia.
const tokenAddress = '0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238'

export const delegation = createDelegation({
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  environment,
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress,
    // 10 USDC
    maxAmount: parseUnits('10', 6),
  },
})
```

</TabItem>
</Tabs>

## `decodeRevertData`

Decodes raw ABI-encoded revert data into a [`DecodedRevertReason`](../types.md#decodedrevertreason).

Tries standard Solidity errors, and known
<GlossaryTerm term="Delegation Framework" /> ABIs, then falls back to decoding printable ASCII bytes.

Returns `undefined` if the data could not be decoded.

### Parameters

| Name      | Type  | Required | Description                      |
| --------- | ----- | -------- | -------------------------------- |
| `rawData` | `Hex` | Yes      | The raw ABI-encoded revert data. |

### Example

```ts

const decoded = decodeRevertData('0x08c379a0...')
```

## `decodeRevertReason`

Extracts revert data from an error object and decodes it using [`decodeRevertData`](#decoderevertdata).
Use this when you catch an error from any <GlossaryTerm term="Delegation Framework" /> interaction
and want to decode the revert reason.

Returns `undefined` if no revert data is found in the error.

### Parameters

| Name    | Type      | Required | Description                                              |
| ------- | --------- | -------- | -------------------------------------------------------- |
| `error` | `unknown` | Yes      | The error object to extract and decode revert data from. |

### Example

This example assumes you have a delegation signed by the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>.

```ts

try {
  await DelegationManager.execute.redeemDelegations({
    delegations: [[signedDelegation]],
    modes: [ExecutionMode.SingleDefault],
    executions: [[execution]],
  })
} catch (error) {
  const decoded = decodeRevertReason(error)
  if (decoded) {
    console.log(decoded.message)
  }
}
```

## `deploySmartAccountsEnvironment`

Deploys the <GlossaryTerm term="Delegation Framework" /> contracts to an EVM chain.

### Parameters

| Name                | Type                          | Required | Description                                                                                                                                                                                                          |
| ------------------- | ----------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `walletClient`      | `WalletClient`                | Yes      | [Viem Wallet Client](https://viem.sh/docs/clients/wallet#wallet-client) to deploy the contracts.                                                                                                                     |
| `publicClient`      | `PublicClient`                | Yes      | [Viem Public Client](https://viem.sh/docs/clients/public) to interact with the given chain.                                                                                                                          |
| `chain`             | `Chain`                       | Yes      | [Viem Chain](https://viem.sh/docs/chains/introduction) where you wish to deploy the Delegation Framework contracts.                                                                                                  |
| `deployedContracts` | `{ [contract: string]: Hex }` | No       | Allows overriding specific contract addresses when calling the function. For example, if certain contracts have already been deployed on the target chain, their addresses can be provided directly to the function. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const environment = await deploySmartAccountsEnvironment(walletClient, publicClient, chain)
```

</TabItem>
<TabItem value="config.ts">

```ts

// Your deployer wallet private key.
const privateKey = '0x123..'
const account = privateKeyToAccount(privateKey)

export const walletClient = createWalletClient({
  account,
  chain,
  transport: http(),
})

export const publicClient = createPublicClient({
  transport: http(),
  chain,
})
```

</TabItem>
</Tabs>

### Inject deployed contracts

Once the contracts are deployed, you can use them to override the delegator
environment using `overrideDeployedEnvironment`.

```ts title="example.ts"

  overrideDeployedEnvironment,
  deploySmartAccountsEnvironment,
} from '@metamask/smart-accounts-kit/utils'

const environment: SmartAccountsEnvironment = await deploySmartAccountsEnvironment(
  walletClient,
  publicClient,
  chain
)

// add-start
overrideDeployedEnvironment(chain.id, '1.3.0', environment)
// add-end
```

## `disableDelegation`

Encodes the calldata for disabling a delegation.

### Parameters

| Name         | Type                                   | Required | Description                    |
| ------------ | -------------------------------------- | -------- | ------------------------------ |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation to be disabled. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const disableDelegationData = DelegationManager.encode.disableDelegation({
  delegation,
})
```

</TabItem>
<TabItem value="delegation.ts">

```ts

export const delegation = createDelegation({
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

## `enableDelegation`

Encodes the calldata to enable a disabled delegation.

### Parameters

| Name         | Type                                   | Required | Description                   |
| ------------ | -------------------------------------- | -------- | ----------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation to be enabled. |

### Example

```ts

const enableDelegationData = DelegationManager.encode.enableDelegation({
  delegation, // Already disabled delegation.
})
```

## `encodeDelegations`

Encodes an array of delegations to an ABI-encoded hex string.

The delegations must be ordered from leaf to root delegation, with each
delegation's `authority` referencing the hash of the next entry in the array.

### Parameters

| Name          | Type                                       | Required | Description                                                           |
| ------------- | ------------------------------------------ | -------- | --------------------------------------------------------------------- |
| `delegations` | [`Delegation`](../types.md#delegation)`[]` | Yes      | The delegation chain to encode, ordered from leaf to root delegation. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const encodedDelegations = encodeDelegations([delegation])
```

</TabItem>
<TabItem value="delegation.ts">

```ts

export const delegation = createDelegation({
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

## `encodeDelegation`

Encodes a single delegation to an ABI-encoded hex string.

### Parameters

| Name         | Type                                   | Required | Description                   |
| ------------ | -------------------------------------- | -------- | ----------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation to be encoded. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const encodedDelegation = encodeDelegation(delegation)
```

</TabItem>
<TabItem value="delegation.ts">

```ts

export const delegation = createDelegation({
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

## `hashDelegation`

Returns the delegation hash.

### Parameters

| Name    | Type                                   | Required | Description                    |
| ------- | -------------------------------------- | -------- | ------------------------------ |
| `input` | [`Delegation`](../types.md#delegation) | Yes      | The delegation object to hash. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const delegationHash = hashDelegation(delegation)
```

</TabItem>
<TabItem value ="config.ts">

```ts

  getSmartAccountsEnvironment,
  createDelegation,
  ScopeType,
} from '@metamask/smart-accounts-kit'

const environment = getSmartAccountsEnvironment(sepolia.id)

// The address to which the delegation is granted. It can be an EOA address, or
// smart account address.
const delegate = '0x2FcB88EC2359fA635566E66415D31dD381CF5585'

export const delegation = createDelegation({
  to: delegate,
  // Address that is granting the delegation.
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  environment,
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

## `getSmartAccountsEnvironment`

Resolves the `SmartAccountsEnvironment` for a chain.

### Parameters

| Name      | Type               | Required | Description                                                                                                                                                   |
| --------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chainId` | `number`           | Yes      | The chain ID of the network for which the `SmartAccountsEnvironment` should be resolved.                                                                      |
| `version` | `SupportedVersion` | No       | Specifies the version of the <GlossaryTerm term="Delegation Framework" /> contracts to use. If omitted, the latest supported version will be used by default. |

### Example

```ts

const environment = getSmartAccountsEnvironment(sepolia.id)
```

## `generateSalt`

Generates a random 32-byte hex salt for creating delegations. This helps prevent hash collisions when creating identical delegations.

### Example

```ts

const salt = generateSalt()
```

## `overrideDeployedEnvironment`

Overrides or adds the `SmartAccountsEnvironment` for a chain and supported version.

### Parameters

| Name          | Type                                                               | Required | Description                                                                                                    |
| ------------- | ------------------------------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------- |
| `chainId`     | `number`                                                           | Yes      | The chain ID of the network for which the `SmartAccountsEnvironment` should be overridden.                     |
| `version`     | `SupportedVersion`                                                 | Yes      | The version of the <GlossaryTerm term="Delegation Framework" /> contracts to override for the specified chain. |
| `environment` | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | The environment containing contract addresses to override for the given chain and version.                     |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

overrideDeployedEnvironment(sepolia.id, '1.3.0', environment)
```

</TabItem>
<TabItem value="environment.ts">

```ts

export const environment: SmartAccountsEnvironment = {
  SimpleFactory: '0x124..',
  // ...
  implementations: {
    // ...
  },
}
```

</TabItem>
</Tabs>

## `redeemDelegations`

Encodes calldata for redeeming delegations.
This method supports batch redemption, allowing multiple delegations to be processed within a single transaction.

Each inner delegation array must be ordered from leaf to root delegation, with each delegation's `authority` referencing the hash of the next entry in the array.

### Parameters

| Name          | Type                                                   | Required | Description                                                                                                                                                         |
| ------------- | ------------------------------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `delegations` | [`Delegation`](../types.md#delegation)`[][]`           | Yes      | A nested collection representing chains of delegations. Each inner collection contains a chain of delegations to be redeemed, ordered from leaf to root delegation. |
| `modes`       | [`ExecutionMode`](../types.md#executionmode)`[]`       | Yes      | A collection specifying the [execution mode](../../concepts/delegation/delegation-manager.md#execution-modes) for each corresponding delegation chain.              |
| `executions`  | [`ExecutionStruct`](../types.md#executionstruct)`[][]` | Yes      | A nested collection where each inner collection contains a list of `ExecutionStruct` objects associated with a specific delegation chain.                           |

### Example

This example assumes you have a delegation signed by the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>.

```ts

const data = DelegationManager.encode.redeemDelegations({
  delegations: [[signedDelegation]],
  modes: [ExecutionMode.SingleDefault],
  executions: [[execution]],
})
```

## `signDelegation`

Signs the delegation and returns the delegation signature.

### Parameters

| Name                                  | Type                                                          | Required | Description                                                                                                                           |
| ------------------------------------- | ------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `privateKey`                          | `Hex`                                                         | Yes      | The private key to use for signing the delegation.                                                                                    |
| `delegation`                          | `Omit<`[`Delegation`](../types.md#delegation)`, "signature">` | Yes      | The unsigned delegation object to sign.                                                                                               |
| `chainId`                             | `number`                                                      | Yes      | The chain ID on which the delegation manager is deployed.                                                                             |
| `delegationManager`                   | `0x${string}`                                                 | Yes      | The address of the Delegation Manager.                                                                                                |
| `name`                                | `string`                                                      | No       | The name of the domain of the Delegation Manager. The default is `DelegationManager`.                                                 |
| `version`                             | `string`                                                      | No       | The version of the domain of the Delegation Manager. The default is `1`.                                                              |
| `allowInsecureUnrestrictedDelegation` | `boolean`                                                     | No       | Whether to allow insecure unrestricted delegation with no <GlossaryTerm term="Caveat">caveats</GlossaryTerm>. The default is `false`. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const signature = signDelegation({
  privateKey,
  delegation,
  chainId: sepolia.id,
  delegationManager,
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

  getSmartAccountsEnvironment,
  createDelegation,
  ScopeType,
} from '@metamask/smart-accounts-kit'

const environment = getSmartAccountsEnvironment(sepolia.id)
export const delegationManager = environment.DelegationManager

export const privateKey = `0x12141..`
const account = privateKeyToAccount(privateKey)

// The address to which the delegation is granted. It can be an EOA address, or
// smart account address.
const delegate = '0x2FcB88EC2359fA635566E66415D31dD381CF5585'

export const delegation = createDelegation({
  to: delegate,
  from: account.address,
  environment,
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

## `toDelegationStruct`

Converts a [`Delegation`](../types.md#delegation) object to a
[`DelegationStruct`](../types.md#delegationstruct) object.

Use when you need to pass a delegation directly to a
<GlossaryTerm term="Delegation Framework" /> contract call or other onchain interaction that expects
the struct form.

### Parameters

| Name         | Type                                   | Required | Description                |
| ------------ | -------------------------------------- | -------- | -------------------------- |
| `delegation` | [`Delegation`](../types.md#delegation) | Yes      | The delegation to convert. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const delegationStruct = toDelegationStruct(delegation)
```

</TabItem>
<TabItem value="delegation.ts">

```ts

  createDelegation,
  getSmartAccountsEnvironment,
  ScopeType,
} from '@metamask/smart-accounts-kit'

export const delegation = createDelegation({
  from: '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1',
  to: '0x2B2dBd1D5fbeB77C4613B66e9F35dBfE12cB0488',
  environment: getSmartAccountsEnvironment(sepolia.id),
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: parseEther('0.001'),
  },
})
```

</TabItem>
</Tabs>

---

## Bundler Client actions reference


These actions extend the [Viem Bundler Client](https://viem.sh/account-abstraction/clients/bundler) to support [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) utilities.

## `sendUserOperationWithDelegation`

Sends a <GlossaryTerm term="User operation">user operation</GlossaryTerm> with redeem permissions according to the [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) specifications.

:::info
To use `sendUserOperationWithDelegation`, the Viem Bundler Client must be
extended with `erc7710BundlerActions`.
:::

### Parameters

See the [Viem `sendUserOperation` parameters](https://viem.sh/account-abstraction/actions/bundler/sendUserOperation).
This function has the same parameters, except it does not accept `callData`.

Objects in the `calls` array also require the following parameters:

| Name                | Type                | Required | Description                                                                                                   |
| ------------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `delegationManager` | `Address`           | Yes      | The address of the <GlossaryTerm term="Delegation Manager" />.                                                |
| `permissionContext` | `PermissionContext` | Yes      | An encoded delegation chain (`Hex`) or a decoded delegation chain (`Delegation[]`) for redeeming permissions. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

// These properties must be extracted from the permission response.
const permissionContext = permissionsResponse[0].context
const delegationManager = permissionsResponse[0].delegationManager

// Calls without permissionContext and delegationManager will be executed
// as a normal user operation.
const userOperationHash = await bundlerClient.sendUserOperationWithDelegation({
  publicClient,
  account: sessionAccount,
  calls: [
    {
      to: sessionAccount.address,
      data: '0x',
      value: 1n,
      permissionContext,
      delegationManager,
    },
  ],
  // Appropriate values must be used for fee-per-gas.
  maxFeePerGas: 1n,
  maxPriorityFeePerGas: 1n,
})
```

</TabItem>
<TabItem value ="client.ts">

```ts

export const publicClient = createPublicClient({
  chain: chain,
  transport: http(),
})

// Your session account for requesting and redeeming should be the same.
const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

export const sessionAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})

export const bundlerClient = createBundlerClient({
  transport: http(`https://your-bundler-url`),
  // Allows you to use the same Bundler Client as paymaster.
  paymaster: true,
}).extend(erc7710BundlerActions())
```

</TabItem>
</Tabs>

---

## Wallet Client actions reference(Erc7710)


These actions extend the [Viem Wallet Client](https://viem.sh/docs/clients/wallet) to support [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) utilities.

## `sendTransactionWithDelegation`

Sends a transaction to redeem delegated permissions according to the [ERC-7710](https://eips.ethereum.org/EIPS/eip-7710) specifications.

:::info
To use `sendTransactionWithDelegation`, the Viem Wallet Client must be
extended with `erc7710WalletActions`.
:::

### Parameters

See the [Viem `sendTransaction` parameters](https://viem.sh/docs/actions/wallet/sendTransaction#parameters).
This function has the same parameters, and it also requires the following parameters:

| Name                | Type                | Required | Description                                                                                                   |
| ------------------- | ------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `delegationManager` | `Address`           | Yes      | The address of the <GlossaryTerm term="Delegation Manager" />.                                                |
| `permissionContext` | `PermissionContext` | Yes      | An encoded delegation chain (`Hex`) or a decoded delegation chain (`Delegation[]`) for redeeming delegations. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

// These properties must be extracted from the permission response. See
// `grantPermissions` action to learn how to request permissions.
const permissionContext = permissionsResponse[0].context
const delegationManager = permissionsResponse[0].delegationManager

const hash = walletClient.sendTransactionWithDelegation({
  chain,
  to: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
  value: 1n,
  permissionContext,
  delegationManager,
})
```

</TabItem>
<TabItem value ="client.ts">

```ts

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})

// Your session account for requesting and redeeming should be the same.
const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

const walletClient = createWalletClient({
  account,
  transport: http(),
  chain,
}).extend(erc7710WalletActions())
```

</TabItem>
</Tabs>

## `redelegatePermissionContext`

Creates a <GlossaryTerm term="Redelegation">redelegation</GlossaryTerm> to a specific <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> from a delegation chain encoded as `Hex` or decoded as [`Delegation`](../types.md#delegation)`[]`.

The action returns [`RedelegatePermissionContextReturnType`](../types.md#redelegatepermissioncontextreturntype).

### Parameters

| Name                | Type                                                               | Required | Description                                                                                                                                                     |
| ------------------- | ------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `environment`       | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | Contract addresses for the <GlossaryTerm term="Delegation Framework" /> on the target chain.                                                                    |
| `permissionContext` | `PermissionContext`                                                | Yes      | Encoded delegation chain (`Hex`) or decoded chain ([`Delegation`](../types.md#delegation)`[]`), leaf first.                                                     |
| `chainId`           | `number`                                                           | No       | Chain ID used when signing the delegation.                                                                                                                      |
| `account`           | `Account` \| `Address`                                             | No       | Account that signs the redelegation. The default is the Wallet Client's configured account.                                                                     |
| `scope`             | `ScopeConfig`                                                      | No       | <GlossaryTerm term="Delegation scope">Delegation scope</GlossaryTerm> to restrict the authority of the redelegation.                                            |
| `caveats`           | `Caveats`                                                          | No       | Additional <GlossaryTerm term="Caveat">caveats</GlossaryTerm> to restrict the authority of the redelegation. See [caveats reference](../delegation/caveats.md). |
| `salt`              | `Hex`                                                              | No       | Salt for redelegation.                                                                                                                                          |
| `to`                | `Address`                                                          | Yes      | Address of the delegate for the redelegation.                                                                                                                   |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

// These properties must be extracted from the permission response. See
// `grantPermissions` action to learn how to request permissions.
const permissionContext = permissionsResponse[0].context

const { permissionContext: redelegatedPermissionContext } =
  walletClient.redelegatePermissionContext({
    to: 'DELEGATE_ADDRESS',
    environment,
    permissionContext: permissionContext,
  })
```

</TabItem>
<TabItem value ="client.ts">

```ts

// Your session account for requesting and redelegating should be the same.
const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

export const environment = getSmartAccountsEnvironment(chain.id)

const walletClient = createWalletClient({
  account,
  transport: http(),
  chain,
}).extend(erc7710WalletActions())
```

</TabItem>
</Tabs>

## `redelegatePermissionContextOpen`

Creates an <GlossaryTerm term="Open redelegation">open redelegation</GlossaryTerm> from a delegation chain encoded as `Hex` or decoded as [`Delegation`](../types.md#delegation)`[]`. This allows any account to redeem the inherited permissions.

The action returns [`RedelegatePermissionContextReturnType`](../types.md#redelegatepermissioncontextreturntype).

### Parameters

| Name                | Type                                                               | Required | Description                                                                                                                                                     |
| ------------------- | ------------------------------------------------------------------ | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `environment`       | [`SmartAccountsEnvironment`](../types.md#smartaccountsenvironment) | Yes      | Contract addresses for the <GlossaryTerm term="Delegation Framework" /> on the target chain.                                                                    |
| `permissionContext` | `PermissionContext`                                                | Yes      | Encoded delegation chain (`Hex`) or decoded chain ([`Delegation`](../types.md#delegation)`[]`), leaf first.                                                     |
| `chainId`           | `number`                                                           | No       | Chain ID used when signing the delegation.                                                                                                                      |
| `account`           | `Account` \| `Address`                                             | No       | Account that signs the redelegation. The default is the Wallet Client's configured account.                                                                     |
| `scope`             | `ScopeConfig`                                                      | No       | <GlossaryTerm term="Delegation scope">Delegation scope</GlossaryTerm> to restrict the authority of the redelegation.                                            |
| `caveats`           | `Caveats`                                                          | No       | Additional <GlossaryTerm term="Caveat">caveats</GlossaryTerm> to restrict the authority of the redelegation. See [caveats reference](../delegation/caveats.md). |
| `salt`              | `Hex`                                                              | No       | Salt for redelegation.                                                                                                                                          |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

// These properties must be extracted from the permission response. See
// `grantPermissions` action to learn how to request permissions.
const permissionContext = permissionsResponse[0].context

const { permissionContext: redelegatedPermissionContext } =
  walletClient.redelegatePermissionContextOpen({
    environment,
    permissionContext: permissionContext,
  })
```

</TabItem>
<TabItem value ="client.ts">

```ts

// Your session account for requesting and redelegating should be the same.
const privateKey = '0x...'
const account = privateKeyToAccount(privateKey)

export const environment = getSmartAccountsEnvironment(chain.id)

const walletClient = createWalletClient({
  account,
  transport: http(),
  chain,
}).extend(erc7710WalletActions())
```

</TabItem>
</Tabs>

---

## Glossary

This glossary defines common Smart Accounts Kit terms used across the documentation.

<!-- AUTO-GENERATED by scripts/generate-smart-accounts-glossary.js. -->
<!-- Edit src/lib/glossary.json and run npm run glossary:generate. -->

### Account abstraction

A conceptual model for programmable onchain accounts, including flexible validation logic, custom signature schemes, and gas abstraction. ERC-4337 defines a mechanism for account abstraction.

### Advanced Permissions

Fine-grained, wallet execution permissions that dapps can request from MetaMask extension users. Based on ERC-7715.

### Bundler

An ERC-4337 component that manages the alternate mempool: it collects user operations from smart accounts, packages them, and submits them to the network.

### Caveat

A restriction attached to a delegation that limits how delegated authority can be used.

### Caveat enforcer

A smart contract that enforces delegation rules by validating caveat conditions during redemption hooks.

### Delegate account

The account that receives delegated authority and can redeem a delegation under its constraints.

### Delegation

The ability for a MetaMask smart account to authorize another account to perform specific executions on its behalf.

### Delegation Framework

A set of audited smart contracts that handle smart account creation, the delegation lifecycle, and caveat enforcement.

### Delegation Manager

The ERC-7710 component that validates and redeems delegations, including signature checks and caveat enforcer hooks.

### Delegation scope

A predefined authority pattern representing a caveat or group of caveats, which sets the initial actions a delegate is allowed to perform. You can combine scopes with additional caveats.

### Delegator account

The account that creates and signs a delegation to grant limited authority to another account.

### EIP-7702 smart account

A stateless MetaMask smart account implementation that represents an upgraded EOA.

### Externally owned account (EOA)

A private-key-controlled account with no built-in programmable execution logic.

### Hybrid smart account

A smart account implementation that supports both an EOA owner and passkey signers.

### MetaMask smart account

A smart contract account created using the Smart Accounts Kit that supports programmable behavior, flexible signing options, and ERC-7710 delegations.

### Multisig smart account

A smart account implementation that requires multiple signers to generate a valid signature.

### Open delegation

A delegation that leaves the delegate unspecified, allowing any account to redeem it.

### Open redelegation

A redelegation with no specific delegate, allowing any account to redeem inherited permissions.

### Passkey

A cryptographic key that can be used to sign transactions instead of a private key.

### Paymaster

A service that pays for user operations on behalf of a smart account.

### Redelegation

A delegation that passes on authority granted by a previous delegation.

### Root delegation

The first delegation in a chain, where an account delegates its own authority directly.

### Signer

An account that can sign transactions for a smart account.

### User operation

A pseudo-transaction object defined by ERC-4337 that describes what a smart account should execute. User operations are submitted to the alternate mempool managed by bundlers.

---

## MetaMask Smart Accounts API reference


The following API methods are related to creating, managing, and signing with [MetaMask Smart Accounts](../concepts/smart-accounts.md).

## `aggregateSignature`

Aggregates multiple partial signatures into a single combined multisig signature.

### Parameters

| Name         | Type                                                | Required | Description                                                                                      |
| ------------ | --------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------ |
| `signatures` | [`PartialSignature`](./types.md#partialsignature)[] | Yes      | Collection of partial signatures provided by signers, to be merged into an aggregated signature. |

### Example

<Tabs>
<TabItem value="example.ts">

```typescript

  bundlerClient,
  aliceSmartAccount,
  bobSmartAccount,
  aliceAccount,
  bobAccount,
} from './config.ts'

const userOperation = await bundlerClient.prepareUserOperation({
  account: aliceSmartAccount,
  calls: [
    {
      target: zeroAddress,
      value: 0n,
      data: '0x',
    },
  ],
})

const aliceSignature = await aliceSmartAccount.signUserOperation(userOperation)
const bobSignature = await bobSmartAccount.signUserOperation(userOperation)

const aggregatedSignature = aggregateSignature({
  signatures: [
    {
      signer: aliceAccount.address,
      signature: aliceSignature,
      type: 'ECDSA',
    },
    {
      signer: bobAccount.address,
      signature: bobSignature,
      type: 'ECDSA',
    },
  ],
})
```

</TabItem>
<TabItem value="config.ts">

```typescript

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const alicePrivateKey = generatePrivateKey()
const aliceAccount = privateKeyToAccount(alicePrivateKey)

const bobPrivateKey = generatePrivateKey()
const bobAccount = privateKeyToAccount(bobPrivateKey)

const signers = [aliceAccount.address, bobAccount.address]
const threshold = 2n

export const aliceSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [signers, threshold],
  deploySalt: '0x',
  signer: [{ account: aliceAccount }],
})

export const bobSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [signers, threshold],
  deploySalt: '0x',
  signer: [{ account: bobAccount }],
})

export const bundlerClient = createBundlerClient({
  client: publicClient,
  transport: http('https://public.pimlico.io/v2/rpc'),
})
```

</TabItem>
</Tabs>

## `encodeCalls`

Encodes calls for execution by a MetaMask smart account. If there's a single call directly to the smart account, it returns the call data directly. For multiple calls or calls to other addresses, it creates executions and encodes them for the smart account's `execute` function.

The execution mode is set to `SingleDefault` for a single call to other address, or `BatchDefault` for multiple calls.

### Parameters

| Name    | Type     | Required | Description                  |
| ------- | -------- | -------- | ---------------------------- |
| `calls` | `Call[]` | Yes      | List of calls to be encoded. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const calls = [
  {
    to: zeroAddress,
    data: '0x',
    value: 0n,
  },
]

const executeCallData = await smartAccount.encodeCalls(calls)
```

</TabItem>

<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const delegatorAccount = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegatorAccount },
})
```

</TabItem>
</Tabs>

## `getFactoryArgs`

Returns the factory address and factory data that can be used to deploy a smart account.

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const { factory, factoryData } = await smartAccount.getFactoryArgs()
```

</TabItem>

<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const delegatorAccount = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegatorAccount },
})
```

</TabItem>
</Tabs>

## `getNonce`

Returns the nonce for a smart account.

### Parameters

| Name  | Type     | Required | Description                                                                                                                           |
| ----- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `key` | `bigint` | No       | The nonce key to retrieve the nonce. Different keys maintain independent nonce sequences, enabling parallel user operation execution. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const nonce = await smartAccount.getNonce()
```

</TabItem>

<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const delegatorAccount = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegatorAccount },
})
```

</TabItem>
</Tabs>

## `isDeployed`

Checks whether the MetaMask smart account has been deployed on the current chain.

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const isDeployed = await smartAccount.isDeployed()
```

</TabItem>
<TabItem value="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  address: '<SMART_ACCOUNT_ADDRESS>',
})
```

</TabItem>
</Tabs>

## `isValid7702Implementation`

Checks whether an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> has
been upgraded to MetaMask smart account using [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702).

### Parameters

| Name             | Type                                                              | Required | Description                                                                                         |
| ---------------- | ----------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------- |
| `client`         | `Client`                                                          | Yes      | Viem Client used to read the account's bytecode.                                                    |
| `accountAddress` | `Address`                                                         | Yes      | The address to check for an EIP-7702 delegation.                                                    |
| `environment`    | [`SmartAccountsEnvironment`](./types.md#smartaccountsenvironment) | Yes      | Environment to resolve `EIP7702StatelessDeleGatorImpl` smart account address for the current chain. |

### Example

<Tabs>
<TabItem value="example.ts">

```ts

const isUpgraded = await isValid7702Implementation({
  client: publicClient,
  accountAddress,
  environment,
})
```

</TabItem>
<TabItem value="config.ts">

```ts

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})

export const environment = getSmartAccountsEnvironment(chain.id)

export const accountAddress = '0x7E48cA6b7fe6F3d57fdd0448B03b839958416fC1'
```

</TabItem>
</Tabs>

## `signDelegation`

Signs the delegation and returns the delegation signature.

### Parameters

| Name         | Type                            | Required | Description                                               |
| ------------ | ------------------------------- | -------- | --------------------------------------------------------- |
| `delegation` | `Omit<Delegation, "signature">` | Yes      | The unsigned delegation object to sign.                   |
| `chainId`    | `number`                        | No       | The chain ID on which the Delegation Manager is deployed. |

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

  createDelegation,
  getSmartAccountsEnvironment,
  ScopeType,
} from '@metamask/smart-accounts-kit'

// The address to which the delegation is granted. It can be an EOA address, or
// smart account address.
const delegate = '0x2FcB88EC2359fA635566E66415D31dD381CF5585'

const delegation = createDelegation({
  to: delegate,
  from: account.address,
  environment: delegatorSmartAccount.environment,
  scope: {
    type: ScopeType.NativeTokenTransferAmount,
    // 0.001 ETH in wei format.
    maxAmount: 1000000000000000n,
  },
})

const signature = delegatorSmartAccount.signDelegation({ delegation })
```

</TabItem>
<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const delegatorAccount = privateKeyToAccount('0x...')

export const delegatorSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [delegatorAccount.address, [], [], []],
  deploySalt: '0x',
  signer: { account: delegatorAccount },
})
```

</TabItem>
</Tabs>

## `signMessage`

Generates the [EIP-191](https://eips.ethereum.org/EIPS/eip-191) signature
using the `MetaMaskSmartAccount` signer. The Smart Accounts Kit
uses Viem under the hood to provide this functionality.

### Parameters

See the [Viem `signMessage` parameters](https://viem.sh/account-abstraction/accounts/smart/signMessage).

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const signature = smartAccount.signMessage({
  message: 'hello world',
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const account = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})
```

</TabItem>
</Tabs>

## `signTypedData`

Generates the [EIP-712](https://eips.ethereum.org/EIPS/eip-712) signature
using the `MetaMaskSmartAccount` signer. The Smart Accounts Kit
uses Viem under the hood to provide this functionality.

### Parameters

See the [Viem `signTypedData` parameters](https://viem.sh/account-abstraction/accounts/smart/signTypedData).

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const signature = smartAccount.signTypedData({
  domain,
  types,
  primaryType: 'Mail',
  message: {
    from: {
      name: 'Cow',
      wallet: '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
    },
    to: {
      name: 'Bob',
      wallet: '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
    },
    contents: 'Hello, Bob!',
  },
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const account = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})
```

</TabItem>
</Tabs>

## `signUserOperation`

Signs a <GlossaryTerm term="User operation">user operation</GlossaryTerm> with the `MetaMaskSmartAccount` signer. The Delegation
Toolkit uses Viem under the hood to provide this functionality.

### Parameters

See the [Viem `signUserOperation` parameters](https://viem.sh/account-abstraction/accounts/smart/signUserOperation#parameters).

### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const userOpSignature = smartAccount.signUserOperation({
  callData: '0xdeadbeef',
  callGasLimit: 141653n,
  maxFeePerGas: 15000000000n,
  maxPriorityFeePerGas: 2000000000n,
  nonce: 0n,
  preVerificationGas: 53438n,
  sender: '0xE911628bF8428C23f179a07b081325cAe376DE1f',
  verificationGasLimit: 259350n,
  signature: '0x',
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const account = privateKeyToAccount('0x...')

export const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account },
})
```

</TabItem>
</Tabs>

## `toMetaMaskSmartAccount`

Creates a `MetaMaskSmartAccount` instance.

### Parameters

| Name              | Type                                                              | Required                                                                                                   | Description                                                                                                                                                                                                                                                                                                                                   |
| ----------------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client`          | `Client`                                                          | Yes                                                                                                        | Viem Client to retrieve smart account data.                                                                                                                                                                                                                                                                                                   |
| `implementation`  | `TImplementation`                                                 | Yes                                                                                                        | Implementation type for the smart account. Can be <GlossaryTerm term="Hybrid smart account">`Hybrid`</GlossaryTerm>, <GlossaryTerm term="Multisig smart account">`Multisig`</GlossaryTerm>, or <GlossaryTerm term="EIP-7702 smart account">`Stateless7702`</GlossaryTerm>.                                                                    |
| `signer`          | `SignerConfigByImplementation <TImplementation>`                  | No                                                                                                         | Signer for the smart account. Can be a Viem Account, Viem Wallet Client, or a WebAuthn Account. WebAuthn accounts are only supported for Hybrid implementations. If omitted, non-signing operations still work, but signing operations such as `signUserOperation`, `signDelegation`, `signMessage`, and `signTypedData` will throw an error. |
| `environment`     | [`SmartAccountsEnvironment`](./types.md#smartaccountsenvironment) | No                                                                                                         | Environment to resolve the smart contracts.                                                                                                                                                                                                                                                                                                   |
| `deployParams`    | `DeployParams<TImplementation>`                                   | Required if `address` is not provided                                                                      | The parameters that will be used to deploy the smart account and generate its deterministic address.                                                                                                                                                                                                                                          |
| `deploySalt`      | `Hex`                                                             | Required if `address` is not provided                                                                      | The salt that will be used to deploy the smart account.                                                                                                                                                                                                                                                                                       |
| `address`         | `Address`                                                         | Required if `deployParams` and `deploySalt` are not provided, or if the implementation is `Stateless7702`. | The address of the smart account. If an address is provided, the smart account will not be deployed. This should be used if you intend to interact with an existing smart account.                                                                                                                                                            |
| `nonceKeyManager` | `NonceManager`                                                    | No                                                                                                         | A custom nonce key manager for managing nonces. If provided, it enables support for multiple nonce keys to avoid collisions during parallel user operation execution.                                                                                                                                                                         |

### Hybrid implementation

#### `deployParams`

All Hybrid deploy parameters are required:

| Name          | Type       | Description                                                                                                   |
| ------------- | ---------- | ------------------------------------------------------------------------------------------------------------- |
| `owner`       | `Hex`      | The owner's account address. The owner can be the zero address, indicating that there is no owner configured. |
| `p256KeyIds`  | `Hex[]`    | An array of key identifiers for passkey signers.                                                              |
| `p256XValues` | `bigint[]` | An array of public key x-values for passkey signers.                                                          |
| `p256YValues` | `bigint[]` | An array of public key y-values for passkey signers.                                                          |

#### Example

<Tabs>
<TabItem value ="example.ts">

```ts

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Hybrid,
  deployParams: [account.address, [], [], []],
  deploySalt: '0x',
  signer: { account: account },
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

### Multisig implementation

#### `deployParams`

All Multisig deploy parameters are required:

| Name        | Type     | Description                                              |
| ----------- | -------- | -------------------------------------------------------- |
| `signers`   | `Hex[]`  | An array of EOA signer addresses.                        |
| `threshold` | `bigint` | The number of signers required to execute a transaction. |

#### Example

<Tabs>
<TabItem value="example.ts">

```ts

const signers = [aliceAccount.address, bobAccount.address]
const threshold = 2n

const aliceSmartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.MultiSig,
  deployParams: [signers, threshold],
  deploySalt: '0x',
  signer: [{ account: aliceAccount }],
})
```

</TabItem>
<TabItem value="config.ts">

```ts

export const publicClient = createPublicClient({
  chain,
  transport: http(),
})

const alicePrivateKey = generatePrivateKey()
export const aliceAccount = privateKeyToAccount(alicePrivateKey)

const bobPrivateKey = generatePrivateKey()
export const bobAccount = privateKeyToAccount(bobPrivateKey)
```

</TabItem>
</Tabs>

### Stateless7702 implementation example

<Tabs>
<TabItem value ="example.ts">

```ts

const smartAccount = await toMetaMaskSmartAccount({
  client: publicClient,
  implementation: Implementation.Stateless7702,
  address: account.address,
  signer: { account },
})
```

</TabItem>
<TabItem value ="config.ts">

```ts

export const account = privateKeyToAccount('0x...')
export const publicClient = createPublicClient({
  chain,
  transport: http(),
})
```

</TabItem>
</Tabs>

---

## Types


This page documents the TypeScript [enums](#enums) and [types](#types-1) used in Smart Accounts Kit APIs.

## Enums

### `CaveatType`

Enum representing the [caveat](delegation/caveats.md) type.

| Value                                         | String                               |
| --------------------------------------------- | ------------------------------------ |
| `CaveatType.ApprovalRevocation`               | `"approvalRevocation"`               |
| `CaveatType.AllowedCalldata`                  | `"allowedCalldata"`                  |
| `CaveatType.AllowedMethods`                   | `"allowedMethods"`                   |
| `CaveatType.AllowedTargets`                   | `"allowedTargets"`                   |
| `CaveatType.ArgsEqualityCheck`                | `"argsEqualityCheck"`                |
| `CaveatType.BlockNumber`                      | `"blockNumber"`                      |
| `CaveatType.Deployed`                         | `"deployed"`                         |
| `CaveatType.Erc1155BalanceChange`             | `"erc1155BalanceChange"`             |
| `CaveatType.Erc20BalanceChange`               | `"erc20BalanceChange"`               |
| `CaveatType.Erc20PeriodTransfer`              | `"erc20PeriodTransfer"`              |
| `CaveatType.Erc20Streaming`                   | `"erc20Streaming"`                   |
| `CaveatType.Erc20TransferAmount`              | `"erc20TransferAmount"`              |
| `CaveatType.Erc721BalanceChange`              | `"erc721BalanceChange"`              |
| `CaveatType.Erc721Transfer`                   | `"erc721Transfer"`                   |
| `CaveatType.ExactCalldata`                    | `"exactCalldata"`                    |
| `CaveatType.ExactCalldataBatch`               | `"exactCalldataBatch"`               |
| `CaveatType.ExactExecution`                   | `"exactExecution"`                   |
| `CaveatType.ExactExecutionBatch`              | `"exactExecutionBatch"`              |
| `CaveatType.Id`                               | `"id"`                               |
| `CaveatType.LimitedCalls`                     | `"limitedCalls"`                     |
| `CaveatType.MultiTokenPeriod`                 | `"multiTokenPeriod"`                 |
| `CaveatType.NativeBalanceChange`              | `"nativeBalanceChange"`              |
| `CaveatType.NativeTokenPayment`               | `"nativeTokenPayment"`               |
| `CaveatType.NativeTokenPeriodTransfer`        | `"nativeTokenPeriodTransfer"`        |
| `CaveatType.NativeTokenStreaming`             | `"nativeTokenStreaming"`             |
| `CaveatType.NativeTokenTransferAmount`        | `"nativeTokenTransferAmount"`        |
| `CaveatType.Nonce`                            | `"nonce"`                            |
| `CaveatType.OwnershipTransfer`                | `"ownershipTransfer"`                |
| `CaveatType.Redeemer`                         | `"redeemer"`                         |
| `CaveatType.SpecificActionERC20TransferBatch` | `"specificActionERC20TransferBatch"` |
| `CaveatType.Timestamp`                        | `"timestamp"`                        |
| `CaveatType.ValueLte`                         | `"valueLte"`                         |

### `ExecutionMode`

Enum specifying how delegated executions are processed when [redeeming delegations](delegation/index.md#redeemdelegations).

| Value                         | Description                                                     |
| ----------------------------- | --------------------------------------------------------------- |
| `ExecutionMode.SingleDefault` | Executes a single call and reverts on failure.                  |
| `ExecutionMode.SingleTry`     | Executes a single call and silently continues on failure.       |
| `ExecutionMode.BatchDefault`  | Executes a batch of calls and reverts if any call fails.        |
| `ExecutionMode.BatchTry`      | Executes a batch of calls and silently continues past failures. |

### `Implementation`

Enum representing the [MetaMask smart account](../concepts/smart-accounts.md) implementation type.

| Value                          | Description                                                                                                       |
| ------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `Implementation.Hybrid`        | Supports both ECDSA and WebAuthn (passkey) signers.                                                               |
| `Implementation.MultiSig`      | Supports multiple ECDSA signers with threshold-based signing.                                                     |
| `Implementation.Stateless7702` | Uses [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) to upgrade an EOA to a smart account without deployment. |

### `ScopeType`

Enum representing [delegation scope types](delegation/delegation-scopes.md).

| Value                                 | String                        |
| ------------------------------------- | ----------------------------- |
| `ScopeType.Erc20TransferAmount`       | `"erc20TransferAmount"`       |
| `ScopeType.Erc20Streaming`            | `"erc20Streaming"`            |
| `ScopeType.Erc20PeriodTransfer`       | `"erc20PeriodTransfer"`       |
| `ScopeType.NativeTokenTransferAmount` | `"nativeTokenTransferAmount"` |
| `ScopeType.NativeTokenStreaming`      | `"nativeTokenStreaming"`      |
| `ScopeType.NativeTokenPeriodTransfer` | `"nativeTokenPeriodTransfer"` |
| `ScopeType.Erc721Transfer`            | `"erc721Transfer"`            |
| `ScopeType.OwnershipTransfer`         | `"ownershipTransfer"`         |
| `ScopeType.FunctionCall`              | `"functionCall"`              |

### `TransferWindow`

Enum representing predefined time intervals in seconds for transfer period durations.

| Value                      | Seconds    |
| -------------------------- | ---------- |
| `TransferWindow.Hourly`    | `3600`     |
| `TransferWindow.Daily`     | `86400`    |
| `TransferWindow.Weekly`    | `604800`   |
| `TransferWindow.BiWeekly`  | `1209600`  |
| `TransferWindow.Monthly`   | `2592000`  |
| `TransferWindow.Quarterly` | `7776000`  |
| `TransferWindow.Yearly`    | `31536000` |

## Types

### `AllowedCalldataBuilderConfig`

Defines an expected calldata segment for a single function signature.

| Name         | Type     | Required | Description                                                                                      |
| ------------ | -------- | -------- | ------------------------------------------------------------------------------------------------ |
| `startIndex` | `number` | Yes      | The byte offset in the calldata (including the 4-byte selector) where the expected value starts. |
| `value`      | `Hex`    | Yes      | The expected hex-encoded calldata at that offset.                                                |

### `Caveat`

Represents a restriction or condition applied to a delegation.

| Name       | Type  | Required | Description                                                                                      |
| ---------- | ----- | -------- | ------------------------------------------------------------------------------------------------ |
| `enforcer` | `Hex` | Yes      | The contract address of the <GlossaryTerm term="Caveat enforcer">caveat enforcer</GlossaryTerm>. |
| `terms`    | `Hex` | Yes      | The terms of the <GlossaryTerm term="Caveat">caveat</GlossaryTerm> encoded as hex data.          |
| `args`     | `Hex` | Yes      | Additional arguments required by the caveat enforcer, encoded as hex data.                       |

### `CaveatBuilderConfig`

Optional configuration for [`createCaveatBuilder`](delegation/index.md#createcaveatbuilder).

| Name                                  | Type      | Required | Description                                                                                                                   |
| ------------------------------------- | --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `allowInsecureUnrestrictedDelegation` | `boolean` | No       | Whether to allow unrestricted delegations with no <GlossaryTerm term="Caveat">caveats</GlossaryTerm>. The default is `false`. |

### `Delegation`

Represents a delegation that grants permissions from a <GlossaryTerm term="Delegator account">delegator</GlossaryTerm> to a <GlossaryTerm term="Delegate account">delegate</GlossaryTerm>.

| Name        | Type                    | Required | Description                                                                                                                        |
| ----------- | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `delegate`  | `Hex`                   | Yes      | The address to which the delegation is being granted.                                                                              |
| `delegator` | `Hex`                   | Yes      | The address that is granting the delegation.                                                                                       |
| `authority` | `Hex`                   | Yes      | The parent delegation hash, or `ROOT_AUTHORITY` for creating <GlossaryTerm term="Root delegation">root delegations</GlossaryTerm>. |
| `caveats`   | [`Caveat`](#caveat)`[]` | Yes      | An array of [caveats](delegation/caveats.md) that constrain the delegation.                                                        |
| `salt`      | `Hex`                   | Yes      | The salt for generating the delegation hash. This helps prevent hash collisions when creating identical delegations.               |
| `signature` | `Hex`                   | Yes      | The signature to validate the delegation.                                                                                          |

### `DelegationStruct`

The onchain representation of a [`Delegation`](#delegation), used when ABI-encoding or interacting
directly with the <GlossaryTerm term="Delegation Framework" /> contracts.
It has the same fields as `Delegation`, except `salt` is a `bigint` instead of a `Hex` string.

| Name        | Type                    | Required | Description                                                                                                                        |
| ----------- | ----------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| `delegate`  | `Hex`                   | Yes      | The address to which the delegation is being granted.                                                                              |
| `delegator` | `Hex`                   | Yes      | The address that is granting the delegation.                                                                                       |
| `authority` | `Hex`                   | Yes      | The parent delegation hash, or `ROOT_AUTHORITY` for creating <GlossaryTerm term="Root delegation">root delegations</GlossaryTerm>. |
| `caveats`   | [`Caveat`](#caveat)`[]` | Yes      | An array of [caveats](delegation/caveats.md) that constrain the delegation.                                                        |
| `salt`      | `bigint`                | Yes      | The salt for generating the delegation hash. This helps prevent hash collisions when creating identical delegations.               |
| `signature` | `Hex`                   | Yes      | The signature to validate the delegation.                                                                                          |

### `DecodedRevertReason`

Represents a decoded revert reason from a <GlossaryTerm term="Delegation Framework" /> error. Returned by [`decodeRevertData`](delegation/index.md#decoderevertdata) and [`decodeRevertReason`](delegation/index.md#decoderevertreason).

| Name        | Type     | Required | Description                        |
| ----------- | -------- | -------- | ---------------------------------- |
| `errorName` | `string` | Yes      | The name of the decoded error.     |
| `message`   | `string` | Yes      | The decoded revert reason message. |
| `rawData`   | `Hex`    | Yes      | The raw ABI-encoded revert data.   |

### `ExactCalldataBuilderConfig`

Defines the exact calldata the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> is allowed to call.

| Name       | Type  | Required | Description                                         |
| ---------- | ----- | -------- | --------------------------------------------------- |
| `calldata` | `Hex` | Yes      | The exact calldata the delegate is allowed to call. |

### `ExecutionStruct`

Represents a single execution to perform on behalf of a <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>.

| Name       | Type      | Required | Description                                                        |
| ---------- | --------- | -------- | ------------------------------------------------------------------ |
| `target`   | `Address` | Yes      | Address of the contract or recipient that the call is directed to. |
| `value`    | `bigint`  | Yes      | Value of native tokens to send along with the call in wei format.  |
| `callData` | `Hex`     | Yes      | Encoded function data to be executed on the target address.        |

### `GetGrantedExecutionPermissionsResult`

The return type of [`getGrantedExecutionPermissions`](advanced-permissions/wallet-client.md#getgrantedexecutionpermissions). An array of [`PermissionResponse`](#permissionresponse) objects.

### `GetSupportedExecutionPermissionsResult`

The return type of [`getSupportedExecutionPermissions`](advanced-permissions/wallet-client.md#getsupportedexecutionpermissions). A `Record<string,` [`SupportedPermissionInfo`](#supportedpermissioninfo)`>` keyed by permission type.

### `PartialSignature`

Represents a single <GlossaryTerm term="Signer">signer</GlossaryTerm>'s contribution to a multisig aggregated signature.

| Name        | Type            | Required | Description                                                                           |
| ----------- | --------------- | -------- | ------------------------------------------------------------------------------------- |
| `signer`    | `Address`       | Yes      | The address of the signer.                                                            |
| `signature` | `Hex`           | Yes      | The signer's signature over the user operation.                                       |
| `type`      | `SignatureType` | Yes      | The signature type to represent signature algorithm. Only supported value is `ECDSA`. |

### `RedelegatePermissionContextReturnType`

Return type of [`redelegatePermissionContext`](erc7710/wallet-client.md#redelegatepermissioncontext) and [`redelegatePermissionContextOpen`](erc7710/wallet-client.md#redelegatepermissioncontextopen).

| Name                | Type                        | Description                                                     |
| ------------------- | --------------------------- | --------------------------------------------------------------- |
| `delegation`        | [`Delegation`](#delegation) | The signed redelegation object.                                 |
| `permissionContext` | `Hex`                       | ABI-encoded delegation chain with the new delegation prepended. |

### `PermissionResponse`

Represents a granted <GlossaryTerm term="Advanced Permissions">Advanced Permission</GlossaryTerm>.

| Name                | Type                                       | Required | Description                                                                                |
| ------------------- | ------------------------------------------ | -------- | ------------------------------------------------------------------------------------------ |
| `chainId`           | `number`                                   | Yes      | The chain ID for which the permission was granted.                                         |
| `from`              | `Address`                                  | Yes      | The account address that granted the permission.                                           |
| `to`                | `Hex`                                      | Yes      | The account address that received the permission.                                          |
| `permission`        | `PermissionTypes`                          | Yes      | The granted [permission](advanced-permissions/permissions.md) details.                     |
| `rules`             | `Record<string, unknown>[]`                | No       | The rules applied to the permission. For example, permission expiry.                       |
| `context`           | `Hex`                                      | Yes      | The permission context (encoded delegation list) used when redeeming the permission.       |
| `dependencies`      | `{ factory: Address, factoryData: Hex }[]` | Yes      | Factory dependencies for account deployment.                                               |
| `delegationManager` | `Address`                                  | Yes      | The address of the <GlossaryTerm term="Delegation Manager" /> contract for the permission. |

### `RequestExecutionPermissionsReturnType`

The return type of [`requestExecutionPermissions`](advanced-permissions/wallet-client.md#requestexecutionpermissions). An array of [`PermissionResponse`](#permissionresponse) objects.

### `SmartAccountsEnvironment`

An object containing the contract addresses required to interact with the <GlossaryTerm term="Delegation Framework" /> on a specific chain.

| Name                | Type                  | Required | Description                                                                                                                           |
| ------------------- | --------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------- |
| `DelegationManager` | `Hex`                 | Yes      | The address of the <GlossaryTerm term="Delegation Manager" /> contract.                                                               |
| `EntryPoint`        | `Hex`                 | Yes      | The address of the ERC-4337 EntryPoint contract.                                                                                      |
| `SimpleFactory`     | `Hex`                 | Yes      | The address of the factory contract for deploying <GlossaryTerm term="MetaMask smart account">MetaMask Smart Accounts</GlossaryTerm>. |
| `implementations`   | `Record<string, Hex>` | Yes      | A map of MetaMask smart account implementation types to their deployed addresses.                                                     |
| `caveatEnforcers`   | `Record<string, Hex>` | Yes      | A map of caveat enforcer types to their deployed addresses.                                                                           |

### `SupportedPermissionInfo`

Describes a supported <GlossaryTerm term="Advanced Permissions">Advanced Permission</GlossaryTerm> type. Used in [`GetSupportedExecutionPermissionsResult`](#getsupportedexecutionpermissionsresult).

| Name        | Type       | Required | Description                                                                 |
| ----------- | ---------- | -------- | --------------------------------------------------------------------------- |
| `chainIds`  | `number[]` | Yes      | The chain IDs on which the permission type is supported.                    |
| `ruleTypes` | `string[]` | Yes      | The rule types supported for the permission type (for example, `"expiry"`). |

### `MaybeDeferred`

Represents a value that can be provided directly or derived at runtime from [`PaymentRequirements`](#paymentrequirements).

```ts
type MaybeDeferred<TResult> =
  | TResult
  | ((requirements: PaymentRequirements) => Promise<TResult> | TResult)
```

### `PaymentRequirements`

Represents the payment requirements returned by an x402 server. [`createx402DelegationProvider`](x402.md#createx402delegationprovider) uses these values to scope and construct the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>.

| Name                | Type                      | Required | Description                                                                                                   |
| ------------------- | ------------------------- | -------- | ------------------------------------------------------------------------------------------------------------- |
| `scheme`            | `string`                  | Yes      | The payment scheme identifier.                                                                                |
| `network`           | `string`                  | Yes      | The [CAIP](https://namespaces.chainagnostic.org/eip155/caip2) network identifier. For example, `eip155:8453`. |
| `asset`             | `string`                  | Yes      | The token contract address for the payment asset.                                                             |
| `amount`            | `string`                  | Yes      | The payment amount in the token's smallest unit.                                                              |
| `payTo`             | `string`                  | Yes      | The recipient address for the payment.                                                                        |
| `maxTimeoutSeconds` | `number`                  | Yes      | The maximum time in seconds before the payment expires.                                                       |
| `extra`             | `Record<string, unknown>` | No       | Additional context for x402, such as the asset transfer method.                                               |

### `RedeemersConfig`

Configuration for the redeemer constraint used in [`createx402DelegationProvider`](x402.md#createx402delegationprovider).

| Name               | Type                                           | Required | Description                                                                                             |
| ------------------ | ---------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------- |
| `requireRedeemers` | `boolean`                                      | Yes      | Whether at least one redeemer constraint must exist.                                                    |
| `addresses`        | [`MaybeDeferred`](#maybedeferred)`<Address[]>` | No       | The addresses that are allowed to redeem the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>. |

### `ValueLteBuilderConfig`

| Name       | Type     | Required | Description                                                                                                              |
| ---------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------ |
| `maxValue` | `bigint` | Yes      | The maximum native token amount the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> can transfer per call. |

---

## x402 API reference


The following API methods are related to x402 to create payments using <GlossaryTerm term="Delegation">delegation</GlossaryTerm>.

## `createx402DelegationProvider`

Creates a delegation provider function too be used with `x402Erc7710Client`.

The provider resolves creates an <GlossaryTerm term="Open delegation">open delegation</GlossaryTerm>, signs it, and returns an ABI-encoded delegation
chain as a hex string. The provider internally appends redeemer, payee, and expiry <GlossaryTerm term="Caveat">caveats</GlossaryTerm> when the
existing caveats, or the <GlossaryTerm term="Root delegation">root delegation</GlossaryTerm> doesn't have it.

### Parameters

| Name                      | Type                                                                                                                    | Required | Description                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `account`                 | [`MaybeDeferred`](./types.md#maybedeferred)`<Account>`                                                             | Yes      | The Viem Account that signs the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>.                                                                                                                                                                                                                                                                                        |
| `environment`             | [`MaybeDeferred`](./types.md#maybedeferred)`<`[`SmartAccountsEnvironment`](./types.md#smartaccountsenvironment)`>` | No       | Environment to resolve the smart contracts for the current chain. If omitted, resolved automatically from the chain ID in the payment requirements.                                                                                                                                                                                                                               |
| `from`                    | [`MaybeDeferred`](./types.md#maybedeferred)`<Hex>`                                                                 | No       | The address that is granting the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>. The default is `account`.                                                                                                                                                                                                                                                             |
| `salt`                    | [`MaybeDeferred`](./types.md#maybedeferred)`<Hex>`                                                                 | No       | The salt for generating the delegation hash. The default is a random 32-byte value.                                                                                                                                                                                                                                                                                               |
| `caveats`                 | [`MaybeDeferred`](./types.md#maybedeferred)`<Caveats>`                                                             | No       | <GlossaryTerm term="Caveat">Caveats</GlossaryTerm> that further refine the authority granted by the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>. [`redeemer`](./delegation/caveats.md#redeemer), [`allowedTargets`](./delegation/caveats.md#allowedtargets), and [`timestamp`](./delegation/caveats.md#timestamp) caveats are auto-appended if not already present. |
| `parentPermissionContext` | [`MaybeDeferred`](./types.md#maybedeferred)`<PermissionContext>`                                                   | No       | Parent chain as `Hex` or as decoded [`Delegation`](./types.md#delegation) values (leaf first). Use this when creating a <GlossaryTerm term="Redelegation">redelegation</GlossaryTerm>.                                                                                                                                                                                            |
| `expirySeconds`           | [`MaybeDeferred`](./types.md#maybedeferred)`<number>`                                                              | No       | Relative expiry in seconds. Adds a timestamp caveat if no tighter constraint exists.                                                                                                                                                                                                                                                                                              |
| `redeemers`               | [`MaybeDeferred`](./types.md#maybedeferred)`<`[`RedeemersConfig`](./types.md#redeemersconfig)`>`                   | No       | Constrains the addresses that are allowed to redeem the <GlossaryTerm term="Delegation">delegation</GlossaryTerm>. Use this to restrict redemption to specific facilitators.                                                                                                                                                                                                      |

### Example

<Tabs>
<TabItem value="delegation" label="Delegation">

```ts

const account = privateKeyToAccount(privateKey)

const erc7710Client = new x402Erc7710Client({
  delegationProvider: createx402DelegationProvider({
    account,
  }),
})
```

</TabItem>
<TabItem value="redelegation" label="Redelegation">

```ts

const parentPermissionContext = '0x...' // Previously stored/issued permission context.

const delegationProvider = createx402DelegationProvider({
  account,
  parentPermissionContext,
})
```

</TabItem>
</Tabs>

## `parseEip155ChainId`

Parses an [EIP-155 CAIP](https://namespaces.chainagnostic.org/eip155/caip2) network identifier into a numeric chain ID.

### Parameters

| Name      | Type     | Required | Description                                               |
| --------- | -------- | -------- | --------------------------------------------------------- |
| `network` | `string` | Yes      | EIP-155 CAIP network identifier. For example, `eip155:1`. |

### Example

```ts

// Returns 137
const chainId = parseEip155ChainId('eip155:137')
```

---

## AA21 didn't pay prefund


The `EntryPoint` contract reverts with `AA21 didn't pay prefund` when a <GlossaryTerm term="MetaMask smart account">smart account</GlossaryTerm> doesn't
have enough native token balance to cover the gas cost of the <GlossaryTerm term="User operation">user operation</GlossaryTerm>.

Before executing a user operation, the `EntryPoint` requires the sender account to prefund the
expected gas cost. If the account's balance is lower than the required prefund, the `EntryPoint`
reverts the operation.

## Solution

### Fund the smart account

Fund the smart account with enough native tokens to cover the required prefund.
Use Viem's [`estimateUserOperationGas`](https://viem.sh/account-abstraction/actions/bundler/estimateUserOperationGas)
to get the gas estimates from your <GlossaryTerm term="Bundler">bundler</GlossaryTerm>, then calculate the required prefund based on the
`EntryPoint` version.

<Tabs>
<TabItem value="v0.7" label="EntryPoint v0.7">

```typescript

const gasEstimate = await bundlerClient.estimateUserOperationGas({
  account: smartAccount,
  calls: [{ to: '0x...', value: 0n }],
})

const { maxFeePerGas } = await publicClient.estimateFeesPerGas()

const requiredGas =
  gasEstimate.verificationGasLimit +
  gasEstimate.callGasLimit +
  (gasEstimate.paymasterVerificationGasLimit ?? 0n) +
  (gasEstimate.paymasterPostOpGasLimit ?? 0n) +
  gasEstimate.preVerificationGas

const requiredPrefund = requiredGas * maxFeePerGas

const balance = await publicClient.getBalance({
  address: smartAccount.address,
})

if (balance < requiredPrefund) {
  console.log(
    `Insufficient balance: account has ${formatEther(balance)} ETH, ` +
      `but needs ${formatEther(requiredPrefund)} ETH`
  )
}
```

</TabItem>
<TabItem value="v0.6" label="EntryPoint v0.6">

```typescript

const gasEstimate = await bundlerClient.estimateUserOperationGas({
  account: smartAccount,
  calls: [{ to: '0x...', value: 0n }],
})

const { maxFeePerGas } = await publicClient.estimateFeesPerGas()

const requiredGas =
  gasEstimate.callGasLimit + gasEstimate.verificationGasLimit + gasEstimate.preVerificationGas

const requiredPrefund = requiredGas * maxFeePerGas

const balance = await publicClient.getBalance({
  address: smartAccount.address,
})

if (balance < requiredPrefund) {
  console.log(
    `Insufficient balance: account has ${formatEther(balance)} ETH, ` +
      `but needs ${formatEther(requiredPrefund)} ETH`
  )
}
```

</TabItem>
</Tabs>

### Use a paymaster

You can use a <GlossaryTerm term="Paymaster">paymaster</GlossaryTerm> to sponsor the gas fees for the smart account, so the account doesn't
need to hold native tokens. For more information about configuring a paymaster, see [Send a gasless transaction](../guides/smart-accounts/send-gasless-transaction.md).

---

## Allowance exceeded


Spending limit [caveat enforcers](../concepts/delegation/caveat-enforcers.md) revert with an
`allowance-exceeded` error in the following cases.

## Spending limit exceeded

The delegation's spending limit has been fully or partially used up by previous redemptions.
Enforcers track cumulative spending onchain using the delegation hash as a key, and revert when
the next transfer exceeds the allowed limit.

### Solution

Use the [`CaveatEnforcerClient`](../reference/delegation/caveat-enforcer-client.md) to check the
available amount before redeeming the delegation.

If the available amount is insufficient, you must wait for the next period (for periodic
enforcers) or for more tokens to accrue (for streaming enforcers). For fixed-limit enforcers,
create a new delegation with a higher limit.

## Delegation hash collision

If you create a new delegation with the same parameters as a previous delegation, both produce
the same delegation hash.

Enforcers track spent amounts using the delegation hash as a key. When two delegations share the
same hash, they also share the same spent balance. This means the new delegation can immediately
revert with `allowance-exceeded`, even if you haven't redeemed it before.

### Solution

Use a unique `salt` when creating the delegation. This produces a different delegation hash,
giving the new delegation a fresh spending allowance.

```typescript

const delegation = createDelegation({
  scope: {
    type: ScopeType.Erc20TransferAmount,
    tokenAddress: '0xc11F3a8E5C7D16b75c9E2F60d26f5321C6Af5E92',
    // USDC has 6 decimal places.
    maxAmount: parseUnits('10', 6),
  },
  salt: '0x00131412',
  to: delegateAccount,
  from: delegatorAccount,
  environment: delegatorAccount.environment,
})
```

---

## Error codes


The following tables describe error codes from the [MetaMask Delegation Framework contracts](https://github.com/metamask/delegation-framework). Use a decoder such as
[calldata.swiss-knife.xyz](https://calldata.swiss-knife.xyz/decoder) to identify error signatures from raw revert data.

## Delegation Manager error codes

| Error code   | Error name                             | Description                                                                                                                                                                     |
| ------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0xb5863604` | `InvalidDelegate()`                    | The caller is not the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> specified in the delegation. [Troubleshoot an invalid delegate.](./invalid-delegate.md)     |
| `0xb9f0f171` | `InvalidDelegator()`                   | The caller is not the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm> specified in the delegation. [Troubleshoot an invalid delegator.](./invalid-delegator.md) |
| `0x05baa052` | `CannotUseADisabledDelegation()`       | The delegation has been disabled by the delegator.                                                                                                                              |
| `0xded4370e` | `InvalidAuthority()`                   | The delegation chain authority validation failed. The authority hash of a child delegation does not match the hash of its parent delegation.                                    |
| `0x1bcaf69f` | `BatchDataLengthMismatch()`            | The array lengths do not match in a batch `redeemDelegations` contract call.                                                                                                    |
| `0x005ecddb` | `AlreadyDisabled()`                    | The delegation has already been disabled.                                                                                                                                       |
| `0xf2a5f75a` | `AlreadyEnabled()`                     | The delegation is already enabled.                                                                                                                                              |
| `0xf645eedf` | `ECDSAInvalidSignature()`              | Invalid ECDSA signature format.                                                                                                                                                 |
| `0xfce698f7` | `ECDSAInvalidSignatureLength(uint256)` | The ECDSA signature length is incorrect.                                                                                                                                        |
| `0xac241e11` | `EmptySignature()`                     | The signature is empty.                                                                                                                                                         |
| `0xd93c0665` | `EnforcedPause()`                      | The <GlossaryTerm term="Delegation Manager" /> contract is paused by the owner.                                                                                                 |
| `0x3db6791c` | `InvalidEOASignature()`                | EOA signature verification failed. [Troubleshoot an invalid EOA signature.](./invalid-signature.md)                                                                             |
| `0x155ff427` | `InvalidERC1271Signature()`            | Smart contract signature (ERC-1271) verification failed.                                                                                                                        |
| `0x118cdaa7` | `OwnableUnauthorizedAccount(address)`  | An unauthorized account attempted an owner only action.                                                                                                                         |
| `0x1e4fbdf7` | `OwnableInvalidOwner(address)`         | Invalid owner address in an ownership transfer.                                                                                                                                 |
| `0xf6b6ef5b` | `InvalidShortString()`                 | A string parameter is too short.                                                                                                                                                |
| `0xaa0ea2d8` | `StringTooLong(string)`                | A string parameter exceeds the maximum length.                                                                                                                                  |

## Smart account error codes

| Error code   | Error name                    | Description                                                                 |
| ------------ | ----------------------------- | --------------------------------------------------------------------------- |
| `0xd663742a` | `NotEntryPoint()`             | The caller is not the EntryPoint contract.                                  |
| `0x0796d945` | `NotEntryPointOrSelf()`       | The caller is neither the EntryPoint contract nor the smart account itself. |
| `0x1a4b3a04` | `NotDelegationManager()`      | The caller is not the <GlossaryTerm term="Delegation Manager" /> contract.  |
| `0xb96fcfe4` | `UnsupportedCallType(bytes1)` | The execution call type is not supported.                                   |
| `0x1187dc06` | `UnsupportedExecType(bytes1)` | The execution type is not supported.                                        |
| `0x29c3b7ee` | `NotSelf()`                   | The caller is not the smart account itself.                                 |

## Caveat enforcer error codes

| Error string                                        | Description                                                                                                                                                                  |
| --------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `AllowedTargetsEnforcer:target-address-not-allowed` | When redeeming a delegation with an `allowedTargets` caveat, the execution's target address is not in the allowed list.                                                      |
| `AllowedTargetsEnforcer:invalid-terms-length`       | When creating a delegation with an `allowedTargets` caveat, the encoded terms length is not a multiple of 20 bytes (Ethereum address).                                       |
| `ERC20TransferAmountEnforcer:invalid-terms-length`  | When creating a delegation with an `erc20TransferAmount` caveat, the encoded terms are not exactly 52 bytes (20 byte Ethereum address + 32 byte amount).                     |
| `ERC20TransferAmountEnforcer:invalid-contract`      | When redeeming a delegation with an `erc20TransferAmount` caveat, the execution targets a different contract than the allowed token address.                                 |
| `ERC20TransferAmountEnforcer:invalid-method`        | When redeeming a delegation with an `erc20TransferAmount` caveat, the execution calls a function other than `transfer(address,uint256)`.                                     |
| `ERC20TransferAmountEnforcer:allowance-exceeded`    | When redeeming a delegation with an `erc20TransferAmount` caveat, the cumulative transfer amount exceeds the allowed limit.                                                  |
| `CaveatEnforcer:invalid-call-type`                  | When redeeming a delegation, the execution uses a batch call type, but the caveat enforcer only supports single calls.                                                       |
| `CaveatEnforcer:invalid-execution-type`             | When redeeming a delegation, the execution uses a non-default [execution mode](../reference/types.md#executionmode), but the caveat enforcer only supports the default mode. |

---

## Invalid delegate


The <GlossaryTerm term="Delegation Manager" /> reverts with `InvalidDelegate()` in the following two cases.

## Account is not the delegate

The account redeeming the delegation is not the <GlossaryTerm term="Delegate account">delegate</GlossaryTerm> specified in the delegation.
The Delegation Manager checks that `msg.sender` matches the `delegate` field of
the delegation, unless it's an [open delegation](../reference/delegation/index.md#createopendelegation).

### Solution

Verify that the account redeeming the delegation matches the address in the
delegation's `to` field. If the delegate is a smart account, send the <GlossaryTerm term="User operation">user operation</GlossaryTerm>
from that smart account.

## Broken redelegation chain

When Delegation Manager validates a [redelegation chain](../guides/delegation/create-redelegation.md), each child delegation's <GlossaryTerm term="Delegator account">`delegator`</GlossaryTerm>
must match the parent delegation's <GlossaryTerm term="Delegate account">`delegate`</GlossaryTerm>. If any link in the chain fails this check, the
authority is invalid.

### Solution

Verify that the redelegation chain is consistent. For each pair of adjacent
delegations, the child's `delegator` must be the parent's `delegate`.

This error can also occur if the delegations are not passed in the correct order. The
delegation array order should be from leaf to root.

For example, if the delegation chain is Alice to Bob to Carol, the order should be following:

```ts
const rootDelegation = createDelegation({
  from: '0xAlice',
  to: '0xBob',
  //..
})

const leafDelegation = createDelegation({
  from: 'OxBob',
  to: '0xCarol',
  parentDelegation: rootDelegation,
  // ...
})

const data = DelegationManager.encode.redeemDelegations({
  // Make sure the order is from leaf to root.
  // Passing them in the wrong order causes the authority validation to fail.
  delegations: [[leafDelegation, rootDelegation]],
  modes: [ExecutionMode.SingleDefault],
  executions: [[execution]],
})
```

---

## Invalid delegator


The <GlossaryTerm term="Delegation Manager" /> reverts with `InvalidDelegator()` when the caller is not the <GlossaryTerm term="Delegator account">delegator</GlossaryTerm>
specified in the delegation.

This error is thrown by the `disableDelegation` and `enableDelegation` contract functions. Only the
account that created the delegation can [disable](../guides/delegation/disable-delegation.md)
or enable it.

## Solution

Verify that you're sending the transaction from the delegator's account. If the delegator is a smart account, submit a <GlossaryTerm term="User operation">user operation</GlossaryTerm> through the smart account.

```typescript

// Generate calldata to disable the delegation.
const disableCalldata = DelegationManager.encode.disableDelegation({
  delegation: signedDelegation, // Signed by delegatorSmartAccount
})

const userOpHash = await bundlerClient.sendUserOperation({
  account: delegatorSmartAccount,
  calls: [
    {
      to: delegatorSmartAccount.environment.DelegationManager,
      data: disableCalldata,
    },
  ],
})
```

---

## Invalid EOA signature


The <GlossaryTerm term="Delegation Manager" /> reverts with `InvalidEOASignature()` in the following cases.

## Smart account is not deployed

The [root delegation's](../concepts/delegation/overview.md#root-delegation) <GlossaryTerm term="Delegator account">delegator</GlossaryTerm> must be a
<GlossaryTerm term="MetaMask smart account" />. The Delegation Manager checks the delegator code to determine
whether it is an <GlossaryTerm term="Externally owned account (EOA)">EOA</GlossaryTerm> or a smart account.

If the smart account is not deployed yet, its address has no contract code. The Delegation
Manager treats the address as an EOA and attempts ECDSA signature recovery. Because the
delegation was signed by the smart account, signature recovery returns a different address,
and the call reverts.

### Solution

Verify that the smart account used as the delegator is deployed before redeeming the delegation. The
smart account can be either an ERC-4337 smart account or an EIP-7702 upgraded EOA.

For an ERC-4337 smart account, the first user operation sent from that account deploys it
automatically. For more information, see [Deploy a smart account](../guides/smart-accounts/deploy-smart-account.md).

For an EIP-7702-upgraded EOA, verify that you submit the authorization to set the account code
before redeeming the delegation.

```ts

// Get the EOA account code
const code = await publicClient.getCode({
  address,
})

if (code) {
  // According to EIP-7702, the code format is 0xef0100 || address.
  // Remove the first 8 characters (0xef0100) to get the delegator address.
  const delegatorAddress = `0x${code.substring(8)}`

  const statelessDelegatorAddress = getSmartAccountsEnvironment(chain.id).implementations
    .EIP7702StatelessDeleGatorImpl

  // If the account isn't upgraded to a MetaMask smart account, you can
  // either upgrade programmatically or ask the user to switch to a smart account manually.
  const isAccountUpgraded =
    delegatorAddress.toLowerCase() === statelessDelegatorAddress.toLowerCase()
}
```

To upgrade an EOA to a MetaMask smart account, see the [EIP-7702 quickstart](../get-started/smart-account-quickstart/eip7702.md).

## Incorrect signer

The delegation was signed with an account that doesn't correspond to the delegator
address. When the delegator is an EOA, the Delegation Manager recovers the signer from
the EIP-712 typed data hash and compares it to the `delegator` field. If they don't
match, the transaction reverts.

This occurs when redeeming a [delegation chain](../guides/delegation/create-redelegation.md). An
intermediate or leaf delegation has an EOA as the delegator, but the delegation is signed by an
account other than the expected delegator.

### Solution

Verify that the private key used to sign the delegation corresponds to the delegator address. For
more information, see the [`signDelegation`](../reference/delegation/index.md#signdelegation) reference.

## Incorrect chain ID or Delegation Manager

The EIP-712 domain separator used for signing the delegation includes the chain ID and the Delegation Manager contract
address. If the delegation was signed on a different chain or against a different
Delegation Manager, the recovered address won't match.

### Solution

Verify that the chain ID and Delegation Manager contract address you use when signing match the
chain and contract where you redeem the delegation.

---

## User operation reverted


A <GlossaryTerm term="User operation">user operation</GlossaryTerm> reverts with reason `0x` when validation succeeds, but execution fails without a
revert reason. This differs from AA-coded `EntryPoint` contract errors such as `AA23`, `AA25`,
or `AA21`.

When the `EntryPoint` contract calls the smart account's execution function, it performs a low-level
`call` internally. If that inner call reverts with empty data, the bundler reports
reason `0x` with no additional details.

The following sections describe common causes and how to troubleshoot them.

## Function doesn't exist

The `callData` encodes a call from the smart account to a target contract, but the function
selector doesn't match any function on that contract, and no fallback function exists. The EVM
reverts with empty data.

This commonly happens when:

- The function selector has a typo or doesn't match the target's ABI.
- The target address is wrong or points to a different contract.
- The target contract isn't deployed on the current chain.

### Solution

Decode `callData` and verify the inner call. Confirm that the target address has deployed code
and that the function selector matches the target's ABI.

```typescript
const code = await publicClient.getCode({
  address: targetAddress,
})

if (!code) {
  console.log('No contract deployed at this address')
}
```

## Bare revert without a message

The target contract uses `require(false)` or `revert` without a reason string. The revert
returns empty data. Contracts commonly use bare reverts in access control checks, reentrancy locks,
or guard functions.

### Solution

Look at the target contract's source code to identify which `require` or `revert` your call
parameters could trigger.

Use [Tenderly](https://tenderly.co) to simulate the transaction and pinpoint the exact line. See the
[Tenderly debugger documentation](https://docs.tenderly.co/debugger) for details.

## Out of gas in the inner call

Smart accounts use a low-level `call` internally in their `execute` function. When the inner
call runs out of gas, the call returns `false` with empty return data.

This differs from the `AA95` error code, which applies when `handleOps` itself runs out of gas.
In this case, `callGasLimit` might be enough for the smart account's execution overhead but not
enough for the actual target contract call.

### Solution

Increase `callGasLimit`. If you estimate gas manually, try doubling the value. Target
contracts doing complex operations often need more gas than default estimates provide.

## Insufficient balance or allowance

The inner call performs an ERC-20 `transferFrom` but the smart account hasn't approved the
spender, or doesn't hold enough tokens. Some ERC-20 implementations use bare `require` statements
that revert without a reason string.

### Solution

Check that the smart account has sufficient token balance and approvals for the operation.

```typescript

const balance = await publicClient.readContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: 'balanceOf',
  args: [smartAccount.address],
})

const allowance = await publicClient.readContract({
  address: tokenAddress,
  abi: erc20Abi,
  functionName: 'allowance',
  args: [smartAccount.address, spenderAddress],
})
```

## Manual debugging

If the cause isn't immediately clear, follow these steps:

1. Decode the inner call: Extract the `(to, value, data)` tuple from your `callData` to
   confirm what the smart account executes.
2. Use Tenderly: Simulate the user operation in [Tenderly](https://tenderly.co) to get a full
   execution trace. The trace view shows the exact line where the inner call reverts.
3. Check the basics: Verify the target has deployed code, the smart account has enough
   ETH and tokens, and the function selector is correct.
