git.delta.rocks / unique-network / refs/commits / 455ab69b4262

difftreelog

source

primitives/nft/src/lib.rs11.7 KiBsourcehistory
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;3233pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {34	10_000_00035} else {36	1037};38pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {39	100_00040} else {41	1042};43pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {44	204845} else {46	1047};48pub const COLLECTION_ADMINS_LIMIT: u32 = 5;49pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;50pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {51	1_000_00052} else {53	1054};5556// Timeouts for item types in passed blocks57pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;58pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;59pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;6061// Schema limits62pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;63pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;64pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;6566pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;67pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;68pub const MAX_TOKEN_PREFIX_LENGTH: usize = 16;6970/// How much items can be created per single71/// create_many call72pub const MAX_ITEMS_PER_BATCH: u32 = 200;7374parameter_types! {75	pub const CustomDataLimit: u32 = CUSTOM_DATA_LIMIT;76}7778#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]79#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]80pub struct CollectionId(pub u32);81impl EncodeLike<u32> for CollectionId {}82impl EncodeLike<CollectionId> for u32 {}8384#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]85#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]86pub struct TokenId(pub u32);87impl EncodeLike<u32> for TokenId {}88impl EncodeLike<TokenId> for u32 {}8990impl TokenId {91	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {92		self.093			.checked_add(1)94			.ok_or(ArithmeticError::Overflow)95			.map(Self)96	}97}9899impl From<TokenId> for U256 {100	fn from(t: TokenId) -> Self {101		t.0.into()102	}103}104105impl TryFrom<U256> for TokenId {106	type Error = &'static str;107108	fn try_from(value: U256) -> Result<Self, Self::Error> {109		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))110	}111}112113pub struct OverflowError;114impl From<OverflowError> for &'static str {115	fn from(_: OverflowError) -> Self {116		"overflow occured"117	}118}119120pub type DecimalPoints = u8;121122#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]123#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]124pub enum CollectionMode {125	NFT,126	// decimal points127	Fungible(DecimalPoints),128	ReFungible,129}130131impl CollectionMode {132	pub fn id(&self) -> u8 {133		match self {134			CollectionMode::NFT => 1,135			CollectionMode::Fungible(_) => 2,136			CollectionMode::ReFungible => 3,137		}138	}139}140141pub trait SponsoringResolve<AccountId, Call> {142	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;143}144145#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]146#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]147pub enum AccessMode {148	Normal,149	AllowList,150}151impl Default for AccessMode {152	fn default() -> Self {153		Self::Normal154	}155}156157#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]158#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]159pub enum SchemaVersion {160	ImageURL,161	Unique,162}163impl Default for SchemaVersion {164	fn default() -> Self {165		Self::ImageURL166	}167}168169#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]170#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]171pub struct Ownership<AccountId> {172	pub owner: AccountId,173	pub fraction: u128,174}175176#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]177#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]178pub enum SponsorshipState<AccountId> {179	/// The fees are applied to the transaction sender180	Disabled,181	Unconfirmed(AccountId),182	/// Transactions are sponsored by specified account183	Confirmed(AccountId),184}185186impl<AccountId> SponsorshipState<AccountId> {187	pub fn sponsor(&self) -> Option<&AccountId> {188		match self {189			Self::Confirmed(sponsor) => Some(sponsor),190			_ => None,191		}192	}193194	pub fn pending_sponsor(&self) -> Option<&AccountId> {195		match self {196			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),197			_ => None,198		}199	}200201	pub fn confirmed(&self) -> bool {202		matches!(self, Self::Confirmed(_))203	}204}205206impl<T> Default for SponsorshipState<T> {207	fn default() -> Self {208		Self::Disabled209	}210}211212#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]213#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]214pub struct Collection<T: frame_system::Config> {215	pub owner: T::AccountId,216	pub mode: CollectionMode,217	pub access: AccessMode,218	pub name: Vec<u16>,        // 64 include null escape char219	pub description: Vec<u16>, // 256 include null escape char220	pub token_prefix: Vec<u8>, // 16 include null escape char221	pub mint_mode: bool,222	pub offchain_schema: Vec<u8>,223	pub schema_version: SchemaVersion,224	pub sponsorship: SponsorshipState<T::AccountId>,225	pub limits: CollectionLimits,          // Collection private restrictions226	pub variable_on_chain_schema: Vec<u8>, //227	pub const_on_chain_schema: Vec<u8>,    //228	pub meta_update_permission: MetaUpdatePermission,229}230231#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]232#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]233pub struct NftItemType<AccountId> {234	pub owner: AccountId,235	pub const_data: Vec<u8>,236	pub variable_data: Vec<u8>,237}238239#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]240#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]241pub struct FungibleItemType {242	pub value: u128,243}244245#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]246#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]247pub struct ReFungibleItemType<AccountId> {248	pub owner: Vec<Ownership<AccountId>>,249	pub const_data: Vec<u8>,250	pub variable_data: Vec<u8>,251}252253#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo)]254#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]255pub struct CollectionLimits {256	pub account_token_ownership_limit: Option<u32>,257	pub sponsored_data_size: Option<u32>,258	/// None - setVariableMetadata is not sponsored259	/// Some(v) - setVariableMetadata is sponsored260	///           if there is v block between txs261	pub sponsored_data_rate_limit: Option<u32>,262	pub token_limit: Option<u32>,263264	// Timeouts for item types in passed blocks265	pub sponsor_transfer_timeout: Option<u32>,266	pub owner_can_transfer: Option<bool>,267	pub owner_can_destroy: Option<bool>,268	pub transfers_enabled: Option<bool>,269}270271impl CollectionLimits {272	pub fn account_token_ownership_limit(&self) -> u32 {273		self.account_token_ownership_limit274			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)275			.min(MAX_TOKEN_OWNERSHIP)276	}277	pub fn sponsored_data_size(&self) -> u32 {278		self.sponsored_data_size279			.unwrap_or(CUSTOM_DATA_LIMIT)280			.min(CUSTOM_DATA_LIMIT)281	}282	pub fn token_limit(&self) -> u32 {283		self.token_limit284			.unwrap_or(COLLECTION_TOKEN_LIMIT)285			.min(COLLECTION_TOKEN_LIMIT)286	}287	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {288		self.sponsor_transfer_timeout289			.unwrap_or(default)290			.min(MAX_SPONSOR_TIMEOUT)291	}292	pub fn owner_can_transfer(&self) -> bool {293		self.owner_can_transfer.unwrap_or(true)294	}295	pub fn owner_can_destroy(&self) -> bool {296		self.owner_can_destroy.unwrap_or(true)297	}298	pub fn transfers_enabled(&self) -> bool {299		self.transfers_enabled.unwrap_or(true)300	}301	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {302		self.sponsored_data_rate_limit303			.map(|v| v.min(MAX_SPONSOR_TIMEOUT))304	}305}306307/// BoundedVec doesn't supports serde308#[cfg(feature = "serde1")]309mod bounded_serde {310	use core::convert::TryFrom;311	use frame_support::{BoundedVec, traits::Get};312	use serde::{313		ser::{self, Serialize},314		de::{self, Deserialize, Error},315	};316	use sp_std::vec::Vec;317318	pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>319	where320		D: ser::Serializer,321		V: Serialize,322	{323		let vec: &Vec<_> = &value;324		vec.serialize(serializer)325	}326327	pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>328	where329		D: de::Deserializer<'de>,330		V: de::Deserialize<'de>,331		S: Get<u32>,332	{333		// TODO: Implement custom visitor, which will limit vec size at parse time? Will serde only be used by chainspec?334		let vec = <Vec<V>>::deserialize(deserializer)?;335		let len = vec.len();336		TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))337	}338}339340#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]341#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]342#[derivative(Debug)]343pub struct CreateNftData {344	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]345	#[derivative(Debug = "ignore")]346	pub const_data: BoundedVec<u8, CustomDataLimit>,347	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]348	#[derivative(Debug = "ignore")]349	pub variable_data: BoundedVec<u8, CustomDataLimit>,350}351352#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]353#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]354pub struct CreateFungibleData {355	pub value: u128,356}357358#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]359#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]360#[derivative(Debug)]361pub struct CreateReFungibleData {362	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]363	#[derivative(Debug = "ignore")]364	pub const_data: BoundedVec<u8, CustomDataLimit>,365	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]366	#[derivative(Debug = "ignore")]367	pub variable_data: BoundedVec<u8, CustomDataLimit>,368	pub pieces: u128,369}370371#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]372#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]373pub enum MetaUpdatePermission {374	ItemOwner,375	Admin,376	None,377}378379impl Default for MetaUpdatePermission {380	fn default() -> Self {381		Self::ItemOwner382	}383}384385#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]386#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]387pub enum CreateItemData {388	NFT(CreateNftData),389	Fungible(CreateFungibleData),390	ReFungible(CreateReFungibleData),391}392393impl CreateItemData {394	pub fn data_size(&self) -> usize {395		match self {396			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),397			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),398			_ => 0,399		}400	}401}402403impl From<CreateNftData> for CreateItemData {404	fn from(item: CreateNftData) -> Self {405		CreateItemData::NFT(item)406	}407}408409impl From<CreateReFungibleData> for CreateItemData {410	fn from(item: CreateReFungibleData) -> Self {411		CreateItemData::ReFungible(item)412	}413}414415impl From<CreateFungibleData> for CreateItemData {416	fn from(item: CreateFungibleData) -> Self {417		CreateItemData::Fungible(item)418	}419}