arb_precompiles/
arbinfo.rs1use alloy_evm::precompiles::{DynPrecompile, PrecompileInput};
2use alloy_primitives::{Address, U256};
3use alloy_sol_types::SolInterface;
4use revm::precompile::{PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult};
5
6use crate::interfaces::IArbInfo;
7
8pub const ARBINFO_ADDRESS: Address = Address::new([
10 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
11 0x00, 0x00, 0x00, 0x65,
12]);
13
14const COPY_GAS: u64 = 3;
15const SLOAD_GAS: u64 = 800;
16
17pub fn create_arbinfo_precompile() -> DynPrecompile {
18 DynPrecompile::new_stateful(PrecompileId::custom("arbinfo"), handler)
19}
20
21fn handler(mut input: PrecompileInput<'_>) -> PrecompileResult {
22 let gas_limit = input.gas;
23 crate::init_precompile_gas(input.data.len());
24
25 let call = match IArbInfo::ArbInfoCalls::abi_decode(input.data) {
26 Ok(c) => c,
27 Err(_) => return crate::burn_all_revert(gas_limit),
28 };
29
30 use IArbInfo::ArbInfoCalls;
31 let result = match call {
32 ArbInfoCalls::getBalance(c) => handle_get_balance(&mut input, c.account),
33 ArbInfoCalls::getCode(c) => handle_get_code(&mut input, c.account),
34 };
35 crate::gas_check(gas_limit, result)
36}
37
38fn handle_get_balance(input: &mut PrecompileInput<'_>, addr: Address) -> PrecompileResult {
39 let gas_limit = input.gas;
40 let internals = input.internals_mut();
41
42 let acct = internals
43 .load_account(addr)
44 .map_err(|e| PrecompileError::other(format!("load_account: {e:?}")))?;
45
46 let balance = acct.data.info.balance;
47 let gas_cost = (SLOAD_GAS + 3 + 700 + COPY_GAS).min(gas_limit);
49
50 Ok(PrecompileOutput::new(
51 gas_cost,
52 balance.to_be_bytes::<32>().to_vec().into(),
53 ))
54}
55
56fn handle_get_code(input: &mut PrecompileInput<'_>, addr: Address) -> PrecompileResult {
57 let gas_limit = input.gas;
58 let internals = input.internals_mut();
59
60 let acct = internals
61 .load_account_code(addr)
62 .map_err(|e| PrecompileError::other(format!("load_account: {e:?}")))?;
63
64 let code = acct
65 .data
66 .code()
67 .map(|c| c.original_bytes())
68 .unwrap_or_default();
69
70 let pad = (32 - code.len() % 32) % 32;
71 let mut out = Vec::with_capacity(64 + code.len() + pad);
72 out.extend_from_slice(&U256::from(32u64).to_be_bytes::<32>());
73 out.extend_from_slice(&U256::from(code.len()).to_be_bytes::<32>());
74 out.extend_from_slice(&code);
75 out.extend(std::iter::repeat_n(0u8, pad));
76
77 let code_words = (code.len() as u64).div_ceil(32);
79 let result_words = (out.len() as u64).div_ceil(32);
80 let gas_cost =
81 (SLOAD_GAS + 3 + 2100 + COPY_GAS * code_words + COPY_GAS * result_words).min(gas_limit);
82 Ok(PrecompileOutput::new(gas_cost, out.into()))
83}