Skip to main content

Batch & Sponsor Transactions (via ERC-5792)

If you are building a Dapp, you communicate the actions to the wallet that the user performs. Instead of sending a single transaction one after the other, you can send an array of transactions, and the wallet will execute the bundle.

EIPs Definitions

  • ERC-5792 standarizes the general communication between the Dapp and the Wallet, with batching as the default capability.
  • ERC-7677 standrizes the communication of Gas Sponsorship capability.

Who is live?

The following apps and wallets support smart capabilities.

Wallets

WalletBatchingSponsor Gas
AmbireERC-7677
Coinbase Smart WalletERC-7677
Reown AppKitERC-7677
thirdweb InAppERC-7677
OpenfortERC-7677
Safe{Wallet}via its Relayer
Abstract Globalvia its Relayer
MetaMask Extension✖️

Apps

AppBatchingSponsor Gas
PoolTogether CabanaERC-767
revoke.cashERC-7677
Lido✖️
Lifi✖️
Jumper.Exchange✖️
PoolTogether PoolTime✖️
Ekubo Exchange✖️
Uniswap Exchange✖️
Vaults.fyi✖️
Spark✖️
Reserve✖️
Matcha✖️
Ethena✖️
Fibrous✖️
PWN✖️
Relay✖️
Relay✖️

Reference example

This exampe demo communicating a batch of transactions and the gas sponsorship info directly to the Wallet.

Quickstart with Viem/WAGMI

Installation

npm install viem wagmi
note

EIP-5792 is supported beginning with viem@2.30 and wagmi@2.15.4 and later

Step 1: Get Wallet Capabilities

Example using wagmi useCapabilities hook

import { useCapabilities } from 'wagmi';

const { data: capabilities } = useCapabilities({
account: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // account address
});

console.log(capabilities);

Step 2: Batch & Sponsor Transactions

The example below uses WAGMI useSendCalls hook that shows how to send two actions in a single one. Your app should fallback to sending normal transactions if the wallet doesn't support smart batching capabilities.

Gas Sponsorship

InstaGas is a no-code solution for Dapps, provided that the wallet natively use Candide's Paymaster API. However, this integration is not a barrier for Apps wishing to sponsor gas fees for wallets that do not natively support Candide. In this step, we demonstrate how to use ERC-7677, which is an extension to ERC-5792 that standarizes the communication of gas sponsorship between the App and the Wallet.

  1. Create an App on dashboard.candide.dev/api-keys
  2. Copy the paymaster URL link with the API key and fill in the candidePaymasterUrl
  3. Setup a Gas Policy and customise it with your rules
import { useSendCalls } from 'wagmi'
import { useChainId, useSendTransaction } from 'wagmi';
import { toHex, zeroAddress } from 'viem';

const { sendCalls, data: id } = useSendCalls(); // to send batch & sponsored tx
const { sendTransaction } = useSendTransaction(); // to send standard tx
const chainId = useChainId();

const paymasterUrl = "https://api.candide.dev/paymaster/v3/network/APY_KEY";
const sponsorshipPolicyId = process.env.SPONSORSHIP_POLICY_ID;

const tx = {
to: zeroAddress as Address,
value: parseGwei('0'),
data: zeroAddress as Hex,
};

const handleSendTx = () => {
// if smart capabilities are supported, send a batched and optionally sponsored transaction
try {
if (!capabilities) {
// Fallback to standard sendTransactions if capabilities are not available
sendTransaction(tx);
return;
}

const atomicStatus = capabilities[chainId].atomic?.status;
const isAtomicSupported = atomicStatus === "supported" || atomicStatus === "ready";

if (isAtomicSupported) {
sendCalls({
calls: [TEST_TX, TEST_TX],
// and sponsor the tx, optionally with a sponsorshipPolicyId
capabilities: {
paymasterService: {
url: paymasterUrl,
optional: true,
context: {
sponsorshipPolicyId,
}
}
},
});
} else {
// if not, fallback to standard sendTransactions
sendTransaction(tx);
}
} catch (err) {
sendError(`Error sending transaction:'${err}`)
console.log('Error sending transaction:', err);
}
};

Step 3: Track Transaction Status

Example using wagmi useCallsStatus hook

import { useCallsStatus } from 'wagmi'

const { data: callStatusData, refetch: refetchCallStatus } = useCallsStatus({
id: id?.id || '',
query: {
enabled: !!id,
refetchInterval: (data) =>
data.state.data?.status === "success" ? false : 1000,
},
});

Optional: if you've lost track of the transaction, you can also delegate showing the status to the wallet directly using useShowCallsStatus.

ERC-5792 Spec

ERC-5792 allows us to standardize JSON-RPC methods for apps to communicate bundle calls to wallets. The flow is usually in this order:

  1. wallet_getCapabilities: App checks which capabilties the wallet support (e.g: batching, sponsorship, ..)
  2. wallet_sendCalls: App sends the batch transactions
  3. wallet_getCallsStatus: App requests to get the status (e.g: pending, confirmed, failed)
  4. wallet_showCallsStatus: optional method for app to request to show the status of the transaction on the wallet interface

wallet_getCapabilities

This RPC allows an application to request capabilities from a wallet (e.g. batch transactions, paymaster communication), without distinct discovery and permission requests.

Invocation

{ "method": "wallet_getCapabilities", "params": [address, [chainId]] }

Return

{ "result": { capabilities } }
["0xd46e8dd67c5d32be8058bb8eb970870f07244567", ["0x2105", "0x14A34"]]

wallet_sendCalls

Requests that the wallet deliver a group of function calls on-chain from the user’s wallet.

Invocation

{ "method": "wallet_sendCalls", "params": [{ chainId, from, calls }] }

Return

{ "result": { transactionHash } }
[
{
"version": "1.0",
"from": "0x0000000000000000000000000000000000000000",
"chainId": "0x01",
"atomicRequired": true,
"calls": [
{
"to": "0x0000000000000000000000000000000000000000",
"value": "0x",
"data": "0x"
},
{
"to": "0x0000000000000000000000000000000000000000",
"value": "0x",
"data": "0x"
}
],
"capabilities": {
"paymasterService": {
"url": "https://...",
"optional": true,
"context" {
"sponsorshipPolicyId": "123",
}
}
}
}
}
]

wallet_getCallsStatus

Returns the status of a bundle that was sent via wallet_sendCalls. The identifier of the bundle is the value returned from the wallet_sendCalls RPC.

Invocation

{ "method": "wallet_getCallsStatus", "params": [transactionHash] }

Return

{ "result": { calls } }
{
"jsonrpc": "2.0",
"id": 0,
"result": "0xe67asds.."
}

wallet_showCallsStatus

Requests that the wallet present UI showing the status of the given bundle. This allows apps to delegate the display of the function call status to the wallet, which can most accurately render the current status of the bundle. This RPC is intended to replace the typical user experience of a dapp linking to a block explorer for a given transaction hash.

Invocation

{ "method": "wallet_showCallsStatus", "params": [transactionHash] }

Return

{ "result": call }
{
"jsonrpc": "2.0",
"id": 0,
"result": "0xe67asds.."
}