1use crate::blueprints::resource::*;
2use crate::internal_prelude::*;
3use radix_common::data::manifest::model::ManifestAddressReservation;
4use radix_common::data::manifest::ManifestValue;
5use radix_common::data::scrypto::{ScryptoCustomTypeKind, ScryptoValue, VersionedScryptoSchema};
6use radix_common::prelude::replace_self_package_address;
7use radix_common::prelude::*;
8use radix_common::traits::NonFungibleData;
9use radix_engine_interface::object_modules::metadata::MetadataInit;
10use radix_engine_interface::object_modules::ModuleConfig;
11use sbor::rust::collections::{IndexMap, IndexSet};
12use sbor::rust::string::String;
13use sbor::rust::string::ToString;
14use sbor::rust::vec::Vec;
15use sbor::{generate_full_schema, LocalTypeId, TypeAggregator};
16
17pub const NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT: &str = "NonFungibleResourceManager";
18
19#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
20#[derive(Default, Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
21pub struct NonFungibleResourceRoles {
22 pub mint_roles: Option<MintRoles<RoleDefinition>>,
23 pub burn_roles: Option<BurnRoles<RoleDefinition>>,
24 pub freeze_roles: Option<FreezeRoles<RoleDefinition>>,
25 pub recall_roles: Option<RecallRoles<RoleDefinition>>,
26 pub withdraw_roles: Option<WithdrawRoles<RoleDefinition>>,
27 pub deposit_roles: Option<DepositRoles<RoleDefinition>>,
28 pub non_fungible_data_update_roles: Option<NonFungibleDataUpdateRoles<RoleDefinition>>,
29}
30
31#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
32#[derive(Default, Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
33pub struct ManifestNonFungibleResourceRoles {
34 pub mint_roles: Option<MintRoles<ManifestRoleDefinition>>,
35 pub burn_roles: Option<BurnRoles<ManifestRoleDefinition>>,
36 pub freeze_roles: Option<FreezeRoles<ManifestRoleDefinition>>,
37 pub recall_roles: Option<RecallRoles<ManifestRoleDefinition>>,
38 pub withdraw_roles: Option<WithdrawRoles<ManifestRoleDefinition>>,
39 pub deposit_roles: Option<DepositRoles<ManifestRoleDefinition>>,
40 pub non_fungible_data_update_roles: Option<NonFungibleDataUpdateRoles<ManifestRoleDefinition>>,
41}
42
43impl From<NonFungibleResourceRoles> for ManifestNonFungibleResourceRoles {
44 fn from(value: NonFungibleResourceRoles) -> Self {
45 Self {
46 mint_roles: value.mint_roles.map(|roles| MintRoles {
47 minter: roles.minter.map(Into::into),
48 minter_updater: roles.minter_updater.map(Into::into),
49 }),
50 burn_roles: value.burn_roles.map(|roles| BurnRoles {
51 burner: roles.burner.map(Into::into),
52 burner_updater: roles.burner_updater.map(Into::into),
53 }),
54 freeze_roles: value.freeze_roles.map(|roles| FreezeRoles {
55 freezer: roles.freezer.map(Into::into),
56 freezer_updater: roles.freezer_updater.map(Into::into),
57 }),
58 recall_roles: value.recall_roles.map(|roles| RecallRoles {
59 recaller: roles.recaller.map(Into::into),
60 recaller_updater: roles.recaller_updater.map(Into::into),
61 }),
62 withdraw_roles: value.withdraw_roles.map(|roles| WithdrawRoles {
63 withdrawer: roles.withdrawer.map(Into::into),
64 withdrawer_updater: roles.withdrawer_updater.map(Into::into),
65 }),
66 deposit_roles: value.deposit_roles.map(|roles| DepositRoles {
67 depositor: roles.depositor.map(Into::into),
68 depositor_updater: roles.depositor_updater.map(Into::into),
69 }),
70 non_fungible_data_update_roles: value.non_fungible_data_update_roles.map(|roles| {
71 NonFungibleDataUpdateRoles {
72 non_fungible_data_updater: roles.non_fungible_data_updater.map(Into::into),
73 non_fungible_data_updater_updater: roles
74 .non_fungible_data_updater_updater
75 .map(Into::into),
76 }
77 }),
78 }
79 }
80}
81
82impl NonFungibleResourceRoles {
83 pub fn single_locked_rule(access_rule: AccessRule) -> Self {
84 Self {
85 mint_roles: mint_roles! {
86 minter => access_rule.clone();
87 minter_updater => rule!(deny_all);
88 },
89 burn_roles: burn_roles! {
90 burner => access_rule.clone();
91 burner_updater => rule!(deny_all);
92 },
93 freeze_roles: freeze_roles! {
94 freezer => access_rule.clone();
95 freezer_updater => rule!(deny_all);
96 },
97 recall_roles: recall_roles! {
98 recaller => access_rule.clone();
99 recaller_updater => rule!(deny_all);
100 },
101 non_fungible_data_update_roles: non_fungible_data_update_roles! {
102 non_fungible_data_updater => access_rule.clone();
103 non_fungible_data_updater_updater => rule!(deny_all);
104 },
105 withdraw_roles: withdraw_roles! {
106 withdrawer => access_rule.clone();
107 withdrawer_updater => rule!(deny_all);
108 },
109 deposit_roles: deposit_roles! {
110 depositor => access_rule;
111 depositor_updater => rule!(deny_all);
112 },
113 }
114 }
115}
116
117pub const NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT: &str = "create";
118
119#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
120#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
121pub struct NonFungibleResourceManagerCreateInput {
122 pub owner_role: OwnerRole,
123 pub id_type: NonFungibleIdType,
124 pub track_total_supply: bool,
125 pub non_fungible_schema: NonFungibleDataSchema,
126 pub resource_roles: NonFungibleResourceRoles,
127 pub metadata: ModuleConfig<MetadataInit>,
128 pub address_reservation: Option<GlobalAddressReservation>,
129}
130
131#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
132#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
133pub struct NonFungibleResourceManagerCreateManifestInput {
134 pub owner_role: ManifestOwnerRole,
135 pub id_type: NonFungibleIdType,
136 pub track_total_supply: bool,
137 pub non_fungible_schema: NonFungibleDataSchema,
138 pub resource_roles: ManifestNonFungibleResourceRoles,
139 pub metadata: ModuleConfig<ManifestMetadataInit, ManifestRoleAssignmentInit>,
140 pub address_reservation: Option<ManifestAddressReservation>,
141}
142
143#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
144#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
145pub struct NonFungibleResourceManagerCreateGenericInput<S> {
146 pub owner_role: OwnerRole,
147 pub id_type: NonFungibleIdType,
148 pub track_total_supply: bool,
149 pub non_fungible_schema: S,
150 pub resource_roles: NonFungibleResourceRoles,
151 pub metadata: ModuleConfig<MetadataInit>,
152 pub address_reservation: Option<GlobalAddressReservation>,
153}
154
155pub type NonFungibleResourceManagerCreateOutput = ResourceAddress;
156
157pub const NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT: &str =
158 "create_with_initial_supply";
159
160#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
161#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
162pub struct NonFungibleResourceManagerCreateWithInitialSupplyInput {
163 pub owner_role: OwnerRole,
164 pub id_type: NonFungibleIdType,
165 pub track_total_supply: bool,
166 pub non_fungible_schema: NonFungibleDataSchema,
167 pub entries: IndexMap<NonFungibleLocalId, (ScryptoValue,)>,
168 pub resource_roles: NonFungibleResourceRoles,
169 pub metadata: ModuleConfig<MetadataInit>,
170 pub address_reservation: Option<GlobalAddressReservation>,
171}
172
173#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
175#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
176pub struct NonFungibleResourceManagerCreateWithInitialSupplyManifestInput {
177 pub owner_role: ManifestOwnerRole,
178 pub id_type: NonFungibleIdType,
179 pub track_total_supply: bool,
180 pub non_fungible_schema: NonFungibleDataSchema,
181 pub entries: IndexMap<NonFungibleLocalId, (ManifestValue,)>,
182 pub resource_roles: ManifestNonFungibleResourceRoles,
183 pub metadata: ModuleConfig<ManifestMetadataInit, ManifestRoleAssignmentInit>,
184 pub address_reservation: Option<ManifestAddressReservation>,
185}
186
187#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
189pub struct NonFungibleResourceManagerCreateWithInitialSupplyGenericInput<S, T> {
190 pub owner_role: OwnerRole,
191 pub id_type: NonFungibleIdType,
192 pub track_total_supply: bool,
193 pub non_fungible_schema: S,
194 pub entries: IndexMap<NonFungibleLocalId, (T,)>,
195 pub resource_roles: NonFungibleResourceRoles,
196 pub metadata: ModuleConfig<MetadataInit>,
197 pub address_reservation: Option<GlobalAddressReservation>,
198}
199
200pub type NonFungibleResourceManagerCreateWithInitialSupplyOutput = (ResourceAddress, Bucket);
201
202pub const NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT: &str =
203 "create_ruid_non_fungible_with_initial_supply";
204
205#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
206#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
207pub struct NonFungibleResourceManagerCreateRuidWithInitialSupplyInput {
208 pub owner_role: OwnerRole,
209 pub track_total_supply: bool,
210 pub non_fungible_schema: NonFungibleDataSchema,
211 pub entries: Vec<(ScryptoValue,)>,
212 pub resource_roles: NonFungibleResourceRoles,
213 pub metadata: ModuleConfig<MetadataInit>,
214 pub address_reservation: Option<GlobalAddressReservation>,
215}
216
217#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
219#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
220pub struct NonFungibleResourceManagerCreateRuidWithInitialSupplyManifestInput {
221 pub owner_role: ManifestOwnerRole,
222 pub track_total_supply: bool,
223 pub non_fungible_schema: NonFungibleDataSchema,
224 pub entries: Vec<(ManifestValue,)>,
225 pub resource_roles: ManifestNonFungibleResourceRoles,
226 pub metadata: ModuleConfig<ManifestMetadataInit, ManifestRoleAssignmentInit>,
227 pub address_reservation: Option<ManifestAddressReservation>,
228}
229
230#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
232#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
233pub struct NonFungibleResourceManagerCreateRuidWithInitialSupplyGenericInput<S, T> {
234 pub owner_role: OwnerRole,
235 pub track_total_supply: bool,
236 pub non_fungible_schema: S,
237 pub entries: Vec<(T,)>,
238 pub resource_roles: NonFungibleResourceRoles,
239 pub metadata: ModuleConfig<MetadataInit>,
240 pub address_reservation: Option<GlobalAddressReservation>,
241}
242
243pub type NonFungibleResourceManagerCreateRuidWithInitialSupplyOutput = (ResourceAddress, Bucket);
244
245pub const NON_FUNGIBLE_RESOURCE_MANAGER_UPDATE_DATA_IDENT: &str = "update_non_fungible_data";
246
247#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
248pub struct NonFungibleResourceManagerUpdateDataInput {
249 pub id: NonFungibleLocalId,
250 pub field_name: String,
251 pub data: ScryptoValue,
252}
253
254#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
256#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
257pub struct NonFungibleResourceManagerUpdateDataManifestInput {
258 pub id: NonFungibleLocalId,
259 pub field_name: String,
260 pub data: ManifestValue,
261}
262
263#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
265pub struct NonFungibleResourceManagerUpdateDataGenericInput<T> {
266 pub id: NonFungibleLocalId,
267 pub field_name: String,
268 pub data: T,
269}
270
271pub type NonFungibleResourceManagerUpdateDataOutput = ();
272
273pub const NON_FUNGIBLE_RESOURCE_MANAGER_EXISTS_IDENT: &str = "non_fungible_exists";
274
275#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
276pub struct NonFungibleResourceManagerExistsInput {
277 pub id: NonFungibleLocalId,
278}
279
280pub type NonFungibleResourceManagerExistsManifestInput = NonFungibleResourceManagerExistsInput;
281
282pub type NonFungibleResourceManagerExistsOutput = bool;
283
284pub const NON_FUNGIBLE_RESOURCE_MANAGER_GET_NON_FUNGIBLE_IDENT: &str = "get_non_fungible";
285
286#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
287pub struct NonFungibleResourceManagerGetNonFungibleInput {
288 pub id: NonFungibleLocalId,
289}
290
291pub type NonFungibleResourceManagerGetNonFungibleManifestInput =
292 NonFungibleResourceManagerGetNonFungibleInput;
293
294pub type NonFungibleResourceManagerGetNonFungibleOutput = ScryptoValue;
295
296pub const NON_FUNGIBLE_RESOURCE_MANAGER_MINT_IDENT: &str = "mint";
297
298#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
299pub struct NonFungibleResourceManagerMintInput {
300 pub entries: IndexMap<NonFungibleLocalId, (ScryptoValue,)>,
301}
302
303#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
305#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
306pub struct NonFungibleResourceManagerMintManifestInput {
307 pub entries: IndexMap<NonFungibleLocalId, (ManifestValue,)>,
308}
309
310#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
312pub struct NonFungibleResourceManagerMintGenericInput<T> {
313 pub entries: IndexMap<NonFungibleLocalId, (T,)>,
314}
315
316pub type NonFungibleResourceManagerMintOutput = Bucket;
317
318pub const NON_FUNGIBLE_RESOURCE_MANAGER_MINT_RUID_IDENT: &str = "mint_ruid";
319
320#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
321pub struct NonFungibleResourceManagerMintRuidInput {
322 pub entries: Vec<(ScryptoValue,)>,
323}
324
325#[cfg_attr(feature = "fuzzing", derive(::arbitrary::Arbitrary))]
327#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
328pub struct NonFungibleResourceManagerMintRuidManifestInput {
329 pub entries: Vec<(ManifestValue,)>,
330}
331
332#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
334pub struct NonFungibleResourceManagerMintRuidGenericInput<T> {
335 pub entries: Vec<(T,)>,
336}
337
338pub type NonFungibleResourceManagerMintRuidOutput = Bucket;
339
340pub const NON_FUNGIBLE_RESOURCE_MANAGER_MINT_SINGLE_RUID_IDENT: &str = "mint_single_ruid";
341
342#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
343pub struct NonFungibleResourceManagerMintSingleRuidInput {
344 pub entry: ScryptoValue,
345}
346
347#[derive(Debug, Clone, Eq, PartialEq, ManifestSbor, ScryptoDescribe)]
348pub struct NonFungibleResourceManagerMintSingleRuidManifestInput {
349 pub entry: ManifestValue,
350}
351
352#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
354pub struct NonFungibleResourceManagerMintSingleRuidGenericInput<T> {
355 pub entry: T,
356}
357
358pub type NonFungibleResourceManagerMintSingleRuidOutput = (Bucket, NonFungibleLocalId);
359
360pub const NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL: u8 = 0;
361pub const NON_FUNGIBLE_DATA_SCHEMA_VARIANT_REMOTE: u8 = 1;
362
363pub type NonFungibleResourceManagerCreateEmptyBucketInput = ResourceManagerCreateEmptyBucketInput;
364pub type NonFungibleResourceManagerCreateEmptyBucketManifestInput =
365 NonFungibleResourceManagerCreateEmptyBucketInput;
366
367pub type NonFungibleResourceManagerPackageBurnInput = ResourceManagerPackageBurnInput;
368pub type NonFungibleResourceManagerPackageBurnManifestInput =
369 NonFungibleResourceManagerPackageBurnInput;
370
371pub type NonFungibleResourceManagerBurnInput = ResourceManagerBurnInput;
372pub type NonFungibleResourceManagerBurnManifestInput = NonFungibleResourceManagerBurnInput;
373
374pub type NonFungibleResourceManagerCreateEmptyVaultInput = ResourceManagerCreateEmptyVaultInput;
375pub type NonFungibleResourceManagerCreateEmptyVaultManifestInput =
376 NonFungibleResourceManagerCreateEmptyVaultInput;
377
378pub type NonFungibleResourceManagerGetResourceTypeInput = ResourceManagerGetResourceTypeInput;
379pub type NonFungibleResourceManagerGetResourceTypeManifestInput =
380 NonFungibleResourceManagerGetResourceTypeInput;
381
382pub type NonFungibleResourceManagerGetTotalSupplyInput = ResourceManagerGetTotalSupplyInput;
383pub type NonFungibleResourceManagerGetTotalSupplyManifestInput =
384 NonFungibleResourceManagerGetTotalSupplyInput;
385
386pub type NonFungibleResourceManagerAmountForWithdrawalInput =
387 ResourceManagerGetAmountForWithdrawalInput;
388pub type NonFungibleResourceManagerAmountForWithdrawalManifestInput =
389 NonFungibleResourceManagerAmountForWithdrawalInput;
390
391pub type NonFungibleResourceManagerDropEmptyBucketInput = ResourceManagerDropEmptyBucketInput;
392pub type NonFungibleResourceManagerDropEmptyBucketManifestInput =
393 NonFungibleResourceManagerDropEmptyBucketInput;
394
395#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor)]
396pub enum NonFungibleDataSchema {
397 Local(#[sbor(flatten)] LocalNonFungibleDataSchema),
399 Remote(#[sbor(flatten)] RemoteNonFungibleDataSchema),
400}
401
402#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor)]
403pub struct LocalNonFungibleDataSchema {
404 pub schema: VersionedScryptoSchema,
405 pub type_id: LocalTypeId,
406 pub mutable_fields: IndexSet<String>,
407}
408
409#[derive(Debug, Clone, PartialEq, Eq, ScryptoSbor, ManifestSbor)]
410pub struct RemoteNonFungibleDataSchema {
411 pub type_id: BlueprintTypeIdentifier,
412 pub mutable_fields: IndexSet<String>,
413}
414
415impl LocalNonFungibleDataSchema {
416 pub fn new_with_self_package_replacement<N: NonFungibleData>(
417 package_address: PackageAddress,
418 ) -> Self {
419 let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
420 let type_id = aggregator.add_child_type_and_descendents::<N>();
421 let mut schema = generate_full_schema(aggregator);
422 replace_self_package_address(&mut schema, package_address);
423 Self {
424 schema,
425 type_id,
426 mutable_fields: N::MUTABLE_FIELDS.iter().map(|s| s.to_string()).collect(),
427 }
428 }
429
430 pub fn new_without_self_package_replacement<N: NonFungibleData>() -> Self {
431 let mut aggregator = TypeAggregator::<ScryptoCustomTypeKind>::new();
432 let type_id = aggregator.add_child_type_and_descendents::<N>();
433 let schema = generate_full_schema(aggregator);
434 Self {
435 schema,
436 type_id,
437 mutable_fields: N::MUTABLE_FIELDS.iter().map(|s| s.to_string()).collect(),
438 }
439 }
440}
441
442impl RemoteNonFungibleDataSchema {
443 pub fn new(type_id: BlueprintTypeIdentifier, mutable_fields: IndexSet<String>) -> Self {
444 Self {
445 type_id,
446 mutable_fields,
447 }
448 }
449}
450
451impl NonFungibleDataSchema {
452 pub fn new_with_self_package_replacement<N: NonFungibleData>(
453 package_address: PackageAddress,
454 ) -> Self {
455 let schema =
456 LocalNonFungibleDataSchema::new_with_self_package_replacement::<N>(package_address);
457 Self::Local(schema)
458 }
459
460 pub fn new_local_without_self_package_replacement<N: NonFungibleData>() -> Self {
461 let schema = LocalNonFungibleDataSchema::new_without_self_package_replacement::<N>();
462 Self::Local(schema)
463 }
464}
465
466#[cfg(feature = "fuzzing")]
467impl<'a> ::arbitrary::Arbitrary<'a> for NonFungibleDataSchema {
468 fn arbitrary(_u: &mut ::arbitrary::Unstructured<'a>) -> ::arbitrary::Result<Self> {
472 Ok(Self::Local(LocalNonFungibleDataSchema {
473 schema: VersionedScryptoSchema::from_latest_version(SchemaV1 {
474 type_kinds: vec![],
475 type_metadata: vec![],
476 type_validations: vec![],
477 }),
478 type_id: LocalTypeId::WellKnown(sbor::basic_well_known_types::UNIT_TYPE),
479 mutable_fields: indexset!(),
480 }))
481 }
482}
483
484#[cfg(test)]
485mod test {
486 use super::*;
487
488 #[derive(ScryptoSbor)]
489 pub struct SomeNonFungibleData {
490 pub field: String,
491 }
492
493 impl NonFungibleData for SomeNonFungibleData {
494 const MUTABLE_FIELDS: &'static [&'static str] = &[];
495 }
496
497 #[test]
498 fn test_non_fungible_data_schema_with_self_package_replacement() {
499 pub const SOME_ADDRESS: PackageAddress =
500 PackageAddress::new_or_panic([EntityType::GlobalPackage as u8; NodeId::LENGTH]);
501
502 let ds: NonFungibleDataSchema = NonFungibleDataSchema::new_with_self_package_replacement::<
503 SomeNonFungibleData,
504 >(SOME_ADDRESS);
505 if let NonFungibleDataSchema::Local(LocalNonFungibleDataSchema {
506 schema,
507 type_id,
508 mutable_fields,
509 }) = ds
510 {
511 let s = schema.fully_update_and_into_latest_version();
512 assert_eq!(s.type_kinds.len(), 1);
513 assert_eq!(s.type_metadata.len(), 1);
514 assert_eq!(s.type_validations.len(), 1);
515 assert_matches!(type_id, LocalTypeId::SchemaLocalIndex(0));
516 assert!(mutable_fields.is_empty());
517 } else {
518 panic!("Wrong Non Fungible Data Schema type")
519 }
520 }
521}