Fetching latest headlines…

Dev

I built a zero-dependency CLI to pause deploys when L2 gas spikes

Dev.toUnited States · NORTH AMERICA

The problem Your CI pipeline deploys to Base mainnet at 11 PM. Gas is 10x normal. You burn $200 in fees. Nobody noticed until the gas bill arrived. This actually happened during Base's gas spike in...

0 views0 likes0 comments

The problem

Your CI pipeline deploys to Base mainnet at 11 PM. Gas is 10x normal. You burn $200 in fees. Nobody noticed until the gas bill arrived.

This actually happened during Base's gas spike in May 2024, when prices hit 0.5 Gwei — 83x the normal rate. Teams without a gas gate in CI deployed contracts and paid hundreds in unnecessary fees.

The solution: l2gas

npx @psicossz/l2gas

No installation required. Zero dependencies. Just Node 18+.

╔══════════════════════════════════════════════════════════════╗
║  ⚡ L2GAS v1.1.0 | REAL-TIME L2 GAS & TRANSFER COSTS        ║
╚══════════════════════════════════════════════════════════════╝

Chain               Tech          Gas (Gwei)    Transfer ($)   Block
──────────────────────────────────────────────────────────────────
Base                OP Stack      0.006 Gwei      $0.000315    #52066208
Arbitrum One        Nitro         0.020 Gwei      $0.001057    #510900717
Optimism            OP Stack      0.001 Gwei      $0.000053    #157661493
Polygon PoS         PoS           304.3 Gwei      $0.002556    #94811082
Linea               zkEVM         0.263 Gwei      $0.013839    #32207812
Scroll              zkEVM         0.0001 Gwei     $0.000006    #35249012
zkSync Era          zkRollup      0.045 Gwei      $0.002376    #72300380
──────────────────────────────────────────────────────────────────

All 7 chains queried in parallel in under 2 seconds, directly from public RPC endpoints — no API key, no rate limits, no third-party service.

Add it to your GitHub Actions pipeline

The --threshold flag exits with code 1 if any chain exceeds the Gwei limit, which natively blocks a CI step:

# .github/workflows/deploy.yml
jobs:
  gas-check:
    runs-on: ubuntu-latest
    steps:
      - name: Check gas before deploying
        run: npx @psicossz/l2gas base arbitrum --threshold=0.05
        # Exit code 1 = gas too high = deploy blocked automatically

  deploy:
    needs: gas-check  # Won't run if gas-check fails
    runs-on: ubuntu-latest
    steps:
      - run: echo "Gas OK — deploying to Base mainnet..."

Or use the reusable workflow for a cleaner setup:

jobs:
  gas-check:
    uses: psicossz29-netizen/l2gas-cli/.github/workflows/l2gas-check.yml@main
    with:
      chains: 'base arbitrum'
      max-gwei: '0.05'
      fail-on-exceed: true

  deploy:
    needs: gas-check
    if: needs.gas-check.outputs.gas-ok == 'true'
    runs-on: ubuntu-latest
    steps:
      - run: echo "Deploying..."

Use it as a library too

npm install @psicossz/l2gas
const { getChainGas, getAllChainsGas } = require('@psicossz/l2gas');

// Single chain
const base = await getChainGas('base');
console.log(base.gasPriceGwei);     // 0.006
console.log(base.transferCostUsd);  // 0.000315

// All chains in parallel
const all = await getAllChainsGas();

// Specific chains
const subset = await getAllChainsGas(['base', 'arbitrum', 'optimism']);

JSON output for scripting

l2gas --json | jq '.chains[] | select(.gasPriceGwei > 0.1)'
{
  "version": "1.1.0",
  "timestamp": "2026-10-02T06:00:00.000Z",
  "chains": [
    {
      "chain": "Base",
      "chainId": 8453,
      "layer": "OP Stack",
      "gasPriceGwei": 0.006,
      "transferCostUsd": 0.000315,
      "blockNumber": 52066208,
      "status": "ONLINE"
    }
  ]
}

Watch mode

l2gas --watch        # Refreshes every 30 seconds
l2gas base --watch   # Watch a single chain

How it works internally

The interesting part: it uses zero npm dependencies. The entire implementation relies on:

  • fetch() (native, Node 18+) for RPC calls
  • AbortSignal.timeout(8000) for per-chain timeouts
  • Promise.all() for parallel querying
  • BigInt arithmetic for precise Wei calculations
// Core logic — this is really all it takes
async function getChainGas(chainKey) {
  const [gasPriceHex, block] = await Promise.all([
    rpcFetch(config.rpc, 'eth_gasPrice'),
    rpcFetch(config.rpc, 'eth_getBlockByNumber', ['latest', false])
  ]);

  const gasPriceWei = BigInt(gasPriceHex);
  const transferCostWei = gasPriceWei * 21000n;
  const transferCostUsd = (Number(transferCostWei) / 1e18) * ETH_PRICE_USD;

  return { gasPriceGwei: Number(gasPriceWei) / 1e9, transferCostUsd };
}

Supported chains (v1.1.0)

Chain Tech ChainId RPC
Base OP Stack 8453 mainnet.base.org
Arbitrum One Nitro 42161 arb1.arbitrum.io/rpc
Optimism OP Stack 10 mainnet.optimism.io
Polygon PoS PoS 137 polygon-bor-rpc.publicnode.com
Linea zkEVM 59144 rpc.linea.build
Scroll zkEVM 534352 rpc.scroll.io
zkSync Era zkRollup 324 mainnet.era.zksync.io

Install

# Global CLI
npm install -g @psicossz/l2gas

# No install (latest version always)
npx @psicossz/l2gas

# As a library
npm install @psicossz/l2gas

GitHub: psicossz29-netizen/l2gas-cli
npm: @psicossz/l2gas

If it saves you from a gas spike disaster, a ⭐ on the repo goes a long way 🙏

Next version (v1.2.0): --alert flag to send a Slack/Discord/Telegram webhook when gas drops below your threshold — so your pipeline can auto-resume when conditions are right.

Comments (0)

Sign in to join the discussion

Be the first to comment!