Skip to content

Commit

Permalink
feat(template_lib): add from_str for NFT addresses (#855)
Browse files Browse the repository at this point in the history
Description
---
* Add from_str string for NFT addresses
* Refactor the `SubstateAddress` parsing for NFTs so it reuses the new
parsing

Motivation and Context
---
In template code we need a convenience method to parse a
`NonFungibleAddress`, because right now the only way is to separately do
it for the resource address, then for the NFT id and at the end build
the address.

How Has This Been Tested?
---
* New unit tests for `NonFungibleAddress` parsing
* Existing unit tests for `SubstateAddress` pass

What process can a PR reviewer use to test or verify this change?
---
Try to parse a NFT address from inside template code.

Breaking Changes
---

- [x] None
- [ ] Requires data directory to be deleted
- [ ] Other - Please specify
  • Loading branch information
mrnaveira authored Jan 2, 2024
1 parent 2a6040a commit 3b769ec
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 8 deletions.
11 changes: 4 additions & 7 deletions dan_layer/engine_types/src/substate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ use tari_template_lib::{
models::{
ComponentAddress,
NonFungibleAddress,
NonFungibleId,
NonFungibleIndexAddress,
ResourceAddress,
UnclaimedConfidentialOutputAddress,
Expand Down Expand Up @@ -296,12 +295,10 @@ impl FromStr for SubstateAddress {
match addr.split_once(' ') {
Some((resource_str, addr)) => match addr.split_once('_') {
// resource_xxxx nft_xxxxx
Some(("nft", addr)) => {
let resource_addr = ResourceAddress::from_hex(resource_str)
.map_err(|_| InvalidSubstateAddressFormat(s.to_string()))?;
let id = NonFungibleId::try_from_canonical_string(addr)
.map_err(|_| InvalidSubstateAddressFormat(s.to_string()))?;
Ok(SubstateAddress::NonFungible(NonFungibleAddress::new(resource_addr, id)))
Some(("nft", _)) => {
let nft_address = NonFungibleAddress::from_str(s)
.map_err(|e| InvalidSubstateAddressFormat(e.to_string()))?;
Ok(SubstateAddress::NonFungible(nft_address))
},
// resource_xxxx index_
Some(("index", index_str)) => {
Expand Down
80 changes: 79 additions & 1 deletion dan_layer/template_lib/src/models/non_fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
use tari_bor::BorTag;
use tari_template_abi::{
call_engine,
rust::{fmt, fmt::Display, write},
rust::{fmt, fmt::Display, str::FromStr, write},
EngineOp,
};

Expand Down Expand Up @@ -242,6 +242,27 @@ impl NonFungibleAddress {
}
}

impl FromStr for NonFungibleAddress {
type Err = ParseNonFungibleAddressError;

fn from_str(s: &str) -> Result<Self, Self::Err> {
// the expected format is "resource_xxxx nft_xxxxx"
match s.split_once(' ') {
Some((resource_str, addr_str)) => match addr_str.split_once('_') {
Some(("nft", id_str)) => {
let resource_addr = ResourceAddress::from_str(resource_str)
.map_err(|e| ParseNonFungibleAddressError::InvalidResource(e.to_string()))?;
let id = NonFungibleId::try_from_canonical_string(id_str)
.map_err(ParseNonFungibleAddressError::InvalidId)?;
Ok(NonFungibleAddress::new(resource_addr, id))
},
_ => Err(ParseNonFungibleAddressError::InvalidFormat),
},
None => Err(ParseNonFungibleAddressError::InvalidFormat),
}
}
}

impl From<NonFungibleAddressContents> for NonFungibleAddress {
fn from(contents: NonFungibleAddressContents) -> Self {
Self(BorTag::new(contents))
Expand Down Expand Up @@ -312,6 +333,27 @@ pub enum ParseNonFungibleIdError {
InvalidUint64,
}

impl Display for ParseNonFungibleIdError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}

/// All the types of errors that can occur when parsing a non-fungible addresses
#[allow(clippy::enum_variant_names)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ParseNonFungibleAddressError {
InvalidFormat,
InvalidResource(String),
InvalidId(ParseNonFungibleIdError),
}

impl Display for ParseNonFungibleAddressError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
}
}

#[cfg(test)]
mod tests {
use std::str::FromStr;
Expand Down Expand Up @@ -444,4 +486,40 @@ mod tests {
assert_eq!(r, v);
}
}

mod non_fungible_address_string {
use super::*;

#[test]
fn it_parses_valid_strings() {
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab55ff1ff64 nft_str:SpecialNft",
)
.unwrap();
NonFungibleAddress::from_str(
"resource_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fa14dfe2b \
nft_uuid:7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
)
.unwrap();
}

#[test]
fn it_rejects_invalid_strings() {
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab55ff1ff64 nft_xxxxx:SpecialNft",
)
.unwrap_err();
NonFungibleAddress::from_str("nft_uuid:7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32")
.unwrap_err();
NonFungibleAddress::from_str("resource_x nft_str:SpecialNft").unwrap_err();
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab55ff1ff64 nft_str:",
)
.unwrap_err();
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab55ff1ff64 nftx_str:SpecialNft",
)
.unwrap_err();
}
}
}

0 comments on commit 3b769ec

Please sign in to comment.