radix_engine_interface/blueprints/resource/non_fungible/
non_fungible_resource_manager.rs

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/// For manifest
174#[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/// For typed value, to skip any codec
188#[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/// For manifest
218#[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/// For typed value, to skip any codec
231#[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/// For manifest
255#[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/// For typed value, to skip any codec
264#[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/// For manifest
304#[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/// For typed value, to skip any codec
311#[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/// For manifest
326#[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/// For typed value, to skip any codec
333#[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/// For typed value, to skip any codec
353#[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    // TODO: ignore this variant in Scrypto for smaller code size
398    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    // At the moment I see no smart method to derive ::arbitrary::Arbitrary for type Schema, which is part of
469    // ScryptoSchema, therefore implementing arbitrary by hand.
470    // TODO: Introduce a method that generates NonFungibleDataSchema in a truly random manner
471    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}