# How to use MetaMask Smart Accounts with permissionless.js

:::info
MetaMask maintains their own in-house SDK built closely on top of viem that you can use for the account system while still plugging in all the other components from permissionless.js. Take a look at [their documentation](https://docs.metamask.io/delegation-toolkit/how-to/send-user-operation) for more information.
:::

The [MetaMask Delegation Toolkit](https://docs.metamask.io/delegation-toolkit/get-started/quickstart) is a collection of tools for creating MetaMask Smart Accounts. A smart account can delegate to another signer with granular permission sharing. It is built over [ERC-7710](https://eip.tools/eip/7710) and [ERC-7715](https://eip.tools/eip/7715) to support a standardized minimal interface. Requesting ERC-7715 permissions and redeeming ERC-7710 delegations are experimental features.

There are two types of accounts involved in delegation:

1. **Delegator account**: A smart account that supports programmable account behavior and advanced features such as multi-signature approvals, automated transaction batching, and custom security policies.
2. **Delegate account**: An account (smart account or EOA) that receives the delegation from the delegator account to perform actions on behalf of the delegator account.

You can use both accounts with permissionless.js.

## Installation

We will be using MetaMask's official SDK to create a smart account.

:::code-group
```bash [npm]
npm install permissionless viem @metamask/delegation-toolkit
```

```bash [yarn]
yarn add permissionless viem @metamask/delegation-toolkit
```

```bash [pnpm]
pnpm install permissionless viem @metamask/delegation-toolkit
```

```bash [bun]
bun install permissionless viem @metamask/delegation-toolkit
```
:::

## Delegator Account

::::steps
### Create the clients

First we must create the public, (optionally) pimlico paymaster clients that will be used to interact with the MetaMask smart account.

```ts
export const publicClient = createPublicClient({
	transport: http("https://sepolia.rpc.thirdweb.com"),
});

export const paymasterClient = createPimlicoClient({
	transport: http("https://api.pimlico.io/v2/sepolia/rpc?apikey=API_KEY"),
	entryPoint: {
		address: entryPoint07Address,
		version: "0.7",
	},
});
```

### Create the signer

MetaMask Smart Accounts can work with a variety of signing algorithms such as ECDSA, passkeys, and multisig.

For example, to create a signer based on a private key:

```ts
import { privateKeyToAccount } from "viem/accounts";
import { createPimlicoClient } from "permissionless/clients/pimlico";
import { entryPoint07Address } from "viem/account-abstraction";

const owner = privateKeyToAccount("0xPRIVATE_KEY");
```

### Create the delegator smart account

:::info
For a full list of options for creating a MetaMask smart account, take a look at the MetaMask's documentation page for [`toMetaMaskSmartAccount`](https://docs.metamask.io/delegation-toolkit/how-to/create-smart-account).
:::

With a signer, you can create a MetaMask smart account as such:

```ts
import {
	Implementation,
	toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";

const delegatorSmartAccount = await toMetaMaskSmartAccount({
	client: publicClient,
	implementation: Implementation.Hybrid,
	deployParams: [owner.address, [], [], []],
	deploySalt: "0x",
	signatory: { account: owner },
});
```

### Create the smart account client

```ts
const smartAccountClient = createSmartAccountClient({
	account: delegatorSmartAccount,
	chain: sepolia,
	paymaster: paymasterClient,
	bundlerTransport: http(
		"https://api.pimlico.io/v2/sepolia/rpc?apikey=API_KEY",
	),
	userOperation: {
		estimateFeesPerGas: async () =>
			(await paymasterClient.getUserOperationGasPrice()).fast,
	},
});
```

### Send a transaction

Transactions using permissionless.js simply wrap around user operations. This means you can switch to permissionless.js from your existing viem EOA codebase with minimal-to-no changes.

```ts
const txHash = await smartAccountClient.sendTransaction({
	to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
	value: parseEther("0.1"),
});
```

This also means you can also use viem Contract instances to transact without any modifications.

```ts
const nftContract = getContract({
	address: "0xFC3e86566895Fb007c6A0d3809eb2827DF94F751",
	abi: tokenAbi,
	client: {
		public: publicClient,
		wallet: smartAccountClient,
	},
});

const txHash = await nftContract.write.mint([
	"0x_MY_ADDRESS_TO_MINT_TOKENS",
	parseEther("1"),
]);
```

You can also send an array of transactions in a single batch.

```ts
const userOpHash = await smartAccountClient.sendUserOperation({
	calls: [
		{
			to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
			value: parseEther("0.1"),
			data: "0x",
		},
		{
			to: "0x1440ec793aE50fA046B95bFeCa5aF475b6003f9e",
			value: parseEther("0.1"),
			data: "0x1234",
		},
	],
});
```
::::

## Delegate Account

A delegate account is an account that receives the delegation from the delegator account to perform actions on behalf of the delegator account.
To create a delegate account, we will follow the following steps:

1. Create a delegate signer
2. Create the delegate smart account
3. Create a delegation using delegator smart account
4. Sign the delegation
5. Send transactions using delegate smart account with signed delegation

::::steps
### Create the clients

First we must create the public, (optionally) pimlico paymaster clients that will be used to interact with the MetaMask smart account.

```ts
export const publicClient = createPublicClient({
	transport: http("https://sepolia.rpc.thirdweb.com"),
});

export const paymasterClient = createPimlicoClient({
	transport: http("https://api.pimlico.io/v2/sepolia/rpc?apikey=API_KEY"),
	entryPoint: {
		address: entryPoint07Address,
		version: "0.7",
	},
});
```

### Create the signer

MetaMask Smart Accounts can work with a variety of signing algorithms such as ECDSA, passkeys, and multisig.

For example, to create a signer based on a private key:

```ts
const delegateSigner = privateKeyToAccount("0xPRIVATE_KEY");
```

### Create the delegate smart account

:::info
For a full list of options for creating a MetaMask smart account, take a look at the MetaMask's documentation page for [`toMetaMaskSmartAccount`](https://docs.metamask.io/delegation-toolkit/how-to/create-smart-account).
:::

With a delegate signer, you can create a MetaMask delegate account as such:

```ts
const delegateSmartAccount = await toMetaMaskSmartAccount({
	client: publicClient,
	implementation: Implementation.Hybrid,
	deployParams: [delegateSigner.address, [], [], []],
	deploySalt: "0x",
	signatory: { account: delegateSigner },
});
```

### Create a delegation

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.

```ts
import { createDelegation } from "@metamask/delegation-toolkit";

const delegation = createDelegation({
	to: delegateSmartAccount.address,
	from: delegatorSmartAccount.address,
	caveats: [],
});
```

### Sign the delegation

```ts
const signature = await delegatorSmartAccount.signDelegation({
	delegation,
});

const signedDelegation = {
	...delegation,
	signature,
};
```

### Create the smart account client

```ts
const delegateSmartAccountClient = createSmartAccountClient({
	account: delegateSmartAccount,
	chain: sepolia,
	paymaster: paymasterClient,
	bundlerTransport: http(
		"https://api.pimlico.io/v2/sepolia/rpc?apikey=API_KEY",
	),
	userOperation: {
		estimateFeesPerGas: async () =>
			(await paymasterClient.getUserOperationGasPrice()).fast,
	},
});
```

### Send transactions using signed delegation

```ts
import { DelegationManager } from "@metamask/delegation-toolkit/contracts";
import { SINGLE_DEFAULT_MODE } from "@metamask/delegation-toolkit/utils";
import { createExecution } from "@metamask/delegation-toolkit";

const delegations = [signedDelegation];

// Actual execution to be performed by the delegate account
const executions = [
	createExecution({
		target: "0xFC3e86566895Fb007c6A0d3809eb2827DF94F751",
		callData: encodeFunctionData({
			abi: tokenAbi,
			functionName: "mint",
			args: ["0x_MY_ADDRESS_TO_MINT_TOKENS", parseEther("1")],
		}),
	}),
];

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

const txHash = await delegateSmartAccountClient.sendTransaction({
	calls: [
		{
			to: delegateSmartAccount.address,
			data: redeemDelegationCalldata,
		},
	],
});
```
::::
