git.delta.rocks / unique-network / refs/commits / 23942aa9dbcc

difftreelog

source

primitives/data-structs/src/lib.rs16.9 KiBsourcehistory
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![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};2627#[cfg(feature = "serde")]28use serde::{Serialize, Deserialize};2930use sp_core::U256;31use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};32use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};33use frame_support::{BoundedVec, traits::ConstU32};34use derivative::Derivative;35use scale_info::TypeInfo;3637mod bounded;38pub mod mapping;39mod migration;4041pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;42pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;43pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;4445pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {46	100_00047} else {48	1049};50pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {51	100_00052} else {53	1054};55pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {56	204857} else {58	1059};60pub const COLLECTION_ADMINS_LIMIT: u32 = 5;61pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;62pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {63	1_000_00064} else {65	1066};6768// Timeouts for item types in passed blocks69pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;70pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;71pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;7273pub const SPONSOR_APPROVE_TIMEOUT: u32 = 5;7475// Schema limits76pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 8192;77pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;78pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;7980pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;81pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;82pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;8384/// How much items can be created per single85/// create_many call86pub const MAX_ITEMS_PER_BATCH: u32 = 200;8788pub type CustomDataLimit = ConstU32<CUSTOM_DATA_LIMIT>;8990#[derive(91	Encode,92	Decode,93	PartialEq,94	Eq,95	PartialOrd,96	Ord,97	Clone,98	Copy,99	Debug,100	Default,101	TypeInfo,102	MaxEncodedLen,103)]104#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]105pub struct CollectionId(pub u32);106impl EncodeLike<u32> for CollectionId {}107impl EncodeLike<CollectionId> for u32 {}108109#[derive(110	Encode,111	Decode,112	PartialEq,113	Eq,114	PartialOrd,115	Ord,116	Clone,117	Copy,118	Debug,119	Default,120	TypeInfo,121	MaxEncodedLen,122)]123#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]124pub struct TokenId(pub u32);125impl EncodeLike<u32> for TokenId {}126impl EncodeLike<TokenId> for u32 {}127128impl TokenId {129	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {130		self.0131			.checked_add(1)132			.ok_or(ArithmeticError::Overflow)133			.map(Self)134	}135}136137impl From<TokenId> for U256 {138	fn from(t: TokenId) -> Self {139		t.0.into()140	}141}142143impl TryFrom<U256> for TokenId {144	type Error = &'static str;145146	fn try_from(value: U256) -> Result<Self, Self::Error> {147		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))148	}149}150151pub struct OverflowError;152impl From<OverflowError> for &'static str {153	fn from(_: OverflowError) -> Self {154		"overflow occured"155	}156}157158pub type DecimalPoints = u8;159160#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]161#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]162pub enum CollectionMode {163	NFT,164	// decimal points165	Fungible(DecimalPoints),166	ReFungible,167}168169impl CollectionMode {170	pub fn id(&self) -> u8 {171		match self {172			CollectionMode::NFT => 1,173			CollectionMode::Fungible(_) => 2,174			CollectionMode::ReFungible => 3,175		}176	}177}178179pub trait SponsoringResolve<AccountId, Call> {180	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;181}182183#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]184#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]185pub enum AccessMode {186	Normal,187	AllowList,188}189impl Default for AccessMode {190	fn default() -> Self {191		Self::Normal192	}193}194195#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]196#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]197pub enum SchemaVersion {198	ImageURL,199	Unique,200}201impl Default for SchemaVersion {202	fn default() -> Self {203		Self::ImageURL204	}205}206207#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]208#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]209pub struct Ownership<AccountId> {210	pub owner: AccountId,211	pub fraction: u128,212}213214#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]215#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]216pub enum SponsorshipState<AccountId> {217	/// The fees are applied to the transaction sender218	Disabled,219	Unconfirmed(AccountId),220	/// Transactions are sponsored by specified account221	Confirmed(AccountId),222}223224impl<AccountId> SponsorshipState<AccountId> {225	pub fn sponsor(&self) -> Option<&AccountId> {226		match self {227			Self::Confirmed(sponsor) => Some(sponsor),228			_ => None,229		}230	}231232	pub fn pending_sponsor(&self) -> Option<&AccountId> {233		match self {234			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),235			_ => None,236		}237	}238239	pub fn confirmed(&self) -> bool {240		matches!(self, Self::Confirmed(_))241	}242}243244impl<T> Default for SponsorshipState<T> {245	fn default() -> Self {246		Self::Disabled247	}248}249250#[struct_versioning::versioned(version = 2, upper)]251#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]252#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]253pub struct Collection<AccountId> {254	pub owner: AccountId,255	pub mode: CollectionMode,256	pub access: AccessMode,257	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]258	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,259	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]260	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,261	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]262	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,263	pub mint_mode: bool,264	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]265	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,266	pub schema_version: SchemaVersion,267	pub sponsorship: SponsorshipState<AccountId>,268269	#[version(..2)]270	pub limits: CollectionLimitsVersion1, // Collection private restrictions271	#[version(2.., upper(limits.into()))]272	pub limits: CollectionLimitsVersion2,273274	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]275	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,276	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]277	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,278	pub meta_update_permission: MetaUpdatePermission,279}280281#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug, Derivative, MaxEncodedLen)]282#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]283#[derivative(Default(bound = ""))]284pub struct CreateCollectionData<AccountId> {285	#[derivative(Default(value = "CollectionMode::NFT"))]286	pub mode: CollectionMode,287	pub access: Option<AccessMode>,288	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]289	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,290	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]291	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,292	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]293	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,294	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]295	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,296	pub schema_version: Option<SchemaVersion>,297	pub pending_sponsor: Option<AccountId>,298	pub limits: Option<CollectionLimits>,299	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]300	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,301	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]302	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,303	pub meta_update_permission: Option<MetaUpdatePermission>,304}305306#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]307#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]308pub struct NftItemType<AccountId> {309	pub owner: AccountId,310	pub const_data: Vec<u8>,311	pub variable_data: Vec<u8>,312}313314#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]315#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]316pub struct FungibleItemType {317	pub value: u128,318}319320#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]321#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]322pub struct ReFungibleItemType<AccountId> {323	pub owner: Vec<Ownership<AccountId>>,324	pub const_data: Vec<u8>,325	pub variable_data: Vec<u8>,326}327328/// All fields are wrapped in `Option`s, where None means chain default329#[struct_versioning::versioned(version = 2, upper)]330#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo, MaxEncodedLen)]331#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]332pub struct CollectionLimits {333	pub account_token_ownership_limit: Option<u32>,334	pub sponsored_data_size: Option<u32>,335	/// None - setVariableMetadata is not sponsored336	/// Some(v) - setVariableMetadata is sponsored337	///           if there is v block between txs338	pub sponsored_data_rate_limit: Option<SponsoringRateLimit>,339	pub token_limit: Option<u32>,340341	// Timeouts for item types in passed blocks342	pub sponsor_transfer_timeout: Option<u32>,343	pub sponsor_approve_timeout: Option<u32>,344	pub owner_can_transfer: Option<bool>,345	pub owner_can_destroy: Option<bool>,346	pub transfers_enabled: Option<bool>,347348	#[version(2.., upper(None))]349	pub nesting_rule: Option<NestingRule>,350}351352impl CollectionLimits {353	pub fn account_token_ownership_limit(&self) -> u32 {354		self.account_token_ownership_limit355			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)356			.min(MAX_TOKEN_OWNERSHIP)357	}358	pub fn sponsored_data_size(&self) -> u32 {359		self.sponsored_data_size360			.unwrap_or(CUSTOM_DATA_LIMIT)361			.min(CUSTOM_DATA_LIMIT)362	}363	pub fn token_limit(&self) -> u32 {364		self.token_limit365			.unwrap_or(COLLECTION_TOKEN_LIMIT)366			.min(COLLECTION_TOKEN_LIMIT)367	}368	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {369		self.sponsor_transfer_timeout370			.unwrap_or(default)371			.min(MAX_SPONSOR_TIMEOUT)372	}373	pub fn sponsor_approve_timeout(&self) -> u32 {374		self.sponsor_approve_timeout375			.unwrap_or(SPONSOR_APPROVE_TIMEOUT)376			.min(MAX_SPONSOR_TIMEOUT)377	}378	pub fn owner_can_transfer(&self) -> bool {379		self.owner_can_transfer.unwrap_or(true)380	}381	pub fn owner_can_destroy(&self) -> bool {382		self.owner_can_destroy.unwrap_or(true)383	}384	pub fn transfers_enabled(&self) -> bool {385		self.transfers_enabled.unwrap_or(true)386	}387	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {388		match self389			.sponsored_data_rate_limit390			.unwrap_or(SponsoringRateLimit::SponsoringDisabled)391		{392			SponsoringRateLimit::SponsoringDisabled => None,393			SponsoringRateLimit::Blocks(v) => Some(v.min(MAX_SPONSOR_TIMEOUT)),394		}395	}396	pub fn nesting_rule(&self) -> &NestingRule {397		static DEFAULT: NestingRule = NestingRule::Owner;398		self.nesting_rule.as_ref().unwrap_or(&DEFAULT)399	}400}401402#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen, Derivative)]403#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]404#[derivative(Debug)]405pub enum NestingRule {406	/// No one can nest tokens407	Disabled,408	/// Owner can nest any tokens409	Owner,410	/// Owner can nest tokens from specified collections411	OwnerRestricted(412		#[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))]413		#[derivative(Debug(format_with = "bounded::set_debug"))]414		BoundedBTreeSet<CollectionId, ConstU32<16>>,415	),416}417418#[derive(Encode, Decode, Debug, Clone, Copy, PartialEq, TypeInfo, MaxEncodedLen)]419#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]420pub enum SponsoringRateLimit {421	SponsoringDisabled,422	Blocks(u32),423}424425#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]426#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]427#[derivative(Debug)]428pub struct CreateNftData {429	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]430	#[derivative(Debug(format_with = "bounded::vec_debug"))]431	pub const_data: BoundedVec<u8, CustomDataLimit>,432	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]433	#[derivative(Debug(format_with = "bounded::vec_debug"))]434	pub variable_data: BoundedVec<u8, CustomDataLimit>,435}436437#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]438#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]439pub struct CreateFungibleData {440	pub value: u128,441}442443#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]444#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]445#[derivative(Debug)]446pub struct CreateReFungibleData {447	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]448	#[derivative(Debug(format_with = "bounded::vec_debug"))]449	pub const_data: BoundedVec<u8, CustomDataLimit>,450	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]451	#[derivative(Debug(format_with = "bounded::vec_debug"))]452	pub variable_data: BoundedVec<u8, CustomDataLimit>,453	pub pieces: u128,454}455456#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo, MaxEncodedLen)]457#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]458pub enum MetaUpdatePermission {459	ItemOwner,460	Admin,461	None,462}463464impl Default for MetaUpdatePermission {465	fn default() -> Self {466		Self::ItemOwner467	}468}469470#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]471#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]472pub enum CreateItemData {473	NFT(CreateNftData),474	Fungible(CreateFungibleData),475	ReFungible(CreateReFungibleData),476}477478#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]479#[derivative(Debug)]480pub struct CreateNftExData<CrossAccountId> {481	#[derivative(Debug(format_with = "bounded::vec_debug"))]482	pub const_data: BoundedVec<u8, CustomDataLimit>,483	#[derivative(Debug(format_with = "bounded::vec_debug"))]484	pub variable_data: BoundedVec<u8, CustomDataLimit>,485	pub owner: CrossAccountId,486}487488#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]489#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]490pub struct CreateRefungibleExData<CrossAccountId> {491	#[derivative(Debug(format_with = "bounded::vec_debug"))]492	pub const_data: BoundedVec<u8, CustomDataLimit>,493	#[derivative(Debug(format_with = "bounded::vec_debug"))]494	pub variable_data: BoundedVec<u8, CustomDataLimit>,495	#[derivative(Debug(format_with = "bounded::map_debug"))]496	pub users: BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,497}498499#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)]500#[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))]501pub enum CreateItemExData<CrossAccountId> {502	NFT(503		#[derivative(Debug(format_with = "bounded::vec_debug"))]504		BoundedVec<CreateNftExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,505	),506	Fungible(507		#[derivative(Debug(format_with = "bounded::map_debug"))]508		BoundedBTreeMap<CrossAccountId, u128, ConstU32<MAX_ITEMS_PER_BATCH>>,509	),510	/// Many tokens, each may have only one owner511	RefungibleMultipleItems(512		#[derivative(Debug(format_with = "bounded::vec_debug"))]513		BoundedVec<CreateRefungibleExData<CrossAccountId>, ConstU32<MAX_ITEMS_PER_BATCH>>,514	),515	/// Single token, which may have many owners516	RefungibleMultipleOwners(CreateRefungibleExData<CrossAccountId>),517}518519impl CreateItemData {520	pub fn data_size(&self) -> usize {521		match self {522			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),523			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),524			_ => 0,525		}526	}527}528529impl From<CreateNftData> for CreateItemData {530	fn from(item: CreateNftData) -> Self {531		CreateItemData::NFT(item)532	}533}534535impl From<CreateReFungibleData> for CreateItemData {536	fn from(item: CreateReFungibleData) -> Self {537		CreateItemData::ReFungible(item)538	}539}540541impl From<CreateFungibleData> for CreateItemData {542	fn from(item: CreateFungibleData) -> Self {543		CreateItemData::Fungible(item)544	}545}546547#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]548#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]549pub struct CollectionStats {550	pub created: u32,551	pub destroyed: u32,552	pub alive: u32,553}