1use alloy_primitives::{B256, Bytes, U256, hex, keccak256};
4use foundry_compilers::artifacts::BytecodeObject;
5use regex::Regex;
6use std::sync::LazyLock;
7
8static BYTECODE_PLACEHOLDER_RE: LazyLock<Regex> =
9 LazyLock::new(|| Regex::new(r"__\$.{34}\$__").expect("invalid regex"));
10
11pub fn block_on<F: std::future::Future>(future: F) -> F::Output {
13 block_on_handle(&tokio::runtime::Handle::current(), future)
14}
15
16pub fn block_on_handle<F: std::future::Future>(
18 handle: &tokio::runtime::Handle,
19 future: F,
20) -> F::Output {
21 tokio::task::block_in_place(|| handle.block_on(future))
22}
23
24pub fn erc7201(id: &str) -> B256 {
44 let x = U256::from_be_bytes(keccak256(id).0) - U256::from(1);
45 keccak256(x.to_be_bytes::<32>()) & B256::from(!U256::from(0xff))
46}
47
48pub fn find_metadata_start(bytecode: &[u8]) -> Option<usize> {
51 let (rest, metadata_len_bytes) = bytecode.split_last_chunk()?;
53 let metadata_len = u16::from_be_bytes(*metadata_len_bytes) as usize;
54 if metadata_len > rest.len() {
55 return None;
56 }
57 ciborium::from_reader::<ciborium::Value, _>(&rest[rest.len() - metadata_len..])
58 .is_ok()
59 .then(|| rest.len() - metadata_len)
60}
61
62pub fn ignore_metadata_hash(bytecode: &[u8]) -> &[u8] {
65 if let Some(metadata) = find_metadata_start(bytecode) {
66 &bytecode[..metadata]
67 } else {
68 bytecode
69 }
70}
71
72pub fn strip_bytecode_placeholders(bytecode: &BytecodeObject) -> Option<Bytes> {
77 match &bytecode {
78 BytecodeObject::Bytecode(bytes) => Some(bytes.clone()),
79 BytecodeObject::Unlinked(s) => {
80 let s = (*BYTECODE_PLACEHOLDER_RE).replace_all(s, "00".repeat(40));
82 let bytes = hex::decode(s.as_bytes());
83 Some(bytes.ok()?.into())
84 }
85 }
86}