# eth_feeHistory - Celo RPC Method

Returns historical gas fee data on Celo, including base fees per gas and priority fee percentiles for a range of recent blocks. This data is essential for building accurate fee estimation algorithms for EIP-1559 transactions.

> **Why Celo?** Build on the mobile-first L2 powering 500K+ daily active users and $2B+ monthly stablecoin volume with phone number-based addressing, sub-cent fees, 150+ country adoption, Nightfall privacy layer, and Opera browser integration.

## When to Use This Method

The `eth_feeHistory` method serves these key scenarios for mobile payment developers, fintech builders, and teams targeting emerging markets:

- **Calculate optimal EIP-1559 fee parameters** - Derive `maxPriorityFeePerGas` from reward percentiles and `maxFeePerGas` from base fee trends for mobile stablecoin payments (MiniPay 10M+ wallets), remittances, humanitarian aid, and local currency stablecoins (cUSD, cNGN, cEUR)
- **Analyze fee market trends** - Inspect historical base fees and gas utilization ratios to forecast fee direction and time transactions for lower costs
- **Build intelligent gas pricing strategies** - Create automated fee estimation that adapts to network congestion on Celo without manual intervention
- **Predict future base fees** - Use the trailing `baseFeePerGas` value (index `blockCount` in the array) to anticipate the next block's base fee using EIP-1559 elasticity math

## Common Use Cases

### 1. Calculate Optimal EIP-1559 Fee Parameters

Derive `maxPriorityFeePerGas` from reward percentile data and set `maxFeePerGas` with a safety margin above the predicted next base fee. This approach gives you fee parameters tuned to real network conditions on Celo.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getEIP1559Fees(blockCount = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockCount.toString(16),
    'latest',
    [50, 90]
  ]);

  const nextBaseFee = BigInt(feeHistory.baseFeePerGas[blockCount]);
  const rewards50th = feeHistory.reward.map(r => BigInt(r[0]));
  const rewards90th = feeHistory.reward.map(r => BigInt(r[1]));

  const avg50th = rewards50th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);
  const avg90th = rewards90th.reduce((s, r) => s + r, 0n) / BigInt(blockCount);

  return {
    medium: {
      maxPriorityFeePerGas: avg50th,
      maxFeePerGas: nextBaseFee * 2n + avg50th
    },
    fast: {
      maxPriorityFeePerGas: avg90th,
      maxFeePerGas: nextBaseFee * 2n + avg90th
    }
  };
}

const fees = await getEIP1559Fees();
console.log('Medium priority fee:', formatUnits(fees.medium.maxPriorityFeePerGas, 'gwei'), 'Gwei');
console.log('Fast priority fee:', formatUnits(fees.fast.maxPriorityFeePerGas, 'gwei'), 'Gwei');
```

### 2. Build Fee Estimation UI

Display recent base fee trends and provide low/medium/high fee estimates to end users. This pattern powers gas estimation widgets in wallets and dApp interfaces.

```javascript
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function getFeeEstimateUI(blockRange = 20) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + blockRange.toString(16),
    'latest',
    [10, 50, 90]
  ]);

  const baseFees = feeHistory.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
  const rewardAvgs = [0, 1, 2].map(idx => {
    const fees = feeHistory.reward.map(r => Number(BigInt(r[idx])) / 1e9);
    return fees.reduce((s, f) => s + f, 0) / fees.length;
  });

  const nextBaseFee = baseFees[baseFees.length - 1];

  return {
    currentBaseFee: nextBaseFee,
    baseFeeTrend: baseFees.slice(-5),
    fees: {
      low: { maxPriority: rewardAvgs[0], max: nextBaseFee + rewardAvgs[0] },
      medium: { maxPriority: rewardAvgs[1], max: nextBaseFee * 2 + rewardAvgs[1] },
      high: { maxPriority: rewardAvgs[2], max: nextBaseFee * 3 + rewardAvgs[2] }
    }
  };
}

const estimate = await getFeeEstimateUI();
console.log('Base fee:', estimate.currentBaseFee, 'Gwei');
console.log('Low:', estimate.fees.low);
console.log('Medium:', estimate.fees.medium);
console.log('High:', estimate.fees.high);
```

### 3. Implement Adaptive Gas Pricing

Build a pricing engine that automatically adjusts fee parameters based on real-time network congestion. When gas utilization ratios spike above 80%, the system shifts to higher priority fees to maintain inclusion speed.

```javascript
import { JsonRpcProvider } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');

async function adaptiveFeeParams(window = 10) {
  const feeHistory = await provider.send('eth_feeHistory', [
    '0x' + window.toString(16),
    'latest',
    [25, 50, 75, 90]
  ]);

  const recentUtilization = feeHistory.gasUsedRatio.slice(-3);
  const avgUtilization = recentUtilization.reduce((s, r) => s + r, 0) / recentUtilization.length;
  const baseFeePerGas = BigInt(feeHistory.baseFeePerGas[window]);

  let priorityFeePercentile;
  let baseFeeMultiplier;

  if (avgUtilization > 0.8) {
    priorityFeePercentile = 3;
    baseFeeMultiplier = 3;
    console.log('High congestion detected, using premium fees');
  } else if (avgUtilization > 0.5) {
    priorityFeePercentile = 2;
    baseFeeMultiplier = 2;
    console.log('Moderate congestion, using standard fees');
  } else {
    priorityFeePercentile = 1;
    baseFeeMultiplier = 2;
    console.log('Low congestion, using economy fees');
  }

  const maxPriorityFeePerGas = feeHistory.reward.reduce(
    (sum, r) => sum + BigInt(r[priorityFeePercentile]), 0n
  ) / BigInt(window);

  return {
    maxPriorityFeePerGas,
    maxFeePerGas: baseFeePerGas * BigInt(baseFeeMultiplier) + maxPriorityFeePerGas,
    congestionLevel: avgUtilization > 0.8 ? 'high' : avgUtilization > 0.5 ? 'moderate' : 'low'
  };
}

const params = await adaptiveFeeParams();
console.log('Adaptive fee params:', params);
```

## Best Practices

- Use 5-20 blocks of history for accurate fee estimation: fewer blocks miss recent trends, more blocks dilute signal with stale data
- Calculate `maxPriorityFeePerGas` from reward percentiles: use the 50th percentile for normal confirmation and the 90th for fast inclusion
- Multiply `baseFeePerGas` by 2x as a safety margin for `maxFeePerGas`: this covers a 12.5% base fee increase per full block over 6 consecutive blocks
- Cache fee history results with a short TTL of 12 seconds (roughly one block on Celo) to balance freshness with API call efficiency
- Fall back to `eth_gasPrice` if `eth_feeHistory` returns a "method not found" error, indicating the node does not support EIP-1559

## Request Parameters

- `blockCount` (`QUANTITY, required`): Number of blocks in the requested range (1 to 1024)
- `newestBlock` (`QUANTITY|TAG, required`): Highest block number or tag (latest, pending) for the range
- `rewardPercentiles` (`Array<Float>, required`): Ascending list of percentile values (0-100) to sample effective priority fees at each block

## Request Example

```json
{
  "jsonrpc": "2.0",
  "method": "eth_feeHistory",
  "params": ["0x5", "latest", [25, 50, 75]],
  "id": 1
}
```

## Response Fields

- `oldestBlock` (`QUANTITY, required`): Block number of the oldest block in the range
- `baseFeePerGas` (`Array<QUANTITY>, required`): Array of base fees per gas for each block (length = blockCount + 1, includes the next block's predicted base fee)
- `gasUsedRatio` (`Array<Float>, required`): Array of gas used ratios (0.0 to 1.0) for each block: values above 0.5 indicate blocks over 50% full
- `reward` (`Array<Array<QUANTITY>>, required`): Array of effective priority fee arrays per block, one entry per requested percentile

## Successful Response

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "oldestBlock": "0x1076E5A",
    "baseFeePerGas": [
      "0x2E90EDD00",
      "0x2DA282B80",
      "0x2E90EDD00",
      "0x2F694E140",
      "0x2E90EDD00",
      "0x2DA282B80"
    ],
    "gasUsedRatio": [
      0.4523,
      0.5891,
      0.5234,
      0.4102,
      0.6789
    ],
    "reward": [
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x9502F900"],
      ["0x59682F00", "0x77359400", "0xB2D05E00"],
      ["0x3B9ACA00", "0x59682F00", "0x77359400"],
      ["0x77359400", "0x9502F900", "0xE8D4A51000"]
    ]
  }
}
```

## Error Responses

### Error Response

- Code: `-32602`

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32602,
    "message": "Invalid params: block count must be between 1 and 1024"
  }
}
```

## Code Examples

cURL
JavaScript
Python
Go

```bash
curl -X POST https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "method": "eth_feeHistory",
    "params": ["0x5", "latest", [25, 50, 75]],
    "id": 1
  }'
```

```javascript
// Using fetch
const response = await fetch('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    jsonrpc: '2.0',
    method: 'eth_feeHistory',
    params: ['0xa', 'latest', [25, 50, 75]],
    id: 1
  })
});

const { result } = await response.json();
const baseFees = result.baseFeePerGas.map(f => Number(BigInt(f)) / 1e9);
console.log('Base fees (Gwei):', baseFees);
console.log('Gas used ratios:', result.gasUsedRatio);

// Using ethers.js
import { JsonRpcProvider, formatUnits } from 'ethers';

const provider = new JsonRpcProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY');
const feeHistory = await provider.send('eth_feeHistory', ['0xa', 'latest', [25, 50, 75]]);

console.log('Base fees:', feeHistory.baseFeePerGas.map(f => formatUnits(f, 'gwei')));
console.log('Reward (25th):', feeHistory.reward.map(r => formatUnits(r[0], 'gwei')));
console.log('Reward (50th):', feeHistory.reward.map(r => formatUnits(r[1], 'gwei')));
console.log('Reward (75th):', feeHistory.reward.map(r => formatUnits(r[2], 'gwei')));
```

```python
import requests

def get_fee_history(block_count=10, newest_block='latest', percentiles=[25, 50, 75]):
    response = requests.post(
        'https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY',
        json={
            'jsonrpc': '2.0',
            'method': 'eth_feeHistory',
            'params': [hex(block_count), newest_block, percentiles],
            'id': 1
        }
    )
    return response.json()['result']

history = get_fee_history()
base_fees = [int(f, 16) / 1e9 for f in history['baseFeePerGas']]
print(f'Base fees (Gwei): {base_fees}')
print(f'Gas used ratios: {history["gasUsedRatio"]}')

# Using web3.py
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY'))
fee_history = w3.eth.fee_history(10, 'latest', [25, 50, 75])
print(f'Base fees: {[w3.from_wei(f, "gwei") for f in fee_history["baseFeePerGas"]]}')
print(f'Gas used ratios: {fee_history["gasUsedRatio"]}')
```

```go
package main

import (
    "context"
    "fmt"
    "log"
    "math/big"

    "github.com/ethereum/go-ethereum/ethclient"
)

func main() {
    client, err := ethclient.Dial("https://api-celo-mainnet-archive.n.dwellir.com/YOUR_API_KEY")
    if err != nil {
        log.Fatal(err)
    }

    feeHistory, err := client.FeeHistory(
        context.Background(),
        10,
        nil,
        []float64{25, 50, 75},
    )
    if err != nil {
        log.Fatal(err)
    }

    gwei := new(big.Float).SetFloat64(1e9)
    for i, baseFee := range feeHistory.BaseFee {
        fee := new(big.Float).Quo(new(big.Float).SetInt(baseFee), gwei)
        fmt.Printf("Block %d base fee: %s Gwei\n", i, fee.Text('f', 4))
    }
}
```

## Related Methods

- [`eth_gasPrice`](https://www.dwellir.com/docs/celo/eth_gasPrice) - Get the current legacy gas price
- [`eth_maxPriorityFeePerGas`](https://www.dwellir.com/docs/celo/eth_maxPriorityFeePerGas) - Get the suggested priority fee for EIP-1559 transactions
- [`eth_estimateGas`](https://www.dwellir.com/docs/celo/eth_estimateGas) - Estimate gas units required for a transaction
- [`eth_getBlockByNumber`](https://www.dwellir.com/docs/celo/eth_getBlockByNumber) - Get block details including `baseFeePerGas`
