Gas & Fees
This page explains how zksync-js quotes deposit gas and fees.
Source Of Truth
The protocol constants and validator rules used by the SDK come from era-contracts:
The SDK mirrors those constants in code, but the contracts above are the protocol source of truth.
Deposit Quotes
Deposit quotes are conservative caps, not realized post-execution charges.
fees.l2.gasLimitis the quoted L2 execution budget used to price the priority transaction.fees.l2.baseCostis the result ofBridgehub.l2TransactionBaseCost(...)for that budget.fees.l2.total = fees.l2.baseCost + operatorTip.fees.maxTotal = fees.l1.maxTotal + fees.l2.total.fees.mintValueis the amount funded into the Bridgehub request. For direct base-token deposits, it includes the transferred L2 value as well as the quoted L2 fee reserve.
That means explorer gasUsed and realized L2 fee can be lower than the quote.
Deposits
Direct Deposits: eth-base and erc20-base
Direct deposits use the exact canonical priority-transaction encoding and the validator floor from TransactionValidator.
The SDK computes the exact abi.encode(L2CanonicalTransaction) length for the direct request shape, then applies:
minBodyGas =
max(
L1_TX_INTRINSIC_L2_GAS +
ceilDiv(encodedLength * L1_TX_DELTA_544_ENCODING_BYTES, 544),
L1_TX_MIN_L2_GAS_BASE,
) +
L1_TX_INTRINSIC_PUBDATA * gasPerPubdata
overhead =
max(
TX_SLOT_OVERHEAD_L2_GAS,
MEMORY_OVERHEAD_GAS * encodedLength,
)
l2GasLimit = minBodyGas + overhead
This is the quoted cap for direct deposits unless the caller explicitly overrides l2GasLimit.
Two-Bridges Asset-Router Deposits: erc20-nonbase and eth-nonbase
For non-base asset-router deposits, the quote depends on whether the bridged asset is already deployed on L2.
Deployed Token Path
When the bridged asset already exists on L2, the SDK asks L1AssetRouter.getDepositCalldata(...) for the exact L2 finalize-deposit calldata, computes the exact canonical priority-transaction encoding length, and applies the same validator-floor formula shown above.
This keeps the quote asset-specific because calldata length depends on the actual bridge payload.
First Deployment Path
For undeployed erc20-nonbase and eth-nonbase deposits, exact deployment-path estimates can fluctuate across environments and underquote the real L2 execution. The SDK therefore uses a calibrated dynamic cap derived from the validator floor instead of trusting the exact estimate:
bodyGas = minBodyGas * 6
l2GasLimit = bodyGas + overhead
This still scales with the exact calldata length and gasPerPubdata, but avoids environment-specific low estimates on first deployment.
Base Cost Pricing
After the route chooses l2GasLimit, the SDK prices it with:
baseCost = Bridgehub.l2TransactionBaseCost(
chainId,
l1GasPrice,
l2GasLimit,
gasPerPubdata,
)
So the gas-limit model and the gas-price model are separate:
l2GasLimitis the execution budget.l1GasPriceandgasPerPubdatadetermine how that budget is priced.
Manual Overrides
If you pass l2GasLimit, the SDK uses your override instead of the route-specific model.
This is useful for controlled environments, but for general-purpose quoting the built-in route models are safer because they align with the current deposit path and protocol validator rules.