use std::fmt; use std::str::FromStr; use near_sdk::near; use schemars::JsonSchema; use serde::de::{self, Visitor}; use serde::{Deserialize, Serialize}; #[near(serializers = [borsh])] #[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Default)] pub struct H256(pub [u8; 32]); impl From<[u8; 32]> for H256 { fn from(bytes: [u8; 32]) -> Self { H256(bytes) } } impl fmt::Display for H256 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let reversed: Vec = self.0.into_iter().rev().collect(); write!(f, "{}", hex::encode(reversed)) } } impl TryFrom> for H256 { type Error = &'static str; fn try_from(value: Vec) -> Result { Ok(H256(value.try_into().map_err(|_| "Invalid hex length")?)) } } impl TryFrom<&[u8]> for H256 { type Error = &'static str; fn try_from(value: &[u8]) -> Result { Ok(H256(value.try_into().map_err(|_| "Invalid hex length")?)) } } impl FromStr for H256 { type Err = hex::FromHexError; fn from_str(s: &str) -> Result { let mut result = [0; 32]; hex::decode_to_slice(s, &mut result)?; result.reverse(); Ok(H256(result)) } } impl<'de> Deserialize<'de> for H256 { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { struct HexVisitor; impl Visitor<'_> for HexVisitor { type Value = H256; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a hex string") } fn visit_str(self, s: &str) -> Result where E: de::Error, { let mut result = [0; 32]; hex::decode_to_slice(s, &mut result).map_err(de::Error::custom)?; result.reverse(); Ok(H256(result)) } } deserializer.deserialize_str(HexVisitor) } } impl Serialize for H256 { fn serialize( &self, serializer: S, ) -> Result<::Ok, ::Error> where S: serde::Serializer, { let reversed: Vec = self.0.into_iter().rev().collect(); serializer.serialize_str(&hex::encode(reversed)) } } impl JsonSchema for H256 { fn is_referenceable() -> bool { false } fn schema_name() -> String { String::schema_name() } fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema { String::json_schema(gen) } } #[must_use] pub fn double_sha256(input: &[u8]) -> H256 { #[cfg(target_arch = "wasm32")] { H256( near_sdk::env::sha256(&near_sdk::env::sha256(input)) .try_into() .unwrap(), ) } #[cfg(not(target_arch = "wasm32"))] { use sha2::{Digest, Sha256}; H256(Sha256::digest(Sha256::digest(input)).into()) } }