Skip to main content

Why choose to customize the precompiles on your Arbitrum chain

Customizing your chain's precompiles refers to modifying or extending the built-in, system-level smart contract-like functions (precompiles) that provide efficient access to chain-specific operations, such as interacting with the parent chain (L1 or L2), querying state, or performing computations. Precompiles are hardcoded at specific addresses (e.g., 0x64 for ArbSys) and executed outside the EVM bytecode level for performance. They inherit from Ethereum's standard precompiles (e.g., for hashing or elliptic curves) while adding Arbitrum-specific ones (e.g., ArbAddressTable for address compression).

Customization allows developers to add new methods, events, gas logic, or state interactions tailored to the chain's needs, such as app-specific utilities or optimizations. This flexibility is an advanced feature requiring modifications to the Nitro software stack, enabling deeper chain personalization beyond defaults like custom gas tokens or DA modes.

Key Concepts

  • Precompiles in Arbitrum: These are predefined contracts at fixed addresses that handle operations more efficiently than regular EVM code. Standard ones include ArbSys (for L1 interactions), ArbInfo (for balances and codes), and others for aggregation, retryables, or gas estimation. Customization builds on this by altering their behavior or adding new ones in the Nitro Go implementation.
  • Customization Scope: Focuses on extending functionality without full EVM changes, such as adding utility methods (e.g., a greeting function) or integrating chain-specific state (e.g., a stored number). It doesn't alter core EVM opcodes but enhances system access.

Options for Customization

There are several approaches, each building on the Nitro codebase:

  • Add New Methods to an Existing Precompile: Extend a built-in precompile (e.g., ArbSys) with additional functions.
  • Create a New Precompile: Define a completely new precompile at a custom address (e.g., 0x011a for ArbHi) with its own methods.
  • Define a New Event: Add events to methods for logging, making the method state-modifying and indexable for off-chain querying.
  • Customize Gas Usage: Adjust or implement gas costs for methods (e.g., burn 300 gas instead of 700 for a balance query) to optimize efficiency or prevent DoS attacks.
  • Call and Modify State: Integrate with ArbOS state by adding storage variables and methods to read/write them, allowing persistent chain-specific data.

Compatibility with Chain Types

  • Works with all Orbit DA modes (Rollup, AnyTrust, Alt-DA) and gas tokens (native ETH or custom), as it's a Nitro-level change.
  • Compatible with BoLD or permissioned validation, but custom precompiles may require eth_call for view methods to avoid breaking block validation.

Pros

  • Enables highly tailored functionality (e.g., custom events for better logging, state for app-specific data).
  • Optimizes performance and gas (e.g., cheaper queries).
  • Enhances chain utility for specialized use cases like DeFi or gaming.

Cons

  • Requires deep expertise in Go, Solidity, and Nitro; complex setup and maintenance.
  • Risks include DoS vulnerabilities without proper gas implementation, security issues without audits, and potential validation breaks.
  • No official review from Offchain Labs; changes may complicate upgrades or fraud proofs.

Examples

  • Adding a "sayHi" method to ArbSys that returns "hi" and emits a "Hi" event.
  • Creating a new ArbHi precompile with a gas-optimized balance query.
  • Storing and modifying a custom state variable like "myNumber" via a new method.

How to configure

Customizing requires building a modified Nitro node, as precompiles are part of the core software:

  1. Clone and Setup Nitro: Use branch v3.7.2 or later (git clone --branch v3.7.2 https://github.com/OffchainLabs/nitro.git), then initialize submodules.
  2. Edit Go Files: Modify /precompiles directory (e.g., add methods to ArbSys.go), register new precompiles in precompile.go, and for state changes, update arbosstate.go with variables, offsets, and initialization.
  3. Update Solidity Interfaces: Add corresponding methods/events to .sol files in the precompiles interface directory for dApp compatibility.
  4. Build and Run Node: Compile a custom Docker image and run the node with your configurations (e.g., specifying parent chain URL and chain ID). Test with tools like curl for eth_call or Foundry's cast for calls/sends.
  5. Post-Launch Changes: Use ArbOS version upgrades to apply without reorganizing the chain; follow related guides for fraud proofs.

This advanced customization aligns with Orbit's modular design but demands careful planning and testing. For implementation, refer to the docs or your RaaS; a list of RaaSes is on the Third-party providers page.