arb_precompiles/
arbinfo.rs1use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
2use alloy_primitives::{Address, U256};
3use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};
4
5pub const ARBINFO_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, 0x65,
9]);
10
11const GET_BALANCE: [u8; 4] = [0xf8, 0xb2, 0xcb, 0x4f]; const GET_CODE: [u8; 4] = [0x7e, 0x10, 0x5c, 0xe2]; const COPY_GAS: u64 = 3;
16const SLOAD_GAS: u64 = 800;
17
18pub fn create_arbinfo_precompile() -> DynPrecompile {
19 DynPrecompile::new_stateful(PrecompileId::custom("arbinfo"), handler)
20}
21
22fn handler(mut input: PrecompileInput<'_>) -> PrecompileResult {
23 let gas_limit = input.gas;
24 let data = input.data;
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 GET_BALANCE => handle_get_balance(&mut input),
33 GET_CODE => handle_get_code(&mut input),
34 _ => Err(PrecompileError::other("unknown ArbInfo selector")),
35 };
36 crate::gas_check(gas_limit, result)
37}
38
39fn handle_get_balance(input: &mut PrecompileInput<'_>) -> PrecompileResult {
40 let data = input.data;
41 if data.len() < 36 {
42 return Err(PrecompileError::other("input too short"));
43 }
44
45 let addr = Address::from_slice(&data[16..36]);
46 let gas_limit = input.gas;
47 let internals = input.internals_mut();
48
49 let acct = internals
50 .load_account(addr)
51 .map_err(|e| PrecompileError::other(format!("load_account: {e:?}")))?;
52
53 let balance = acct.data.info.balance;
54 let gas_cost = (SLOAD_GAS + 3 + 700 + COPY_GAS).min(gas_limit);
56
57 Ok(PrecompileOutput::new(
58 gas_cost,
59 balance.to_be_bytes::<32>().to_vec().into(),
60 ))
61}
62
63fn handle_get_code(input: &mut PrecompileInput<'_>) -> PrecompileResult {
64 let data = input.data;
65 if data.len() < 36 {
66 return Err(PrecompileError::other("input too short"));
67 }
68
69 let addr = Address::from_slice(&data[16..36]);
70 let gas_limit = input.gas;
71 let internals = input.internals_mut();
72
73 let acct = internals
74 .load_account_code(addr)
75 .map_err(|e| PrecompileError::other(format!("load_account: {e:?}")))?;
76
77 let code = acct
78 .data
79 .code()
80 .map(|c| c.original_bytes())
81 .unwrap_or_default();
82
83 let pad = (32 - code.len() % 32) % 32;
85 let mut out = Vec::with_capacity(64 + code.len() + pad);
86 out.extend_from_slice(&U256::from(32u64).to_be_bytes::<32>());
87 out.extend_from_slice(&U256::from(code.len()).to_be_bytes::<32>());
88 out.extend_from_slice(&code);
89 out.extend(std::iter::repeat_n(0u8, pad));
90
91 let code_words = (code.len() as u64).div_ceil(32);
94 let result_words = (out.len() as u64).div_ceil(32);
95 let gas_cost =
96 (SLOAD_GAS + 3 + 2100 + COPY_GAS * code_words + COPY_GAS * result_words).min(gas_limit);
97 Ok(PrecompileOutput::new(gas_cost, out.into()))
98}