1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "serde")]4pub use serde::{Serialize, Deserialize};56use sp_runtime::sp_std::prelude::Vec;7use codec::{Decode, Encode, MaxEncodedLen};8pub use frame_support::{9 BoundedVec, construct_runtime, decl_event, decl_module, decl_storage, decl_error,10 dispatch::DispatchResult,11 ensure, fail, parameter_types,12 traits::{13 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,14 Randomness, IsSubType, WithdrawReasons,15 },16 weights::{17 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},18 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,19 WeightToFeePolynomial, DispatchClass,20 },21 StorageValue, transactional,22};23use derivative::Derivative;2425pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;26pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;27pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;28pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;2930pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {31 10000032} else {33 1034};35pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {36 204837} else {38 1039};40pub const COLLECTION_ADMINS_LIMIT: u64 = 5;41pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {42 100000043} else {44 1045};464748pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;49pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;50pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;515253pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;54pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;55pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;5657pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;58pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;59pub const MAX_TOKEN_PREFIX_LENGTH: usize = 16;60616263pub const MAX_ITEMS_PER_BATCH: u32 = 200;6465parameter_types! {66 pub const CustomDataLimit: u32 = CUSTOM_DATA_LIMIT;67}6869pub type CollectionId = u32;70pub type TokenId = u32;71pub type DecimalPoints = u8;7273#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]74#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]75pub enum CollectionMode {76 Invalid,77 NFT,78 79 Fungible(DecimalPoints),80 ReFungible,81}8283impl Default for CollectionMode {84 fn default() -> Self {85 Self::Invalid86 }87}8889impl CollectionMode {90 pub fn id(&self) -> u8 {91 match self {92 CollectionMode::Invalid => 0,93 CollectionMode::NFT => 1,94 CollectionMode::Fungible(_) => 2,95 CollectionMode::ReFungible => 3,96 }97 }98}99100pub trait SponsoringResolve<AccountId, Call> {101 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;102}103104#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]105#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]106pub enum AccessMode {107 Normal,108 WhiteList,109}110impl Default for AccessMode {111 fn default() -> Self {112 Self::Normal113 }114}115116#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]117#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]118pub enum SchemaVersion {119 ImageURL,120 Unique,121}122impl Default for SchemaVersion {123 fn default() -> Self {124 Self::ImageURL125 }126}127128#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]129#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]130pub struct Ownership<AccountId> {131 pub owner: AccountId,132 pub fraction: u128,133}134135#[derive(Encode, Decode, Debug, Clone, PartialEq)]136#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]137pub enum SponsorshipState<AccountId> {138 139 Disabled,140 Unconfirmed(AccountId),141 142 Confirmed(AccountId),143}144145impl<AccountId> SponsorshipState<AccountId> {146 pub fn sponsor(&self) -> Option<&AccountId> {147 match self {148 Self::Confirmed(sponsor) => Some(sponsor),149 _ => None,150 }151 }152153 pub fn pending_sponsor(&self) -> Option<&AccountId> {154 match self {155 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),156 _ => None,157 }158 }159160 pub fn confirmed(&self) -> bool {161 matches!(self, Self::Confirmed(_))162 }163}164165impl<T> Default for SponsorshipState<T> {166 fn default() -> Self {167 Self::Disabled168 }169}170171#[derive(Encode, Decode, Clone, PartialEq)]172#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]173pub struct Collection<T: frame_system::Config> {174 pub owner: T::AccountId,175 pub mode: CollectionMode,176 pub access: AccessMode,177 pub decimal_points: DecimalPoints,178 pub name: Vec<u16>, 179 pub description: Vec<u16>, 180 pub token_prefix: Vec<u8>, 181 pub mint_mode: bool,182 pub offchain_schema: Vec<u8>,183 pub schema_version: SchemaVersion,184 pub sponsorship: SponsorshipState<T::AccountId>,185 pub limits: CollectionLimits<T::BlockNumber>, 186 pub variable_on_chain_schema: Vec<u8>, 187 pub const_on_chain_schema: Vec<u8>, 188 pub meta_update_permission: MetaUpdatePermission,189 pub transfers_enabled: bool,190}191192#[derive(Encode, Decode, Debug, Clone, PartialEq)]193#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]194pub struct NftItemType<AccountId> {195 pub owner: AccountId,196 pub const_data: Vec<u8>,197 pub variable_data: Vec<u8>,198}199200#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]201#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]202pub struct FungibleItemType {203 pub value: u128,204}205206#[derive(Encode, Decode, Debug, Clone, PartialEq)]207#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]208pub struct ReFungibleItemType<AccountId> {209 pub owner: Vec<Ownership<AccountId>>,210 pub const_data: Vec<u8>,211 pub variable_data: Vec<u8>,212}213214#[derive(Encode, Decode, Debug, Clone, PartialEq)]215#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]216pub struct CollectionLimits<BlockNumber: Encode + Decode> {217 pub account_token_ownership_limit: u32,218 pub sponsored_data_size: u32,219 220 221 222 pub sponsored_data_rate_limit: Option<BlockNumber>,223 pub token_limit: u32,224225 226 pub sponsor_transfer_timeout: u32,227 pub owner_can_transfer: bool,228 pub owner_can_destroy: bool,229}230231impl<BlockNumber: Encode + Decode> Default for CollectionLimits<BlockNumber> {232 fn default() -> Self {233 Self {234 account_token_ownership_limit: 10_000_000,235 token_limit: u32::max_value(),236 sponsored_data_size: u32::MAX,237 sponsored_data_rate_limit: None,238 sponsor_transfer_timeout: 14400,239 owner_can_transfer: true,240 owner_can_destroy: true,241 }242 }243}244245246#[cfg(feature = "serde1")]247mod bounded_serde {248 use core::convert::TryFrom;249 use frame_support::{BoundedVec, traits::Get};250 use serde::{251 ser::{self, Serialize},252 de::{self, Deserialize, Error},253 };254 use sp_std::vec::Vec;255256 pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>257 where258 D: ser::Serializer,259 V: Serialize,260 {261 let vec: &Vec<_> = &value;262 vec.serialize(serializer)263 }264265 pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>266 where267 D: de::Deserializer<'de>,268 V: de::Deserialize<'de>,269 S: Get<u32>,270 {271 272 let vec = <Vec<V>>::deserialize(deserializer)?;273 let len = vec.len();274 TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))275 }276}277278#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative)]279#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]280#[derivative(Debug)]281pub struct CreateNftData {282 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]283 #[derivative(Debug = "ignore")]284 pub const_data: BoundedVec<u8, CustomDataLimit>,285 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]286 #[derivative(Debug = "ignore")]287 pub variable_data: BoundedVec<u8, CustomDataLimit>,288}289290#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq)]291#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]292pub struct CreateFungibleData {293 pub value: u128,294}295296#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative)]297#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]298#[derivative(Debug)]299pub struct CreateReFungibleData {300 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]301 #[derivative(Debug = "ignore")]302 pub const_data: BoundedVec<u8, CustomDataLimit>,303 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]304 #[derivative(Debug = "ignore")]305 pub variable_data: BoundedVec<u8, CustomDataLimit>,306 pub pieces: u128,307}308309#[derive(Encode, Decode, Debug, Clone, PartialEq)]310#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]311pub enum MetaUpdatePermission {312 ItemOwner,313 Admin,314 None,315}316317impl Default for MetaUpdatePermission {318 fn default() -> Self {319 Self::ItemOwner320 }321}322323#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug)]324#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]325pub enum CreateItemData {326 NFT(CreateNftData),327 Fungible(CreateFungibleData),328 ReFungible(CreateReFungibleData),329}330331impl CreateItemData {332 pub fn data_size(&self) -> usize {333 match self {334 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),335 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),336 _ => 0,337 }338 }339}340341impl From<CreateNftData> for CreateItemData {342 fn from(item: CreateNftData) -> Self {343 CreateItemData::NFT(item)344 }345}346347impl From<CreateReFungibleData> for CreateItemData {348 fn from(item: CreateReFungibleData) -> Self {349 CreateItemData::ReFungible(item)350 }351}352353impl From<CreateFungibleData> for CreateItemData {354 fn from(item: CreateFungibleData) -> Self {355 CreateItemData::Fungible(item)356 }357}