1#![cfg_attr(not(feature = "std"), no_std)]23use core::convert::{TryFrom, TryInto};45#[cfg(feature = "serde")]6pub use serde::{Serialize, Deserialize};78use sp_core::U256;9use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};10use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};11pub use frame_support::{12 BoundedVec, construct_runtime, decl_event, decl_module, decl_storage, decl_error,13 dispatch::DispatchResult,14 ensure, fail, parameter_types,15 traits::{16 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,17 Randomness, IsSubType, WithdrawReasons,18 },19 weights::{20 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},21 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,22 WeightToFeePolynomial, DispatchClass,23 },24 StorageValue, transactional,25};26use derivative::Derivative;27use scale_info::TypeInfo;2829pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;30pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;31pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;32pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;3334pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {35 10000036} else {37 1038};39pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {40 204841} else {42 1043};44pub const COLLECTION_ADMINS_LIMIT: u64 = 5;45pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {46 100000047} else {48 1049};505152pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;53pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;54pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;555657pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;58pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;59pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;6061pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;62pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;63pub const MAX_TOKEN_PREFIX_LENGTH: usize = 16;64656667pub const MAX_ITEMS_PER_BATCH: u32 = 200;6869parameter_types! {70 pub const CustomDataLimit: u32 = CUSTOM_DATA_LIMIT;71}7273#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]74#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]75pub struct CollectionId(pub u32);76impl EncodeLike<u32> for CollectionId {}77impl EncodeLike<CollectionId> for u32 {}7879#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]80#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]81pub struct TokenId(pub u32);82impl EncodeLike<u32> for TokenId {}83impl EncodeLike<TokenId> for u32 {}8485impl TokenId {86 pub fn try_next(self) -> Result<TokenId, ArithmeticError> {87 self.088 .checked_add(1)89 .ok_or(ArithmeticError::Overflow)90 .map(Self)91 }92}9394impl From<TokenId> for U256 {95 fn from(t: TokenId) -> Self {96 t.0.into()97 }98}99100impl TryFrom<U256> for TokenId {101 type Error = &'static str;102103 fn try_from(value: U256) -> Result<Self, Self::Error> {104 Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))105 }106}107108pub struct OverflowError;109impl From<OverflowError> for &'static str {110 fn from(_: OverflowError) -> Self {111 "overflow occured"112 }113}114115pub type DecimalPoints = u8;116117#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]118#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]119pub enum CollectionMode {120 NFT,121 122 Fungible(DecimalPoints),123 ReFungible,124}125126impl CollectionMode {127 pub fn id(&self) -> u8 {128 match self {129 CollectionMode::NFT => 1,130 CollectionMode::Fungible(_) => 2,131 CollectionMode::ReFungible => 3,132 }133 }134}135136pub trait SponsoringResolve<AccountId, Call> {137 fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;138}139140#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]141#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]142pub enum AccessMode {143 Normal,144 WhiteList,145}146impl Default for AccessMode {147 fn default() -> Self {148 Self::Normal149 }150}151152#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]153#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]154pub enum SchemaVersion {155 ImageURL,156 Unique,157}158impl Default for SchemaVersion {159 fn default() -> Self {160 Self::ImageURL161 }162}163164#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]165#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]166pub struct Ownership<AccountId> {167 pub owner: AccountId,168 pub fraction: u128,169}170171#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]172#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]173pub enum SponsorshipState<AccountId> {174 175 Disabled,176 Unconfirmed(AccountId),177 178 Confirmed(AccountId),179}180181impl<AccountId> SponsorshipState<AccountId> {182 pub fn sponsor(&self) -> Option<&AccountId> {183 match self {184 Self::Confirmed(sponsor) => Some(sponsor),185 _ => None,186 }187 }188189 pub fn pending_sponsor(&self) -> Option<&AccountId> {190 match self {191 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),192 _ => None,193 }194 }195196 pub fn confirmed(&self) -> bool {197 matches!(self, Self::Confirmed(_))198 }199}200201impl<T> Default for SponsorshipState<T> {202 fn default() -> Self {203 Self::Disabled204 }205}206207#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]208#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]209pub struct Collection<T: frame_system::Config> {210 pub owner: T::AccountId,211 pub mode: CollectionMode,212 pub access: AccessMode,213 pub name: Vec<u16>, 214 pub description: Vec<u16>, 215 pub token_prefix: Vec<u8>, 216 pub mint_mode: bool,217 pub offchain_schema: Vec<u8>,218 pub schema_version: SchemaVersion,219 pub sponsorship: SponsorshipState<T::AccountId>,220 pub limits: CollectionLimits<T::BlockNumber>, 221 pub variable_on_chain_schema: Vec<u8>, 222 pub const_on_chain_schema: Vec<u8>, 223 pub meta_update_permission: MetaUpdatePermission,224 pub transfers_enabled: bool,225}226227#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]228#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]229pub struct NftItemType<AccountId> {230 pub owner: AccountId,231 pub const_data: Vec<u8>,232 pub variable_data: Vec<u8>,233}234235#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]236#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]237pub struct FungibleItemType {238 pub value: u128,239}240241#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]242#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]243pub struct ReFungibleItemType<AccountId> {244 pub owner: Vec<Ownership<AccountId>>,245 pub const_data: Vec<u8>,246 pub variable_data: Vec<u8>,247}248249#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]250#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]251pub struct CollectionLimits<BlockNumber: Encode + Decode> {252 pub account_token_ownership_limit: Option<u32>,253 pub sponsored_data_size: u32,254 255 256 257 pub sponsored_data_rate_limit: Option<BlockNumber>,258 pub token_limit: u32,259260 261 pub sponsor_transfer_timeout: u32,262 pub owner_can_transfer: bool,263 pub owner_can_destroy: bool,264}265266impl<BlockNumber: Encode + Decode> CollectionLimits<BlockNumber> {267 pub fn account_token_ownership_limit(&self) -> u32 {268 self.account_token_ownership_limit269 .unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)270 .min(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)271 }272}273274impl<BlockNumber: Encode + Decode> Default for CollectionLimits<BlockNumber> {275 fn default() -> Self {276 Self {277 account_token_ownership_limit: Some(10_000_000),278 token_limit: u32::max_value(),279 sponsored_data_size: u32::MAX,280 sponsored_data_rate_limit: None,281 sponsor_transfer_timeout: 14400,282 owner_can_transfer: true,283 owner_can_destroy: true,284 }285 }286}287288289#[cfg(feature = "serde1")]290mod bounded_serde {291 use core::convert::TryFrom;292 use frame_support::{BoundedVec, traits::Get};293 use serde::{294 ser::{self, Serialize},295 de::{self, Deserialize, Error},296 };297 use sp_std::vec::Vec;298299 pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>300 where301 D: ser::Serializer,302 V: Serialize,303 {304 let vec: &Vec<_> = &value;305 vec.serialize(serializer)306 }307308 pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>309 where310 D: de::Deserializer<'de>,311 V: de::Deserialize<'de>,312 S: Get<u32>,313 {314 315 let vec = <Vec<V>>::deserialize(deserializer)?;316 let len = vec.len();317 TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))318 }319}320321#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]322#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]323#[derivative(Debug)]324pub struct CreateNftData {325 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]326 #[derivative(Debug = "ignore")]327 pub const_data: BoundedVec<u8, CustomDataLimit>,328 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]329 #[derivative(Debug = "ignore")]330 pub variable_data: BoundedVec<u8, CustomDataLimit>,331}332333#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]334#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]335pub struct CreateFungibleData {336 pub value: u128,337}338339#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]340#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]341#[derivative(Debug)]342pub struct CreateReFungibleData {343 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]344 #[derivative(Debug = "ignore")]345 pub const_data: BoundedVec<u8, CustomDataLimit>,346 #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]347 #[derivative(Debug = "ignore")]348 pub variable_data: BoundedVec<u8, CustomDataLimit>,349 pub pieces: u128,350}351352#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]353#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]354pub enum MetaUpdatePermission {355 ItemOwner,356 Admin,357 None,358}359360impl Default for MetaUpdatePermission {361 fn default() -> Self {362 Self::ItemOwner363 }364}365366#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]367#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]368pub enum CreateItemData {369 NFT(CreateNftData),370 Fungible(CreateFungibleData),371 ReFungible(CreateReFungibleData),372}373374impl CreateItemData {375 pub fn data_size(&self) -> usize {376 match self {377 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),378 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),379 _ => 0,380 }381 }382}383384impl From<CreateNftData> for CreateItemData {385 fn from(item: CreateNftData) -> Self {386 CreateItemData::NFT(item)387 }388}389390impl From<CreateReFungibleData> for CreateItemData {391 fn from(item: CreateReFungibleData) -> Self {392 CreateItemData::ReFungible(item)393 }394}395396impl From<CreateFungibleData> for CreateItemData {397 fn from(item: CreateFungibleData) -> Self {398 CreateItemData::Fungible(item)399 }400}