MIP Adoption
On-chain measurement of Monad Improvement Proposals. Every MIP on this page carries a method tag, and a description of how on-chain data was measured. See /mips/methodology for more details.
Final MIPs
live on Monad mainnet since MONAD_NINEMIP-2 raised two limits at MONAD_NINE: deployed MAX_CODE_SIZE from 24 KB (EIP-170) to 128 KB, and MAX_INITCODE_SIZEfrom 48 KB (EIP-3860) to 256 KB. Adoption shows up as two distinct signals: contracts whose deployed bytecode wouldn't fit on Ethereum, and contracts whose constructor payload wouldn't.
Deployed code > 24.0KB (EIP-170 ceiling)
For every successful contract creation since MONAD_NINE activation (block 62,466,234), the scanner records the deployed bytecode length. Creations are identified by walking `eth_getBlockReceipts` for each block and filtering receipts where `contractAddress` is set (covers both top-level CREATE transactions and factory CREATE/CREATE2 spawns). The bytecode itself is fetched via `eth_getCode`. Contracts whose deployed bytecode exceeds 24,576 bytes (EIP-170, the pre-MIP-2 ceiling) use MIP-2's `MAX_CODE_SIZE` raise.
source · eth_getBlockReceipts + eth_getCode against the public Monad RPC pool
Initcode > 48.0KB (EIP-3860 ceiling)
A contract can clear the EIP-3860 initcode limit while staying within the EIP-170 deployed-code limit: long constructors that compress to a small runtime. Those count as MIP-2 adopters even if their deployed bytecode looks ordinary.
For each successful deployment, the deployment transaction's `input` field equals the initcode length when the transaction is a top-level CREATE (`to == null`). Contracts whose initcode exceeded 49,152 bytes (EIP-3860, the pre-MIP-2 initcode ceiling) use MIP-2's `MAX_INITCODE_SIZE` raise.
Limitations. Contracts deployed by factories (`CREATE`/`CREATE2` inside another transaction) have their deployed bytecode captured but not their initcode — `tx.input` is the factory's calldata, not the spawned contract's initcode. Recovering the latter requires call traces, which are not currently indexed at scale for Monad. In practice all 200 sampled jumbo (>24KB) contracts were direct-CREATE, so jumbo-initcode coverage is effectively complete; the small-contract initcode dimension is partial.
source · eth_getTransactionByHash on the deployment tx; `input.length` measured client-side
MIP-3 replaces Ethereum's quadratic memory cost (words² / 512 + 3·words) with linear pricing (words / 2) and caps memory at 8 MB per transaction. The change is a pure gas-pricing recompute: transaction receipts don't reveal which regime applied, so we don't publish a usage count. The calculator below shows the gas you'd save by allocating a given memory size under MIP-3 vs Ethereum.
MIP-3 changes the gas-cost formula for memory expansion from quadratic (`words² / 512 + 3·words`) to linear (`words / 2`), with an 8 MB hard cap per transaction. The change is a server-side pricing recompute - transaction receipts show only the final `gasUsed`, with no indication of which regime applied or how much memory was expanded. Detecting MIP-3 usage directly would require step-level execution traces (e.g. `debug_traceTransaction` with the `structLogger`) to recover peak memory per transaction and recompute the Ethereum-equivalent cost.
Limitations. Step-level tracing across every Monad transaction is currently infeasible (no trace-indexed source for Monad on Envio HyperSync; rpc.monad.xyz's `debug_traceBlockByNumber` is rate-limited below the chain's own block-production rate). Instead the page exposes a calculator so developers can compute the savings for their own use cases.
source · interactive calculator - no on-chain measurement
MIP-4 introduced a precompile at 0x000000…001001 exposing dippedIntoReserve() (selector 0x3a61584e). It returns a bool indicating whether the executing transaction has dipped into reserve balance, designed for mid-execution checks by other contracts, never a top-level transaction target. Adoption has two distinct flavors and we report each separately: static potential (contracts that could invoke it) and runtime reality (whether they actually do).
Static · contracts that could invoke MIP-4
0x…10010x3a61584eFor every contract deployed since MONAD_NINE, the scanner walks the deployed bytecode as opcodes (skipping `PUSH1..PUSH32` immediate data) and looks for two patterns: the literal precompile address `0x…1001` (which Solidity emits for hardcoded `address(0x…1001)`), and the 4-byte function selector `0x3a61584e` (which catches contracts that load the address dynamically — from storage, calldata, or computation — but still invoke `dippedIntoReserve()`). Either signal counts a contract as statically MIP-4-aware.
Limitations. This counts contracts that *could* invoke the precompile, not the count of actual invocations. A contract with the bytes baked in might never take the MIP-4 branch in practice. For actual on-chain usage see the runtime sample below.
source · deployed bytecode of every scanned contract, opcode-aware walk
Runtime · actual on-chain invocations
sample-mip4-runtime.ts against the trace-supporting endpoint and updates this block; numbers will appear after the first successful run.Once per day a sparse trace sample runs: 25 windows of 60 blocks each, evenly distributed across the post-MONAD_NINE range. Each block goes through `debug_traceBlockByNumber` (`callTracer`) on `rpc.monad.xyz` — the only Monad endpoint we have access to that exposes trace methods. The call tree of every transaction is walked, counting CALL frames where the destination is the MIP-4 precompile. (Per the MIP-4 spec, `dippedIntoReserve()` must be invoked via `CALL`; `STATICCALL`/`DELEGATECALL`/`CALLCODE` are forbidden and would revert. Non-CALL frames are reported separately as anomalies.) Each run covers ~1,500 blocks (~7 minutes of chain time) spread across 50+ days of history; the cumulative result is preserved.
Limitations. A true exhaustive runtime backfill is currently infeasible on the available infrastructure. `rpc.monad.xyz` sustains roughly 3 blocks/second of sequential tracing while the chain produces ~3.5 blocks/second, so brute-force scanning can't even keep pace, let alone backfill 14M+ blocks of history. The other Monad pool endpoints (`rpc1/2/3`) reject trace methods (403). Envio HyperSync does not currently index Monad trace data — confirmed empirically. Until either of those changes, runtime usage is reported as a sampled estimate, not a complete count.
source · debug_traceBlockByNumber + callTracer on rpc.monad.xyz
MIP-5 activates three EIPs from Ethereum's Fusaka upgrade. They have very different shapes - one adds a new opcode (positive adoption signal), one tightens a precompile's input bounds (a restriction, no positive metric), and one increases a precompile's gas cost (not detectable from RPC). We report each separately rather than rolling them into one misleading number.
EIP-7939 · CLZ opcode (0x1e)
For every contract deployed since MONAD_NINE the scanner walks the deployed bytecode as opcodes (skipping `PUSH1..PUSH32` immediate data) and counts contracts that contain the new CLZ opcode (byte 0x1e). A naive substring check would false-positive on `0x1e` bytes appearing inside `PUSH32` payloads; the disassembly walk avoids that.
source · deployed bytecode of every scanned contract, opcode-aware walk
EIP-7823 · MODEXP input bounds (0x000000…000005)
Real usage isn't measurable on Monad. MODEXP is a precompile called internally via CALL from other contracts — an exhaustive scan of the post-MONAD_NINE range found zero top-level calls to 0x…0005— and internal precompile calls require execution traces Monad doesn't expose (HyperSync has no traces; debug_trace is rate-limited below block production). So this is a restrictive change we document rather than count. The new cap is 1,024 Bper length parameter; the EIP author's historical analysis found the largest real MODEXP input was 513 B, so no real caller is expected to be affected.
MODEXP precompile (`0x…0005`) invocation counts are derived from the full transactions history via HyperSync. We surface total observed calls and the count exceeding the new 1024-byte input bound (which is expected to be zero — the EIP author's historical Ethereum analysis showed the largest observed MODEXP input in past history was 513 bytes, well below the new cap).
Limitations. This is a *restrictive* change rather than a positive adoption signal. The published number is a confirmation that no real-world caller was affected, not a measure of adoption.
source · HyperSync transactions query filtered by `to = 0x…0005`
EIP-7883 · MODEXP gas-cost increase
EIP-7883 raises MODEXP gas cost; the change is a server-side pricing recompute and is not detectable from RPC receipts. Documented only.
EIP-7883 raises the gas cost for the MODEXP precompile (from `max(200, mc·ic/3)` to `max(500, mc·ic)`, with the multiplier for oversized exponents doubled). The change is a server-side pricing recompute: the same inputs and outputs occur, only the gas debit differs. Transaction receipts cannot distinguish the old regime from the new — they only show the final `gasUsed`. We document the change but do not publish a number.
source · documented only — no measurement
MIP-6 is a meta proposal that coordinated the simultaneous activation of MIPs 3, 4, and 5 on Monad mainnet. It introduces no standalone protocol changes - it is the umbrella event the substantive MIPs anchor to, and the lower bound of every adoption metric on this page.
Roadmap
draft MIPs not yet on mainnetExhaustive- the number is derived from every event in the scanned range; no sampling. Sampled- a statistical estimate with the sample size and time coverage quoted alongside. Calculator- no on-chain measurement; an interactive tool to compute what the spec implies for inputs you supply. Not measurable - the spec change is real but receipts/traces don't expose it; we document the change and report no number.
Weekly snapshots are published to the public monscope-data archive and exposed via the /api/v1/mips endpoint.