For the complete documentation index, see llms.txt. This page is also available as Markdown.

Oracle

MegaETH Oracle system contract — address, storage layout, hint forwarding, and gas detention trigger.

This page specifies the Oracle system contract. It defines the address, interface, restricted write behavior, storage access semantics, and hint forwarding.

Motivation

MegaETH needs a canonical protocol-level storage backend for externally sourced data such as timestamps and other oracle-fed values. That storage must be readable by contracts, writable by protocol-controlled maintenance transactions, and stable across specs.

Specification

Address

The Oracle system contract MUST exist at ORACLE_CONTRACT_ADDRESS.

Bytecode

A node MUST deploy the bytecode version corresponding to the active spec. The current version (2.0.0) reads its authorized system address dynamically from SequencerRegistry.currentSystemAddress(). Earlier versions 1.0.0 and 1.1.0 instead took MEGA_SYSTEM_ADDRESS as a constructor immutable.

Version 1.0.0

Since: MiniRex

Code hash: 0xe9b044afb735a0f569faeb248088b4f267578f60722f87d06ec3867b250a2c34

Deployed bytecode:

0x608060405234801561000f575f5ffd5b506004361061006f575f3560e01c80637eba7ba61161004d5780637eba7ba614610118578063a21e2d6914610138578063fbc0d03514610158575f5ffd5b806301caec13146100735780630dc9b5da1461008857806354fd4d50146100d9575b5f5ffd5b610086610081366004610324565b61016b565b005b6100af7f000000000000000000000000a887dcb9d5f39ef79272801d05abdf707cfbbd1d81565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b604080518082018252600581527f312e302e30000000000000000000000000000000000000000000000000000000602082015290516100d09190610390565b61012a6101263660046103e3565b5490565b6040519081526020016100d0565b61014b6101463660046103fa565b6101e6565b6040516100d09190610439565b61008661016636600461047b565b61025c565b8281146101b2576040517f5b7232fa000000000000000000000000000000000000000000000000000000008152600481018490526024810182905260440160405180910390fd5b8382845f5b818110156101d457602081028381013590850135556001016101b7565b505050506101e061026b565b50505050565b60608167ffffffffffffffff8111156102015761020161049b565b60405190808252806020026020018201604052801561022a578160200160208202803683370190505b5090506020810183835f5b818110156102525760208102838101355490850152600101610235565b5050505092915050565b80825561026761026b565b5050565b3373ffffffffffffffffffffffffffffffffffffffff7f000000000000000000000000a887dcb9d5f39ef79272801d05abdf707cfbbd1d16146102da576040517f5e742c5a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b565b5f5f83601f8401126102ec575f5ffd5b50813567ffffffffffffffff811115610303575f5ffd5b6020830191508360208260051b850101111561031d575f5ffd5b9250929050565b5f5f5f5f60408587031215610337575f5ffd5b843567ffffffffffffffff81111561034d575f5ffd5b610359878288016102dc565b909550935050602085013567ffffffffffffffff811115610378575f5ffd5b610384878288016102dc565b95989497509550505050565b602081525f82518060208401528060208501604085015e5f6040828501015260407fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f83011684010191505092915050565b5f602082840312156103f3575f5ffd5b5035919050565b5f5f6020838503121561040b575f5ffd5b823567ffffffffffffffff811115610421575f5ffd5b61042d858286016102dc565b90969095509350505050565b602080825282518282018190525f918401906040840190835b81811015610470578351835260209384019390920191600101610452565b509095945050505050565b5f5f6040838503121561048c575f5ffd5b50508035926020909101359150565b7f4e487b71000000000000000000000000000000000000000000000000000000005f52604160045260245ffdfea26469706673582212205bb66f27c8ccdec3b5bbd6071d5f516754488531634a3ad38e6c7ffacf47a02464736f6c634300081e0033

Version 1.1.0

Since: Rex2

Code hash: 0x06df675a69e53ea2a3c948521e330b3801740fede324a1cef2044418f8e09242

Deployed bytecode:

Version 2.0.0

Since: Rex5

Code hash: 0x71a65239db8d0f1bb765fad36e34f57600420d103a4401ef7555bd50b229dc55

Deployed bytecode:

The authorization check MUST read the authorized address from SequencerRegistry.currentSystemAddress() instead of a constructor immutable. This enables system address change without redeploying the Oracle contract. All other functionality is preserved from v1.1.0.

Public Read Interface

The Oracle contract MUST expose the following externally callable read methods:

getSlot MUST return the storage value at the specified slot. getSlots MUST return the storage values at the specified slots in the same order as the input array.

Restricted Write Interface

The Oracle contract MUST expose the following write and log-emission methods:

The methods above MUST be callable only by MEGA_SYSTEM_ADDRESS. Calls from any other sender MUST revert with NotSystemAddress().

For setSlots, if the slots and values array lengths differ, the call MUST revert with InvalidLength(uint256 slotsLength, uint256 valuesLength).

Authorization Check Ordering

For setSlot, setSlots, emitLog, and emitLogs, the function body — including all SSTORE operations and LOG emissions — MUST execute before the caller authorization check. On an unauthorized call, the body MUST run to completion (consuming gas for all operations it performs — SSTORE writes, LOG emissions, and any loop iterations), and the call MUST then revert with NotSystemAddress(). The revert MUST roll back all storage writes and log emissions performed by the body, leaving no observable state change at the transaction boundary if the surrounding transaction does not catch the revert.

Authorization for setSlots is checked after the array-length equality check. If the lengths differ, the call MUST revert with InvalidLength(uint256, uint256) before any SSTORE runs and before the authorization check.

Design intent. Running the body before the authorization check makes the would-be storage writes and log emissions visible to off-chain EVM inspectors and trace consumers, even when the call ultimately reverts. This is intentional and is part of the observable behavior of the Oracle contract.

Auxiliary Interface

The Oracle contract MUST expose the following auxiliary methods:

multiCall MUST execute each payload by DELEGATECALL into the Oracle contract and MUST return the results in order. If any delegated call fails, multiCall MUST revert and MUST bubble up the revert data if present.

sendHint MUST be externally callable and MUST be a no-op at the Solidity bytecode level.

Storage Access Semantics

Reads. getSlot and getSlots read Oracle storage via SLOAD. The node MAY serve Oracle reads from an external data source that provides realtime, per-transaction values. When an SLOAD targets ORACLE_CONTRACT_ADDRESS, the node MUST first consult the external data source. If it provides a value for the requested slot, that value MUST be returned. Otherwise, the node MUST return the on-chain storage value.

Writes. setSlot and setSlots write Oracle storage via SSTORE. These methods are restricted to MEGA_SYSTEM_ADDRESS (see Restricted Write Interface).

On-chain persistence. When the external data source provides a value for a read, the sequencer MUST persist that value on-chain by inserting a Mega System Transaction that calls setSlot or setSlots. This system transaction MUST be ordered before the user transaction that triggered the read, so that full nodes replaying the block observe the same storage state.

Hint Forwarding

sendHint is the only function in Oracle system contract that participates in call interception. All other Oracle functions (getSlot, getSlots, setSlot, setSlots, emitLog, emitLogs, multiCall) execute via ordinary contract bytecode only.

When a CALL or STATICCALL targets ORACLE_CONTRACT_ADDRESS with the sendHint(bytes32,bytes) selector, the node MUST forward the topic and data to the external oracle backend as a side effect, subject to the admission conditions below. The call MUST then fall through — the Oracle contract's deployed sendHint function body executes as ordinary bytecode.

Because the Solidity implementation of sendHint is a no-op view function, the net observable behavior is the combination of:

  • hint forwarding to the oracle backend (side effect), and

  • normal bytecode execution of the no-op function body (which returns successfully with no output).

Calls to ORACLE_CONTRACT_ADDRESS that do not match the sendHint selector MUST fall through without any side effect.

When the call's gas limit is greater than zero and the calldata's leading four bytes match the sendHint selector, the node MUST charge the full byte length of the call's calldata — the entire call input — against the transaction's data-size resource lane before attempting to decode it. A call whose gas limit is zero MUST NOT be charged and MUST fall through to the on-chain Oracle bytecode for canonical handling. This charge MUST apply regardless of whether the calldata subsequently decodes successfully. If decoding the calldata fails, the node MUST NOT invoke the hint callback; the byte charge still applies.

The node MUST forward a hint to the off-chain backend only when the call's gas limit is greater than zero, the leading four bytes of the calldata match the sendHint selector, the calldata decodes as a valid sendHint(bytes32 topic, bytes data) invocation, AND recording the calldata byte length keeps the transaction within its data-size limit. If the gas limit is zero, or the selector does not match, or decoding fails, the node MUST NOT invoke the hint callback. A zero-gas-limit, selector-mismatch, or decode-failure call falls through to the on-chain Oracle bytecode for canonical handling. A data-size overflow halts the transaction with the canonical data-size OutOfGas failure.

If a transaction calls sendHint and subsequently reads an Oracle slot, the hint MUST be delivered to the oracle backend before the read is served.

Gas and Detention Semantics

The following gas and detention rules MUST apply:

  • SLOAD against Oracle storage MUST use the cold access gas cost.

  • Oracle storage reads MUST participate in gas detention.

  • CALL or STATICCALL to the Oracle contract address alone MUST NOT trigger oracle detention unless Oracle storage is actually read.

  • DELEGATECALL to the Oracle contract MUST NOT trigger oracle detention solely by targeting the Oracle address.

Versioning

Pre-Rex2, the deployed Oracle bytecode does not include sendHint. From Rex2 onward, the stable Oracle bytecode includes sendHint.

Upgrade storage semantics. When the Oracle account's bytecode is upgraded, the fate of existing Oracle storage is consensus-critical.

A bytecode upgrade MUST NOT mark the Oracle account as newly created. Existing Oracle storage MUST be preserved across the upgrade.

A historical exception applies to the Rex2 upgrade only: that upgrade marked the Oracle account as newly created, clearing any storage accumulated under the previous bytecode version, and canonical mainnet state reflects that the Oracle storage present at the Rex2 activation boundary was cleared.

Constants

Constant
Value
Description

ORACLE_CONTRACT_ADDRESS

0x6342000000000000000000000000000000000001

Stable Oracle system-contract address

Rationale

Why centralize oracle-backed data in one contract? Oracle-backed protocol data needs a single canonical storage location so all contracts and all nodes observe the same values under the same addressing scheme.

Why restrict writes to MEGA_SYSTEM_ADDRESS? Externally sourced oracle values are part of protocol-maintained state. Allowing arbitrary writes would destroy the meaning of oracle-backed data and make the values untrustworthy as protocol inputs.

Why use a per-transaction external data source instead of pre-populating all oracle data? Traditional oracle designs require all data to be written on-chain before any transaction can read it, even if most transactions never access oracle data. The external data source enables a realtime lazy oracle: values are only fetched and persisted when a transaction actually reads them. This avoids unnecessary system transactions for data that no one consumes, reduces block overhead, and allows oracle data to be as fresh as the moment of access rather than the moment of block construction. The sequencer's frontrunning system transaction ensures that the lazily served value is still persisted on-chain for full nodes and verifiers that replay the block.

Why intercept sendHint during call interception? Hint forwarding depends on external backend behavior that cannot be expressed by on-chain bytecode alone. The no-op Solidity body provides a stable interface, while the call interception mechanism supplies the protocol-level side effect.

Why run the restricted-write body before the authorization check? The authorization check is intentionally placed after the function body so that off-chain EVM inspectors observe the would-be storage writes and log emissions even when the call reverts. This preserves trace visibility for simulators that exercise the Oracle's write paths from non-system callers, at the cost of allowing unauthorized callers to perform unbounded body work that is rolled back on revert. The trade-off and its consequences are spelled out in Security Considerations.

Security Considerations

Block gas consumption by unauthorized callers. Because the body of setSlot, setSlots, emitLog, and emitLogs runs before the authorization check, an unauthorized caller MAY supply arbitrarily large input arrays to setSlots or emitLogs and cause the body to iterate and SSTORE (or emit LOG) up to the caller's gas allowance before the call reverts. The unauthorized caller pays the full gas cost of this work, but the gas consumed counts against the block's gas budget. This is not differentiable from any other unbounded-loop gas-burn pattern reachable from ordinary EVM bytecode, so it does not imply a contract change. A node implementation that gates the SSTORE or LOG operations on authorization first would produce gas accounting that disagrees with the canonical Oracle bytecode and MUST NOT be used.

Execution trace semantics for trace consumers. A trace produced by debug_traceTransaction or any equivalent inspector for an Oracle write call MAY contain SSTORE and LOG operations even when the surrounding call reverts. A consumer that infers permanent state changes from raw trace operations alone MUST NOT treat such operations as committed without first checking the final transaction status: if the transaction reverts, all SSTOREs and LOGs in its trace MUST be discarded. A consumer that fails to filter by transaction status MAY misattribute Oracle slot updates to unauthorized callers and corrupt downstream indexing or replay state.

Invariants preserved. The Oracle's restricted-write methods preserve the invariant that, at the transaction boundary, no Oracle storage slot is modified and no Log event is emitted by an unauthorized caller. Per-frame trace visibility of the would-be writes is informative only and MUST NOT be interpreted as a state change.

Spec History

  • MiniRex introduced the Oracle contract.

  • Rex2 added the sendHint entry point to the deployed Oracle bytecode.

  • Rex3 changed oracle detention to SLOAD-based triggering and raised the oracle detention cap to 20M.

  • Rex5 replaced the constructor immutable authority with a dynamic read from SequencerRegistry.currentSystemAddress() (Oracle v2.0.0), preserved existing Oracle storage across in-place bytecode upgrades, and gated hint forwarding on a positive gas limit while metering the full hint calldata against the transaction data-size lane before decoding.

Last updated