Batch & Sponsor Transactions (ERC-5792)
Batched transactions allows apps to perform multiple actions in one single on-chain transaction. 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. ERC-5792 standarizes the communication between the App and the Wallet.
InstaGas is a no-code solution for apps, 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. Thanks to ERC-7677, which is an extension to ERC-5792 which standarizes the communication of gas sponsorship between the App and the Wallet. Apps can still send InstaGas info programmatically to Wallets.

Who is live?
The following apps and wallets support smart capabilities.
Apps
Wallets
- Coinbase Smart Wallet
- Ambire
- Safe{Wallet}
- MetaMask Extension v12.15 on Sepolia
- Reown AppKit
- thirdweb InApp
- Openfort
- Abstract Global
Our Favourites ❤️
PoolTogether and Candide
Back then where we were first building Candide Wallet, Pooltogether proposed to sponsor gas to enable No-Loss donation to fund public goods.
Sponsorship was tailored with precision. PoolTogether leveraged InstaGas Transaction Rules to limit sponsorship to only a selected methods qualify on PoolTogether Contracts; necessitating a minimum deposit of 200 USDC and a lock duration of 14 days. This precision safeguarded against Sybil attacks and fortifies the integrity of PoolTogether’s Gas Sponsorship Funds.

Demo example
This exampe demo communicating a batch of transactions and the gas sponsorship info of InstaGas directly to the Wallet.
candidelabs/batch-sponsor-calls-instagas
Quickstart with Viem/WAGMI
Step 1: Get Wallet Capabilities
Example using wagmi useCapabilities hook
- Usage
- Response
import { useCapabilities } from 'wagmi/experimental';
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
- Create an App on dashboard.candide.dev/api-keys
- Copy the paymaster URL link with the API key and fill in the
candidePaymasterUrl
- Create a Gas Policy and customise it with your rules
Learn how to setup a gas policy
The example below uses WAGMI useSendCalls hook that shows how to send two actions in a single one. Your app shouldfallback to sending normal transactions if the wallet doesn't support smart batching capabilities.
import { useSendCalls } from 'wagmi/experimental'
import { useChainId, useSendTransaction } from 'wagmi';
import { toHex } from 'viem';
const { sendCalls, data: id } = useSendCalls(); // wagmi hook to send batch & sponsored tx
const { sendTransaction } = useSendTransaction(); // wagmi hook to send standard tx
const chainId = useChainId();
const paymasterUrl = "https://api.candide.dev/paymaster/v3/network/APY_KEY";
const handleSendTx = () => {
// check if capabilities are supported
try {
sendCalls({
calls: [
{
to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Vitalik's address
value: parseGwei('0'),
data: "0x" as Hex,
},
{
to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Vitalik's address
value: parseGwei('0'),
data: "0x" as Hex,
}
],
capabilities: {
paymasterService: {
[toHex(chainId)]: {
url: paymasterUrl,
}
}
},
});
} else {
// fallback to regular sendTransactions
sendTransaction({
to: "0xd8da6bf26964af9d7eed9e03e53415d37aa96045", // Vitalik's address
value: parseGwei('0'),
data: "0x" as Hex,
});
}
} catch (err) {
sendError(`Error sending transaction:'${err}`)
}
Step 3: Track Transaction Status
Example using wagmi useCallsStatus hook
import { useCallsStatus } from 'wagmi/experimental'
const { data: callStatusData, refetch: refetchCallStatus } = useCallsStatus({
id: id as string,
query: {
enabled: !!id,
refetchInterval: (data) => data.state.data?.status === "CONFIRMED" ? false : 1000,
},
});
Optional: if you've lost track of the transaction, you can also delegate showing the status to the wallet directly using useShowCallsStatus.
EIP-5792 Spec
EIP-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
These requests are sent to Wallets, not to nodes. These RPC requests are communicated directly to the wallet through a standard EIP-1193 custom requests.
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": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"chainId": "0x01",
"atomicRequired": true,
"calls": [
{
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x9184e72a",
"data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"
},
{
"to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567",
"value": "0x182183",
"data": "0xfbadbaf01"
}
],
"capabilities": {
"paymasterService": {
"url": "https://...",
"context": {
"sponsorshipPolicyId": "962b252c"
}
}
}
}
]
{
"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"
}
}