diff --git a/framework/base/src/storage/mappers/token.rs b/framework/base/src/storage/mappers/token.rs index 3fa7032349..7ccaffa767 100644 --- a/framework/base/src/storage/mappers/token.rs +++ b/framework/base/src/storage/mappers/token.rs @@ -1,11 +1,12 @@ +#![allow(unused)] + +mod error; mod fungible_token_mapper; mod non_fungible_token_mapper; mod token_attributes_mapper; -mod token_mapper; mod token_mapper_state; pub use fungible_token_mapper::FungibleTokenMapper; pub use non_fungible_token_mapper::NonFungibleTokenMapper; pub use token_attributes_mapper::TokenAttributesMapper; -pub use token_mapper::StorageTokenWrapper; pub use token_mapper_state::TokenMapperState; diff --git a/framework/base/src/storage/mappers/token/error.rs b/framework/base/src/storage/mappers/token/error.rs new file mode 100644 index 0000000000..45953bd4a3 --- /dev/null +++ b/framework/base/src/storage/mappers/token/error.rs @@ -0,0 +1,5 @@ +pub(crate) const TOKEN_ID_ALREADY_SET_ERR_MSG: &[u8] = b"Token ID already set"; +pub(crate) const PENDING_ERR_MSG: &[u8] = b"Issue was already called"; +pub(crate) const MUST_SET_TOKEN_ID_ERR_MSG: &[u8] = b"Must issue or set token ID first"; +pub(crate) const INVALID_TOKEN_ID_ERR_MSG: &[u8] = b"Invalid token ID"; +pub(crate) const INVALID_PAYMENT_TOKEN_ERR_MSG: &[u8] = b"Invalid payment token"; diff --git a/framework/base/src/storage/mappers/token/fungible_token_mapper.rs b/framework/base/src/storage/mappers/token/fungible_token_mapper.rs index 384e0d6096..e3cd41702e 100644 --- a/framework/base/src/storage/mappers/token/fungible_token_mapper.rs +++ b/framework/base/src/storage/mappers/token/fungible_token_mapper.rs @@ -1,17 +1,26 @@ +use multiversx_chain_core::types::EsdtLocalRole; + use crate::{ abi::{TypeAbi, TypeAbiFrom}, api::ErrorApiImpl, codec::{EncodeErrorHandler, TopEncodeMulti, TopEncodeMultiOutput}, - storage_clear, storage_get, storage_set, + storage::mappers::{ + set_mapper::{CurrentStorage, StorageAddress}, + StorageMapperFromAddress, + }, + storage_clear, storage_get, storage_get_len, storage_set, types::{ system_proxy::{ESDTSystemSCProxy, FungibleTokenProperties}, - ESDTSystemSCAddress, Tx, + ESDTSystemSCAddress, ManagedRef, Tx, }, }; use super::{ super::StorageMapper, - token_mapper::{check_not_set, store_token_id, StorageTokenWrapper, INVALID_TOKEN_ID_ERR_MSG}, + error::{ + INVALID_PAYMENT_TOKEN_ERR_MSG, INVALID_TOKEN_ID_ERR_MSG, MUST_SET_TOKEN_ID_ERR_MSG, + PENDING_ERR_MSG, TOKEN_ID_ALREADY_SET_ERR_MSG, + }, TokenMapperState, }; use crate::{ @@ -21,7 +30,7 @@ use crate::{ storage::StorageKey, types::{ BigUint, CallbackClosure, EsdtTokenPayment, EsdtTokenType, ManagedAddress, ManagedBuffer, - ManagedType, TokenIdentifier, + ManagedType, ManagedVec, TokenIdentifier, }, }; @@ -29,15 +38,17 @@ pub(crate) const DEFAULT_ISSUE_CALLBACK_NAME: &str = "default_issue_cb"; pub(crate) const DEFAULT_ISSUE_WITH_INIT_SUPPLY_CALLBACK_NAME: &str = "default_issue_init_supply_cb"; -pub struct FungibleTokenMapper +pub struct FungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, + A: StorageAddress, { key: StorageKey, token_state: TokenMapperState, + address: A, } -impl StorageMapper for FungibleTokenMapper +impl StorageMapper for FungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { @@ -45,45 +56,25 @@ where Self { token_state: storage_get(base_key.as_ref()), key: base_key, + address: CurrentStorage, } } } -impl StorageTokenWrapper for FungibleTokenMapper +impl StorageMapperFromAddress for FungibleTokenMapper> where SA: StorageMapperApi + CallTypeApi, { - fn get_storage_key(&self) -> crate::types::ManagedRef> { - self.key.as_ref() - } - - fn get_token_state(&self) -> TokenMapperState { - self.token_state.clone() - } - - fn get_token_id(&self) -> TokenIdentifier { - if let TokenMapperState::Token(token) = &self.token_state { - token.clone() - } else { - SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG) - } - } - - fn get_token_id_ref(&self) -> &TokenIdentifier { - if let TokenMapperState::Token(token) = &self.token_state { - token - } else { - SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + Self { + token_state: storage_get(base_key.as_ref()), + key: base_key, + address, } } - - fn set_token_id(&mut self, token_id: TokenIdentifier) { - store_token_id(self, &token_id); - self.token_state = TokenMapperState::Token(token_id); - } } -impl FungibleTokenMapper +impl FungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { @@ -114,7 +105,7 @@ where num_decimals: usize, opt_callback: Option>, ) -> ! { - check_not_set(self); + self.check_not_set(); let callback = match opt_callback { Some(cb) => cb, @@ -166,7 +157,7 @@ where num_decimals: usize, opt_callback: Option>, ) -> ! { - check_not_set(self); + self.check_not_set(); let callback = match opt_callback { Some(cb) => cb, @@ -195,21 +186,6 @@ where } } - fn default_callback_closure_obj(&self, initial_supply: &BigUint) -> CallbackClosure { - let initial_caller = BlockchainWrapper::::new().get_caller(); - let cb_name = if initial_supply > &0 { - DEFAULT_ISSUE_WITH_INIT_SUPPLY_CALLBACK_NAME - } else { - DEFAULT_ISSUE_CALLBACK_NAME - }; - - let mut cb_closure = CallbackClosure::new(cb_name); - cb_closure.push_endpoint_arg(&initial_caller); - cb_closure.push_endpoint_arg(&self.key.buffer); - - cb_closure - } - pub fn mint(&self, amount: BigUint) -> EsdtTokenPayment { let send_wrapper = SendWrapper::::new(); let token_id = self.get_token_id(); @@ -237,6 +213,63 @@ where send_wrapper.esdt_local_burn(token_id, 0, amount); } + pub fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { + Tx::new_tx_from_sc() + .to(to) + .single_esdt(&payment.token_identifier, 0, &payment.amount) + .transfer(); + } + + pub fn set_if_empty(&mut self, token_id: TokenIdentifier) { + if self.is_empty() { + self.set_token_id(token_id); + } + } + + pub fn set_local_roles( + &self, + roles: &[EsdtLocalRole], + opt_callback: Option>, + ) -> ! { + let own_sc_address = Self::get_sc_address(); + self.set_local_roles_for_address(&own_sc_address, roles, opt_callback); + } + + pub fn set_local_roles_for_address( + &self, + address: &ManagedAddress, + roles: &[EsdtLocalRole], + opt_callback: Option>, + ) -> ! { + self.require_issued_or_set(); + + let token_id = self.get_token_id_ref(); + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) + .set_special_roles(address, token_id, roles[..].iter().cloned()) + .callback(opt_callback) + .async_call_and_exit() + } + + pub fn set_token_id(&mut self, token_id: TokenIdentifier) { + self.store_token_id(&token_id); + self.token_state = TokenMapperState::Token(token_id); + } + + pub(crate) fn store_token_id(&self, token_id: &TokenIdentifier) { + if self.get_token_state().is_set() { + SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); + } + if !token_id.is_valid_esdt_identifier() { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + } + storage_set( + self.get_storage_key(), + &TokenMapperState::Token(token_id.clone()), + ); + } + pub fn get_balance(&self) -> BigUint { let b_wrapper = BlockchainWrapper::new(); let own_sc_address = Self::get_sc_address(); @@ -245,11 +278,96 @@ where b_wrapper.get_esdt_balance(&own_sc_address, token_id, 0) } - fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { - Tx::new_tx_from_sc() - .to(to) - .single_esdt(&payment.token_identifier, 0, &payment.amount) - .transfer(); + pub fn get_sc_address() -> ManagedAddress { + let b_wrapper = BlockchainWrapper::new(); + b_wrapper.get_sc_address() + } +} + +impl FungibleTokenMapper +where + SA: StorageMapperApi + CallTypeApi, + A: StorageAddress, +{ + pub fn get_storage_key(&self) -> ManagedRef> { + self.key.as_ref() + } + + pub fn get_token_state(&self) -> TokenMapperState { + self.token_state.clone() + } + + pub fn get_token_id(&self) -> TokenIdentifier { + if let TokenMapperState::Token(token) = &self.token_state { + token.clone() + } else { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG) + } + } + + pub fn get_token_id_ref(&self) -> &TokenIdentifier { + if let TokenMapperState::Token(token) = &self.token_state { + token + } else { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + } + } + + pub fn is_empty(&self) -> bool { + storage_get_len(self.get_storage_key()) == 0 + } + + pub fn require_issued_or_set(&self) { + if self.is_empty() { + SA::error_api_impl().signal_error(MUST_SET_TOKEN_ID_ERR_MSG); + } + } + + pub fn require_same_token(&self, expected_token_id: &TokenIdentifier) { + let actual_token_id = self.get_token_id_ref(); + if actual_token_id != expected_token_id { + SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); + } + } + + pub fn require_all_same_token(&self, payments: &ManagedVec>) { + let actual_token_id = self.get_token_id_ref(); + for p in payments { + if actual_token_id != &p.token_identifier { + SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); + } + } + } + + pub fn default_callback_closure_obj( + &self, + initial_supply: &BigUint, + ) -> CallbackClosure { + let initial_caller = BlockchainWrapper::::new().get_caller(); + let cb_name = if initial_supply > &0 { + DEFAULT_ISSUE_WITH_INIT_SUPPLY_CALLBACK_NAME + } else { + DEFAULT_ISSUE_CALLBACK_NAME + }; + + let mut cb_closure = CallbackClosure::new(cb_name); + cb_closure.push_endpoint_arg(&initial_caller); + cb_closure.push_endpoint_arg(&self.key.buffer); + + cb_closure + } + + pub(crate) fn check_not_set(&self) { + let storage_value: TokenMapperState = storage_get(self.get_storage_key()); + match storage_value { + TokenMapperState::NotSet => {}, + TokenMapperState::Pending => { + SA::error_api_impl().signal_error(PENDING_ERR_MSG); + }, + TokenMapperState::Token(_) => { + SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); + }, + } } } diff --git a/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs b/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs index 70fc3be81f..3a4d63ab97 100644 --- a/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs +++ b/framework/base/src/storage/mappers/token/non_fungible_token_mapper.rs @@ -1,17 +1,26 @@ +use multiversx_chain_core::types::EsdtLocalRole; + use crate::{ abi::TypeAbiFrom, codec::{EncodeErrorHandler, TopDecode, TopEncode, TopEncodeMulti, TopEncodeMultiOutput}, - storage_clear, storage_get, storage_set, + storage::mappers::{ + set_mapper::{CurrentStorage, StorageAddress}, + StorageMapperFromAddress, + }, + storage_clear, storage_get, storage_get_len, storage_set, types::{ system_proxy::ESDTSystemSCProxy, ESDTSystemSCAddress, EgldPayment, FunctionCall, - OriginalResultMarker, Tx, TxScEnv, + ManagedVec, OriginalResultMarker, Tx, TxScEnv, }, }; use super::{ super::StorageMapper, + error::{ + INVALID_PAYMENT_TOKEN_ERR_MSG, INVALID_TOKEN_ID_ERR_MSG, MUST_SET_TOKEN_ID_ERR_MSG, + PENDING_ERR_MSG, TOKEN_ID_ALREADY_SET_ERR_MSG, + }, fungible_token_mapper::DEFAULT_ISSUE_CALLBACK_NAME, - token_mapper::{check_not_set, store_token_id, StorageTokenWrapper, INVALID_TOKEN_ID_ERR_MSG}, TokenMapperState, }; use crate::{ @@ -40,15 +49,17 @@ pub type IssueCallTo = Tx< OriginalResultMarker>, >; -pub struct NonFungibleTokenMapper +pub struct NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, + A: StorageAddress, { key: StorageKey, token_state: TokenMapperState, + address: A, } -impl StorageMapper for NonFungibleTokenMapper +impl StorageMapper for NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { @@ -56,45 +67,25 @@ where Self { token_state: storage_get(base_key.as_ref()), key: base_key, + address: CurrentStorage, } } } -impl StorageTokenWrapper for NonFungibleTokenMapper +impl StorageMapperFromAddress for NonFungibleTokenMapper> where SA: StorageMapperApi + CallTypeApi, { - fn get_storage_key(&self) -> crate::types::ManagedRef> { - self.key.as_ref() - } - - fn get_token_state(&self) -> TokenMapperState { - self.token_state.clone() - } - - fn get_token_id(&self) -> TokenIdentifier { - if let TokenMapperState::Token(token) = &self.token_state { - token.clone() - } else { - SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); - } - } - - fn get_token_id_ref(&self) -> &TokenIdentifier { - if let TokenMapperState::Token(token) = &self.token_state { - token - } else { - SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + Self { + token_state: storage_get(base_key.as_ref()), + key: base_key, + address, } } - - fn set_token_id(&mut self, token_id: TokenIdentifier) { - store_token_id(self, &token_id); - self.token_state = TokenMapperState::Token(token_id); - } } -impl NonFungibleTokenMapper +impl NonFungibleTokenMapper where SA: StorageMapperApi + CallTypeApi, { @@ -125,7 +116,7 @@ where num_decimals: usize, opt_callback: Option>, ) -> ! { - check_not_set(self); + self.check_not_set(); let callback = match opt_callback { Some(cb) => cb, @@ -175,7 +166,7 @@ where num_decimals: usize, opt_callback: Option>, ) -> ! { - check_not_set(self); + self.check_not_set(); if token_type == EsdtTokenType::Fungible || token_type == EsdtTokenType::Invalid { SA::error_api_impl().signal_error(INVALID_TOKEN_TYPE_ERR_MSG); @@ -208,18 +199,7 @@ where } } - fn default_callback_closure_obj(&self) -> CallbackClosure { - let initial_caller = BlockchainWrapper::::new().get_caller(); - let cb_name = DEFAULT_ISSUE_CALLBACK_NAME; - - let mut cb_closure = CallbackClosure::new(cb_name); - cb_closure.push_endpoint_arg(&initial_caller); - cb_closure.push_endpoint_arg(&self.key.buffer); - - cb_closure - } - - fn nft_issue( + pub fn nft_issue( issue_cost: BigUint, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, @@ -235,7 +215,7 @@ where ) } - fn sft_issue( + pub fn sft_issue( issue_cost: BigUint, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, @@ -251,7 +231,7 @@ where ) } - fn meta_issue( + pub fn meta_issue( issue_cost: BigUint, token_display_name: ManagedBuffer, token_ticker: ManagedBuffer, @@ -355,12 +335,65 @@ where send_wrapper.esdt_local_burn(token_id, token_nonce, amount); } - pub fn get_all_token_data(&self, token_nonce: u64) -> EsdtTokenData { - let b_wrapper = BlockchainWrapper::new(); + pub fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { + Tx::new_tx_from_sc() + .to(to) + .single_esdt( + &payment.token_identifier, + payment.token_nonce, + &payment.amount, + ) + .transfer(); + } + + pub fn set_token_id(&mut self, token_id: TokenIdentifier) { + self.store_token_id(&token_id); + self.token_state = TokenMapperState::Token(token_id); + } + + pub fn set_if_empty(&mut self, token_id: TokenIdentifier) { + if self.is_empty() { + self.set_token_id(token_id); + } + } + + pub fn set_local_roles( + &self, + roles: &[EsdtLocalRole], + opt_callback: Option>, + ) -> ! { let own_sc_address = Self::get_sc_address(); + self.set_local_roles_for_address(&own_sc_address, roles, opt_callback); + } + + pub fn set_local_roles_for_address( + &self, + address: &ManagedAddress, + roles: &[EsdtLocalRole], + opt_callback: Option>, + ) -> ! { + self.require_issued_or_set(); + let token_id = self.get_token_id_ref(); + Tx::new_tx_from_sc() + .to(ESDTSystemSCAddress) + .typed(ESDTSystemSCProxy) + .set_special_roles(address, token_id, roles[..].iter().cloned()) + .callback(opt_callback) + .async_call_and_exit() + } - b_wrapper.get_esdt_token_data(&own_sc_address, token_id, token_nonce) + pub(crate) fn store_token_id(&self, token_id: &TokenIdentifier) { + if self.get_token_state().is_set() { + SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); + } + if !token_id.is_valid_esdt_identifier() { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + } + storage_set( + self.get_storage_key(), + &TokenMapperState::Token(token_id.clone()), + ); } pub fn get_balance(&self, token_nonce: u64) -> BigUint { @@ -371,20 +404,102 @@ where b_wrapper.get_esdt_balance(&own_sc_address, token_id, token_nonce) } + pub fn get_sc_address() -> ManagedAddress { + let b_wrapper = BlockchainWrapper::new(); + b_wrapper.get_sc_address() + } + + pub fn get_all_token_data(&self, token_nonce: u64) -> EsdtTokenData { + let b_wrapper = BlockchainWrapper::new(); + let own_sc_address = Self::get_sc_address(); + let token_id = self.get_token_id_ref(); + + b_wrapper.get_esdt_token_data(&own_sc_address, token_id, token_nonce) + } + pub fn get_token_attributes(&self, token_nonce: u64) -> T { let token_data = self.get_all_token_data(token_nonce); token_data.decode_attributes() } +} - fn send_payment(&self, to: &ManagedAddress, payment: &EsdtTokenPayment) { - Tx::new_tx_from_sc() - .to(to) - .single_esdt( - &payment.token_identifier, - payment.token_nonce, - &payment.amount, - ) - .transfer(); +impl NonFungibleTokenMapper +where + SA: StorageMapperApi + CallTypeApi, + A: StorageAddress, +{ + pub(crate) fn check_not_set(&self) { + let storage_value: TokenMapperState = storage_get(self.get_storage_key()); + match storage_value { + TokenMapperState::NotSet => {}, + TokenMapperState::Pending => { + SA::error_api_impl().signal_error(PENDING_ERR_MSG); + }, + TokenMapperState::Token(_) => { + SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); + }, + } + } + + pub fn is_empty(&self) -> bool { + storage_get_len(self.get_storage_key()) == 0 + } + + pub fn require_issued_or_set(&self) { + if self.is_empty() { + SA::error_api_impl().signal_error(MUST_SET_TOKEN_ID_ERR_MSG); + } + } + + pub fn require_same_token(&self, expected_token_id: &TokenIdentifier) { + let actual_token_id = self.get_token_id_ref(); + if actual_token_id != expected_token_id { + SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); + } + } + + pub fn require_all_same_token(&self, payments: &ManagedVec>) { + let actual_token_id = self.get_token_id_ref(); + for p in payments { + if actual_token_id != &p.token_identifier { + SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); + } + } + } + + pub fn get_storage_key(&self) -> crate::types::ManagedRef> { + self.key.as_ref() + } + + pub fn get_token_state(&self) -> TokenMapperState { + self.token_state.clone() + } + + pub fn get_token_id(&self) -> TokenIdentifier { + if let TokenMapperState::Token(token) = &self.token_state { + token.clone() + } else { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + } + } + + pub fn get_token_id_ref(&self) -> &TokenIdentifier { + if let TokenMapperState::Token(token) = &self.token_state { + token + } else { + SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); + } + } + + pub fn default_callback_closure_obj(&self) -> CallbackClosure { + let initial_caller = BlockchainWrapper::::new().get_caller(); + let cb_name = DEFAULT_ISSUE_CALLBACK_NAME; + + let mut cb_closure = CallbackClosure::new(cb_name); + cb_closure.push_endpoint_arg(&initial_caller); + cb_closure.push_endpoint_arg(&self.key.buffer); + + cb_closure } } diff --git a/framework/base/src/storage/mappers/token/token_attributes_mapper.rs b/framework/base/src/storage/mappers/token/token_attributes_mapper.rs index 33b00f56f3..f9631cf983 100644 --- a/framework/base/src/storage/mappers/token/token_attributes_mapper.rs +++ b/framework/base/src/storage/mappers/token/token_attributes_mapper.rs @@ -1,6 +1,13 @@ use core::marker::PhantomData; -use crate::codec::{NestedDecode, NestedEncode, TopDecode, TopEncode}; +use crate::{ + codec::{NestedDecode, NestedEncode, TopDecode, TopEncode}, + storage::mappers::{ + set_mapper::{CurrentStorage, StorageAddress}, + StorageMapperFromAddress, + }, + types::ManagedAddress, +}; use super::super::StorageMapper; use crate::{ @@ -23,15 +30,16 @@ const VALUE_NOT_PREVIOUSLY_SET_ERROR_MESSAGE: &[u8] = b"A value was not previous const COUNTER_OVERFLOW_ERROR_MESSAGE: &[u8] = b"Counter overflow. This module can hold evidence for maximum u8::MAX different token IDs"; -pub struct TokenAttributesMapper +pub struct TokenAttributesMapper where SA: StorageMapperApi, { _phantom_api: PhantomData, base_key: StorageKey, + address: A, } -impl StorageMapper for TokenAttributesMapper +impl StorageMapper for TokenAttributesMapper where SA: StorageMapperApi, { @@ -39,11 +47,25 @@ where TokenAttributesMapper { _phantom_api: PhantomData, base_key, + address: CurrentStorage, + } + } +} + +impl StorageMapperFromAddress for TokenAttributesMapper> +where + SA: StorageMapperApi, +{ + fn new_from_address(address: ManagedAddress, base_key: StorageKey) -> Self { + Self { + _phantom_api: PhantomData, + base_key, + address, } } } -impl TokenAttributesMapper +impl TokenAttributesMapper where SA: StorageMapperApi, { @@ -124,6 +146,60 @@ where self.clear_attributes_to_nonce_mapping(mapping, &attr); } + fn set_counter_value(&self, value: u8) { + storage_set(self.build_key_token_id_counter().as_ref(), &value); + } + + fn set_mapping_value(&self, token_id: &TokenIdentifier, value: u8) { + storage_set(self.build_key_token_id_mapping(token_id).as_ref(), &value); + } + + fn set_attributes_to_nonce_mapping( + &self, + mapping: u8, + attr: &T, + token_nonce: u64, + ) { + storage_set( + self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref(), + &token_nonce, + ); + } + + fn clear_attributes_to_nonce_mapping( + &self, + mapping: u8, + attr: &T, + ) { + storage_clear(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()); + } + + fn set_token_attributes_value( + &self, + mapping: u8, + token_nonce: u64, + value: &T, + ) { + storage_set( + self.build_key_token_attr_value(mapping, token_nonce) + .as_ref(), + value, + ); + } + + fn clear_token_attributes_value(&self, mapping: u8, token_nonce: u64) { + storage_clear( + self.build_key_token_attr_value(mapping, token_nonce) + .as_ref(), + ); + } +} + +impl TokenAttributesMapper +where + SA: StorageMapperApi, + A: StorageAddress, +{ pub fn has_attributes( &self, token_id: &TokenIdentifier, @@ -249,18 +325,10 @@ where storage_get(self.build_key_token_id_counter().as_ref()) } - fn set_counter_value(&self, value: u8) { - storage_set(self.build_key_token_id_counter().as_ref(), &value); - } - fn get_mapping_value(&self, token_id: &TokenIdentifier) -> u8 { storage_get(self.build_key_token_id_mapping(token_id).as_ref()) } - fn set_mapping_value(&self, token_id: &TokenIdentifier, value: u8) { - storage_set(self.build_key_token_id_mapping(token_id).as_ref(), &value); - } - fn is_empty_mapping_value(&self, token_id: &TokenIdentifier) -> bool { storage_get_len(self.build_key_token_id_mapping(token_id).as_ref()) == 0 } @@ -273,18 +341,6 @@ where storage_get(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()) } - fn set_attributes_to_nonce_mapping( - &self, - mapping: u8, - attr: &T, - token_nonce: u64, - ) { - storage_set( - self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref(), - &token_nonce, - ); - } - fn is_empty_attributes_to_nonce_mapping< T: TopEncode + TopDecode + NestedEncode + NestedDecode, >( @@ -295,14 +351,6 @@ where storage_get_len(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()) == 0 } - fn clear_attributes_to_nonce_mapping( - &self, - mapping: u8, - attr: &T, - ) { - storage_clear(self.build_key_attr_to_nonce_mapping(mapping, attr).as_ref()); - } - fn get_token_attributes_value( &self, mapping: u8, @@ -314,30 +362,10 @@ where ) } - fn set_token_attributes_value( - &self, - mapping: u8, - token_nonce: u64, - value: &T, - ) { - storage_set( - self.build_key_token_attr_value(mapping, token_nonce) - .as_ref(), - value, - ); - } - fn is_empty_token_attributes_value(&self, mapping: u8, token_nonce: u64) -> bool { storage_get_len( self.build_key_token_attr_value(mapping, token_nonce) .as_ref(), ) == 0 } - - fn clear_token_attributes_value(&self, mapping: u8, token_nonce: u64) { - storage_clear( - self.build_key_token_attr_value(mapping, token_nonce) - .as_ref(), - ); - } } diff --git a/framework/base/src/storage/mappers/token/token_mapper.rs b/framework/base/src/storage/mappers/token/token_mapper.rs deleted file mode 100644 index 77f435a546..0000000000 --- a/framework/base/src/storage/mappers/token/token_mapper.rs +++ /dev/null @@ -1,129 +0,0 @@ -use crate::{ - api::{CallTypeApi, ErrorApiImpl, StorageMapperApi}, - contract_base::BlockchainWrapper, - storage::StorageKey, - storage_get, storage_get_len, storage_set, - types::{ - system_proxy::ESDTSystemSCProxy, CallbackClosure, ESDTSystemSCAddress, EsdtLocalRole, - EsdtTokenPayment, ManagedAddress, ManagedRef, ManagedVec, TokenIdentifier, Tx, - }, -}; - -use super::TokenMapperState; - -pub(crate) const TOKEN_ID_ALREADY_SET_ERR_MSG: &[u8] = b"Token ID already set"; -pub(crate) const PENDING_ERR_MSG: &[u8] = b"Issue was already called"; -pub(crate) const MUST_SET_TOKEN_ID_ERR_MSG: &[u8] = b"Must issue or set token ID first"; -pub(crate) const INVALID_TOKEN_ID_ERR_MSG: &[u8] = b"Invalid token ID"; -pub(crate) const INVALID_PAYMENT_TOKEN_ERR_MSG: &[u8] = b"Invalid payment token"; - -pub trait StorageTokenWrapper -where - SA: StorageMapperApi + CallTypeApi, -{ - fn get_storage_key(&self) -> ManagedRef>; - - fn is_empty(&self) -> bool { - storage_get_len(self.get_storage_key()) == 0 - } - - fn get_token_state(&self) -> TokenMapperState; - - fn get_token_id(&self) -> TokenIdentifier; - - fn get_token_id_ref(&self) -> &TokenIdentifier; - - fn set_token_id(&mut self, token_id: TokenIdentifier); - - fn set_if_empty(&mut self, token_id: TokenIdentifier) { - if self.is_empty() { - self.set_token_id(token_id); - } - } - - fn require_issued_or_set(&self) { - if self.is_empty() { - SA::error_api_impl().signal_error(MUST_SET_TOKEN_ID_ERR_MSG); - } - } - - fn require_same_token(&self, expected_token_id: &TokenIdentifier) { - let actual_token_id = self.get_token_id_ref(); - if actual_token_id != expected_token_id { - SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); - } - } - - fn require_all_same_token(&self, payments: &ManagedVec>) { - let actual_token_id = self.get_token_id_ref(); - for p in payments { - if actual_token_id != &p.token_identifier { - SA::error_api_impl().signal_error(INVALID_PAYMENT_TOKEN_ERR_MSG); - } - } - } - - fn set_local_roles( - &self, - roles: &[EsdtLocalRole], - opt_callback: Option>, - ) -> ! { - let own_sc_address = Self::get_sc_address(); - self.set_local_roles_for_address(&own_sc_address, roles, opt_callback); - } - - fn set_local_roles_for_address( - &self, - address: &ManagedAddress, - roles: &[EsdtLocalRole], - opt_callback: Option>, - ) -> ! { - self.require_issued_or_set(); - - let token_id = self.get_token_id_ref(); - Tx::new_tx_from_sc() - .to(ESDTSystemSCAddress) - .typed(ESDTSystemSCProxy) - .set_special_roles(address, token_id, roles[..].iter().cloned()) - .callback(opt_callback) - .async_call_and_exit() - } - - fn get_sc_address() -> ManagedAddress { - let b_wrapper = BlockchainWrapper::new(); - b_wrapper.get_sc_address() - } -} - -pub(crate) fn store_token_id< - SA: StorageMapperApi + CallTypeApi, - Mapper: StorageTokenWrapper, ->( - mapper: &Mapper, - token_id: &TokenIdentifier, -) { - if mapper.get_token_state().is_set() { - SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); - } - if !token_id.is_valid_esdt_identifier() { - SA::error_api_impl().signal_error(INVALID_TOKEN_ID_ERR_MSG); - } - storage_set( - mapper.get_storage_key(), - &TokenMapperState::Token(token_id.clone()), - ); -} -pub(crate) fn check_not_set>( - mapper: &Mapper, -) { - let storage_value: TokenMapperState = storage_get(mapper.get_storage_key()); - match storage_value { - TokenMapperState::NotSet => {}, - TokenMapperState::Pending => { - SA::error_api_impl().signal_error(PENDING_ERR_MSG); - }, - TokenMapperState::Token(_) => { - SA::error_api_impl().signal_error(TOKEN_ID_ALREADY_SET_ERR_MSG); - }, - } -}