1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
2
3use alloy_evm::{
12 precompiles::{DynPrecompile, Precompile, PrecompileInput, PrecompilesMap},
13 Database, Evm, EvmEnv, EvmFactory, EvmInternals,
14};
15use alloy_primitives::{Address, Bytes, U256};
16use monad_revm::{
17 instructions::MonadInstructions,
18 monad_context_with_db,
19 precompiles::MonadPrecompiles,
20 reserve_balance::{self, abi::RESERVE_BALANCE_ADDRESS},
21 staking::{self, write::StakingStorage, StorageReader, STAKING_ADDRESS},
22 MonadBuilder, MonadCfgEnv, MonadEvm as InnerMonadEvm, MonadSpecId,
23};
24use revm::{
25 context::{BlockEnv, TxEnv},
26 context_interface::result::{EVMError, HaltReason, ResultAndState},
27 context_interface::{ContextTr, JournalTr, LocalContextTr},
28 handler::PrecompileProvider,
29 inspector::NoOpInspector,
30 interpreter::{CallInput, CallInputs, Gas, InstructionResult, InterpreterResult},
31 precompile::{PrecompileError, PrecompileId, PrecompileOutput},
32 Context, ExecuteEvm, InspectEvm, Inspector, SystemCallEvm,
33};
34use std::ops::{Deref, DerefMut};
35
36pub use monad_revm::{handler::MonadHandler, MonadContext};
38
39#[derive(Clone, Debug)]
41pub struct MonadPrecompilesMap {
42 inner: PrecompilesMap,
43 spec: MonadSpecId,
44}
45
46impl MonadPrecompilesMap {
47 pub fn new_with_spec(spec: MonadSpecId) -> Self {
49 let monad_precompiles = MonadPrecompiles::new_with_spec(spec);
50 let mut inner = PrecompilesMap::from_static(monad_precompiles.precompiles());
51 extend_monad_precompiles(&mut inner);
52 Self { inner, spec }
53 }
54
55 pub fn addresses(&self) -> impl Iterator<Item = Address> + '_ {
57 let reserve_balance_enabled = MonadSpecId::MonadNine.is_enabled_in(self.spec);
58 std::iter::once(STAKING_ADDRESS)
59 .chain(reserve_balance_enabled.then_some(RESERVE_BALANCE_ADDRESS))
60 .chain(self.inner.addresses().copied().filter(move |address| {
61 *address != STAKING_ADDRESS
62 && (!reserve_balance_enabled || *address != RESERVE_BALANCE_ADDRESS)
63 }))
64 }
65
66 pub fn contains(&self, address: &Address) -> bool {
68 *address == STAKING_ADDRESS
69 || (MonadSpecId::MonadNine.is_enabled_in(self.spec)
70 && *address == RESERVE_BALANCE_ADDRESS)
71 || self.inner.get(address).is_some()
72 }
73
74 fn run_dynamic<DB: Database>(
75 &mut self,
76 context: &mut MonadContext<DB>,
77 inputs: &CallInputs,
78 ) -> Result<Option<InterpreterResult>, String> {
79 let Some(precompile) = self.inner.get(&inputs.bytecode_address) else {
80 return Ok(None);
81 };
82
83 let mut result = InterpreterResult {
84 result: InstructionResult::Return,
85 gas: Gas::new(inputs.gas_limit),
86 output: Bytes::new(),
87 };
88
89 let (block, tx, cfg, journaled_state, _, local) = context.all_mut();
90
91 let input_bytes = match &inputs.input {
92 CallInput::SharedBuffer(range) => {
93 if let Some(slice) = local.shared_memory_buffer_slice(range.clone()) {
94 slice.to_vec()
95 } else {
96 Vec::new()
97 }
98 }
99 CallInput::Bytes(bytes) => bytes.to_vec(),
100 };
101
102 let precompile_result = precompile.call(PrecompileInput {
103 data: &input_bytes,
104 gas: inputs.gas_limit,
105 caller: inputs.caller,
106 value: inputs.call_value(),
107 is_static: inputs.is_static,
108 internals: EvmInternals::new(journaled_state, block, cfg, tx),
109 target_address: inputs.target_address,
110 bytecode_address: inputs.bytecode_address,
111 });
112
113 match precompile_result {
114 Ok(output) => {
115 let underflow = result.gas.record_cost(output.gas_used);
116 assert!(underflow, "Gas underflow is not possible");
117 result.result = if output.reverted {
118 InstructionResult::Revert
119 } else {
120 InstructionResult::Return
121 };
122 result.output = output.bytes;
123 }
124 Err(PrecompileError::Fatal(error)) => return Err(error),
125 Err(error) => {
126 result.result = if error.is_oog() {
127 InstructionResult::PrecompileOOG
128 } else {
129 InstructionResult::PrecompileError
130 };
131 if !error.is_oog() && context.journal().depth() == 1 {
132 context
133 .local_mut()
134 .set_precompile_error_context(error.to_string());
135 }
136 }
137 }
138
139 Ok(Some(result))
140 }
141}
142
143impl Deref for MonadPrecompilesMap {
144 type Target = PrecompilesMap;
145
146 fn deref(&self) -> &Self::Target {
147 &self.inner
148 }
149}
150
151impl DerefMut for MonadPrecompilesMap {
152 fn deref_mut(&mut self) -> &mut Self::Target {
153 &mut self.inner
154 }
155}
156
157impl<DB: Database> PrecompileProvider<MonadContext<DB>> for MonadPrecompilesMap {
158 type Output = InterpreterResult;
159
160 fn set_spec(&mut self, spec: MonadSpecId) -> bool {
161 if spec == self.spec {
162 return false;
163 }
164 *self = Self::new_with_spec(spec);
165 true
166 }
167
168 fn run(
169 &mut self,
170 context: &mut MonadContext<DB>,
171 inputs: &CallInputs,
172 ) -> Result<Option<Self::Output>, String> {
173 if let Some(result) = staking::run_staking_precompile(context, inputs)? {
174 return Ok(Some(result));
175 }
176
177 if let Some(result) = reserve_balance::run_reserve_balance_precompile(context, inputs)? {
178 return Ok(Some(result));
179 }
180
181 self.run_dynamic(context, inputs)
182 }
183
184 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
185 Box::new(self.addresses())
186 }
187
188 fn contains(&self, address: &Address) -> bool {
189 Self::contains(self, address)
190 }
191}
192
193#[allow(missing_debug_implementations)] pub struct MonadEvm<DB: Database, I, P = MonadPrecompilesMap> {
200 inner: InnerMonadEvm<MonadContext<DB>, I, MonadInstructions<MonadContext<DB>>, P>,
201 inspect: bool,
202}
203
204impl<DB: Database, I, P> MonadEvm<DB, I, P> {
205 pub const fn ctx(&self) -> &MonadContext<DB> {
207 &self.inner.0.ctx
208 }
209
210 pub const fn ctx_mut(&mut self) -> &mut MonadContext<DB> {
212 &mut self.inner.0.ctx
213 }
214}
215
216impl<DB: Database, I, P> MonadEvm<DB, I, P> {
217 pub const fn new(
222 evm: InnerMonadEvm<MonadContext<DB>, I, MonadInstructions<MonadContext<DB>>, P>,
223 inspect: bool,
224 ) -> Self {
225 Self {
226 inner: evm,
227 inspect,
228 }
229 }
230}
231
232impl<DB: Database, I, P> Deref for MonadEvm<DB, I, P> {
233 type Target = MonadContext<DB>;
234
235 #[inline]
236 fn deref(&self) -> &Self::Target {
237 self.ctx()
238 }
239}
240
241impl<DB: Database, I, P> DerefMut for MonadEvm<DB, I, P> {
242 #[inline]
243 fn deref_mut(&mut self) -> &mut Self::Target {
244 self.ctx_mut()
245 }
246}
247
248impl<DB, I, P> Evm for MonadEvm<DB, I, P>
249where
250 DB: Database,
251 I: Inspector<MonadContext<DB>>,
252 P: PrecompileProvider<MonadContext<DB>, Output = InterpreterResult>,
253{
254 type DB = DB;
255 type Tx = TxEnv;
256 type Error = EVMError<DB::Error>;
257 type HaltReason = HaltReason;
258 type Spec = MonadSpecId;
259 type BlockEnv = BlockEnv;
260 type Precompiles = P;
261 type Inspector = I;
262
263 fn block(&self) -> &BlockEnv {
264 &self.block
265 }
266
267 fn chain_id(&self) -> u64 {
268 self.cfg.chain_id
269 }
270
271 fn transact_raw(
272 &mut self,
273 tx: Self::Tx,
274 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
275 if self.inspect {
276 self.inner.inspect_tx(tx)
277 } else {
278 self.inner.transact(tx)
279 }
280 }
281
282 fn transact_system_call(
283 &mut self,
284 caller: Address,
285 contract: Address,
286 data: Bytes,
287 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
288 self.inner.system_call_with_caller(caller, contract, data)
289 }
290
291 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>) {
292 let Context {
293 block: block_env,
294 cfg: monad_cfg,
295 journaled_state,
296 ..
297 } = self.inner.0.ctx;
298 let cfg_env = monad_cfg.into_inner();
300
301 (
302 journaled_state.into_database(),
303 EvmEnv { block_env, cfg_env },
304 )
305 }
306
307 fn set_inspector_enabled(&mut self, enabled: bool) {
308 self.inspect = enabled;
309 }
310
311 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
312 (
313 &self.inner.0.ctx.journaled_state.database,
314 &self.inner.0.inspector,
315 &self.inner.0.precompiles,
316 )
317 }
318
319 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
320 (
321 &mut self.inner.0.ctx.journaled_state.database,
322 &mut self.inner.0.inspector,
323 &mut self.inner.0.precompiles,
324 )
325 }
326}
327
328#[derive(Debug, Default, Clone, Copy)]
332#[non_exhaustive]
333pub struct MonadEvmFactory;
334
335impl EvmFactory for MonadEvmFactory {
336 type Evm<DB: Database, I: Inspector<MonadContext<DB>>> = MonadEvm<DB, I, Self::Precompiles>;
337 type Context<DB: Database> = MonadContext<DB>;
338 type Tx = TxEnv;
339 type Error<DBError: core::error::Error + Send + Sync + 'static> = EVMError<DBError>;
340 type HaltReason = HaltReason;
341 type Spec = MonadSpecId;
342 type BlockEnv = BlockEnv;
343 type Precompiles = MonadPrecompilesMap;
344
345 fn create_evm<DB: Database>(
346 &self,
347 db: DB,
348 input: EvmEnv<MonadSpecId>,
349 ) -> Self::Evm<DB, NoOpInspector> {
350 let spec_id = input.cfg_env.spec;
351 let monad_cfg = MonadCfgEnv::from(input.cfg_env);
353
354 MonadEvm {
355 inner: monad_context_with_db(db)
356 .with_block(input.block_env)
357 .with_cfg(monad_cfg)
358 .build_monad_with_inspector(NoOpInspector {})
359 .with_precompiles(MonadPrecompilesMap::new_with_spec(spec_id)),
360 inspect: false,
361 }
362 }
363
364 fn create_evm_with_inspector<DB: Database, I: Inspector<Self::Context<DB>>>(
365 &self,
366 db: DB,
367 input: EvmEnv<MonadSpecId>,
368 inspector: I,
369 ) -> Self::Evm<DB, I> {
370 let spec_id = input.cfg_env.spec;
371 let monad_cfg = MonadCfgEnv::from(input.cfg_env);
373
374 MonadEvm {
375 inner: monad_context_with_db(db)
376 .with_block(input.block_env)
377 .with_cfg(monad_cfg)
378 .build_monad_with_inspector(inspector)
379 .with_precompiles(MonadPrecompilesMap::new_with_spec(spec_id)),
380 inspect: true,
381 }
382 }
383}
384
385pub fn extend_monad_precompiles(precompiles: &mut PrecompilesMap) {
409 precompiles.apply_precompile(&STAKING_ADDRESS, |_| {
410 Some(DynPrecompile::new_stateful(
411 PrecompileId::Custom("MonadStaking".into()),
412 |input: PrecompileInput<'_>| -> Result<PrecompileOutput, PrecompileError> {
413 if !input.is_direct_call() {
415 return Ok(PrecompileOutput::new_reverted(0, Bytes::new()));
416 }
417
418 if input.is_static {
420 return Ok(PrecompileOutput::new_reverted(0, Bytes::new()));
421 }
422
423 let selector: [u8; 4] = match input.data.get(..4).and_then(|s| s.try_into().ok()) {
425 Some(s) => s,
426 None => {
427 let mut storage = PrecompileInputStakingStorage {
429 internals: input.internals,
430 };
431 let result = staking::write::run_staking_write(
432 input.data,
433 input.gas,
434 &mut storage,
435 &input.caller,
436 input.value,
437 )
438 .map_err(|e| PrecompileError::Other(e.into()))?;
439 return interpreter_result_to_output(input.gas, result);
440 }
441 };
442
443 if staking::write::is_write_selector(selector) {
445 let mut storage = PrecompileInputStakingStorage {
446 internals: input.internals,
447 };
448 let caller = input.caller;
449 let call_value = input.value;
450 match staking::write::run_staking_write(
451 input.data,
452 input.gas,
453 &mut storage,
454 &caller,
455 call_value,
456 ) {
457 Ok(result) => interpreter_result_to_output(input.gas, result),
458 Err(e) => Err(PrecompileError::Other(e.into())),
459 }
460 } else {
461 let mut reader = PrecompileInputStakingStorage {
463 internals: input.internals,
464 };
465 match staking::run_staking_with_reader(
466 input.data,
467 input.gas,
468 &mut reader,
469 input.value,
470 ) {
471 Ok(result) => interpreter_result_to_output(input.gas, result),
472 Err(e) => Err(PrecompileError::Other(e.into())),
473 }
474 }
475 },
476 ))
477 });
478}
479
480fn interpreter_result_to_output(
482 gas_limit: u64,
483 result: InterpreterResult,
484) -> Result<PrecompileOutput, PrecompileError> {
485 let gas_used = gas_limit.saturating_sub(result.gas.remaining());
486 if result.result == InstructionResult::Return {
487 Ok(PrecompileOutput::new(gas_used, result.output))
488 } else if result.result == InstructionResult::PrecompileOOG {
489 Err(PrecompileError::OutOfGas)
490 } else {
491 Ok(PrecompileOutput::new_reverted(gas_used, result.output))
493 }
494}
495
496struct PrecompileInputStakingStorage<'a> {
498 internals: alloy_evm::EvmInternals<'a>,
499}
500
501impl StorageReader for PrecompileInputStakingStorage<'_> {
502 fn sload(&mut self, key: U256) -> Result<U256, PrecompileError> {
503 self.internals
504 .sload(STAKING_ADDRESS, key)
505 .map(|r| r.data)
506 .map_err(|e| PrecompileError::Other(format!("Storage read failed: {e:?}").into()))
507 }
508}
509
510impl StakingStorage for PrecompileInputStakingStorage<'_> {
511 fn sstore(&mut self, key: U256, value: U256) -> Result<(), PrecompileError> {
512 self.internals
513 .sstore(STAKING_ADDRESS, key, value)
514 .map(|_| ())
515 .map_err(|e| PrecompileError::Other(format!("Storage write failed: {e:?}").into()))
516 }
517
518 fn transfer(
519 &mut self,
520 from: Address,
521 to: Address,
522 amount: U256,
523 ) -> Result<(), PrecompileError> {
524 if amount.is_zero() {
525 return Ok(());
526 }
527 match self.internals.transfer(from, to, amount) {
528 Ok(None) => Ok(()),
529 Ok(Some(e)) => Err(PrecompileError::Other(
530 format!("Transfer failed: {e:?}").into(),
531 )),
532 Err(e) => Err(PrecompileError::Other(
533 format!("Transfer error: {e:?}").into(),
534 )),
535 }
536 }
537
538 fn emit_log(&mut self, log: revm::primitives::Log) -> Result<(), PrecompileError> {
539 self.internals.log(log);
540 Ok(())
541 }
542}
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547
548 #[test]
549 fn staking_precompile_is_available_on_all_monad_specs() {
550 for spec in [
551 MonadSpecId::MonadEight,
552 MonadSpecId::MonadNine,
553 MonadSpecId::MonadNext,
554 ] {
555 let precompiles = MonadPrecompilesMap::new_with_spec(spec);
556 let addresses = precompiles.addresses().collect::<Vec<_>>();
557
558 assert!(precompiles.contains(&STAKING_ADDRESS));
559 assert!(addresses.contains(&STAKING_ADDRESS));
560 }
561 }
562
563 #[test]
564 fn reserve_balance_precompile_is_gated_to_monad_nine_and_later() {
565 let monad_eight = MonadPrecompilesMap::new_with_spec(MonadSpecId::MonadEight);
566 let monad_nine = MonadPrecompilesMap::new_with_spec(MonadSpecId::MonadNine);
567 let monad_next = MonadPrecompilesMap::new_with_spec(MonadSpecId::MonadNext);
568
569 assert!(!monad_eight.contains(&RESERVE_BALANCE_ADDRESS));
570 assert!(!monad_eight
571 .addresses()
572 .any(|address| address == RESERVE_BALANCE_ADDRESS));
573
574 assert!(monad_nine.contains(&RESERVE_BALANCE_ADDRESS));
575 assert!(monad_nine
576 .addresses()
577 .any(|address| address == RESERVE_BALANCE_ADDRESS));
578
579 assert!(monad_next.contains(&RESERVE_BALANCE_ADDRESS));
580 assert!(monad_next
581 .addresses()
582 .any(|address| address == RESERVE_BALANCE_ADDRESS));
583 }
584
585 #[test]
586 fn set_spec_rebuilds_monad_only_precompile_set() {
587 let mut precompiles = MonadPrecompilesMap::new_with_spec(MonadSpecId::MonadEight);
588
589 assert!(!precompiles.contains(&RESERVE_BALANCE_ADDRESS));
590 assert!(
591 PrecompileProvider::<MonadContext<revm::database::EmptyDB>>::set_spec(
592 &mut precompiles,
593 MonadSpecId::MonadNine
594 )
595 );
596 assert!(precompiles.contains(&RESERVE_BALANCE_ADDRESS));
597 assert!(
598 !PrecompileProvider::<MonadContext<revm::database::EmptyDB>>::set_spec(
599 &mut precompiles,
600 MonadSpecId::MonadNine
601 )
602 );
603 }
604}