neo_solidity/
storage_key.rs1use num_bigint::BigInt;
20use num_traits::Signed;
21use sha2::{Digest, Sha256};
22
23#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum KeyFragment {
26 Integer {
27 value: BigInt,
28 bits: u16,
29 signed: bool,
30 },
31 Boolean(bool),
32 Address(Vec<u8>),
33 Bytes(Vec<u8>),
34 String(String),
35}
36
37impl KeyFragment {
38 pub fn integer(value: BigInt, bits: u16, signed: bool) -> Self {
40 Self::Integer {
41 value,
42 bits,
43 signed,
44 }
45 }
46
47 pub fn boolean(value: bool) -> Self {
49 Self::Boolean(value)
50 }
51
52 pub fn address(bytes: impl Into<Vec<u8>>) -> Self {
54 Self::Address(bytes.into())
55 }
56
57 pub fn bytes(bytes: impl Into<Vec<u8>>) -> Self {
59 Self::Bytes(bytes.into())
60 }
61
62 pub fn string(value: impl Into<String>) -> Self {
64 Self::String(value.into())
65 }
66
67 pub fn uint256(value: BigInt) -> Self {
69 Self::Integer {
70 value,
71 bits: 256,
72 signed: false,
73 }
74 }
75
76 pub fn int256(value: BigInt) -> Self {
78 Self::Integer {
79 value,
80 bits: 256,
81 signed: true,
82 }
83 }
84
85 pub fn type_name(&self) -> &'static str {
87 match self {
88 Self::Integer { signed: true, .. } => "int",
89 Self::Integer { signed: false, .. } => "uint",
90 Self::Boolean(_) => "bool",
91 Self::Address(_) => "address",
92 Self::Bytes(_) => "bytes",
93 Self::String(_) => "string",
94 }
95 }
96}
97
98pub fn compute_state_slot(name: &str) -> [u8; 32] {
102 let mut hasher = Sha256::new();
103 hasher.update(name.as_bytes());
104 let digest = hasher.finalize();
105 let mut out = [0u8; 32];
106 out.copy_from_slice(&digest);
107 out
108}
109
110pub fn derive_mapping_slot(base_slot: &[u8], fragments: &[KeyFragment]) -> [u8; 32] {
115 let mut buffer = Vec::new();
116 for fragment in fragments {
117 let encoded = encode_fragment(fragment);
118 buffer.extend_from_slice(&(encoded.len() as u32).to_le_bytes());
119 buffer.extend_from_slice(&encoded);
120 }
121 buffer.extend_from_slice(base_slot);
122
123 let digest = Sha256::digest(buffer);
124 let mut out = [0u8; 32];
125 out.copy_from_slice(&digest);
126 out
127}
128
129fn encode_fragment(fragment: &KeyFragment) -> Vec<u8> {
130 match fragment {
131 KeyFragment::Integer {
132 value,
133 bits,
134 signed,
135 } => encode_integer(value, *bits, *signed),
136 KeyFragment::Boolean(value) => vec![if *value { 1 } else { 0 }],
137 KeyFragment::Address(bytes) => bytes.clone(),
138 KeyFragment::Bytes(bytes) => bytes.clone(),
139 KeyFragment::String(value) => value.as_bytes().to_vec(),
140 }
141}
142
143fn encode_integer(value: &BigInt, bits: u16, signed: bool) -> Vec<u8> {
144 let min_bytes = (bits.max(8) as usize).div_ceil(8);
145 if signed {
146 let mut raw = value.to_signed_bytes_be();
147 let needs_negative_padding = value.is_negative();
148 let pad_byte = if needs_negative_padding { 0xFF } else { 0x00 };
149 if raw.len() < min_bytes {
150 let mut padded = vec![pad_byte; min_bytes];
151 padded[min_bytes - raw.len()..].copy_from_slice(&raw);
152 raw = padded;
153 }
154 raw
155 } else {
156 let (_, mut raw) = value.to_bytes_be();
157 let pad_byte = 0x00;
158 if raw.len() < min_bytes {
159 let mut padded = vec![pad_byte; min_bytes];
160 padded[min_bytes - raw.len()..].copy_from_slice(&raw);
161 raw = padded;
162 }
163 raw
164 }
165}
166
167#[cfg(test)]
168mod tests;