Delegation Toolkit quickstart
This page demonstrates how to get started quickly with the MetaMask Delegation Toolkit, by creating a delegator account and completing the delegation lifecycle (creating, signing, and redeeming a delegation).
Prerequisites
Install and set up the Delegation Toolkit.
Steps
1. Set up a Public Client
Set up a Viem Public Client using Viem's createPublicClient
function.
This client will let the delegator account query the signer's account state and interact with smart contracts.
import { createPublicClient, http } from "viem";
import { lineaSepolia as chain } from "viem/chains";
const publicClient = createPublicClient({
chain,
transport: http(),
});
2. Set up a Bundler Client
Set up a Viem Bundler Client using Viem's createBundlerClient
function.
This lets you use the bundler service to estimate gas for user operations and submit transactions to the network.
import { createBundlerClient } from "viem/account-abstraction";
const bundlerClient = createBundlerClient({
client: publicClient,
transport: http("https://your-bundler-rpc.com"),
});
3. Create a delegator account
Create a delegator account to set up a delegation. The delegator must be a smart account.
This example configures a Hybrid Delegator:
import {
Implementation,
toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";
import { privateKeyToAccount } from "viem/accounts";
const delegatorAccount = privateKeyToAccount("0x...");
const delegatorSmartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [delegatorAccount.address, [], [], []],
deploySalt: "0x",
signatory: { account: delegatorAccount },
});
4. Create a delegate account
Create a delegate account to receive the delegation. The delegate can be either a smart contract account (SCA) or an externally owned account (EOA).
This example uses an SCA:
import {
Implementation,
toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";
import { privateKeyToAccount } from "viem/accounts";
const delegateAccount = privateKeyToAccount("0x...");
const delegateSmartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [delegateAccount.address, [], [], []],
deploySalt: "0x",
signatory: { account: delegateAccount },
});
5. Create a delegation
Create a root delegation from the delegator account to the delegate account.
This example passes an empty caveats
array, which means the delegate can perform any action on the delegator's behalf.
We recommend restricting the delegation by adding caveat enforcers.
import { createDelegation } from "@metamask/delegation-toolkit";
const delegation = createDelegation({
to: delegateSmartAccount.address,
from: delegatorSmartAccount.address,
caveats: [] // Empty caveats array - we recommend adding appropriate restrictions.
});
6. Sign the delegation
Sign the delegation using the signDelegation
method from MetaMaskSmartAccount
.
Alternatively, you can use the Delegation Toolkit's signDelegation
utility.
The signed delegation will be used later to perform actions on behalf of the delegator.
const signature = await delegatorSmartAccount.signDelegation({
delegation
});
const signedDelegation = {
...delegation,
signature,
};
7. Redeem the delegation
The delegate account can now redeem the delegation.
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 from the Delegation Toolkit.
import {
createExecution,
DelegationFramework,
SINGLE_DEFAULT_MODE,
} from "@metamask/delegation-toolkit";
import { zeroAddress } from "viem";
const delegations = [ signedDelegation ];
const executions = [{
target: zeroAddress,
value: 0n,
callData: "0x"
}];
const redeemDelegationCalldata = DelegationFramework.encode.redeemDelegations({
delegations: [ delegations ],
modes: [ SINGLE_DEFAULT_MODE ],
executions: [ executions ]
});
const userOperationHash = await bundlerClient.sendUserOperation({
account: delegateSmartAccount,
calls: [
{
to: delegateSmartAccount.address,
data: redeemDelegationCalldata
}
],
maxFeePerGas: 1n,
maxPriorityFeePerGas: 1n,
});