eth_estimateL1Fee
Estimate L1 data posting fee on the Linea zkEVM network. This method helps calculate the additional cost of posting transaction data to Ethereum L1 as part of Linea's zkEVM rollup architecture.
Overview
Linea zkEVM is a Layer 2 rollup that periodically submits batched transaction data and proofs to Ethereum L1. While most transaction execution happens on L2 with low gas costs, there's an additional fee component for the L1 data availability costs.
Parameters
Parameter | Type | Required | Description |
---|---|---|---|
transaction | Object | Yes | Transaction object to estimate L1 fee for |
Transaction Object
Field | Type | Required | Description |
---|---|---|---|
from | Address | No | Sender address |
to | Address | No | Recipient address |
gas | Quantity | No | Gas limit |
gasPrice | Quantity | No | Gas price in wei |
value | Quantity | No | Value to transfer in wei |
data | Data | No | Transaction data |
Returns
Type | Description |
---|---|
QUANTITY | Estimated L1 fee in wei |
Implementation Example
- cURL
- JavaScript
- Python
curl -X POST https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "eth_estimateL1Fee",
"params": [
{
"from": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5",
"to": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
"gas": "0x5208",
"gasPrice": "0x3b9aca00",
"value": "0x1bc16d674ec80000",
"data": "0x"
}
],
"id": 1
}'
const response = await fetch('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_estimateL1Fee',
params: [
{
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
gas: '0x5208',
gasPrice: '0x3b9aca00',
value: '0x1bc16d674ec80000',
data: '0x'
}
],
id: 1
})
});
const data = await response.json();
console.log('L1 Fee:', data.result);
// Advanced L1 fee estimation with transaction cost breakdown
class LineaFeeEstimator {
constructor(rpcUrl) {
this.rpcUrl = rpcUrl;
}
async estimateL1Fee(transaction) {
const response = await fetch(this.rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_estimateL1Fee',
params: [transaction],
id: 1
})
});
const data = await response.json();
if (data.error) {
throw new Error(`RPC Error: ${data.error.message}`);
}
return parseInt(data.result, 16);
}
async getFullFeeBreakdown(transaction) {
try {
// Estimate L2 gas cost
const l2GasResponse = await fetch(this.rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_estimateGas',
params: [transaction],
id: 1
})
});
const l2GasData = await l2GasResponse.json();
const l2GasEstimate = parseInt(l2GasData.result, 16);
// Get current gas price
const gasPriceResponse = await fetch(this.rpcUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
jsonrpc: '2.0',
method: 'eth_gasPrice',
params: [],
id: 1
})
});
const gasPriceData = await gasPriceResponse.json();
const gasPrice = parseInt(gasPriceData.result, 16);
// Estimate L1 fee
const l1Fee = await this.estimateL1Fee(transaction);
// Calculate L2 execution cost
const l2ExecutionCost = l2GasEstimate * gasPrice;
return {
l1Fee: l1Fee,
l2ExecutionCost: l2ExecutionCost,
totalEstimatedCost: l1Fee + l2ExecutionCost,
gasEstimate: l2GasEstimate,
gasPrice: gasPrice,
breakdown: {
l1FeePercentage: ((l1Fee / (l1Fee + l2ExecutionCost)) * 100).toFixed(2),
l2FeePercentage: ((l2ExecutionCost / (l1Fee + l2ExecutionCost)) * 100).toFixed(2)
}
};
} catch (error) {
throw new Error(`Failed to get fee breakdown: ${error.message}`);
}
}
async compareFeesByDataSize(baseTransaction, dataSizes) {
const results = [];
for (const size of dataSizes) {
// Generate test data of specified size
const testData = '0x' + '00'.repeat(size);
const testTransaction = {
...baseTransaction,
data: testData
};
try {
const breakdown = await this.getFullFeeBreakdown(testTransaction);
results.push({
dataSize: size,
dataSizeKB: (size / 1024).toFixed(2),
l1Fee: breakdown.l1Fee,
l2ExecutionCost: breakdown.l2ExecutionCost,
totalCost: breakdown.totalEstimatedCost,
l1FeePerByte: breakdown.l1Fee / size,
costIncrease: size === dataSizes[0] ? 0 :
((breakdown.totalEstimatedCost - results[0].totalCost) / results[0].totalCost * 100).toFixed(2)
});
} catch (error) {
results.push({
dataSize: size,
error: error.message
});
}
}
return results;
}
async optimizeTransactionCost(transaction) {
const recommendations = [];
// Get baseline cost
const baseline = await this.getFullFeeBreakdown(transaction);
// Check if transaction has unnecessary data
if (transaction.data && transaction.data.length > 2) {
// Estimate with minimal data
const minimalTx = { ...transaction, data: '0x' };
const minimal = await this.getFullFeeBreakdown(minimalTx);
const dataCostSavings = baseline.l1Fee - minimal.l1Fee;
if (dataCostSavings > 0) {
recommendations.push({
type: 'data_optimization',
description: 'Consider reducing transaction data size',
potentialSavings: dataCostSavings,
savingsPercentage: ((dataCostSavings / baseline.totalEstimatedCost) * 100).toFixed(2)
});
}
}
// Check gas optimization
if (baseline.gasEstimate > 100000) {
recommendations.push({
type: 'gas_optimization',
description: 'High gas usage detected - consider optimizing contract calls',
currentGas: baseline.gasEstimate,
suggestion: 'Review contract logic for gas efficiency'
});
}
// Check if L1 fees dominate
if (parseFloat(baseline.breakdown.l1FeePercentage) > 70) {
recommendations.push({
type: 'l1_fee_dominance',
description: 'L1 fees represent majority of transaction cost',
l1Percentage: baseline.breakdown.l1FeePercentage,
suggestion: 'Consider batching transactions or reducing data payload'
});
}
return {
baseline: baseline,
recommendations: recommendations,
optimizationPotential: recommendations.length > 0
};
}
}
// Usage examples
const feeEstimator = new LineaFeeEstimator('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
// Basic L1 fee estimation
const l1Fee = await feeEstimator.estimateL1Fee({
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
value: '0x1bc16d674ec80000',
data: '0x'
});
console.log(`L1 Fee: ${l1Fee} wei`);
// Full fee breakdown
const breakdown = await feeEstimator.getFullFeeBreakdown({
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
value: '0x1bc16d674ec80000',
data: '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
});
console.log('Fee Breakdown:', breakdown);
// Compare fees by data size
const dataSizeComparison = await feeEstimator.compareFeesByDataSize(
{
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'
},
[0, 100, 500, 1000, 5000] // bytes
);
console.log('Data Size Impact:', dataSizeComparison);
// Optimization suggestions
const optimization = await feeEstimator.optimizeTransactionCost({
from: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
to: '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
data: '0xa9059cbb' + '0'.repeat(1000) // Large data payload
});
console.log('Optimization Analysis:', optimization);
import requests
import json
from typing import Dict, List, Any, Optional
class LineaFeeEstimator:
"""Estimate L1 fees and analyze transaction costs on Linea zkEVM"""
def __init__(self, rpc_url: str):
self.rpc_url = rpc_url
def estimate_l1_fee(self, transaction: Dict[str, Any]) -> int:
"""Estimate L1 data posting fee for a transaction"""
payload = {
"jsonrpc": "2.0",
"method": "eth_estimateL1Fee",
"params": [transaction],
"id": 1
}
response = requests.post(self.rpc_url, json=payload)
data = response.json()
if 'error' in data:
raise Exception(f"RPC Error: {data['error']['message']}")
return int(data['result'], 16)
def _make_rpc_call(self, method: str, params: List = None) -> Any:
"""Helper method for RPC calls"""
payload = {
"jsonrpc": "2.0",
"method": method,
"params": params or [],
"id": 1
}
response = requests.post(self.rpc_url, json=payload)
data = response.json()
if 'error' in data:
raise Exception(f"RPC Error: {data['error']['message']}")
return data['result']
def get_full_fee_breakdown(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
"""Get complete fee breakdown including L1 and L2 costs"""
# Estimate L2 gas
l2_gas_estimate = int(self._make_rpc_call('eth_estimateGas', [transaction]), 16)
# Get current gas price
gas_price = int(self._make_rpc_call('eth_gasPrice'), 16)
# Estimate L1 fee
l1_fee = self.estimate_l1_fee(transaction)
# Calculate L2 execution cost
l2_execution_cost = l2_gas_estimate * gas_price
total_cost = l1_fee + l2_execution_cost
return {
'l1_fee': l1_fee,
'l2_execution_cost': l2_execution_cost,
'total_estimated_cost': total_cost,
'gas_estimate': l2_gas_estimate,
'gas_price': gas_price,
'breakdown': {
'l1_fee_percentage': round((l1_fee / total_cost) * 100, 2) if total_cost > 0 else 0,
'l2_fee_percentage': round((l2_execution_cost / total_cost) * 100, 2) if total_cost > 0 else 0
}
}
def analyze_data_cost_impact(
self,
base_transaction: Dict[str, Any],
data_payloads: List[str]
) -> List[Dict[str, Any]]:
"""Analyze how different data payloads affect L1 fees"""
results = []
for i, data in enumerate(data_payloads):
test_tx = {**base_transaction, 'data': data}
try:
breakdown = self.get_full_fee_breakdown(test_tx)
data_size = (len(data) - 2) // 2 if data.startswith('0x') else len(data) // 2
result = {
'data_payload': data[:20] + '...' if len(data) > 20 else data,
'data_size_bytes': data_size,
'l1_fee': breakdown['l1_fee'],
'l2_execution_cost': breakdown['l2_execution_cost'],
'total_cost': breakdown['total_estimated_cost'],
'l1_fee_per_byte': breakdown['l1_fee'] / data_size if data_size > 0 else 0
}
# Calculate cost increase relative to first payload
if i > 0 and results:
base_cost = results[0]['total_cost']
result['cost_increase_pct'] = round(
((result['total_cost'] - base_cost) / base_cost) * 100, 2
) if base_cost > 0 else 0
else:
result['cost_increase_pct'] = 0
results.append(result)
except Exception as e:
results.append({
'data_payload': data[:20] + '...' if len(data) > 20 else data,
'error': str(e)
})
return results
def suggest_optimizations(self, transaction: Dict[str, Any]) -> Dict[str, Any]:
"""Analyze transaction and suggest cost optimizations"""
baseline = self.get_full_fee_breakdown(transaction)
suggestions = []
# Check data optimization potential
if transaction.get('data') and len(transaction['data']) > 2:
minimal_tx = {**transaction, 'data': '0x'}
minimal_cost = self.get_full_fee_breakdown(minimal_tx)
data_cost_impact = baseline['l1_fee'] - minimal_cost['l1_fee']
if data_cost_impact > 0:
suggestions.append({
'type': 'data_optimization',
'description': 'Transaction data contributes significantly to L1 costs',
'potential_savings_wei': data_cost_impact,
'potential_savings_pct': round(
(data_cost_impact / baseline['total_estimated_cost']) * 100, 2
),
'recommendation': 'Consider compressing data or using events for large payloads'
})
# Check gas efficiency
if baseline['gas_estimate'] > 200000:
suggestions.append({
'type': 'gas_optimization',
'description': f'High gas usage detected: {baseline["gas_estimate"]:,} gas',
'recommendation': 'Review contract logic for gas efficiency improvements'
})
# Check fee composition
if baseline['breakdown']['l1_fee_percentage'] > 80:
suggestions.append({
'type': 'l1_fee_dominance',
'description': f'L1 fees dominate total cost ({baseline["breakdown"]["l1_fee_percentage"]}%)',
'recommendation': 'Consider batching multiple operations into single transaction'
})
return {
'baseline_cost': baseline,
'optimization_suggestions': suggestions,
'total_potential_savings': sum(
s.get('potential_savings_wei', 0) for s in suggestions
)
}
def compare_transaction_efficiency(
self,
transactions: List[Dict[str, Any]],
labels: List[str] = None
) -> Dict[str, Any]:
"""Compare efficiency of different transaction approaches"""
if labels is None:
labels = [f"Transaction {i+1}" for i in range(len(transactions))]
comparisons = []
for i, (tx, label) in enumerate(zip(transactions, labels)):
try:
breakdown = self.get_full_fee_breakdown(tx)
comparisons.append({
'label': label,
'total_cost': breakdown['total_estimated_cost'],
'l1_fee': breakdown['l1_fee'],
'l2_cost': breakdown['l2_execution_cost'],
'gas_estimate': breakdown['gas_estimate'],
'efficiency_score': breakdown['gas_estimate'] / breakdown['total_estimated_cost']
})
except Exception as e:
comparisons.append({
'label': label,
'error': str(e)
})
# Find most efficient
valid_comparisons = [c for c in comparisons if 'error' not in c]
if valid_comparisons:
most_efficient = min(valid_comparisons, key=lambda x: x['total_cost'])
least_efficient = max(valid_comparisons, key=lambda x: x['total_cost'])
return {
'comparisons': comparisons,
'most_efficient': most_efficient,
'least_efficient': least_efficient,
'cost_difference': least_efficient['total_cost'] - most_efficient['total_cost'],
'efficiency_improvement_pct': round(
((least_efficient['total_cost'] - most_efficient['total_cost']) /
least_efficient['total_cost']) * 100, 2
)
}
return {'comparisons': comparisons}
# Usage examples
fee_estimator = LineaFeeEstimator('https://api-linea-mainnet-archive.n.dwellir.com/YOUR_API_KEY')
# Basic L1 fee estimation
transaction = {
'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5',
'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913',
'value': '0x1bc16d674ec80000',
'data': '0xa9059cbb000000000000000000000000recipient000000000000000000000000'
}
l1_fee = fee_estimator.estimate_l1_fee(transaction)
print(f"L1 Fee: {l1_fee:,} wei")
# Full breakdown
breakdown = fee_estimator.get_full_fee_breakdown(transaction)
print(f"Total Cost: {breakdown['total_estimated_cost']:,} wei")
print(f"L1 Fee: {breakdown['l1_fee']:,} wei ({breakdown['breakdown']['l1_fee_percentage']}%)")
print(f"L2 Cost: {breakdown['l2_execution_cost']:,} wei ({breakdown['breakdown']['l2_fee_percentage']}%)")
# Data impact analysis
data_payloads = [
'0x', # Empty
'0xa9059cbb' + '00' * 32, # Basic ERC20 transfer
'0xa9059cbb' + '00' * 100, # Larger payload
'0xa9059cbb' + '00' * 500 # Very large payload
]
data_analysis = fee_estimator.analyze_data_cost_impact(
{'from': '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb5', 'to': '0x833589fcd6edb6e08f4c7c32d4f71b54bda02913'},
data_payloads
)
print("\nData Size Impact Analysis:")
for result in data_analysis:
if 'error' not in result:
print(f" {result['data_size_bytes']} bytes: {result['total_cost']:,} wei "
f"(+{result['cost_increase_pct']}%)")
# Optimization suggestions
optimization = fee_estimator.suggest_optimizations(transaction)
print(f"\nOptimization Suggestions:")
for suggestion in optimization['optimization_suggestions']:
print(f" - {suggestion['description']}")
print(f" {suggestion['recommendation']}")
Response Example
{
"jsonrpc": "2.0",
"id": 1,
"result": "0x1c6bf526340"
}
Understanding L1 Fees on Linea
Fee Components
- L2 Execution Fee: Standard gas cost for transaction execution on Linea
- L1 Data Fee: Cost of posting transaction data to Ethereum L1 for data availability
Data Size Impact
L1 fees scale with transaction data size:
- Simple transfers: Minimal L1 fee
- Contract interactions: Moderate L1 fee based on calldata
- Large data payloads: Significant L1 fee component
Cost Optimization Strategies
- Minimize Data: Reduce unnecessary data in transactions
- Batch Operations: Combine multiple operations into single transaction
- Use Events: Emit events instead of storing large data on-chain
- Optimize Encoding: Use efficient data encoding methods
Common Use Cases
1. Transaction Cost Planning
// Plan transaction costs before execution
async function planTransactionCosts(transactions) {
const feeEstimator = new LineaFeeEstimator(rpcUrl);
const plans = [];
for (const tx of transactions) {
const breakdown = await feeEstimator.getFullFeeBreakdown(tx);
plans.push({
transaction: tx,
estimatedCost: breakdown.totalEstimatedCost,
l1FeeRatio: breakdown.breakdown.l1FeePercentage,
recommendation: breakdown.breakdown.l1FeePercentage > 70 ?
'Consider batching or data optimization' : 'Cost efficient'
});
}
return plans.sort((a, b) => a.estimatedCost - b.estimatedCost);
}
2. Data Optimization Analysis
def optimize_contract_call_data(base_transaction, data_variations):
"""Find most cost-effective data encoding"""
fee_estimator = LineaFeeEstimator(rpc_url)
results = []
for name, data in data_variations.items():
tx = {**base_transaction, 'data': data}
breakdown = fee_estimator.get_full_fee_breakdown(tx)
results.append({
'encoding': name,
'data_size': len(data) // 2 - 1, # Hex bytes
'total_cost': breakdown['total_estimated_cost'],
'l1_fee': breakdown['l1_fee'],
'efficiency': breakdown['l1_fee'] / (len(data) // 2 - 1)
})
# Sort by total cost
return sorted(results, key=lambda x: x['total_cost'])
Related Methods
eth_estimateGas
- Estimate L2 execution gaseth_gasPrice
- Get current L2 gas priceeth_feeHistory
- Historical fee data
Need help? Contact our support team or check the Linea documentation.