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};8use max_encoded_len::MaxEncodedLen;9pub use frame_support::{10 BoundedVec, construct_runtime, decl_event, decl_module, decl_storage, decl_error,11 dispatch::DispatchResult,12 ensure, fail, parameter_types,13 traits::{14 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,15 Randomness, IsSubType, WithdrawReasons,16 },17 weights::{18 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},19 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,20 WeightToFeePolynomial, DispatchClass,21 },22 StorageValue, transactional,23};24use derivative::Derivative;2526pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;27pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;28pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;29pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;3031pub type CollectionId = u32;32pub type TokenId = u32;33pub type DecimalPoints = u8;3435#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]36#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]37pub enum CollectionMode {38 Invalid,39 NFT,40 41 Fungible(DecimalPoints),42 ReFungible,43}4445impl Default for CollectionMode {46 fn default() -> Self {47 Self::Invalid48 }49}5051impl CollectionMode {52 pub fn id(&self) -> u8 {53 match self {54 CollectionMode::Invalid => 0,55 CollectionMode::NFT => 1,56 CollectionMode::Fungible(_) => 2,57 CollectionMode::ReFungible => 3,58 }59 }60}6162pub trait SponsoringResolve<AccountId, Call> {63 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;64}6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]68pub enum AccessMode {69 Normal,70 WhiteList,71}72impl Default for AccessMode {73 fn default() -> Self {74 Self::Normal75 }76}7778#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]79#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]80pub enum SchemaVersion {81 ImageURL,82 Unique,83}84impl Default for SchemaVersion {85 fn default() -> Self {86 Self::ImageURL87 }88}8990#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]91#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]92pub struct Ownership<AccountId> {93 pub owner: AccountId,94 pub fraction: u128,95}9697#[derive(Encode, Decode, Debug, Clone, PartialEq)]98#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]99pub enum SponsorshipState<AccountId> {100 101 Disabled,102 Unconfirmed(AccountId),103 104 Confirmed(AccountId),105}106107impl<AccountId> SponsorshipState<AccountId> {108 pub fn sponsor(&self) -> Option<&AccountId> {109 match self {110 Self::Confirmed(sponsor) => Some(sponsor),111 _ => None,112 }113 }114115 pub fn pending_sponsor(&self) -> Option<&AccountId> {116 match self {117 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),118 _ => None,119 }120 }121122 pub fn confirmed(&self) -> bool {123 matches!(self, Self::Confirmed(_))124 }125}126127impl<T> Default for SponsorshipState<T> {128 fn default() -> Self {129 Self::Disabled130 }131}132133#[derive(Encode, Decode, Clone, PartialEq)]134#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]135pub struct Collection<T: frame_system::Config> {136 pub owner: T::AccountId,137 pub mode: CollectionMode,138 pub access: AccessMode,139 pub decimal_points: DecimalPoints,140 pub name: Vec<u16>, 141 pub description: Vec<u16>, 142 pub token_prefix: Vec<u8>, 143 pub mint_mode: bool,144 pub offchain_schema: Vec<u8>,145 pub schema_version: SchemaVersion,146 pub sponsorship: SponsorshipState<T::AccountId>,147 pub limits: CollectionLimits<T::BlockNumber>, 148 pub variable_on_chain_schema: Vec<u8>, 149 pub const_on_chain_schema: Vec<u8>, 150 pub transfers_enabled: bool,151}152153#[derive(Encode, Decode, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]155pub struct NftItemType<AccountId> {156 pub owner: AccountId,157 pub const_data: Vec<u8>,158 pub variable_data: Vec<u8>,159}160161#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]162#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]163pub struct FungibleItemType {164 pub value: u128,165}166167#[derive(Encode, Decode, Debug, Clone, PartialEq)]168#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]169pub struct ReFungibleItemType<AccountId> {170 pub owner: Vec<Ownership<AccountId>>,171 pub const_data: Vec<u8>,172 pub variable_data: Vec<u8>,173}174175#[derive(Encode, Decode, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]177pub struct CollectionLimits<BlockNumber: Encode + Decode> {178 pub account_token_ownership_limit: u32,179 pub sponsored_data_size: u32,180 181 182 183 pub sponsored_data_rate_limit: Option<BlockNumber>,184 pub token_limit: u32,185186 187 pub sponsor_transfer_timeout: u32,188 pub owner_can_transfer: bool,189 pub owner_can_destroy: bool,190}191192impl<BlockNumber: Encode + Decode> Default for CollectionLimits<BlockNumber> {193 fn default() -> Self {194 Self {195 account_token_ownership_limit: 10_000_000,196 token_limit: u32::max_value(),197 sponsored_data_size: u32::MAX,198 sponsored_data_rate_limit: None,199 sponsor_transfer_timeout: 14400,200 owner_can_transfer: true,201 owner_can_destroy: true,202 }203 }204}205206pub trait ChainLimits {207 type CollectionNumberLimit: Get<u32>;208 type AccountTokenOwnershipLimit: Get<u32>;209 type CollectionAdminsLimit: Get<u64>;210 type CustomDataLimit: Get<u32>;211212 213 type NftSponsorTransferTimeout: Get<u32>;214 type FungibleSponsorTransferTimeout: Get<u32>;215 type ReFungibleSponsorTransferTimeout: Get<u32>;216217 218 type OffchainSchemaLimit: Get<u32>;219 type VariableOnChainSchemaLimit: Get<u32>;220 type ConstOnChainSchemaLimit: Get<u32>;221222 223 224 type MaxItemsPerBatch: Get<u32>;225}226227228#[cfg(feature = "serde1")]229mod bounded_serde {230 use core::convert::TryFrom;231 use frame_support::{BoundedVec, traits::Get};232 use serde::{233 ser::{self, Serialize},234 de::{self, Deserialize, Error},235 };236 use sp_std::vec::Vec;237238 pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>239 where240 D: ser::Serializer,241 V: Serialize,242 {243 let vec: &Vec<_> = &value;244 vec.serialize(serializer)245 }246247 pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>248 where249 D: de::Deserializer<'de>,250 V: de::Deserialize<'de>,251 S: Get<u32>,252 {253 254 let vec = <Vec<V>>::deserialize(deserializer)?;255 let len = vec.len();256 TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))257 }258}259260#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)]261#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]262#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]263pub struct CreateNftData<T: ChainLimits> {264 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]265 #[derivative(Debug = "ignore")]266 pub const_data: BoundedVec<u8, T::CustomDataLimit>,267 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]268 #[derivative(Debug = "ignore")]269 pub variable_data: BoundedVec<u8, T::CustomDataLimit>,270}271272#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq)]273#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]274pub struct CreateFungibleData {275 pub value: u128,276}277278#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)]279#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]280#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]281pub struct CreateReFungibleData<T: ChainLimits> {282 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]283 #[derivative(Debug = "ignore")]284 pub const_data: BoundedVec<u8, T::CustomDataLimit>,285 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]286 #[derivative(Debug = "ignore")]287 pub variable_data: BoundedVec<u8, T::CustomDataLimit>,288 pub pieces: u128,289}290291#[derive(Encode, Decode, MaxEncodedLen, Derivative)]292#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]293#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))]294pub enum CreateItemData<T: ChainLimits> {295 NFT(CreateNftData<T>),296 Fungible(CreateFungibleData),297 ReFungible(CreateReFungibleData<T>),298}299300impl<T: ChainLimits> CreateItemData<T> {301 pub fn data_size(&self) -> usize {302 match self {303 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),304 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),305 _ => 0,306 }307 }308}309310impl<T: ChainLimits> From<CreateNftData<T>> for CreateItemData<T> {311 fn from(item: CreateNftData<T>) -> Self {312 CreateItemData::NFT(item)313 }314}315316impl<T: ChainLimits> From<CreateReFungibleData<T>> for CreateItemData<T> {317 fn from(item: CreateReFungibleData<T>) -> Self {318 CreateItemData::ReFungible(item)319 }320}321322impl<T: ChainLimits> From<CreateFungibleData> for CreateItemData<T> {323 fn from(item: CreateFungibleData) -> Self {324 CreateItemData::Fungible(item)325 }326}