Setup & Configuration (Stylus-first Shims)


This document describes installation and configuration for the Stylus-first precompile shims used in this integration. Scope is limited to shim mode, reseeding from a Stylus RPC, and validation via Hardhat scripts.


Prerequisites

  • Node.js: v22 LTS recommended.
  • Hardhat: project includes @nomicfoundation/hardhat-ethers (ethers v6).

Installation

Before configuring the plugin, you must first install it as a development dependency in your Hardhat project:

BASH
npm install --save-dev @dappsoverapps.com/hardhat-patch

  • Repository layout (relevant parts):

    TEXT
    src/hardhat-patch/
      index.ts
      arbitrum-patch.ts
      native-precompiles.ts
      shims/
        ArbSysShim.json
        ArbGasInfoShim.json
      tasks/
        arb-install-shims.ts
        arb-reseed-shims.ts
        arb-gas-info.ts
    
    probes/hardhat/
      hardhat.config.js
      precompiles.config.json            (optional)
      contracts/
        ArbSysShim.sol
        ArbGasInfoShim.sol
      scripts/
        predeploy-precompiles.js         (preinstall bytecode at 0x…64/0x…6c)
        install-and-check-shims.js       (one-shot install + verify)
        check-gasinfo-local.js           (read getPricesInWei())
        validate-precompiles.js          (end-to-end probe)
    

Options (Hardhat arbitrum block)

KeyTypeDefaultNotes
enabledbooleantrueTurns the patch on/off.
runtime"stylus" | "nitro""stylus"Stylus-first target.
precompiles.mode"shim" | "auto" | "native""auto"integration uses shim path; auto gracefully installs shims.
stylusRpcstring(unset)Remote RPC used by tasks when --stylus is selected. Can also be set via STYLUS_RPC.
gas.pricesInWeistring[6](unset)Shim order: [ perL2Tx, perL1CalldataFee, perStorageAllocation, perArbGasBase, perArbGasCongestion, perArbGasTotal ]. Used when no RPC/ cache is chosen.
arbSysChainIdnumber42161Returned by ArbSysShim at slot 0.
costing.enabledbooleanfalseIf implemented, returns a small, stable non-zero gasUsed for precompile calls in shim mode (off by default).

Configuration

hardhat.config.js (Stylus-first defaults)

JS
require("@nomicfoundation/hardhat-ethers");
require("@dappsoverapps.com/hardhat-patch");     // plugin entry; auto-loads tasks

module.exports = {
  solidity: "0.8.19",
  networks: {
    hardhat: { chainId: 42161 },
    // optional persistent node:
    // localhost: { url: "http://127.0.0.1:8549", chainId: 42161 }
  },
  arbitrum: {
    enabled: true,
    runtime: "stylus",                  // Stylus-first
    precompiles: { mode: "auto" },      // tries native later; shims today
    // stylusRpc: "https://sepolia-rollup.arbitrum.io/rpc", // optional default
  },
};
  • runtime: "stylus" sets Stylus as the default runtime flavor.
  • precompiles.mode: "auto" enables lazy shim installation in this integration (native hooks can be introduced in a later phase).

precompiles.config.json (optional)

JSON
{
  "arbSysChainId": 42161,
  "runtime": "stylus",
  "gas": {
    "pricesInWei": ["69440", "496", "2000000000000", "100000000", "0", "100000000"]
  },
  "stylusRpc": "https://sepolia-rollup.arbitrum.io/rpc"
}
  • gas.pricesInWei is a 6-tuple in shim order:

    TEXT
    [ perL2Tx, perL1CalldataFee, perStorageAllocation, perArbGasBase, perArbGasCongestion, perArbGasTotal ]
    
  • When both stylusRpc and gas.pricesInWei are present, reseeding prioritizes RPC (§3.4).

2.3 Environment variables (optional)

  • STYLUS_RPC — RPC endpoint for Stylus (for example, https://sepolia-rollup.arbitrum.io/rpc).
  • ARB_PRECOMPILES_CONFIG — path override to a non-default precompiles.config.json.

Stability toggles (often helpful on WSL/docker):

  • NODE_OPTIONS=--dns-result-order=ipv4first
  • NODE_NO_HTTP2=1

Example:

BASH
export NODE_OPTIONS=--dns-result-order=ipv4first
export NODE_NO_HTTP2=1
export STYLUS_RPC=https://sepolia-rollup.arbitrum.io/rpc

Shim installation & reseeding

Two flows are supported: ephemeral (in-process Hardhat VM) and persistent (a running Hardhat node on a port, e.g., 8549). Both install shims at the canonical addresses:

  • ArbSys0x0000000000000000000000000000000000000064
  • ArbGasInfo0x000000000000000000000000000000000000006c

Ephemeral Hardhat (fastest loop)

This mode spins up a fresh in-process Hardhat network per command.

BASH
# One-shot install + verify
npx hardhat --config hardhat.config.js run scripts/install-and-check-shims.js

Expected example:

TEXT

Arbitrum Precompile Installer & Verifier
Target Address: 0x000000000000000000000000000000000000006c

   [1/4] Compiling contracts... Nothing to compile
Done.
   [2/4] Installing bytecode (4091 bytes)... Done.
   [3/4] Seeding default configuration...

   [4/4] Verifying State:
   Parameter            | Actual          | Expected        | Status
   ---------------------+-----------------+-----------------+-------
   Wei: Per L2 Tx       | 1843139200      | 1843139200      | OK
   Wei: Per L1 Call     | 13165280        | 13165280        | OK
   Arb: Per L2 Tx       | 91              | 91              | OK
   Arb: Per Storage     | 20000           | 20000           | OK

Tasks auto-loaded by the plugin can also be used:

BASH
npx hardhat --config hardhat.config.js arb:install-shims

Persistent Hardhat node (HTTP)

Start a node and point “localhost” at it:

BASH
# Start persistent node on 8549
npx hardhat node --port 8549
# …leave running

Optional environment setup:

BASH
export NODE_OPTIONS=--dns-result-order=ipv4first
export NODE_NO_HTTP2=1
export STYLUS_RPC=https://sepolia-rollup.arbitrum.io/rpc

Network entry for the persistent node:

JS
networks: {
  localhost: { url: "http://127.0.0.1:8549", chainId: 42161 },
}

Predeploy shim bytecode:

BASH
npx hardhat --config hardhat.config.js run --network localhost scripts/predeploy-precompiles.js
# Example:
# ArbSys code len: 582 ArbGasInfo code len: 1600
# ✅ Shims predeployed at 0x...64 and 0x...6c

Reseed from Stylus (preferred)

BASH
# Reseed using Stylus RPC (explicit flag)
npx hardhat --config hardhat.config.js arb:reseed-shims --network localhost --stylus

Examples:

Success

TEXT
=== Arbitrum Shim Reseeder ===
   [RPC] Fetched Wei Prices from Stylus.
   [RPC] Fetched ArbGas Prices from Stylus.
   > Processing updates...
   [Success] Wei Prices Updated:
      - Per L2 Tx      : 88946706240
      - Per L1 Call    : 635333616
      - Per Storage    : 400000000000
      - ArbGas Base    : 20000000
      - Congestion     : 0
      - Total          : 20000000
   [Success] ArbGas Prices Updated: [4446, 31, 20000]
   [Success] Nitro Scalars Updated
   [Success] Constraints Updated (6 items)

Temporary failure (fallback)

TEXT
=== Arbitrum Shim Reseeder ===
   [Config] Using JSON for Wei Prices.
   [Config] Using JSON for ArbGas Prices.
   > Processing updates...
   [Success] Wei Prices Updated:
      - Per L2 Tx      : 69440
      - Per L1 Call    : 1
      - Per Storage    : 2000000000000
      - ArbGas Base    : 100000000
      - Congestion     : 0
      - Total          : 1
   [Success] ArbGas Prices Updated: [91, 0, 20000]
   [Success] Nitro Scalars Updated
   [Success] Constraints Updated (1 items)

Source priority (reseeding)

  1. Stylus RPC (flag --stylus, or stylusRpc/STYLUS_RPC)
  2. precompiles.config.json (gas.pricesInWei in shim order)
  3. Built-in fallback (safe defaults)

Supported flags:

  • --stylus — prioritize Stylus RPC
  • --nitro — prioritize Nitro RPC (optional, for parity checks)
  • No flag — follow config/env; otherwise fall back to config/defaults

Validation scripts

Readback sanity check

BASH
npx hardhat --config hardhat.config.js run --network localhost scripts/check-gasinfo-local.js
# Example:
# [ '69440', '496', '2000000000000', '100000000', '0', '100000000' ]

Full validation (raw selectors + contract calls)

BASH
npx hardhat --config hardhat.config.js run --network localhost scripts/validate-precompiles.js

Expected example:

TEXT
 Validating Arbitrum Precompiles in Hardhat Context...

Arbitrum patch found in HRE
 Found 2 precompile handlers:
   ArbSys: 0x0000000000000000000000000000000000000064
   ArbGasInfo: 0x000000000000000000000000000000000000006c

 Testing ArbSys arbChainID...
ArbSys arbChainID returned: 42161

⛽ Testing ArbGasInfo getL1BaseFeeEstimate...
ArbGasInfo getL1BaseFeeEstimate returned: 1000000000 wei (1 gwei)

📄 Testing contract deployment and precompile calls...
ArbProbes contract deployed at: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
Contract ArbSys call returned: 42161
Contract ArbGasInfo call returned: 496

 Precompile validation completed!

Note: in shim mode, getCurrentTxL1GasFees() returns the estimate (slot 1) for deterministic test results.


Operational notes

  • Address immutability: shims are placed at canonical precompile addresses; this mirrors Arbitrum expectations in local testing.
  • Determinism vs. realism: shim values can be fixed via config or sampled via RPC. For reproducible tests, the config tuple is recommended.
  • RPC networking: ipv4first and NODE_NO_HTTP2=1 often resolve transient TLS/HTTP2 issues on WSL/docker.
  • ChainId: ArbSysShim returns arbSysChainId (from config) at slot 0; default resolves to 42161.

Quick reference (common commands)

Ephemeral, one-shot

BASH
npx hardhat --config hardhat.config.js run scripts/install-and-check-shims.js
# or
npx hardhat --config hardhat.config.js arb:install-shims

Persistent node (8549)

BASH
# Terminal A
npx hardhat node --port 8549

# Terminal B
npx hardhat --config hardhat.config.js run --network localhost scripts/predeploy-precompiles.js
STYLUS_RPC=https://sepolia-rollup.arbitrum.io/rpc \
npx hardhat --config hardhat.config.js arb:reseed-shims --network localhost --stylus
npx hardhat --config hardhat.config.js run --network localhost scripts/check-gasinfo-local.js
npx hardhat --config hardhat.config.js run --network localhost scripts/validate-precompiles.js