neo_devpack_solidity/neo/
contract_hash.rs1use ripemd::Ripemd160;
2use sha2::{Digest, Sha256};
3
4pub fn compute_contract_hash(sender_le: [u8; 20], nef_checksum: u32, name: &str) -> [u8; 20] {
18 let mut script = Vec::new();
19 script.push(0x38); emit_push_bytes(&mut script, &sender_le);
21 emit_push_u32(&mut script, nef_checksum);
22 emit_push_bytes(&mut script, name.as_bytes());
23 hash160(&script)
24}
25
26pub fn parse_uint160_hex_be(value: &str) -> Result<[u8; 20], String> {
30 let trimmed = value.trim();
31 let without_prefix = trimmed
32 .strip_prefix("0x")
33 .or_else(|| trimmed.strip_prefix("0X"))
34 .unwrap_or(trimmed);
35 if without_prefix.len() != 40 {
36 return Err(format!(
37 "expected 40 hex characters for UInt160 (got {})",
38 without_prefix.len()
39 ));
40 }
41 let bytes_be = hex::decode(without_prefix)
42 .map_err(|err| format!("invalid hex UInt160 '{value}': {err}"))?;
43 if bytes_be.len() != 20 {
44 return Err(format!(
45 "expected 20 bytes for UInt160 (got {})",
46 bytes_be.len()
47 ));
48 }
49 let mut le = [0u8; 20];
50 for (dst, src) in le.iter_mut().zip(bytes_be.into_iter().rev()) {
51 *dst = src;
52 }
53 Ok(le)
54}
55
56pub fn format_uint160_hex_be(value_le: &[u8; 20]) -> String {
58 let be: Vec<u8> = value_le.iter().rev().copied().collect();
59 format!("0x{}", hex::encode(be))
60}
61
62fn hash160(data: &[u8]) -> [u8; 20] {
63 let sha = Sha256::digest(data);
64 let digest = Ripemd160::digest(sha);
65 let mut out = [0u8; 20];
66 out.copy_from_slice(&digest[..20]);
67 out
68}
69
70fn emit_push_bytes(script: &mut Vec<u8>, data: &[u8]) {
71 if data.len() <= u8::MAX as usize {
72 script.push(0x0C); script.push(data.len() as u8);
74 } else if data.len() <= u16::MAX as usize {
75 script.push(0x0D); script.extend_from_slice(&(data.len() as u16).to_le_bytes());
77 } else {
78 script.push(0x0E); script.extend_from_slice(&(data.len() as u32).to_le_bytes());
80 }
81 script.extend_from_slice(data);
82}
83
84fn emit_push_u32(script: &mut Vec<u8>, value: u32) {
85 if value == 0 {
86 script.push(0x10); return;
88 }
89 if value <= 16 {
90 script.push(0x10 + value as u8);
91 return;
92 }
93 if value <= i8::MAX as u32 {
94 script.push(0x00); script.push(value as u8);
96 return;
97 }
98 if value <= i16::MAX as u32 {
99 script.push(0x01); script.extend_from_slice(&(value as i16).to_le_bytes());
101 return;
102 }
103 if value <= i32::MAX as u32 {
104 script.push(0x02); script.extend_from_slice(&(value as i32).to_le_bytes());
106 return;
107 }
108 script.push(0x03); script.extend_from_slice(&(value as i64).to_le_bytes());
110}