diff --git a/crates/madara/primitives/receipt/src/to_starknet_types.rs b/crates/madara/primitives/receipt/src/to_starknet_types.rs index caf980a76..503c66aac 100644 --- a/crates/madara/primitives/receipt/src/to_starknet_types.rs +++ b/crates/madara/primitives/receipt/src/to_starknet_types.rs @@ -1,3 +1,4 @@ +use primitive_types::H256; use starknet_types_core::felt::Felt; use crate::{ @@ -59,7 +60,9 @@ impl L1HandlerTransactionReceipt { finality_status: starknet_types_rpc::TxnFinalityStatus, ) -> starknet_types_rpc::L1HandlerTxnReceipt { starknet_types_rpc::L1HandlerTxnReceipt:: { - message_hash: self.message_hash.to_string(), + // We have to manually convert the H256 bytes to a hex hash as the + // impl of Display for H256 skips the middle bytes. + message_hash: hash_as_string(self.message_hash), common_receipt_properties: starknet_types_rpc::CommonReceiptProperties { actual_fee: self.actual_fee.into(), events: self.events.into_iter().map(starknet_types_rpc::Event::from).collect(), @@ -73,6 +76,23 @@ impl L1HandlerTransactionReceipt { } } +/// Gets the **full** string hex representation of an [H256]. +/// +/// This is necessary as the default implementation of [ToString] for [H256] +/// will keep only the first and last 2 bytes, eliding the rest with '...'. +fn hash_as_string(message_hash: H256) -> String { + use std::fmt::Write; + + // 32 bytes x 2 (1 hex char = 4 bits) + 2 (for 0x) + let mut acc = String::with_capacity(68); + acc.push_str("0x"); + + message_hash.as_fixed_bytes().iter().fold(acc, |mut acc, b| { + write!(&mut acc, "{b:02x}").expect("Pre-allocated"); + acc + }) +} + impl DeclareTransactionReceipt { pub fn to_starknet_types( self, @@ -201,3 +221,35 @@ impl From for starknet_types_rpc::ExecutionStatus { } } } + +#[cfg(test)] +mod test { + use primitive_types::H256; + + use crate::{to_starknet_types::hash_as_string, L1HandlerTransactionReceipt}; + + #[test] + fn test_hash_as_string() { + let mut hash = String::with_capacity(68); + hash.push_str("0x"); + hash.push_str(&"f".repeat(64)); + assert_eq!(hash_as_string(H256::from_slice(&[u8::MAX; 32])), hash); + } + + /// The default implementation of [ToString] for [H256] will keep only the + /// first and last 2 bytes, eliding the rest with '...'. This test makes + /// sure this is not the case and we are using [hash_as_string] instead. + #[test] + fn test_l1_tx_receipt_full_hash() { + let l1_transaction_receipt = + L1HandlerTransactionReceipt { message_hash: H256::from_slice(&[u8::MAX; 32]), ..Default::default() }; + let message_hash = + l1_transaction_receipt.to_starknet_types(starknet_types_rpc::TxnFinalityStatus::L1).message_hash; + + let mut hash = String::with_capacity(68); + hash.push_str("0x"); + hash.push_str(&"f".repeat(64)); + assert_eq!(message_hash, hash); + assert!(!message_hash.contains(".")); + } +}