payment_queryInfo - Bridge Hub RPC Method
Estimate transaction fees on Bridge Hub. Get the weight, dispatch class, and partial fee for an extrinsic before submitting it to the network.
Estimates the fee for an encoded extrinsic on Bridge Hub. Returns the weight, dispatch class, and partial fee so you can display costs to users or verify sufficient balance before submitting transactions.
Why Bridge Hub? Build on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum with on-chain BEEFY/Beacon light clients (no multisigs), 100+ ERC-20 tokens supported, 24+ parachain integrations, and 1-2 minute transfer times.
When to Use This Method
payment_queryInfo is essential for cross-chain developers, bridge operators, and teams requiring trustless Ethereum-Polkadot transfers:
- Fee Display -- Show users the estimated transaction cost before they sign on Bridge Hub
- Balance Validation -- Verify the sender has sufficient funds to cover the fee plus the transfer amount for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers
- Transaction Planning -- Compare fees across different extrinsic types to optimize costs
- Batch Cost Estimation -- Estimate the total cost of batch transactions before submission
Code Examples
Common Use Cases
1. Pre-Transaction Fee Display
Show fees to users before they confirm a transaction:
import { ApiPromise, WsProvider } from '@polkadot/api';
import { BN } from '@polkadot/util';
async function displayFeeEstimate(api, extrinsic, senderAddress) {
const [info, properties] = await Promise.all([
extrinsic.paymentInfo(senderAddress),
api.rpc.system.properties()
]);
const decimals = properties.tokenDecimals.toJSON()[0];
const symbol = properties.tokenSymbol.toJSON()[0];
const fee = info.partialFee;
// Convert to human-readable
const divisor = new BN(10).pow(new BN(decimals));
const whole = fee.div(divisor);
const fractional = fee.mod(divisor).toString().padStart(decimals, '0');
const formatted = `${whole}.${fractional.slice(0, 6)} ${symbol}`;
console.log(`Estimated fee: ${formatted}`);
console.log(`Dispatch class: ${info.class.toString()}`);
return { fee: fee.toString(), formatted, class: info.class.toString() };
}2. Sufficient Balance Check
Verify the sender can afford the transaction plus fees:
async function canAffordTransaction(api, senderAddress, recipient, amount) {
const transfer = api.tx.balances.transferKeepAlive(recipient, amount);
const [info, account] = await Promise.all([
transfer.paymentInfo(senderAddress),
api.query.system.account(senderAddress)
]);
const fee = info.partialFee.toBigInt();
const transferAmount = BigInt(amount);
const totalCost = fee + transferAmount;
const freeBalance = account.data.free.toBigInt();
// Account for existential deposit
const existentialDeposit = api.consts.balances.existentialDeposit.toBigInt();
const available = freeBalance - existentialDeposit;
const canAfford = available >= totalCost;
console.log(`Free balance: ${freeBalance}`);
console.log(`Total cost (amount + fee): ${totalCost}`);
console.log(`Can afford: ${canAfford}`);
return canAfford;
}3. Compare Fees Across Transaction Types
Estimate fees for different operations to find the cheapest approach:
async function compareFees(api, sender) {
const recipient = '5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY';
const amount = 1000000000000;
// Different transaction types
const extrinsics = {
'transfer': api.tx.balances.transferKeepAlive(recipient, amount),
'transferAll': api.tx.balances.transferAll(recipient, false),
'batchTransfer': api.tx.utility.batchAll([
api.tx.balances.transferKeepAlive(recipient, amount / 2),
api.tx.balances.transferKeepAlive(recipient, amount / 2)
])
};
const fees = {};
for (const [name, ext] of Object.entries(extrinsics)) {
const info = await ext.paymentInfo(sender);
fees[name] = {
partialFee: info.partialFee.toHuman(),
weight: info.weight.toString(),
class: info.class.toString()
};
}
console.table(fees);
return fees;
}Error Handling
Common errors and solutions:
| Error Code | Description | Solution |
|---|---|---|
| -32603 | Unable to query dispatch info | Ensure the extrinsic is properly encoded; verify it is a valid call for the current runtime |
| -32602 | Invalid params | Check the extrinsic hex is properly formatted with 0x prefix |
| -32005 | Rate limit exceeded | Implement client-side rate limiting or cache fee estimates for similar transactions |
| Execution error | Runtime unable to compute fee | The extrinsic may reference invalid pallets or calls; verify against current metadata |
Related Methods
author_submitExtrinsic-- Submit the extrinsic after verifying the feepayment_queryFeeDetails-- Get a detailed fee breakdown (base fee, length fee, weight fee)system_properties-- Get token decimals and symbol for formatting the feestate_call-- CallTransactionPaymentApidirectly for advanced fee queriesauthor_pendingExtrinsics-- Check pending extrinsics in the pool
author_rotateKeys
Generate new session keys for validator operations on Bridge Hub. Essential for validator setup, key rotation, and security best practices on Polkadot's trustless bridging parachain with $75M+ TVL via Snowbridge to Ethereum.
payment_queryFeeDetails
Get a detailed fee breakdown for an extrinsic on Bridge Hub. Analyze base fee, length fee, and adjusted weight fee components to optimize transaction costs for trustless ETH and ERC-20 bridging, cross-chain messaging, and parachain-to-Ethereum asset transfers.