arb_precompiles/
arbfunctiontable.rs

1use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
2use alloy_primitives::{Address, U256};
3use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};
4
5/// ArbFunctionTable precompile address (0x68).
6pub const ARBFUNCTIONTABLE_ADDRESS: Address = Address::new([
7    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
8    0x00, 0x00, 0x00, 0x68,
9]);
10
11const UPLOAD: [u8; 4] = [0x88, 0x3c, 0x9d, 0x6b]; // upload(bytes)
12const SIZE: [u8; 4] = [0x17, 0x24, 0x56, 0x7f]; // size(address)
13const GET: [u8; 4] = [0xa0, 0x69, 0xee, 0x85]; // get(address,uint256)
14
15const COPY_GAS: u64 = 3;
16
17pub fn create_arbfunctiontable_precompile() -> DynPrecompile {
18    DynPrecompile::new_stateful(PrecompileId::custom("arbfunctiontable"), handler)
19}
20
21fn handler(input: PrecompileInput<'_>) -> PrecompileResult {
22    let gas_limit = input.gas;
23    let data = input.data;
24
25    if data.len() < 4 {
26        return Err(PrecompileError::other("input too short"));
27    }
28
29    let selector: [u8; 4] = [data[0], data[1], data[2], data[3]];
30
31    let result = match selector {
32        UPLOAD => {
33            // No-op, returns empty.
34            let gas_cost = COPY_GAS.min(gas_limit);
35            Ok(PrecompileOutput::new(gas_cost, vec![].into()))
36        }
37        SIZE => {
38            // Returns 0.
39            let gas_cost = COPY_GAS.min(gas_limit);
40            Ok(PrecompileOutput::new(
41                gas_cost,
42                U256::ZERO.to_be_bytes::<32>().to_vec().into(),
43            ))
44        }
45        GET => Err(PrecompileError::other("table is empty")),
46        _ => Err(PrecompileError::other("unknown ArbFunctionTable selector")),
47    };
48    crate::gas_check(gas_limit, result)
49}