Gas Parameters

Overview

OP_NET uses a gas system for pricing contract execution, where computational operations consume gas units paid in satoshis. Gas parameters are derived from recent block data and reflect current network conditions.

Fetching Gas Parameters

Using gasParameters()

The gasParameters() method retrieves current network gas parameters with automatic caching to minimize redundant RPC calls. The cached values refresh every 10 seconds, ensuring a balance between data freshness and network efficiency. This method requires no parameters and can be called at any time to obtain the latest fee estimates.

The method returns a BlockGasParameters object containing comprehensive gas metrics. These include the current block number, gas usage statistics, base gas price, gas-to-satoshi conversion rate, and Bitcoin fee recommendations for different priority levels. This data enables applications to calculate transaction costs accurately and select appropriate fee rates based on confirmation requirements.

Method Signature

gasParameters() signature
typescript
async gasParameters(): Promise<BlockGasParameters>

BlockGasParameters Structure

BlockGasParameters structure
typescript
interface BlockGasParameters {
    // Block reference
    blockNumber: bigint;

    // Gas metrics
    gasUsed: bigint;           // Gas consumed in recent block
    targetGasLimit: bigint;    // Target gas limit per block
    ema: bigint;               // Exponential moving average
    baseGas: bigint;           // Minimum gas price
    gasPerSat: bigint;         // Gas units per satoshi

    // Bitcoin fee recommendations
    bitcoin: BitcoinFees;
}

interface BitcoinFees {
    conservative: number;      // Conservative fee estimate
    recommended: {
        low: number;           // Low priority (~1 hour)
        medium: number;        // Medium priority (~30 min)
        high: number;          // High priority (next block)
    };
}

Getting Gas Parameters

Getting gas parameters
typescript
import { JSONRpcProvider } from 'opnet';
import { networks } from '@btc-vision/bitcoin';

const network = networks.regtest;
const provider = new JSONRpcProvider({ url: 'https://regtest.opnet.org', network });

const gasParams = await provider.gasParameters();

console.log('Gas Parameters:');
console.log('  Block:', gasParams.blockNumber);
console.log('  Gas per sat:', gasParams.gasPerSat);
console.log('  Base gas:', gasParams.baseGas);
console.log('  Gas used:', gasParams.gasUsed);
console.log('  Gas limit:', gasParams.targetGasLimit);

Fee Recommendations

The BlockGasParameters object includes Bitcoin fee recommendations for different priority levels. These recommendations are derived from current mempool conditions and provide guidance for selecting an appropriate fee rate based on confirmation urgency. The conservative rate prioritizes reliability, while low, medium, and high rates offer varying trade-offs between cost and confirmation speed.

Get Recommended Fee Rates

Get recommended fee rates
typescript
const gasParams = await provider.gasParameters();

const fees = gasParams.bitcoin;

console.log('Fee Recommendations (sat/vB):');
console.log('  Conservative:', fees.conservative);
console.log('  Low:', fees.recommended.low);
console.log('  Medium:', fees.recommended.medium);
console.log('  High:', fees.recommended.high);

Choose Appropriate Fee Rate

Choose appropriate fee rate
typescript
function selectFeeRate(
    gasParams: BlockGasParameters,
    priority: 'low' | 'medium' | 'high' | 'conservative'
): number {
    const fees = gasParams.bitcoin;

    switch (priority) {
        case 'conservative':
            return fees.conservative;
        case 'low':
            return fees.recommended.low;
        case 'medium':
            return fees.recommended.medium;
        case 'high':
            return fees.recommended.high;
    }
}

// Usage
const gasParams = await provider.gasParameters();
const feeRate = selectFeeRate(gasParams, 'medium');
console.log('Using fee rate:', feeRate, 'sat/vB');

Calculating Gas Costs

Transaction costs on OP_NET consist of two components: the gas cost for contract execution and the Bitcoin network fee for transaction inclusion. The gas cost is calculated by dividing the gas consumed by the gasPerSat rate, while the Bitcoin fee depends on the transaction size in virtual bytes and the selected fee rate. Combining these values provides an accurate estimate of the total satoshis required for a transaction.

Calculate Transaction Gas Cost

The following example demonstrates how to convert gas units into satoshis for a given transaction.

Calculate transaction gas cost
typescript
async function calculateGasCost(
    provider: JSONRpcProvider,
    gasUsed: bigint
): Promise<bigint> {
    const gasParams = await provider.gasParameters();

    // Gas cost in satoshis = gas used / gas per sat
    const costInSats = gasUsed / gasParams.gasPerSat;

    return costInSats;
}

// Usage
const gasCost = await calculateGasCost(provider, 50000n);
console.log('Gas cost:', gasCost, 'satoshis');

Estimate Total Transaction Cost

A complete transaction cost estimate combines the gas cost for contract execution with the Bitcoin network fee for transaction inclusion. The network fee is calculated by multiplying the transaction size in virtual bytes by the selected fee rate. The following example returns a breakdown of both components along with the total cost in satoshis.

Estimate total transaction cost
typescript
interface TransactionCostEstimate {
    gasCost: bigint;
    bitcoinFee: bigint;
    totalCost: bigint;
}

async function estimateTransactionCost(
    provider: JSONRpcProvider,
    gasUsed: bigint,
    txSizeVBytes: number = 250,
    priority: 'low' | 'medium' | 'high' = 'medium'
): Promise<TransactionCostEstimate> {
    const gasParams = await provider.gasParameters();

    // Gas cost
    const gasCost = gasUsed / gasParams.gasPerSat;

    // Bitcoin transaction fee
    const feeRate = gasParams.bitcoin.recommended[priority];
    const bitcoinFee = BigInt(Math.ceil(txSizeVBytes * feeRate));

    return {
        gasCost,
        bitcoinFee,
        totalCost: gasCost + bitcoinFee,
    };
}

// Usage
const estimate = await estimateTransactionCost(provider, 50000n, 300, 'medium');
console.log('Gas cost:', estimate.gasCost, 'sats');
console.log('Bitcoin fee:', estimate.bitcoinFee, 'sats');
console.log('Total:', estimate.totalCost, 'sats');

Tracking Gas Prices

Monitor Gas Prices

For applications that require real-time fee awareness, gas prices can be monitored at regular intervals. The following example polls the network for updated gas parameters and invokes a callback with each update, enabling dynamic fee adjustments and user notifications when rates change significantly.

Monitor Gas Prices
typescript
async function monitorGasPrices(
    provider: JSONRpcProvider,
    callback: (params: BlockGasParameters) => void,
    intervalMs: number = 60000
): Promise<() => void> {
    // Initial fetch
    const initial = await provider.gasParameters();
    callback(initial);

    const intervalId = setInterval(async () => {
        try {
            const params = await provider.gasParameters();
            callback(params);
        } catch (error) {
            console.error('Error fetching gas parameters:', error);
        }
    }, intervalMs);

    return () => clearInterval(intervalId);
}

// Usage
const stopMonitoring = await monitorGasPrices(provider, (params) => {
    console.log(`Block ${params.blockNumber}: ${params.gasPerSat} gas/sat`);
}, 30000);

Historical Gas Analysis

Analyzing gas usage across recent blocks provides insight into network trends and helps identify optimal times for transaction submission. The following example collects gas metrics from a specified number of recent blocks, enabling applications to calculate averages, detect congestion patterns, and inform fee strategies.

Historical Gas Analysis
typescript
interface GasHistory {
    blockNumber: bigint;
    gasUsed: bigint;
    baseGas: bigint;
    timestamp: number;
}

async function collectGasHistory(
    provider: JSONRpcProvider,
    blockCount: number
): Promise<GasHistory[]> {
    const currentBlock = await provider.getBlockNumber();
    const history: GasHistory[] = [];

    for (let i = 0; i < blockCount; i++) {
        const blockNum = currentBlock - BigInt(i);
        if (blockNum < 1n) break;

        const block = await provider.getBlock(blockNum);
        history.push({
            blockNumber: BigInt(block.height),
            gasUsed: block.gasUsed,
            baseGas: block.baseGas,
            timestamp: block.time,
        });
    }

    return history.reverse();
}

// Usage
const history = await collectGasHistory(provider, 10);
console.log('Gas history (last 10 blocks):');
for (const entry of history) {
    console.log(`  Block ${entry.blockNumber}: ${entry.gasUsed} gas used`);
}

Gas Optimization Strategies

Wait for Low Gas

For non-urgent transactions, waiting for favorable gas conditions can reduce costs significantly. The following example polls the network until gas prices fall below a specified threshold or a timeout is reached, allowing applications to defer transactions until network congestion subsides.

Wait for Low Gas
typescript
async function waitForLowGas(
    provider: JSONRpcProvider,
    maxGasPerSat: bigint,
    timeoutMs: number = 300000
): Promise<BlockGasParameters> {
    const startTime = Date.now();

    while (Date.now() - startTime < timeoutMs) {
        const params = await provider.gasParameters();

        if (params.gasPerSat <e; maxGasPerSat) {
            return params;
        }

        console.log(`Gas too high: ${params.gasPerSat}, waiting...`);
        await new Promise((resolve) => setTimeout(resolve, 10000));
    }

    throw new Error('Timeout waiting for low gas');
}

// Usage
try {
    const params = await waitForLowGas(provider, 1000n, 60000);
    console.log('Low gas found, proceeding with transaction');
} catch {
    console.log('Gas remained high, proceeding anyway');
}

Calculate Optimal Time

Determining the optimal time to submit a transaction requires sampling fee rates over a period and comparing current rates against observed trends. The following example collects multiple readings, identifies the lowest observed fee, and provides a recommendation based on whether current conditions are favorable for transaction submission.

Calculate Optimal Time
typescript
async function findBestFeeTime(
    provider: JSONRpcProvider,
    checkIntervalMs: number = 60000,
    checkCount: number = 10
): Promise<{
    bestFee: number;
    currentFee: number;
    recommendation: string;
}> {
    const readings: number[] = [];

    for (let i = 0; i < checkCount; i++) {
        const params = await provider.gasParameters();
        readings.push(params.bitcoin.recommended.medium);

        if (i < checkCount - 1) {
            await new Promise((r) => setTimeout(r, checkIntervalMs));
        }
    }

    const currentFee = readings[readings.length - 1];
    const bestFee = Math.min(...readings);
    const avgFee = readings.reduce((a, b) => a + b, 0) / readings.length;

    let recommendation: string;
    if (currentFee <e; bestFee * 1.1) {
        recommendation = 'Good time to transact';
    } else if (currentFee > avgFee * 1.5) {
        recommendation = 'Fees high, consider waiting';
    } else {
        recommendation = 'Fees normal';
    }

    return { bestFee, currentFee, recommendation };
}

Complete Gas Service

Complete Gas Service
typescript
class GasService {
    private provider: JSONRpcProvider;
    private cache: BlockGasParameters | null = null;
    private cacheTime: number = 0;
    private cacheDuration: number = 10000; // 10 seconds

    constructor(provider: JSONRpcProvider) {
        this.provider = provider;
    }

    async getParams(): Promise<BlockGasParameters> {
        if (this.cache && Date.now() - this.cacheTime < this.cacheDuration) {
            return this.cache;
        }

        this.cache = await this.provider.gasParameters();
        this.cacheTime = Date.now();

        return this.cache;
    }

    async getGasPrice(): Promise<bigint> {
        const params = await this.getParams();
        return params.gasPerSat;
    }

    async getFeeRate(
        priority: 'low' | 'medium' | 'high' = 'medium'
    ): Promise<number> {
        const params = await this.getParams();
        return params.bitcoin.recommended[priority];
    }

    async estimateCost(
        gasUsed: bigint,
        txSizeVBytes: number = 250
    ): Promise<{
        gas: bigint;
        fee: bigint;
        total: bigint;
    }> {
        const params = await this.getParams();

        const gas = gasUsed / params.gasPerSat;
        const fee = BigInt(Math.ceil(
            txSizeVBytes * params.bitcoin.recommended.medium
        ));

        return {
            gas,
            fee,
            total: gas + fee,
        };
    }

    async shouldWait(targetFeeRate: number): Promise<boolean> {
        const currentRate = await this.getFeeRate('medium');
        return currentRate > targetFeeRate;
    }

    clearCache(): void {
        this.cache = null;
    }
}

// Usage
const gasService = new GasService(provider);

const feeRate = await gasService.getFeeRate('medium');
console.log('Current fee rate:', feeRate, 'sat/vB');

const estimate = await gasService.estimateCost(50000n, 300);
console.log('Total cost:', estimate.total, 'sats');

if (await gasService.shouldWait(5)) {
    console.log('Fees are high, consider waiting');
}