# Perform executions on a smart account's behalf

> Use delegations to perform executions on a smart account's behalf.

# 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.
