> For the complete documentation index, see [llms.txt](https://docs.megaeth.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.megaeth.com/spec/system-contracts/mega-access-control.md).

# MegaAccessControl

This page specifies the MegaAccessControl system contract. It defines the address, interface, interception semantics, and the volatile-data access restriction mechanism.

## Motivation

[Gas detention](/spec/megaevm/gas-detention.md) is reactive — it caps remaining compute gas only after volatile data has already been accessed. Contracts that call untrusted code have no way to prevent that code from silently triggering detention and tightening the caller's gas budget.

MegaAccessControl provides a proactive mechanism: a contract can disable volatile data access for its entire call subtree before any untrusted code runs. Attempts to access volatile data while disabled revert immediately, preventing both the access and the detention side effect.

## Specification

### Address

The MegaAccessControl system contract MUST exist at `MEGA_ACCESS_CONTROL_ADDRESS`.

### Bytecode

The contract takes no constructor arguments. A node MUST deploy the bytecode version corresponding to the active spec.

#### Version 1.0.0

Since: [Rex4](/spec/network-upgrades/rex4.md)

Code hash: `0x96d0f3ba6b474e9684a97e4388ec8dbb7929818b51e6b4f19f885ccbdf642f9b`

Deployed bytecode: `0x60806040526004361061003e...` (full bytecode: [`MegaAccessControl-1.0.0.json`](https://github.com/megaeth-labs/mega-evm/blob/main/crates/system-contracts/artifacts/MegaAccessControl-1.0.0.json), `deployedBytecode` field).

To verify the code hash, from the repository root:

```bash
cast keccak $(jq -r .deployedBytecode crates/system-contracts/artifacts/MegaAccessControl-1.0.0.json)
```

### Interface

```solidity
interface IMegaAccessControl {
    enum VolatileDataAccessType {
        BlockNumber,    // 0  — NUMBER opcode
        Timestamp,      // 1  — TIMESTAMP opcode
        Coinbase,       // 2  — COINBASE opcode
        Difficulty,     // 3  — DIFFICULTY opcode
        GasLimit,       // 4  — GASLIMIT opcode
        BaseFee,        // 5  — BASEFEE opcode
        PrevRandao,     // 6  — PREVRANDAO opcode
        BlockHash,      // 7  — BLOCKHASH opcode
        BlobBaseFee,    // 8  — BLOBBASEFEE opcode
        BlobHash,       // 9  — BLOBHASH opcode
        Beneficiary,    // 10 — account access targeting the block beneficiary
        Oracle          // 11 — SLOAD on oracle contract
    }

    error NotIntercepted();
    error NonZeroTransfer();
    error VolatileDataAccessDisabled(VolatileDataAccessType accessType);
    error DisabledByParent();

    function disableVolatileDataAccess() external view;
    function enableVolatileDataAccess() external view;
    function isVolatileDataAccessDisabled() external view returns (bool disabled);
}
```

### Interception Scope

All three functions (`disableVolatileDataAccess`, `enableVolatileDataAccess`, `isVolatileDataAccessDisabled`) participate in [call interception](/spec/system-contracts/interception.md). The node MUST intercept `CALL` and `STATICCALL` to `MEGA_ACCESS_CONTROL_ADDRESS` when the input matches a known selector.

`DELEGATECALL` and `CALLCODE` to this address MUST NOT be intercepted. They fall through to the on-chain bytecode, which reverts with `NotIntercepted()`.

Unknown selectors MUST NOT be intercepted and MUST fall through to the on-chain bytecode.

### Execution-Local Policy State

The restriction controlled by `disableVolatileDataAccess` and `enableVolatileDataAccess` MUST be treated as execution-local policy state rather than persistent chain state. Successful interception of those selectors MUST update that execution-local policy state identically for `CALL` and `STATICCALL`. Those updates MUST NOT write account storage, emit logs, or transfer value.

### Value Transfer Policy

All intercepted functions MUST reject calls with non-zero value transfer. If the call carries a non-zero transferred value, the node MUST revert with `NonZeroTransfer()`.

### `disableVolatileDataAccess`

When intercepted, the node MUST disable volatile data access for the caller's [call frame](/spec/reference/glossary.md#call-frame) and all descendant call frames. The rule above MUST apply identically when the selector is reached through `CALL` or `STATICCALL`.

While disabled, any volatile data access — block environment reads, beneficiary-targeted account access (including `SELFDESTRUCT` to the beneficiary), and [oracle](/spec/system-contracts/oracle.md) storage reads — MUST revert immediately with `VolatileDataAccessDisabled(VolatileDataAccessType accessType)`.

Blocked volatile access MUST NOT update volatile-access tracking and MUST NOT tighten [gas detention](/spec/megaevm/gas-detention.md).

For opcodes that are unconditionally volatile — block-environment reads such as `TIMESTAMP`, `NUMBER`, `COINBASE`, `DIFFICULTY` / `PREVRANDAO`, `GASLIMIT`, `BASEFEE`, `BLOBBASEFEE`, `BLOCKHASH`, and `BLOBHASH` — the disabled-state revert is synthesized before operand validation. A malformed invocation of an operand-taking unconditionally volatile opcode (`BLOCKHASH`, `BLOBHASH`) with an insufficient stack therefore reverts with `VolatileDataAccessDisabled` instead of halting with the canonical stack-underflow error; this is intended MegaETH semantics. Conditionally volatile opcodes — `BALANCE`, `EXTCODESIZE`, `EXTCODECOPY`, `EXTCODEHASH`, the CALL family, and `SELFDESTRUCT`, which are volatile only when their operand resolves to the beneficiary — inspect their operands first and keep the canonical stack-underflow halt when the stack is malformed.

<details>

<summary>Rex6 (unstable): source-side SELFDESTRUCT and EIP-7702-delegated call targets</summary>

Under Rex6, two additional beneficiary accesses MUST revert with `VolatileDataAccessDisabled` while volatile data access is disabled:

* a `SELFDESTRUCT` executed by a contract whose own address is the block beneficiary — the operation reads and zeroes the executing contract's balance, so it observes beneficiary state regardless of its stack target; the guard applies only once the target operand exists, so a stack-underflow `SELFDESTRUCT` keeps its canonical stack-underflow halt;
* a `CALL`, `CALLCODE`, `DELEGATECALL`, or `STATICCALL` whose target's [EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) delegation designation resolves (one hop) to the beneficiary.

Pre-Rex6, only the `SELFDESTRUCT` stack target and the raw CALL-family target operand are compared to the beneficiary.

</details>

<details>

<summary>Rex6 (unstable): Oracle `sendHint` forwarding</summary>

Under Rex6, a `sendHint` call (see [`Oracle`](/spec/system-contracts/oracle.md#hint-forwarding)) MUST NOT forward its payload to the off-chain oracle backend when the calling frame's volatile data access is disabled. Unlike the reverting accesses above, a disabled `sendHint` call MUST NOT revert: the node MUST skip forwarding and let the call fall through to the on-chain Oracle bytecode, without charging the call against the transaction's data-size resource lane — the same admission-failure shape as a zero-gas-limit or selector-mismatch call (a decode failure differs: it is still charged). The hint is an off-chain side-channel, not consensus state, so silently dropping it — rather than reverting the caller's on-chain control flow — is the correct failure mode.

Pre-Rex6, `sendHint` forwarding did not consult the volatile-access-disabled state at all.

</details>

### `enableVolatileDataAccess`

When intercepted, the node MUST re-enable volatile data access for the caller's call frame and descendant call frames if and only if the restriction was set at the caller's depth or was not active. The rule above MUST apply identically when the selector is reached through `CALL` or `STATICCALL`.

If the restriction was set by an ancestor call frame (a parent at a shallower depth), the node MUST revert with `DisabledByParent()`.

### `isVolatileDataAccessDisabled`

When intercepted, the node MUST return `true` if volatile data access is currently disabled for the caller's call frame (whether disabled by the caller or an ancestor call frame), and `false` otherwise.

### Lifetime

The volatile data access restriction automatically ends when the call frame that called `disableVolatileDataAccess` returns. No explicit cleanup is needed.

## Constants

| Constant                      | Value                                        | Description                        |
| ----------------------------- | -------------------------------------------- | ---------------------------------- |
| `MEGA_ACCESS_CONTROL_ADDRESS` | `0x6342000000000000000000000000000000000004` | MegaAccessControl contract address |

## Rationale

**Why a system contract instead of an EVM opcode?** Volatile data access control is a MegaETH-specific mechanism with no Ethereum precedent. Using a system contract avoids polluting the opcode space and provides a stable Solidity interface that existing toolchains can use without modifications.

**Why revert instead of silently blocking?** Silent blocking would hide bugs. If a contract expects to read block data but the access is silently suppressed, the contract would receive stale or zero values and proceed with incorrect state. Reverting makes the restriction visible and forces the caller to handle it explicitly.

**Why prevent descendant re-enabling when a parent disabled access?** Allowing untrusted child code to re-enable access would defeat the purpose. The calling contract disables access precisely because it does not trust inner calls to behave correctly with volatile data. The parent-override rule preserves the caller's intent.

**Why allow `disableVolatileDataAccess()` and `enableVolatileDataAccess()` under `STATICCALL`?** These functions change execution-local policy state only. Allowing the same interception semantics under `STATICCALL` lets read-only frames defend themselves against descendant volatile accesses and restore their own policy when the disable was set at the same depth. Treating these selectors as forbidden mutable side effects under `STATICCALL` would make that defense unavailable to `view` entrypoints.

## Spec History

* [Rex4](/spec/network-upgrades/rex4.md) introduced the MegaAccessControl system contract.
* [Rex6](/spec/network-upgrades/rex6.md) (**unstable**) — extends the disabled-state beneficiary guard to a `SELFDESTRUCT` whose executing contract is the beneficiary and to CALL-family targets whose EIP-7702 delegate resolves to the beneficiary.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.megaeth.com/spec/system-contracts/mega-access-control.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
