123456789101112131415161718192021#![cfg_attr(not(feature = "std"), no_std)]2223use core::{24 convert::{TryFrom, TryInto},25 fmt,26};27use frame_support::{28 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},29 traits::Get,30 parameter_types,31};3233#[cfg(feature = "serde")]34use serde::{Serialize, Deserialize};3536use sp_core::U256;37use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};38use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};39use bondrewd::Bitfields;40use frame_support::{BoundedVec, traits::ConstU32};41use derivative::Derivative;42use scale_info::TypeInfo;434445use rmrk_traits::{46 CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,47 ResourceTypes, BasicResource, ComposableResource, SlotResource, EquippableList,48};49pub use rmrk_traits::{50 primitives::{51 CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId,52 SlotId as RmrkSlotId, PartId as RmrkPartId, ResourceId as RmrkResourceId,53 },54 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,55 FixedPart as RmrkFixedPart, SlotPart as RmrkSlotPart,56};5758mod bondrewd_codec;59mod bounded;60pub mod budget;61pub mod mapping;62mod migration;636465pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;666768pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;69pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;707172pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {73 100_00074} else {75 1076};777879pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {80 100_00081} else {82 1083};848586pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {87 204888} else {89 1090};919293pub const COLLECTION_ADMINS_LIMIT: u32 = 5;949596pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;979899pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {100 1_000_000101} else {102 10103};104105106pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;107108pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;109110pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;111112113pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;114115116pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;117pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;118pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;119120121pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;122123124pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;125126127pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;128129130pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;131132133pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;134135136pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;137138139pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;140141142pub const MAX_AUX_PROPERTY_VALUE_LENGTH: u32 = 2048;143144145pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;146147148pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;149150151152pub const MAX_ITEMS_PER_BATCH: u32 = 200;153154155pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;156157158#[derive(159 Encode,160 Decode,161 PartialEq,162 Eq,163 PartialOrd,164 Ord,165 Clone,166 Copy,167 Debug,168 Default,169 TypeInfo,170 MaxEncodedLen,171)]172#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]173pub struct CollectionId(pub u32);174impl EncodeLike<u32> for CollectionId {}175impl EncodeLike<CollectionId> for u32 {}176177178#[derive(179 Encode,180 Decode,181 PartialEq,182 Eq,183 PartialOrd,184 Ord,185 Clone,186 Copy,187 Debug,188 Default,189 TypeInfo,190 MaxEncodedLen,191)]192#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]193pub struct TokenId(pub u32);194impl EncodeLike<u32> for TokenId {}195impl EncodeLike<TokenId> for u32 {}196197impl TokenId {198 199 200 201 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {202 self.0203 .checked_add(1)204 .ok_or(ArithmeticError::Overflow)205 .map(Self)206 }207}208209impl From<TokenId> for U256 {210 fn from(t: TokenId) -> Self {211 t.0.into()212 }213}214215impl TryFrom<U256> for TokenId {216 type Error = &'static str;217218 fn try_from(value: U256) -> Result<Self, Self::Error> {219 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))220 }221}222223224#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]225#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]226pub struct TokenData<CrossAccountId> {227 228 pub properties: Vec<Property>,229230 231 pub owner: Option<CrossAccountId>,232233 234 pub pieces: u128,235}236237238pub struct OverflowError;239impl From<OverflowError> for &'static str {240 fn from(_: OverflowError) -> Self {241 "overflow occured"242 }243}244245246pub type DecimalPoints = u8;247248249250251252253#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]254#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]255pub enum CollectionMode {256 257 NFT,258 259 Fungible(DecimalPoints),260 261 ReFungible,262}263264impl CollectionMode {265 266 pub fn id(&self) -> u8 {267 match self {268 CollectionMode::NFT => 1,269 CollectionMode::Fungible(_) => 2,270 CollectionMode::ReFungible => 3,271 }272 }273}274275276pub trait SponsoringResolve<AccountId, Call> {277 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;278}279280281#[derive(Encode, Decode, Eq, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]282#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]283pub enum AccessMode {284 285 Normal,286 287 AllowList,288}289impl Default for AccessMode {290 fn default() -> Self {291 Self::Normal292 }293}294295296#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]297#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]298pub enum SchemaVersion {299 ImageURL,300 Unique,301}302impl Default for SchemaVersion {303 fn default() -> Self {304 Self::ImageURL305 }306}307308309#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]310#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]311pub struct Ownership<AccountId> {312 pub owner: AccountId,313 pub fraction: u128,314}315316317#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]318#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]319pub enum SponsorshipState<AccountId> {320 321 Disabled,322 323 324 Unconfirmed(AccountId),325 326 Confirmed(AccountId),327}328329impl<AccountId> SponsorshipState<AccountId> {330 331 pub fn sponsor(&self) -> Option<&AccountId> {332 match self {333 Self::Confirmed(sponsor) => Some(sponsor),334 _ => None,335 }336 }337338 339 pub fn pending_sponsor(&self) -> Option<&AccountId> {340 match self {341 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),342 _ => None,343 }344 }345346 347 pub fn confirmed(&self) -> bool {348 matches!(self, Self::Confirmed(_))349 }350}351352impl<T> Default for SponsorshipState<T> {353 fn default() -> Self {354 Self::Disabled355 }356}357358pub type CollectionName = BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>;359pub type CollectionDescription = BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>;360pub type CollectionTokenPrefix = BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>;361362#[derive(Bitfields, Clone, Copy, PartialEq, Eq, Debug, Default)]363#[bondrewd(enforce_bytes = 1)]364pub struct CollectionFlags {365 366 #[bondrewd(bits = "0..1")]367 pub foreign: bool,368 369 #[bondrewd(bits = "1..2")]370 pub erc721metadata: bool,371 372 #[bondrewd(bits = "7..8")]373 pub external: bool,374375 #[bondrewd(reserve, bits = "2..7")]376 pub reserved: u8,377}378bondrewd_codec!(CollectionFlags);379380381382383384385386#[struct_versioning::versioned(version = 2, upper)]387#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]388pub struct Collection<AccountId> {389 390 pub owner: AccountId,391392 393 pub mode: CollectionMode,394395 396 #[version(..2)]397 pub access: AccessMode,398399 400 pub name: CollectionName,401402 403 pub description: CollectionDescription,404405 406 pub token_prefix: CollectionTokenPrefix,407408 #[version(..2)]409 pub mint_mode: bool,410411 #[version(..2)]412 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,413414 #[version(..2)]415 pub schema_version: SchemaVersion,416417 418 pub sponsorship: SponsorshipState<AccountId>,419420 421 pub limits: CollectionLimits,422423 424 #[version(2.., upper(Default::default()))]425 pub permissions: CollectionPermissions,426427 #[version(2.., upper(Default::default()))]428 pub flags: CollectionFlags,429430 #[version(..2)]431 pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,432433 #[version(..2)]434 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,435436 #[version(..2)]437 pub meta_update_permission: MetaUpdatePermission,438}439440#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]441#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]442pub struct RpcCollectionFlags {443 444 pub foreign: bool,445 446 pub erc721metadata: bool,447}448449450#[struct_versioning::versioned(version = 2, upper)]451#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]452#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]453pub struct RpcCollection<AccountId> {454 455 pub owner: AccountId,456457 458 pub mode: CollectionMode,459460 461 pub name: Vec<u16>,462463 464 pub description: Vec<u16>,465466 467 pub token_prefix: Vec<u8>,468469 470 pub sponsorship: SponsorshipState<AccountId>,471472 473 pub limits: CollectionLimits,474475 476 pub permissions: CollectionPermissions,477478 479 pub token_property_permissions: Vec<PropertyKeyPermission>,480481 482 pub properties: Vec<Property>,483484 485 pub read_only: bool,486487 488 #[version(2.., upper(RpcCollectionFlags {foreign: false, erc721metadata: false}))]489 pub flags: RpcCollectionFlags,490}491492493494495#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]496#[derivative(Debug, Default(bound = ""))]497pub struct CreateCollectionData<AccountId> {498 499 #[derivative(Default(value = "CollectionMode::NFT"))]500 pub mode: CollectionMode,501502 503 pub access: Option<AccessMode>,504505 506 pub name: CollectionName,507508 509 pub description: CollectionDescription,510511 512 pub token_prefix: CollectionTokenPrefix,513514 515 pub pending_sponsor: Option<AccountId>,516517 518 pub limits: Option<CollectionLimits>,519520 521 pub permissions: Option<CollectionPermissions>,522523 524 pub token_property_permissions: CollectionPropertiesPermissionsVec,525526 527 pub properties: CollectionPropertiesVec,528}529530531532pub type CollectionPropertiesPermissionsVec =533 BoundedVec<PropertyKeyPermission, ConstU32<MAX_PROPERTIES_PER_ITEM>>;534535536pub type CollectionPropertiesVec = BoundedVec<Property, ConstU32<MAX_PROPERTIES_PER_ITEM>>;537538539540541542543544#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]545#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]546547548549pub struct CollectionLimits {550 551 552 553 pub account_token_ownership_limit: Option<u32>,554555 556 557 558 pub sponsored_data_size: Option<u32>,559560 561 562 563 564 565 566 567 568 569 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,570 571572 573 574 575 576 pub token_limit: Option<u32>,577578 579 580 581 582 583 584 585 pub sponsor_transfer_timeout: Option<u32>,586587 588 589 590 591 pub sponsor_approve_timeout: Option<u32>,592593 594 595 596 pub owner_can_transfer: Option<bool>,597598 599 600 601 pub owner_can_destroy: Option<bool>,602603 604 605 606 pub transfers_enabled: Option<bool>,607}608609impl CollectionLimits {610 611 pub fn account_token_ownership_limit(&self) -> u32 {612 self.account_token_ownership_limit613 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)614 .min(MAX_TOKEN_OWNERSHIP)615 }616617 618 pub fn sponsored_data_size(&self) -> u32 {619 self.sponsored_data_size620 .unwrap_or(CUSTOM_DATA_LIMIT)621 .min(CUSTOM_DATA_LIMIT)622 }623624 625 pub fn token_limit(&self) -> u32 {626 self.token_limit627 .unwrap_or(COLLECTION_TOKEN_LIMIT)628 .min(COLLECTION_TOKEN_LIMIT)629 }630631 632 633 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {634 self.sponsor_transfer_timeout635 .unwrap_or(default)636 .min(MAX_SPONSOR_TIMEOUT)637 }638639 640 pub fn sponsor_approve_timeout(&self) -> u32 {641 self.sponsor_approve_timeout642 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)643 .min(MAX_SPONSOR_TIMEOUT)644 }645646 647 pub fn owner_can_transfer(&self) -> bool {648 self.owner_can_transfer.unwrap_or(false)649 }650651 652 pub fn owner_can_transfer_instaled(&self) -> bool {653 self.owner_can_transfer.is_some()654 }655656 657 pub fn owner_can_destroy(&self) -> bool {658 self.owner_can_destroy.unwrap_or(true)659 }660661 662 pub fn transfers_enabled(&self) -> bool {663 self.transfers_enabled.unwrap_or(true)664 }665666 667 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {668 match self669 .sponsored_data_rate_limit670 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)671 {672 SponsoringRateLimit::SponsoringDisabled => None,673 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),674 }675 }676}677678679680681682683#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]684#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]685686687pub struct CollectionPermissions {688 689 690 691 pub access: Option<AccessMode>,692693 694 695 696 pub mint_mode: Option<bool>,697698 699 700 701 702 703 704 pub nesting: Option<NestingPermissions>,705}706707impl CollectionPermissions {708 709 pub fn access(&self) -> AccessMode {710 self.access.unwrap_or(AccessMode::Normal)711 }712713 714 pub fn mint_mode(&self) -> bool {715 self.mint_mode.unwrap_or(false)716 }717718 719 pub fn nesting(&self) -> &NestingPermissions {720 static DEFAULT: NestingPermissions = NestingPermissions {721 token_owner: false,722 collection_admin: false,723 restricted: None,724 #[cfg(feature = "runtime-benchmarks")]725 permissive: false,726 };727 self.nesting.as_ref().unwrap_or(&DEFAULT)728 }729}730731732type OwnerRestrictedSetInner = BoundedBTreeSet<CollectionId, ConstU32<16>>;733734735#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]736#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]737#[derivative(Debug)]738pub struct OwnerRestrictedSet(739 #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]740 #[derivative(Debug(format_with = "bounded::set_debug"))]741 pub OwnerRestrictedSetInner,742);743744impl OwnerRestrictedSet {745 746 pub fn new() -> Self {747 Self(Default::default())748 }749}750impl core::ops::Deref for OwnerRestrictedSet {751 type Target = OwnerRestrictedSetInner;752 fn deref(&self) -> &Self::Target {753 &self.0754 }755}756impl core::ops::DerefMut for OwnerRestrictedSet {757 fn deref_mut(&mut self) -> &mut Self::Target {758 &mut self.0759 }760}761762763#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]764#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]765#[derivative(Debug)]766pub struct NestingPermissions {767 768 pub token_owner: bool,769 770 pub collection_admin: bool,771 772 pub restricted: Option<OwnerRestrictedSet>,773774 #[cfg(feature = "runtime-benchmarks")]775 776 pub permissive: bool,777}778779780781782#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]783#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]784pub enum SponsoringRateLimit {785 786 SponsoringDisabled,787 788 Blocks(u32),789}790791792#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]793#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]794#[derivative(Debug)]795pub struct CreateNftData {796 797 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]798 #[derivative(Debug(format_with = "bounded::vec_debug"))]799 800 pub properties: CollectionPropertiesVec,801}802803804#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]805#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]806pub struct CreateFungibleData {807 808 pub value: u128,809}810811812#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]813#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]814#[derivative(Debug)]815pub struct CreateReFungibleData {816 817 pub pieces: u128,818819 820 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]821 #[derivative(Debug(format_with = "bounded::vec_debug"))]822 pub properties: CollectionPropertiesVec,823}824825826#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]827#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]828pub enum MetaUpdatePermission {829 ItemOwner,830 Admin,831 None,832}833834835836#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]837#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]838pub enum CreateItemData {839 840 NFT(CreateNftData),841 842 Fungible(CreateFungibleData),843 844 ReFungible(CreateReFungibleData),845}846847848#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]849#[derivative(Debug)]850pub struct CreateNftExData<CrossAccountId> {851 852 #[derivative(Debug(format_with = "bounded::vec_debug"))]853 pub properties: CollectionPropertiesVec,854855 856 pub owner: CrossAccountId,857}858859860#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]861#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]862pub struct CreateRefungibleExMultipleOwners<CrossAccountId> {863 #[derivative(Debug(format_with = "bounded::map_debug"))]864 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,865 #[derivative(Debug(format_with = "bounded::vec_debug"))]866 pub properties: CollectionPropertiesVec,867}868869870#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]871#[derivative(Debug(bound = "CrossAccountId: fmt::Debug"))]872pub struct CreateRefungibleExSingleOwner<CrossAccountId> {873 pub user: CrossAccountId,874 pub pieces: u128,875 #[derivative(Debug(format_with = "bounded::vec_debug"))]876 pub properties: CollectionPropertiesVec,877}878879880#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]881#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]882pub enum CreateItemExData<CrossAccountId> {883 884 NFT(885 #[derivative(Debug(format_with = "bounded::vec_debug"))]886 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,887 ),888889 890 Fungible(891 #[derivative(Debug(format_with = "bounded::map_debug"))]892 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,893 ),894895 896 897 RefungibleMultipleItems(898 #[derivative(Debug(format_with = "bounded::vec_debug"))]899 BoundedVec<CreateRefungibleExSingleOwner<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,900 ),901902 903 904 RefungibleMultipleOwners(CreateRefungibleExMultipleOwners<CrossAccountId>),905}906907impl From<CreateNftData> for CreateItemData {908 fn from(item: CreateNftData) -> Self {909 CreateItemData::NFT(item)910 }911}912913impl From<CreateReFungibleData> for CreateItemData {914 fn from(item: CreateReFungibleData) -> Self {915 CreateItemData::ReFungible(item)916 }917}918919impl From<CreateFungibleData> for CreateItemData {920 fn from(item: CreateFungibleData) -> Self {921 CreateItemData::Fungible(item)922 }923}924925926#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]927#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]928929pub struct TokenChild {930 931 pub token: TokenId,932933 934 pub collection: CollectionId,935}936937938#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]939#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]940pub struct CollectionStats {941 942 pub created: u32,943944 945 pub destroyed: u32,946947 948 pub alive: u32,949}950951952#[derive(Encode, Decode, Clone, Debug)]953#[cfg_attr(feature = "std", derive(PartialEq))]954pub struct PhantomType<T>(core::marker::PhantomData<T>);955956impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {957 type Identity = PhantomType<T>;958959 fn type_info() -> scale_info::Type {960 use scale_info::{961 Type, Path,962 build::{FieldsBuilder, UnnamedFields},963 type_params,964 };965 Type::builder()966 .path(Path::new("up_data_structs", "PhantomType"))967 .type_params(type_params!(T))968 .composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))969 }970}971impl<T> MaxEncodedLen for PhantomType<T> {972 fn max_encoded_len() -> usize {973 0974 }975}976977978pub type BoundedBytes<S> = BoundedVec<u8, S>;979980981pub type AuxPropertyValue = BoundedBytes<ConstU32<MAX_AUX_PROPERTY_VALUE_LENGTH>>;982983984pub type PropertyKey = BoundedBytes<ConstU32<MAX_PROPERTY_KEY_LENGTH>>;985986987pub type PropertyValue = BoundedBytes<ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;988989990#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]991#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]992pub struct PropertyPermission {993 994 995 996 pub mutable: bool,997998 999 pub collection_admin: bool,10001001 1002 pub token_owner: bool,1003}10041005impl PropertyPermission {1006 1007 pub fn none() -> Self {1008 Self {1009 mutable: true,1010 collection_admin: false,1011 token_owner: false,1012 }1013 }1014}101510161017#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1018#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1019pub struct Property {1020 1021 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1022 pub key: PropertyKey,10231024 1025 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1026 pub value: PropertyValue,1027}10281029impl Into<(PropertyKey, PropertyValue)> for Property {1030 fn into(self) -> (PropertyKey, PropertyValue) {1031 (self.key, self.value)1032 }1033}103410351036#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]1037#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]1038pub struct PropertyKeyPermission {1039 1040 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]1041 pub key: PropertyKey,10421043 1044 pub permission: PropertyPermission,1045}10461047impl Into<(PropertyKey, PropertyPermission)> for PropertyKeyPermission {1048 fn into(self) -> (PropertyKey, PropertyPermission) {1049 (self.key, self.permission)1050 }1051}105210531054#[derive(Debug)]1055pub enum PropertiesError {1056 1057 1058 1059 1060 NoSpaceForProperty,10611062 1063 1064 1065 PropertyLimitReached,10661067 1068 InvalidCharacterInPropertyKey,10691070 1071 1072 1073 PropertyKeyIsTooLong,10741075 1076 EmptyPropertyKey,1077}10781079108010811082#[derive(Encode, Decode, MaxEncodedLen, TypeInfo, PartialEq, Clone, Copy)]1083pub enum PropertyScope {1084 None,1085 Rmrk,1086}10871088impl PropertyScope {1089 1090 pub fn apply(self, key: PropertyKey) -> Result<PropertyKey, PropertiesError> {1091 let scope_str: &[u8] = match self {1092 Self::None => return Ok(key),1093 Self::Rmrk => b"rmrk",1094 };10951096 [scope_str, b":", key.as_slice()]1097 .concat()1098 .try_into()1099 .map_err(|_| PropertiesError::PropertyKeyIsTooLong)1100 }1101}110211031104pub trait TrySetProperty: Sized {1105 type Value;11061107 1108 fn try_scoped_set(1109 &mut self,1110 scope: PropertyScope,1111 key: PropertyKey,1112 value: Self::Value,1113 ) -> Result<(), PropertiesError>;11141115 1116 fn try_scoped_set_from_iter<I, KV>(1117 &mut self,1118 scope: PropertyScope,1119 iter: I,1120 ) -> Result<(), PropertiesError>1121 where1122 I: Iterator<Item = KV>,1123 KV: Into<(PropertyKey, Self::Value)>,1124 {1125 for kv in iter {1126 let (key, value) = kv.into();1127 self.try_scoped_set(scope, key, value)?;1128 }11291130 Ok(())1131 }11321133 1134 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {1135 self.try_scoped_set(PropertyScope::None, key, value)1136 }11371138 1139 fn try_set_from_iter<I, KV>(&mut self, iter: I) -> Result<(), PropertiesError>1140 where1141 I: Iterator<Item = KV>,1142 KV: Into<(PropertyKey, Self::Value)>,1143 {1144 self.try_scoped_set_from_iter(PropertyScope::None, iter)1145 }1146}114711481149#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]1150#[derivative(Default(bound = ""))]1151pub struct PropertiesMap<Value>(1152 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,1153);11541155impl<Value> PropertiesMap<Value> {1156 1157 pub fn new() -> Self {1158 Self(BoundedBTreeMap::new())1159 }11601161 1162 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {1163 Self::check_property_key(key)?;11641165 Ok(self.0.remove(key))1166 }11671168 1169 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {1170 self.0.get(key)1171 }11721173 1174 pub fn contains_key(&self, key: &PropertyKey) -> bool {1175 self.0.contains_key(key)1176 }11771178 1179 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {1180 if key.is_empty() {1181 return Err(PropertiesError::EmptyPropertyKey);1182 }11831184 for byte in key.as_slice().iter() {1185 let byte = *byte;11861187 if !byte.is_ascii_alphanumeric() && byte != b'_' && byte != b'-' && byte != b'.' {1188 return Err(PropertiesError::InvalidCharacterInPropertyKey);1189 }1190 }11911192 Ok(())1193 }1194}11951196impl<Value> IntoIterator for PropertiesMap<Value> {1197 type Item = (PropertyKey, Value);1198 type IntoIter = <1199 BoundedBTreeMap<1200 PropertyKey,1201 Value,1202 ConstU32<MAX_PROPERTIES_PER_ITEM>1203 > as IntoIterator1204 >::IntoIter;12051206 fn into_iter(self) -> Self::IntoIter {1207 self.0.into_iter()1208 }1209}12101211impl<Value> TrySetProperty for PropertiesMap<Value> {1212 type Value = Value;12131214 fn try_scoped_set(1215 &mut self,1216 scope: PropertyScope,1217 key: PropertyKey,1218 value: Self::Value,1219 ) -> Result<(), PropertiesError> {1220 Self::check_property_key(&key)?;12211222 let key = scope.apply(key)?;1223 self.01224 .try_insert(key, value)1225 .map_err(|_| PropertiesError::PropertyLimitReached)?;12261227 Ok(())1228 }1229}123012311232pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;123312341235#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]1236pub struct Properties {1237 map: PropertiesMap<PropertyValue>,1238 consumed_space: u32,1239 space_limit: u32,1240}12411242impl Properties {1243 1244 pub fn new(space_limit: u32) -> Self {1245 Self {1246 map: PropertiesMap::new(),1247 consumed_space: 0,1248 space_limit,1249 }1250 }12511252 1253 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {1254 let value = self.map.remove(key)?;12551256 if let Some(ref value) = value {1257 let value_len = value.len() as u32;1258 self.consumed_space -= value_len;1259 }12601261 Ok(value)1262 }12631264 1265 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {1266 self.map.get(key)1267 }1268}12691270impl IntoIterator for Properties {1271 type Item = (PropertyKey, PropertyValue);1272 type IntoIter = <PropertiesMap<PropertyValue> as IntoIterator>::IntoIter;12731274 fn into_iter(self) -> Self::IntoIter {1275 self.map.into_iter()1276 }1277}12781279impl TrySetProperty for Properties {1280 type Value = PropertyValue;12811282 fn try_scoped_set(1283 &mut self,1284 scope: PropertyScope,1285 key: PropertyKey,1286 value: Self::Value,1287 ) -> Result<(), PropertiesError> {1288 let value_len = value.len();12891290 if self.consumed_space as usize + value_len > self.space_limit as usize1291 && !cfg!(feature = "runtime-benchmarks")1292 {1293 return Err(PropertiesError::NoSpaceForProperty);1294 }12951296 self.map.try_scoped_set(scope, key, value)?;12971298 self.consumed_space += value_len as u32;12991300 Ok(())1301 }1302}130313041305pub struct CollectionProperties;13061307impl Get<Properties> for CollectionProperties {1308 fn get() -> Properties {1309 Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)1310 }1311}131213131314pub struct TokenProperties;13151316impl Get<Properties> for TokenProperties {1317 fn get() -> Properties {1318 Properties::new(MAX_TOKEN_PROPERTIES_SIZE)1319 }1320}1321132213231324parameter_types! {1325 #[derive(PartialEq, TypeInfo)]1326 pub const RmrkStringLimit: u32 = 128;1327 #[derive(PartialEq)]1328 pub const RmrkCollectionSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;1329 #[derive(PartialEq)]1330 pub const RmrkResourceSymbolLimit: u32 = 10;1331 #[derive(PartialEq)]1332 pub const RmrkBaseSymbolLimit: u32 = MAX_TOKEN_PREFIX_LENGTH;1333 #[derive(PartialEq)]1334 pub const RmrkKeyLimit: u32 = 32;1335 #[derive(PartialEq)]1336 pub const RmrkValueLimit: u32 = 256;1337 #[derive(PartialEq)]1338 pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;1339 #[derive(PartialEq)]1340 pub const MaxPropertiesPerTheme: u32 = 5;1341 #[derive(PartialEq)]1342 pub const RmrkPartsLimit: u32 = 25;1343 #[derive(PartialEq)]1344 pub const RmrkMaxPriorities: u32 = 25;1345 #[derive(PartialEq)]1346 pub const MaxResourcesOnMint: u32 = 100;1347}13481349impl From<RmrkCollectionId> for CollectionId {1350 fn from(id: RmrkCollectionId) -> Self {1351 Self(id)1352 }1353}13541355impl From<RmrkNftId> for TokenId {1356 fn from(id: RmrkNftId) -> Self {1357 Self(id)1358 }1359}13601361pub type RmrkCollectionInfo<AccountId> =1362 CollectionInfo<RmrkString, RmrkCollectionSymbol, AccountId>;1363pub type RmrkInstanceInfo<AccountId> = NftInfo<AccountId, Permill, RmrkString>;1364pub type RmrkResourceInfo = ResourceInfo<RmrkString, RmrkBoundedParts>;1365pub type RmrkPropertyInfo = PropertyInfo<RmrkKeyString, RmrkValueString>;1366pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;1367pub type BoundedEquippableCollectionIds =1368 BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>;1369pub type RmrkPartType = PartType<RmrkString, BoundedEquippableCollectionIds>;1370pub type RmrkEquippableList = EquippableList<BoundedEquippableCollectionIds>;1371pub type RmrkThemeProperty = ThemeProperty<RmrkString>;1372pub type RmrkTheme = Theme<RmrkString, Vec<RmrkThemeProperty>>;1373pub type RmrkBoundedTheme = Theme<RmrkString, BoundedVec<RmrkThemeProperty, MaxPropertiesPerTheme>>;1374pub type RmrkResourceTypes = ResourceTypes<RmrkString, RmrkBoundedParts>;13751376pub type RmrkBasicResource = BasicResource<RmrkString>;1377pub type RmrkComposableResource = ComposableResource<RmrkString, RmrkBoundedParts>;1378pub type RmrkSlotResource = SlotResource<RmrkString>;13791380pub type RmrkString = BoundedVec<u8, RmrkStringLimit>;1381pub type RmrkCollectionSymbol = BoundedVec<u8, RmrkCollectionSymbolLimit>;1382pub type RmrkBaseSymbol = BoundedVec<u8, RmrkBaseSymbolLimit>;1383pub type RmrkKeyString = BoundedVec<u8, RmrkKeyLimit>;1384pub type RmrkValueString = BoundedVec<u8, RmrkValueLimit>;1385pub type RmrkBoundedResource = BoundedVec<u8, RmrkResourceSymbolLimit>;1386pub type RmrkBoundedParts = BoundedVec<RmrkPartId, RmrkPartsLimit>; 13871388pub type RmrkRpcString = Vec<u8>;1389pub type RmrkThemeName = RmrkRpcString;1390pub type RmrkPropertyKey = RmrkRpcString;