use crate::engine::scrypto_env::ScryptoVmV1Api;
use crate::runtime::Runtime;
use radix_common::constants::RESOURCE_PACKAGE;
use radix_common::data::scrypto::model::*;
use radix_common::prelude::*;
use radix_common::traits::NonFungibleData;
use radix_engine_interface::blueprints::resource::*;
use radix_engine_interface::object_modules::metadata::MetadataInit;
use radix_engine_interface::object_modules::role_assignment::RoleDefinition;
use radix_engine_interface::object_modules::ModuleConfig;
use scrypto::resource::{FungibleResourceManager, NonFungibleResourceManager};
pub const DIVISIBILITY_NONE: u8 = 0;
pub const DIVISIBILITY_MAXIMUM: u8 = 18;
pub struct ResourceBuilder;
impl ResourceBuilder {
pub fn new_fungible(owner_role: OwnerRole) -> InProgressResourceBuilder<FungibleResourceType> {
InProgressResourceBuilder::new(owner_role, FungibleResourceType::default())
}
pub fn new_string_non_fungible<D: NonFungibleData>(
owner_role: OwnerRole,
) -> InProgressResourceBuilder<
NonFungibleResourceType<
StringNonFungibleLocalId,
D,
SborFixedEnumVariant<
NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
LocalNonFungibleDataSchema,
>,
>,
> {
InProgressResourceBuilder::new(
owner_role,
NonFungibleResourceType::new(SborFixedEnumVariant {
fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
Runtime::package_address(),
),
}),
)
}
pub fn new_integer_non_fungible<D: NonFungibleData>(
owner_role: OwnerRole,
) -> InProgressResourceBuilder<
NonFungibleResourceType<
IntegerNonFungibleLocalId,
D,
SborFixedEnumVariant<
NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
LocalNonFungibleDataSchema,
>,
>,
> {
InProgressResourceBuilder::new(
owner_role,
NonFungibleResourceType::new(SborFixedEnumVariant {
fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
Runtime::package_address(),
),
}),
)
}
pub fn new_bytes_non_fungible<D: NonFungibleData>(
owner_role: OwnerRole,
) -> InProgressResourceBuilder<
NonFungibleResourceType<
BytesNonFungibleLocalId,
D,
SborFixedEnumVariant<
NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
LocalNonFungibleDataSchema,
>,
>,
> {
InProgressResourceBuilder::new(
owner_role,
NonFungibleResourceType::new(SborFixedEnumVariant {
fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
Runtime::package_address(),
),
}),
)
}
pub fn new_ruid_non_fungible<D: NonFungibleData>(
owner_role: OwnerRole,
) -> InProgressResourceBuilder<
NonFungibleResourceType<
RUIDNonFungibleLocalId,
D,
SborFixedEnumVariant<
NON_FUNGIBLE_DATA_SCHEMA_VARIANT_LOCAL,
LocalNonFungibleDataSchema,
>,
>,
> {
InProgressResourceBuilder::new(
owner_role,
NonFungibleResourceType::new(SborFixedEnumVariant {
fields: LocalNonFungibleDataSchema::new_with_self_package_replacement::<D>(
Runtime::package_address(),
),
}),
)
}
}
#[must_use]
pub struct InProgressResourceBuilder<T: AnyResourceType> {
owner_role: OwnerRole,
resource_type: T,
resource_roles: T::ResourceRoles,
metadata_config: Option<ModuleConfig<MetadataInit>>,
address_reservation: Option<GlobalAddressReservation>,
}
impl<T: AnyResourceType> InProgressResourceBuilder<T> {
pub fn new(owner_role: OwnerRole, resource_type: T) -> Self {
Self {
owner_role,
resource_type,
metadata_config: None,
address_reservation: None,
resource_roles: T::ResourceRoles::default(),
}
}
}
pub trait AnyResourceType {
type ResourceRoles: Default;
}
pub struct FungibleResourceType {
divisibility: u8,
}
impl AnyResourceType for FungibleResourceType {
type ResourceRoles = FungibleResourceRoles;
}
impl Default for FungibleResourceType {
fn default() -> Self {
Self {
divisibility: DIVISIBILITY_MAXIMUM,
}
}
}
pub struct NonFungibleResourceType<
T: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
>(S, PhantomData<T>, PhantomData<D>);
impl<
T: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
> AnyResourceType for NonFungibleResourceType<T, D, S>
{
type ResourceRoles = NonFungibleResourceRoles;
}
impl<
T: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
> NonFungibleResourceType<T, D, S>
{
pub fn new(schema: S) -> Self {
Self(schema, PhantomData, PhantomData)
}
}
pub trait UpdateMetadataBuilder: private::CanSetMetadata {
fn metadata(self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder {
self.set_metadata(metadata)
}
}
impl<B: private::CanSetMetadata> UpdateMetadataBuilder for B {}
pub trait SetAddressReservationBuilder: private::CanSetAddressReservation {
fn with_address(self, reservation: GlobalAddressReservation) -> Self::OutputBuilder {
self.set_address(reservation)
}
}
impl<B: private::CanSetAddressReservation> SetAddressReservationBuilder for B {}
pub trait UpdateAuthBuilder {
fn mint_roles(self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self;
fn burn_roles(self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self;
fn recall_roles(self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self;
fn freeze_roles(self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self;
fn withdraw_roles(self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self;
fn deposit_roles(self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self;
}
impl UpdateAuthBuilder for InProgressResourceBuilder<FungibleResourceType> {
fn mint_roles(mut self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self {
self.resource_roles.mint_roles = mint_roles;
self
}
fn burn_roles(mut self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self {
self.resource_roles.burn_roles = burn_roles;
self
}
fn recall_roles(mut self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self {
self.resource_roles.recall_roles = recall_roles;
self
}
fn freeze_roles(mut self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self {
self.resource_roles.freeze_roles = freeze_roles;
self
}
fn withdraw_roles(mut self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self {
self.resource_roles.withdraw_roles = withdraw_roles;
self
}
fn deposit_roles(mut self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self {
self.resource_roles.deposit_roles = deposit_roles;
self
}
}
impl<
T: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
> UpdateAuthBuilder for InProgressResourceBuilder<NonFungibleResourceType<T, D, S>>
{
fn mint_roles(mut self, mint_roles: Option<MintRoles<RoleDefinition>>) -> Self {
self.resource_roles.mint_roles = mint_roles;
self
}
fn burn_roles(mut self, burn_roles: Option<BurnRoles<RoleDefinition>>) -> Self {
self.resource_roles.burn_roles = burn_roles;
self
}
fn recall_roles(mut self, recall_roles: Option<RecallRoles<RoleDefinition>>) -> Self {
self.resource_roles.recall_roles = recall_roles;
self
}
fn freeze_roles(mut self, freeze_roles: Option<FreezeRoles<RoleDefinition>>) -> Self {
self.resource_roles.freeze_roles = freeze_roles;
self
}
fn withdraw_roles(mut self, withdraw_roles: Option<WithdrawRoles<RoleDefinition>>) -> Self {
self.resource_roles.withdraw_roles = withdraw_roles;
self
}
fn deposit_roles(mut self, deposit_roles: Option<DepositRoles<RoleDefinition>>) -> Self {
self.resource_roles.deposit_roles = deposit_roles;
self
}
}
impl<
T: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
> InProgressResourceBuilder<NonFungibleResourceType<T, D, S>>
{
pub fn non_fungible_data_update_roles(
mut self,
non_fungible_data_update_roles: Option<NonFungibleDataUpdateRoles<RoleDefinition>>,
) -> Self {
self.resource_roles.non_fungible_data_update_roles = non_fungible_data_update_roles;
self
}
}
pub trait SetOwnerBuilder: private::CanAddOwner {
fn owner_non_fungible_badge(self, owner_badge: NonFungibleGlobalId) -> Self::OutputBuilder {
self.set_owner(owner_badge)
}
}
impl<B: private::CanAddOwner> SetOwnerBuilder for B {}
impl InProgressResourceBuilder<FungibleResourceType> {
pub fn create_with_no_initial_supply(self) -> FungibleResourceManager {
let metadata = self.metadata_config.unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
scrypto_encode(&FungibleResourceManagerCreateInput {
owner_role: self.owner_role,
track_total_supply: true,
divisibility: self.resource_type.divisibility,
resource_roles: self.resource_roles,
metadata,
address_reservation: self.address_reservation,
})
.unwrap(),
);
scrypto_decode(&bytes).unwrap()
}
}
impl<
Y: IsNonFungibleLocalId,
D: NonFungibleData,
S: ScryptoCategorize + ScryptoEncode + ScryptoDecode,
> InProgressResourceBuilder<NonFungibleResourceType<Y, D, S>>
{
pub fn create_with_no_initial_supply(self) -> NonFungibleResourceManager {
let metadata = self.metadata_config.unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_IDENT,
scrypto_encode(&NonFungibleResourceManagerCreateGenericInput {
owner_role: self.owner_role,
id_type: Y::id_type(),
track_total_supply: true,
non_fungible_schema: self.resource_type.0,
resource_roles: self.resource_roles,
metadata,
address_reservation: self.address_reservation,
})
.unwrap(),
);
scrypto_decode(&bytes).unwrap()
}
}
impl InProgressResourceBuilder<FungibleResourceType> {
pub fn divisibility(mut self, divisibility: u8) -> Self {
assert!(divisibility <= 18);
self.resource_type = FungibleResourceType { divisibility };
self
}
}
impl InProgressResourceBuilder<FungibleResourceType> {
pub fn mint_initial_supply<T: Into<Decimal>>(mut self, amount: T) -> FungibleBucket {
let metadata = self.metadata_config.take().unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
scrypto_encode(&FungibleResourceManagerCreateWithInitialSupplyInput {
owner_role: self.owner_role,
track_total_supply: true,
divisibility: self.resource_type.divisibility,
resource_roles: self.resource_roles,
metadata,
initial_supply: amount.into(),
address_reservation: self.address_reservation,
})
.unwrap(),
);
scrypto_decode::<(ResourceAddress, FungibleBucket)>(&bytes)
.unwrap()
.1
}
}
impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
InProgressResourceBuilder<NonFungibleResourceType<StringNonFungibleLocalId, D, S>>
{
pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
where
T: IntoIterator<Item = (StringNonFungibleLocalId, D)>,
{
let metadata = self.metadata_config.take().unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
scrypto_encode(
&NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
owner_role: self.owner_role,
track_total_supply: true,
id_type: StringNonFungibleLocalId::id_type(),
non_fungible_schema: self.resource_type.0,
resource_roles: self.resource_roles,
metadata,
entries: map_entries(entries),
address_reservation: self.address_reservation,
},
)
.unwrap(),
);
scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
.unwrap()
.1
}
}
impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
InProgressResourceBuilder<NonFungibleResourceType<IntegerNonFungibleLocalId, D, S>>
{
pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
where
T: IntoIterator<Item = (IntegerNonFungibleLocalId, D)>,
{
let metadata = self.metadata_config.take().unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
scrypto_encode(
&NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
owner_role: self.owner_role,
track_total_supply: true,
id_type: IntegerNonFungibleLocalId::id_type(),
non_fungible_schema: self.resource_type.0,
resource_roles: self.resource_roles,
metadata,
entries: map_entries(entries),
address_reservation: self.address_reservation,
},
)
.unwrap(),
);
scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
.unwrap()
.1
}
}
impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
InProgressResourceBuilder<NonFungibleResourceType<BytesNonFungibleLocalId, D, S>>
{
pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
where
T: IntoIterator<Item = (BytesNonFungibleLocalId, D)>,
{
let metadata = self.metadata_config.take().unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_WITH_INITIAL_SUPPLY_IDENT,
scrypto_encode(
&NonFungibleResourceManagerCreateWithInitialSupplyGenericInput {
owner_role: self.owner_role,
id_type: BytesNonFungibleLocalId::id_type(),
track_total_supply: true,
non_fungible_schema: self.resource_type.0,
resource_roles: self.resource_roles,
metadata,
entries: map_entries(entries),
address_reservation: self.address_reservation,
},
)
.unwrap(),
);
scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
.unwrap()
.1
}
}
impl<D: NonFungibleData, S: ScryptoCategorize + ScryptoEncode + ScryptoDecode>
InProgressResourceBuilder<NonFungibleResourceType<RUIDNonFungibleLocalId, D, S>>
{
pub fn mint_initial_supply<T>(mut self, entries: T) -> NonFungibleBucket
where
T: IntoIterator<Item = D>,
D: ScryptoEncode,
{
let metadata = self.metadata_config.take().unwrap_or_default();
let bytes = ScryptoVmV1Api::blueprint_call(
RESOURCE_PACKAGE,
NON_FUNGIBLE_RESOURCE_MANAGER_BLUEPRINT,
NON_FUNGIBLE_RESOURCE_MANAGER_CREATE_RUID_WITH_INITIAL_SUPPLY_IDENT,
scrypto_encode(
&NonFungibleResourceManagerCreateRuidWithInitialSupplyGenericInput {
owner_role: self.owner_role,
non_fungible_schema: self.resource_type.0,
track_total_supply: true,
resource_roles: self.resource_roles,
metadata,
entries: entries.into_iter().map(|data| (data,)).collect(),
address_reservation: self.address_reservation,
},
)
.unwrap(),
);
scrypto_decode::<(ResourceAddress, NonFungibleBucket)>(&bytes)
.unwrap()
.1
}
}
fn map_entries<T: IntoIterator<Item = (Y, V)>, V: NonFungibleData, Y: IsNonFungibleLocalId>(
entries: T,
) -> IndexMap<NonFungibleLocalId, (V,)> {
entries
.into_iter()
.map(|(id, data)| (id.into(), (data,)))
.collect()
}
impl<T: AnyResourceType> private::CanSetMetadata for InProgressResourceBuilder<T> {
type OutputBuilder = Self;
fn set_metadata(mut self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder {
self.metadata_config = Some(metadata);
self
}
}
impl<T: AnyResourceType> private::CanSetAddressReservation for InProgressResourceBuilder<T> {
type OutputBuilder = Self;
fn set_address(mut self, address_reservation: GlobalAddressReservation) -> Self::OutputBuilder {
self.address_reservation = Some(address_reservation);
self
}
}
mod private {
use super::*;
use radix_common::types::NonFungibleGlobalId;
pub trait CanSetMetadata: Sized {
type OutputBuilder;
fn set_metadata(self, metadata: ModuleConfig<MetadataInit>) -> Self::OutputBuilder;
}
pub trait CanSetAddressReservation: Sized {
type OutputBuilder;
fn set_address(self, address_reservation: GlobalAddressReservation) -> Self::OutputBuilder;
}
pub trait CanAddOwner: Sized {
type OutputBuilder;
fn set_owner(self, owner_badge: NonFungibleGlobalId) -> Self::OutputBuilder;
}
}