Skip to content

Latest commit

 

History

History
410 lines (326 loc) · 12.9 KB

File metadata and controls

410 lines (326 loc) · 12.9 KB
title Batch Transactions with EIP-5792 - MetaMask Connect EVM
sidebar_label Batch transactions
description Send multiple transactions atomically using wallet_sendCalls (EIP-5792), check capabilities, and track batch status in MetaMask.
keywords
EIP-5792
atomic batch
wallet_sendCalls
wallet_getCapabilities
wallet_getCallsStatus
bundle transactions
batch transactions
metamask

import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';

Send batch transactions

MetaMask Connect EVM supports atomic batch transactions through EIP-5792, allowing your dapp to submit multiple calls as a single atomic operation. Use wallet_getCapabilities to check support, wallet_sendCalls to submit the batch, and wallet_getCallsStatus to track execution.

Send and manage batch transactions in MetaMask, using the methods specified by EIP-5792:

About atomic batch transactions

An atomic batch transaction is a group of transactions that are executed together as a single unit. When a dapp requests to submit a batch of transactions atomically, MetaMask may prompt users to upgrade their externally owned account (EOA) to a MetaMask smart account. If the user accepts, MetaMask proceeds to upgrade the account and process the request as a single atomic transaction as specified by EIP-7702.

:::note MetaMask Smart Accounts MetaMask Smart Accounts are ERC-4337 smart contract accounts that support programmable account behavior and advanced features such as multi-signature approvals, transaction batching, and custom security policies.

See the Smart Accounts Kit documentation for more information about smart accounts and their capabilities. :::

The key benefits of atomic batch transactions include:

  • Fewer steps and less friction - Users only need to review and approve a single wallet confirmation, instead of multiple confirmations. For example, users can confirm a spending cap and swap in one step instead of two.
  • Faster completion times - Only a single atomic transaction is confirmed onchain, instead of multiple individual transactions.
  • Reduced gas fees - When multiple transactions are executed atomically, users only need to pay a single gas fee.

This page describes how to send batch transactions directly in your dapp. You can also send batch transactions using third-party libraries.

Prerequisites

Follow the JavaScript quickstart or Wagmi quickstart to install, initialize, and connect the EVM client.

Steps

1. Query whether atomic batch is supported

Use wallet_getCapabilities to query whether MetaMask supports atomic batch transactions for a specific address and specific chain IDs. For example:

import { createEVMClient } from '@metamask/connect-evm'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const capabilities = await provider.request({
  method: 'wallet_getCapabilities',
  params: [
    '0xd46e8dd67c5d32be8058bb8eb970870f07244567', // The user's wallet address.
    ['0x1', '0xaa36a7'], // (Optional) A list of chain IDs to query for.
  ],
})
import { createEVMClient } from '@metamask/connect-evm'
import { createWalletClient, custom } from 'viem'
import { mainnet } from 'viem/chains'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const walletClient = createWalletClient({ chain: mainnet, transport: custom(provider) })

const address = await walletClient.getAddresses()

const capabilities = await walletClient.getCapabilities({
  account: address[0],
})
import { createEVMClient } from '@metamask/connect-evm'
import { useCapabilities } from 'wagmi'

const evmClient = await createEVMClient({
  dapp: {
    name: 'MetaMask Connect EVM Example',
    url: window.location.href,
    iconUrl: 'https://mydapp.com/icon.png', // Optional
  },
  api: {
    supportedNetworks: {
      '0x1': 'https://mainnet.infura.io/v3/YOUR_INFURA_API_KEY',
      '0xaa36a7': 'https://sepolia.infura.io/v3/YOUR_INFURA_API_KEY',
    },
  },
})
const provider = evmClient.getProvider()

const status = await useCapabilities({
  account: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
})

This method returns the status of the atomic capability for each chain ID. For example:

{
  "0x1": {
    "atomic": {
      "status": "ready"
    }
  },
  "0xaa36a7": {
    "atomic": {
      "status": "supported"
    }
  }
}

The atomic capability can have a status of supported or ready:

  • supported means MetaMask supports atomic batch transactions for the account and chain ID.
  • ready means MetaMask will prompt the user to upgrade their account to a MetaMask smart account. If the user approves, the status will upgrade to supported.

If the atomic capability is not supported or ready for a specified chain ID, MetaMask will not return anything for that chain ID. If you don't specify any chain IDs in wallet_getCapabilities, MetaMask will return all chains in the wallet where the atomic capability is supported or ready.

Supported networks
MetaMask's support for atomic batch transactions includes the following networks:
  • Ethereum Mainnet and Sepolia
  • Gnosis Mainnet and Chiado
  • BNB Smart Chain Mainnet and Testnet
  • OP Mainnet and Sepolia
  • Base Mainnet and Sepolia
  • Polygon Mainnet and Amoy
  • Arbitrum Mainnet, Sepolia, and Nova
  • Unichain Mainnet and Sepolia
  • Berachain Mainnet and Bepolia

MetaMask supports this feature on more networks as they adopt EIP-7702.

:::note Atomic batch unsupported

2. Submit a batch of transactions

Use wallet_sendCalls to submit a batch of transactions. For example:

const result = await provider.request({
  method: 'wallet_sendCalls',
  params: [
    {
      version: '2.0.0', // The version of the API format. This must be 2.0.0.
      from: '0xd46e8dd67c5d32be8058bb8eb970870f07244567', // The sender's address.
      chainId: '0xaa36a7', // The chain ID, which must match the currently selected network.
      atomicRequired: true, // Whether or not atomicity is required.
      calls: [
        // The list of calls to send as a batch.
        {
          to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
          value: '0x0',
        },
        {
          to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
          value: '0x0',
        },
      ],
    },
  ],
})
const { id } = await walletClient.sendCalls({
  account: address[0],
  calls: [
    {
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      value: '0x0',
    },
    {
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      value: '0x0',
    },
  ],
})
import { useSendCalls } from 'wagmi'

const { sendCalls, data } = useSendCalls()

sendCalls({
  calls: [
    {
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      value: '0x0',
    },
    {
      to: '0xd46e8dd67c5d32be8058bb8eb970870f07244567',
      value: '0x0',
    },
  ],
})

:::note Atomic required parameter MetaMask only supports using wallet_sendCalls to send atomic batch transactions (not sequential batch transactions), so atomicRequired can be set to either true or false. If the atomic capability is not supported, wallet_sendCalls will return an error. :::

This method returns a batch ID that you can use to track the status of the batch. For example:

{
  "id": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331"
}

3. Track the status of the batch of transactions

Use wallet_getCallsStatus to track the status of the submitted batch of transactions, using the batch ID returned by wallet_sendCalls. For example:

const status = await provider.request({
  method: 'wallet_getCallsStatus',
  params: [
    '0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331', // Batch ID.
  ],
})
const { result } = await walletClient.getCallsStatus({
  id: '0x1234567890abcdef',
})
import { getCallsStatus } from 'wagmi'

const status = await getCallsStatus(config, { id: data.id })

This method returns status information about the batch of transactions, including:

  • The status code of the batch.
  • Whether the batch was executed atomically. Currently, this will always be true if the execution was successful.
  • A list of transaction receipts.

For example:

{
  "version": "2.0.0",
  "chainId": "0xaa36a7",
  "id": "0xe670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
  "status": 200, // Status code. 200 means confirmed.
  "atomic": true, // Whether the calls were executed atomically.
  "receipts": [
    // List of transaction receipts.
    {
      "logs": [
        {
          "address": "0xa922b54716264130634d6ff183747a8ead91a40b",
          "topics": ["0x5a2a90727cc9d000dd060b1132a5c977c9702bb3a52afe360c9c22f0e9451a68"],
          "data": "0xabcd"
        }
      ],
      "status": "0x1",
      "blockHash": "0xf19bbafd9fd0124ec110b848e8de4ab4f62bf60c189524e54213285e7f540d4a",
      "blockNumber": "0xabcd",
      "gasUsed": "0xdef",
      "transactionHash": "0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff"
    }
  ]
}

:::note If the calls were executed atomically in a single transaction, a single receipt is returned.

In some cases, calls can be executed atomically but in multiple transactions (for example, using eth_bundle on an L2 network resistant to reorgs). In these cases, atomic is true but multiple receipts are returned. :::

Use third-party libraries

Send batch transactions using the following third-party libraries that support EIP-5792:

Resources