Skip to main content

Redeem a delegation

A delegate can redeem a delegation by submitting either a user operation or a regular transaction, depending on whether the delegate is a smart contract account (SCA) or externally owned account (EOA).

The redeem transaction is sent to the DelegationManager contract, which validates the delegation and executes actions on the delegator's behalf. To prepare the call data for the redeem transaction, use the redeemDelegation utility function. The function supports batch redemption, allowing multiple delegations to be processed within a single transaction.

Prerequisites

Redeem a delegation

Redeem a delegation with a smart contract account (SCA) or an externally owned account (EOA).

Redeem with an SCA

The following example demonstrates how to submit a user operation to redeem a delegation. It assumes you have a delegation signed by the delegator, and that the delegate is an SCA.

import { 
DelegationFramework,
SINGLE_DEFAULT_MODE,
ExecutionStruct
} from "@metamask/delegation-toolkit";
import { bundlerClient, pimlicoClient } from "./client.ts";
import { delegateSmartAccount } from "./account.ts";

const delegations: Delegation[] = [ signedDelegation ];

// SINGLE_DEFAULT_MODE is the default execution mode.
const mode: ExecutionMode = SINGLE_DEFAULT_MODE;

// For SINGLE execution modes, the executions array must be length 1.
const executions: ExecutionStruct[] = [{
target: zeroAddress,
value: 0n,
callData: "0x"
}];

const redeemDelegationCalldata = DelegationFramework.encode.redeemDelegations({
delegations: [ delegations ],
modes: [ mode ],
executions: [ executions ]
});

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

const userOperationHash = await bundlerClient.sendUserOperation({
account: delegateSmartAccount,
calls: [
{
to: "<DELEGATOR-SMART-ACCOUNT-ADDRESS>",
data: redeemDelegationCalldata
}
],
...fee
});

Redeem with an EOA

The following example demonstrates how to submit a transaction to redeem a delegation. It assumes you have a delegation signed by the delegator, and that the delegate is an EOA.

import { 
DelegationFramework,
SINGLE_DEFAULT_MODE,
ExecutionStruct
} from "@metamask/delegation-toolkit";
import { lineaSepolia as chain } from "viem/chains";
import { delegateWalletClient } from "./account.ts";

const delegations: Delegation[] = [ signedDelegation ];

// SINGLE_DEFAULT_MODE is the default execution mode.
const mode: ExecutionMode = SINGLE_DEFAULT_MODE;

// For SINGLE execution modes, the executions array must be length 1.
// Modify the executions to fit your use case.
const executions: ExecutionStruct[] = [{
target: zeroAddress,
value: 0n,
callData: "0x"
}];

const redeemDelegationCalldata = DelegationFramework.encode.redeemDelegations({
delegations: [ delegations ],
modes: [ mode ],
executions: [ executions ]
});

const transactionHash = await walletClient.sendTransaction({
to: getDeleGatorEnvironment(chain.id).DelegationManager,
data: redeemDelegationCalldata,
chain,
});

Redeem multiple delegations

You can redeem multiple delegations in a single user operation, each delegation independent of the others. Each element in the delegationsArray must have a corresponding element in the executionsArray and modes.

The following example assumes you already have multiple signed delegations and that the delegate is an SCA. The preparation of the call data is the same when using an EOA as the delegate; the primary difference is that an EOA submits a regular transaction instead of a user operation.

import { 
DelegationFramework,
SINGLE_DEFAULT_MODE,
ExecutionStruct
} from "@metamask/delegation-toolkit";
import { bundlerClient, pimlicoClient } from "./client.ts";
import { delegateSmartAccount } from "./account.ts";

const delegationsArray: Delegation[][] = [
[ signedDelegation1 ]
[ signedDelegation2 ]
[ signedDelegation3 ]
];

const modes: ExecutionMode = [
SINGLE_DEFAULT_MODE,
SINGLE_DEFAULT_MODE,
SINGLE_DEFAULT_MODE
];

const execution: ExecutionStruct[] = [{
target: zeroAddress,
value: 0n,
callData: "0x"
}];

// Modify the executions to fit your use case. For simplicity, we've
// included a basic example. The execution array can contain
// multiple different executions.
const executionsArray: ExecutionStruct:[][] = [
execution,
execution,
execution
];

const redeemDelegationCalldata = DelegationFramework.encode.redeemDelegations({
delegations: [ delegations ],
modes: [ mode ],
executions: [ executions ]
});

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

const userOperationHash = await bundlerClient.sendUserOperation({
account: delegateSmartAccount,
calls: [
{
to: "<DELEGATOR-SMART-ACCOUNT-ADDRESS>",
data: redeemDelegationCalldata
}
],
...fee
});

Execution modes

The Delegation Toolkit supports several execution modes based on ERC-7579. See the ERC implementation for more details about the execution modes.

The supported execution modes are SINGLE_DEFAULT_MODE, SINGLE_TRY_MODE, BATCH_DEFAULT_MODE, and BATCH_TRY_MODE.

SINGLE execution modes

In SINGLE execution modes, only a single delegation chain and a single execution can be provided. This mode 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.

BATCH execution modes

In BATCH execution modes, multiple delegation chains and multiple executions can be provided. This mode executes delegations in an interleaved way:

  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.

DEFAULT modes

In DEFAULT modes, if a revert occurs during redemption, the entire user operation reverts at that point.

TRY modes

In TRY modes, if a revert occurs during redemption, execution of the user operation continues.