From 8dbaee29a3587b91df80df949205bedeff89034a Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 4 Sep 2024 15:00:36 +0100 Subject: [PATCH] fix(dan): refactor nft address parse --- dan_layer/engine_types/src/substate.rs | 56 +++++------------ .../template_lib/src/models/non_fungible.rs | 62 ++++--------------- 2 files changed, 28 insertions(+), 90 deletions(-) diff --git a/dan_layer/engine_types/src/substate.rs b/dan_layer/engine_types/src/substate.rs index 01c89d255..46ad1f483 100644 --- a/dan_layer/engine_types/src/substate.rs +++ b/dan_layer/engine_types/src/substate.rs @@ -30,15 +30,10 @@ use tari_bor::{decode, decode_exact, encode, BorError}; use tari_common_types::types::FixedHash; use tari_template_lib::{ models::{ - ComponentAddress, - NonFungibleAddress, - NonFungibleIndexAddress, - ObjectKey, - ResourceAddress, - UnclaimedConfidentialOutputAddress, - VaultId, + ComponentAddress, NonFungibleAddress, NonFungibleIndexAddress, ObjectKey, ResourceAddress, + UnclaimedConfidentialOutputAddress, VaultId, }, - prelude::{NonFungibleId, PUBLIC_IDENTITY_RESOURCE_ADDRESS}, + prelude::PUBLIC_IDENTITY_RESOURCE_ADDRESS, Hash, }; #[cfg(feature = "ts")] @@ -152,14 +147,14 @@ impl SubstateId { /// Returns true for any substate that has is "versionable" i.e. can have a version > 0, otherwise false. pub fn is_versioned(&self) -> bool { match self { - SubstateId::Component(_) | - SubstateId::Resource(_) | - SubstateId::Vault(_) | - SubstateId::NonFungibleIndex(_) | - SubstateId::NonFungible(_) => true, - SubstateId::UnclaimedConfidentialOutput(_) | - SubstateId::TransactionReceipt(_) | - SubstateId::FeeClaim(_) => false, + SubstateId::Component(_) + | SubstateId::Resource(_) + | SubstateId::Vault(_) + | SubstateId::NonFungibleIndex(_) + | SubstateId::NonFungible(_) => true, + SubstateId::UnclaimedConfidentialOutput(_) + | SubstateId::TransactionReceipt(_) + | SubstateId::FeeClaim(_) => false, } } @@ -351,31 +346,14 @@ impl FromStr for SubstateId { Ok(SubstateId::Component(addr)) }, Some(("resource", addr)) => { - if addr.split_once('_').is_none() { - // resource_xxxxx - let addr = ResourceAddress::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?; - return Ok(SubstateId::Resource(addr)); - } - Err(InvalidSubstateIdFormat("Missing resource address".to_string())) + // resource_xxxxx + let addr = ResourceAddress::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?; + Ok(SubstateId::Resource(addr)) }, Some(("nft", rest)) => { - // nft_{resource_addr}_{id_type}_{id} - let (resource, nft_rest) = rest - .split_once('_') - .ok_or_else(|| InvalidSubstateIdFormat(s.to_string()))?; - - let resource_addr = - ResourceAddress::from_hex(resource).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?; - - let (id_type, id) = nft_rest - .split_once('_') - .ok_or_else(|| InvalidSubstateIdFormat(s.to_string()))?; - - let nft_id = NonFungibleId::try_from_canonical_string(&format!("{id_type}_{id}")) - .map_err(|_| InvalidSubstateIdFormat(s.to_string()))?; - - let full_addr = NonFungibleAddress::new(resource_addr, nft_id); - Ok(SubstateId::NonFungible(full_addr)) + // nft_{resource_hex}_{id_type}_{id} + let addr = NonFungibleAddress::from_str(rest).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?; + Ok(SubstateId::NonFungible(addr)) }, Some(("nftindex", rest)) => { // nftindex_{resource_id}_{index} diff --git a/dan_layer/template_lib/src/models/non_fungible.rs b/dan_layer/template_lib/src/models/non_fungible.rs index 0bb62cf35..030312736 100644 --- a/dan_layer/template_lib/src/models/non_fungible.rs +++ b/dan_layer/template_lib/src/models/non_fungible.rs @@ -133,25 +133,7 @@ impl NonFungibleId { } pub fn try_from_canonical_string(s: &str) -> Result { - let mut splitted = s.split('_'); - - // ideally wanted this method to receive `id_type` and `id` but since it is used elsewhere, - // this will keep it compatible with the rest of the code, so potentially doing the same token parsing - // again is easier - let id_type: &str; - if let Some(token) = splitted.next() { - id_type = token; - } else { - return Err(ParseNonFungibleIdError::InvalidFormat); - } - - let id: &str; - if let Some(token) = splitted.next() { - id = token; - } else { - return Err(ParseNonFungibleIdError::InvalidFormat); - } - + let (id_type, id) = s.split_once('_').ok_or(ParseNonFungibleIdError::InvalidFormat)?; match id_type { "uuid" => Ok(NonFungibleId::U256( Hash::from_hex(id) @@ -281,41 +263,19 @@ impl FromStr for NonFungibleAddress { type Err = ParseNonFungibleAddressError; fn from_str(s: &str) -> Result { - // the expected format is nft_{resource_hex}_{type}_{id} - let mut splitted = s.split('_'); + // nft_{resource_hex}_{type}_{id} - if let Some(token) = splitted.next() { - if token != "nft" { - return Err(ParseNonFungibleAddressError::InvalidFormat); - } - } else { - return Err(ParseNonFungibleAddressError::InvalidFormat); - } + let rest = s.strip_prefix("nft_").unwrap_or(s); + let (resource, nft_rest) = rest + .split_once('_') + .ok_or(ParseNonFungibleAddressError::InvalidFormat)?; - let resource_addr: ResourceAddress; - if let Some(token) = splitted.next() { - resource_addr = ResourceAddress::from_str(token) - .map_err(|e| ParseNonFungibleAddressError::InvalidResource(e.to_string()))?; - } else { - return Err(ParseNonFungibleAddressError::InvalidFormat); - } - - let id_type: &str; - if let Some(token) = splitted.next() { - id_type = token; - } else { - return Err(ParseNonFungibleAddressError::InvalidFormat); - } - - let id: NonFungibleId; - if let Some(token) = splitted.next() { - id = NonFungibleId::try_from_canonical_string(&format!("{id_type}_{token}")) - .map_err(ParseNonFungibleAddressError::InvalidId)?; - } else { - return Err(ParseNonFungibleAddressError::InvalidFormat); - } + let resource_addr = + ResourceAddress::from_hex(resource).map_err(|_| ParseNonFungibleAddressError::InvalidFormat)?; + let nft_id = NonFungibleId::try_from_canonical_string(nft_rest) + .map_err(|_| ParseNonFungibleAddressError::InvalidFormat)?; - Ok(NonFungibleAddress::new(resource_addr, id)) + Ok(NonFungibleAddress::new(resource_addr, nft_id)) } }