1use alloy_primitives::Address;
2use foundry_evm::revm::precompile::Precompile;
3use std::{fmt::Debug, sync::Arc};
4
5pub trait PrecompileFactory: Send + Sync + Unpin + Debug {
8 fn precompiles(&self) -> Vec<(Address, Precompile)>;
10}
11
12pub fn inject_precompiles<DB: revm::Database, I>(
17 evm: &mut revm::Evm<'_, I, DB>,
18 precompiles: Vec<(Address, Precompile)>,
19) {
20 evm.handler.append_handler_register_box(Box::new(move |handler| {
21 let precompiles = precompiles.clone();
22 let prev = handler.pre_execution.load_precompiles.clone();
23 handler.pre_execution.load_precompiles = Arc::new(move || {
24 let mut cx = prev();
25 cx.extend(precompiles.iter().cloned().map(|(a, b)| (a, b.into())));
26 cx
27 });
28 }));
29}
30
31#[cfg(test)]
32mod tests {
33 use crate::{evm::inject_precompiles, PrecompileFactory};
34 use alloy_primitives::Address;
35 use foundry_evm::revm::primitives::{address, Bytes, Precompile, PrecompileResult, SpecId};
36 use revm::primitives::PrecompileOutput;
37
38 #[test]
39 fn build_evm_with_extra_precompiles() {
40 const PRECOMPILE_ADDR: Address = address!("0x0000000000000000000000000000000000000071");
41
42 fn my_precompile(_bytes: &Bytes, _gas_limit: u64) -> PrecompileResult {
43 Ok(PrecompileOutput { bytes: Bytes::new(), gas_used: 0 })
44 }
45
46 #[derive(Debug)]
47 struct CustomPrecompileFactory;
48
49 impl PrecompileFactory for CustomPrecompileFactory {
50 fn precompiles(&self) -> Vec<(Address, Precompile)> {
51 vec![(PRECOMPILE_ADDR, Precompile::Standard(my_precompile))]
52 }
53 }
54
55 let db = revm::db::EmptyDB::default();
56 let env = Box::<revm::primitives::Env>::default();
57 let spec = SpecId::LATEST;
58 let handler_cfg = revm::primitives::HandlerCfg::new(spec);
59 let inspector = revm::inspectors::NoOpInspector;
60 let context = revm::Context::new(revm::EvmContext::new_with_env(db, env), inspector);
61 let handler = revm::Handler::new(handler_cfg);
62 let mut evm = revm::Evm::new(context, handler);
63 assert!(!evm
64 .handler
65 .pre_execution()
66 .load_precompiles()
67 .addresses()
68 .any(|&addr| addr == PRECOMPILE_ADDR));
69
70 inject_precompiles(&mut evm, CustomPrecompileFactory.precompiles());
71 assert!(evm
72 .handler
73 .pre_execution()
74 .load_precompiles()
75 .addresses()
76 .any(|&addr| addr == PRECOMPILE_ADDR));
77
78 let result = evm.transact().unwrap();
79 assert!(result.result.is_success());
80 }
81}