Skip to main content

multiversx_sc/contract_base/wrappers/
blockchain_wrapper.rs

1use core::marker::PhantomData;
2
3use multiversx_chain_core::{
4    EGLD_000000_TOKEN_IDENTIFIER,
5    types::{DurationMillis, TimestampMillis, TimestampSeconds},
6};
7
8use crate::{
9    api::{
10        BigIntApiImpl, BlockchainApi, BlockchainApiImpl, ErrorApi, ErrorApiImpl, HandleConstraints,
11        ManagedBufferApiImpl, ManagedTypeApi, ManagedTypeApiImpl, StaticVarApiImpl, StorageReadApi,
12        StorageReadApiImpl, const_handles, use_raw_handle,
13    },
14    codec::TopDecode,
15    err_msg::{ONLY_OWNER_CALLER, ONLY_USER_ACCOUNT_CALLER},
16    storage,
17    types::{
18        BackTransfers, BackTransfersLegacy, BigUint, CodeMetadata, EgldOrEsdtTokenIdentifier,
19        EgldOrEsdtTokenPayment, EsdtLocalRoleFlags, EsdtTokenData, EsdtTokenIdentifier,
20        EsdtTokenType, ManagedAddress, ManagedBuffer, ManagedByteArray, ManagedRef, ManagedRefMut,
21        ManagedType, ManagedVec, SystemSCAddress, TokenId,
22    },
23};
24
25/// Interface to be used by the actual smart contract code.
26///
27/// Note: contracts and the api are not mutable.
28/// They simply pass on/retrieve data to/from the protocol.
29/// When mocking the blockchain state, we use the Rc/RefCell pattern
30/// to isolate mock state mutability from the contract interface.
31#[derive(Default)]
32pub struct BlockchainWrapper<A>
33where
34    A: ManagedTypeApi + ErrorApi,
35{
36    _phantom: PhantomData<A>,
37}
38
39impl<A> BlockchainWrapper<A>
40where
41    A: ManagedTypeApi + ErrorApi,
42{
43    pub fn new() -> Self {
44        BlockchainWrapper {
45            _phantom: PhantomData,
46        }
47    }
48}
49
50impl<A> BlockchainWrapper<A>
51where
52    A: BlockchainApi + ManagedTypeApi + ErrorApi,
53{
54    #[deprecated(since = "0.41.0", note = "Please use method `get_caller` instead.")]
55    #[cfg(feature = "alloc")]
56    #[inline]
57    pub fn get_caller_legacy(&self) -> crate::types::Address {
58        A::blockchain_api_impl().get_caller_legacy()
59    }
60
61    #[inline]
62    pub fn get_caller(&self) -> ManagedAddress<A> {
63        unsafe {
64            let result = ManagedAddress::new_uninit();
65            A::blockchain_api_impl().load_caller_managed(result.get_handle());
66            result
67        }
68    }
69
70    #[deprecated(since = "0.41.0", note = "Please use method `get_sc_address` instead.")]
71    #[cfg(feature = "alloc")]
72    #[inline]
73    pub fn get_sc_address_legacy(&self) -> crate::types::Address {
74        A::blockchain_api_impl().get_sc_address_legacy()
75    }
76
77    #[inline]
78    pub fn get_sc_address(&self) -> ManagedAddress<A> {
79        unsafe {
80            let result = ManagedAddress::new_uninit();
81            A::blockchain_api_impl().load_sc_address_managed(result.get_handle());
82            result
83        }
84    }
85
86    #[inline]
87    pub fn get_owner_address(&self) -> ManagedAddress<A> {
88        unsafe {
89            let result = ManagedAddress::new_uninit();
90            A::blockchain_api_impl().load_owner_address_managed(result.get_handle());
91            result
92        }
93    }
94
95    pub fn check_caller_is_owner(&self) {
96        if self.get_owner_address() != self.get_caller() {
97            A::error_api_impl().signal_error(ONLY_OWNER_CALLER.as_bytes());
98        }
99    }
100
101    pub fn check_caller_is_user_account(&self) {
102        let mbuf_temp_1: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
103        A::blockchain_api_impl().load_caller_managed(mbuf_temp_1.clone());
104        if A::blockchain_api_impl().is_smart_contract(mbuf_temp_1) {
105            A::error_api_impl().signal_error(ONLY_USER_ACCOUNT_CALLER.as_bytes());
106        }
107    }
108
109    #[deprecated(
110        since = "0.41.0",
111        note = "Please use method `get_shard_of_address` instead."
112    )]
113    #[cfg(feature = "alloc")]
114    #[inline]
115    pub fn get_shard_of_address_legacy(&self, address: &crate::types::Address) -> u32 {
116        A::blockchain_api_impl().get_shard_of_address_legacy(address)
117    }
118
119    #[inline]
120    pub fn get_shard_of_address(&self, address: &ManagedAddress<A>) -> u32 {
121        A::blockchain_api_impl().get_shard_of_address(address.get_handle())
122    }
123
124    #[deprecated(
125        since = "0.41.0",
126        note = "Please use method `is_smart_contract` instead."
127    )]
128    #[cfg(feature = "alloc")]
129    #[inline]
130    pub fn is_smart_contract_legacy(&self, address: &crate::types::Address) -> bool {
131        A::blockchain_api_impl().is_smart_contract_legacy(address)
132    }
133
134    #[inline]
135    pub fn is_smart_contract(&self, address: &ManagedAddress<A>) -> bool {
136        A::blockchain_api_impl().is_smart_contract(address.get_handle())
137    }
138
139    #[deprecated(since = "0.41.0", note = "Please use method `get_balance` instead.")]
140    #[cfg(feature = "alloc")]
141    #[inline]
142    pub fn get_balance_legacy(&self, address: &crate::types::Address) -> BigUint<A> {
143        unsafe {
144            let result = BigUint::new_uninit();
145            A::blockchain_api_impl().load_balance_legacy(result.get_handle(), address);
146            result
147        }
148    }
149
150    #[inline]
151    pub fn get_balance(&self, address: &ManagedAddress<A>) -> BigUint<A> {
152        unsafe {
153            let result = BigUint::new_uninit();
154            A::blockchain_api_impl().load_balance(result.get_handle(), address.get_handle());
155            result
156        }
157    }
158
159    pub fn get_code_metadata(&self, address: &ManagedAddress<A>) -> CodeMetadata {
160        let mbuf_temp_1: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
161        A::blockchain_api_impl()
162            .managed_get_code_metadata(address.get_handle(), mbuf_temp_1.clone());
163        let mut buffer = [0u8; 2];
164        unsafe {
165            ManagedRefMut::<'static, A, ManagedBuffer<A>>::wrap_handle(mbuf_temp_1)
166                .load_to_byte_array(&mut buffer);
167        }
168        CodeMetadata::from(buffer)
169    }
170
171    pub fn get_code_hash(&self, address: &ManagedAddress<A>) -> ManagedBuffer<A> {
172        unsafe {
173            let result = ManagedBuffer::new_uninit();
174            A::blockchain_api_impl()
175                .managed_get_code_hash(address.get_handle(), result.get_handle());
176            result
177        }
178    }
179
180    #[inline]
181    pub fn is_builtin_function(&self, function_name: &ManagedBuffer<A>) -> bool {
182        A::blockchain_api_impl().managed_is_builtin_function(function_name.get_handle())
183    }
184
185    #[inline]
186    pub fn get_sc_balance(&self, token_id: impl AsRef<TokenId<A>>, nonce: u64) -> BigUint<A> {
187        let token_id_ref = token_id.as_ref();
188        if self.is_native_token(token_id_ref) {
189            self.get_balance(&self.get_sc_address())
190        } else {
191            self.get_esdt_balance(
192                &self.get_sc_address(),
193                unsafe { token_id_ref.as_esdt_unchecked() },
194                nonce,
195            )
196        }
197    }
198
199    #[deprecated(
200        since = "0.41.0",
201        note = "Please use method `get_state_root_hash` instead."
202    )]
203    #[cfg(feature = "alloc")]
204    #[inline]
205    pub fn get_state_root_hash_legacy(&self) -> crate::types::H256 {
206        self.get_state_root_hash().to_byte_array().into()
207    }
208
209    #[inline]
210    pub fn get_state_root_hash(&self) -> ManagedByteArray<A, 32> {
211        unsafe {
212            let result = ManagedByteArray::new_uninit();
213            A::blockchain_api_impl().load_state_root_hash_managed(result.get_handle());
214            result
215        }
216    }
217
218    #[deprecated(since = "0.41.0", note = "Please use method `get_tx_hash` instead.")]
219    #[cfg(feature = "alloc")]
220    #[inline]
221    pub fn get_tx_hash_legacy(&self) -> crate::types::H256 {
222        A::blockchain_api_impl().get_tx_hash_legacy()
223    }
224
225    #[inline]
226    pub fn get_tx_hash(&self) -> ManagedByteArray<A, 32> {
227        unsafe {
228            let result = ManagedByteArray::new_uninit();
229            A::blockchain_api_impl().load_tx_hash_managed(result.get_handle());
230            result
231        }
232    }
233
234    #[inline]
235    pub fn get_gas_left(&self) -> u64 {
236        A::blockchain_api_impl().get_gas_left()
237    }
238
239    /// Block timestamp, in seconds.
240    #[deprecated(
241        since = "0.63.0",
242        note = "Use get_block_timestamp_seconds instead, it returns a properly typed timestamps"
243    )]
244    #[inline]
245    pub fn get_block_timestamp(&self) -> u64 {
246        A::blockchain_api_impl().get_block_timestamp()
247    }
248
249    /// Block timestamp, in seconds.
250    #[inline]
251    pub fn get_block_timestamp_seconds(&self) -> TimestampSeconds {
252        TimestampSeconds::new(A::blockchain_api_impl().get_block_timestamp())
253    }
254
255    /// Block timestamp, in milliseconds.
256    #[deprecated(
257        since = "0.63.0",
258        note = "Use get_block_timestamp_millis instead, it returns a properly typed timestamps"
259    )]
260    pub fn get_block_timestamp_ms(&self) -> u64 {
261        A::blockchain_api_impl().get_block_timestamp_ms()
262    }
263
264    /// Block timestamp, in milliseconds.
265    pub fn get_block_timestamp_millis(&self) -> TimestampMillis {
266        TimestampMillis::new(A::blockchain_api_impl().get_block_timestamp_ms())
267    }
268
269    #[inline]
270    pub fn get_block_nonce(&self) -> u64 {
271        A::blockchain_api_impl().get_block_nonce()
272    }
273
274    #[inline]
275    pub fn get_block_round(&self) -> u64 {
276        A::blockchain_api_impl().get_block_round()
277    }
278
279    #[inline]
280    pub fn get_block_epoch(&self) -> u64 {
281        A::blockchain_api_impl().get_block_epoch()
282    }
283
284    /// Block round time, in milliseconds.
285    #[deprecated(
286        since = "0.63.0",
287        note = "Use get_block_round_time_millis instead, it returns a properly typed duration"
288    )]
289    #[inline]
290    pub fn get_block_round_time_ms(&self) -> u64 {
291        A::blockchain_api_impl().get_block_round_time_ms()
292    }
293
294    /// Block round time, in milliseconds.
295    #[inline]
296    pub fn get_block_round_time_millis(&self) -> DurationMillis {
297        DurationMillis::new(A::blockchain_api_impl().get_block_round_time_ms())
298    }
299
300    /// Epoch start block timestamp, in milliseconds.
301    #[deprecated(
302        since = "0.63.0",
303        note = "Use epoch_start_block_timestamp_millis instead, it returns a properly typed timestamps"
304    )]
305    pub fn epoch_start_block_timestamp_ms(&self) -> u64 {
306        self.get_epoch_start_block_timestamp_millis()
307            .as_u64_millis()
308    }
309
310    #[deprecated(
311        since = "0.63.1",
312        note = "Renamed to get_epoch_start_block_timestamp_millis"
313    )]
314    pub fn epoch_start_block_timestamp_millis(&self) -> TimestampMillis {
315        self.get_epoch_start_block_timestamp_millis()
316    }
317
318    /// Epoch start block timestamp, in milliseconds.
319    pub fn get_epoch_start_block_timestamp_millis(&self) -> TimestampMillis {
320        TimestampMillis::new(A::blockchain_api_impl().epoch_start_block_timestamp_ms())
321    }
322
323    pub fn get_epoch_start_block_nonce(&self) -> u64 {
324        A::blockchain_api_impl().epoch_start_block_nonce()
325    }
326
327    #[deprecated(since = "0.63.1", note = "Renamed to get_epoch_start_block_nonce")]
328    pub fn epoch_start_block_nonce(&self) -> u64 {
329        self.get_epoch_start_block_nonce()
330    }
331
332    pub fn get_epoch_start_block_round(&self) -> u64 {
333        A::blockchain_api_impl().epoch_start_block_round()
334    }
335
336    #[deprecated(since = "0.63.1", note = "Renamed to get_epoch_start_block_round")]
337    pub fn epoch_start_block_round(&self) -> u64 {
338        self.get_epoch_start_block_round()
339    }
340
341    #[deprecated(
342        since = "0.41.0",
343        note = "Please use method `get_block_random_seed` instead."
344    )]
345    #[cfg(feature = "alloc")]
346    #[inline]
347    pub fn get_block_random_seed_legacy(&self) -> crate::types::Box<[u8; 48]> {
348        crate::types::Box::new(self.get_block_random_seed().to_byte_array())
349    }
350
351    #[inline]
352    pub fn get_block_random_seed(&self) -> ManagedByteArray<A, 48> {
353        unsafe {
354            let result = ManagedByteArray::new_uninit();
355            A::blockchain_api_impl().load_block_random_seed_managed(result.get_handle());
356            result
357        }
358    }
359
360    /// Previous block timestamp, in seconds.
361    #[deprecated(
362        since = "0.63.0",
363        note = "Use get_prev_block_timestamp_seconds instead, it returns a properly typed timestamps"
364    )]
365    #[inline]
366    pub fn get_prev_block_timestamp(&self) -> u64 {
367        A::blockchain_api_impl().get_prev_block_timestamp()
368    }
369
370    /// Previous block timestamp, in seconds.
371    pub fn get_prev_block_timestamp_seconds(&self) -> TimestampSeconds {
372        TimestampSeconds::new(A::blockchain_api_impl().get_prev_block_timestamp())
373    }
374
375    /// Previous block timestamp, in milliseconds.
376    #[deprecated(
377        since = "0.63.0",
378        note = "Use get_prev_block_timestamp_millis instead, it returns a properly typed timestamps"
379    )]
380    #[inline]
381    pub fn get_prev_block_timestamp_ms(&self) -> u64 {
382        A::blockchain_api_impl().get_prev_block_timestamp_ms()
383    }
384
385    /// Previous block timestamp, in milliseconds.
386    #[inline]
387    pub fn get_prev_block_timestamp_millis(&self) -> TimestampMillis {
388        TimestampMillis::new(A::blockchain_api_impl().get_prev_block_timestamp_ms())
389    }
390
391    /// Previous block nonce.
392    #[inline]
393    pub fn get_prev_block_nonce(&self) -> u64 {
394        A::blockchain_api_impl().get_prev_block_nonce()
395    }
396
397    /// Previous block round.
398    #[inline]
399    pub fn get_prev_block_round(&self) -> u64 {
400        A::blockchain_api_impl().get_prev_block_round()
401    }
402
403    #[inline]
404    pub fn get_prev_block_epoch(&self) -> u64 {
405        A::blockchain_api_impl().get_prev_block_epoch()
406    }
407
408    #[deprecated(
409        since = "0.41.0",
410        note = "Please use method `get_prev_block_random_seed` instead."
411    )]
412    #[cfg(feature = "alloc")]
413    #[inline]
414    pub fn get_prev_block_random_seed_legacy(&self) -> crate::types::Box<[u8; 48]> {
415        A::blockchain_api_impl().get_prev_block_random_seed_legacy()
416    }
417
418    #[inline]
419    pub fn get_prev_block_random_seed(&self) -> ManagedByteArray<A, 48> {
420        unsafe {
421            let result = ManagedByteArray::new_uninit();
422            A::blockchain_api_impl().load_prev_block_random_seed_managed(result.get_handle());
423            result
424        }
425    }
426
427    #[inline]
428    pub fn get_current_esdt_nft_nonce(
429        &self,
430        address: &ManagedAddress<A>,
431        token_id: &EsdtTokenIdentifier<A>,
432    ) -> u64 {
433        A::blockchain_api_impl()
434            .get_current_esdt_nft_nonce(address.get_handle(), token_id.get_handle())
435    }
436
437    #[inline]
438    pub fn get_esdt_balance(
439        &self,
440        address: &ManagedAddress<A>,
441        token_id: &EsdtTokenIdentifier<A>,
442        nonce: u64,
443    ) -> BigUint<A> {
444        unsafe {
445            let result = BigUint::new_uninit();
446            A::blockchain_api_impl().load_esdt_balance(
447                address.get_handle(),
448                token_id.get_handle(),
449                nonce,
450                result.get_handle(),
451            );
452            result
453        }
454    }
455}
456
457impl<A> BlockchainWrapper<A>
458where
459    A: ManagedTypeApi + ErrorApi,
460{
461    pub(crate) fn get_native_token_handle(&self) -> A::ManagedBufferHandle {
462        let handle: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_EGLD_000000);
463        A::managed_type_impl()
464            .mb_overwrite(handle.clone(), EGLD_000000_TOKEN_IDENTIFIER.as_bytes());
465        handle
466    }
467
468    /// The native token of the given chain. It can currently only return `EGLD-000000`.
469    pub fn get_native_token(&self) -> ManagedRef<'static, A, TokenId<A>> {
470        let handle = self.get_native_token_handle();
471        unsafe { ManagedRef::wrap_handle(handle) }
472    }
473
474    /// Checks if a token is the native one on the chain. Currently only returns true for `EGLD-000000`.
475    pub fn is_native_token(&self, token_id: &TokenId<A>) -> bool {
476        let handle = self.get_native_token_handle();
477        A::managed_type_impl().mb_eq(handle, token_id.buffer.handle.clone())
478    }
479}
480
481impl<A> BlockchainWrapper<A>
482where
483    A: BlockchainApi + ManagedTypeApi + ErrorApi,
484{
485    fn get_esdt_token_type_raw(
486        &self,
487        address: &ManagedAddress<A>,
488        token_id: &EgldOrEsdtTokenIdentifier<A>,
489        nonce: u64,
490    ) -> u64 {
491        unsafe {
492            let big_int_temp_handle: A::BigIntHandle =
493                use_raw_handle(const_handles::BIG_INT_TEMPORARY_1);
494
495            A::blockchain_api_impl().managed_get_esdt_token_type(
496                address.get_handle(),
497                token_id.get_handle(),
498                nonce,
499                big_int_temp_handle.clone(),
500            );
501
502            let bu = ManagedRef::<A, BigUint<A>>::wrap_handle(big_int_temp_handle);
503            bu.to_u64().unwrap_or(255)
504        }
505    }
506
507    pub fn get_esdt_token_type(
508        &self,
509        address: &ManagedAddress<A>,
510        token_id: &EgldOrEsdtTokenIdentifier<A>,
511        nonce: u64,
512    ) -> EsdtTokenType {
513        EsdtTokenType::from(self.get_esdt_token_type_raw(address, token_id, nonce) as u8)
514    }
515
516    pub fn get_esdt_token_data(
517        &self,
518        address: &ManagedAddress<A>,
519        token_id: &EsdtTokenIdentifier<A>,
520        nonce: u64,
521    ) -> EsdtTokenData<A> {
522        // initializing outputs
523        // the current version of VM does not set/overwrite them if the token is missing,
524        // which is why we need to initialize them explicitly
525        let managed_api_impl = A::managed_type_impl();
526        let value_handle = managed_api_impl.bi_new_zero();
527        let properties_handle = managed_api_impl.mb_new_empty(); // TODO: replace with const_handles::MBUF_TEMPORARY_1 after VM fix
528        let hash_handle = managed_api_impl.mb_new_empty();
529        let name_handle = managed_api_impl.mb_new_empty();
530        let attributes_handle = managed_api_impl.mb_new_empty();
531        let creator_handle = managed_api_impl.mb_new_empty();
532        let royalties_handle = managed_api_impl.bi_new_zero();
533        let uris_handle = managed_api_impl.mb_new_empty();
534
535        A::blockchain_api_impl().managed_get_esdt_token_data(
536            address.get_handle().get_raw_handle(),
537            token_id.get_handle().get_raw_handle(),
538            nonce,
539            value_handle.get_raw_handle(),
540            properties_handle.get_raw_handle(),
541            hash_handle.get_raw_handle(),
542            name_handle.get_raw_handle(),
543            attributes_handle.get_raw_handle(),
544            creator_handle.get_raw_handle(),
545            royalties_handle.get_raw_handle(),
546            uris_handle.get_raw_handle(),
547        );
548
549        let token_type = self.get_esdt_token_type(address, token_id.token_id.as_legacy(), nonce);
550
551        if managed_api_impl.mb_len(creator_handle.clone()) == 0 {
552            managed_api_impl.mb_overwrite(creator_handle.clone(), &[0u8; 32][..]);
553        }
554
555        let properties_bytes = load_properties::<A>(properties_handle);
556        let frozen = esdt_is_frozen(&properties_bytes);
557
558        unsafe {
559            EsdtTokenData {
560                token_type,
561                amount: BigUint::from_raw_handle(value_handle.get_raw_handle()),
562                frozen,
563                hash: ManagedBuffer::from_raw_handle(hash_handle.get_raw_handle()),
564                name: ManagedBuffer::from_raw_handle(name_handle.get_raw_handle()),
565                attributes: ManagedBuffer::from_raw_handle(attributes_handle.get_raw_handle()),
566                creator: ManagedAddress::from_raw_handle(creator_handle.get_raw_handle()),
567                royalties: BigUint::from_raw_handle(royalties_handle.get_raw_handle()),
568                uris: ManagedVec::from_raw_handle(uris_handle.get_raw_handle()),
569            }
570        }
571    }
572
573    /// Retrieves back-transfers from the VM, after a contract call.
574    ///
575    /// Works after:
576    /// - synchronous calls
577    /// - asynchronous calls too, in callbacks.
578    #[deprecated(
579        since = "0.59.0",
580        note = "Does not handle multi-transfers properly, use get_back_transfers instead"
581    )]
582    pub fn get_back_transfers_legacy(&self) -> BackTransfersLegacy<A> {
583        let esdt_transfer_value_handle: A::BigIntHandle =
584            use_raw_handle(A::static_var_api_impl().next_handle());
585        let call_value_handle: A::BigIntHandle =
586            use_raw_handle(A::static_var_api_impl().next_handle());
587
588        A::blockchain_api_impl().managed_get_back_transfers(
589            esdt_transfer_value_handle.get_raw_handle(),
590            call_value_handle.get_raw_handle(),
591        );
592
593        unsafe {
594            BackTransfersLegacy {
595                total_egld_amount: BigUint::from_raw_handle(call_value_handle.get_raw_handle()),
596                esdt_payments: ManagedVec::from_raw_handle(
597                    esdt_transfer_value_handle.get_raw_handle(),
598                ),
599            }
600        }
601    }
602
603    /// Retrieves all back-transfers as a collection of payments.
604    ///
605    /// Covers all cases, including EGLD sent via multi-transfer.
606    pub fn get_back_transfers(&self) -> BackTransfers<A> {
607        unsafe {
608            let mut all_bt_vec = ManagedVec::new_uninit();
609            let bt_direct_egld = BigUint::<A>::new_uninit();
610
611            A::blockchain_api_impl().managed_get_back_transfers(
612                all_bt_vec.get_raw_handle_unchecked(),
613                bt_direct_egld.get_raw_handle_unchecked(),
614            );
615
616            if bt_direct_egld > 0u64 {
617                all_bt_vec.push(EgldOrEsdtTokenPayment::egld_payment(bt_direct_egld));
618            }
619
620            BackTransfers::new(all_bt_vec)
621        }
622    }
623
624    /// Clears back transfers by retrieving current back transfers and ignoring result.
625    pub fn reset_back_transfers(&self) {
626        A::blockchain_api_impl().managed_get_back_transfers(
627            const_handles::MBUF_TEMPORARY_1,
628            const_handles::BIG_INT_TEMPORARY_1,
629        );
630    }
631
632    /// Retrieves and deserializes token attributes from the SC account, with given token identifier and nonce.
633    pub fn get_token_attributes<T: TopDecode>(
634        &self,
635        token_id: &EsdtTokenIdentifier<A>,
636        token_nonce: u64,
637    ) -> T {
638        let own_sc_address = self.get_sc_address();
639        let token_data = self.get_esdt_token_data(&own_sc_address, token_id, token_nonce);
640        token_data.decode_attributes()
641    }
642
643    #[inline]
644    pub fn is_esdt_frozen(
645        &self,
646        address: &ManagedAddress<A>,
647        token_id: &EsdtTokenIdentifier<A>,
648        nonce: u64,
649    ) -> bool {
650        A::blockchain_api_impl().check_esdt_frozen(
651            address.get_handle(),
652            token_id.get_handle(),
653            nonce,
654        )
655    }
656
657    #[inline]
658    pub fn is_esdt_paused(&self, token_id: &EsdtTokenIdentifier<A>) -> bool {
659        A::blockchain_api_impl().check_esdt_paused(token_id.get_handle())
660    }
661
662    #[inline]
663    pub fn is_esdt_limited_transfer(&self, token_id: &EsdtTokenIdentifier<A>) -> bool {
664        A::blockchain_api_impl().check_esdt_limited_transfer(token_id.get_handle())
665    }
666
667    #[inline]
668    pub fn get_esdt_local_roles(&self, token_id: &EsdtTokenIdentifier<A>) -> EsdtLocalRoleFlags {
669        A::blockchain_api_impl().load_esdt_local_roles(token_id.get_handle())
670    }
671}
672
673impl<A> BlockchainWrapper<A>
674where
675    A: BlockchainApi + StorageReadApi + ManagedTypeApi + ErrorApi,
676{
677    /// Retrieves validator rewards, as set by the protocol.
678    #[inline]
679    pub fn get_cumulated_validator_rewards(&self) -> BigUint<A> {
680        let temp_handle_1: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
681        let temp_handle_2: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_2);
682
683        // prepare key
684        A::managed_type_impl().mb_overwrite(
685            temp_handle_1.clone(),
686            storage::protected_keys::ELROND_REWARD_KEY,
687        );
688
689        // load value
690        A::storage_read_api_impl()
691            .storage_load_managed_buffer_raw(temp_handle_1, temp_handle_2.clone());
692
693        // convert value to BigUint
694        let result = unsafe { BigUint::new_uninit() };
695        A::managed_type_impl().mb_to_big_int_unsigned(temp_handle_2, result.get_handle());
696        result
697    }
698
699    pub fn token_has_transfer_role(&self, token_identifier: EsdtTokenIdentifier<A>) -> bool {
700        // Prepare key
701        let key_handle: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_1);
702        A::managed_type_impl().mb_overwrite(key_handle.clone(), b"ELRONDtransferesdt");
703
704        // Append token identifier
705        A::managed_type_impl().mb_append(
706            key_handle.clone(),
707            token_identifier.into_managed_buffer().get_handle(),
708        );
709
710        // Prepare result
711        let result_handle: A::ManagedBufferHandle = use_raw_handle(const_handles::MBUF_TEMPORARY_2);
712
713        // Read storage from address
714        A::storage_read_api_impl().storage_load_from_address(
715            SystemSCAddress.to_managed_address::<A>().get_handle(),
716            key_handle,
717            result_handle.clone(),
718        );
719
720        let result = unsafe { ManagedRef::<A, ManagedBuffer<A>>::wrap_handle(result_handle) };
721
722        // Decoding the response needs more research
723        // Empty response means no address has transferRole for the token
724        !result.is_empty()
725    }
726}
727
728fn load_properties<A: ManagedTypeApi>(properties_handle: A::ManagedBufferHandle) -> [u8; 2] {
729    let mut properties_bytes = [0u8; 2];
730    if A::managed_type_impl().mb_len(properties_handle.clone()) == 2 {
731        let _ =
732            A::managed_type_impl().mb_load_slice(properties_handle, 0, &mut properties_bytes[..]);
733    }
734    properties_bytes
735}
736
737fn esdt_is_frozen(properties_bytes: &[u8; 2]) -> bool {
738    properties_bytes[0] > 0 // token is frozen if the first byte is 1
739}