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...
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 -
BigIntarithmetic 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.