arb_storage/
slot.rs

1use alloy_primitives::{keccak256, U256};
2
3/// Computes a storage slot using the keccak256-based mapAddress algorithm.
4///
5/// The algorithm: hash(storage_key || key_bytes[0..31]) || key_bytes[31]
6/// This preserves the last byte and hashes only the first 31 bytes.
7pub fn storage_key_map(storage_key: &[u8], offset: u64) -> U256 {
8    const BOUNDARY: usize = 31;
9
10    let mut key_bytes = [0u8; 32];
11    key_bytes[24..32].copy_from_slice(&offset.to_be_bytes());
12
13    let mut data = Vec::with_capacity(storage_key.len() + BOUNDARY);
14    data.extend_from_slice(storage_key);
15    data.extend_from_slice(&key_bytes[..BOUNDARY]);
16    let h = keccak256(&data);
17
18    let mut mapped = [0u8; 32];
19    mapped[..BOUNDARY].copy_from_slice(&h.0[..BOUNDARY]);
20    mapped[BOUNDARY] = key_bytes[BOUNDARY];
21    U256::from_be_bytes(mapped)
22}
23
24/// Computes a storage slot for an arbitrary B256 key using the mapAddress algorithm.
25pub fn storage_key_map_b256(storage_key: &[u8], key: &[u8; 32]) -> U256 {
26    const BOUNDARY: usize = 31;
27
28    let mut data = Vec::with_capacity(storage_key.len() + BOUNDARY);
29    data.extend_from_slice(storage_key);
30    data.extend_from_slice(&key[..BOUNDARY]);
31    let h = keccak256(&data);
32
33    let mut mapped = [0u8; 32];
34    mapped[..BOUNDARY].copy_from_slice(&h.0[..BOUNDARY]);
35    mapped[BOUNDARY] = key[BOUNDARY];
36    U256::from_be_bytes(mapped)
37}