Skip to main content

scrypto/resource/
resource_builder.rs

1use crate::engine::scrypto_env::ScryptoVmV1Api;
2use crate::runtime::Runtime;
3use radix_common::constants::RESOURCE_PACKAGE;
4use radix_common::data::scrypto::model::*;
5use radix_common::prelude::*;
6use radix_common::traits::NonFungibleData;
7use radix_engine_interface::blueprints::resource::*;
8use radix_engine_interface::object_modules::metadata::MetadataInit;
9use radix_engine_interface::object_modules::role_assignment::RoleDefinition;
10use radix_engine_interface::object_modules::ModuleConfig;
11use scrypto::resource::{FungibleResourceManager, NonFungibleResourceManager};
12
13/// Not divisible.
14pub const DIVISIBILITY_NONE: u8 = 0;
15/// The maximum divisibility supported.
16pub const DIVISIBILITY_MAXIMUM: u8 = 18;
17
18/// Utility for setting up a new resource.
19///
20/// * You start the building process with one of the methods starting with `new_`.
21/// * The allowed methods change depending on which methods have already been called.
22///   For example, you can either use `owner_non_fungible_badge` or set access rules individually, but not both.
23/// * You can complete the building process using either `create_with_no_initial_supply()` or `mint_initial_supply(..)`.
24///
25/// ### Example
26/// ```no_run
27/// use scrypto::prelude::*;
28///
29/// let bucket = ResourceBuilder::new_fungible(OwnerRole::None)
30///     .mint_initial_supply(5);
31/// ```
32pub struct ResourceBuilder;
33
34impl ResourceBuilder {
35    /// Starts a new builder to create a fungible resource.
36    pub fn new_fungible(owner_role: OwnerRole) -> InProgressResourceBuilder<FungibleResourceType> {
37        InProgressResourceBuilder::new(owner_role, FungibleResourceType::default())
38    }
39
40    /// Starts a new builder to create a non-fungible resource with a `NonFungibleIdType::String`
41    pub fn new_string_non_fungible<D: NonFungibleData>(
42        owner_role: OwnerRole,
43    ) -> InProgressResourceBuilder<
44        NonFungibleResourceType<
45            StringNonFungibleLocalId,
46            D,
47            SborFixedEnumVariant<
48                NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
49                LocalNonFungibleDataSchema,
50            >,
51        >,
52    > {
53        InProgressResourceBuilder::new(
54            owner_role,
55            NonFungibleResourceType::new(SborFixedEnumVariant {
56                fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
57                    Runtime::package_address(),
58                ),
59            }),
60        )
61    }
62
63    /// Starts a new builder to create a non-fungible resource with a `NonFungibleIdType::Integer`
64    pub fn new_integer_non_fungible<D: NonFungibleData>(
65        owner_role: OwnerRole,
66    ) -> InProgressResourceBuilder<
67        NonFungibleResourceType<
68            IntegerNonFungibleLocalId,
69            D,
70            SborFixedEnumVariant<
71                NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
72                LocalNonFungibleDataSchema,
73            >,
74        >,
75    > {
76        InProgressResourceBuilder::new(
77            owner_role,
78            NonFungibleResourceType::new(SborFixedEnumVariant {
79                fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
80                    Runtime::package_address(),
81                ),
82            }),
83        )
84    }
85
86    /// Starts a new builder to create a non-fungible resource with a `NonFungibleIdType::Bytes`
87    pub fn new_bytes_non_fungible<D: NonFungibleData>(
88        owner_role: OwnerRole,
89    ) -> InProgressResourceBuilder<
90        NonFungibleResourceType<
91            BytesNonFungibleLocalId,
92            D,
93            SborFixedEnumVariant<
94                NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
95                LocalNonFungibleDataSchema,
96            >,
97        >,
98    > {
99        InProgressResourceBuilder::new(
100            owner_role,
101            NonFungibleResourceType::new(SborFixedEnumVariant {
102                fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
103                    Runtime::package_address(),
104                ),
105            }),
106        )
107    }
108
109    /// Starts a new builder to create a non-fungible resource with a `NonFungibleIdType::RUID`
110    pub fn new_ruid_non_fungible<D: NonFungibleData>(
111        owner_role: OwnerRole,
112    ) -> InProgressResourceBuilder<
113        NonFungibleResourceType<
114            RUIDNonFungibleLocalId,
115            D,
116            SborFixedEnumVariant<
117                NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
118                LocalNonFungibleDataSchema,
119            >,
120        >,
121    > {
122        InProgressResourceBuilder::new(
123            owner_role,
124            NonFungibleResourceType::new(SborFixedEnumVariant {
125                fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
126                    Runtime::package_address(),
127                ),
128            }),
129        )
130    }
131}
132
133/// Utility for setting up a new resource, which has building in progress.
134///
135/// * You start the building process with one of the methods starting with `ResourceBuilder::new_`.
136/// * The allowed methods change depending on which methods have already been called.
137///   For example, you can either use `owner_non_fungible_badge` or set access rules individually, but not both.
138/// * You can complete the building process using either `create_with_no_initial_supply()` or `mint_initial_supply(..)`.
139///
140/// ### Example
141/// ```no_run
142/// use scrypto::prelude::*;
143///
144/// let bucket = ResourceBuilder::new_fungible(OwnerRole::None)
145///     .mint_initial_supply(5);
146/// ```
147#[must_use]
148pub struct InProgressResourceBuilder<T: AnyResourceType> {
149    owner_role: OwnerRole,
150    resource_type: T,
151    resource_roles: T::ResourceRoles,
152    metadata_config: Option<ModuleConfig<MetadataInit>>,
153    address_reservation: Option<GlobalAddressReservation>,
154}
155
156impl<T: AnyResourceType> InProgressResourceBuilder<T> {
157    pub fn new(owner_role: OwnerRole, resource_type: T) -> Self {
158        Self {
159            owner_role,
160            resource_type,
161            metadata_config: None,
162            address_reservation: None,
163            resource_roles: T::ResourceRoles::default(),
164        }
165    }
166}
167
168// Various types for ResourceType
169pub trait AnyResourceType {
170    type ResourceRoles: Default;
171}
172
173pub struct FungibleResourceType {
174    divisibility: u8,
175}
176impl AnyResourceType for FungibleResourceType {
177    type ResourceRoles = FungibleResourceRoles;
178}
179impl Default for FungibleResourceType {
180    fn default() -> Self {
181        Self {
182            divisibility: DIVISIBILITY_MAXIMUM,
183        }
184    }
185}
186
187pub struct NonFungibleResourceType<
188    T: IsNonFungibleLocalId,
189    D: NonFungibleData,
190    S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
191>(S, PhantomData<T>, PhantomData<D>);
192impl<
193        T: IsNonFungibleLocalId,
194        D: NonFungibleData,
195        S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
196    > AnyResourceType for NonFungibleResourceType<T, D, S>
197{
198    type ResourceRoles = NonFungibleResourceRoles;
199}
200impl<
201        T: IsNonFungibleLocalId,
202        D: NonFungibleData,
203        S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
204    > NonFungibleResourceType<T, D, S>
205{
206    pub fn new(schema: S) -> Self {
207        Self(schema, PhantomData, PhantomData)
208    }
209}
210
211// //////////////////////////////////////////////////////////
212//  PUBLIC TRAITS AND METHODS
213//  All public methods first - these all need good rust docs
214// //////////////////////////////////////////////////////////
215
216pub trait UpdateMetadataBuilder: private::CanSetMetadata {
217    fn metadata(self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder {
218        self.set_metadata(metadata)
219    }
220}
221impl<B: private::CanSetMetadata> UpdateMetadataBuilder for B {}
222
223pub trait SetAddressReservationBuilder: private::CanSetAddressReservation {
224    /// Sets the address reservation
225    fn with_address(self, reservation: GlobalAddressReservation) -> Self::OutputBuilder {
226        self.set_address(reservation)
227    }
228}
229impl<B: private::CanSetAddressReservation> SetAddressReservationBuilder for B {}
230
231pub trait UpdateAuthBuilder {
232    /// Sets the resource to be mintable
233    ///
234    /// * The first parameter is the access rule which allows minting of the resource.
235    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
236    ///
237    /// ### Examples
238    ///
239    /// ```no_run
240    /// use radix_engine_interface::mint_roles;
241    /// use scrypto::prelude::*;
242    ///
243    /// # let resource_address = XRD;
244    /// // Sets the resource to be mintable with a proof of a specific resource, and this is locked forever.
245    /// ResourceBuilder::new_fungible(OwnerRole::None)
246    ///    .mint_roles(mint_roles! {
247    ///         minter => rule!(require(resource_address));
248    ///         minter_updater => rule!(deny_all);
249    ///     });
250    ///
251    /// # let resource_address = XRD;
252    /// // Sets the resource to not be mintable, but this is can be changed in future by the second rule
253    /// ResourceBuilder::new_fungible(OwnerRole::None)
254    ///    .mint_roles(mint_roles! {
255    ///         minter => rule!(deny_all);
256    ///         minter_updater => rule!(require(resource_address));
257    ///    });
258    /// ```
259    fn mint_roles(self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self;
260
261    /// Sets the resource to be burnable.
262    ///
263    /// * The first parameter is the access rule which allows minting of the resource.
264    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
265    ///
266    /// ### Examples
267    ///
268    /// ```no_run
269    /// use radix_engine_interface::burn_roles;
270    /// use scrypto::prelude::*;
271    ///
272    /// # let resource_address = XRD;
273    /// // Sets the resource to be burnable with a proof of a specific resource, and this is locked forever.
274    /// ResourceBuilder::new_fungible(OwnerRole::None)
275    ///    .burn_roles(burn_roles! {
276    ///        burner => rule!(require(resource_address));
277    ///        burner_updater => rule!(deny_all);
278    ///    });
279    ///
280    /// # let resource_address = XRD;
281    /// // Sets the resource to be freely burnable, but this is can be changed in future by the second rule.
282    /// ResourceBuilder::new_fungible(OwnerRole::None)
283    ///    .burn_roles(burn_roles! {
284    ///        burner => rule!(allow_all);
285    ///        burner_updater => rule!(require(resource_address));
286    ///    });
287    /// ```
288    fn burn_roles(self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self;
289
290    /// Sets the resource to be recallable from vaults.
291    ///
292    /// * The first parameter is the access rule which allows recalling of the resource.
293    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
294    ///
295    /// ### Examples
296    ///
297    /// ```no_run
298    /// use scrypto::prelude::*;
299    ///
300    /// # let resource_address = XRD;
301    /// // Sets the resource to be recallable with a proof of a specific resource, and this is locked forever.
302    /// ResourceBuilder::new_fungible(OwnerRole::None)
303    ///    .recall_roles(recall_roles! {
304    ///        recaller => rule!(require(resource_address));
305    ///        recaller_updater => rule!(deny_all);
306    ///    });
307    ///
308    /// # let resource_address = XRD;
309    /// // Sets the resource to not be recallable, but this is can be changed in future by the second rule
310    /// ResourceBuilder::new_fungible(OwnerRole::None)
311    ///    .recall_roles(recall_roles! {
312    ///        recaller => rule!(deny_all);
313    ///        recaller_updater => rule!(require(resource_address));
314    ///    });
315    /// ```
316    fn recall_roles(self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self;
317
318    /// Sets the resource to have vaults be freezable.
319    ///
320    /// * The first parameter is the access rule which allows freezing of the vault.
321    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
322    ///
323    /// ### Examples
324    ///
325    /// ```no_run
326    /// use radix_engine_interface::freeze_roles;
327    /// use scrypto::prelude::*;
328    ///
329    /// # let resource_address = XRD;
330    /// // Sets the resource to be freezeable with a proof of a specific resource, and this is locked forever.
331    /// ResourceBuilder::new_fungible(OwnerRole::None)
332    ///    .freeze_roles(freeze_roles! {
333    ///        freezer => rule!(require(resource_address));
334    ///        freezer_updater => rule!(deny_all);
335    ///    });
336    ///
337    /// # let resource_address = XRD;
338    /// // Sets the resource to not be freezeable, but this is can be changed in future by the second rule
339    /// ResourceBuilder::new_fungible(OwnerRole::None)
340    ///    .freeze_roles(freeze_roles! {
341    ///        freezer => rule!(deny_all);
342    ///        freezer_updater => rule!(require(resource_address));
343    ///    });
344    /// ```
345    fn freeze_roles(self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self;
346
347    /// Sets the role rules of withdrawing from a vault of this resource.
348    ///
349    /// * The first parameter is the access rule which allows withdrawing from a vault.
350    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
351    ///
352    /// ### Examples
353    ///
354    /// ```no_run
355    /// use radix_engine_interface::withdraw_roles;
356    /// use scrypto::prelude::*;
357    ///
358    /// # let resource_address = XRD;
359    /// // Sets the resource to be withdrawable with a proof of a specific resource, and this is locked forever.
360    /// ResourceBuilder::new_fungible(OwnerRole::None)
361    ///    .withdraw_roles(withdraw_roles! {
362    ///        withdrawer => rule!(require(resource_address));
363    ///        withdrawer_updater => rule!(deny_all);
364    ///    });
365    ///
366    /// # let resource_address = XRD;
367    /// // Sets the resource to not be withdrawable, but this is can be changed in future by the second rule
368    /// ResourceBuilder::new_fungible(OwnerRole::None)
369    ///    .withdraw_roles(withdraw_roles! {
370    ///        withdrawer => rule!(deny_all);
371    ///        withdrawer_updater => rule!(require(resource_address));
372    ///    });
373    /// ```
374    fn withdraw_roles(self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self;
375
376    /// Sets the roles rules of depositing this resource into a vault.
377    ///
378    /// * The first parameter is the access rule which allows depositing into a vault.
379    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
380    ///
381    /// ### Examples
382    ///
383    /// ```no_run
384    /// use scrypto::prelude::*;
385    ///
386    /// # let resource_address = XRD;
387    /// // Sets the resource to be depositable with a proof of a specific resource, and this is locked forever.
388    /// ResourceBuilder::new_fungible(OwnerRole::None)
389    ///    .deposit_roles(deposit_roles! {
390    ///        depositor => rule!(require(resource_address));
391    ///        depositor_updater => rule!(deny_all);
392    ///    });
393    ///
394    /// # let resource_address = XRD;
395    /// // Sets the resource to not be depositable, but this is can be changed in future by the second rule
396    /// ResourceBuilder::new_fungible(OwnerRole::None)
397    ///    .deposit_roles(deposit_roles! {
398    ///        depositor => rule!(deny_all);
399    ///        depositor_updater => rule!(require(resource_address));
400    ///    });
401    /// ```
402    fn deposit_roles(self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self;
403}
404
405impl UpdateAuthBuilder for InProgressResourceBuilder<FungibleResourceType> {
406    fn mint_roles(mut self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self {
407        self.resource_roles.mint_roles = mint_roles;
408        self
409    }
410
411    fn burn_roles(mut self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self {
412        self.resource_roles.burn_roles = burn_roles;
413        self
414    }
415
416    fn recall_roles(mut self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self {
417        self.resource_roles.recall_roles = recall_roles;
418        self
419    }
420
421    fn freeze_roles(mut self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self {
422        self.resource_roles.freeze_roles = freeze_roles;
423        self
424    }
425
426    fn withdraw_roles(mut self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self {
427        self.resource_roles.withdraw_roles = withdraw_roles;
428        self
429    }
430
431    fn deposit_roles(mut self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self {
432        self.resource_roles.deposit_roles = deposit_roles;
433        self
434    }
435}
436
437impl<
438        T: IsNonFungibleLocalId,
439        D: NonFungibleData,
440        S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
441    > UpdateAuthBuilder for InProgressResourceBuilder<NonFungibleResourceType<T, D, S>>
442{
443    fn mint_roles(mut self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self {
444        self.resource_roles.mint_roles = mint_roles;
445        self
446    }
447
448    fn burn_roles(mut self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self {
449        self.resource_roles.burn_roles = burn_roles;
450        self
451    }
452
453    fn recall_roles(mut self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self {
454        self.resource_roles.recall_roles = recall_roles;
455        self
456    }
457
458    fn freeze_roles(mut self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self {
459        self.resource_roles.freeze_roles = freeze_roles;
460        self
461    }
462
463    fn withdraw_roles(mut self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self {
464        self.resource_roles.withdraw_roles = withdraw_roles;
465        self
466    }
467
468    fn deposit_roles(mut self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self {
469        self.resource_roles.deposit_roles = deposit_roles;
470        self
471    }
472}
473
474impl<
475        T: IsNonFungibleLocalId,
476        D: NonFungibleData,
477        S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
478    > InProgressResourceBuilder<NonFungibleResourceType<T, D, S>>
479{
480    /// Sets how each non-fungible's mutable data can be updated.
481    ///
482    /// * The first parameter is the access rule which allows updating the mutable data of each non-fungible.
483    /// * The second parameter is the mutability / access rule which controls if and how the access rule can be updated.
484    ///
485    /// ### Examples
486    ///
487    /// ```no_run
488    /// use radix_engine_interface::non_fungible_data_update_roles;
489    /// use scrypto::prelude::*;
490    ///
491    /// # let resource_address = XRD;
492    ///
493    /// #[derive(ScryptoSbor, NonFungibleData)]
494    /// struct NFData {
495    ///     pub name: String,
496    ///     #[mutable]
497    ///     pub flag: bool,
498    /// }
499    /// // Permits the updating of non-fungible mutable data with a proof of a specific resource, and this is locked forever.
500    /// ResourceBuilder::new_ruid_non_fungible::<NFData>(OwnerRole::None)
501    ///    .non_fungible_data_update_roles(non_fungible_data_update_roles! {
502    ///        non_fungible_data_updater => rule!(require(resource_address));
503    ///        non_fungible_data_updater_updater => rule!(deny_all);
504    ///    });
505    ///
506    /// # let resource_address = XRD;
507    /// // Does not currently permit the updating of non-fungible mutable data, but this is can be changed in future by the second rule.
508    /// ResourceBuilder::new_ruid_non_fungible::<NFData>(OwnerRole::None)
509    ///    .non_fungible_data_update_roles(non_fungible_data_update_roles! {
510    ///        non_fungible_data_updater => rule!(deny_all);
511    ///        non_fungible_data_updater_updater => rule!(require(resource_address));
512    ///    });
513    /// ```
514    pub fn non_fungible_data_update_roles(
515        mut self,
516        non_fungible_data_update_roles: Option<NonFungibleDataUpdateRoles<RoleDefinition>>,
517    ) -> Self {
518        self.resource_roles.non_fungible_data_update_roles = non_fungible_data_update_roles;
519        self
520    }
521}
522
523pub trait SetOwnerBuilder: private::CanAddOwner {
524    /// Sets the owner badge to be the given non-fungible.
525    ///
526    /// The owner badge is given starting permissions to update the metadata/data associated with the resource,
527    /// and to change any of the access rules after creation.
528    fn owner_non_fungible_badge(self, owner_badge: NonFungibleGlobalId) -> Self::OutputBuilder {
529        self.set_owner(owner_badge)
530    }
531}
532impl<B: private::CanAddOwner> SetOwnerBuilder for B {}
533
534impl InProgressResourceBuilder<FungibleResourceType> {
535    /// Creates the fungible resource with no initial supply.
536    ///
537    /// The fungible resource's manager is returned.
538    /// It is easily convertible to generic resource manager.
539    /// One just can use `.into()` method.
540    ///
541    /// ### Example
542    ///
543    /// ```no_run
544    /// # // Can't run because it tries to call into the radix engine
545    /// # use scrypto::prelude::*;
546    /// # let address_reservation: GlobalAddressReservation = todo!();
547    /// let resource_manager = ResourceBuilder::new_fungible(OwnerRole::None)
548    ///     .mint_roles(mint_roles! {
549    ///         minter => rule!(deny_all);
550    ///         minter_updater => rule!(deny_all);
551    ///     })
552    ///     .metadata(metadata! {
553    ///         init {
554    ///             "name" => "Super Admin Badge", locked;
555    ///         }
556    ///     })
557    ///     .with_address(address_reservation)
558    ///     .create_with_no_initial_supply();
559    /// ```
560    pub fn create_with_no_initial_supply(self) -> FungibleResourceManager {
561        let metadata = self.metadata_config.unwrap_or_default();
562
563        let bytes = ScryptoVmV1Api::blueprint_call(
564            RESOURCE_PACKAGE,
565            FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
566            FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
567            scrypto_encode(&FungibleResourceManagerCreateInput {
568                owner_role: self.owner_role,
569                track_total_supply: true,
570                divisibility: self.resource_type.divisibility,
571                resource_roles: self.resource_roles,
572                metadata,
573                address_reservation: self.address_reservation,
574            })
575            .unwrap(),
576        );
577        scrypto_decode(&bytes).unwrap()
578    }
579}
580
581impl<
582        Y: IsNonFungibleLocalId,
583        D: NonFungibleData,
584        S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
585    > InProgressResourceBuilder<NonFungibleResourceType<Y, D, S>>
586{
587    /// Creates the non-fungible resource with no initial supply.
588    ///
589    /// The non-fungible resource's manager is returned.
590    /// It is easily convertible to the generic resource manager.
591    /// One just can use `.into()` method.
592    ///
593    /// ### Example
594    ///
595    /// ```no_run
596    /// # use scrypto::prelude::*;
597    /// #[derive(ScryptoSbor, NonFungibleData)]
598    /// struct Sandwich {
599    ///     name: String,
600    ///     with_ham: bool,
601    /// }
602    ///
603    /// let resource_manager: ResourceManager =
604    ///     ResourceBuilder::new_ruid_non_fungible::<Sandwich>(OwnerRole::None)
605    ///         .mint_roles(mint_roles! {
606    ///             minter => rule!(allow_all);
607    ///             minter_updater => rule!(deny_all);
608    ///         })
609    ///         .create_with_no_initial_supply()
610    ///         .into();
611    /// ```
612    pub fn create_with_no_initial_supply(self) -> NonFungibleResourceManager {
613        let metadata = self.metadata_config.unwrap_or_default();
614
615        let bytes = ScryptoVmV1Api::blueprint_call(
616            RESOURCE_PACKAGE,
617            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
618            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
619            scrypto_encode(&NonFungibleResourceManagerCreateGenericInput {
620                owner_role: self.owner_role,
621                id_type: Y::id_type(),
622                track_total_supply: true,
623                non_fungible_schema: self.resource_type.0,
624                resource_roles: self.resource_roles,
625                metadata,
626                address_reservation: self.address_reservation,
627            })
628            .unwrap(),
629        );
630        scrypto_decode(&bytes).unwrap()
631    }
632}
633
634impl InProgressResourceBuilder<FungibleResourceType> {
635    /// Set the resource's divisibility: the number of digits of precision after the decimal point in its balances.
636    ///
637    /// * `0` means the resource is not divisible (balances are always whole numbers)
638    /// * `18` is the maximum divisibility, and the default.
639    ///
640    /// ### Examples
641    ///
642    /// ```no_run
643    /// # use scrypto::prelude::*;
644    /// #
645    /// // Only permits whole-number balances.
646    /// ResourceBuilder::new_fungible(OwnerRole::None)
647    ///    .divisibility(0);
648    ///
649    /// // Only permits balances to 3 decimal places.
650    /// ResourceBuilder::new_fungible(OwnerRole::None)
651    ///    .divisibility(3);
652    /// ```
653    pub fn divisibility(mut self, divisibility: u8) -> Self {
654        assert!(divisibility <= 18);
655        self.resource_type = FungibleResourceType { divisibility };
656        self
657    }
658}
659
660impl InProgressResourceBuilder<FungibleResourceType> {
661    /// Creates resource with the given initial supply.
662    ///
663    /// # Example
664    /// ```no_run
665    /// use scrypto::prelude::*;
666    ///
667    /// let bucket: FungibleBucket = ResourceBuilder::new_fungible(OwnerRole::None)
668    ///     .mint_initial_supply(5);
669    /// ```
670    pub fn mint_initial_supply<T: Into<Decimal>>(mut self, amount: T) -> FungibleBucket {
671        let metadata = self.metadata_config.take().unwrap_or_default();
672
673        let bytes = ScryptoVmV1Api::blueprint_call(
674            RESOURCE_PACKAGE,
675            FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
676            FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
677            scrypto_encode(&FungibleResourceManagerCreateWithInitialSupplyInput {
678                owner_role: self.owner_role,
679                track_total_supply: true,
680                divisibility: self.resource_type.divisibility,
681                resource_roles: self.resource_roles,
682                metadata,
683                initial_supply: amount.into(),
684                address_reservation: self.address_reservation,
685            })
686            .unwrap(),
687        );
688
689        scrypto_decode::<(ResourceAddress, FungibleBucket)>(&bytes)
690            .unwrap()
691            .1
692    }
693}
694
695impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
696    InProgressResourceBuilder<NonFungibleResourceType<StringNonFungibleLocalId, D, S>>
697{
698    /// Creates the non-fungible resource, and mints an individual non-fungible for each key/data pair provided.
699    ///
700    /// ### Example
701    /// ```no_run
702    /// use scrypto::prelude::*;
703    ///
704    /// #[derive(ScryptoSbor, NonFungibleData)]
705    /// struct NFData {
706    ///     pub name: String,
707    ///     #[mutable]
708    ///     pub flag: bool,
709    /// }
710    ///
711    /// let bucket: NonFungibleBucket = ResourceBuilder::new_string_non_fungible::<NFData>(OwnerRole::None)
712    ///     .mint_initial_supply([
713    ///         ("One".try_into().unwrap(), NFData { name: "NF One".to_owned(), flag: true }),
714    ///         ("Two".try_into().unwrap(), NFData { name: "NF Two".to_owned(), flag: true }),
715    ///     ]);
716    /// ```
717    pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
718    where
719        T: IntoIterator<Item = (StringNonFungibleLocalId, D)>,
720    {
721        let metadata = self.metadata_config.take().unwrap_or_default();
722
723        let bytes = ScryptoVmV1Api::blueprint_call(
724            RESOURCE_PACKAGE,
725            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
726            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
727            scrypto_encode(
728                &NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
729                    owner_role: self.owner_role,
730                    track_total_supply: true,
731                    id_type: StringNonFungibleLocalId::id_type(),
732                    non_fungible_schema: self.resource_type.0,
733                    resource_roles: self.resource_roles,
734                    metadata,
735                    entries: map_entries(entries),
736                    address_reservation: self.address_reservation,
737                },
738            )
739            .unwrap(),
740        );
741        scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
742            .unwrap()
743            .1
744    }
745}
746
747impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
748    InProgressResourceBuilder<NonFungibleResourceType<IntegerNonFungibleLocalId, D, S>>
749{
750    /// Creates the non-fungible resource, and mints an individual non-fungible for each key/data pair provided.
751    ///
752    /// ### Example
753    /// ```no_run
754    /// use scrypto::prelude::*;
755    ///
756    /// #[derive(ScryptoSbor, NonFungibleData)]
757    /// struct NFData {
758    ///     pub name: String,
759    ///     #[mutable]
760    ///     pub flag: bool,
761    /// }
762    ///
763    /// let bucket: NonFungibleBucket = ResourceBuilder::new_integer_non_fungible(OwnerRole::None)
764    ///     .mint_initial_supply([
765    ///         (1u64.into(), NFData { name: "NF One".to_owned(), flag: true }),
766    ///         (2u64.into(), NFData { name: "NF Two".to_owned(), flag: true }),
767    ///     ]);
768    /// ```
769    pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
770    where
771        T: IntoIterator<Item = (IntegerNonFungibleLocalId, D)>,
772    {
773        let metadata = self.metadata_config.take().unwrap_or_default();
774
775        let bytes = ScryptoVmV1Api::blueprint_call(
776            RESOURCE_PACKAGE,
777            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
778            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
779            scrypto_encode(
780                &NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
781                    owner_role: self.owner_role,
782                    track_total_supply: true,
783                    id_type: IntegerNonFungibleLocalId::id_type(),
784                    non_fungible_schema: self.resource_type.0,
785                    resource_roles: self.resource_roles,
786                    metadata,
787                    entries: map_entries(entries),
788                    address_reservation: self.address_reservation,
789                },
790            )
791            .unwrap(),
792        );
793        scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
794            .unwrap()
795            .1
796    }
797}
798
799impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
800    InProgressResourceBuilder<NonFungibleResourceType<BytesNonFungibleLocalId, D, S>>
801{
802    /// Creates the non-fungible resource, and mints an individual non-fungible for each key/data pair provided.
803    ///
804    /// ### Example
805    /// ```no_run
806    /// use scrypto::prelude::*;
807    ///
808    /// #[derive(ScryptoSbor, NonFungibleData)]
809    /// struct NFData {
810    ///     pub name: String,
811    ///     #[mutable]
812    ///     pub flag: bool,
813    /// }
814    ///
815    /// let bucket: NonFungibleBucket = ResourceBuilder::new_bytes_non_fungible::<NFData>(OwnerRole::None)
816    ///     .mint_initial_supply([
817    ///         (vec![1u8].try_into().unwrap(), NFData { name: "NF One".to_owned(), flag: true }),
818    ///         (vec![2u8].try_into().unwrap(), NFData { name: "NF Two".to_owned(), flag: true }),
819    ///     ]);
820    /// ```
821    pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
822    where
823        T: IntoIterator<Item = (BytesNonFungibleLocalId, D)>,
824    {
825        let metadata = self.metadata_config.take().unwrap_or_default();
826
827        let bytes = ScryptoVmV1Api::blueprint_call(
828            RESOURCE_PACKAGE,
829            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
830            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
831            scrypto_encode(
832                &NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
833                    owner_role: self.owner_role,
834                    id_type: BytesNonFungibleLocalId::id_type(),
835                    track_total_supply: true,
836                    non_fungible_schema: self.resource_type.0,
837                    resource_roles: self.resource_roles,
838                    metadata,
839                    entries: map_entries(entries),
840                    address_reservation: self.address_reservation,
841                },
842            )
843            .unwrap(),
844        );
845        scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
846            .unwrap()
847            .1
848    }
849}
850
851impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
852    InProgressResourceBuilder<NonFungibleResourceType<RUIDNonFungibleLocalId, D, S>>
853{
854    /// Creates the RUID non-fungible resource, and mints an individual non-fungible for each piece of data provided.
855    ///
856    /// The system automatically generates a new RUID `NonFungibleLocalId` for each non-fungible,
857    /// and assigns the given data to each.
858    ///
859    /// ### Example
860    /// ```no_run
861    /// use scrypto::prelude::*;
862    ///
863    /// #[derive(ScryptoSbor, NonFungibleData)]
864    /// struct NFData {
865    ///     pub name: String,
866    ///     #[mutable]
867    ///     pub flag: bool,
868    /// }
869    ///
870    /// let bucket: NonFungibleBucket = ResourceBuilder::new_ruid_non_fungible::<NFData>(OwnerRole::None)
871    ///     .mint_initial_supply([
872    ///         (NFData { name: "NF One".to_owned(), flag: true }),
873    ///         (NFData { name: "NF Two".to_owned(), flag: true }),
874    ///     ]);
875    /// ```
876    pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
877    where
878        T: IntoIterator<Item = D>,
879        D: ScryptoEncode,
880    {
881        let metadata = self.metadata_config.take().unwrap_or_default();
882
883        let bytes = ScryptoVmV1Api::blueprint_call(
884            RESOURCE_PACKAGE,
885            NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
886            NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT,
887            scrypto_encode(
888                &NonFungibleResourceManagerCreateRuidWithInitialSupplyGenericInput {
889                    owner_role: self.owner_role,
890                    non_fungible_schema: self.resource_type.0,
891                    track_total_supply: true,
892                    resource_roles: self.resource_roles,
893                    metadata,
894                    entries: entries.into_iter().map(|data| (data,)).collect(),
895                    address_reservation: self.address_reservation,
896                },
897            )
898            .unwrap(),
899        );
900        scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
901            .unwrap()
902            .1
903    }
904}
905
906// /////////////////////////////////
907//  PRIVATE TRAIT IMPLEMENTATIONS
908//  These don't need good rust docs
909// /////////////////////////////////
910
911fn map_entries<T: IntoIterator<Item = (Y, V)>, V: NonFungibleData, Y: IsNonFungibleLocalId>(
912    entries: T,
913) -> IndexMap<NonFungibleLocalId, (V,)> {
914    entries
915        .into_iter()
916        .map(|(id, data)| (id.into(), (data,)))
917        .collect()
918}
919
920impl<T: AnyResourceType> private::CanSetMetadata for InProgressResourceBuilder<T> {
921    type OutputBuilder = Self;
922
923    fn set_metadata(mut self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder {
924        self.metadata_config = Some(metadata);
925        self
926    }
927}
928
929impl<T: AnyResourceType> private::CanSetAddressReservation for InProgressResourceBuilder<T> {
930    type OutputBuilder = Self;
931
932    fn set_address(mut self, address_reservation: GlobalAddressReservation) -> Self::OutputBuilder {
933        self.address_reservation = Some(address_reservation);
934        self
935    }
936}
937
938/// This file was experiencing combinatorial explosion - as part of the clean-up, we've used private traits to keep things simple.
939///
940/// Each public method has essentially one implementation, and one Rust doc (where there weren't clashes due to Rust trait issues -
941/// eg with the `mint_initial_supply` methods).
942///
943/// Internally, the various builders implement these private traits, and then automatically implement the "nice" public traits.
944/// The methods defined in the private traits are less nice, and so are hidden in order to not pollute the user facing API.
945///
946/// As users will nearly always use `scrypto::prelude::*`, as long as we make sure that the public traits are exported, this will
947/// be seamless for the user.
948///
949/// See https://stackoverflow.com/a/53207767 for more information on this.
950mod private {
951    use super::*;
952    use radix_common::types::NonFungibleGlobalId;
953
954    pub trait CanSetMetadata: Sized {
955        type OutputBuilder;
956
957        fn set_metadata(self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder;
958    }
959
960    pub trait CanSetAddressReservation: Sized {
961        type OutputBuilder;
962
963        fn set_address(self, address_reservation: GlobalAddressReservation) -> Self::OutputBuilder;
964    }
965
966    pub trait CanAddOwner: Sized {
967        type OutputBuilder;
968
969        fn set_owner(self, owner_badge: NonFungibleGlobalId) -> Self::OutputBuilder;
970    }
971}