diff --git a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs index 80ce8f7762..c0e08e33ff 100644 --- a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs @@ -491,7 +491,7 @@ where uris_handle.get_raw_handle(), ); - let token_type = self.get_esdt_token_type(address, &token_id.data, nonce); + let token_type = self.get_esdt_token_type(address, token_id.token_id.as_legacy(), nonce); if managed_api_impl.mb_len(creator_handle.clone()) == 0 { managed_api_impl.mb_overwrite(creator_handle.clone(), &[0u8; 32][..]); diff --git a/framework/base/src/types/interaction/tx_data/function_call.rs b/framework/base/src/types/interaction/tx_data/function_call.rs index 7b8e5c9dfc..8e6911f014 100644 --- a/framework/base/src/types/interaction/tx_data/function_call.rs +++ b/framework/base/src/types/interaction/tx_data/function_call.rs @@ -203,7 +203,7 @@ where for payment in payments { // serializing token identifier buffer to get EGLD-00000 instead of EGLD result = result - .argument(&payment.token_identifier.buffer) + .argument(&payment.token_identifier.token_id) .argument(&payment.token_nonce) .argument(&payment.amount); } diff --git a/framework/base/src/types/managed/wrapped/token.rs b/framework/base/src/types/managed/wrapped/token.rs index 131137a71d..3e4249755d 100644 --- a/framework/base/src/types/managed/wrapped/token.rs +++ b/framework/base/src/types/managed/wrapped/token.rs @@ -5,6 +5,7 @@ mod esdt_token_data; mod esdt_token_identifier; mod esdt_token_payment; mod multi_egld_or_esdt_token_payment; +mod token_id; pub use egld_or_esdt_token_identifier::EgldOrEsdtTokenIdentifier; pub use egld_or_esdt_token_payment::{EgldOrEsdtTokenPayment, EgldOrEsdtTokenPaymentRefs}; @@ -13,3 +14,4 @@ pub use esdt_token_data::EsdtTokenData; pub use esdt_token_identifier::{EsdtTokenIdentifier, TokenIdentifier}; pub use esdt_token_payment::{EsdtTokenPayment, EsdtTokenPaymentRefs, MultiEsdtPayment}; pub use multi_egld_or_esdt_token_payment::MultiEgldOrEsdtPayment; +pub use token_id::TokenId; diff --git a/framework/base/src/types/managed/wrapped/token/egld_or_esdt_token_identifier.rs b/framework/base/src/types/managed/wrapped/token/egld_or_esdt_token_identifier.rs index 223a36d128..61e9acaed4 100644 --- a/framework/base/src/types/managed/wrapped/token/egld_or_esdt_token_identifier.rs +++ b/framework/base/src/types/managed/wrapped/token/egld_or_esdt_token_identifier.rs @@ -3,15 +3,12 @@ use multiversx_chain_core::EGLD_000000_TOKEN_IDENTIFIER; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeName}, - api::{ - const_handles, use_raw_handle, ErrorApiImpl, HandleConstraints, ManagedBufferApiImpl, - ManagedTypeApi, - }, + api::{const_handles, use_raw_handle, ErrorApiImpl, ManagedBufferApiImpl, ManagedTypeApi}, codec::*, err_msg, formatter::{FormatByteReceiver, SCDisplay, SCLowerHex}, proxy_imports::TestTokenIdentifier, - types::{EsdtTokenIdentifier, ManagedBuffer, ManagedRef, ManagedType}, + types::{EsdtTokenIdentifier, ManagedBuffer, ManagedRef, ManagedType, TokenId}, }; /// Specialized type for handling either EGLD or ESDT token identifiers. @@ -32,7 +29,7 @@ use crate::{ #[repr(transparent)] #[derive(Clone)] pub struct EgldOrEsdtTokenIdentifier { - pub(crate) buffer: ManagedBuffer, + pub(crate) token_id: TokenId, } impl ManagedType for EgldOrEsdtTokenIdentifier { @@ -41,16 +38,16 @@ impl ManagedType for EgldOrEsdtTokenIdentifier { #[inline] unsafe fn from_handle(handle: M::ManagedBufferHandle) -> Self { EgldOrEsdtTokenIdentifier { - buffer: ManagedBuffer::from_handle(handle), + token_id: TokenId::from_handle(handle), } } fn get_handle(&self) -> M::ManagedBufferHandle { - self.buffer.get_handle() + self.token_id.get_handle() } unsafe fn forget_into_handle(self) -> Self::OwnHandle { - self.buffer.forget_into_handle() + self.token_id.forget_into_handle() } fn transmute_from_handle_ref(handle_ref: &M::ManagedBufferHandle) -> &Self { @@ -70,7 +67,7 @@ impl EgldOrEsdtTokenIdentifier { #[inline] pub fn egld() -> Self { EgldOrEsdtTokenIdentifier { - buffer: ManagedBuffer::from(EGLD_000000_TOKEN_IDENTIFIER), + token_id: TokenId::from(EGLD_000000_TOKEN_IDENTIFIER), } } @@ -81,14 +78,16 @@ impl EgldOrEsdtTokenIdentifier { EsdtTokenIdentifier: From, { let ti_obj = EsdtTokenIdentifier::from(token_identifier); - ti_obj.data + ti_obj.token_id.into() } pub fn parse(data: ManagedBuffer) -> Self { if data == Self::EGLD_REPRESENTATION { Self::egld() } else { - Self { buffer: data } + Self { + token_id: data.into(), + } } } @@ -100,7 +99,7 @@ impl EgldOrEsdtTokenIdentifier { ); M::managed_type_impl().mb_eq( use_raw_handle(const_handles::MBUF_EGLD_000000), - self.buffer.handle.clone(), + self.token_id.buffer.handle.clone(), ) } @@ -131,17 +130,17 @@ impl EgldOrEsdtTokenIdentifier { #[inline] pub fn into_managed_buffer(self) -> ManagedBuffer { - self.buffer + self.token_id.buffer } #[inline] pub fn as_managed_buffer(&self) -> &ManagedBuffer { - &self.buffer + &self.token_id.buffer } #[inline] pub fn to_boxed_bytes(&self) -> crate::types::heap::BoxedBytes { - self.buffer.to_boxed_bytes() + self.token_id.to_boxed_bytes() } pub fn map_or_else(self, context: Context, for_egld: D, for_esdt: F) -> R @@ -206,14 +205,23 @@ impl EgldOrEsdtTokenIdentifier { impl From> for EgldOrEsdtTokenIdentifier { #[inline] fn from(buffer: ManagedBuffer) -> Self { - EgldOrEsdtTokenIdentifier { buffer } + EgldOrEsdtTokenIdentifier { + token_id: buffer.into(), + } + } +} + +impl From> for EgldOrEsdtTokenIdentifier { + #[inline] + fn from(token_id: TokenId) -> Self { + EgldOrEsdtTokenIdentifier { token_id } } } impl From<&[u8]> for EgldOrEsdtTokenIdentifier { fn from(bytes: &[u8]) -> Self { EgldOrEsdtTokenIdentifier { - buffer: ManagedBuffer::new_from_bytes(bytes), + token_id: TokenId::from(bytes), } } } @@ -233,7 +241,7 @@ impl From<&String> for EgldOrEsdtTokenIdentifier { impl PartialEq for EgldOrEsdtTokenIdentifier { #[inline] fn eq(&self, other: &Self) -> bool { - self.buffer == other.buffer + self.token_id == other.token_id } } @@ -260,7 +268,7 @@ impl NestedEncode for EgldOrEsdtTokenIdentifier { if self.is_egld() { (&Self::EGLD_REPRESENTATION[..]).dep_encode_or_handle_err(dest, h) } else { - self.buffer.dep_encode_or_handle_err(dest, h) + self.token_id.dep_encode_or_handle_err(dest, h) } } } @@ -275,7 +283,7 @@ impl TopEncode for EgldOrEsdtTokenIdentifier { if self.is_egld() { (&Self::EGLD_REPRESENTATION[..]).top_encode_or_handle_err(output, h) } else { - self.buffer.top_encode_or_handle_err(output, h) + self.token_id.top_encode_or_handle_err(output, h) } } } @@ -337,9 +345,7 @@ impl SCDisplay for EgldOrEsdtTokenIdentifier { if self.is_egld() { f.append_bytes(Self::EGLD_REPRESENTATION); } else { - let cast_handle = self.buffer.get_handle().cast_or_signal_error::(); - let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) }; - f.append_managed_buffer(&wrap_cast); + SCDisplay::fmt(&self.token_id, f) } } } @@ -351,9 +357,7 @@ impl SCLowerHex for EgldOrEsdtTokenIdentifier { if self.is_egld() { f.append_bytes(EGLD_REPRESENTATION_HEX); } else { - let cast_handle = self.buffer.get_handle().cast_or_signal_error::(); - let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) }; - f.append_managed_buffer_lower_hex(&wrap_cast); + SCLowerHex::fmt(&self.token_id, f) } } } diff --git a/framework/base/src/types/managed/wrapped/token/esdt_token_identifier.rs b/framework/base/src/types/managed/wrapped/token/esdt_token_identifier.rs index a9f5f203f6..0b53bab102 100644 --- a/framework/base/src/types/managed/wrapped/token/esdt_token_identifier.rs +++ b/framework/base/src/types/managed/wrapped/token/esdt_token_identifier.rs @@ -2,11 +2,11 @@ use alloc::string::ToString; use crate::{ abi::{TypeAbi, TypeAbiFrom, TypeName}, - api::{ErrorApi, ErrorApiImpl, HandleConstraints, ManagedTypeApi, ManagedTypeApiImpl}, + api::{ErrorApi, HandleConstraints, ManagedTypeApi}, codec::*, err_msg, formatter::{FormatByteReceiver, SCDisplay, SCLowerHex}, - types::{ManagedBuffer, ManagedRef, ManagedType}, + types::{ManagedBuffer, ManagedRef, ManagedType, TokenId}, }; use super::EgldOrEsdtTokenIdentifier; @@ -20,7 +20,7 @@ pub type TokenIdentifier = EsdtTokenIdentifier; #[repr(transparent)] #[derive(Clone)] pub struct EsdtTokenIdentifier { - pub(crate) data: EgldOrEsdtTokenIdentifier, + pub(crate) token_id: TokenId, } impl ManagedType for EsdtTokenIdentifier { @@ -29,16 +29,16 @@ impl ManagedType for EsdtTokenIdentifier { #[inline] unsafe fn from_handle(handle: M::ManagedBufferHandle) -> Self { EsdtTokenIdentifier { - data: EgldOrEsdtTokenIdentifier::from_handle(handle), + token_id: TokenId::from_handle(handle), } } fn get_handle(&self) -> M::ManagedBufferHandle { - self.data.get_handle() + self.token_id.get_handle() } unsafe fn forget_into_handle(self) -> Self::OwnHandle { - self.data.forget_into_handle() + self.token_id.forget_into_handle() } fn transmute_from_handle_ref(handle_ref: &M::ManagedBufferHandle) -> &Self { @@ -57,7 +57,9 @@ impl EsdtTokenIdentifier { /// /// Calling it for the EGLD token might lead to unexpected bugs. pub unsafe fn esdt_unchecked(data: EgldOrEsdtTokenIdentifier) -> Self { - Self { data } + Self { + token_id: data.into(), + } } pub fn try_new(data: EgldOrEsdtTokenIdentifier) -> Option { @@ -75,30 +77,25 @@ impl EsdtTokenIdentifier { #[inline] pub fn into_managed_buffer(self) -> ManagedBuffer { - self.data.into_managed_buffer() + self.token_id.into_managed_buffer() } #[inline] pub fn as_managed_buffer(&self) -> &ManagedBuffer { - self.data.as_managed_buffer() + self.token_id.as_managed_buffer() } #[inline] pub fn to_boxed_bytes(&self) -> crate::types::heap::BoxedBytes { - self.data.to_boxed_bytes() + self.token_id.to_boxed_bytes() } pub fn is_valid_esdt_identifier(&self) -> bool { - M::managed_type_impl().validate_token_identifier(self.data.buffer.handle.clone()) + self.token_id.is_valid() } pub fn ticker(&self) -> ManagedBuffer { - let buffer = self.as_managed_buffer(); - let token_id_len = buffer.len(); - let ticker_len = M::managed_type_impl().get_token_ticker_len(token_id_len); - buffer.copy_slice(0, ticker_len).unwrap_or_else(|| { - M::error_api_impl().signal_error(err_msg::BAD_TOKEN_TICKER_FORMAT.as_bytes()) - }) + self.token_id.ticker() } } @@ -109,6 +106,13 @@ impl From> for EsdtTokenIdentifier { } } +impl From> for EsdtTokenIdentifier { + #[inline] + fn from(token_id: TokenId) -> Self { + EgldOrEsdtTokenIdentifier::from(token_id).unwrap_esdt() + } +} + impl From<&[u8]> for EsdtTokenIdentifier { fn from(bytes: &[u8]) -> Self { EgldOrEsdtTokenIdentifier::from(bytes).unwrap_esdt() @@ -130,7 +134,7 @@ impl From<&crate::types::heap::String> for EsdtTokenIdentifie impl PartialEq for EsdtTokenIdentifier { #[inline] fn eq(&self, other: &Self) -> bool { - self.data == other.data + self.token_id == other.token_id } } @@ -154,7 +158,7 @@ impl NestedEncode for EsdtTokenIdentifier { O: NestedEncodeOutput, H: EncodeErrorHandler, { - self.data.dep_encode_or_handle_err(dest, h) + self.token_id.dep_encode_or_handle_err(dest, h) } } @@ -165,7 +169,7 @@ impl TopEncode for EsdtTokenIdentifier { O: TopEncodeOutput, H: EncodeErrorHandler, { - self.data.top_encode_or_handle_err(output, h) + self.token_id.top_encode_or_handle_err(output, h) } } diff --git a/framework/base/src/types/managed/wrapped/token/token_id.rs b/framework/base/src/types/managed/wrapped/token/token_id.rs new file mode 100644 index 0000000000..d5e63f8493 --- /dev/null +++ b/framework/base/src/types/managed/wrapped/token/token_id.rs @@ -0,0 +1,253 @@ +use alloc::string::String; +use multiversx_chain_core::EGLD_000000_TOKEN_IDENTIFIER; + +use crate::{ + abi::{TypeAbi, TypeAbiFrom, TypeName}, + api::{quick_signal_error, HandleConstraints, ManagedTypeApi, ManagedTypeApiImpl}, + codec::*, + err_msg, + formatter::{FormatByteReceiver, SCDisplay, SCLowerHex}, + proxy_imports::TestTokenIdentifier, + types::{ + EgldOrEsdtTokenIdentifier, EsdtTokenIdentifier, ManagedBuffer, ManagedRef, ManagedType, + TokenIdentifier, + }, +}; + +/// Specialized type for handling token identifiers (e.g. ABCDEF-123456). +#[repr(transparent)] +#[derive(Debug, Clone)] +pub struct TokenId { + pub(crate) buffer: ManagedBuffer, +} + +impl ManagedType for TokenId { + type OwnHandle = M::ManagedBufferHandle; + + #[inline] + unsafe fn from_handle(handle: M::ManagedBufferHandle) -> Self { + TokenId { + buffer: ManagedBuffer::from_handle(handle), + } + } + + fn get_handle(&self) -> M::ManagedBufferHandle { + self.buffer.get_handle() + } + + unsafe fn forget_into_handle(self) -> Self::OwnHandle { + self.buffer.forget_into_handle() + } + + fn transmute_from_handle_ref(handle_ref: &M::ManagedBufferHandle) -> &Self { + unsafe { core::mem::transmute(handle_ref) } + } + + fn transmute_from_handle_ref_mut(handle_ref: &mut M::ManagedBufferHandle) -> &mut Self { + unsafe { core::mem::transmute(handle_ref) } + } +} + +impl TokenId { + pub fn new(data: ManagedBuffer) -> Self { + Self { buffer: data } + } + + pub fn new_backwards_compatible(data: ManagedBuffer) -> Self { + if data == EgldOrEsdtTokenIdentifier::::EGLD_REPRESENTATION { + Self::from(EGLD_000000_TOKEN_IDENTIFIER.as_bytes()) + } else { + Self { buffer: data } + } + } + + #[inline] + pub fn into_managed_buffer(self) -> ManagedBuffer { + self.buffer + } + + #[inline] + pub fn as_managed_buffer(&self) -> &ManagedBuffer { + &self.buffer + } + + #[inline] + pub fn into_legacy(self) -> EgldOrEsdtTokenIdentifier { + EgldOrEsdtTokenIdentifier { token_id: self } + } + + pub fn as_legacy(&self) -> &EgldOrEsdtTokenIdentifier { + // safe because of #[repr(transparent)] + unsafe { core::mem::transmute(self) } + } + + pub fn as_esdt(&self) -> &EsdtTokenIdentifier { + // safe because of #[repr(transparent)] + unsafe { core::mem::transmute(self) } + } + + #[inline] + pub fn to_boxed_bytes(&self) -> crate::types::heap::BoxedBytes { + self.buffer.to_boxed_bytes() + } + + /// Checks the ESDT token identifier for validity. + /// + /// Will fail if it encodes an invalid ESDT token identifier. + pub fn is_valid(&self) -> bool { + M::managed_type_impl().validate_token_identifier(self.buffer.handle.clone()) + } + + /// Old method name. Kept for easier transition. Use `is_valid` instead. + pub fn is_valid_esdt_identifier(&self) -> bool { + self.is_valid() + } + + /// Extracts the ticker from the token identifier. + /// + /// E.g. for "ABCDEF-123456" it will return "ABCDEF". + pub fn ticker(&self) -> ManagedBuffer { + let buffer = self.as_managed_buffer(); + let token_id_len = buffer.len(); + let ticker_len = M::managed_type_impl().get_token_ticker_len(token_id_len); + buffer + .copy_slice(0, ticker_len) + .unwrap_or_else(|| quick_signal_error::(err_msg::BAD_TOKEN_TICKER_FORMAT)) + } +} + +impl From> for TokenId { + #[inline] + fn from(buffer: ManagedBuffer) -> Self { + TokenId { buffer } + } +} + +impl From> for TokenId { + #[inline] + fn from(token_id: EgldOrEsdtTokenIdentifier) -> Self { + token_id.token_id + } +} + +impl From<&[u8]> for TokenId { + fn from(bytes: &[u8]) -> Self { + TokenId { + buffer: ManagedBuffer::new_from_bytes(bytes), + } + } +} + +impl From<&[u8; N]> for TokenId { + fn from(bytes: &[u8; N]) -> Self { + TokenId { + buffer: ManagedBuffer::new_from_bytes(bytes), + } + } +} + +impl From<&str> for TokenId { + fn from(s: &str) -> Self { + TokenId::from(s.as_bytes()) + } +} + +impl From<&String> for TokenId { + fn from(s: &String) -> Self { + TokenId::from(s.as_bytes()) + } +} + +impl PartialEq for TokenId { + #[inline] + fn eq(&self, other: &Self) -> bool { + self.buffer == other.buffer + } +} + +impl Eq for TokenId {} + +impl NestedEncode for TokenId { + #[inline] + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + where + O: NestedEncodeOutput, + H: EncodeErrorHandler, + { + self.buffer.dep_encode_or_handle_err(dest, h) + } +} + +impl TopEncode for TokenId { + #[inline] + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + self.buffer.top_encode_or_handle_err(output, h) + } +} + +impl NestedDecode for TokenId { + fn dep_decode_or_handle_err(input: &mut I, h: H) -> Result + where + I: NestedDecodeInput, + H: DecodeErrorHandler, + { + Ok(Self::new_backwards_compatible( + ManagedBuffer::dep_decode_or_handle_err(input, h)?, + )) + } +} + +impl TopDecode for TokenId { + fn top_decode_or_handle_err(input: I, h: H) -> Result + where + I: TopDecodeInput, + H: DecodeErrorHandler, + { + Ok(Self::new_backwards_compatible( + ManagedBuffer::top_decode_or_handle_err(input, h)?, + )) + } +} + +impl TypeAbiFrom> for TokenId where M: ManagedTypeApi {} +impl TypeAbiFrom<&TokenIdentifier> for TokenId where M: ManagedTypeApi {} +impl TypeAbiFrom<&[u8]> for TokenId where M: ManagedTypeApi {} +impl TypeAbiFrom<&str> for TokenId where M: ManagedTypeApi {} + +impl TypeAbiFrom> for TokenId where M: ManagedTypeApi {} +impl TypeAbiFrom<&TestTokenIdentifier<'_>> for TokenId where M: ManagedTypeApi {} + +impl TypeAbiFrom for TokenId {} +impl TypeAbiFrom<&Self> for TokenId {} + +impl TypeAbi for TokenId { + type Unmanaged = Self; + + fn type_name() -> TypeName { + "TokenId".into() + } + + fn type_name_rust() -> TypeName { + "TokenId<$API>".into() + } +} + +impl SCDisplay for TokenId { + fn fmt(&self, f: &mut F) { + let cast_handle = self.buffer.get_handle().cast_or_signal_error::(); + let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) }; + f.append_managed_buffer(&wrap_cast); + } +} + +impl SCLowerHex for TokenId { + fn fmt(&self, f: &mut F) { + let cast_handle = self.buffer.get_handle().cast_or_signal_error::(); + let wrap_cast = unsafe { ManagedRef::wrap_handle(cast_handle) }; + f.append_managed_buffer_lower_hex(&wrap_cast); + } +} diff --git a/framework/scenario/src/scenario_macros.rs b/framework/scenario/src/scenario_macros.rs index d5cdb46922..4971f09f57 100644 --- a/framework/scenario/src/scenario_macros.rs +++ b/framework/scenario/src/scenario_macros.rs @@ -36,9 +36,9 @@ macro_rules! managed_token_id { #[macro_export] macro_rules! managed_token_id_wrapped { ($bytes:expr) => {{ - let ___esdt_token_id___ = - multiversx_sc::types::EsdtTokenIdentifier::from_esdt_bytes($bytes); - multiversx_sc::types::EgldOrEsdtTokenIdentifier::esdt(___esdt_token_id___) + multiversx_sc::types::EgldOrEsdtTokenIdentifier::esdt( + multiversx_sc::types::EsdtTokenIdentifier::from_esdt_bytes($bytes), + ) }}; } @@ -49,6 +49,13 @@ macro_rules! managed_egld_token_id { }}; } +#[macro_export] +macro_rules! token_id { + ($bytes:expr) => {{ + multiversx_sc::types::TokenId::from($bytes) + }}; +} + #[macro_export] macro_rules! assert_sc_error { ($sc_result:expr, $expected_string:expr) => {{ diff --git a/framework/scenario/tests/token_identifier_test.rs b/framework/scenario/tests/token_id_legacy_test.rs similarity index 99% rename from framework/scenario/tests/token_identifier_test.rs rename to framework/scenario/tests/token_id_legacy_test.rs index bf84248069..6a610a8965 100644 --- a/framework/scenario/tests/token_identifier_test.rs +++ b/framework/scenario/tests/token_id_legacy_test.rs @@ -13,12 +13,15 @@ fn test_egld() { } #[test] -fn test_codec() { +fn test_codec_top() { check_managed_top_encode_decode( EgldOrEsdtTokenIdentifier::::egld(), EgldOrEsdtTokenIdentifier::::EGLD_REPRESENTATION, ); +} +#[test] +fn test_codec_nested() { let expected = BoxedBytes::from_concat(&[ &[0, 0, 0, 4], &EgldOrEsdtTokenIdentifier::::EGLD_REPRESENTATION[..], diff --git a/framework/scenario/tests/token_id_test.rs b/framework/scenario/tests/token_id_test.rs new file mode 100644 index 0000000000..30f983d431 --- /dev/null +++ b/framework/scenario/tests/token_id_test.rs @@ -0,0 +1,224 @@ +use multiversx_sc::{ + chain_core::EGLD_000000_TOKEN_IDENTIFIER, + types::{ + BoxedBytes, EgldOrEsdtTokenIdentifier, EgldOrEsdtTokenPayment, EsdtTokenPayment, + ManagedBuffer, TokenId, + }, +}; +use multiversx_sc_scenario::{ + api::StaticApi, managed_test_util::check_managed_top_encode_decode, multiversx_sc, token_id, +}; + +#[test] +fn test_codec_top() { + check_managed_top_encode_decode( + TokenId::::from(EGLD_000000_TOKEN_IDENTIFIER), + EGLD_000000_TOKEN_IDENTIFIER.as_bytes(), + ); +} + +#[test] +fn test_codec_nested() { + let expected = BoxedBytes::from_concat(&[ + &[0, 0, 0, EGLD_000000_TOKEN_IDENTIFIER.len() as u8], + EGLD_000000_TOKEN_IDENTIFIER.as_bytes(), + ]); + check_managed_top_encode_decode( + vec![TokenId::::from(EGLD_000000_TOKEN_IDENTIFIER)], + expected.as_slice(), + ); +} + +#[test] +#[rustfmt::skip] +fn test_is_valid_esdt_identifier() { + // valid identifier + assert!(TokenId::::from("ALC-6258d2").is_valid_esdt_identifier()); + + // valid identifier with numbers in ticker + assert!(TokenId::::from("ALC123-6258d2").is_valid_esdt_identifier()); + + // valid ticker only numbers + assert!(TokenId::::from("12345-6258d2").is_valid_esdt_identifier()); + + // missing dash + assert!(!TokenId::::from("ALC6258d2").is_valid_esdt_identifier()); + + // wrong dash position + assert!(!TokenId::::from("AL-C6258d2").is_valid_esdt_identifier()); + + // lowercase ticker + assert!(!TokenId::::from("alc-6258d2").is_valid_esdt_identifier()); + + // uppercase random chars + assert!(!TokenId::::from("ALC-6258D2").is_valid_esdt_identifier()); + + // too many random chars + assert!(!TokenId::::from("ALC-6258d2ff").is_valid_esdt_identifier()); + + // ticker too short + assert!(!TokenId::::from("AL-6258d2").is_valid_esdt_identifier()); + + // ticker too long + assert!(!TokenId::::from("ALCCCCCCCCC-6258d2").is_valid_esdt_identifier()); +} + +#[test] +#[rustfmt::skip] +fn test_ticker() { + // valid identifier + assert_eq!( + TokenId::::from("ALC-6258d2").ticker(), + ManagedBuffer::::from("ALC"), + ); + + // valid identifier with numbers in ticker + assert_eq!( + TokenId::::from("ALC123-6258d2").ticker(), + ManagedBuffer::::from("ALC123"), + ); + + // valid ticker only numbers + assert_eq!( + TokenId::::from("12345-6258d2").ticker(), + ManagedBuffer::::from("12345"), + ); + + // missing dash + assert_eq!( + TokenId::::from("ALC6258d2").ticker(), + ManagedBuffer::::from("AL"), + ); + + // wrong dash position + assert_eq!( + TokenId::::from("AL-C6258d2").ticker(), + ManagedBuffer::::from("AL-"), + ); + + // lowercase ticker + assert_eq!( + TokenId::::from("alc-6258d2").ticker(), + ManagedBuffer::::from("alc"), + ); + + // uppercase random chars + assert_eq!( + TokenId::::from("ALC-6258D2").ticker(), + ManagedBuffer::::from("ALC"), + ); + + // too many random chars + assert_eq!( + TokenId::::from("ALC-6258d2ff").ticker(), + ManagedBuffer::::from("ALC-6"), + ); + + // ticker too short + assert_eq!( + TokenId::::from("AL-6258d2").ticker(), + ManagedBuffer::::from("AL"), + ); + + // ticker too long + assert_eq!( + TokenId::::from("ALCCCCCCCCC-6258d2").ticker(), + ManagedBuffer::::from("ALCCCCCCCCC"), + ); +} + +#[test] +fn test_is_valid_egld_or_esdt() { + // egld is always valid + assert!(EgldOrEsdtTokenIdentifier::::egld().is_valid()); + + // valid esdt + assert!(EgldOrEsdtTokenIdentifier::::esdt(TokenId::from("ALC-6258d2")).is_valid()); + + // invalid esdt, see above + assert!( + !EgldOrEsdtTokenIdentifier::::esdt(TokenId::from("ALCCCCCCCCC-6258d2")) + .is_valid() + ); +} + +#[test] +fn test_token_identifier_eq() { + assert_eq!( + TokenId::::from("ESDT-00000"), + TokenId::::from("ESDT-00000") + ); + assert_ne!( + TokenId::::from("ESDT-00001"), + TokenId::::from("ESDT-00002") + ); + + assert_eq!( + EgldOrEsdtTokenIdentifier::::esdt(TokenId::from("ESDT-00003")), + TokenId::::from("ESDT-00003").into_legacy() + ); + assert_ne!( + EgldOrEsdtTokenIdentifier::::egld(), + TokenId::::from("ANYTHING-1234").into_legacy() + ); + assert_ne!( + EgldOrEsdtTokenIdentifier::::egld(), + TokenId::::from("EGLD").into_legacy() + ); +} + +#[test] +fn test_payment_eq() { + assert_eq!( + EsdtTokenPayment::::new("PAY-00000".into(), 0, 1000u32.into()), + EsdtTokenPayment::::new("PAY-00000".into(), 0, 1000u32.into()), + ); + assert_ne!( + EsdtTokenPayment::::new("PAY-00001".into(), 0, 1000u32.into()), + EsdtTokenPayment::::new("PAY-00002".into(), 0, 1000u32.into()), + ); + assert_eq!( + EgldOrEsdtTokenPayment::::no_payment(), + EgldOrEsdtTokenPayment::::no_payment(), + ); + assert_eq!( + EgldOrEsdtTokenPayment::::new( + EgldOrEsdtTokenIdentifier::esdt("ESDTPAY-00000"), + 0, + 1000u32.into() + ), + EgldOrEsdtTokenPayment::::new( + EgldOrEsdtTokenIdentifier::esdt("ESDTPAY-00000"), + 0, + 1000u32.into() + ), + ); + assert_ne!( + EgldOrEsdtTokenPayment::::new( + EgldOrEsdtTokenIdentifier::esdt("ESDTPAY-00001"), + 0, + 1000u32.into() + ), + EgldOrEsdtTokenPayment::::new( + EgldOrEsdtTokenIdentifier::esdt("ESDTPAY-00002"), + 0, + 1000u32.into() + ), + ); + assert_ne!( + EgldOrEsdtTokenPayment::::new( + EgldOrEsdtTokenIdentifier::esdt("ESDTPAY-00001"), + 0, + 1000u32.into() + ), + EgldOrEsdtTokenPayment::::no_payment(), + ); +} + +#[test] +fn test_managed_token_id_macro() { + assert_eq!( + token_id!(b"ALC-6258d2"), + TokenId::::from("ALC-6258d2") + ); +} diff --git a/tools/rust-debugger/format-tests/src/format_tests.rs b/tools/rust-debugger/format-tests/src/format_tests.rs index 5fd8628615..95e60c24c3 100644 --- a/tools/rust-debugger/format-tests/src/format_tests.rs +++ b/tools/rust-debugger/format-tests/src/format_tests.rs @@ -92,8 +92,10 @@ fn main() { ManagedByteArray::new_from_bytes(b"test"); push!(to_check, managed_byte_array, "\"test\" - (4) 0x74657374"); - let managed_option_some_token_identifier: ManagedOption> = - ManagedOption::some(token_identifier.clone()); + let managed_option_some_token_identifier: ManagedOption< + DebugApi, + EsdtTokenIdentifier, + > = ManagedOption::some(token_identifier.clone()); push!( to_check, managed_option_some_token_identifier, diff --git a/tools/rust-debugger/pretty-printers/multiversx_sc_lldb_pretty_printers.py b/tools/rust-debugger/pretty-printers/multiversx_sc_lldb_pretty_printers.py index 6886a55dcd..21c6170706 100644 --- a/tools/rust-debugger/pretty-printers/multiversx_sc_lldb_pretty_printers.py +++ b/tools/rust-debugger/pretty-printers/multiversx_sc_lldb_pretty_printers.py @@ -369,7 +369,7 @@ def value_summary(self, big_uint: lldb.value, context: lldb.value, type_info: ll class EsdtTokenIdentifier(PlainManagedVecItem, ManagedType): def lookup(self, token_identifier: lldb.value) -> lldb.value: - return token_identifier.data.buffer + return token_identifier.token_id.buffer def value_summary(self, buffer: lldb.value, context: lldb.value, type_info: lldb.SBType) -> str: return buffer_as_string(buffer) @@ -454,7 +454,7 @@ def to_string(self, token_id: str, nonce: int, amount: str) -> str: class EgldOrEsdtTokenIdentifier(PlainManagedVecItem, ManagedType): def lookup(self, egld_or_esdt_token_identifier: lldb.value) -> lldb.value: - return egld_or_esdt_token_identifier.buffer + return egld_or_esdt_token_identifier.token_id.buffer def value_summary(self, buffer: lldb.value, context: lldb.value, type_info: lldb.SBType) -> str: token_id = buffer_as_string(buffer)