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
Wallet | Batching | Sponsor Gas |
---|---|---|
Ambire | ✅ | ERC-7677 |
Coinbase Smart Wallet | ✅ | ERC-7677 |
Reown AppKit | ✅ | ERC-7677 |
thirdweb InApp | ✅ | ERC-7677 |
Openfort | ✅ | ERC-7677 |
Safe{Wallet} | ✅ | via its Relayer |
Abstract Global | ✅ | via its Relayer |
MetaMask Extension | ✅ | ✖️ |
Apps
App | Batching | Sponsor Gas |
---|---|---|
PoolTogether Cabana | ✅ | ERC-767 |
revoke.cash | ✅ | ERC-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.
- Live Demo batch-and-sponsor.on-fleek.app
- Source code candidelabs/batch-sponsor-calls-instagas
Quickstart with Viem/WAGMI
Installation
npm install viem wagmi
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
- Usage
- Response
import { useCapabilities } from 'wagmi';
const { data: capabilities } = useCapabilities({
account: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // account address
});
console.log(capabilities);
{
"1": {
"paymasterService": {
"supported": true
},
"atomic": {
"supported": true
}
},
"10": {
"paymasterService": {
"supported": true
},
"atomic": {
"supported": true
}
},
}
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.
- Create an App on dashboard.candide.dev/api-keys
- Copy the paymaster URL link with the API key and fill in the
candidePaymasterUrl
- 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:
wallet_getCapabilities
: App checks which capabilties the wallet support (e.g: batching, sponsorship, ..)wallet_sendCalls
: App sends the batch transactionswallet_getCallsStatus
: App requests to get the status (e.g: pending, confirmed, failed)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 } }
- Example Request
- Example Response
["0xd46e8dd67c5d32be8058bb8eb970870f07244567", ["0x2105", "0x14A34"]]
{
"0x0": {
"flow-control": {
"supported": true
}
},
"0x2105": {
"paymasterService": {
"supported": true
},
"sessionKeys": {
"supported": true
}
},
"0x14A34": {
"auxiliaryFunds": {
"supported": true
}
}
}
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 } }
- Example Request
- Example Response
[
{
"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",
}
}
}
}
}
]
{
"jsonrpc": "2.0",
"id": 0,
"result": "0xe67asds.."
}
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 } }
- Example Request
- Example Response
{
"jsonrpc": "2.0",
"id": 0,
"result": "0xe67asds.."
}
{
"version": "1.0",
"chainId": "0x01",
"id": "0x00000000000000000000000000000000000000000000000000000000000000000e670ec64341771606e55d6b4ca35a1a6b75ee3d5145a99d05921026d1527331",
"status": 200,
"atomic": true,
"receipts": [
{
"logs": [
{
"address": "0xa922b54716264130634d6ff183747a8ead91a40b",
"topics": [
"0x5a2a90727cc9d000dd060b1132a5c977c9702bb3a52afe360c9c22f0e9451a68"
],
"data": "0xabcd"
}
],
"status": "0x1",
"blockHash": "0xf19bbafd9fd0124ec110b848e8de4ab4f62bf60c189524e54213285e7f540d4a",
"blockNumber": "0xabcd",
"gasUsed": "0xdef",
"transactionHash": "0x9b7bb827c2e5e3c1a0a44dc53e573aa0b3af3bd1f9f5ed03071b100bb039eaff"
}
]
}
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 }
- Example Request
- Example Response
{
"jsonrpc": "2.0",
"id": 0,
"result": "0xe67asds.."
}
{
status: "CONFIRMED"
receipt: {
logs: [..]
success: true
blockHash: "0x84b9f48e922c6b500fa07a1e94144cb1452f2466199fc726e807d31bae6b4e52"
blockNumber: "0x7dbc3c"
gasUsed: "0x25c8e"
transactionHash: "0xcb8c43372800586bffc7521e0ca09f8828a87d4f0003f36ea68f9cbcf3e229f9"
}
}