git.delta.rocks / unique-network / refs/commits / 2f8a220cd113

difftreelog

Weights added

str-mv2020-10-23parent: #2f98826.patch.diff
in: master

3 files changed

addedpallets/nft/src/benchmarking.rsdiffbeforeafterboth
--- /dev/null
+++ b/pallets/nft/src/benchmarking.rs
@@ -0,0 +1,279 @@
+#[cfg(feature = "runtime-benchmarks")]
+// mod benchmarking {
+    use super::*;
+    use sp_std::prelude::*;
+    use frame_system::RawOrigin;
+    // use frame_support::{ensure, traits::OnFinalize};
+    use frame_benchmarking::{benchmarks, account, whitelisted_caller};  // , TrackedStorageKey, 
+    use crate::Module as Nft;
+
+    const SEED: u32 = 1;
+
+    benchmarks! {
+
+        _ {}
+
+        create_collection {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = account("caller", 0, SEED);
+        }: create_collection(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode)
+        verify {
+			assert_eq!(Nft::<T>::collection(2).owner, caller);
+        }
+
+        destroy_collection {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: destroy_collection(RawOrigin::Signed(caller.clone()), 2)
+
+        add_to_white_list {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            let whitelist_account: T::AccountId = account("admin", 0, SEED);
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: add_to_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account)
+
+        remove_from_white_list {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            let whitelist_account: T::AccountId = account("admin", 0, SEED);
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::add_to_white_list(RawOrigin::Signed(caller.clone()).into(), 2, whitelist_account.clone())?;
+        }: remove_from_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account)
+
+        set_public_access_mode {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: set_public_access_mode(RawOrigin::Signed(caller.clone()), 2, AccessMode::WhiteList)
+
+        set_mint_permission {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: set_mint_permission(RawOrigin::Signed(caller.clone()), 2, true)
+
+        change_collection_owner {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let new_owner: T::AccountId = account("admin", 0, SEED);
+        }: change_collection_owner(RawOrigin::Signed(caller.clone()), 2, new_owner)
+
+        add_collection_admin {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let new_admin: T::AccountId = account("admin", 0, SEED);
+        }: add_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin)
+
+        remove_collection_admin {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            let new_admin: T::AccountId = account("admin", 0, SEED);
+            Nft::<T>::add_collection_admin(RawOrigin::Signed(caller.clone()).into(), 2, new_admin.clone())?;
+        }: remove_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin)
+
+        set_collection_sponsor {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+        }: set_collection_sponsor(RawOrigin::Signed(caller.clone()), 2, caller.clone())
+
+        confirm_sponsorship {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
+        }: confirm_sponsorship(RawOrigin::Signed(caller.clone()), 2)
+
+        remove_collection_sponsor {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?;
+            Nft::<T>::confirm_sponsorship(RawOrigin::Signed(caller.clone()).into(), 2)?;
+        }: remove_collection_sponsor(RawOrigin::Signed(caller.clone()), 2)
+
+        // nft item
+        create_item_nft {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, [1, 2, 3].to_vec(), caller.clone())
+
+        // fungible item
+        create_item_fungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::Fungible(3);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, [].to_vec(), caller.clone())
+
+        // refungible item
+        create_item_refungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3, 3);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+
+        }: create_item(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec(), caller.clone())
+
+        burn_item {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+
+        }: burn_item(RawOrigin::Signed(caller.clone()), 2, 1)
+
+        transfer_nft {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(2000);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1, 2, 3].to_vec(), caller.clone())?;
+
+        }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
+        
+        transfer_fungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::Fungible(3);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+
+        }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
+
+        transfer_refungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+
+        }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1)
+
+        approve {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+
+        }: approve(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1)
+
+        // Nft
+        transfer_from_nft {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::NFT(300);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
+
+        }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
+
+        // Fungible
+        transfer_from_fungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::Fungible(3);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [].to_vec(), caller.clone())?;
+            Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
+
+        }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
+
+        // ReFungible
+        transfer_from_refungible {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let recipient: T::AccountId = account("recipient", 0, SEED);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+            Nft::<T>::create_item(RawOrigin::Signed(caller.clone()).into(), 2, [1,2,3].to_vec(), caller.clone())?;
+            Nft::<T>::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?;
+
+        }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1)
+
+        set_offchain_schema {
+            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();
+            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();
+            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();
+            let mode: CollectionMode = CollectionMode::ReFungible(3,3);
+            let caller: T::AccountId = T::AccountId::from(whitelisted_caller());
+            Nft::<T>::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?;
+
+        }: set_offchain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec())
+    }
\ No newline at end of file
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11    construct_runtime, decl_event, decl_module, decl_storage,12    dispatch::DispatchResult,13    ensure, parameter_types,14    traits::{15        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16        Randomness, WithdrawReason,17    },18    weights::{19        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21        WeightToFeePolynomial,22    },23    IsSubType, StorageValue,24};2526use frame_system::{self as system, ensure_signed, ensure_root};27use sp_runtime::sp_std::prelude::Vec;28use sp_runtime::{29    traits::{30        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,31        SignedExtension, Zero,32    },33    transaction_validity::{34        InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,35        ValidTransaction,36    },37    FixedPointOperand, FixedU128,38};3940#[cfg(test)]41mod mock;4243#[cfg(test)]44mod tests;4546// Structs47// #region4849#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]50#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]51pub enum CollectionMode {52    Invalid,53    // custom data size54    NFT(u32),55    // decimal points56    Fungible(u32),57    // custom data size and decimal points58    ReFungible(u32, u32),59}6061impl Into<u8> for CollectionMode {62    fn into(self) -> u8 {63        match self {64            CollectionMode::Invalid => 0,65            CollectionMode::NFT(_) => 1,66            CollectionMode::Fungible(_) => 2,67            CollectionMode::ReFungible(_, _) => 3,68        }69    }70}7172#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]73#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]74pub enum AccessMode {75    Normal,76    WhiteList,77}78impl Default for AccessMode {79    fn default() -> Self {80        Self::Normal81    }82}8384impl Default for CollectionMode {85    fn default() -> Self {86        Self::Invalid87    }88}8990#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]91#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]92pub struct Ownership<AccountId> {93    pub owner: AccountId,94    pub fraction: u128,95}9697#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]98#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]99pub struct CollectionType<AccountId> {100    pub owner: AccountId,101    pub mode: CollectionMode,102    pub access: AccessMode,103    pub decimal_points: u32,104    pub name: Vec<u16>,        // 64 include null escape char105    pub description: Vec<u16>, // 256 include null escape char106    pub token_prefix: Vec<u8>, // 16 include null escape char107    pub custom_data_size: u32,108    pub mint_mode: bool,109    pub offchain_schema: Vec<u8>,110    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender111    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship112}113114#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]115#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]116pub struct CollectionAdminsType<AccountId> {117    pub admin: AccountId,118    pub collection_id: u64,119}120121#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]122#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]123pub struct NftItemType<AccountId> {124    pub collection: u64,125    pub owner: AccountId,126    pub data: Vec<u8>,127}128129#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]130#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]131pub struct FungibleItemType<AccountId> {132    pub collection: u64,133    pub owner: AccountId,134    pub value: u128,135}136137#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]138#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]139pub struct ReFungibleItemType<AccountId> {140    pub collection: u64,141    pub owner: Vec<Ownership<AccountId>>,142    pub data: Vec<u8>,143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct ApprovePermissions<AccountId> {148    pub approved: AccountId,149    pub amount: u64,150}151152#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]153#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]154pub struct VestingItem<AccountId, Moment> {155    pub sender: AccountId,156    pub recipient: AccountId,157    pub collection_id: u64,158    pub item_id: u64,159    pub amount: u64,160    pub vesting_date: Moment,161}162163#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]164#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]165pub struct BasketItem<AccountId, BlockNumber> {166    pub address: AccountId,167    pub start_block: BlockNumber,168}169170#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]171#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]172pub struct ChainLimits {173    pub collection_numbers_limit: u64,174    pub account_token_ownership_limit: u64,175    pub collections_admins_limit: u64,176    pub custom_data_limit: u32,177178    // Timeouts for item types in passed blocks179    pub nft_sponsor_transfer_timeout: u32,180    pub fungible_sponsor_transfer_timeout: u32,181    pub refungible_sponsor_transfer_timeout: u32,182}183184pub trait Trait: system::Trait {185    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;186}187188189#[cfg(feature = "runtime-benchmarks")]190mod benchmarking {191    use super::*;192    use sp_std::prelude::*;193    use frame_system::RawOrigin;194    // use frame_support::{ensure, traits::OnFinalize};195    use frame_benchmarking::{benchmarks, account};  // , TrackedStorageKey, whitelisted_caller196    use crate::Module as Nft;197198    const SEED: u32 = 1;199200    benchmarks! {201202        _ {}203204        create_collection {205            let col_name1: Vec<u16> = "Test1".encode_utf16().collect::<Vec<u16>>();206            let col_desc1: Vec<u16> = "TestDescription1".encode_utf16().collect::<Vec<u16>>();207            let token_prefix1: Vec<u8> = b"token_prefix1".to_vec();208            let mode: CollectionMode = CollectionMode::NFT(2000);209            let caller: T::AccountId = account("caller", 0, SEED);210        }: create_collection(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode)211        verify {212			assert_eq!(Nft::<T>::collection(2).owner, caller);213		}214    }215216    #[cfg(test)]217    mod tests {218        use super::*;219        use crate::tests_composite::{ExtBuilder, Test};220        use frame_support::assert_ok;221222        #[test]223        fn create_collection() {224            ExtBuilder::default().build().execute_with(|| {225                assert_ok!(test_benchmark_create_collection::<Test>());226            });227        }228    }229}230231// #endregion232233decl_storage! {234    trait Store for Module<T: Trait> as Nft {235236        // Private members237        NextCollectionID: u64;238        CreatedCollectionCount: u64;239        ChainVersion: u64;240        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;241242        // Chain limits struct243        pub ChainLimit get(fn chain_limit) config(): ChainLimits;244245        // Bound counters246        CollectionCount: u64;247        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;248249        // Basic collections250        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;251        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;252        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;253254        /// Balance owner per collection map255        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;256257        /// second parameter: item id + owner account id258        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;259260        /// Item collections261        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;262        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;263        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;264265        /// Index list266        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;267268        /// Tokens transfer baskets269        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;270        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;271        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;272273        // Sponsorship274        pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;275        pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;276    }277    add_extra_genesis {278        build(|config: &GenesisConfig<T>| {279            // Modification of storage280            for (_num, _c) in &config.collection {281                <Module<T>>::init_collection(_c);282            }283284            for (_num, _q, _i) in &config.nft_item_id {285                <Module<T>>::init_nft_token(_i);286            }287288            for (_num, _q, _i) in &config.fungible_item_id {289                <Module<T>>::init_fungible_token(_i);290            }291292            for (_num, _q, _i) in &config.refungible_item_id {293                <Module<T>>::init_refungible_token(_i);294            }295        })296    }297}298299decl_event!(300    pub enum Event<T>301    where302        AccountId = <T as system::Trait>::AccountId,303    {304        /// New collection was created305        /// 306        /// # Arguments307        /// 308        /// * collection_id: Globally unique identifier of newly created collection.309        /// 310        /// * mode: [CollectionMode] converted into u8.311        /// 312        /// * account_id: Collection owner.313        Created(u64, u8, AccountId),314315        /// New item was created.316        /// 317        /// # Arguments318        /// 319        /// * collection_id: Id of the collection where item was created.320        /// 321        /// * item_id: Id of an item. Unique within the collection.322        ItemCreated(u64, u64),323324        /// Collection item was burned.325        /// 326        /// # Arguments327        /// 328        /// collection_id.329        /// 330        /// item_id: Identifier of burned NFT.331        ItemDestroyed(u64, u64),332    }333);334335decl_module! {336    pub struct Module<T: Trait> for enum Call where origin: T::Origin {337338        fn deposit_event() = default;339340        fn on_initialize(now: T::BlockNumber) -> Weight {341342            if ChainVersion::get() < 2343            {344                let value = NextCollectionID::get();345                CreatedCollectionCount::put(value);346                ChainVersion::put(2);347            }348349            0350        }351352        /// This method creates a Collection of NFTs. Each Token may have multiple properties encoded as an array of bytes of certain length. The initial owner and admin of the collection are set to the address that signed the transaction. Both addresses can be changed later.353        /// 354        /// # Permissions355        /// 356        /// * Anyone.357        /// 358        /// # Arguments359        /// 360        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.361        /// 362        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.363        /// 364        /// * token_prefix: UTF-8 string with token prefix.365        /// 366        /// * mode: [CollectionMode] collection type and type dependent data.367        // returns collection ID368        #[weight = 0]369        pub fn create_collection(origin,370                                 collection_name: Vec<u16>,371                                 collection_description: Vec<u16>,372                                 token_prefix: Vec<u8>,373                                 mode: CollectionMode) -> DispatchResult {374375            // Anyone can create a collection376            let who = ensure_signed(origin)?;377            let custom_data_size = match mode {378                CollectionMode::NFT(size) => {379380                    // bound Custom data size381                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");382                    size383                },384                CollectionMode::ReFungible(size, _) => {385386                    // bound Custom data size387                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");388                    size389                },390                _ => 0391            };392393            let decimal_points = match mode {394                CollectionMode::Fungible(points) => points,395                CollectionMode::ReFungible(_, points) => points,396                _ => 0397            };398399            // bound Total number of collections400            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");401402            // check params403            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");404405            let mut name = collection_name.to_vec();406            name.push(0);407            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");408409            let mut description = collection_description.to_vec();410            description.push(0);411            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");412413            let mut prefix = token_prefix.to_vec();414            prefix.push(0);415            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");416417            // Generate next collection ID418            let next_id = CreatedCollectionCount::get()419                .checked_add(1)420                .expect("collection id error");421422            // bound counter423            let total = CollectionCount::get()424                .checked_add(1)425                .expect("collection counter error");426427            CreatedCollectionCount::put(next_id);428            CollectionCount::put(total);429430            // Create new collection431            let new_collection = CollectionType {432                owner: who.clone(),433                name: name,434                mode: mode.clone(),435                mint_mode: false,436                access: AccessMode::Normal,437                description: description,438                decimal_points: decimal_points,439                token_prefix: prefix,440                offchain_schema: Vec::new(),441                custom_data_size: custom_data_size,442                sponsor: T::AccountId::default(),443                unconfirmed_sponsor: T::AccountId::default(),444            };445446            // Add new collection to map447            <Collection<T>>::insert(next_id, new_collection);448449            // call event450            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));451452            Ok(())453        }454455        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.456        /// 457        /// # Permissions458        /// 459        /// * Collection Owner.460        /// 461        /// # Arguments462        /// 463        /// * collection_id: collection to destroy.464        #[weight = 0]465        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {466467            let sender = ensure_signed(origin)?;468            Self::check_owner_permissions(collection_id, sender)?;469470            <AddressTokens<T>>::remove_prefix(collection_id);471            <ApprovedList<T>>::remove_prefix(collection_id);472            <Balance<T>>::remove_prefix(collection_id);473            <ItemListIndex>::remove(collection_id);474            <AdminList<T>>::remove(collection_id);475            <Collection<T>>::remove(collection_id);476            <WhiteList<T>>::remove(collection_id);477478            <NftItemList<T>>::remove_prefix(collection_id);479            <FungibleItemList<T>>::remove_prefix(collection_id);480            <ReFungibleItemList<T>>::remove_prefix(collection_id);481482            <NftTransferBasket<T>>::remove_prefix(collection_id);483            <FungibleTransferBasket<T>>::remove_prefix(collection_id);484            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);485486            if CollectionCount::get() > 0487            {488                // bound couter489                let total = CollectionCount::get()490                    .checked_sub(1)491                    .expect("collection counter error");492493                CollectionCount::put(total);494            }495496            Ok(())497        }498499        /// Add an address to white list.500        /// 501        /// # Permissions502        /// 503        /// * Collection Owner504        /// * Collection Admin505        /// 506        /// # Arguments507        /// 508        /// * collection_id.509        /// 510        /// * address.511        #[weight = 0]512        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{513514            let sender = ensure_signed(origin)?;515            Self::check_owner_or_admin_permissions(collection_id, sender)?;516517            let mut white_list_collection: Vec<T::AccountId>;518            if <WhiteList<T>>::contains_key(collection_id) {519                white_list_collection = <WhiteList<T>>::get(collection_id);520                if !white_list_collection.contains(&address.clone())521                {522                    white_list_collection.push(address.clone());523                }524            }525            else {526                white_list_collection = Vec::new();527                white_list_collection.push(address.clone());528            }529530            <WhiteList<T>>::insert(collection_id, white_list_collection);531            Ok(())532        }533534        /// Remove an address from white list.535        /// 536        /// # Permissions537        /// 538        /// * Collection Owner539        /// * Collection Admin540        /// 541        /// # Arguments542        /// 543        /// * collection_id.544        /// 545        /// * address.546        #[weight = 0]547        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{548549            let sender = ensure_signed(origin)?;550            Self::check_owner_or_admin_permissions(collection_id, sender)?;551552            if <WhiteList<T>>::contains_key(collection_id) {553                let mut white_list_collection = <WhiteList<T>>::get(collection_id);554                if white_list_collection.contains(&address.clone())555                {556                    white_list_collection.retain(|i| *i != address.clone());557                    <WhiteList<T>>::insert(collection_id, white_list_collection);558                }559            }560561            Ok(())562        }563564        /// Toggle between normal and white list access for the methods with access for `Anyone`.565        /// 566        /// # Permissions567        /// 568        /// * Collection Owner.569        /// 570        /// # Arguments571        /// 572        /// * collection_id.573        /// 574        /// * mode: [AccessMode]575        #[weight = 0]576        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult577        {578            let sender = ensure_signed(origin)?;579580            Self::check_owner_permissions(collection_id, sender)?;581            let mut target_collection = <Collection<T>>::get(collection_id);582            target_collection.access = mode;583            <Collection<T>>::insert(collection_id, target_collection);584585            Ok(())586        }587588        /// Allows Anyone to create tokens if:589        /// * White List is enabled, and590        /// * Address is added to white list, and591        /// * This method was called with True parameter592        /// 593        /// # Permissions594        /// * Collection Owner595        ///596        /// # Arguments597        /// 598        /// * collection_id.599        /// 600        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.601        #[weight = 0]602        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult603        {604            let sender = ensure_signed(origin)?;605606            Self::check_owner_permissions(collection_id, sender)?;607            let mut target_collection = <Collection<T>>::get(collection_id);608            target_collection.mint_mode = mint_permission;609            <Collection<T>>::insert(collection_id, target_collection);610611            Ok(())612        }613614        /// Change the owner of the collection.615        /// 616        /// # Permissions617        /// 618        /// * Collection Owner.619        /// 620        /// # Arguments621        /// 622        /// * collection_id.623        /// 624        /// * new_owner.625        #[weight = 0]626        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {627628            let sender = ensure_signed(origin)?;629            Self::check_owner_permissions(collection_id, sender)?;630            let mut target_collection = <Collection<T>>::get(collection_id);631            target_collection.owner = new_owner;632            <Collection<T>>::insert(collection_id, target_collection);633634            Ok(())635        }636637        /// Adds an admin of the Collection.638        /// NFT Collection can be controlled by multiple admin addresses (some which can also be servers, for example). Admins can issue and burn NFTs, as well as add and remove other admins, but cannot change NFT or Collection ownership. 639        /// 640        /// # Permissions641        /// 642        /// * Collection Owner.643        /// * Collection Admin.644        /// 645        /// # Arguments646        /// 647        /// * collection_id: ID of the Collection to add admin for.648        /// 649        /// * new_admin_id: Address of new admin to add.650        #[weight = 0]651        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {652653            let sender = ensure_signed(origin)?;654            Self::check_owner_or_admin_permissions(collection_id, sender)?;655            let mut admin_arr: Vec<T::AccountId> = Vec::new();656657            if <AdminList<T>>::contains_key(collection_id)658            {659                admin_arr = <AdminList<T>>::get(collection_id);660                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");661            }662663            // Number of collection admins664            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");665666            admin_arr.push(new_admin_id);667            <AdminList<T>>::insert(collection_id, admin_arr);668669            Ok(())670        }671672        /// Remove admin address of the Collection. An admin address can remove itself. List of admins may become empty, in which case only Collection Owner will be able to add an Admin.673        ///674        /// # Permissions675        /// 676        /// * Collection Owner.677        /// * Collection Admin.678        /// 679        /// # Arguments680        /// 681        /// * collection_id: ID of the Collection to remove admin for.682        /// 683        /// * account_id: Address of admin to remove.684        #[weight = 0]685        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {686687            let sender = ensure_signed(origin)?;688            Self::check_owner_or_admin_permissions(collection_id, sender)?;689690            if <AdminList<T>>::contains_key(collection_id)691            {692                let mut admin_arr = <AdminList<T>>::get(collection_id);693                admin_arr.retain(|i| *i != account_id);694                <AdminList<T>>::insert(collection_id, admin_arr);695            }696697            Ok(())698        }699700        /// # Permissions701        /// 702        /// * Collection Owner703        /// 704        /// # Arguments705        /// 706        /// * collection_id.707        /// 708        /// * new_sponsor.709        #[weight = 0]710        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {711712            let sender = ensure_signed(origin)?;713            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");714715            let mut target_collection = <Collection<T>>::get(collection_id);716            ensure!(sender == target_collection.owner, "You do not own this collection");717718            target_collection.unconfirmed_sponsor = new_sponsor;719            <Collection<T>>::insert(collection_id, target_collection);720721            Ok(())722        }723724        /// # Permissions725        /// 726        /// * Sponsor.727        /// 728        /// # Arguments729        /// 730        /// * collection_id.731        #[weight = 0]732        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {733734            let sender = ensure_signed(origin)?;735            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");736737            let mut target_collection = <Collection<T>>::get(collection_id);738            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");739740            target_collection.sponsor = target_collection.unconfirmed_sponsor;741            target_collection.unconfirmed_sponsor = T::AccountId::default();742            <Collection<T>>::insert(collection_id, target_collection);743744            Ok(())745        }746747        /// Switch back to pay-per-own-transaction model.748        ///749        /// # Permissions750        ///751        /// * Collection owner.752        /// 753        /// # Arguments754        /// 755        /// * collection_id.756        #[weight = 0]757        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {758759            let sender = ensure_signed(origin)?;760            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");761762            let mut target_collection = <Collection<T>>::get(collection_id);763            ensure!(sender == target_collection.owner, "You do not own this collection");764765            target_collection.sponsor = T::AccountId::default();766            <Collection<T>>::insert(collection_id, target_collection);767768            Ok(())769        }770771        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.772        /// 773        /// # Permissions774        /// 775        /// * Collection Owner.776        /// * Collection Admin.777        /// * Anyone if778        ///     * White List is enabled, and779        ///     * Address is added to white list, and780        ///     * MintPermission is enabled (see SetMintPermission method)781        /// 782        /// # Arguments783        /// 784        /// * collection_id: ID of the collection.785        /// 786        /// * properties: Array of bytes that contains NFT properties. Since NFT Module is agnostic of properties meaning, it is treated purely as an array of bytes.787        /// 788        /// * owner: Address, initial owner of the NFT.789        #[weight = 0]790        pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {791792            let sender = ensure_signed(origin)?;793            Self::collection_exists(collection_id)?;794            let target_collection = <Collection<T>>::get(collection_id);795796            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {797                ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");798                Self::check_white_list(collection_id, &owner)?;799                Self::check_white_list(collection_id, &sender)?;800            }801802            match target_collection.mode803            {804                CollectionMode::NFT(_) => {805806                    // check size807                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");808809                    // Create nft item810                    let item = NftItemType {811                        collection: collection_id,812                        owner: owner,813                        data: properties.clone(),814                    };815816                    Self::add_nft_item(item)?;817818                },819                CollectionMode::Fungible(_) => {820821                    // check size822                    ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");823824                    let item = FungibleItemType {825                        collection: collection_id,826                        owner: owner,827                        value: (10 as u128).pow(target_collection.decimal_points)828                    };829830                    Self::add_fungible_item(item)?;831                },832                CollectionMode::ReFungible(_, _) => {833834                    // check size835                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");836837                    let mut owner_list = Vec::new();838                    let value = (10 as u128).pow(target_collection.decimal_points);839                    owner_list.push(Ownership {owner: owner.clone(), fraction: value});840841                    let item = ReFungibleItemType {842                        collection: collection_id,843                        owner: owner_list,844                        data: properties.clone()845                    };846847                    Self::add_refungible_item(item)?;848                },849                _ => { ensure!(1 == 0,"just error"); }850851            };852853            // call event854            Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));855856            Ok(())857        }858859        /// Destroys a concrete instance of NFT.860        /// 861        /// # Permissions862        /// 863        /// * Collection Owner.864        /// * Collection Admin.865        /// * Current NFT Owner.866        /// 867        /// # Arguments868        /// 869        /// * collection_id: ID of the collection.870        /// 871        /// * item_id: ID of NFT to burn.872        #[weight = 0]873        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {874875            let sender = ensure_signed(origin)?;876            Self::collection_exists(collection_id)?;877878            // Transfer permissions check879            let target_collection = <Collection<T>>::get(collection_id);880            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||881                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),882                "Only item owner, collection owner and admins can modify item");883884            if target_collection.access == AccessMode::WhiteList {885                Self::check_white_list(collection_id, &sender)?;886            }887888            match target_collection.mode889            {890                CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,891                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,892                CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,893                _ => ()894            };895896            // call event897            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));898899            Ok(())900        }901902        /// Change ownership of the token.903        /// 904        /// # Permissions905        /// 906        /// * Collection Owner907        /// * Collection Admin908        /// * Current NFT owner909        ///910        /// # Arguments911        /// 912        /// * recipient: Address of token recipient.913        /// 914        /// * collection_id.915        /// 916        /// * item_id: ID of the item917        ///     * Non-Fungible Mode: Required.918        ///     * Fungible Mode: Ignored.919        ///     * Re-Fungible Mode: Required.920        /// 921        /// * value: Amount to transfer.922        ///     * Non-Fungible Mode: Ignored923        ///     * Fungible Mode: Must specify transferred amount924        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)925        #[weight = 0]926        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {927928            let sender = ensure_signed(origin)?;929930            // Transfer permissions check931            let target_collection = <Collection<T>>::get(collection_id);932            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||933                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),934                "Only item owner, collection owner and admins can modify item");935936            if target_collection.access == AccessMode::WhiteList {937                Self::check_white_list(collection_id, &sender)?;938                Self::check_white_list(collection_id, &recipient)?;939            }940941            match target_collection.mode942            {943                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,944                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,945                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,946                _ => ()947            };948949            Ok(())950        }951952        /// Set, change, or remove approved address to transfer the ownership of the NFT.953        /// 954        /// # Permissions955        /// 956        /// * Collection Owner957        /// * Collection Admin958        /// * Current NFT owner959        /// 960        /// # Arguments961        /// 962        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).963        /// 964        /// * collection_id.965        /// 966        /// * item_id: ID of the item.967        #[weight = 0]968        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {969970            let sender = ensure_signed(origin)?;971972            // Transfer permissions check973            let target_collection = <Collection<T>>::get(collection_id);974            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||975                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),976                "Only item owner, collection owner and admins can approve");977978            if target_collection.access == AccessMode::WhiteList {979                Self::check_white_list(collection_id, &sender)?;980                Self::check_white_list(collection_id, &approved)?;981            }982983            // amount param stub984            let amount = 100000000;985986            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));987            if list_exists {988989                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));990                let item_contains = list.iter().any(|i| i.approved == approved);991992                if !item_contains {993                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });994                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);995                }996            } else {997998                let mut list = Vec::new();999                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1000                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1001            }10021003            Ok(())1004        }1005        1006        /// Change ownership of a NFT on behalf of the owner. See Approve method for additional information. After this method executes, the approval is removed so that the approved address will not be able to transfer this NFT again from this owner.1007        /// 1008        /// # Permissions1009        /// * Collection Owner1010        /// * Collection Admin1011        /// * Current NFT owner1012        /// * Address approved by current NFT owner1013        /// 1014        /// # Arguments1015        /// 1016        /// * from: Address that owns token.1017        /// 1018        /// * recipient: Address of token recipient.1019        /// 1020        /// * collection_id.1021        /// 1022        /// * item_id: ID of the item.1023        /// 1024        /// * value: Amount to transfer.1025        #[weight = 0]1026        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10271028            let sender = ensure_signed(origin)?;1029            let mut appoved_transfer = false;10301031            // Check approve1032            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1033                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1034                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1035                appoved_transfer = opt_item.is_some();1036                ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1037            }10381039            // Transfer permissions check1040            let target_collection = <Collection<T>>::get(collection_id);1041            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1042                "Only item owner, collection owner and admins can modify items");10431044            if target_collection.access == AccessMode::WhiteList {1045                Self::check_white_list(collection_id, &sender)?;1046                Self::check_white_list(collection_id, &recipient)?;1047            }10481049            // remove approve1050            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1051                .into_iter().filter(|i| i.approved != sender.clone()).collect();1052            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);105310541055            match target_collection.mode1056            {1057                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1058                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1059                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1060                _ => ()1061            };10621063            Ok(())1064        }10651066        ///1067        #[weight = 0]1068        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10691070            // let no_perm_mes = "You do not have permissions to modify this collection";1071            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1072            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1073            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10741075            // // on_nft_received  call10761077            // Self::transfer(origin, collection_id, item_id, new_owner)?;10781079            Ok(())1080        }10811082        /// Set off-chain data schema.1083        /// 1084        /// # Permissions1085        /// 1086        /// * Collection Owner1087        /// * Collection Admin1088        /// 1089        /// # Arguments1090        /// 1091        /// * collection_id.1092        /// 1093        /// * schema: String representing the offchain data schema.1094        #[weight = 0]1095        pub fn set_offchain_schema(1096            origin,1097            collection_id: u64,1098            schema: Vec<u8>1099        ) -> DispatchResult {1100            let sender = ensure_signed(origin)?;1101            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11021103            let mut target_collection = <Collection<T>>::get(collection_id);1104            target_collection.offchain_schema = schema;1105            <Collection<T>>::insert(collection_id, target_collection);11061107            Ok(())1108        }11091110        // Sudo permissions function1111        #[weight = 0]1112        pub fn set_chain_limits(1113            origin,1114            limits: ChainLimits1115        ) -> DispatchResult {1116            ensure_root(origin)?;1117            <ChainLimit>::put(limits);1118            Ok(())1119        }        1120    }1121}11221123impl<T: Trait> Module<T> {1124    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1125        let current_index = <ItemListIndex>::get(item.collection)1126            .checked_add(1)1127            .expect("Item list index id error");1128        let itemcopy = item.clone();1129        let owner = item.owner.clone();1130        let value = item.value as u64;11311132        Self::add_token_index(item.collection, current_index, owner.clone())?;11331134        <ItemListIndex>::insert(item.collection, current_index);1135        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11361137        // Add current block1138        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1139        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1140        1141        // Update balance1142        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1143            .checked_add(value)1144            .unwrap();1145        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11461147        Ok(())1148    }11491150    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1151        let current_index = <ItemListIndex>::get(item.collection)1152            .checked_add(1)1153            .expect("Item list index id error");1154        let itemcopy = item.clone();11551156        let value = item.owner.first().unwrap().fraction as u64;1157        let owner = item.owner.first().unwrap().owner.clone();11581159        Self::add_token_index(item.collection, current_index, owner.clone())?;11601161        <ItemListIndex>::insert(item.collection, current_index);1162        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11631164        // Add current block1165        let block_number: T::BlockNumber = 0.into();1166        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11671168        // Update balance1169        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1170            .checked_add(value)1171            .unwrap();1172        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11731174        Ok(())1175    }11761177    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1178        let current_index = <ItemListIndex>::get(item.collection)1179            .checked_add(1)1180            .expect("Item list index id error");11811182        let item_owner = item.owner.clone();1183        let collection_id = item.collection.clone();1184        Self::add_token_index(collection_id, current_index, item.owner.clone())?;11851186        <ItemListIndex>::insert(collection_id, current_index);1187        <NftItemList<T>>::insert(collection_id, current_index, item);11881189        // Add current block1190        let block_number: T::BlockNumber = 0.into();1191        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);11921193        // Update balance1194        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1195            .checked_add(1)1196            .unwrap();1197        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);11981199        Ok(())1200    }12011202    fn burn_refungible_item(1203        collection_id: u64,1204        item_id: u64,1205        owner: T::AccountId,1206    ) -> DispatchResult {1207        ensure!(1208            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1209            "Item does not exists"1210        );1211        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1212        let item = collection1213            .owner1214            .iter()1215            .filter(|&i| i.owner == owner)1216            .next()1217            .unwrap();1218        Self::remove_token_index(collection_id, item_id, owner.clone())?;12191220        // remove approve list1221        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12221223        // update balance1224        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1225            .checked_sub(item.fraction as u64)1226            .unwrap();1227        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12281229        <ReFungibleItemList<T>>::remove(collection_id, item_id);12301231        Ok(())1232    }12331234    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1235        ensure!(1236            <NftItemList<T>>::contains_key(collection_id, item_id),1237            "Item does not exists"1238        );1239        let item = <NftItemList<T>>::get(collection_id, item_id);1240        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12411242        // remove approve list1243        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12441245        // update balance1246        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1247            .checked_sub(1)1248            .unwrap();1249        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1250        <NftItemList<T>>::remove(collection_id, item_id);12511252        Ok(())1253    }12541255    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1256        ensure!(1257            <FungibleItemList<T>>::contains_key(collection_id, item_id),1258            "Item does not exists"1259        );1260        let item = <FungibleItemList<T>>::get(collection_id, item_id);1261        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12621263        // remove approve list1264        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12651266        // update balance1267        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1268            .checked_sub(item.value as u64)1269            .unwrap();1270        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12711272        <FungibleItemList<T>>::remove(collection_id, item_id);12731274        Ok(())1275    }12761277    fn collection_exists(collection_id: u64) -> DispatchResult {1278        ensure!(1279            <Collection<T>>::contains_key(collection_id),1280            "This collection does not exist"1281        );1282        Ok(())1283    }12841285    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1286        Self::collection_exists(collection_id)?;12871288        let target_collection = <Collection<T>>::get(collection_id);1289        ensure!(1290            subject == target_collection.owner,1291            "You do not own this collection"1292        );12931294        Ok(())1295    }12961297    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1298        let target_collection = <Collection<T>>::get(collection_id);1299        let mut result: bool = subject == target_collection.owner;1300        let exists = <AdminList<T>>::contains_key(collection_id);13011302        if !result & exists {1303            if <AdminList<T>>::get(collection_id).contains(&subject) {1304                result = true1305            }1306        }13071308        result1309    }13101311    fn check_owner_or_admin_permissions(1312        collection_id: u64,1313        subject: T::AccountId,1314    ) -> DispatchResult {1315        Self::collection_exists(collection_id)?;1316        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13171318        ensure!(1319            result,1320            "You do not have permissions to modify this collection"1321        );1322        Ok(())1323    }13241325    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1326        let target_collection = <Collection<T>>::get(collection_id);13271328        match target_collection.mode {1329            CollectionMode::NFT(_) => {1330                <NftItemList<T>>::get(collection_id, item_id).owner == subject1331            }1332            CollectionMode::Fungible(_) => {1333                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1334            }1335            CollectionMode::ReFungible(_, _) => {1336                <ReFungibleItemList<T>>::get(collection_id, item_id)1337                    .owner1338                    .iter()1339                    .any(|i| i.owner == subject)1340            }1341            CollectionMode::Invalid => false,1342        }1343    }13441345    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1346        let mes = "Address is not in white list";1347        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1348        let wl = <WhiteList<T>>::get(collection_id);1349        ensure!(wl.contains(address), mes);13501351        Ok(())1352    }13531354    fn transfer_fungible(1355        collection_id: u64,1356        item_id: u64,1357        value: u64,1358        owner: T::AccountId,1359        new_owner: T::AccountId,1360    ) -> DispatchResult {1361        ensure!(1362            <FungibleItemList<T>>::contains_key(collection_id, item_id),1363            "Item not exists"1364        );13651366        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1367        let amount = full_item.value;13681369        ensure!(amount >= value.into(), "Item balance not enouth");13701371        // update balance1372        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1373            .checked_sub(value)1374            .unwrap();1375        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13761377        let mut new_owner_account_id = 0;1378        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1379        if new_owner_items.len() > 0 {1380            new_owner_account_id = new_owner_items[0];1381        }13821383        let val64 = value.into();13841385        // transfer1386        if amount == val64 && new_owner_account_id == 0 {1387            // change owner1388            // new owner do not have account1389            let mut new_full_item = full_item.clone();1390            new_full_item.owner = new_owner.clone();1391            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);13921393            // update balance1394            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1395                .checked_add(value)1396                .unwrap();1397            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);13981399            // update index collection1400            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1401        } else {1402            let mut new_full_item = full_item.clone();1403            new_full_item.value -= val64;14041405            // separate amount1406            if new_owner_account_id > 0 {1407                // new owner has account1408                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1409                item.value += val64;14101411                // update balance1412                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1413                    .checked_add(value)1414                    .unwrap();1415                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14161417                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1418            } else {1419                // new owner do not have account1420                let item = FungibleItemType {1421                    collection: collection_id,1422                    owner: new_owner.clone(),1423                    value: val64,1424                };14251426                Self::add_fungible_item(item)?;1427            }14281429            if amount == val64 {1430                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14311432                // remove approve list1433                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1434                <FungibleItemList<T>>::remove(collection_id, item_id);1435            }14361437            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1438        }14391440        Ok(())1441    }14421443    fn transfer_refungible(1444        collection_id: u64,1445        item_id: u64,1446        value: u64,1447        owner: T::AccountId,1448        new_owner: T::AccountId,1449    ) -> DispatchResult {1450        ensure!(1451            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1452            "Item not exists"1453        );14541455        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1456        let item = full_item1457            .owner1458            .iter()1459            .filter(|i| i.owner == owner)1460            .next()1461            .unwrap();1462        let amount = item.fraction;14631464        ensure!(amount >= value.into(), "Item balance not enouth");14651466        // update balance1467        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1468            .checked_sub(value)1469            .unwrap();1470        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14711472        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1473            .checked_add(value)1474            .unwrap();1475        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14761477        let old_owner = item.owner.clone();1478        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1479        let val64 = value.into();14801481        // transfer1482        if amount == val64 && !new_owner_has_account {1483            // change owner1484            // new owner do not have account1485            let mut new_full_item = full_item.clone();1486            new_full_item1487                .owner1488                .iter_mut()1489                .find(|i| i.owner == owner)1490                .unwrap()1491                .owner = new_owner.clone();1492            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14931494            // update index collection1495            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1496        } else {1497            let mut new_full_item = full_item.clone();1498            new_full_item1499                .owner1500                .iter_mut()1501                .find(|i| i.owner == owner)1502                .unwrap()1503                .fraction -= val64;15041505            // separate amount1506            if new_owner_has_account {1507                // new owner has account1508                new_full_item1509                    .owner1510                    .iter_mut()1511                    .find(|i| i.owner == new_owner)1512                    .unwrap()1513                    .fraction += val64;1514            } else {1515                // new owner do not have account1516                new_full_item.owner.push(Ownership {1517                    owner: new_owner.clone(),1518                    fraction: val64,1519                });1520                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1521            }15221523            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1524        }15251526        Ok(())1527    }15281529    fn transfer_nft(1530        collection_id: u64,1531        item_id: u64,1532        sender: T::AccountId,1533        new_owner: T::AccountId,1534    ) -> DispatchResult {1535        ensure!(1536            <NftItemList<T>>::contains_key(collection_id, item_id),1537            "Item not exists"1538        );15391540        let mut item = <NftItemList<T>>::get(collection_id, item_id);15411542        ensure!(1543            sender == item.owner,1544            "sender parameter and item owner must be equal"1545        );15461547        // update balance1548        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1549            .checked_sub(1)1550            .unwrap();1551        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15521553        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1554            .checked_add(1)1555            .unwrap();1556        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15571558        // change owner1559        let old_owner = item.owner.clone();1560        item.owner = new_owner.clone();1561        <NftItemList<T>>::insert(collection_id, item_id, item);15621563        // update index collection1564        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15651566        // reset approved list1567        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1568        Ok(())1569    }15701571    fn init_collection(item: &CollectionType<T::AccountId>) {1572        // check params1573        assert!(1574            item.decimal_points <= 4,1575            "decimal_points parameter must be lower than 4"1576        );1577        assert!(1578            item.name.len() <= 64,1579            "Collection name can not be longer than 63 char"1580        );1581        assert!(1582            item.name.len() <= 256,1583            "Collection description can not be longer than 255 char"1584        );1585        assert!(1586            item.token_prefix.len() <= 16,1587            "Token prefix can not be longer than 15 char"1588        );15891590        // Generate next collection ID1591        let next_id = CreatedCollectionCount::get()1592            .checked_add(1)1593            .expect("collection id error");15941595        CreatedCollectionCount::put(next_id);1596    }15971598    fn init_nft_token(item: &NftItemType<T::AccountId>) {1599        let current_index = <ItemListIndex>::get(item.collection)1600            .checked_add(1)1601            .expect("Item list index id error");16021603        let item_owner = item.owner.clone();1604        let collection_id = item.collection.clone();1605        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16061607        <ItemListIndex>::insert(collection_id, current_index);16081609        // Update balance1610        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1611            .checked_add(1)1612            .unwrap();1613        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1614    }16151616    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1617        let current_index = <ItemListIndex>::get(item.collection)1618            .checked_add(1)1619            .expect("Item list index id error");1620        let owner = item.owner.clone();1621        let value = item.value as u64;16221623        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16241625        <ItemListIndex>::insert(item.collection, current_index);16261627        // Update balance1628        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1629            .checked_add(value)1630            .unwrap();1631        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1632    }16331634    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1635        let current_index = <ItemListIndex>::get(item.collection)1636            .checked_add(1)1637            .expect("Item list index id error");16381639        let value = item.owner.first().unwrap().fraction as u64;1640        let owner = item.owner.first().unwrap().owner.clone();16411642        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16431644        <ItemListIndex>::insert(item.collection, current_index);16451646        // Update balance1647        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1648            .checked_add(value)1649            .unwrap();1650        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1651    }16521653    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16541655        // add to account limit1656        if <AccountItemCount<T>>::contains_key(owner.clone()) {16571658            // bound Owned tokens by a single address1659            let count = <AccountItemCount<T>>::get(owner.clone());1660            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16611662            <AccountItemCount<T>>::insert(owner.clone(), 1663                count.checked_add(1).unwrap());1664        }1665        else {1666            <AccountItemCount<T>>::insert(owner.clone(), 1);1667        }16681669        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1670        if list_exists {1671            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1672            let item_contains = list.contains(&item_index.clone());16731674            if !item_contains {1675                list.push(item_index.clone());1676            }16771678            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1679        } else {1680            let mut itm = Vec::new();1681            itm.push(item_index.clone());1682            <AddressTokens<T>>::insert(collection_id, owner, itm);1683            1684        }16851686        Ok(())1687    }16881689    fn remove_token_index(1690        collection_id: u64,1691        item_index: u64,1692        owner: T::AccountId,1693    ) -> DispatchResult {16941695        // update counter1696        <AccountItemCount<T>>::insert(owner.clone(), 1697            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());169816991700        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1701        if list_exists {1702            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1703            let item_contains = list.contains(&item_index.clone());17041705            if item_contains {1706                list.retain(|&item| item != item_index);1707                <AddressTokens<T>>::insert(collection_id, owner, list);1708            }1709        }17101711        Ok(())1712    }17131714    fn move_token_index(1715        collection_id: u64,1716        item_index: u64,1717        old_owner: T::AccountId,1718        new_owner: T::AccountId,1719    ) -> DispatchResult {1720        Self::remove_token_index(collection_id, item_index, old_owner)?;1721        Self::add_token_index(collection_id, item_index, new_owner)?;17221723        Ok(())1724    }1725}17261727////////////////////////////////////////////////////////////////////////////////////////////////////1728// Economic models1729// #region17301731/// Fee multiplier.1732pub type Multiplier = FixedU128;17331734type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1735    <T as system::Trait>::AccountId,1736>>::Balance;1737type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1738    <T as system::Trait>::AccountId,1739>>::NegativeImbalance;17401741/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1742/// in the queue.1743#[derive(Encode, Decode, Clone, Eq, PartialEq)]1744pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1745    #[codec(compact)] BalanceOf<T>,1746);17471748impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1749    for ChargeTransactionPayment<T>1750{1751    #[cfg(feature = "std")]1752    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1753        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1754    }1755    #[cfg(not(feature = "std"))]1756    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1757        Ok(())1758    }1759}17601761impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1762where1763    T::Call:1764        Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1765    BalanceOf<T>: Send + Sync + FixedPointOperand,1766{1767    /// utility constructor. Used only in client/factory code.1768    pub fn from(fee: BalanceOf<T>) -> Self {1769        Self(fee)1770    }17711772    pub fn traditional_fee(1773        len: usize,1774        info: &DispatchInfoOf<T::Call>,1775        tip: BalanceOf<T>,1776    ) -> BalanceOf<T>1777    where1778        T::Call: Dispatchable<Info = DispatchInfo>,1779    {1780        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1781    }17821783    fn withdraw_fee(1784        &self,1785        who: &T::AccountId,1786        call: &T::Call,1787        info: &DispatchInfoOf<T::Call>,1788        len: usize,1789    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1790        let tip = self.0;17911792        // Set fee based on call type. Creating collection costs 1 Unique.1793        // All other transactions have traditional fees so far1794        let fee = match call.is_sub_type() {1795            Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1796            _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1797                                                        // _ => <BalanceOf<T>>::from(100)1798        };17991800        // Determine who is paying transaction fee based on ecnomic model1801        // Parse call to extract collection ID and access collection sponsor1802        let sponsor: T::AccountId = match call.is_sub_type() {1803            Some(Call::create_item(collection_id, _properties, _owner)) => {1804                <Collection<T>>::get(collection_id).sponsor1805            }1806            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1807                let _collection_mode = <Collection<T>>::get(collection_id).mode;18081809                // sponsor timeout1810                let sponsor_transfer = match _collection_mode {1811                    CollectionMode::NFT(_) => {1812                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1813                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1814                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1815                        if block_number >= limit_time {1816                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1817                            true1818                        }1819                        else {1820                            false1821                        }1822                    }1823                    CollectionMode::Fungible(_) => {1824                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1825                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1826                        if basket.iter().any(|i| i.address == _new_owner.clone())1827                        {1828                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1829                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1830                            if block_number >= limit_time {1831                                basket.retain(|x| x.address == item.address);1832                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1833                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1834                                true1835                            }1836                            else {1837                                false1838                            }1839                        }1840                        else {1841                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1842                            true1843                        }1844                    }1845                    CollectionMode::ReFungible(_, _) => {1846                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1847                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1848                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1849                        if block_number >= limit_time {1850                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1851                            true1852                        } else {1853                            false1854                        }1855                    }1856                    _ => {1857                        false1858                    },1859                };18601861                if !sponsor_transfer {1862                    T::AccountId::default()1863                } else {1864                    <Collection<T>>::get(collection_id).sponsor1865                }1866            }18671868            _ => T::AccountId::default(),1869        };18701871        let mut who_pays_fee: T::AccountId = sponsor.clone();1872        if sponsor == T::AccountId::default() {1873            who_pays_fee = who.clone();1874        }18751876        // Only mess with balances if fee is not zero.1877        if fee.is_zero() {1878            return Ok((fee, None));1879        }18801881        match <T as transaction_payment::Trait>::Currency::withdraw(1882            &who_pays_fee,1883            fee,1884            if tip.is_zero() {1885                WithdrawReason::TransactionPayment.into()1886            } else {1887                WithdrawReason::TransactionPayment | WithdrawReason::Tip1888            },1889            ExistenceRequirement::KeepAlive,1890        ) {1891            Ok(imbalance) => Ok((fee, Some(imbalance))),1892            Err(_) => Err(InvalidTransaction::Payment.into()),1893        }1894    }1895}18961897impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1898    for ChargeTransactionPayment<T>1899where1900    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1901    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1902{1903    const IDENTIFIER: &'static str = "ChargeTransactionPayment";1904    type AccountId = T::AccountId;1905    type Call = T::Call;1906    type AdditionalSigned = ();1907    type Pre = (1908        BalanceOf<T>,1909        Self::AccountId,1910        Option<NegativeImbalanceOf<T>>,1911        BalanceOf<T>,1912    );1913    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1914        Ok(())1915    }19161917    fn validate(1918        &self,1919        who: &Self::AccountId,1920        call: &Self::Call,1921        info: &DispatchInfoOf<Self::Call>,1922        len: usize,1923    ) -> TransactionValidity {1924        let (fee, _) = self.withdraw_fee(who, call, info, len)?;19251926        let mut r = ValidTransaction::default();1927        // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which1928        // will be a bit more than setting the priority to tip. For now, this is enough.1929        r.priority = fee.saturated_into::<TransactionPriority>();1930        Ok(r)1931    }19321933    fn pre_dispatch(1934        self,1935        who: &Self::AccountId,1936        call: &Self::Call,1937        info: &DispatchInfoOf<Self::Call>,1938        len: usize,1939    ) -> Result<Self::Pre, TransactionValidityError> {1940        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1941        Ok((self.0, who.clone(), imbalance, fee))1942    }19431944    fn post_dispatch(1945        pre: Self::Pre,1946        info: &DispatchInfoOf<Self::Call>,1947        post_info: &PostDispatchInfoOf<Self::Call>,1948        len: usize,1949        _result: &DispatchResult,1950    ) -> Result<(), TransactionValidityError> {1951        let (tip, who, imbalance, fee) = pre;1952        if let Some(payed) = imbalance {1953            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1954                len as u32, info, post_info, tip,1955            );1956            let refund = fee.saturating_sub(actual_fee);1957            let actual_payment =1958                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1959                    &who, refund,1960                ) {1961                    Ok(refund_imbalance) => {1962                        // The refund cannot be larger than the up front payed max weight.1963                        // `PostDispatchInfo::calc_unspent` guards against such a case.1964                        match payed.offset(refund_imbalance) {1965                            Ok(actual_payment) => actual_payment,1966                            Err(_) => return Err(InvalidTransaction::Payment.into()),1967                        }1968                    }1969                    // We do not recreate the account using the refund. The up front payment1970                    // is gone in that case.1971                    Err(_) => payed,1972                };1973            let imbalances = actual_payment.split(tip);1974            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1975                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1976            );1977        }1978        Ok(())1979    }1980}1981// #endregion19821983
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -528,16 +528,16 @@
 			use frame_benchmarking::{Benchmarking, BenchmarkBatch, add_benchmark, TrackedStorageKey};
 
 			let whitelist: Vec<TrackedStorageKey> = vec![
-				// Block Number
-				hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac").to_vec().into(),
-				// Total Issuance
-				hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
-				// Execution Phase
-				hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
-				// Event Count
-				hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
-				// System Events
-				hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
+				// Alice account
+				hex_literal::hex!("d43593c715fdd31c61141abd04a99fd6822c8558854ccde39a5684e7a56da27d").to_vec().into(),
+				// // Total Issuance
+				// hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80").to_vec().into(),
+				// // Execution Phase
+				// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a").to_vec().into(),
+				// // Event Count
+				// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850").to_vec().into(),
+				// // System Events
+				// hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7").to_vec().into(),
             ];
 
 			let mut batches = Vec::<BenchmarkBatch>::new();