# Gas Network Developer Tutorial - Getting Started


By [Gas Network - Blog](https://blog.gas.network) · 2025-05-12

---

### **Introduction**

Gas prices fluctuate constantly, and onchain contracts often need those prices to make decisions or to expose up‑to‑date information to apps. [Gas Network](https://gas.network/) solves this by delivering signed, accurate gas estimates for many chains directly on‑chain via its **Oracle**.

This tutorial expands on the [Oracle docs](https://gas.network/docs/v2-oracle) and explains how to build and integrate the Gas Network Oracle. It is meant to be accessible to everyone, including those who may be newer to solidity.

### **Roadmap**

**In this post we will:**

1.  Look up the oracle's address for your network.
    
2.  Declare a Solidity interface so our code can talk to the oracle.
    
3.  Call the oracle's `getInTime` function (and explain every parameter).
    
4.  Use the returned gas price inside contract logic.
    
5.  Finish with a fully‑annotated example contract you can deploy in Remix.
    

### **1\. Find the Oracle Address**

Each supported EVM chain already has an Oracle deployed. The official docs list them here [https://gas.network/docs/v2-oracle#Update-Consumer-Chain-Oracle](https://gas.network/docs/v2-oracle#Update-Consumer-Chain-Oracle).

We suggest to start off with the **Ethereum Sepolia (testnet)**

### **2\. Describe the Oracle with a Solidity Interface**

Copy the interface below into a new file named `IGasOracleV2.sol` or at the top of your contract:

    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.17;
    
    /**
     * @title IGasOracleV2
     * @dev Minimal interface for the Gas Network Oracle V2.
     */
    interface IGasOracleV2 {
        /**
         * @notice Fetch a gas value.
         * @param systemId Architecture ID -- always 2 for any EVM chain. Gas Network has provisioned systemId 1 for BTC.
         * @param chainId Chain ID to query (use block.chainid for current chain).
         * @param typeId Which metric? 107 = base fee, 322 = p90 priority fee, etc. See docs for more!
         * @param maxAge Freshness in ms. Oracle returns 0 if data is older.
         * @return value The gas metric (wei).
         * @return blockNumber Block number of the estimate.
         * @return timestamp When the estimate was created (ms UTC).
         */
        function getInTime(
            uint8 systemId,
            uint64 chainId,
            uint16 typeId,
            uint64 maxAge
        ) external view returns (
            uint256 value,
            uint64 blockNumber,
            uint64 timestamp
        );
    }

**Why an interface?**

Solidity needs a function's **ABI** to call it. By giving the compiler this interface, we can treat the on‑chain oracle contract as if it were a local object. No source code from the oracle itself is required.

### **3\. Connect & Read: line‑by‑line explanation**

Create a new contract named `GasPriceReader.sol`. We start by storing the oracle's address and casting it to our interface:

    contract GasPriceReader {
        // 1️⃣ Address of the v2 Oracle on Sepolia.
        address constant GAS_ORACLE = 0xCc936bE977BeDb5140C5584d8B6043C9068622A6;
        
        // 2️⃣ Create a typed handle so we can call its functions.
        IGasOracleV2 oracle = IGasOracleV2(GAS_ORACLE);
    
        /**
         * @notice Get the latest base fee.
         * @dev Returns both raw wei and more human‑friendly gwei.
         */
        function getCurrentBaseFee()
            external
            view
            returns (uint256 baseFeeWei, uint256 baseFeeGwei)
        {
            // 3️⃣ Call the oracle. Parameters:
            // 2 → EVM system
            // block.chainid → current chain
            // 107 → metric ID for base fee
            // 60000 → only accept data younger than 60 s
            (uint256 value,,) = oracle.getInTime(
                2,
                uint64(block.chainid),
                107,
                60_000
            );
            
            // 4️⃣ If oracle has no fresh data it returns all zeros.
            require(value > 0, "No recent gas data");
            
            baseFeeWei = value;
            baseFeeGwei = value / 1e9; // 1 Gwei = 1e9 wei
        }
    }

**What just happened?**

*   We asked for record type **107** (base fee).
    
*   `maxAge` = 60,000 ms means "don't accept oracle data older than 60s."
    
*   `value` is the base fee in wei; dividing by `1e9` gives Gwei for readability.
    
*   A zero return means data is stale or not yet published for this chain.
    

### **4\. Using gas data in conditional logic**

Here's a mini‑game/app idea: **Run a function only when gas is cheap.**

    /**
     * @notice Only succeeds if base fee ≤ maxBaseFeeGwei.
     */
    function doActionIfGasCheap(uint256 maxBaseFeeGwei) external {
        (uint256 baseFeeWei,,) = oracle.getInTime(2, uint64(block.chainid), 107, 60_000);
        require(baseFeeWei > 0, "No recent gas data");
        
        uint256 currentBaseFeeGwei = baseFeeWei / 1e9;
        require(currentBaseFeeGwei <= maxBaseFeeGwei, "Gas too high");
        
        // (Put real logic here)
        emit ActionDone(currentBaseFeeGwei);
    }
    
    event ActionDone(uint256 baseFeeAtExecution);

⚠**Gas cost warning:** Reading an external contract (`oracle.getInTime`) inside a state‑changing transaction adds ~2k gas. This is because the EVM needs to execute that external call as part of the state change. So, the "free read" becomes part of a paid "write." Not very much, but account for it if every byte matters.

### **5\. Full annotated example**

Below is a self‑contained contract you can paste into **_Remix > "Solidity"_** and deploy on Sepolia. Inline comments explain each part thoroughly.

    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.17;
    
    interface IGasOracleV2 {
        function getInTime(
            uint8 systemId,
            uint64 chainId,
            uint16 typeId,
            uint64 maxAge
        ) external view returns (uint256, uint64, uint64);
    }
    
    contract GasOracleExample {
        /**
         * @notice Using Sepolia testnet below - change as needed
         **/
        address constant ORACLE = 0xCc936bE977BeDb5140C5584d8B6043C9068622A6;
        IGasOracleV2 constant oracle = IGasOracleV2(ORACLE);
        
        /**
         * @notice Read current base fee and P90 priority tip in Gwei.
         */
        function getGasPrices()
            public
            view
            returns (uint256 baseFeeGwei, uint256 priorityFeeGwei)
        {
            (uint256 baseWei,,) = oracle.getInTime(2, uint64(block.chainid), 107, 300_000);
            (uint256 tipWei,,) = oracle.getInTime(2, uint64(block.chainid), 322, 300_000);
            
            require(baseWei > 0 && tipWei > 0, "Oracle missing");
            
            baseFeeGwei = baseWei / 1e9;
            priorityFeeGwei = tipWei / 1e9;
        }
        
        function doActionIfGasCheap(uint256 maxBaseFeeGwei) external {
            (uint256 baseWei,,) = oracle.getInTime(2, uint64(block.chainid), 107, 60_000);
            uint256 baseGwei = baseWei / 1e9;
            
            require(baseGwei <= maxBaseFeeGwei, "Gas too high");
            
            emit ActionExecuted(baseGwei);
        }
        
        event ActionExecuted(uint256 baseGwei);
        
        /**
         * @dev Convenience helper -- returns a ready‑to‑sign maxFeePerGas.
         *
         * What happens under the hood?
         * 1. Fetches baseFeePerGas (type 107) -- the mandatory part every
         *    transaction must pay; this portion is burned.
         * 2. Fetches the oracle's 90‑percentile priority tip (type 322).
         *    That is, a tip big enough to be included ~90% of the time.
         * 3. Adds them together and returns the sum in wei.
         *
         * How do wallets use it?
         * 1. Set `maxFeePerGas = recommendedMaxFeeWei()` -- the value returned
         *    by this helper (already base + tip).
         * 2. Set `maxPriorityFeePerGas = p90 priority tip` (see getGasPrices).
         *
         * Why is this useful for devs?
         * ✔ You don't need to do EIP‑1559 math or handle units manually.
         * ✔ It compresses two oracle calls into one 256‑bit integer.
         * ✔ Front‑ends can `eth_call` this view method for free and drop the
         *   result straight into ethers.js / web3.js transaction objects.
         *
         * @return recommendedWei Total recommended `maxFeePerGas` (wei).
         */
        function recommendedMaxFeeWei() public view returns (uint256 recommendedWei) {
            (uint256 baseWei,,) = oracle.getInTime(2, uint64(block.chainid), 107, 300_000);
            (uint256 tipWei,,) = oracle.getInTime(2, uint64(block.chainid), 322, 300_000);
            
            require(baseWei > 0 && tipWei > 0, "Oracle missing");
            
            return baseWei + tipWei;
        }
    }

### **6\. Deploy & Test in Remix**

1.  Open [https://remix.ethereum.org](https://remix.ethereum.org) and create a new file `GasOracleExample.sol`.
    
2.  Paste the full contract above.
    
3.  Compile with Solidity 0.8.x.
    
4.  In the 'Deploy & Run' sidebar select Sepolia network via MetaMask (Or any other EVM Wallet).
    
5.  Deploy. After confirmation, expand the contract and click `getGasPrices()`. You should see two numbers (_base fee & p90 priority fee_) returned in Gwei.
    

🚨**Troubleshooting**:

*   If any value is `0`, the oracle might not have published recently. Try a higher `maxAge` (e.g. 900000ms).
    
*   Wrong chain? Make sure MetaMask (or any other EVM wallet you use) is on the same network whose oracle address you set in `ORACLE`.
    

### **7\. Bonus: How a app or wallet could use the recommendedMaxFeeWei() helper**

By exposing this helper function the contract becomes a "**gas oracle proxy**" that any front-end (or even another contract) can consume without needing to worry about type IDs, units, or fee mathematics. Below is a lightweight JS example using the ethers.js library.

    import { ethers } from "ethers";
    
    const gasOracle = new ethers.Contract(
        GAS_ORACLE_ADDRESS,
        ["function recommendedMaxFeeWei() view returns(uint256)",
         "function getGasPrices() view returns(uint256,uint256)"],
        provider
    );
    
    const maxFee = await gasOracle.recommendedMaxFeeWei(); // wei
    const [baseG, prioG] = await gasOracle.getGasPrices(); // gwei
    
    const tx = {
        to: recipient,
        value: ethers.parseEther("0.1"),
        maxFeePerGas: maxFee, // wei (already base+tip)
        maxPriorityFeePerGas: ethers.parseUnits(prioG.toString(), "gwei"),
        gasLimit: 21000 // 21k for transfers
    };
    
    const receipt = await signer.sendTransaction(tx);

### **Conclusion**

You now have a complete, well‑commented template for reading **Gas Network** estimates. Yay!

**From here you can customise:**

*   Different `typeId` values (see [docs](https://gas.network/docs/v2-oracle#Record\(s\)) for new metrics).
    
*   Freshness windows (`maxAge`) to balance speed vs. certainty.
    
*   On‑chain automations that react to gas spikes in real time.
    

**Enjoy building gas‑aware apps!**

---

*Originally published on [Gas Network - Blog](https://blog.gas.network/gas-network-developer-tutorial-getting-started)*
