Predictable Polygon Gas: Using EIP-1559 Type-2 Transactions in Your dApp
Polygon PoS supports EIP-1559 type-2 transactions, letting you cap worst-case gas spend instead of guessing a single gas price. Here is how to apply that pattern with ethers.js, plus the trade-offs around fee volatility and finality you need to plan for.
20 Dec 2025, 22:21 UTC

The problem: unpredictable gas costs erode user trust
If your dApp asks users to approve a transaction without a clear upper bound on cost, you are asking them to trust the network's mood. On Polygon PoS, a single gasPrice estimate can leave a user paying far more than expected during a congestion spike, or watching their transaction sit pending because the estimate was too low. EIP-1559 type-2 transactions solve part of this by letting you set an explicit ceiling.
The useful takeaway: you can cap worst-case gas spend with maxFeePerGas and influence inclusion speed with maxPriorityFeePerGas, but you must still plan for base-fee volatility and Polygon's checkpoint-based finality.
Type-2 transactions give you a ceiling, not a guess
Polygon PoS supports EIP-1559, so instead of one gasPrice field you provide two values. maxFeePerGas is the absolute maximum you will pay per unit of gas; anything above the effective price is refunded. maxPriorityFeePerGas is the tip that incentivizes validators to include your transaction sooner.
The network exposes standard JSON-RPC methods to inform these values. eth_maxPriorityFeePerGas returns a suggested tip, and eth_feeHistory shows recent base-fee trends so you can add a buffer instead of hardcoding a constant. One caution: Polygon operates multiple networks—PoS, zkEVM, and others—with different fee behavior and token symbols. Always confirm your endpoint with eth_chainId before applying this pattern.
Worked example: bounding a transfer with ethers.js
The example below uses ethers v6 to fetch fee data, construct a type-2 transaction, and send it to a Polygon PoS RPC endpoint. Run it in a Node.js environment where the private key is loaded from a secure secret manager, never from client-side code.
import { JsonRpcProvider, Wallet, parseEther, parseUnits, formatUnits } from "ethers";
// Replace with your Polygon PoS RPC endpoint and a funded signer key.
const RPC_URL = "https://polygon-rpc.com";
const PRIVATE_KEY = "0x...";
const RECIPIENT = "0x...";
async function sendBoundedTx() {
const provider = new JsonRpcProvider(RPC_URL);
// Confirm the network. A common Polygon PoS mainnet chainId is 137; verify yours.
const chainIdHex = await provider.send("eth_chainId", []);
console.log(`Connected to chainId: ${parseInt(chainIdHex, 16)}`);
// Fetch a suggested priority fee and the latest base fee.
const priorityHex = await provider.send("eth_maxPriorityFeePerGas", []);
const suggestedPriority = BigInt(priorityHex);
const latestBlock = await provider.getBlock("latest");
const baseFee = latestBlock?.baseFeePerGas ?? 0n;
// Add a buffer to cover near-term base-fee movement.
const buffer = parseUnits("30", "gwei");
const maxFeePerGas = baseFee + suggestedPriority + buffer;
const wallet = new Wallet(PRIVATE_KEY, provider);
const tx = await wallet.sendTransaction({
to: RECIPIENT,
value: parseEther("0.001"),
maxFeePerGas,
maxPriorityFeePerGas: suggestedPriority,
type: 2,
});
console.log(`Transaction sent: ${tx.hash}`);
const receipt = await tx.wait();
if (receipt) {
// Expected checks: status should be 1, and receipt.gasPrice must not exceed maxFeePerGas.
const totalFee = receipt.gasUsed * receipt.gasPrice;
console.log(`Gas used: ${receipt.gasUsed}`);
console.log(`Effective gas price: ${formatUnits(receipt.gasPrice, "gwei")} gwei`);
console.log(`Total fee: ${formatUnits(totalFee, "ether")} POL`);
}
}
sendBoundedTx().catch(console.error);
After sending, inspect the receipt. The gasUsed field tells you actual execution cost, and receipt.gasPrice is the effective price paid per gas unit. If that value ever exceeds your maxFeePerGas, your node or estimator is misbehaving. If the transaction remains pending, your maxPriorityFeePerGas is likely too low relative to competing transactions.
Trade-offs: volatility, native-token friction, and finality
A hard cap is not a fixed price. Polygon's base fee can spike during congestion. If you set maxFeePerGas too low, the transaction may stay pending until the base fee falls or you replace it. If you set maxPriorityFeePerGas generously to avoid that risk, the user pays a larger tip than necessary. UX teams must decide whether to absorb that overpayment or accept the risk of a stuck transaction.
Fees are denominated in the network's native gas token—POL, formerly MATIC—not in an ERC-20. If a user holds only stablecoins or bridged assets, they cannot transact until they acquire POL. Token economics and validator rewards are also version-sensitive; upgrades can change how fees are burned or distributed, so re-verify fee flow after major network changes.
Finally, do not treat a Polygon confirmation as an Ethereum L1 finality equivalent. Polygon PoS relies on a separate validator set and periodic checkpointing to Ethereum. A transaction confirmed on Polygon is probabilistic until the relevant checkpoint is submitted and verified on Ethereum. For high-value actions, wait for checkpoint milestones rather than counting block confirmations alone.
Checklist before you ship
- Call
eth_chainIdon startup and confirm you are on the intended Polygon network. - Use
eth_feeHistoryto setmaxFeePerGasdynamically; avoid hardcoded gas constants. - Run your fee-estimation logic against two independent RPC providers and compare results. Large discrepancies may indicate node version drift or provider-specific policies.
- Log estimated versus actual
gasUsedandeffectiveGasPrice, and alert when the base fee crosses a threshold that would make your default cap too tight. - Provide an in-app path for users to acquire the native gas token before they attempt a transaction.
- Document your finality assumptions: for irreversible operations, wait for Ethereum checkpoint confirmation, not just Polygon block depth.
Predictable gas is an engineering discipline, not a network guarantee. Bound the cost, instrument the reality, and respect the checkpoint boundary.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.