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
async gasParameters(): Promise<BlockGasParameters>BlockGasParameters Structure
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
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
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
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.
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.
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.
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.
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.
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.
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
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');
}