Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 21 additions & 25 deletions docs/pages/guides/how-to/accounts/use-metamask-account.mdx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# 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.
MetaMask maintains their own in-house SDK built on top of Viem that you can use for the account system while still plugging in all the other components from permissionless.js. See [their documentation](https://docs.metamask.io/smart-accounts-kit) 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.
The [MetaMask Smart Accounts Kit](https://docs.metamask.io/smart-accounts-kit) enables embedding MetaMask Smart Accounts into dapps. [Delegation](https://docs.metamask.io/smart-accounts-kit/guides/delegation/execute-on-smart-accounts-behalf) is a core feature of smart accounts, enabling secure, rule-based permission sharing.

There are two types of accounts involved in delegation:

Expand All @@ -15,43 +15,43 @@ You can use both accounts with permissionless.js.

## Installation

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

:::code-group

```bash [npm]
npm install permissionless viem @metamask/delegation-toolkit
npm install permissionless viem @metamask/smart-accounts-kit
```

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

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

```bash [bun]
bun install permissionless viem @metamask/delegation-toolkit
bun install permissionless viem @metamask/smart-accounts-kit
```

:::

## Delegator Account
## 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.
First, create the public client and (optional) pimlico paymaster client that will be used to interact with the MetaMask smart account.

```ts
// [!include ~/snippets/accounts/metamask.ts:clients]
```

### Create the signer

MetaMask Smart Accounts can work with a variety of signing algorithms such as ECDSA, passkeys, and multisig.
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:

Expand All @@ -62,7 +62,7 @@ For example, to create a signer based on a private 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).
For a full list of options for creating a MetaMask smart account, see [the MetaMask documentation](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account).
:::

With a signer, you can create a MetaMask smart account as such:
Expand All @@ -79,13 +79,13 @@ With a signer, you can create a MetaMask smart account as such:

### 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.
Transactions using permissionless.js wrap around user operations. This means you can switch to permissionless.js from your existing Viem EOA codebase with minimal-to-no changes.

```ts
// [!include ~/snippets/accounts/metamask.ts:submit]
```

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

```ts
// [!include ~/snippets/accounts/metamask.ts:submitNft]
Expand All @@ -99,30 +99,25 @@ You can also send an array of transactions in a single batch.

::::

## Delegate Account
## 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
The delegate account can be a MetaMask smart account or an EOA.
The following example uses a smart 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.
First, create the public client and (optional) pimlico paymaster client that will be used to interact with the MetaMask smart account.

```ts
// [!include ~/snippets/accounts/metamask.ts:clients]
```

### Create the signer

MetaMask Smart Accounts can work with a variety of signing algorithms such as ECDSA, passkeys, and multisig.
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:

Expand All @@ -133,7 +128,7 @@ For example, to create a signer based on a private 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).
For a full list of options for creating a MetaMask smart account, see [the MetaMask documentation](https://docs.metamask.io/smart-accounts-kit/guides/smart-accounts/create-smart-account).
:::

With a delegate signer, you can create a MetaMask delegate account as such:
Expand All @@ -144,7 +139,8 @@ With a delegate signer, you can create a MetaMask delegate account as such:

### 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.
This example uses the ERC-20 transfer scope, which ensures that ERC-20 token transfers made by the delegate account are limited to a specified amount.
You can read more about the Smart Accounts Kit's [delegation scopes](https://docs.metamask.io/smart-accounts-kit/guides/delegation/use-delegation-scopes).

```ts
// [!include ~/snippets/accounts/metamask.ts:createDelegation]
Expand Down
58 changes: 35 additions & 23 deletions docs/snippets/accounts/metamask.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
// [!region imports]
import { createSmartAccountClient } from "permissionless";
import {
createPublicClient,
encodeFunctionData,
getContract,
http,
parseEther,
} from "viem";
// [!region clients]
import { createPublicClient, http } from "viem";
import { sepolia } from "viem/chains";
// [!endregion imports]
import { createPimlicoClient } from "permissionless/clients/pimlico";
import { entryPoint07Address } from "viem/account-abstraction";

// [!region clients]
export const publicClient = createPublicClient({
chain: sepolia,
transport: http("https://sepolia.rpc.thirdweb.com"),
});

Expand All @@ -26,49 +20,59 @@ export const paymasterClient = createPimlicoClient({

// [!region signer]
import { privateKeyToAccount } from "viem/accounts";
import { createPimlicoClient } from "permissionless/clients/pimlico";
import { entryPoint07Address } from "viem/account-abstraction";

const owner = privateKeyToAccount("0xPRIVATE_KEY");
// [!endregion signer]

// [!region delegateSigner]
import { privateKeyToAccount } from "viem/accounts";

const delegateSigner = privateKeyToAccount("0xPRIVATE_KEY");
// [!endregion delegateSigner]

// [!region smartAccount]
import {
Implementation,
toMetaMaskSmartAccount,
} from "@metamask/delegation-toolkit";
} from "@metamask/smart-accounts-kit";

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

// [!endregion smartAccount]

// [!region delegateSmartAccount]
import {
Implementation,
toMetaMaskSmartAccount,
} from "@metamask/smart-accounts-kit";

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

// [!region createDelegation]
import { createDelegation } from "@metamask/delegation-toolkit";
import { createDelegation } from "@metamask/smart-accounts-kit";
import { parseUnits } from "viem";

const delegation = createDelegation({
to: delegateSmartAccount.address,
from: delegatorSmartAccount.address,
caveats: [],
environment: delegatorSmartAccount.environment
scope: {
type: "erc20TransferAmount",
tokenAddress,
maxAmount: parseUnits("10", 6),
},
});
// [!endregion createDelegation]

Expand All @@ -84,6 +88,8 @@ const signedDelegation = {
// [!endregion signDelegation]

// [!region smartAccountClient]
import { createSmartAccountClient } from "permissionless";

const smartAccountClient = createSmartAccountClient({
account: delegatorSmartAccount,
chain: sepolia,
Expand All @@ -99,6 +105,8 @@ const smartAccountClient = createSmartAccountClient({
// [!endregion smartAccountClient]

// [!region delegateSmartAccountClient]
import { createSmartAccountClient } from "permissionless";

const delegateSmartAccountClient = createSmartAccountClient({
account: delegateSmartAccount,
chain: sepolia,
Expand All @@ -114,6 +122,8 @@ const delegateSmartAccountClient = createSmartAccountClient({
// [!endregion delegateSmartAccountClient]

// [!region submit]
import { parseEther } from "viem";

const txHash_$1 = await smartAccountClient.sendTransaction({
to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
value: parseEther("0.1"),
Expand All @@ -134,6 +144,8 @@ const tokenAbi = [
] as const;

// [!region submitNft]
import { getContract } from "viem";

const nftContract = getContract({
address: "0xFC3e86566895Fb007c6A0d3809eb2827DF94F751",
abi: tokenAbi,
Expand Down Expand Up @@ -167,9 +179,9 @@ const userOpHash_$3 = await smartAccountClient.sendUserOperation({
// [!endregion submitBatch]

// [!region sendTransactionWithDelegation]
import { DelegationManager } from "@metamask/delegation-toolkit/contracts";
import { SINGLE_DEFAULT_MODE } from "@metamask/delegation-toolkit/utils";
import { createExecution } from "@metamask/delegation-toolkit";
import { DelegationManager } from "@metamask/smart-accounts-kit/contracts";
import { createExecution, ExecutionMode } from "@metamask/smart-accounts-kit";
import { encodeFunctionData, parseEther } from "viem";

const delegations = [signedDelegation];

Expand All @@ -187,7 +199,7 @@ const executions = [

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

Expand Down