Skip to main content

Manage delegations

Delegation is the ability for an account owner (the delegator) to grant permission to another smart contract account (SCA) or externally owned account (EOA) to perform specific actions on the delegator's behalf, under defined rules and conditions. This page provides instructions to complete specific tasks within the delegation lifecycle.

note

Delegations are compatible with ERC-7710 and ERC-7715, to support a standardized minimal interface.

Prerequisites

Create a delegation

A delegation is an instance of DelegationStruct, where delegator is the account granting permission to the delegate account. Caveats are constraints placed on the granted permission.

export type DelegationStruct = {
delegate: Hex;
delegator: Hex;
authority: Hex;
caveats: CaveatStruct[];
salt: bigint;
signature: Hex;
};

The following is an example of creating a delegation using the provided helper function:

import {
createDelegation,
} from "@codefi/delegator-core-viem";

...

const delegation = createDelegation(
delegatorClient.account.address,
'0x2FcB88EC2359fA635566E66415D31dD381CF5585',
);
note

This code sample assumes the existence of a delegatorClient.

Restrict a delegation

In the previous example, no caveats enforcers were provided, which would grant the delegate complete control over the delegator's account. While this level of access might be acceptable in certain scenarios, such as delegating to another account you own or to a trusted family member, it is essentially equivalent to handing over your private keys.

Important

We strongly recommend applying caveats enforcers to limit delegated permissions.

The MetaMask Delegation Toolkit provides some out-of-the-box caveat enforcers that cover common use cases. For more granular or custom control, you can also create a custom caveat enforcer.

You can apply multiple caveats to a single delegation by adding the address of each caveat enforcer to the caveats array in the delegation struct.

tip

We recommend using the CaveatBuilder interface to easily apply multiple caveat enforcers to a delegation. Learn more in Restrict a delegation.

Stacking caveats in this way enables highly customizable access control. For example, using a combination of out-of-the-box caveat enforcers can result in a delegation with the caveats that the delegate can:

  1. Only send up to 100 USDC.
  2. Only send it to Alice.
  3. Only send funds twice.

Open delegations

In some cases, it might be optimal to create more open-ended delegations by not specifying a single delegate.

Open delegations can be redeemed by any account that meets the requirements set by the caveat enforcers.

To create an open delegation, set the delegate to the special value address(0xa11).

Sign a delegation

The delegator must sign a delegation in order for it to be valid. The following is an example of signing a delegation:

const signedDelegation = await delegatorClient.signDelegation(delegation);
note

This code sample assumes the existence of a delegatorClient.

note

The user interaction this triggers depends on the configured signer.

Store a delegation

important

Delegations often need to be stored for extended periods of time, so it's crucial to store them securely until they are redeemed.

The MetaMask Delegation Toolkit offers a DelegationStorageClient to provide storage for signed delegations.

Import the DelegationStorageClient from the @codefi/delegator-core-viem package. When using this service, delegations are stored in MetaMask's secure storage to ensure they are available when needed.

See more information about storing and retrieving delegations using DelegationStorageClient.

Redeem a delegation

Redeeming a delegation occurs when the delegate initiates an on-chain action within the bounds of the caveats. For example, Bob (the delegate) might transfer an NFT from Alice's account (the delegator) to Carol's account.

note

If there are no caveats limiting it, delegations can be redeemed multiple times.

The delegation must be signed by the delegator, and is redeemed by sending a user operation that executes the delegated action.

The following is an example of redeeming a delegation:

const action = {
to: account.address,
data: "0x",
value: 0n,
};

const signedUserOp = await client.createAndSignInvokeUserOp(
[delegation],
action,
userOpOptions,
nonce,
);

const { result: userOpHash } = await bundler.sendUserOp(
signedUserOp,
client.account.environment.EntryPoint,
);
note

This code sample assumes the existence of a valid delegation to redeem.

Redelegate a delegation

Redelegating is the act of assigning an existing delegation to a new account. When redelegating:

  • The account redelegating retains the same permissions as before they redelegated, and any caveats applied to their delegation are unchanged.
  • All caveats applied to the delegation are maintained and enforced on the account that receives the redelegation.

The following is an example of redelegating a delegation:

import {
createDelegation,
getDelegationHashOffchain,
} from "@codefi/delegator-core-viem";

const delegate = ACCOUNT_RECEIVING_REDELEGATION;
const delegator = ACCOUNT_WITH_EXISTING_DELEGATION;
const authority = getDelegationHashOffchain(delegation)

createDelegation(delegate, delegator, authority);