foundry_evm_networks/
arbitrum.rs1use std::borrow::Cow;
4
5use alloy_chains::Chain;
6use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
7use alloy_primitives::{Address, Bytes, U256, address, hex};
8use revm::precompile::{PrecompileHalt, PrecompileId, PrecompileOutput, PrecompileResult};
9
10pub const ARB_SYS_ADDRESS: Address = address!("0000000000000000000000000000000000000064");
12
13pub const ARB_BLOCK_NUMBER_SELECTOR: [u8; 4] = hex!("a3b1b31d");
15
16pub const ARB_BLOCK_NUMBER_GAS_COST: u64 = 3;
18
19pub static PRECOMPILE_ID_ARB_SYS: PrecompileId = PrecompileId::Custom(Cow::Borrowed("ArbSys"));
21
22pub fn is_arbitrum_chain(chain_id: u64) -> bool {
24 Chain::from_id(chain_id).is_arbitrum()
25}
26
27pub fn arb_block_number_output(block_number: u64) -> Bytes {
29 Bytes::copy_from_slice(&U256::from(block_number).to_be_bytes::<32>())
30}
31
32pub fn arb_block_number_call(gas_limit: u64, block_number: u64) -> Option<(u64, Bytes)> {
34 (gas_limit >= ARB_BLOCK_NUMBER_GAS_COST)
35 .then(|| (ARB_BLOCK_NUMBER_GAS_COST, arb_block_number_output(block_number)))
36}
37
38pub fn arb_sys_precompile(block_number: u64) -> DynPrecompile {
40 DynPrecompile::new_stateful(PRECOMPILE_ID_ARB_SYS.clone(), move |input| {
41 arb_sys_precompile_call(input, block_number)
42 })
43}
44
45fn arb_sys_precompile_call(input: PrecompileInput<'_>, block_number: u64) -> PrecompileResult {
46 if input.data.get(..4) != Some(&ARB_BLOCK_NUMBER_SELECTOR) {
47 return Ok(PrecompileOutput::halt(
48 PrecompileHalt::Other("unsupported ArbSys selector".into()),
49 input.reservoir,
50 ));
51 }
52
53 let Some((gas_cost, output)) = arb_block_number_call(input.gas, block_number) else {
54 return Ok(PrecompileOutput::halt(PrecompileHalt::OutOfGas, input.reservoir));
55 };
56
57 Ok(PrecompileOutput::new(gas_cost, output, input.reservoir))
58}