getGaslessBatchFeeQuote
Preview what relayGaslessBatch would charge for the same calls — before any signature prompt, and without building a single operation by hand. It is the way to show a gasless fee next to any action, from one relayable write to a mixed batch.
import { getGaslessBatchFeeQuote } from "@symmio/trading-core";
import { formatUnits } from "viem";
const quote = await getGaslessBatchFeeQuote(config, {
account: subAccount,
calls: [
{ functionName: "allocate", args: [amount] },
{ walletId: 1n, walletCalls: [{ target: usdc, abi: erc20Abi, functionName: "transfer", args: [to, value] }] },
],
});
formatUnits(quote.totalFee18, 18); // the batch total, e.g. "0.1"
quote.payments[1]; // the wallet entry's own rowThe calls are resolved exactly as the relay resolves them, encoded as the relayInstantBatch call the relayer submits, and priced by the GaslessLayer’s previewFeeQuote. The preview never checks nonces, deadlines, salts or signatures, so they are fixed placeholders: the result depends only on the account and the calls, and it caches cleanly — a call given by functionName, by abi or as raw data shares one cache entry.
Only a batch with GaslessWallet entries pays for extra reads: the preview rejects a wallet operation whose target is not the real wallet, so the SDK resolves the account’s owner and the wallet address first.
Reading the quote
The quote is the same GaslessFeeQuote getGaslessFeeQuote returns — every amount 18-decimal:
paymentshas one row per call, in order. A GaslessWallet entry is one row, priced by its inner call selectors, and it carrieswalletCreationFee18when it is the first to execute from an undeployed wallet.totalFee18is the batch total. Grouppaymentsbypayerandsourceto tell the user which balance pays: a relayed batch is charged to the SYMMIO account’s Core balance, bounded by its operational-fee allowance — never to the wallet.freeOpsAppliedcounts the calls the daily free quota covers. Quote the whole batch at once: free-quota slots and first-use creation fees are allocated across it.
A preview, not a guarantee. exact is always false. An approval or a transfer inside the batch can change the
final fee or its payer, and so can any state change before execution. The quote does not check that the payer can
afford it — the relayer’s own simulation is authoritative. An exhausted daily free quota on a deployment that refuses
paid operations is an error, GASLESS_FREE_QUOTA_EXHAUSTED, not a zero fee.
React consumers use useGaslessBatchFeeQuote. Plain TanStack Query consumers use getGaslessBatchFeeQuoteQueryOptions(config, { account, calls }); its key holds each call’s encoded calldata rather than its ABI, and a call whose arguments do not encode yet keys deterministically instead of throwing, so the key is safe to build while a form is still being filled in.
Parameters
accountAddressrequiredThe sub-account every operation runs under — the account relayGaslessBatch would relay with. It decides the
billing account (a virtual account bills its parent) and, for wallet entries, which owner’s wallets execute.
callsreadonly GaslessBatchCall[]requiredThe batch, in relay order, in any of the call forms. An empty list throws
GASLESS_EMPTY_BATCH.
chainIdnumberoptionalTarget chain id. Defaults to the config’s defaultChainId.
Returns
Promise<GaslessFeeQuote>The preview — see getGaslessFeeQuote for every field.
Throws
SymmError("config", "GASLESS_NOT_CONFIGURED")/("config", "GASLESS_UNSUPPORTED_CONTRACTS_VERSION").SymmError("validation", "GASLESS_EMPTY_BATCH"),("validation", "GASLESS_NOT_RELAYABLE")or("validation", "GASLESS_WALLET_ID_INVALID"): thrown before any RPC call.- Viem’s encoding error when an ABI-level call’s arguments do not encode.
SymmError("api", "GASLESS_FREE_QUOTA_EXHAUSTED"),("validation", "GASLESS_FEE_QUOTE_REVERTED")or("config", "GASLESS_LAYER_INTERFACE_UNSUPPORTED"), exactly asgetGaslessFeeQuotethrows them.- Viem transport errors, unchanged.