Create a redelegation
Redelegation is a core feature that sets Advanced Permissions apart from other permission sharing frameworks. It allows a session account (delegate) to create a delegation chain, passing on the same or reduced level of authority from the MetaMask account (delegator).
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
- Learn about Advanced Permissions
- Learn how to request Advanced Permissions
Request Advanced Permissions
Request Advanced Permissions from the user with the Wallet Client's requestExecutionPermissions action.
This example uses the ERC-20 periodic permission, allowing the user to grant dapp the ability to spend 10 USDC on their behalf.
- example.ts
- config.ts
import { sepolia as chain } from "viem/chains";
import { sessionAccount, walletClient, tokenAddress } from "./config.ts";
import { parseUnits } from "viem";
// 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,
signer: {
type: "account",
data: {
// The requested permissions will be granted to the
// session account.
address: 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,
}]);
import { createWalletClient, custom, createPublicClient, http } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { toMetaMaskSmartAccount, Implementation } from "@metamask/smart-accounts-kit";
import { erc7715ProviderActions } from "@metamask/smart-accounts-kit/actions";
import { sepolia as chain } from "viem/chains";
// 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 = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [account.address, [], [], []],
deploySalt: "0x",
signer: { account },
});
export const walletClient = createWalletClient({
transport: custom(window.ethereum),
}).extend(erc7715ProviderActions());
Decode delegations
The granted permissions object includes a context property that represents the encoded delegations.
To create a redelegation, you must first decode these delegations to access the underlying delegations. To decode the delegations, use the decodeDelegations utility function.
import { decodeDelegations } from "@metamask/smart-accounts-kit/utils";
const permissionsContext = grantedPermissions[0].context;
const delegations = decodeDelegations(permissionsContext);
const rootDelegation = delegations[0];
Create a redelegation
Create a redelegation from dapp to a Swap agent.
To create a redelegation, provide the signed delegation as the parentDelegation argument when calling createDelegation.
This example uses the erc20TransferAmount scope, allowing
dapp to delegate to a Swap agent the ability to spend 5 USDC on user's behalf.
When creating a redelegation, you can only narrow the scope of the original authority, not expand it.
- redelegation.ts
- config.ts
import { sessionAccount, agentSmartAccount, tokenAddress } from "./config.ts";
import { createDelegation } from "@metamask/smart-accounts-kit";
import { parseUnits } from "viem";
const redelegation = createDelegation({
scope: {
type: "erc20TransferAmount",
tokenAddress,
// USDC has 6 decimal places.
maxAmount: parseUnits("5", 6),
},
to: agentSmartAccount.address,
from: sessionAccount.address,
// Signed root delegation extracted from Advanced Permissions.
parentDelegation: rootDelegation,
environment: sessionAccount.environment,
})
const signedRedelegation = await sessionAccount.signDelegation({ delegation: redelegation })
// Update the existing config to create a smart account for a Swap agent.
const agentAccount = privateKeyToAccount("0x...")
export const agentSmartAccount = await toMetaMaskSmartAccount({
client: publicClient,
implementation: Implementation.Hybrid,
deployParams: [agentAccount.address, [], [], []],
deploySalt: "0x",
signer: { account: agentAccount },
})