Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(dan)!: update nft address format #1129

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
5cde4a7
fix(dan): update nft address format
therealdannzor Sep 3, 2024
0e24bb1
fix(dan): various autogenerated bindings
therealdannzor Sep 3, 2024
a14e185
fix(dan): remove print
therealdannzor Sep 3, 2024
682624d
Merge branch 'development' into fix-improve-nft-address-format
therealdannzor Sep 3, 2024
9753a80
fix(dan): update nft address format
therealdannzor Sep 3, 2024
2e6d8bc
Merge branch 'fix-improve-nft-address-format' of github.com:therealda…
therealdannzor Sep 3, 2024
ffe9835
Merge branch 'development' into fix-improve-nft-address-format
therealdannzor Sep 3, 2024
e24adf9
chore: make linter happy
therealdannzor Sep 3, 2024
8345396
Merge branch
therealdannzor Sep 3, 2024
5d5385a
fix(dan): nft format comment
therealdannzor Sep 3, 2024
605ed6a
chore: linter happy
therealdannzor Sep 3, 2024
8f0d90f
fix(dan): update nft address format
therealdannzor Sep 4, 2024
6282dd6
chore: linter happy
therealdannzor Sep 4, 2024
d7e0f4c
Merge branch 'development' into fix-improve-nft-address-format
therealdannzor Sep 4, 2024
0f4679e
Merge branch 'development' into fix-improve-nft-address-format
therealdannzor Sep 4, 2024
8dbaee2
fix(dan): refactor nft address parse
therealdannzor Sep 4, 2024
6863eb7
chore: linter and revert change
therealdannzor Sep 4, 2024
8dd22e6
ensure that substate_id to_string and from_str impls are correct (test)
sdbondi Sep 5, 2024
aa85277
rebuild bindings
sdbondi Sep 5, 2024
9430bcd
fix mint_specific_id test
sdbondi Sep 5, 2024
7ea5281
fix .license.ignore
sdbondi Sep 5, 2024
d7c253d
Merge branch 'development' into fix-improve-nft-address-format
sdbondi Sep 5, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .license.ignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
./applications/tari_indexer/src/substate_storage_sqlite/schema.rs
./networking/sqlite_message_logger/src/schema.rs
./dan_layer/storage_sqlite/src/global/schema.rs
./dan_layer/state_store_sqlite/src/schema.rs
./dan_layer/wallet/storage_sqlite/src/schema.rs
./networking/sqlite_message_logger/src/schema.rs
1 change: 1 addition & 0 deletions bindings/dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ export * from "./types/SubstateDiff";
export * from "./types/SubstateId";
export * from "./types/SubstateLockType";
export * from "./types/SubstateRecord";
export * from "./types/SubstateRequirementLockIntent";
export * from "./types/SubstateRequirement";
export * from "./types/Substate";
export * from "./types/SubstateType";
Expand Down
1 change: 1 addition & 0 deletions bindings/dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ export * from "./types/SubstateDiff";
export * from "./types/SubstateId";
export * from "./types/SubstateLockType";
export * from "./types/SubstateRecord";
export * from "./types/SubstateRequirementLockIntent";
export * from "./types/SubstateRequirement";
export * from "./types/Substate";
export * from "./types/SubstateType";
Expand Down
7 changes: 7 additions & 0 deletions bindings/dist/types/SubstateRequirementLockIntent.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import type { SubstateLockType } from "./SubstateLockType";
import type { SubstateRequirement } from "./SubstateRequirement";
export interface SubstateRequirementLockIntent {
substate_requirement: SubstateRequirement;
version_to_lock: number;
lock_type: SubstateLockType;
}
1 change: 1 addition & 0 deletions bindings/dist/types/SubstateRequirementLockIntent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {};
1 change: 1 addition & 0 deletions bindings/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export * from "./types/SubstateDiff";
export * from "./types/SubstateId";
export * from "./types/SubstateLockType";
export * from "./types/SubstateRecord";
export * from "./types/SubstateRequirementLockIntent";
export * from "./types/SubstateRequirement";
export * from "./types/Substate";
export * from "./types/SubstateType";
Expand Down
9 changes: 9 additions & 0 deletions bindings/src/types/SubstateRequirementLockIntent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { SubstateLockType } from "./SubstateLockType";
import type { SubstateRequirement } from "./SubstateRequirement";

export interface SubstateRequirementLockIntent {
substate_requirement: SubstateRequirement;
version_to_lock: number;
lock_type: SubstateLockType;
}
8 changes: 4 additions & 4 deletions dan_layer/engine/tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -759,16 +759,16 @@ mod basic_nft {
.collect::<Vec<_>>();
assert_eq!(
nfts.iter()
.filter(|n| n.to_canonical_string() == "str:SpecialNft")
.filter(|n| n.to_canonical_string() == "str_SpecialNft")
.count(),
1
);
assert_eq!(nfts.iter().filter(|n| n.to_canonical_string() == "u32:123").count(), 1);
assert_eq!(nfts.iter().filter(|n| n.to_canonical_string() == "u64:456").count(), 1);
assert_eq!(nfts.iter().filter(|n| n.to_canonical_string() == "u32_123").count(), 1);
assert_eq!(nfts.iter().filter(|n| n.to_canonical_string() == "u64_456").count(), 1);
assert_eq!(
nfts.iter()
.filter(|n| n.to_canonical_string() ==
"uuid:746869732077696c6c20626520696e7465727072657465642061732075756964")
"uuid_746869732077696c6c20626520696e7465727072657465642061732075756964")
.count(),
1
);
Expand Down
79 changes: 41 additions & 38 deletions dan_layer/engine_types/src/substate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,33 +355,20 @@ impl FromStr for SubstateId {
Ok(SubstateId::Component(addr))
},
Some(("resource", addr)) => {
match addr.split_once(' ') {
Some((resource_str, addr)) => match addr.split_once('_') {
// resource_xxxx nft_xxxxx
Some(("nft", _)) => {
let nft_address =
NonFungibleAddress::from_str(s).map_err(|e| InvalidSubstateIdFormat(e.to_string()))?;
Ok(SubstateId::NonFungible(nft_address))
},
// resource_xxxx index_
Some(("index", index_str)) => {
let resource_addr = ResourceAddress::from_hex(resource_str)
.map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
let index = u64::from_str(index_str).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Ok(SubstateId::NonFungibleIndex(NonFungibleIndexAddress::new(
resource_addr,
index,
)))
},
_ => Err(InvalidSubstateIdFormat(s.to_string())),
},
// resource_xxxx
None => {
let addr =
ResourceAddress::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Ok(SubstateId::Resource(addr))
},
}
// resource_xxxxx
let addr = ResourceAddress::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Ok(SubstateId::Resource(addr))
},
Some(("nft", rest)) => {
// 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}
let addr =
NonFungibleIndexAddress::from_str(rest).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Ok(SubstateId::NonFungibleIndex(addr))
},
Some(("vault", addr)) => {
let id = VaultId::from_hex(addr).map_err(|_| InvalidSubstateIdFormat(s.to_string()))?;
Expand Down Expand Up @@ -732,11 +719,11 @@ impl SubstateDiff {
mod tests {
use super::*;

mod substate_address_parse {
mod substate_id_parse {
use super::*;

#[test]
fn it_parses_valid_substate_addresses() {
fn it_parses_valid_substate_ids() {
SubstateId::from_str("component_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff")
.unwrap()
.as_component_address()
Expand All @@ -749,23 +736,39 @@ mod tests {
.unwrap()
.as_resource_address()
.unwrap();
SubstateId::from_str("nft_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_str_SpecialNft")
.unwrap()
.as_non_fungible_address()
.unwrap();
SubstateId::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff nft_str:SpecialNft",
)
.unwrap()
.as_non_fungible_address()
.unwrap();
SubstateId::from_str(
"resource_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff \
nft_uuid:7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
"nft_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff_uuid_7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
)
.unwrap()
.as_non_fungible_address()
.unwrap();
SubstateId::from_str("resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff index_0")
SubstateId::from_str("nftindex_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_0")
.unwrap()
.as_non_fungible_index_address()
.unwrap();
}

#[test]
fn it_parses_a_display_string() {
fn check(s: &str) {
let id = SubstateId::from_str(s).unwrap();
assert_eq!(id.to_string(), s);
}
check("component_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("vault_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("nft_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_str_SpecialNft");
check(
"nft_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff_uuid_7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
);
check("nftindex_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_0");
check("feeclaim_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("txreceipt_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
check("commitment_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff");
}
}
}
96 changes: 52 additions & 44 deletions dan_layer/template_lib/src/models/non_fungible.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ use crate::{
Hash,
};

const DELIM: char = ':';

/// The unique identification of a non-fungible token inside it's parent resource
#[serde_as]
#[derive(Debug, Clone, Ord, PartialOrd, PartialEq, Eq, Serialize, Deserialize, Hash)]
Expand Down Expand Up @@ -66,15 +64,15 @@ impl NonFungibleId {
}

/// A string in one of the following formats
/// - uuid:736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d
/// - str:my_special_nft_name
/// - u32:1234
/// - u64:1234
/// - uuid_736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d
/// - str_my_special_nft_name
/// - u32_1234
/// - u64_1234
pub fn to_canonical_string(&self) -> String {
let type_name = self.type_name();
let mut s = String::with_capacity(type_name.len() + 1 + self.str_repr_len());
s.push_str(self.type_name());
s.push(DELIM);
s.push('_');

match self {
NonFungibleId::U256(uuid) => {
Expand Down Expand Up @@ -133,7 +131,7 @@ impl NonFungibleId {
}

pub fn try_from_canonical_string(s: &str) -> Result<Self, ParseNonFungibleIdError> {
let (id_type, id) = s.split_once(':').ok_or(ParseNonFungibleIdError::InvalidFormat)?;
let (id_type, id) = s.split_once('_').ok_or(ParseNonFungibleIdError::InvalidFormat)?;
match id_type {
"uuid" => Ok(NonFungibleId::U256(
Hash::from_hex(id)
Expand Down Expand Up @@ -193,10 +191,10 @@ fn validate_nft_id_str(s: &str) -> Result<(), ParseNonFungibleIdError> {
impl Display for NonFungibleId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
NonFungibleId::U256(v) => write!(f, "uuid:{}", Hash::from(*v)),
NonFungibleId::String(s) => write!(f, "str:{}", s),
NonFungibleId::Uint32(v) => write!(f, "u32:{}", v),
NonFungibleId::Uint64(v) => write!(f, "u64:{}", v),
NonFungibleId::U256(v) => write!(f, "uuid_{}", Hash::from(*v)),
NonFungibleId::String(s) => write!(f, "str_{}", s),
NonFungibleId::Uint32(v) => write!(f, "u32_{}", v),
NonFungibleId::Uint64(v) => write!(f, "u64_{}", v),
}
}
}
Expand Down Expand Up @@ -263,20 +261,19 @@ 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),
}
// nft_{resource_hex}_{type}_{id}

let rest = s.strip_prefix("nft_").unwrap_or(s);
let (resource, nft_rest) = rest
.split_once('_')
.ok_or(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, nft_id))
}
}

Expand All @@ -288,7 +285,11 @@ impl From<NonFungibleAddressContents> for NonFungibleAddress {

impl Display for NonFungibleAddress {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} nft_{}", self.0.resource_address, self.0.id)
write!(f, "nft_")?;
for byte in self.resource_address().as_bytes() {
write!(f, "{:02x}", byte)?;
}
write!(f, "_{}", self.id())
}
}

Expand Down Expand Up @@ -438,21 +439,21 @@ mod tests {
#[test]
fn it_generates_correct_canonical_string() {
// u32
assert_eq!(NonFungibleId::from_u32(0).to_canonical_string(), "u32:0");
assert_eq!(NonFungibleId::from_u32(100000).to_canonical_string(), "u32:100000");
assert_eq!(NonFungibleId::from_u32(0).to_canonical_string(), "u32_0");
assert_eq!(NonFungibleId::from_u32(100000).to_canonical_string(), "u32_100000");
assert_eq!(
NonFungibleId::from_u32(u32::MAX).to_canonical_string(),
format!("u32:{}", u32::MAX)
format!("u32_{}", u32::MAX)
);

// u64
assert_eq!(NonFungibleId::from_u64(0).to_canonical_string(), "u64:0");
assert_eq!(NonFungibleId::from_u64(1).to_canonical_string(), "u64:1");
assert_eq!(NonFungibleId::from_u64(10).to_canonical_string(), "u64:10");
assert_eq!(NonFungibleId::from_u64(100).to_canonical_string(), "u64:100");
assert_eq!(NonFungibleId::from_u64(0).to_canonical_string(), "u64_0");
assert_eq!(NonFungibleId::from_u64(1).to_canonical_string(), "u64_1");
assert_eq!(NonFungibleId::from_u64(10).to_canonical_string(), "u64_10");
assert_eq!(NonFungibleId::from_u64(100).to_canonical_string(), "u64_100");
assert_eq!(
NonFungibleId::from_u64(u64::MAX).to_canonical_string(),
format!("u64:{}", u64::MAX)
format!("u64_{}", u64::MAX)
);

// uuid
Expand All @@ -463,17 +464,25 @@ mod tests {
.into_array()
)
.to_canonical_string(),
"uuid:736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d"
"uuid_736bab0c3af393a0423c578ddcf7e19b81086f6ecbbc148713e95da75ef8171d"
);

// string
assert_eq!(
NonFungibleId::try_from_string("hello_world")
.unwrap()
.to_canonical_string(),
"str:hello_world"
"str_hello_world"
);
}

#[test]
fn it_parses_a_display_string() {
let id = NonFungibleId::from_u32(123);
let s = id.to_string();
let id2 = NonFungibleId::try_from_canonical_string(&s).unwrap();
assert_eq!(id, id2);
}
}

mod serde_deser {
Expand Down Expand Up @@ -510,33 +519,32 @@ mod tests {
#[test]
fn it_parses_valid_strings() {
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff nft_str:SpecialNft",
"nft_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_str_SpecialNft",
)
.unwrap();
NonFungibleAddress::from_str(
"resource_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff \
nft_uuid:7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
"nft_a7cf4fd18ada7f367b1c102a9c158abc3754491665033231c5eb907fffffffff_uuid_7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32",
)
.unwrap();
}

#[test]
fn it_rejects_invalid_strings() {
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff nft_xxxxx:SpecialNft",
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_nft_xxxxx_SpecialNft",
)
.unwrap_err();
NonFungibleAddress::from_str(
"nft_uuid:7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32ffffffff",
"nft_uuid_7f19c3fe5fa13ff66a0d379fe5f9e3508acbd338db6bedd7350d8d565b2c5d32ffffffff",
)
.unwrap_err();
NonFungibleAddress::from_str("resource_x nft_str:SpecialNft").unwrap_err();
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff nft_str:",
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_nft_str_",
)
.unwrap_err();
NonFungibleAddress::from_str(
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff nftx_str:SpecialNft",
"resource_7cbfe29101c24924b1b6ccefbfff98986d648622272ae24f7585dab5ffffffff_nftx_str_SpecialNft",
)
.unwrap_err();
}
Expand Down
Loading
Loading