Gas Network V1 Oracle

Fetch Gasnet Estimation Data

Gasnet currently stores estimates in the form of quantiles representing likelihood of estimate being sufficient to be included soon in a block. The full estimation for a specific chain and timestamp has the following structure:

    struct Estimation {
        EstimationValues Q70;
        EstimationValues Q80;
        EstimationValues Q90;
        EstimationValues Q95;
        EstimationValues Q99;
        uint8 precision;
        uint128 height;
        uint256 timestamp;
        uint256 chainid;
    }
solidity

Each EstimationValues quantile contains the following estimate details:

    struct EstimationValues {
        uint256 gasPrice;
        uint256 maxPriorityFeePerGas;
        uint256 maxFeePerGas;
    }
solidity

Additional estimate values will be added to accommodate chain specific mechanics, such as blob pricing. Gas estimates are available for all the chains currently support by the Blocknative Gas API. The complete list of available chains is listed in the API docs available here: https://docs.blocknative.com/gas-prediction/gas-platform

The following code will fetch a gas estimate from Gasnet using Ethers in Typescript:

const GASNET_URL=https://http-rpc.devnet.gas.network
const GASNET_CONTRACT_ADDRESS = '0xC2F61FAfA65D874725e485f4B52B9B495559F381'

const gasnetProvider = new ethers.JsonRpcProvider(GASNET_URL);
const gasnetContract = new ethers.Contract(
  GASNET_CONTRACT_ADDRESS,
  abi,
  gasnetProvider
);

let est: Estimation; // the estimation data read from Gasnet
let sig: Bytes;
try {
  [est, sig] = await gasnetContract.getEstimation('1'); // estimates for ethereum mainnet
} catch (error) {
  console.error(error);
  return;
}
typescript

This estimate containing the supported quantiles for the specified chain includes a signature that the Gasnet Pull Oracle on the Consumer Chain uses to verify the integrity of the estimate.

Update Consumer Chain Oracle

Once a gas estimation is retrieved from Gasnet above, the following sample code puts the data on the Consumer Chain with the Pull Oracle using Ethers in Typescript:

// Ethereum Sepolia Testnet
export const CONSUMER_CHAIN_URL=https://endpoints.omniatech.io/v1/eth/sepolia/public
export const CONSUMER_CHAIN_CONTRACT_ADDRESS = '0xE4859432d9Af6D40C2D923e3F13D66057F4AEcA0'

// Optimism Sepolia Testnet
export const CONSUMER_CHAIN_URL=https://sepolia.optimism.io
export const CONSUMER_CHAIN_CONTRACT_ADDRESS = '0x1a3d7A0bD9585B730e615aE0fD9a2294C33Df1E1'

// Base Sepolia Testnet
export const CONSUMER_CHAIN_URL=https://sepolia.base.org
export const CONSUMER_CHAIN_CONTRACT_ADDRESS = '0x1a3d7A0bD9585B730e615aE0fD9a2294C33Df1E1'
typescript
const consumerChainProvider = new ethers.JsonRpcProvider(CONSUMER_CHAIN_URL);
const wallet = new ethers.Wallet(
  consumerWalletPrivateKey,
  consumerChainProvider
);
const oracle = new ethers.Contract(
  CONSUMER_CHAIN_CONTRACT_ADDRESS,
  abi,
  wallet
);

try {
  const transaction = await oracle.setEstimation(est, sig);
  const result = await transaction.wait();
  return result;
} catch (error) {
  console.error(error);
}
typescript

At this point the estimates are available on the Consumer Chain for use by other contracts on that chain. You can find example code to update the estimate on the Consumer Chain using an injected provider (i.e. wallet) in the demo dapp .

Read Consumer Chain Oracle

Sample code calling the Pull Oracle to read a gas estimate using ethers in Typescript:

// Ethereum mainnet chain id, 60 second delay, Q99 quantile
const result = await oracle.getGasEstimationQuantile(BigInt('1'), 60, 99);
typescript

Sample code calling the Pull Oracle to read a gas estimate using Solidity:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

import {Test, console} from "forge-std/Test.sol";
import {Oracle} from "../src/Oracle.sol";

// parameters needed for eip712 verification
contract OracleTest is Test {
    Oracle public oracle;

    function setUp() public {
        oracle = new Oracle(
            "GasOracle",
            address(0xb690C4CbDE4747FD614477Ab24c7630C5aAa6Ec5),
            uint256(6177644545)
        );

        oracle.setVerifier(address(0x26222b1a8C061f7Ebda1f4a4d15A66683260dBE5));
    }

    oracle.getGasEstimationQuantile(0xa, 10000000000000, Oracle.Quantile.Q99);
}
solidity

You can find example code to read the estimate on the Consumer Chain using an injected provider (i.e. wallet) in the demo dapp .

Oracle Revert Reasons

Updating the Oracle

If the oracle is updated with an Estimation and a newer Estimation already exists, the contract will revert.

The revert message newer block estimation already exists means that an Estimation already exists with a higher block number. This is the block number of the chainId of the Estimation.

The revert message newer timestamp estimation already exists means that a more recent Estimation already exists. The timestamp allows for Estimation updates within the same block, which is particularly important for estimates from slower chains.

These reverts ensure that only more recent (timestamp and/or block height) estimates can update the oracle on the Customer Chain.

Reading the Oracle

If there are no estimates available for the specified chainId, the contract will revert with message no estimations for network. To remedy this, call the update function (setEstimation) of the oracle to place a fresh estimate on the Consumer Chain.

If there are no estimates available within the specified delay period, the contract will revert with message timeout. To remedy this, call the update function (setEstimation) of the oracle to place a fresher estimate on the Consumer Chain, or change the delay to a longer period of time. The delay value is indicated in seconds since the block timestamp of the last estimate update for the specified chain.

If there is no estimate for the specified quantile , the contract will revert with message quantile not supported. Currently the quantiles 99, 95, 90, 80, and 70 are supported, but this may change in the future.