EIP-7702 Transaction Batching

Overview

What It Does

EIP-7702 batching lets you combine multiple DeFi operations — fee payment, token approval, and a swap or deposit — into a single transaction that the user signs once. Without batching, each step is a separate transaction requiring its own signature and gas fee.

Who It's For

  • Wallet developers integrating with the Blockdaemon DeFi API who want a smoother UX for end users.
  • DApp builders looking to reduce the number of signing prompts and transaction confirmations.
  • Backend engineers building trading or portfolio management systems that interact with DeFi protocols.

Why It Matters

In a typical DeFi swap with fees enabled, a user must sign and submit up to three separate transactions (fee, approval, swap) — each costing gas and requiring confirmation. EIP-7702 batching collapses all of these into one atomic transaction. If any step fails, the entire batch reverts, so you never end up in a partial state (e.g., fee paid but swap failed).


Key Concepts

Before diving in, here are the core ideas you'll encounter throughout this guide.

EOA (Externally Owned Account)

A standard Ethereum wallet controlled by a private key — the kind most users have (e.g., MetaMask accounts). Unlike smart contract wallets, EOAs can't normally execute multiple operations in one transaction.

EIP-7702

An Ethereum standard that temporarily gives an EOA the ability to act like a smart contract for a single transaction. The EOA signs an authorization that delegates its execution to a smart contract — called the delegation address — runs the batch through that contract's logic, and then returns to normal.

Smart Contract Delegation Address

The smart contract that an EOA delegates its execution to via EIP-7702. In the context of this API, the delegation address is an ERC-7821 batcher contract that exposes one function — execute(mode, calldata) — which runs a list of sub-calls in sequence. Blockdaemon deploys and manages these contracts on each supported chain, but you can also bring your own.

The API response returns this address in the batcherContract field.

Atomic Execution

All sub-calls in the batch either succeed together or fail together. There's no in-between state where some calls executed but others didn't.

EIP-7702 vs. EIP-5792

Both achieve the same outcome (atomic batching), but they work differently:

EIP-7702EIP-5792
ReturnsA single transaction objectAn array of calls
Submission methodeth_sendTransactionwallet_sendCalls
Best forEOA wallets with type-4 auth supportSmart contract / AA wallets
Wallet requirementMust support EIP-7702 authorization signingMust support wallet_sendCalls

If you're unsure which to use: check what your target wallet supports. If it can sign EIP-7702 type-4 authorizations, use this. If it supports wallet_sendCalls (common in smart contract wallets like Safe), use EIP-5792 batching instead.


How It Works

High-Level Flow

Here's what happens when you send a request with batchOption: "EIP-7702":

  1. You send a request to the DeFi API (e.g., a swap), including "batchOption": "EIP-7702" in the body.
  2. The API assembles all required operations — fee payment, token approval (if needed), and the main operation — into a single encoded payload targeting the delegation address.
  3. The API returns one transaction object with the encoded payload as data and the delegation address in the batcherContract field.
  4. The EOA signs an authorization delegating its execution to the smart contract at batcherContract.
  5. The transaction is submitted via eth_sendTransaction with the signed authorization attached. The delegation address executes all sub-calls atomically on behalf of the EOA.

Visual Summary

You                          DeFi API                         Blockchain
 │                              │                                │
 ├─ POST /dex/swap ────────────►│                                │
 │  (batchOption: "EIP-7702")   │                                │
 │                              ├─ Assemble sub-calls:           │
 │                              │   1. Fee transfer              │
 │                              │   2. Token approval            │
 │                              │   3. Swap                      │
 │                              │                                │
 │◄─ Single transaction ────────┤                                │
 │   object returned            │                                │
 │                              │                                │
 ├─ EOA signs authorization ────┤                                │
 │  (delegates to batcher)      │                                │
 │                              │                                │
 ├─ eth_sendTransaction ────────┼───────────────────────────────►│
 │  (with authorizationList)    │                  Delegation    │
 │                              │                  address       │
 │                              │                  executes      │
 │                              │                  all calls     │
 │                              │                  atomically    │

What Gets Batched

The number of sub-calls depends on the endpoint and whether fees are enabled:

ScenarioSub-calls
Swap with fee, no approval needed2: fee → swap
Swap with fee + approval needed3: fee → approve → swap
Swap without fee1: swap only
Deposit with fee2: fee → deposit
📘

Note

The API automatically checks whether a token approval is needed. If the user already has sufficient allowance, the approval step is skipped.


Quick Start

The fastest path to your first batched transaction.

Prerequisites

  1. A valid Blockdaemon API key. See Send Your First API Request.
  2. A wallet that supports EIP-7702 authorization signing.
  3. A supported chain (Ethereum, Optimism, BNB Chain, Polygon, Arbitrum, Base, or Sepolia).

Steps

Step 1 — Add batchOption to your existing request.

Take any supported endpoint request and add "batchOption": "EIP-7702" to the body. That's the only change needed.

{
  "dexId": "1300",
  "amountIn": "1000000000000000",
  "from": "0x6305...1006",
  "to": "0x6305...1006",
  "path": ["0xC02a...6Cc2", "0x6B17...1d0F"],
  "poolFees": "3000",
  "enableFee": true,
  "batchOption": "EIP-7702"
}

Step 2 — Sign the authorization and submit the transaction.

The API returns a single transaction object. Before submitting, the EOA must sign an authorization that delegates its execution to the smart contract at batcherContract (the delegation address). Here's the full flow using viem.

EIP-7702 supports two patterns: a relay (a separate account sponsors gas and sends the transaction on behalf of the EOA) or self-executing (the EOA signs the authorization and sends the transaction itself). Both are shown below.

Option A — Relay pattern (recommended for production)

A relay account sponsors gas and submits the transaction. The EOA only signs the authorization delegating to the smart contract.

import { createWalletClient, http } from "viem";
import { mainnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

// The EOA that will delegate its execution to the batcher contract
const eoa = privateKeyToAccount("0xEOA_PRIVATE_KEY");

const walletClient = createWalletClient({
  account: eoa.address,
  chain: mainnet,
  transport: http(),
});

// 1. Fetch the batched transaction from the DeFi API
const result = await fetch("https://svc.blockdaemon.com/defi/v1/dex/swap-with-approval", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-API-Key": "YOUR_BLOCKDAEMON_API_KEY",
  },
  body: JSON.stringify({
    dexId: "1300",
    amountIn: "1000000000000000",
    amountOutMin: "0",
    path: ["0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "0x6B175474E89094C44Da98b954EedeAC495271d0F"],
    to: eoa.address,
    poolFees: "3000",
    from: eoa.address,
    gas: "173376",
    enableFee: true,
    batchOption: "EIP-7702",
  }),
}).then((r) => r.json());

const { to, value, data, batcherContract } = result.data;

// 2. EOA signs the authorization, delegating to the smart contract
//    at batcherContract (the delegation address)
const authorization = await walletClient.signAuthorization({
  account: eoa,
  contractAddress: batcherContract,
});

// 3. Relay sends the transaction with the signed authorization
const txHash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  to,
  value: BigInt(value),
  data,
});

console.log("Transaction hash:", txHash);

Option B — Self-executing (EOA signs and sends)

When the EOA is both the authorization signer and the transaction sender, pass executor: 'self' to signAuthorization. This ensures the authorization nonce is incremented correctly relative to the transaction nonce.

import { createWalletClient, http } from "viem";
import { mainnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const eoa = privateKeyToAccount("0xEOA_PRIVATE_KEY");

const walletClient = createWalletClient({
  account: eoa,
  chain: mainnet,
  transport: http(),
});

// ... fetch the batched transaction from the DeFi API (same as above) ...

const { to, value, data, batcherContract } = result.data;

// Sign authorization with executor: 'self' since the EOA is also sending
const authorization = await walletClient.signAuthorization({
  contractAddress: batcherContract,
  executor: "self",
});

const txHash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  to,
  value: BigInt(value),
  data,
});

That's it. The authorization delegates the EOA to the smart contract, and the single transaction executes the fee payment, any needed approvals, and the swap atomically.


Detailed Guide

Supported Chains

EIP-7702 batching is available on the following networks:

Chain IDNetwork
1Ethereum Mainnet
10Optimism
56BNB Smart Chain
137Polygon
42161Arbitrum One
8453Base
11155111Sepolia Testnet

Default Smart Contract Delegation Addresses

Blockdaemon deploys and manages an ERC-7821 batcher contract on each supported chain. These serve as the default delegation addresses — the smart contracts that EOAs delegate their execution to when using EIP-7702 batching.

When you send a request with batchOption: "EIP-7702" and don't specify a batcherContract, the API automatically uses the default delegation address for that chain.

The response always includes a batcherContract field confirming the delegation address that will execute the batch. You can use this to verify before submitting.

Using a Custom Delegation Address

If you need custom execution logic, access controls, or a self-managed deployment, you can provide your own smart contract as the delegation address via the batcherContract parameter:

{
  "batchOption": "EIP-7702",
  "batcherContract": "0xYourCustomContractAddress"
}

Your contract must implement the ERC-7821 execute(bytes32 mode, bytes executionData) function. The API encodes sub-calls to this interface regardless of whether you use the default or a custom delegation address.

⚠️

Warning

If your contract doesn't implement ERC-7821, the transaction will revert on-chain. Always verify your contract's interface before using it in production.

Supported Endpoints

EIP-7702 batching works across DEX, Bridge, and Lend/Borrow endpoints:

DomainEndpointCalls (fee on)Calls (fee off)
DEXPOST /defi/v1/dex/swap2 (fee + swap)1
DEXPOST /defi/v1/dex/swap-with-approval3 (fee + approve + swap)2
DEXPOST /defi/v1/dex/swaps2 per route1 per route
BridgePOST /defi/v1/bridge/swap-with-approval3 (fee + approve + swap)2
BridgePOST /defi/v1/bridge/swaps2 per route1 per route
Lend/BorrowPOST /defi/v1/lend-borrow/deposit2 (fee + deposit)1
Lend/BorrowPOST /defi/v1/lend-borrow/withdraw2 (fee + withdraw)1
Lend/BorrowPOST /defi/v1/lend-borrow/borrow2 (fee + borrow)1
Lend/BorrowPOST /defi/v1/lend-borrow/repay2 (fee + repay)1
Lend/BorrowPOST /defi/v1/lend-borrow/transfer2 (fee + transfer)1

Request Parameters

Add these to any supported endpoint's standard parameters:

ParameterTypeRequiredDescription
batchOptionstringYesSet to "EIP-7702" to enable batching.
batcherContractstringNoAddress of a custom ERC-7821 smart contract to use as the delegation address. If omitted, the Blockdaemon default for the target chain is used.

Response Format

With batchOption: "EIP-7702", the API returns a single transaction object instead of separate ones:

{
  "status": 200,
  "msg": "success",
  "data": {
    "from": "0x<sender>",
    "to": "0x<delegation address>",
    "value": "0x0",
    "data": "0x<ABI-encoded execute(mode, calldata)>",
    "batcherContract": "0x<delegation address>",
    "chainId": "1",
    "dexName": "UniswapV3",
    "amountsOut": ["1000000"],
    "referenceId": "abc-123",
    "methodUsed": "EIP-7702"
  }
}

Field reference:

FieldDescription
fromThe sender's EOA address.
toThe smart contract delegation address — where the transaction is sent.
valueAlways "0x0". ETH values for individual sub-calls are embedded in the encoded calldata.
dataThe ABI-encoded execute(mode, calldata) payload containing all sub-calls.
batcherContractThe smart contract delegation address (same as to). Pass this as contractAddress when calling signAuthorization in viem.
chainIdTarget chain as a decimal string. Convert to hex if your wallet provider requires it.
dexName / bridgeNameThe protocol used (varies by endpoint).
amountsOutExpected output amounts.
referenceIdUnique ID for tracking and debugging.
methodUsedAlways "EIP-7702".

Aggregator Responses

For aggregator endpoints (/dex/swaps, /bridge/swaps), the response data is an array — one transaction object per available route:

{
  "status": 200,
  "msg": "success",
  "data": [
    {
      "bridgeName": "Stargate",
      "amountsOut": ["999000"],
      "methodUsed": "EIP-7702",
      "to": "0x<delegation address>",
      "data": "0x<encoded batch>",
      "value": "0x0",
      "batcherContract": "0x<delegation address>"
    },
    {
      "bridgeName": "Across",
      "amountsOut": ["998500"],
      "methodUsed": "EIP-7702",
      "to": "0x<delegation address>",
      "data": "0x<encoded batch>",
      "value": "0x0",
      "batcherContract": "0x<delegation address>"
    }
  ]
}

Pick the route that fits your criteria (best rate, preferred bridge, etc.) and submit that route's transaction object. See the Quote Aggregator guide for route selection strategies.

Sending the Transaction with viem

Here's the core signing and submission flow using viem. This example uses the relay pattern (a separate account sponsors gas). For the self-executing pattern where the EOA sends its own transaction, see the Quick Start above.

import { createWalletClient, http } from "viem";
import { mainnet } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";

const eoa = privateKeyToAccount("0xEOA_PRIVATE_KEY");

const walletClient = createWalletClient({
  account: eoa.address,
  chain: mainnet,
  transport: http(),
});

// After fetching the batched transaction from the API...
const { to, value, data, batcherContract } = result.data;

// EOA signs the authorization, delegating to the smart contract
// at batcherContract (the delegation address)
const authorization = await walletClient.signAuthorization({
  account: eoa,
  contractAddress: batcherContract,
});

// Relay submits the transaction with the signed authorization
const txHash = await walletClient.sendTransaction({
  authorizationList: [authorization],
  to,
  value: BigInt(value),
  data,
});

Tip: If the EOA is also the sender, pass executor: 'self' to signAuthorization so the authorization nonce is set correctly relative to the transaction nonce. See the viem EIP-7702 docs for details.

Under the Hood

For developers who want to understand the encoding:

The API encodes all sub-calls using the ERC-7821 execute(bytes32 mode, bytes executionData) interface on the delegation address:

  • mode — Set to 0x0100...0000 (batch execution mode).
  • executionData — An ABI-encoded array of (address target, uint256 value, bytes data) tuples, one per sub-call, in this exact execution order:
    1. Fee payment (if enableFee: true)
    2. Token approval (if required)
    3. Main operation (swap, deposit, borrow, etc.)

When the EOA signs an EIP-7702 authorization for the delegation address, the EOA temporarily gains the contract's code. The execute function then runs atomically on behalf of the EOA — each sub-call executes as if the EOA itself made the call. If any sub-call reverts, the entire batch reverts.

📘

Ordering Matters

Sub-calls execute in the order they're encoded. Do not reorder the encoded data.

Wallet Compatibility

EIP-7702 requires the wallet to support signing type-4 authorization tuples that delegate the EOA to a smart contract. Check your target wallet before integrating.

Wallet TypeSupport
Wallets with native EIP-7702 support✅ Supported
Smart contract wallets (e.g., Safe, ERC-4337)✅ Use EIP-5792 instead
Legacy EOA wallets without EIP-7702❌ Not supported — use individual transactions

Fallback for unsupported wallets: Omit batchOption entirely. The API returns separate transaction objects that you submit one by one, in order:

// Without batchOption — separate transactions
const { createFeeTxn, swapTxn } = result.data;

// Always submit in order: fee first, then swap
await walletProvider.request({ method: "eth_sendTransaction", params: [createFeeTxn] });
await walletProvider.request({ method: "eth_sendTransaction", params: [swapTxn] });
⚠️

Important

When falling back to individual transactions, always submit them in order: fee → approval → main operation.


Examples

Example 1: DEX Swap with Fee (Ethereum Mainnet)

A WETH → DAI swap on Uniswap V3 with fees enabled. Uses the default Ethereum delegation address.

Request:

POST https://svc.blockdaemon.com/defi/v1/dex/swap
Content-Type: application/json
X-API-Key: <your-key>

{
  "dexId": "1300",
  "amountIn": "1000000000000000",
  "amountOutMin": "0",
  "path": [
    "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "0x6B175474E89094C44Da98b954EedeAC495271d0F"
  ],
  "to": "0x63056E00436Da25BcF48A40dfBbDcc7089351006",
  "poolFees": "3000",
  "from": "0x63056E00436Da25BcF48A40dfBbDcc7089351006",
  "gas": "173376",
  "enableFee": true,
  "batchOption": "EIP-7702"
}

Response:

{
  "status": 200,
  "msg": "success",
  "data": {
    "from": "0x63056E00436Da25BcF48A40dfBbDcc7089351006",
    "to": "0xe386b98Cd06c6aee22D66eDF97Df0476e3514222",
    "value": "0x0",
    "data": "0x6943...0000",
    "batcherContract": "0xe386b98Cd06c6aee22D66eDF97Df0476e3514222",
    "chainId": "1",
    "referenceId": "6106186031fb415bbeb3e45fd707ad18",
    "methodUsed": "EIP-7702"
  }
}

The batcherContract confirms the default Ethereum Mainnet delegation address was used.

Example 2: Lend/Borrow Deposit with Fee

Deposit USDC into Aave V3 on Ethereum with fees enabled.

Request:

POST https://svc.blockdaemon.com/defi/v1/lend-borrow/deposit
Content-Type: application/json
X-API-Key: <your-key>

{
  "lendborrowId": "1200",
  "asset": "0x65afadd39029741b3b8f0756952c74678c9cec93",
  "amount": "10000000000000000",
  "from": "0x829bFB482331b9Dc2BEcb5483ecA79c0578c3A45",
  "onBehalfOf": "0x829bFB482331b9Dc2BEcb5483ecA79c0578c3A45",
  "gas": "408298",
  "batchOption": "EIP-7702"
}

Response:

{
  "status": 200,
  "msg": "success",
  "data": {
    "from": "0x829bFB482331b9Dc2BEcb5483ecA79c0578c3A45",
    "chainId": "1",
    "referenceId": "557009b1dbbb4bc4a32124ea2804ce2e",
    "methodUsed": "EIP-7702",
    "to": "0xe386b98Cd06c6aee22D66eDF97Df0476e3514222",
    "data": "0xe9ae5c[...]00000000",
    "value": "0x0",
    "batcherContract": "0xe386b98Cd06c6aee22D66eDF97Df0476e3514222"
  }
}

Example 3: Bridge Swap with a Custom Delegation Address

Cross-chain USDT (Ethereum) → USDC (Polygon) bridge using your own smart contract as the delegation address.

Request:

POST https://svc.blockdaemon.com/defi/v1/bridge/swap-with-approval
Content-Type: application/json
X-API-Key: <your-key>

{
  "bridgeId": "600",
  "srcChainId": "1",
  "dstChainId": "137",
  "srcTokenSymbol": "USDT",
  "dstTokenSymbol": "USDC",
  "amountIn": "10000000",
  "amountOutMin": "0",
  "from": "0xdAe2F6EdDdA6fb4fb60cc02633DE27e2b431B402",
  "to": "0xdAe2F6EdDdA6fb4fb60cc02633DE27e2b431B402",
  "gasPriority": "low",
  "srcChainSymbol": "ETH",
  "enableFee": true,
  "batchOption": "EIP-7702",
  "batcherContract": "0xYourCustomContractAddress"
}
📘

Note

Your custom contract must implement ERC-7821. The API encodes sub-calls to execute(bytes32 mode, bytes executionData) regardless of which delegation address is used.


Common Mistakes and Troubleshooting

"My transaction reverted on-chain"

Likely cause: You supplied a custom batcherContract (delegation address) that doesn't implement the ERC-7821 execute interface.

Fix: Verify your contract exposes execute(bytes32 mode, bytes executionData). Test on Sepolia first.

"The wallet rejected the transaction"

Likely cause: The wallet doesn't support EIP-7702 type-4 authorization signing.

Fix: Confirm your wallet supports EIP-7702. If not, omit batchOption and submit transactions individually. For smart contract wallets, try EIP-5792 batching instead.

"I got separate transaction objects instead of a single one"

Likely cause: You forgot to include "batchOption": "EIP-7702" in the request body.

Fix: Add "batchOption": "EIP-7702" to the request. This is the only parameter needed to enable batching.

"The chainId is in decimal but my wallet expects hex"

Explanation: The API returns chainId as a decimal string (e.g., "1"). Some wallet providers expect hex (e.g., "0x1").

Fix: Convert before submitting:

const hexChainId = `0x${parseInt(chainId).toString(16)}`;

"I submitted individual transactions in the wrong order"

Explanation: When falling back to individual transactions (no batchOption), order matters. Fee must come first, then approval, then the main operation.

Fix: Always submit in sequence: createFeeTxn → approval (if present) → swapTxn / main operation.

"The response doesn't include an approval transaction"

Explanation: This is expected. The API checks the user's existing token allowance. If it already covers the required amount, the approval step is skipped — reducing gas costs.


Summary

What to remember:

  • Add "batchOption": "EIP-7702" to any supported endpoint request to enable batching. That's the only required change.
  • The API returns a single transaction object targeting the smart contract delegation address. The EOA signs an authorization delegating to this contract, and the transaction is submitted with eth_sendTransaction.
  • All sub-calls (fee, approval, swap/deposit/etc.) execute atomically — all succeed or all revert.
  • Blockdaemon manages default delegation addresses on every supported chain (returned in the batcherContract response field). You can also supply your own via the batcherContract request parameter, as long as it implements ERC-7821.
  • The wallet must support EIP-7702 authorization signing. For smart contract wallets, use EIP-5792 instead. For legacy wallets, fall back to individual transactions.
  • Supported across DEX swap, Bridge, and Lend/Borrow endpoints on 7 chains (Ethereum, Optimism, BNB Chain, Polygon, Arbitrum, Base, Sepolia).

Related Resources

ResourceDescription
Getting StartedSet up your API key and make your first DeFi API call
EIP-5792 BatchingAlternative batching via wallet_sendCalls for smart contract wallets
DEX Swap AggregatorMulti-route aggregator for best-rate swaps
Bridge SwapCross-chain bridge endpoint reference
Lend/Borrow Deposit GuideDepositing and withdrawing in vaults
Fee ConfigurationSetting up basis points and collector addresses
viem EIP-7702 Guideviem's guide to sending EIP-7702 transactions
EIP-7702 SpecificationOfficial EIP-7702 standard
ERC-7821 SpecificationMinimal batch execution interface used by the delegation address