multiversx_sc/storage/mappers/token/
token_attributes_mapper.rs1use core::marker::PhantomData;
2
3use crate::{
4 codec::{NestedDecode, NestedEncode, TopDecode, TopEncode},
5 storage::mappers::{
6 StorageMapperFromAddress,
7 source::{CurrentStorage, StorageAddress},
8 },
9 types::ManagedAddress,
10};
11
12use super::super::StorageMapper;
13use crate::{
14 api::{ErrorApiImpl, ManagedTypeApi, StorageMapperApi},
15 storage::{StorageKey, storage_clear, storage_get, storage_get_len, storage_set},
16 types::{EsdtTokenIdentifier, ManagedType},
17};
18
19const MAPPING_SUFFIX: &str = ".mapping";
20const COUNTER_SUFFIX: &str = ".counter";
21const ATTR_SUFFIX: &str = ".attr";
22const NONCE_SUFFIX: &str = ".nonce";
23
24const VALUE_ALREADY_SET_ERROR_MESSAGE: &str = "A value was already set";
25
26const UNKNOWN_TOKEN_ID_ERROR_MESSAGE: &str = "Unknown token id";
27
28const VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE: &str = "A value was not previously set";
29
30const COUNTER_OVERFLOW_ERROR_MESSAGE: &str =
31 "Counter overflow. This module can hold evidence for maximum u8::MAX different token IDs";
32
33pub struct TokenAttributesMapper<SA, A = CurrentStorage>
80where
81 SA: StorageMapperApi,
82{
83 _phantom_api: PhantomData<SA>,
84 base_key: StorageKey<SA>,
85 address: A,
86}
87
88impl<SA> StorageMapper<SA> for TokenAttributesMapper<SA, CurrentStorage>
89where
90 SA: StorageMapperApi,
91{
92 fn new(base_key: StorageKey<SA>) -> Self {
93 TokenAttributesMapper {
94 _phantom_api: PhantomData,
95 base_key,
96 address: CurrentStorage,
97 }
98 }
99}
100
101impl<SA> StorageMapperFromAddress<SA> for TokenAttributesMapper<SA, ManagedAddress<SA>>
102where
103 SA: StorageMapperApi,
104{
105 fn new_from_address(address: ManagedAddress<SA>, base_key: StorageKey<SA>) -> Self {
106 Self {
107 _phantom_api: PhantomData,
108 base_key,
109 address,
110 }
111 }
112}
113
114impl<SA> TokenAttributesMapper<SA, CurrentStorage>
115where
116 SA: StorageMapperApi,
117{
118 pub fn set<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
119 &self,
120 token_id: &EsdtTokenIdentifier<M>,
121 token_nonce: u64,
122 attributes: &T,
123 ) {
124 let has_mapping = self.has_mapping_value(token_id);
125
126 let mapping = if has_mapping {
127 self.get_mapping_value(token_id)
128 } else {
129 let mut counter = self.get_counter_value();
130 if counter == u8::MAX {
131 SA::error_api_impl().signal_error(COUNTER_OVERFLOW_ERROR_MESSAGE.as_bytes());
132 }
133
134 counter += 1;
135 self.set_mapping_value(token_id, counter);
136 self.set_counter_value(counter);
137 counter
138 };
139
140 let has_value = self.has_token_attributes_value(mapping, token_nonce);
141 if has_value {
142 SA::error_api_impl().signal_error(VALUE_ALREADY_SET_ERROR_MESSAGE.as_bytes());
143 }
144
145 self.set_token_attributes_value(mapping, token_nonce, attributes);
146 self.set_attributes_to_nonce_mapping(mapping, attributes, token_nonce);
147 }
148
149 pub fn update<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
151 &self,
152 token_id: &EsdtTokenIdentifier<M>,
153 token_nonce: u64,
154 attributes: &T,
155 ) {
156 let has_mapping = self.has_mapping_value(token_id);
157 if !has_mapping {
158 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE.as_bytes());
159 }
160
161 let mapping = self.get_mapping_value(token_id);
162 let has_value = self.has_token_attributes_value(mapping, token_nonce);
163 if !has_value {
164 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE.as_bytes());
165 }
166
167 let old_attr = self.get_token_attributes_value::<T>(mapping, token_nonce);
168 self.clear_attributes_to_nonce_mapping(mapping, &old_attr);
169
170 self.set_token_attributes_value(mapping, token_nonce, attributes);
171 self.set_attributes_to_nonce_mapping(mapping, attributes, token_nonce);
172 }
173
174 pub fn clear<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
175 &self,
176 token_id: &EsdtTokenIdentifier<M>,
177 token_nonce: u64,
178 ) {
179 let has_mapping = self.has_mapping_value(token_id);
180 if !has_mapping {
181 return;
182 }
183
184 let mapping = self.get_mapping_value(token_id);
185 let has_value = self.has_token_attributes_value(mapping, token_nonce);
186 if !has_value {
187 return;
188 }
189
190 let attr: T = self.get_token_attributes_value(mapping, token_nonce);
191 self.clear_token_attributes_value(mapping, token_nonce);
192 self.clear_attributes_to_nonce_mapping(mapping, &attr);
193 }
194
195 fn set_counter_value(&self, value: u8) {
196 storage_set(self.build_key_token_id_counter().as_ref(), &value);
197 }
198
199 fn set_mapping_value<M: ManagedTypeApi>(&self, token_id: &EsdtTokenIdentifier<M>, value: u8) {
200 storage_set(self.build_key_token_id_mapping(token_id).as_ref(), &value);
201 }
202
203 fn set_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
204 &self,
205 mapping: u8,
206 attr: &T,
207 token_nonce: u64,
208 ) {
209 storage_set(
210 self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref(),
211 &token_nonce,
212 );
213 }
214
215 fn clear_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
216 &self,
217 mapping: u8,
218 attr: &T,
219 ) {
220 storage_clear(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref());
221 }
222
223 fn set_token_attributes_value<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
224 &self,
225 mapping: u8,
226 token_nonce: u64,
227 value: &T,
228 ) {
229 storage_set(
230 self.build_key_token_attr_value(mapping, token_nonce)
231 .as_ref(),
232 value,
233 );
234 }
235
236 fn clear_token_attributes_value(&self, mapping: u8, token_nonce: u64) {
237 storage_clear(
238 self.build_key_token_attr_value(mapping, token_nonce)
239 .as_ref(),
240 );
241 }
242}
243
244impl<SA, A> TokenAttributesMapper<SA, A>
245where
246 SA: StorageMapperApi,
247 A: StorageAddress<SA>,
248{
249 pub fn has_attributes<M: ManagedTypeApi>(
250 &self,
251 token_id: &EsdtTokenIdentifier<M>,
252 token_nonce: u64,
253 ) -> bool {
254 let has_mapping = self.has_mapping_value(token_id);
255 if !has_mapping {
256 return true;
257 }
258
259 let mapping = self.get_mapping_value(token_id);
260 self.is_empty_token_attributes_value(mapping, token_nonce)
261 }
262
263 pub fn has_nonce<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
264 &self,
265 token_id: &EsdtTokenIdentifier<M>,
266 attr: &T,
267 ) -> bool {
268 let has_mapping = self.has_mapping_value(token_id);
269 if !has_mapping {
270 return true;
271 }
272
273 let mapping = self.get_mapping_value(token_id);
274 self.is_empty_attributes_to_nonce_mapping(mapping, attr)
275 }
276
277 pub fn get_attributes<
278 T: TopEncode + TopDecode + NestedEncode + NestedDecode,
279 M: ManagedTypeApi,
280 >(
281 &self,
282 token_id: &EsdtTokenIdentifier<M>,
283 token_nonce: u64,
284 ) -> T {
285 let has_mapping = self.has_mapping_value(token_id);
286 if !has_mapping {
287 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE.as_bytes());
288 }
289
290 let mapping = self.get_mapping_value(token_id);
291 let has_value = self.has_token_attributes_value(mapping, token_nonce);
292 if !has_value {
293 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE.as_bytes());
294 }
295
296 self.get_token_attributes_value(mapping, token_nonce)
297 }
298
299 pub fn get_nonce<T: TopEncode + TopDecode + NestedEncode + NestedDecode, M: ManagedTypeApi>(
300 &self,
301 token_id: &EsdtTokenIdentifier<M>,
302 attr: &T,
303 ) -> u64 {
304 let has_mapping = self.has_mapping_value(token_id);
305 if !has_mapping {
306 SA::error_api_impl().signal_error(UNKNOWN_TOKEN_ID_ERROR_MESSAGE.as_bytes());
307 }
308
309 let mapping = self.get_mapping_value(token_id);
310 let has_value = self.has_attr_to_nonce_mapping::<T>(mapping, attr);
311 if !has_value {
312 SA::error_api_impl().signal_error(VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE.as_bytes());
313 }
314
315 self.get_attributes_to_nonce_mapping(mapping, attr)
316 }
317
318 fn has_mapping_value<M: ManagedTypeApi>(&self, token_id: &EsdtTokenIdentifier<M>) -> bool {
319 !self.is_empty_mapping_value(token_id)
320 }
321
322 fn has_token_attributes_value(&self, mapping: u8, token_nonce: u64) -> bool {
323 !self.is_empty_token_attributes_value(mapping, token_nonce)
324 }
325
326 fn has_attr_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
327 &self,
328 mapping: u8,
329 attr: &T,
330 ) -> bool {
331 !self.is_empty_attributes_to_nonce_mapping(mapping, attr)
332 }
333
334 fn build_key_token_id_counter(&self) -> StorageKey<SA> {
335 let mut key = self.base_key.clone();
336 key.append_bytes(COUNTER_SUFFIX.as_bytes());
337 key
338 }
339
340 fn build_key_token_id_mapping<M: ManagedTypeApi>(
341 &self,
342 token_id: &EsdtTokenIdentifier<M>,
343 ) -> StorageKey<SA> {
344 let mut key = self.base_key.clone();
345 key.append_bytes(MAPPING_SUFFIX.as_bytes());
346 key.append_item(token_id);
347 key
348 }
349
350 fn build_key_token_attr_value(&self, mapping: u8, token_nonce: u64) -> StorageKey<SA> {
351 let mut key = self.base_key.clone();
352 key.append_bytes(ATTR_SUFFIX.as_bytes());
353 key.append_item(&mapping);
354 key.append_item(&token_nonce);
355 key
356 }
357
358 fn build_key_attr_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
359 &self,
360 mapping: u8,
361 attr: &T,
362 ) -> StorageKey<SA> {
363 let mut key = self.base_key.clone();
364 key.append_bytes(NONCE_SUFFIX.as_bytes());
365 key.append_item(&mapping);
366 key.append_item(attr);
367 key
368 }
369
370 fn get_counter_value(&self) -> u8 {
371 storage_get(self.build_key_token_id_counter().as_ref())
372 }
373
374 fn get_mapping_value<M: ManagedTypeApi>(&self, token_id: &EsdtTokenIdentifier<M>) -> u8 {
375 storage_get(self.build_key_token_id_mapping(token_id).as_ref())
376 }
377
378 fn is_empty_mapping_value<M: ManagedTypeApi>(&self, token_id: &EsdtTokenIdentifier<M>) -> bool {
379 storage_get_len(self.build_key_token_id_mapping(token_id).as_ref()) == 0
380 }
381
382 fn get_attributes_to_nonce_mapping<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
383 &self,
384 mapping: u8,
385 attr: &T,
386 ) -> u64 {
387 storage_get(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref())
388 }
389
390 fn is_empty_attributes_to_nonce_mapping<
391 T: TopEncode + TopDecode + NestedEncode + NestedDecode,
392 >(
393 &self,
394 mapping: u8,
395 attr: &T,
396 ) -> bool {
397 storage_get_len(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()) == 0
398 }
399
400 fn get_token_attributes_value<T: TopEncode + TopDecode + NestedEncode + NestedDecode>(
401 &self,
402 mapping: u8,
403 token_nonce: u64,
404 ) -> T {
405 storage_get(
406 self.build_key_token_attr_value(mapping, token_nonce)
407 .as_ref(),
408 )
409 }
410
411 fn is_empty_token_attributes_value(&self, mapping: u8, token_nonce: u64) -> bool {
412 storage_get_len(
413 self.build_key_token_attr_value(mapping, token_nonce)
414 .as_ref(),
415 ) == 0
416 }
417}