Special thanks to Łukasz Miłkowski for his valuable input during the development of this specification
RIGID (Rollup Interoperable Gas Interface Declaration) establishes a standard for rollups in the Ethereum ecosystem to declare their gas market characteristics in a machine-actionable format. By publishing these parameters, RIGID enables trustless interoperability, automated fee optimization by Gas Agents, and transparent adaptation to changes in fee models across diverse Layer 2 solutions.
Rollups today operate with disparate and opaque gas pricing models, making it difficult for developers, users, and automated agents to reason about transaction costs across ecosystems. This complexity arises because each rollup defines its own fee components, adjustment logic, and update cadence - often offchain and inconsistently documented.
RIGID addresses this gap by establishing a standard, onchain declaration format for rollup gas markets. The motivation is threefold:
By standardizing how networks expose gas market data, RIGID unlocks a new layer of composability and coordination for the L2 ecosystem.
Each network has a distinct gas market model. RIGID standardizes the process of publishing this information onchain in a verifiable way. RIGID introduces a set of standardized fields like structured fee components and robust RPN formalism. This enables automated systems to retrieve the declared gas market parameters, compute fees dynamically, and react to changes immediately. This allows changes in rollup gas market parameters to be transparently published and broadcast via events, allowing real-time automated adjustments.
For example, a historical protocol upgrade such as Optimism's Ecotone would have triggered a GasMarketUpdated event with new parameters defined by a RIGID declaration. The rollup effectively transitioned from a calldata-only fee model to a hybrid model incorporating blob pricing - moving from a formula based solely on baseFee to one weighted by both baseFeeScalar and blobBaseFeeScalar to reflect Ethereum’s blob data pricing (EIP-4844). A corresponding RIGID interface could clearly expose these parameter changes to gas agents for automated fee adjustment.
RIGID establishes a standard by defining highly optimized onchain data structures (Solidity structs) for declaring rollup gas market characteristics. These structured types are the canonical and only representation for RIGID declarations, designed for maximum efficiency in onchain storage and machine-actionable parsing by smart contracts and gas agents.
The core declaration is encapsulated within the GasMarketDeclaration struct. All fields included directly influence automated decision-making. The precise definitions of all RIGID structs, including GasMarketDeclaration, FeeComponent, ParamTuple, and RollupSpecificContextVariable, are provided in Section 5.1: Smart Contract Interface.
GasMarketDeclaration Onchain Data Structure Diagram V1.0The Standard Context Variables are predefined inputs necessary for calculating fees within RIGID formulas. Each variable is identified by a unique id (uint8). IDs from 0 to 100 are reserved for these globally defined standard variables.
These variables are consumed by the onchain fee formulas and represent commonly used parameters by fee formulas. Their types and units are precisely defined to ensure deterministic interpretation by smart contracts and gas agents.
| ID | Variable | Unit | Type |
|---|---|---|---|
| 0 | L1_basefee | wei/L1 gas | uint256 |
| 1 | L1_blob_basefee | wei/blob gas | uint256 |
| 2 | transaction_calldata_size_bytes | bytes | uint256 |
| 3 | transaction_blob_count | count | uint256 |
| 4 | transaction_L2_gas_used | L2 gas units | uint256 |
| 5 | user_priority_fee_per_gas | wei/L2 gas | uint256 |
| 6 | transaction_L2_computation_unit | custom unit | uint256 |
| 7 | transaction_proof_size_bytes | bytes | uint256 |
| 8 | transaction_dac_data_size_bytes | bytes | uint256 |
| 9 | L2_state_access_reads | count | uint256 |
| 10 | L2_state_access_writes | count | uint256 |
| 11 | calldata_byte_cost | L1 gas/byte | uint256 |
| 12 | max_block_size | gas units | uint64 |
| 13 | target_block_size | gas units | uint64 |
| 14 - 99 | reserved_for_future_use | - | - |
Context Variable Accessibility: The mapping of Standard Context Variable IDs (0–99) to their units and types is maintained offchain in a canonical registry (e.g., within the RIGID GitHub repo or by indexers). Implementers must use this registry to resolve variable metadata consistently. Their values are derived from various sources, such as direct transaction inputs or dynamic state queries from the Layer 1 or Layer 2 blockchain. Agents consuming RIGID interfaces will integrate these values into their context for accurate formula evaluation.
Note on Gas Units (in EVM Ecosystem): All gas costs are ultimately valued and paid for in the base currency unit, wei. This is crucial for interpreting fee calculations. The L2 gas units metric quantifies the computational work within a specific Layer-2 rollup. While user fees are ultimately paid in wei, the conversion rate between L2 gas units and a corresponding value in wei is defined by each rollup and can differ from the wei/L1 gas cost. The user_priority_fee_per_gas reflects the amount of wei willing to be paid per L2 gas unit. Conversely, L1 basefee and L1 blob basefee are denominated in wei/L1 gas and wei/blob gas, representing the L1 costs incurred by the rollup. The calldata_byte_cost specifies the L1 gas cost per byte of calldata. This distinction allows RIGID to represent the nuanced gas economics of different rollups.
rollup_specific_context_variables:RollupSpecificContextVariable[]
Rollup-Specific Context Variables provide dynamic inputs unique to a particular rollup's gas market. These are non-standard variables introduced by the rollup itself, representing information that is specific to its unique fee model and changes dynamically (e.g., per block, based on rollup state, or governance updates). They are essential for calculations within a rollup's specific fee formula.
Each rollup-specific variable is defined within the RollupSpecificContextVariable struct (as detailed in Section 5.1). This struct includes:
id (uint8): A unique identifier for the custom context variable.
100 to 199 for their custom context variables. IDs from 0 to 99 are reserved for standard context variables and potential future additions to the standard set.unit (string): The unit of the variable.dataType (string): The data type of the variable.description (string): A human-readable explanation of the variable's purpose.These variables are included in the rollupSpecificContextVariables array within the GasMarketDeclaration struct, making them an integral part of the onchain declaration.
The fees field within the GasMarketDeclaration struct (see Section 5.1) is an array of FeeComponent structs. Each FeeComponent defines a distinct part of the gas calculation and includes the following structured fields:
id:uint8: Numeric identifier for the fee component.formula:string: RPN (Reverse Polish Notation) string defining the fee calculation logic.tokens:uint8[]: Array of numeric token IDs representing accepted payment tokens (e.g., 0 for ETH).params:ParamTuple[]: Array of ParamTuple structs (as defined in Section 5.1), each representing a constant parameter used in the formula.flags:uint32: Bitwise flags indicating specific behaviors or modifiers for the fee component.id:uint8
The id field within a FeeComponent is a uint8 numeric identifier.
This ID uniquely identifies the fee component and always corresponds to a Context Variable (Standard or Rollup Specific).
rollupSpecificContextVariables array of the GasMarketDeclaration struct, as described in Section 2.3.formula:string
The formula field contains a string encoded in RPN (Reverse Polish Notation). RPN is chosen for its suitability for onchain evaluation and processing by automated agents due to the following characteristics:
RIGID utilizes RPN to ensure gas agents can process fee formulas reliably and efficiently.
The set of supported operators within RIGID is specifically defined to ensure consistent evaluation across all implementations. Unrecognized operators must consistently default to zero or trigger a safe revert, never consume unbounded gas or produce invalid results. This policy ensures deterministic and safe formula evaluations. All operations operate on unsigned 256-bit integers with integer division (truncating towards zero).
Supported Operators:
add (+), multiply (*), divide (/), subtract (-)greater than (>), if (condition, true_result, false_result), equal (=), minimum (min), maximum (max)square root (sqrt), natural logarithm (ln)Error Handling for Mathematical Functions:
Implementations must handle potential error conditions gracefully to ensure deterministic results.
0.sqrt: If the input is negative, the result must be 0.ln (natural logarithm):
0 or 1, the result must be 0.0.Variables and Constants in Formulas:
All numbers appearing in the formula string are IDs that refer to either:
rollupSpecificContextVariables array (Section 2.3).ParamTuple): Any constant values needed within a formula must be defined as parameters within the params:ParamTuple[] array of that specific FeeComponent and are referenced by their ID (from 200 to 255) within the formula string.Unit Considerations in Formulas: Implementers must ensure that the RPN formula logic respects the units of the involved context variables and parameters. Operations should only combine compatible units in a mathematically meaningful way to produce a final fee value with a relevant unit (typically representing cost in wei).
RPN Formula Example:
Consider a formula field containing the string "4 6 * 5 +".
This corresponds to the following evaluation logic:
4 (representing transaction_L2_gas_used).6 (representing transaction_L2_computation_unit).* (multiply): Pop the top two values (6 and 4), multiply them, and push the result (4 * 6). This represents the L2 execution cost.5 (representing user_priority_fee_per_gas).+ (add): Pop the top two values (5 and 4*6), add them, and push the final result (4 * 6) + 5. This represents the total L2 execution cost plus the priority fee.tokens:uint8[]
This array holds numeric identifiers for the tokens accepted for payment of this specific fee component (e.g., 0 for ETH). Each FeeComponent specifies which tokens can be used for its associated cost. The mapping of these numeric token IDs to their corresponding token contracts or symbols is maintained offchain, typically in the same registry that resolves context variable metadata.
This registry provides the canonical mapping, making it accessible to gas agents for reliable context to understand accepted tokens and facilitate crosschain transfers or conversions.
| ID | Ticker | Hex (Address) |
|---|---|---|
| 0 | ETH | 0x0000000000000000000000000000000000000000 |
| 1 | USDC | 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48 |
| 2 | USDT | 0xdAC17F958D2Ee523a2206206994597C13D831ec7 |
| 3 | DAI | 0x6B175474E89094C44Da98b954EedeAC495271d0F |
| 4 | MATIC | 0x7D1AfA7B718FbC363b0893A57080E1945F06Bd4b |
params:ParamTuple[]
Each parameter is defined as a ParamTuple struct (as defined in Section 5.1). This struct contains an id (uint8), referenced within the formula, and its corresponding arbitrary-precision value (uint256). Each parameter must represent a constant used in the fee calculation for this specific fee component.
To avoid conflicts with Context Variable IDs, parameters must use IDs starting from 200 to 255 (as uint8 goes up to 255).
flags:uint32
The flags field uses a concise, bitwise mechanism to indicate specific boolean behaviors or modifiers that apply to a fee component, beyond the calculation defined in its RPN formula. These flags signal rules affecting how automated agents handle the fee. Bits are interpreted in big-endian order.
| Bit Position | Flag Name | Default Behavior (if bit is 0) |
|---|---|---|
| 31 | is_subsidized | Transaction is not subsidized. |
| 30 | enforce_min_price | Minimum price is not enforced beyond the base calculation. |
| 29 | allow_zero_gas_payment | Transactions must pay some gas (zero payment not allowed). |
| 28 | fixed_fee | Fee is not a fixed amount. |
| 27 - 0 | reserved_for_future_use | Behavior is undefined and must be treated as 0 (inactive). |
Interpretation of Flags:
A flag is considered active if its corresponding bit is 1 in the flags field for a given fee component. If the bit is 0, the flag's default behavior is applied. If a flag set to 1 isn't recognized (not part of the standard), it must be ignored.
How to use the flags field:
Consider a FeeComponent struct where the flags field is set to 134217728.
This decimal value corresponds to 0b00001000000000000000000000000000 in binary (32-bit), where only bit 27 (from the right, 0-indexed) is set to 1. This signifies that the fixed_fee flag is active.
is_subsidized (bit 31)
Some rollups or applications absorb the entire fee on behalf of end users.
is_subsidized = 1 means the user’s balance is never debited; the protocol covers the cost.allow_zero_gas_payment (bit 29)
Allows users to submit transactions with zero tip, relying on a separate sponsor/paymaster.
allow_zero_gas_payment = 1 lets agents generate a valid tx with zero user fee.version:uint16
This integer indicates the version of the RIGID specification schema used for this declaration. This allows agents to interpret the data according to the correct version's rules, ensuring compatibility and proper schema interpretation.
timestamp:uint64
This field records the UNIX timestamp (in seconds) indicating when this RIGID declaration was last updated or became active. It helps agents track the freshness of the data and reason about the validity period of the declared parameters.
version and timestamp for defining validity.When a rollup modifies its gas market, the following process is followed:
updateGasMarketDeclaration().updateGasMarketDeclaration function is called with a complete GasMarketDeclaration struct.GasMarketUpdated event is emitted.GasMarketUpdated.mapping(uint16 => Declaration) for O(1) access by version.This section outlines the pseudocode interface for a RIGID-compliant onchain declaration contract. This interface defines the canonical data structures and functions for publishing and accessing rollup gas market parameters directly on the blockchain.
For implementers, optimizing gas costs in smart contracts often involves trade-offs. Emitting large data structures, such as the full GasMarketDeclaration struct, in events can lead to significant gas consumption due to log storage costs. A common pattern is to emit only minimal data (e.g., version, blockNumber, or a hash) and let offchain consumers retrieve the full struct via getLatestDeclaration().
Similarly, while updating the full GasMarketDeclaration is simple, more gas-efficient alternatives may involve supporting targeted updates to individual FeeComponent or RollupSpecificContextVariable entries. This is especially useful when declarations change frequently.
To prevent unit mismatches in fee calculations, implementers should define a minimal UnitRegistry that maps each context variable ID to its unit. Updates must validate unit compatibility and revert on incompatible references.
Consumers must validate formulas offchain and check unit compatibility before execution to avoid overflows or incorrect fee results. Future versions of RIGID may include stricter validation rules or external verification mechanisms.
The RIGID specification introduces a structured onchain format for declaring gas market parameters. The following risks and mitigations must be considered by implementers:
UnitRegistry and strict validation logic should be used to detect and prevent invalid updates.ln() and sqrt() safely. These must return zero, not throw.timestamp, but consumers must not rely on this as proof of freshness without additional verification (e.g., checking event block numbers).These considerations are essential to avoid incorrect gas computation, DoS vectors, or exploit paths via misconfigured declarations.
This specification introduces a new, optional standard. It does not modify any existing rollup or L1 protocol behavior.
RIGID declarations exist in isolated onchain contracts and do not interfere with legacy gas pricing systems unless adopted by integrators.
Rollups may adopt RIGID in parallel of any existing documentation effort.
RIGID establishes a universal, onchain standard that empowers Ethereum rollups to transparently publish their gas market parameters in a uniform, machine-actionable format. By leveraging structured, minimal schemas and RPN-encoded fee formulas with well-defined context variables, it enables automated agents to estimate costs accurately, adapt dynamically to evolving fee models, and route transactions optimally across diverse Layer 2 environments.
Its built-in versioning and event-driven update mechanisms ensure full auditability and trustless interoperability, while the onchain registry and optional aggregators unlocks a better experience by providing a unified view and real-time notification. Altogether, RIGID lays the technical foundation for a cohesive, scalable ecosystem where developers, operators, and agents can interact with rollup gas markets confidently and efficiently.
To ensure RIGID remains practical, robust, and implementable, the following areas require further definition or enhancements:
FeeComponent.tokens. This ensures integrators consistently resolve the exact same metadata, maintaining ecosystem-wide coherence. Defining the specific governance, integrity, and tooling for this canonical offchain registry remains an open discussion.GasMarketDeclaration structures is costly. Implementers could define an explicit emission mode (Full vs Lite) allowing contracts to broadcast only minimal data (version, hash, blockNumber) for gas efficiency, with full declarations retrievable offchain via view functions.UnitRegistry mapping each Context Variable ID explicitly to its unit. Implementers could leverage this mapping and add a validation step in the declaration update flow, causing incompatible unit references to revert clearly and immediately.uint8 ID namespace to a larger uint16 namespace. While immediate migration isn't necessary, specifying a planned upgrade path ensures the namespace will comfortably accommodate future expansion, avoiding potential exhaustion.Join the discussion on Ethereum Magicians. Feedback, issues, and PRs are welcome.
Copyright and related rights waived via CC0 1.0 Universal.