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