Skip to main content

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

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.

See Video announcement

PoolTogether Sponsorship

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

import { useCapabilities } from 'wagmi/experimental';

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

console.log(capabilities);

Step 2: Batch & Sponsor Transactions

  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. 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:

  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
Did you know?

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 } }
["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": "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"
}
}
}
}
]

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.."
}