1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819use core::{20 convert::{TryFrom, TryInto},21 fmt,22};23use frame_support::{24 storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet},25 traits::Get, parameter_types,26};2728#[cfg(feature = "serde")]29use serde::{Serialize, Deserialize};3031use sp_core::U256;32use sp_runtime::{ArithmeticError, sp_std::prelude::Vec, Permill};33use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};34use frame_support::{BoundedVec, traits::ConstU32};35use derivative::Derivative;36use scale_info::TypeInfo;373839use rmrk_types::{40 CollectionInfo, NftInfo, ResourceInfo, PropertyInfo, BaseInfo, PartType, Theme, ThemeProperty,41};42pub use rmrk_types::{43 primitives::{CollectionId as RmrkCollectionId, NftId as RmrkNftId, BaseId as RmrkBaseId, PartId as RmrkPartId, ResourceId as RmrkResourceId},44 NftChild as RmrkNftChild, AccountIdOrCollectionNftTuple as RmrkAccountIdOrCollectionNftTuple,45};4647mod bounded;48pub mod budget;49pub mod mapping;50mod migration;5152pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;53pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;54pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;5556pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {57 100_00058} else {59 1060};61pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {62 100_00063} else {64 1065};66pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {67 204868} else {69 1070};71pub const COLLECTION_ADMINS_LIMIT: u32 = 5;72pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;73pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {74 1_000_00075} else {76 1077};787980pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;81pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;82pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;8384pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;858687pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;88pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;8990pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;9192pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;93pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;94pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;9596pub const MAX_PROPERTY_KEY_LENGTH: u32 = 256;97pub const MAX_PROPERTY_VALUE_LENGTH: u32 = 32768;98pub const MAX_PROPERTIES_PER_ITEM: u32 = 64;99100101pub const MAX_COLLECTION_PROPERTIES_SIZE: u32 = 40960;102pub const MAX_TOKEN_PROPERTIES_SIZE: u32 = 32768;103104pub const MAX_COLLECTION_PROPERTIES_ENCODE_LEN: u32 =105 MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH + MAX_COLLECTION_PROPERTIES_SIZE;106107108pub const RMRK_STRING_LIMIT: u32 = 128;109pub const RMRK_COLLECTION_SYMBOL_LIMIT: u32 = 100;110pub const RMRK_RESOURCE_SYMBOL_LIMIT: u32 = 10;111pub const RMRK_KEY_LIMIT: u32 = 32;112pub const RMRK_VALUE_LIMIT: u32 = 256;113114pub struct MaxPropertiesPermissionsEncodeLen;115116impl Get<u32> for MaxPropertiesPermissionsEncodeLen {117 fn get() -> u32 {118 MAX_PROPERTIES_PER_ITEM * MAX_PROPERTY_KEY_LENGTH119 + <PropertyPermission as MaxEncodedLen>::max_encoded_len() as u32120 }121}122123124125pub const MAX_ITEMS_PER_BATCH: u32 = 200;126127pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;128129#[derive(130 Encode,131 Decode,132 PartialEq,133 Eq,134 PartialOrd,135 Ord,136 Clone,137 Copy,138 Debug,139 Default,140 TypeInfo,141 MaxEncodedLen,142)]143#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]144pub struct CollectionId(pub u32);145impl EncodeLike<u32> for CollectionId {}146impl EncodeLike<CollectionId> for u32 {}147148#[derive(149 Encode,150 Decode,151 PartialEq,152 Eq,153 PartialOrd,154 Ord,155 Clone,156 Copy,157 Debug,158 Default,159 TypeInfo,160 MaxEncodedLen,161)]162#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]163pub struct TokenId(pub u32);164impl EncodeLike<u32> for TokenId {}165impl EncodeLike<TokenId> for u32 {}166167impl TokenId {168 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {169 self.0170 .checked_add(1)171 .ok_or(ArithmeticError::Overflow)172 .map(Self)173 }174}175176impl From<TokenId> for U256 {177 fn from(t: TokenId) -> Self {178 t.0.into()179 }180}181182impl TryFrom<U256> for TokenId {183 type Error = &'static str;184185 fn try_from(value: U256) -> Result<Self, Self::Error> {186 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))187 }188}189190#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]191#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]192pub struct TokenData<CrossAccountId> {193 pub const_data: Vec<u8>,194 pub properties: Vec<Property>,195 pub owner: Option<CrossAccountId>,196}197198pub struct OverflowError;199impl From<OverflowError> for &'static str {200 fn from(_: OverflowError) -> Self {201 "overflow occured"202 }203}204205pub type DecimalPoints = u8;206207#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]208#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]209pub enum CollectionMode {210 NFT,211 212 Fungible(DecimalPoints),213 ReFungible,214}215216impl CollectionMode {217 pub fn id(&self) -> u8 {218 match self {219 CollectionMode::NFT => 1,220 CollectionMode::Fungible(_) => 2,221 CollectionMode::ReFungible => 3,222 }223 }224}225226pub trait SponsoringResolve<AccountId, Call> {227 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;228}229230#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]231#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]232pub enum AccessMode {233 Normal,234 AllowList,235}236impl Default for AccessMode {237 fn default() -> Self {238 Self::Normal239 }240}241242#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]243#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]244pub enum SchemaVersion {245 ImageURL,246 Unique,247}248impl Default for SchemaVersion {249 fn default() -> Self {250 Self::ImageURL251 }252}253254#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]255#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]256pub struct Ownership<AccountId> {257 pub owner: AccountId,258 pub fraction: u128,259}260261#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]262#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]263pub enum SponsorshipState<AccountId> {264 265 Disabled,266 Unconfirmed(AccountId),267 268 Confirmed(AccountId),269}270271impl<AccountId> SponsorshipState<AccountId> {272 pub fn sponsor(&self) -> Option<&AccountId> {273 match self {274 Self::Confirmed(sponsor) => Some(sponsor),275 _ => None,276 }277 }278279 pub fn pending_sponsor(&self) -> Option<&AccountId> {280 match self {281 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),282 _ => None,283 }284 }285286 pub fn confirmed(&self) -> bool {287 matches!(self, Self::Confirmed(_))288 }289}290291impl<T> Default for SponsorshipState<T> {292 fn default() -> Self {293 Self::Disabled294 }295}296297298#[struct_versioning::versioned(version = 2, upper)]299#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]300pub struct Collection<AccountId> {301 pub owner: AccountId,302 pub mode: CollectionMode,303 pub access: AccessMode,304 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,305 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,306 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,307 pub mint_mode: bool,308309 #[version(..2)]310 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,311312 pub schema_version: SchemaVersion,313 pub sponsorship: SponsorshipState<AccountId>,314315 #[version(..2)]316 pub limits: CollectionLimitsVersion1, 317 #[version(2.., upper(limits.into()))]318 pub limits: CollectionLimitsVersion2,319320 #[version(..2)]321 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,322323 pub meta_update_permission: MetaUpdatePermission,324}325326327#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]328#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]329pub struct RpcCollection<AccountId> {330 pub owner: AccountId,331 pub mode: CollectionMode,332 pub access: AccessMode,333 pub name: Vec<u16>,334 pub description: Vec<u16>,335 pub token_prefix: Vec<u8>,336 pub mint_mode: bool,337 pub offchain_schema: Vec<u8>,338 pub schema_version: SchemaVersion,339 pub sponsorship: SponsorshipState<AccountId>,340 pub limits: CollectionLimits,341 pub const_on_chain_schema: Vec<u8>,342 pub meta_update_permission: MetaUpdatePermission,343 pub token_property_permissions: Vec<PropertyKeyPermission>,344 pub properties: Vec<Property>,345}346347#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]348#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]349pub enum CollectionField {350 ConstOnChainSchema,351 OffchainSchema,352}353354#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Derivative, MaxEncodedLen)]355#[derivative(Debug, Default(bound = ""))]356pub struct CreateCollectionData<AccountId> {357 #[derivative(Default(value = "CollectionMode::NFT"))]358 pub mode: CollectionMode,359 pub access: Option<AccessMode>,360 pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,361 pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,362 pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,363 pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,364 pub schema_version: Option<SchemaVersion>,365 pub pending_sponsor: Option<AccountId>,366 pub limits: Option<CollectionLimits>,367 pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,368 pub meta_update_permission: Option<MetaUpdatePermission>,369 pub token_property_permissions: CollectionPropertiesPermissionsVec,370 pub properties: CollectionPropertiesVec,371}372373pub type CollectionPropertiesPermissionsVec =374 BoundedVec<PropertyKeyPermission, MaxPropertiesPermissionsEncodeLen>;375376pub type CollectionPropertiesVec =377 BoundedVec<Property, ConstU32<MAX_COLLECTION_PROPERTIES_ENCODE_LEN>>;378379#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]380#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]381pub struct NftItemType<AccountId> {382 pub owner: AccountId,383 pub const_data: Vec<u8>,384 pub variable_data: Vec<u8>,385}386387#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]388#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]389pub struct FungibleItemType {390 pub value: u128,391}392393#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]394#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]395pub struct ReFungibleItemType<AccountId> {396 pub owner: Vec<Ownership<AccountId>>,397 pub const_data: Vec<u8>,398 pub variable_data: Vec<u8>,399}400401402#[struct_versioning::versioned(version = 2, upper)]403#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]404#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]405pub struct CollectionLimits {406 pub account_token_ownership_limit: Option<u32>,407 pub sponsored_data_size: Option<u32>,408 409 410 411 pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,412 pub token_limit: Option<u32>,413414 415 pub sponsor_transfer_timeout: Option<u32>,416 pub sponsor_approve_timeout: Option<u32>,417 pub owner_can_transfer: Option<bool>,418 pub owner_can_destroy: Option<bool>,419 pub transfers_enabled: Option<bool>,420421 #[version(2.., upper(None))]422 pub nesting_rule: Option<NestingRule>,423}424425impl CollectionLimits {426 pub fn account_token_ownership_limit(&self) -> u32 {427 self.account_token_ownership_limit428 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)429 .min(MAX_TOKEN_OWNERSHIP)430 }431 pub fn sponsored_data_size(&self) -> u32 {432 self.sponsored_data_size433 .unwrap_or(CUSTOM_DATA_LIMIT)434 .min(CUSTOM_DATA_LIMIT)435 }436 pub fn token_limit(&self) -> u32 {437 self.token_limit438 .unwrap_or(COLLECTION_TOKEN_LIMIT)439 .min(COLLECTION_TOKEN_LIMIT)440 }441 pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {442 self.sponsor_transfer_timeout443 .unwrap_or(default)444 .min(MAX_SPONSOR_TIMEOUT)445 }446 pub fn sponsor_approve_timeout(&self) -> u32 {447 self.sponsor_approve_timeout448 .unwrap_or(SPONSOR_APPROVE_TIMEOUT)449 .min(MAX_SPONSOR_TIMEOUT)450 }451 pub fn owner_can_transfer(&self) -> bool {452 self.owner_can_transfer.unwrap_or(true)453 }454 pub fn owner_can_destroy(&self) -> bool {455 self.owner_can_destroy.unwrap_or(true)456 }457 pub fn transfers_enabled(&self) -> bool {458 self.transfers_enabled.unwrap_or(true)459 }460 pub fn sponsored_data_rate_limit(&self) -> Option<u32> {461 match self462 .sponsored_data_rate_limit463 .unwrap_or(SponsoringRateLimit::SponsoringDisabled)464 {465 SponsoringRateLimit::SponsoringDisabled => None,466 SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),467 }468 }469 pub fn nesting_rule(&self) -> &NestingRule {470 static DEFAULT: NestingRule = NestingRule::Disabled;471 self.nesting_rule.as_ref().unwrap_or(&DEFAULT)472 }473}474475#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]476#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]477#[derivative(Debug)]478pub enum NestingRule {479 480 Disabled,481 482 Owner,483 484 OwnerRestricted(485 #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]486 #[derivative(Debug(format_with = "bounded::set_debug"))]487 BoundedBTreeSet<CollectionId, ConstU32<16>>,488 ),489}490491#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]492#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]493pub enum SponsoringRateLimit {494 SponsoringDisabled,495 Blocks(u32),496}497498#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]499#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]500#[derivative(Debug)]501pub struct CreateNftData {502 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]503 #[derivative(Debug(format_with = "bounded::vec_debug"))]504 pub const_data: BoundedVec<u8, CustomDataLimit>,505 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]506 #[derivative(Debug(format_with = "bounded::vec_debug"))]507 pub variable_data: BoundedVec<u8, CustomDataLimit>,508509 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]510 #[derivative(Debug(format_with = "bounded::vec_debug"))]511 pub properties: CollectionPropertiesVec,512}513514#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]515#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]516pub struct CreateFungibleData {517 pub value: u128,518}519520#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]521#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]522#[derivative(Debug)]523pub struct CreateReFungibleData {524 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]525 #[derivative(Debug(format_with = "bounded::vec_debug"))]526 pub const_data: BoundedVec<u8, CustomDataLimit>,527 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]528 #[derivative(Debug(format_with = "bounded::vec_debug"))]529 pub variable_data: BoundedVec<u8, CustomDataLimit>,530 pub pieces: u128,531}532533#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]534#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]535pub enum MetaUpdatePermission {536 ItemOwner,537 Admin,538 None,539}540541impl Default for MetaUpdatePermission {542 fn default() -> Self {543 Self::ItemOwner544 }545}546547#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]548#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]549pub enum CreateItemData {550 NFT(CreateNftData),551 Fungible(CreateFungibleData),552 ReFungible(CreateReFungibleData),553}554555#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]556#[derivative(Debug)]557pub struct CreateNftExData<CrossAccountId> {558 #[derivative(Debug(format_with = "bounded::vec_debug"))]559 pub const_data: BoundedVec<u8, CustomDataLimit>,560 #[derivative(Debug(format_with = "bounded::vec_debug"))]561 pub variable_data: BoundedVec<u8, CustomDataLimit>,562 #[derivative(Debug(format_with = "bounded::vec_debug"))]563 pub properties: CollectionPropertiesVec,564 pub owner: CrossAccountId,565}566567#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]568#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]569pub struct CreateRefungibleExData<CrossAccountId> {570 #[derivative(Debug(format_with = "bounded::vec_debug"))]571 pub const_data: BoundedVec<u8, CustomDataLimit>,572 #[derivative(Debug(format_with = "bounded::vec_debug"))]573 pub variable_data: BoundedVec<u8, CustomDataLimit>,574 #[derivative(Debug(format_with = "bounded::map_debug"))]575 pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,576}577578#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]579#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]580pub enum CreateItemExData<CrossAccountId> {581 NFT(582 #[derivative(Debug(format_with = "bounded::vec_debug"))]583 BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,584 ),585 Fungible(586 #[derivative(Debug(format_with = "bounded::map_debug"))]587 BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,588 ),589 590 RefungibleMultipleItems(591 #[derivative(Debug(format_with = "bounded::vec_debug"))]592 BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,593 ),594 595 RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),596}597598impl CreateItemData {599 pub fn data_size(&self) -> usize {600 match self {601 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),602 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),603 _ => 0,604 }605 }606}607608impl From<CreateNftData> for CreateItemData {609 fn from(item: CreateNftData) -> Self {610 CreateItemData::NFT(item)611 }612}613614impl From<CreateReFungibleData> for CreateItemData {615 fn from(item: CreateReFungibleData) -> Self {616 CreateItemData::ReFungible(item)617 }618}619620impl From<CreateFungibleData> for CreateItemData {621 fn from(item: CreateFungibleData) -> Self {622 CreateItemData::Fungible(item)623 }624}625626#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]627#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]628pub struct CollectionStats {629 pub created: u32,630 pub destroyed: u32,631 pub alive: u32,632}633634#[derive(Encode, Decode, Clone, Debug)]635#[cfg_attr(feature = "std", derive(PartialEq))]636pub struct PhantomType<T>(core::marker::PhantomData<T>);637638impl<T: TypeInfo + 'static> TypeInfo for PhantomType<T> {639 type Identity = PhantomType<T>;640641 fn type_info() -> scale_info::Type {642 use scale_info::{643 Type, Path,644 build::{FieldsBuilder, UnnamedFields},645 type_params,646 };647 Type::builder()648 .path(Path::new("up_data_structs", "PhantomType"))649 .type_params(type_params!(T))650 .composite(<FieldsBuilder<UnnamedFields>>::default().field(|b| b.ty::<[T; 0]>()))651 }652}653impl<T> MaxEncodedLen for PhantomType<T> {654 fn max_encoded_len() -> usize {655 0656 }657}658659pub type PropertyKey = BoundedVec<u8, ConstU32<MAX_PROPERTY_KEY_LENGTH>>;660pub type PropertyValue = BoundedVec<u8, ConstU32<MAX_PROPERTY_VALUE_LENGTH>>;661662#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]663#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]664pub struct PropertyPermission {665 pub mutable: bool,666 pub collection_admin: bool,667 pub token_owner: bool,668}669670impl PropertyPermission {671 pub fn none() -> Self {672 Self {673 mutable: true,674 collection_admin: false,675 token_owner: false,676 }677 }678}679680#[derive(Encode, Decode, Debug, TypeInfo, Clone, PartialEq, MaxEncodedLen)]681#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]682pub struct Property {683 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]684 pub key: PropertyKey,685686 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]687 pub value: PropertyValue,688}689690#[derive(Encode, Decode, TypeInfo, Debug, MaxEncodedLen, PartialEq, Clone)]691#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]692pub struct PropertyKeyPermission {693 #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]694 pub key: PropertyKey,695696 pub permission: PropertyPermission,697}698699pub enum PropertiesError {700 NoSpaceForProperty,701 PropertyLimitReached,702 InvalidCharacterInPropertyKey,703 EmptyPropertyKey,704}705706pub trait TrySet: Sized {707 type Value;708709 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError>;710711 fn try_set_from_iter<I>(&mut self, iter: I) -> Result<(), PropertiesError>712 where713 I: Iterator<Item = (PropertyKey, Self::Value)>,714 {715 for (key, value) in iter {716 self.try_set(key, value)?;717 }718719 Ok(())720 }721}722723#[derive(Encode, Decode, TypeInfo, Derivative, Clone, PartialEq, MaxEncodedLen)]724#[derivative(Default(bound = ""))]725pub struct PropertiesMap<Value>(726 BoundedBTreeMap<PropertyKey, Value, ConstU32<MAX_PROPERTIES_PER_ITEM>>,727);728729impl<Value> PropertiesMap<Value> {730 pub fn new() -> Self {731 Self(BoundedBTreeMap::new())732 }733734 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<Value>, PropertiesError> {735 Self::check_property_key(key)?;736737 Ok(self.0.remove(key))738 }739740 pub fn get(&self, key: &PropertyKey) -> Option<&Value> {741 self.0.get(key)742 }743744 pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &Value)> {745 self.0.iter()746 }747748 fn check_property_key(key: &PropertyKey) -> Result<(), PropertiesError> {749 if key.is_empty() {750 return Err(PropertiesError::EmptyPropertyKey);751 }752753 for byte in key.as_slice().iter() {754 match char::from_u32(*byte as u32) {755 Some(ch)756 if ch.is_ascii_alphanumeric()757 || ch == '_'758 || ch == '-' => { },759 _ => return Err(PropertiesError::InvalidCharacterInPropertyKey)760 }761 }762763 Ok(())764 }765}766767impl<Value> TrySet for PropertiesMap<Value> {768 type Value = Value;769770 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {771 Self::check_property_key(&key)?;772773 self.0774 .try_insert(key, value)775 .map_err(|_| PropertiesError::PropertyLimitReached)?;776777 Ok(())778 }779}780781pub type PropertiesPermissionMap = PropertiesMap<PropertyPermission>;782783#[derive(Encode, Decode, TypeInfo, Clone, PartialEq, MaxEncodedLen)]784pub struct Properties {785 map: PropertiesMap<PropertyValue>,786 consumed_space: u32,787 space_limit: u32,788}789790impl Properties {791 pub fn new(space_limit: u32) -> Self {792 Self {793 map: PropertiesMap::new(),794 consumed_space: 0,795 space_limit,796 }797 }798799 pub fn remove(&mut self, key: &PropertyKey) -> Result<Option<PropertyValue>, PropertiesError> {800 let value = self.map.remove(key)?;801802 if let Some(ref value) = value {803 let value_len = value.len() as u32;804 self.consumed_space -= value_len;805 }806807 Ok(value)808 }809810 pub fn get(&self, key: &PropertyKey) -> Option<&PropertyValue> {811 self.map.get(key)812 }813814 pub fn iter(&self) -> impl Iterator<Item = (&PropertyKey, &PropertyValue)> {815 self.map.iter()816 }817}818819impl TrySet for Properties {820 type Value = PropertyValue;821822 fn try_set(&mut self, key: PropertyKey, value: Self::Value) -> Result<(), PropertiesError> {823 let value_len = value.len();824825 if self.consumed_space as usize + value_len > self.space_limit as usize {826 return Err(PropertiesError::NoSpaceForProperty);827 }828829 self.map.try_set(key, value)?;830831 self.consumed_space += value_len as u32;832833 Ok(())834 }835}836837pub struct CollectionProperties;838839impl Get<Properties> for CollectionProperties {840 fn get() -> Properties {841 Properties::new(MAX_COLLECTION_PROPERTIES_SIZE)842 }843}844845pub struct TokenProperties;846847impl Get<Properties> for TokenProperties {848 fn get() -> Properties {849 Properties::new(MAX_TOKEN_PROPERTIES_SIZE)850 }851}852853854855parameter_types! {856 #[derive(PartialEq, TypeInfo)]857 pub const RmrkStringLimit: u32 = 128;858 #[derive(PartialEq)]859 pub const RmrkCollectionSymbolLimit: u32 = 100;860 #[derive(PartialEq)]861 pub const RmrkResourceSymbolLimit: u32 = 10;862 #[derive(PartialEq)]863 pub const RmrkKeyLimit: u32 = 32;864 #[derive(PartialEq)]865 pub const RmrkValueLimit: u32 = 256;866 #[derive(PartialEq)]867 pub const RmrkMaxCollectionsEquippablePerPart: u32 = 100;868 #[derive(PartialEq)]869 pub const RmrkPartsLimit: u32 = 3;870}871872pub type RmrkCollectionInfo<AccountId> = CollectionInfo<873 RmrkString,874 BoundedVec<u8, RmrkCollectionSymbolLimit>,875 AccountId876>;877pub type RmrkInstanceInfo<AccountId> = NftInfo<878 AccountId, 879 Permill,880 RmrkString881>;882pub type RmrkResourceInfo = ResourceInfo::<883 BoundedVec<u8, RmrkResourceSymbolLimit>,884 RmrkString,885 BoundedVec<RmrkPartId, RmrkPartsLimit>886>;887pub type RmrkPropertyInfo = PropertyInfo<888 BoundedVec<u8, RmrkKeyLimit>, 889 BoundedVec<u8, RmrkValueLimit>890>;891pub type RmrkBaseInfo<AccountId> = BaseInfo<AccountId, RmrkString>;892pub type RmrkPartType = PartType<893 RmrkString,894 BoundedVec<RmrkCollectionId, RmrkMaxCollectionsEquippablePerPart>895>;896pub type RmrkTheme = Theme<RmrkString, Vec<ThemeProperty<RmrkString>>>;897898pub type RmrkRpcString = Vec<u8>;899pub type RmrkThemeName = RmrkRpcString;900pub type RmrkPropertyKey = RmrkRpcString;901902type RmrkString = BoundedVec<u8, RmrkStringLimit>;