foundry_common/
utils.rs

1//! Uncategorised utilities.
2
3use alloy_primitives::{keccak256, B256, U256};
4/// Block on a future using the current tokio runtime on the current thread.
5pub fn block_on<F: std::future::Future>(future: F) -> F::Output {
6    block_on_handle(&tokio::runtime::Handle::current(), future)
7}
8
9/// Block on a future using the current tokio runtime on the current thread with the given handle.
10pub fn block_on_handle<F: std::future::Future>(
11    handle: &tokio::runtime::Handle,
12    future: F,
13) -> F::Output {
14    tokio::task::block_in_place(|| handle.block_on(future))
15}
16
17/// Computes the storage slot as specified by `ERC-7201`, using the `erc7201` formula ID.
18///
19/// This is defined as:
20///
21/// ```text
22/// erc7201(id: string) = keccak256(keccak256(id) - 1) & ~0xff
23/// ```
24///
25/// # Examples
26///
27/// ```
28/// use alloy_primitives::b256;
29/// use foundry_common::erc7201;
30///
31/// assert_eq!(
32///     erc7201("example.main"),
33///     b256!("0x183a6125c38840424c4a85fa12bab2ab606c4b6d0e7cc73c0c06ba5300eab500"),
34/// );
35/// ```
36pub fn erc7201(id: &str) -> B256 {
37    let x = U256::from_be_bytes(keccak256(id).0) - U256::from(1);
38    keccak256(x.to_be_bytes::<32>()) & B256::from(!U256::from(0xff))
39}
40
41/// Utility function to ignore metadata hash of the given bytecode.
42/// This assumes that the metadata is at the end of the bytecode.
43pub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] {
44    // Get the last two bytes of the bytecode to find the length of CBOR metadata.
45    let Some((rest, metadata_len_bytes)) = bytecode.split_last_chunk() else { return bytecode };
46    let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize;
47    if metadata_len > rest.len() {
48        return bytecode;
49    }
50    let (rest, metadata) = rest.split_at(rest.len() - metadata_len);
51    if ciborium::from_reader::<ciborium::Value, _>(metadata).is_ok() {
52        rest
53    } else {
54        bytecode
55    }
56}