#[allow(missing_docs)]
mod generated {
include!("native_contracts_generated.rs");
}
pub use generated::NativeContractInfo;
#[allow(dead_code)]
const fn script_hash_lt(left: &[u8; 20], right: &[u8; 20]) -> bool {
let mut i = 0usize;
while i < 20 {
if left[i] < right[i] {
return true;
}
if left[i] > right[i] {
return false;
}
i += 1;
}
false
}
#[allow(dead_code)]
const fn assert_native_contracts_sorted_by_hash(contracts: &[NativeContractInfo]) {
let mut i = 1usize;
while i < contracts.len() {
assert!(
script_hash_lt(&contracts[i - 1].script_hash, &contracts[i].script_hash),
"generated::NATIVE_CONTRACTS must be sorted by script_hash (strictly increasing)"
);
i += 1;
}
}
const _: () = assert_native_contracts_sorted_by_hash(generated::NATIVE_CONTRACTS);
#[must_use]
pub fn lookup(hash: &[u8; 20]) -> Option<&'static NativeContractInfo> {
generated::NATIVE_CONTRACTS
.binary_search_by_key(hash, |info| info.script_hash)
.ok()
.map(|index| &generated::NATIVE_CONTRACTS[index])
}
#[must_use]
pub fn all() -> &'static [NativeContractInfo] {
generated::NATIVE_CONTRACTS
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct NativeMethodHint {
pub contract: &'static str,
pub canonical_method: Option<&'static str>,
}
impl NativeMethodHint {
#[must_use]
pub fn formatted_label(&self, provided: &str) -> String {
match self.canonical_method {
Some(method) => format!("{}::{method}", self.contract),
None => format!("{}::<unknown {provided}>", self.contract),
}
}
#[must_use]
pub fn has_exact_method(&self) -> bool {
self.canonical_method.is_some()
}
}
#[must_use]
pub fn describe_method_token(hash: &[u8; 20], method: &str) -> Option<NativeMethodHint> {
let contract = lookup(hash)?;
let canonical_method = contract
.methods
.iter()
.find(|candidate| **candidate == method)
.copied()
.or_else(|| {
contract
.methods
.iter()
.find(|candidate| candidate.eq_ignore_ascii_case(method))
.copied()
});
Some(NativeMethodHint {
contract: contract.name,
canonical_method,
})
}
#[cfg(test)]
mod tests;