arb_precompiles/
arbfunctiontable.rs

1use std::sync::Arc;
2
3use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
4use alloy_primitives::{Address, U256};
5use alloy_sol_types::SolInterface;
6use arb_context::ArbPrecompileCtx;
7use revm::precompile::{PrecompileId, PrecompileOutput, PrecompileResult};
8
9use crate::{ArbPrecompileError, interfaces::IArbFunctionTable};
10
11/// ArbFunctionTable precompile address (0x68).
12pub const ARBFUNCTIONTABLE_ADDRESS: Address = Address::new([
13    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
14    0x00, 0x00, 0x00, 0x68,
15]);
16
17const COPY_GAS: u64 = 3;
18
19pub fn create_arbfunctiontable_precompile(ctx: Arc<ArbPrecompileCtx>) -> DynPrecompile {
20    DynPrecompile::new_stateful(PrecompileId::custom("arbfunctiontable"), move |input| {
21        handler(input, &ctx)
22    })
23}
24
25fn handler(input: PrecompileInput<'_>, ctx: &ArbPrecompileCtx) -> PrecompileResult {
26    let mut gas_used = 0u64;
27    let gas_limit = input.gas;
28    crate::init_precompile_gas(&mut gas_used, ctx, input.data.len());
29
30    let call = match IArbFunctionTable::ArbFunctionTableCalls::abi_decode(input.data) {
31        Ok(c) => c,
32        Err(_) => return crate::burn_all_revert(gas_limit),
33    };
34    if let Some(r) = crate::reject_nonpayable_value(input.value, input.data, gas_limit, &[]) {
35        return r;
36    }
37    if let Some(r) = crate::reject_static_write(
38        input.is_static,
39        input.data,
40        gas_limit,
41        &[[0xce, 0x2a, 0xe1, 0x59]],
42    ) {
43        return r;
44    }
45    if let Some(r) = crate::reject_delegate_nonpure(
46        input.target_address != input.bytecode_address,
47        input.data,
48        gas_limit,
49        &[],
50    ) {
51        return r;
52    }
53
54    use IArbFunctionTable::ArbFunctionTableCalls;
55    let result = match call {
56        // Upload: no-op. Cost = OpenArbosState + argsCost (pre-charged).
57        ArbFunctionTableCalls::upload(_) => Ok(PrecompileOutput::new(
58            gas_used.min(gas_limit),
59            vec![].into(),
60        )),
61        // Size: no-op returning 0. Cost = OpenArbosState + argsCost + 1-word resultCost.
62        ArbFunctionTableCalls::size(_) => {
63            crate::charge_computation(&mut gas_used, ctx, COPY_GAS);
64            Ok(PrecompileOutput::new(
65                gas_used.min(gas_limit),
66                U256::ZERO.to_be_bytes::<32>().to_vec().into(),
67            ))
68        }
69        // Get unconditionally reverts (table is empty). gas_check will return
70        // accumulated_gas (OpenArbosState + argsCost) on the revert path.
71        ArbFunctionTableCalls::get(_) => Err(ArbPrecompileError::empty_revert(gas_used).into()),
72    };
73    crate::gas_check(ctx, gas_limit, gas_used, result)
74}