alloy-monad-evm is the Alloy integration layer for Monad execution.
It wraps monad-revm behind alloy-evm traits so Foundry/Alloy-based execution stacks can instantiate Monad EVMs through standard interfaces.
For the staking precompile design and detailed semantics, see the monad-revm README:
| Component | Version |
|---|---|
alloy-evm |
0.39.0 |
alloy-primitives |
1.6.1 |
monad-revm |
0.8.0 |
revm |
43.0.0 |
| Rust MSRV | 1.94.1 |
Development builds temporarily pin monad-revm to
bc7f7af,
which contains the merged core fixes for delegated precompiles, fatal staking database errors,
and reserve enforcement.
Applications consuming this branch and depending directly on monad-revm must use the same Git
revision until these fixes are released.
MonadEvm:alloy_evm::Evmimplementation wrappingmonad_revm::MonadEvm.MonadEvmFactory:alloy_evm::EvmFactoryimplementation for building Monad EVM instances from Alloy environments.extend_monad_precompiles_for_spec: helper that registers Monad precompile metadata into aPrecompilesMapfor a specific Monad spec.
alloy-monad-evm does not reimplement staking logic. It delegates execution to monad-revm staking modules and focuses on wiring:
- Registers Monad-only precompile addresses via
PrecompilesMap::apply_precompileso they are discoverable in precompile address sets. - Ensures precompile-aware tooling behavior (for example, Foundry warm precompile handling and better revert diagnostics).
- Routes write selectors through
monad_revm::staking::write::run_staking_write. - Routes read selectors through
monad_revm::staking::run_staking_with_reader. - Enforces direct-call behavior (
DELEGATECALL/CALLCODE, delegated top-level calls, and static contexts are rejected in this integration path).
This keeps staking behavior centralized in one place (monad-revm) while allowing Alloy-based runtimes to execute the same semantics.
- Monad gas model (cold access repricing, no refunds).
- MIP-8 page-level storage warming and SSTORE accounting on MonadTen and later.
- Monad precompile repricing.
- Staking precompile at
0x1000(read + write + syscalls, viamonad-revm). - Reserve-balance precompile execution and metadata at
0x1001for MonadNine and later. - Transaction reserve enforcement on every supported hardfork, exposed as
MonadHaltReason::ReserveBalanceViolation. BothEvmandEvmFactoryuse the re-exportedMonadHaltReason; ordinary Ethereum halts are wrapped inMonadHaltReason::Ethereum. - Per-frame protocol precompile selection when execution crosses Monad hardforks.
- Mutable precompile overrides and removals that remain authoritative for dispatch and warming.
Reserve violations roll back execution state and logs while retaining transaction fees and
the sender nonce. The root inspector completion callbacks observe the adjudicated outcome,
including immediate empty-account and precompile calls. Stock revm-inspectors Geth and
Parity traces therefore report a failed root with their ordinary execution reverted and
Reverted labels. The distinct reason is available in the returned
ExecutionResult::Halt { reason: MonadHaltReason::ReserveBalanceViolation, .. }; the stock
trace formats do not add a Monad-specific error message.
With with_log enabled, the stock Geth call tracer retains attempted root logs even after a
revert, just as it does for an ordinary EVM REVERT. Those trace logs are not committed
transaction logs. Successful child frames can also remain visible beneath a rejected root.
Embedders that execute an internal call in an isolated EVM can preserve the enclosing
reserve tracker with MonadJournalTr::set_preserve_reserve_balance_tracker(true). Such
execution defers reserve adjudication until the enclosing transaction finishes. Return the
journal and tracker to the enclosing execution, retain its rollback checkpoint, and restore
preservation to false before normal execution resumes. A later repayment can clear the
deficit; an unpaid deficit rejects the enclosing transaction and rolls back the isolated
state too. Reverted isolated calls recompute the restored balances without finalizing the
enclosing reserve status. These integration tests exercise the Alloy factory and core
execution APIs; adopting this behavior in Foundry requires a separate downstream update.
[dependencies]
alloy-monad-evm = "0.8.0"
monad-revm = "0.8.0"Applications that also depend directly on alloy-evm or revm must use version 0.39 and
43, respectively. Update these dependencies together because their public EVM, database,
inspector, and precompile types must match.
use alloy_evm::EvmFactory;
use alloy_monad_evm::MonadEvmFactory;
let factory = MonadEvmFactory::default();
let evm = factory.create_evm(db, env);use alloy_evm::precompiles::PrecompilesMap;
use alloy_monad_evm::extend_monad_precompiles_for_spec;
use monad_revm::{precompiles::MonadPrecompiles, MonadHardfork};
let spec = MonadHardfork::MonadNine;
let monad_precompiles = MonadPrecompiles::new_with_spec(spec);
let mut precompiles = PrecompilesMap::from_static(monad_precompiles.precompiles());
extend_monad_precompiles_for_spec(&mut precompiles, spec);MonadEvmMonadEvmFactoryMonadPrecompilesMapMonadContext(re-export frommonad-revm)MonadHandler(re-export frommonad-revm)extend_monad_precompiles_for_spec
std(default): Enables standard-library support foralloy-primitives,revm,alloy-evm, andmonad-revm.memory_limit(default): Enables Monad MIP-3 memory-limit support throughmonad-revm.asm-keccak: Enables platform-dependent assembly Keccak implementations inalloy-evm,alloy-primitives, andrevm.
With default features disabled, the crate is no_std and uses alloc. CI checks both the base
configuration and memory_limit on thumbv7em-none-eabi; asm-keccak is not available on every
bare-metal target.
Licensed under MIT license.