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
after · 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};25// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2627use frame_system::{self as system, ensure_signed, ensure_root};28use sp_runtime::sp_std::prelude::Vec;29use sp_runtime::{30    traits::{31        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,32        SignedExtension, Zero,33    },34    transaction_validity::{35        InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,36        ValidTransaction,37    },38    FixedPointOperand, FixedU128,39};4041#[cfg(test)]42mod mock;4344#[cfg(test)]45mod tests;4647// Structs48// #region4950#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]51#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]52pub enum CollectionMode {53    Invalid,54    // custom data size55    NFT(u32),56    // decimal points57    Fungible(u32),58    // custom data size and decimal points59    ReFungible(u32, u32),60}6162impl Into<u8> for CollectionMode {63    fn into(self) -> u8 {64        match self {65            CollectionMode::Invalid => 0,66            CollectionMode::NFT(_) => 1,67            CollectionMode::Fungible(_) => 2,68            CollectionMode::ReFungible(_, _) => 3,69        }70    }71}7273#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]74#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]75pub enum AccessMode {76    Normal,77    WhiteList,78}79impl Default for AccessMode {80    fn default() -> Self {81        Self::Normal82    }83}8485impl Default for CollectionMode {86    fn default() -> Self {87        Self::Invalid88    }89}9091#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]92#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]93pub struct Ownership<AccountId> {94    pub owner: AccountId,95    pub fraction: u128,96}9798#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]99#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]100pub struct CollectionType<AccountId> {101    pub owner: AccountId,102    pub mode: CollectionMode,103    pub access: AccessMode,104    pub decimal_points: u32,105    pub name: Vec<u16>,        // 64 include null escape char106    pub description: Vec<u16>, // 256 include null escape char107    pub token_prefix: Vec<u8>, // 16 include null escape char108    pub custom_data_size: u32,109    pub mint_mode: bool,110    pub offchain_schema: Vec<u8>,111    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender112    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship113}114115#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]116#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]117pub struct CollectionAdminsType<AccountId> {118    pub admin: AccountId,119    pub collection_id: u64,120}121122#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]123#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]124pub struct NftItemType<AccountId> {125    pub collection: u64,126    pub owner: AccountId,127    pub data: Vec<u8>,128}129130#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]131#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]132pub struct FungibleItemType<AccountId> {133    pub collection: u64,134    pub owner: AccountId,135    pub value: u128,136}137138#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]139#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]140pub struct ReFungibleItemType<AccountId> {141    pub collection: u64,142    pub owner: Vec<Ownership<AccountId>>,143    pub data: Vec<u8>,144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct ApprovePermissions<AccountId> {149    pub approved: AccountId,150    pub amount: u64,151}152153#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]155pub struct VestingItem<AccountId, Moment> {156    pub sender: AccountId,157    pub recipient: AccountId,158    pub collection_id: u64,159    pub item_id: u64,160    pub amount: u64,161    pub vesting_date: Moment,162}163164#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]165#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]166pub struct BasketItem<AccountId, BlockNumber> {167    pub address: AccountId,168    pub start_block: BlockNumber,169}170171#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]172#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]173pub struct ChainLimits {174    pub collection_numbers_limit: u64,175    pub account_token_ownership_limit: u64,176    pub collections_admins_limit: u64,177    pub custom_data_limit: u32,178179    // Timeouts for item types in passed blocks180    pub nft_sponsor_transfer_timeout: u32,181    pub fungible_sponsor_transfer_timeout: u32,182    pub refungible_sponsor_transfer_timeout: u32,183}184185pub trait Trait: system::Trait {186    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;187}188189#[cfg(feature = "runtime-benchmarks")]190mod benchmarking;191192// #endregion193194decl_storage! {195    trait Store for Module<T: Trait> as Nft {196197        // Private members198        NextCollectionID: u64;199        CreatedCollectionCount: u64;200        ChainVersion: u64;201        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;202203        // Chain limits struct204        pub ChainLimit get(fn chain_limit) config(): ChainLimits;205206        // Bound counters207        CollectionCount: u64;208        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;209210        // Basic collections211        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;212        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;213        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;214215        /// Balance owner per collection map216        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;217218        /// second parameter: item id + owner account id219        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;220221        /// Item collections222        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;223        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;224        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;225226        /// Index list227        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;228229        /// Tokens transfer baskets230        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;231        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>>;232        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;233234        // Sponsorship235        pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;236        pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;237    }238    add_extra_genesis {239        build(|config: &GenesisConfig<T>| {240            // Modification of storage241            for (_num, _c) in &config.collection {242                <Module<T>>::init_collection(_c);243            }244245            for (_num, _q, _i) in &config.nft_item_id {246                <Module<T>>::init_nft_token(_i);247            }248249            for (_num, _q, _i) in &config.fungible_item_id {250                <Module<T>>::init_fungible_token(_i);251            }252253            for (_num, _q, _i) in &config.refungible_item_id {254                <Module<T>>::init_refungible_token(_i);255            }256        })257    }258}259260decl_event!(261    pub enum Event<T>262    where263        AccountId = <T as system::Trait>::AccountId,264    {265        /// New collection was created266        /// 267        /// # Arguments268        /// 269        /// * collection_id: Globally unique identifier of newly created collection.270        /// 271        /// * mode: [CollectionMode] converted into u8.272        /// 273        /// * account_id: Collection owner.274        Created(u64, u8, AccountId),275276        /// New item was created.277        /// 278        /// # Arguments279        /// 280        /// * collection_id: Id of the collection where item was created.281        /// 282        /// * item_id: Id of an item. Unique within the collection.283        ItemCreated(u64, u64),284285        /// Collection item was burned.286        /// 287        /// # Arguments288        /// 289        /// collection_id.290        /// 291        /// item_id: Identifier of burned NFT.292        ItemDestroyed(u64, u64),293    }294);295296decl_module! {297    pub struct Module<T: Trait> for enum Call where origin: T::Origin {298299        fn deposit_event() = default;300301        fn on_initialize(now: T::BlockNumber) -> Weight {302303            if ChainVersion::get() < 2304            {305                let value = NextCollectionID::get();306                CreatedCollectionCount::put(value);307                ChainVersion::put(2);308            }309310            0311        }312313        /// 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.314        /// 315        /// # Permissions316        /// 317        /// * Anyone.318        /// 319        /// # Arguments320        /// 321        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.322        /// 323        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.324        /// 325        /// * token_prefix: UTF-8 string with token prefix.326        /// 327        /// * mode: [CollectionMode] collection type and type dependent data.328        // returns collection ID329        #[weight =330        (70_000_000 as Weight)331        .saturating_add(RocksDbWeight::get().reads(7 as Weight))332        .saturating_add(RocksDbWeight::get().writes(5 as Weight))]333        pub fn create_collection(origin,334                                 collection_name: Vec<u16>,335                                 collection_description: Vec<u16>,336                                 token_prefix: Vec<u8>,337                                 mode: CollectionMode) -> DispatchResult {338339            // Anyone can create a collection340            let who = ensure_signed(origin)?;341            let custom_data_size = match mode {342                CollectionMode::NFT(size) => {343344                    // bound Custom data size345                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");346                    size347                },348                CollectionMode::ReFungible(size, _) => {349350                    // bound Custom data size351                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");352                    size353                },354                _ => 0355            };356357            let decimal_points = match mode {358                CollectionMode::Fungible(points) => points,359                CollectionMode::ReFungible(_, points) => points,360                _ => 0361            };362363            // bound Total number of collections364            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");365366            // check params367            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");368369            let mut name = collection_name.to_vec();370            name.push(0);371            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");372373            let mut description = collection_description.to_vec();374            description.push(0);375            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");376377            let mut prefix = token_prefix.to_vec();378            prefix.push(0);379            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");380381            // Generate next collection ID382            let next_id = CreatedCollectionCount::get()383                .checked_add(1)384                .expect("collection id error");385386            // bound counter387            let total = CollectionCount::get()388                .checked_add(1)389                .expect("collection counter error");390391            CreatedCollectionCount::put(next_id);392            CollectionCount::put(total);393394            // Create new collection395            let new_collection = CollectionType {396                owner: who.clone(),397                name: name,398                mode: mode.clone(),399                mint_mode: false,400                access: AccessMode::Normal,401                description: description,402                decimal_points: decimal_points,403                token_prefix: prefix,404                offchain_schema: Vec::new(),405                custom_data_size: custom_data_size,406                sponsor: T::AccountId::default(),407                unconfirmed_sponsor: T::AccountId::default(),408            };409410            // Add new collection to map411            <Collection<T>>::insert(next_id, new_collection);412413            // call event414            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));415416            Ok(())417        }418419        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.420        /// 421        /// # Permissions422        /// 423        /// * Collection Owner.424        /// 425        /// # Arguments426        /// 427        /// * collection_id: collection to destroy.428        #[weight =429        (90_000_000 as Weight)430        .saturating_add(RocksDbWeight::get().reads(2 as Weight))431        .saturating_add(RocksDbWeight::get().writes(5 as Weight))]432        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {433434            let sender = ensure_signed(origin)?;435            Self::check_owner_permissions(collection_id, sender)?;436437            <AddressTokens<T>>::remove_prefix(collection_id);438            <ApprovedList<T>>::remove_prefix(collection_id);439            <Balance<T>>::remove_prefix(collection_id);440            <ItemListIndex>::remove(collection_id);441            <AdminList<T>>::remove(collection_id);442            <Collection<T>>::remove(collection_id);443            <WhiteList<T>>::remove(collection_id);444445            <NftItemList<T>>::remove_prefix(collection_id);446            <FungibleItemList<T>>::remove_prefix(collection_id);447            <ReFungibleItemList<T>>::remove_prefix(collection_id);448449            <NftTransferBasket<T>>::remove_prefix(collection_id);450            <FungibleTransferBasket<T>>::remove_prefix(collection_id);451            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);452453            if CollectionCount::get() > 0454            {455                // bound couter456                let total = CollectionCount::get()457                    .checked_sub(1)458                    .expect("collection counter error");459460                CollectionCount::put(total);461            }462463            Ok(())464        }465466        /// Add an address to white list.467        /// 468        /// # Permissions469        /// 470        /// * Collection Owner471        /// * Collection Admin472        /// 473        /// # Arguments474        /// 475        /// * collection_id.476        /// 477        /// * address.478        #[weight =479        (30_000_000 as Weight)480        .saturating_add(RocksDbWeight::get().reads(3 as Weight))481        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]482        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{483484            let sender = ensure_signed(origin)?;485            Self::check_owner_or_admin_permissions(collection_id, sender)?;486487            let mut white_list_collection: Vec<T::AccountId>;488            if <WhiteList<T>>::contains_key(collection_id) {489                white_list_collection = <WhiteList<T>>::get(collection_id);490                if !white_list_collection.contains(&address.clone())491                {492                    white_list_collection.push(address.clone());493                }494            }495            else {496                white_list_collection = Vec::new();497                white_list_collection.push(address.clone());498            }499500            <WhiteList<T>>::insert(collection_id, white_list_collection);501            Ok(())502        }503504        /// Remove an address from white list.505        /// 506        /// # Permissions507        /// 508        /// * Collection Owner509        /// * Collection Admin510        /// 511        /// # Arguments512        /// 513        /// * collection_id.514        /// 515        /// * address.516        #[weight =517        (35_000_000 as Weight)518        .saturating_add(RocksDbWeight::get().reads(3 as Weight))519        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]520        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{521522            let sender = ensure_signed(origin)?;523            Self::check_owner_or_admin_permissions(collection_id, sender)?;524525            if <WhiteList<T>>::contains_key(collection_id) {526                let mut white_list_collection = <WhiteList<T>>::get(collection_id);527                if white_list_collection.contains(&address.clone())528                {529                    white_list_collection.retain(|i| *i != address.clone());530                    <WhiteList<T>>::insert(collection_id, white_list_collection);531                }532            }533534            Ok(())535        }536537        /// Toggle between normal and white list access for the methods with access for `Anyone`.538        /// 539        /// # Permissions540        /// 541        /// * Collection Owner.542        /// 543        /// # Arguments544        /// 545        /// * collection_id.546        /// 547        /// * mode: [AccessMode]548        #[weight =549        (27_000_000 as Weight)550        .saturating_add(RocksDbWeight::get().reads(1 as Weight))551        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]552        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult553        {554            let sender = ensure_signed(origin)?;555556            Self::check_owner_permissions(collection_id, sender)?;557            let mut target_collection = <Collection<T>>::get(collection_id);558            target_collection.access = mode;559            <Collection<T>>::insert(collection_id, target_collection);560561            Ok(())562        }563564        /// Allows Anyone to create tokens if:565        /// * White List is enabled, and566        /// * Address is added to white list, and567        /// * This method was called with True parameter568        /// 569        /// # Permissions570        /// * Collection Owner571        ///572        /// # Arguments573        /// 574        /// * collection_id.575        /// 576        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.577        #[weight =578        (27_000_000 as Weight)579        .saturating_add(RocksDbWeight::get().reads(1 as Weight))580        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]581        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult582        {583            let sender = ensure_signed(origin)?;584585            Self::check_owner_permissions(collection_id, sender)?;586            let mut target_collection = <Collection<T>>::get(collection_id);587            target_collection.mint_mode = mint_permission;588            <Collection<T>>::insert(collection_id, target_collection);589590            Ok(())591        }592593        /// Change the owner of the collection.594        /// 595        /// # Permissions596        /// 597        /// * Collection Owner.598        /// 599        /// # Arguments600        /// 601        /// * collection_id.602        /// 603        /// * new_owner.604        #[weight =605        (27_000_000 as Weight)606        .saturating_add(RocksDbWeight::get().reads(1 as Weight))607        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]608        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {609610            let sender = ensure_signed(origin)?;611            Self::check_owner_permissions(collection_id, sender)?;612            let mut target_collection = <Collection<T>>::get(collection_id);613            target_collection.owner = new_owner;614            <Collection<T>>::insert(collection_id, target_collection);615616            Ok(())617        }618619        /// Adds an admin of the Collection.620        /// 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. 621        /// 622        /// # Permissions623        /// 624        /// * Collection Owner.625        /// * Collection Admin.626        /// 627        /// # Arguments628        /// 629        /// * collection_id: ID of the Collection to add admin for.630        /// 631        /// * new_admin_id: Address of new admin to add.632        #[weight =633        (32_000_000 as Weight)634        .saturating_add(RocksDbWeight::get().reads(3 as Weight))635        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]636        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {637638            let sender = ensure_signed(origin)?;639            Self::check_owner_or_admin_permissions(collection_id, sender)?;640            let mut admin_arr: Vec<T::AccountId> = Vec::new();641642            if <AdminList<T>>::contains_key(collection_id)643            {644                admin_arr = <AdminList<T>>::get(collection_id);645                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");646            }647648            // Number of collection admins649            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");650651            admin_arr.push(new_admin_id);652            <AdminList<T>>::insert(collection_id, admin_arr);653654            Ok(())655        }656657        /// 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.658        ///659        /// # Permissions660        /// 661        /// * Collection Owner.662        /// * Collection Admin.663        /// 664        /// # Arguments665        /// 666        /// * collection_id: ID of the Collection to remove admin for.667        /// 668        /// * account_id: Address of admin to remove.669        #[weight =670        (50_000_000 as Weight)671        .saturating_add(RocksDbWeight::get().reads(2 as Weight))672        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]673        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {674675            let sender = ensure_signed(origin)?;676            Self::check_owner_or_admin_permissions(collection_id, sender)?;677678            if <AdminList<T>>::contains_key(collection_id)679            {680                let mut admin_arr = <AdminList<T>>::get(collection_id);681                admin_arr.retain(|i| *i != account_id);682                <AdminList<T>>::insert(collection_id, admin_arr);683            }684685            Ok(())686        }687688        /// # Permissions689        /// 690        /// * Collection Owner691        /// 692        /// # Arguments693        /// 694        /// * collection_id.695        /// 696        /// * new_sponsor.697        #[weight =698        (32_000_000 as Weight)699        .saturating_add(RocksDbWeight::get().reads(2 as Weight))700        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]701        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {702703            let sender = ensure_signed(origin)?;704            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");705706            let mut target_collection = <Collection<T>>::get(collection_id);707            ensure!(sender == target_collection.owner, "You do not own this collection");708709            target_collection.unconfirmed_sponsor = new_sponsor;710            <Collection<T>>::insert(collection_id, target_collection);711712            Ok(())713        }714715        /// # Permissions716        /// 717        /// * Sponsor.718        /// 719        /// # Arguments720        /// 721        /// * collection_id.722        #[weight =723        (22_000_000 as Weight)724        .saturating_add(RocksDbWeight::get().reads(1 as Weight))725        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]726        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {727728            let sender = ensure_signed(origin)?;729            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");730731            let mut target_collection = <Collection<T>>::get(collection_id);732            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");733734            target_collection.sponsor = target_collection.unconfirmed_sponsor;735            target_collection.unconfirmed_sponsor = T::AccountId::default();736            <Collection<T>>::insert(collection_id, target_collection);737738            Ok(())739        }740741        /// Switch back to pay-per-own-transaction model.742        ///743        /// # Permissions744        ///745        /// * Collection owner.746        /// 747        /// # Arguments748        /// 749        /// * collection_id.750        #[weight =751        (24_000_000 as Weight)752        .saturating_add(RocksDbWeight::get().reads(1 as Weight))753        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]754        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {755756            let sender = ensure_signed(origin)?;757            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");758759            let mut target_collection = <Collection<T>>::get(collection_id);760            ensure!(sender == target_collection.owner, "You do not own this collection");761762            target_collection.sponsor = T::AccountId::default();763            <Collection<T>>::insert(collection_id, target_collection);764765            Ok(())766        }767768        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.769        /// 770        /// # Permissions771        /// 772        /// * Collection Owner.773        /// * Collection Admin.774        /// * Anyone if775        ///     * White List is enabled, and776        ///     * Address is added to white list, and777        ///     * MintPermission is enabled (see SetMintPermission method)778        /// 779        /// # Arguments780        /// 781        /// * collection_id: ID of the collection.782        /// 783        /// * 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.784        /// 785        /// * owner: Address, initial owner of the NFT.786        #[weight =787        (130_000_000 as Weight)788        .saturating_add(RocksDbWeight::get().reads(10 as Weight))789        .saturating_add(RocksDbWeight::get().writes(8 as Weight))]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 =873        (170_000_000 as Weight)874        .saturating_add(RocksDbWeight::get().reads(9 as Weight))875        .saturating_add(RocksDbWeight::get().writes(7 as Weight))]876        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {877878            let sender = ensure_signed(origin)?;879            Self::collection_exists(collection_id)?;880881            // Transfer permissions check882            let target_collection = <Collection<T>>::get(collection_id);883            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||884                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),885                "Only item owner, collection owner and admins can modify item");886887            if target_collection.access == AccessMode::WhiteList {888                Self::check_white_list(collection_id, &sender)?;889            }890891            match target_collection.mode892            {893                CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,894                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,895                CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,896                _ => ()897            };898899            // call event900            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));901902            Ok(())903        }904905        /// Change ownership of the token.906        /// 907        /// # Permissions908        /// 909        /// * Collection Owner910        /// * Collection Admin911        /// * Current NFT owner912        ///913        /// # Arguments914        /// 915        /// * recipient: Address of token recipient.916        /// 917        /// * collection_id.918        /// 919        /// * item_id: ID of the item920        ///     * Non-Fungible Mode: Required.921        ///     * Fungible Mode: Ignored.922        ///     * Re-Fungible Mode: Required.923        /// 924        /// * value: Amount to transfer.925        ///     * Non-Fungible Mode: Ignored926        ///     * Fungible Mode: Must specify transferred amount927        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)928        #[weight =929        (125_000_000 as Weight)930        .saturating_add(RocksDbWeight::get().reads(7 as Weight))931        .saturating_add(RocksDbWeight::get().writes(7 as Weight))]932        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {933934            let sender = ensure_signed(origin)?;935936            // Transfer permissions check937            let target_collection = <Collection<T>>::get(collection_id);938            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||939                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),940                "Only item owner, collection owner and admins can modify item");941942            if target_collection.access == AccessMode::WhiteList {943                Self::check_white_list(collection_id, &sender)?;944                Self::check_white_list(collection_id, &recipient)?;945            }946947            match target_collection.mode948            {949                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,950                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,951                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,952                _ => ()953            };954955            Ok(())956        }957958        /// Set, change, or remove approved address to transfer the ownership of the NFT.959        /// 960        /// # Permissions961        /// 962        /// * Collection Owner963        /// * Collection Admin964        /// * Current NFT owner965        /// 966        /// # Arguments967        /// 968        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).969        /// 970        /// * collection_id.971        /// 972        /// * item_id: ID of the item.973        #[weight =974        (45_000_000 as Weight)975        .saturating_add(RocksDbWeight::get().reads(3 as Weight))976        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]977        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {978979            let sender = ensure_signed(origin)?;980981            // Transfer permissions check982            let target_collection = <Collection<T>>::get(collection_id);983            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||984                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),985                "Only item owner, collection owner and admins can approve");986987            if target_collection.access == AccessMode::WhiteList {988                Self::check_white_list(collection_id, &sender)?;989                Self::check_white_list(collection_id, &approved)?;990            }991992            // amount param stub993            let amount = 100000000;994995            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));996            if list_exists {997998                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));999                let item_contains = list.iter().any(|i| i.approved == approved);10001001                if !item_contains {1002                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1003                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1004                }1005            } else {10061007                let mut list = Vec::new();1008                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1009                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1010            }10111012            Ok(())1013        }1014        1015        /// 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.1016        /// 1017        /// # Permissions1018        /// * Collection Owner1019        /// * Collection Admin1020        /// * Current NFT owner1021        /// * Address approved by current NFT owner1022        /// 1023        /// # Arguments1024        /// 1025        /// * from: Address that owns token.1026        /// 1027        /// * recipient: Address of token recipient.1028        /// 1029        /// * collection_id.1030        /// 1031        /// * item_id: ID of the item.1032        /// 1033        /// * value: Amount to transfer.1034        #[weight =1035        (150_000_000 as Weight)1036        .saturating_add(RocksDbWeight::get().reads(9 as Weight))1037        .saturating_add(RocksDbWeight::get().writes(8 as Weight))]1038        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10391040            let sender = ensure_signed(origin)?;1041            let mut appoved_transfer = false;10421043            // Check approve1044            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1045                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1046                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1047                if opt_item.is_some()1048                {1049                    appoved_transfer = true;1050                    ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1051                }1052            }10531054            // Transfer permissions check1055            let target_collection = <Collection<T>>::get(collection_id);1056            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1057                "Only item owner, collection owner and admins can modify items");10581059            if target_collection.access == AccessMode::WhiteList {1060                Self::check_white_list(collection_id, &sender)?;1061                Self::check_white_list(collection_id, &recipient)?;1062            }10631064            // remove approve1065            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1066                .into_iter().filter(|i| i.approved != sender.clone()).collect();1067            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);106810691070            match target_collection.mode1071            {1072                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1073                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1074                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1075                _ => ()1076            };10771078            Ok(())1079        }10801081        ///1082        #[weight = 0]1083        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10841085            // let no_perm_mes = "You do not have permissions to modify this collection";1086            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1087            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1088            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10891090            // // on_nft_received  call10911092            // Self::transfer(origin, collection_id, item_id, new_owner)?;10931094            Ok(())1095        }10961097        /// Set off-chain data schema.1098        /// 1099        /// # Permissions1100        /// 1101        /// * Collection Owner1102        /// * Collection Admin1103        /// 1104        /// # Arguments1105        /// 1106        /// * collection_id.1107        /// 1108        /// * schema: String representing the offchain data schema.1109        #[weight =1110        (33_000_000 as Weight)1111        .saturating_add(RocksDbWeight::get().reads(2 as Weight))1112        .saturating_add(RocksDbWeight::get().writes(1 as Weight))]1113        pub fn set_offchain_schema(1114            origin,1115            collection_id: u64,1116            schema: Vec<u8>1117        ) -> DispatchResult {1118            let sender = ensure_signed(origin)?;1119            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11201121            let mut target_collection = <Collection<T>>::get(collection_id);1122            target_collection.offchain_schema = schema;1123            <Collection<T>>::insert(collection_id, target_collection);11241125            Ok(())1126        }11271128        // Sudo permissions function1129        #[weight = 0]1130        pub fn set_chain_limits(1131            origin,1132            limits: ChainLimits1133        ) -> DispatchResult {1134            ensure_root(origin)?;1135            <ChainLimit>::put(limits);1136            Ok(())1137        }        1138    }1139}11401141impl<T: Trait> Module<T> {1142    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1143        let current_index = <ItemListIndex>::get(item.collection)1144            .checked_add(1)1145            .expect("Item list index id error");1146        let itemcopy = item.clone();1147        let owner = item.owner.clone();1148        let value = item.value as u64;11491150        Self::add_token_index(item.collection, current_index, owner.clone())?;11511152        <ItemListIndex>::insert(item.collection, current_index);1153        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11541155        // Add current block1156        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1157        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1158        1159        // Update balance1160        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1161            .checked_add(value)1162            .unwrap();1163        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11641165        Ok(())1166    }11671168    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1169        let current_index = <ItemListIndex>::get(item.collection)1170            .checked_add(1)1171            .expect("Item list index id error");1172        let itemcopy = item.clone();11731174        let value = item.owner.first().unwrap().fraction as u64;1175        let owner = item.owner.first().unwrap().owner.clone();11761177        Self::add_token_index(item.collection, current_index, owner.clone())?;11781179        <ItemListIndex>::insert(item.collection, current_index);1180        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11811182        // Add current block1183        let block_number: T::BlockNumber = 0.into();1184        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11851186        // Update balance1187        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1188            .checked_add(value)1189            .unwrap();1190        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11911192        Ok(())1193    }11941195    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1196        let current_index = <ItemListIndex>::get(item.collection)1197            .checked_add(1)1198            .expect("Item list index id error");11991200        let item_owner = item.owner.clone();1201        let collection_id = item.collection.clone();1202        Self::add_token_index(collection_id, current_index, item.owner.clone())?;12031204        <ItemListIndex>::insert(collection_id, current_index);1205        <NftItemList<T>>::insert(collection_id, current_index, item);12061207        // Add current block1208        let block_number: T::BlockNumber = 0.into();1209        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);12101211        // Update balance1212        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1213            .checked_add(1)1214            .unwrap();1215        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);12161217        Ok(())1218    }12191220    fn burn_refungible_item(1221        collection_id: u64,1222        item_id: u64,1223        owner: T::AccountId,1224    ) -> DispatchResult {1225        ensure!(1226            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1227            "Item does not exists"1228        );1229        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1230        let item = collection1231            .owner1232            .iter()1233            .filter(|&i| i.owner == owner)1234            .next()1235            .unwrap();1236        Self::remove_token_index(collection_id, item_id, owner.clone())?;12371238        // remove approve list1239        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12401241        // update balance1242        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1243            .checked_sub(item.fraction as u64)1244            .unwrap();1245        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12461247        <ReFungibleItemList<T>>::remove(collection_id, item_id);12481249        Ok(())1250    }12511252    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1253        ensure!(1254            <NftItemList<T>>::contains_key(collection_id, item_id),1255            "Item does not exists"1256        );1257        let item = <NftItemList<T>>::get(collection_id, item_id);1258        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12591260        // remove approve list1261        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12621263        // update balance1264        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1265            .checked_sub(1)1266            .unwrap();1267        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1268        <NftItemList<T>>::remove(collection_id, item_id);12691270        Ok(())1271    }12721273    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1274        ensure!(1275            <FungibleItemList<T>>::contains_key(collection_id, item_id),1276            "Item does not exists"1277        );1278        let item = <FungibleItemList<T>>::get(collection_id, item_id);1279        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12801281        // remove approve list1282        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12831284        // update balance1285        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1286            .checked_sub(item.value as u64)1287            .unwrap();1288        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12891290        <FungibleItemList<T>>::remove(collection_id, item_id);12911292        Ok(())1293    }12941295    fn collection_exists(collection_id: u64) -> DispatchResult {1296        ensure!(1297            <Collection<T>>::contains_key(collection_id),1298            "This collection does not exist"1299        );1300        Ok(())1301    }13021303    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1304        Self::collection_exists(collection_id)?;13051306        let target_collection = <Collection<T>>::get(collection_id);1307        ensure!(1308            subject == target_collection.owner,1309            "You do not own this collection"1310        );13111312        Ok(())1313    }13141315    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1316        let target_collection = <Collection<T>>::get(collection_id);1317        let mut result: bool = subject == target_collection.owner;1318        let exists = <AdminList<T>>::contains_key(collection_id);13191320        if !result & exists {1321            if <AdminList<T>>::get(collection_id).contains(&subject) {1322                result = true1323            }1324        }13251326        result1327    }13281329    fn check_owner_or_admin_permissions(1330        collection_id: u64,1331        subject: T::AccountId,1332    ) -> DispatchResult {1333        Self::collection_exists(collection_id)?;1334        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13351336        ensure!(1337            result,1338            "You do not have permissions to modify this collection"1339        );1340        Ok(())1341    }13421343    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1344        let target_collection = <Collection<T>>::get(collection_id);13451346        match target_collection.mode {1347            CollectionMode::NFT(_) => {1348                <NftItemList<T>>::get(collection_id, item_id).owner == subject1349            }1350            CollectionMode::Fungible(_) => {1351                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1352            }1353            CollectionMode::ReFungible(_, _) => {1354                <ReFungibleItemList<T>>::get(collection_id, item_id)1355                    .owner1356                    .iter()1357                    .any(|i| i.owner == subject)1358            }1359            CollectionMode::Invalid => false,1360        }1361    }13621363    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1364        let mes = "Address is not in white list";1365        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1366        let wl = <WhiteList<T>>::get(collection_id);1367        ensure!(wl.contains(address), mes);13681369        Ok(())1370    }13711372    fn transfer_fungible(1373        collection_id: u64,1374        item_id: u64,1375        value: u64,1376        owner: T::AccountId,1377        new_owner: T::AccountId,1378    ) -> DispatchResult {1379        ensure!(1380            <FungibleItemList<T>>::contains_key(collection_id, item_id),1381            "Item not exists"1382        );13831384        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1385        let amount = full_item.value;13861387        ensure!(amount >= value.into(), "Item balance not enouth");13881389        // update balance1390        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1391            .checked_sub(value)1392            .unwrap();1393        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13941395        let mut new_owner_account_id = 0;1396        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1397        if new_owner_items.len() > 0 {1398            new_owner_account_id = new_owner_items[0];1399        }14001401        let val64 = value.into();14021403        // transfer1404        if amount == val64 && new_owner_account_id == 0 {1405            // change owner1406            // new owner do not have account1407            let mut new_full_item = full_item.clone();1408            new_full_item.owner = new_owner.clone();1409            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);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            // update index collection1418            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1419        } else {1420            let mut new_full_item = full_item.clone();1421            new_full_item.value -= val64;14221423            // separate amount1424            if new_owner_account_id > 0 {1425                // new owner has account1426                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1427                item.value += val64;14281429                // update balance1430                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1431                    .checked_add(value)1432                    .unwrap();1433                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14341435                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1436            } else {1437                // new owner do not have account1438                let item = FungibleItemType {1439                    collection: collection_id,1440                    owner: new_owner.clone(),1441                    value: val64,1442                };14431444                Self::add_fungible_item(item)?;1445            }14461447            if amount == val64 {1448                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14491450                // remove approve list1451                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1452                <FungibleItemList<T>>::remove(collection_id, item_id);1453            }14541455            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1456        }14571458        Ok(())1459    }14601461    fn transfer_refungible(1462        collection_id: u64,1463        item_id: u64,1464        value: u64,1465        owner: T::AccountId,1466        new_owner: T::AccountId,1467    ) -> DispatchResult {1468        ensure!(1469            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1470            "Item not exists"1471        );14721473        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1474        let item = full_item1475            .owner1476            .iter()1477            .filter(|i| i.owner == owner)1478            .next()1479            .unwrap();1480        let amount = item.fraction;14811482        ensure!(amount >= value.into(), "Item balance not enouth");14831484        // update balance1485        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1486            .checked_sub(value)1487            .unwrap();1488        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14891490        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1491            .checked_add(value)1492            .unwrap();1493        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14941495        let old_owner = item.owner.clone();1496        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1497        let val64 = value.into();14981499        // transfer1500        if amount == val64 && !new_owner_has_account {1501            // change owner1502            // new owner do not have account1503            let mut new_full_item = full_item.clone();1504            new_full_item1505                .owner1506                .iter_mut()1507                .find(|i| i.owner == owner)1508                .unwrap()1509                .owner = new_owner.clone();1510            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);15111512            // update index collection1513            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1514        } else {1515            let mut new_full_item = full_item.clone();1516            new_full_item1517                .owner1518                .iter_mut()1519                .find(|i| i.owner == owner)1520                .unwrap()1521                .fraction -= val64;15221523            // separate amount1524            if new_owner_has_account {1525                // new owner has account1526                new_full_item1527                    .owner1528                    .iter_mut()1529                    .find(|i| i.owner == new_owner)1530                    .unwrap()1531                    .fraction += val64;1532            } else {1533                // new owner do not have account1534                new_full_item.owner.push(Ownership {1535                    owner: new_owner.clone(),1536                    fraction: val64,1537                });1538                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1539            }15401541            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1542        }15431544        Ok(())1545    }15461547    fn transfer_nft(1548        collection_id: u64,1549        item_id: u64,1550        sender: T::AccountId,1551        new_owner: T::AccountId,1552    ) -> DispatchResult {1553        ensure!(1554            <NftItemList<T>>::contains_key(collection_id, item_id),1555            "Item not exists"1556        );15571558        let mut item = <NftItemList<T>>::get(collection_id, item_id);15591560        ensure!(1561            sender == item.owner,1562            "sender parameter and item owner must be equal"1563        );15641565        // update balance1566        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1567            .checked_sub(1)1568            .unwrap();1569        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15701571        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1572            .checked_add(1)1573            .unwrap();1574        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15751576        // change owner1577        let old_owner = item.owner.clone();1578        item.owner = new_owner.clone();1579        <NftItemList<T>>::insert(collection_id, item_id, item);15801581        // update index collection1582        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15831584        // reset approved list1585        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1586        Ok(())1587    }15881589    fn init_collection(item: &CollectionType<T::AccountId>) {1590        // check params1591        assert!(1592            item.decimal_points <= 4,1593            "decimal_points parameter must be lower than 4"1594        );1595        assert!(1596            item.name.len() <= 64,1597            "Collection name can not be longer than 63 char"1598        );1599        assert!(1600            item.name.len() <= 256,1601            "Collection description can not be longer than 255 char"1602        );1603        assert!(1604            item.token_prefix.len() <= 16,1605            "Token prefix can not be longer than 15 char"1606        );16071608        // Generate next collection ID1609        let next_id = CreatedCollectionCount::get()1610            .checked_add(1)1611            .expect("collection id error");16121613        CreatedCollectionCount::put(next_id);1614    }16151616    fn init_nft_token(item: &NftItemType<T::AccountId>) {1617        let current_index = <ItemListIndex>::get(item.collection)1618            .checked_add(1)1619            .expect("Item list index id error");16201621        let item_owner = item.owner.clone();1622        let collection_id = item.collection.clone();1623        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16241625        <ItemListIndex>::insert(collection_id, current_index);16261627        // Update balance1628        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1629            .checked_add(1)1630            .unwrap();1631        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1632    }16331634    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1635        let current_index = <ItemListIndex>::get(item.collection)1636            .checked_add(1)1637            .expect("Item list index id error");1638        let owner = item.owner.clone();1639        let value = item.value as u64;16401641        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16421643        <ItemListIndex>::insert(item.collection, current_index);16441645        // Update balance1646        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1647            .checked_add(value)1648            .unwrap();1649        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1650    }16511652    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1653        let current_index = <ItemListIndex>::get(item.collection)1654            .checked_add(1)1655            .expect("Item list index id error");16561657        let value = item.owner.first().unwrap().fraction as u64;1658        let owner = item.owner.first().unwrap().owner.clone();16591660        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16611662        <ItemListIndex>::insert(item.collection, current_index);16631664        // Update balance1665        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1666            .checked_add(value)1667            .unwrap();1668        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1669    }16701671    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16721673        // add to account limit1674        if <AccountItemCount<T>>::contains_key(owner.clone()) {16751676            // bound Owned tokens by a single address1677            let count = <AccountItemCount<T>>::get(owner.clone());1678            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16791680            <AccountItemCount<T>>::insert(owner.clone(), 1681                count.checked_add(1).unwrap());1682        }1683        else {1684            <AccountItemCount<T>>::insert(owner.clone(), 1);1685        }16861687        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1688        if list_exists {1689            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1690            let item_contains = list.contains(&item_index.clone());16911692            if !item_contains {1693                list.push(item_index.clone());1694            }16951696            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1697        } else {1698            let mut itm = Vec::new();1699            itm.push(item_index.clone());1700            <AddressTokens<T>>::insert(collection_id, owner, itm);1701            1702        }17031704        Ok(())1705    }17061707    fn remove_token_index(1708        collection_id: u64,1709        item_index: u64,1710        owner: T::AccountId,1711    ) -> DispatchResult {17121713        // update counter1714        <AccountItemCount<T>>::insert(owner.clone(), 1715            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());171617171718        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1719        if list_exists {1720            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1721            let item_contains = list.contains(&item_index.clone());17221723            if item_contains {1724                list.retain(|&item| item != item_index);1725                <AddressTokens<T>>::insert(collection_id, owner, list);1726            }1727        }17281729        Ok(())1730    }17311732    fn move_token_index(1733        collection_id: u64,1734        item_index: u64,1735        old_owner: T::AccountId,1736        new_owner: T::AccountId,1737    ) -> DispatchResult {1738        Self::remove_token_index(collection_id, item_index, old_owner)?;1739        Self::add_token_index(collection_id, item_index, new_owner)?;17401741        Ok(())1742    }1743}17441745////////////////////////////////////////////////////////////////////////////////////////////////////1746// Economic models1747// #region17481749/// Fee multiplier.1750pub type Multiplier = FixedU128;17511752type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1753    <T as system::Trait>::AccountId,1754>>::Balance;1755type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1756    <T as system::Trait>::AccountId,1757>>::NegativeImbalance;17581759/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1760/// in the queue.1761#[derive(Encode, Decode, Clone, Eq, PartialEq)]1762pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1763    #[codec(compact)] BalanceOf<T>,1764);17651766impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1767    for ChargeTransactionPayment<T>1768{1769    #[cfg(feature = "std")]1770    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1771        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1772    }1773    #[cfg(not(feature = "std"))]1774    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1775        Ok(())1776    }1777}17781779impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1780where1781    T::Call:1782        Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1783    BalanceOf<T>: Send + Sync + FixedPointOperand,1784{1785    /// utility constructor. Used only in client/factory code.1786    pub fn from(fee: BalanceOf<T>) -> Self {1787        Self(fee)1788    }17891790    pub fn traditional_fee(1791        len: usize,1792        info: &DispatchInfoOf<T::Call>,1793        tip: BalanceOf<T>,1794    ) -> BalanceOf<T>1795    where1796        T::Call: Dispatchable<Info = DispatchInfo>,1797    {1798        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1799    }18001801    fn withdraw_fee(1802        &self,1803        who: &T::AccountId,1804        call: &T::Call,1805        info: &DispatchInfoOf<T::Call>,1806        len: usize,1807    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1808        let tip = self.0;18091810        // Set fee based on call type. Creating collection costs 1 Unique.1811        // All other transactions have traditional fees so far1812        let fee = match call.is_sub_type() {1813            Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1814            _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1815                                                        // _ => <BalanceOf<T>>::from(100)1816        };18171818        // Determine who is paying transaction fee based on ecnomic model1819        // Parse call to extract collection ID and access collection sponsor1820        let sponsor: T::AccountId = match call.is_sub_type() {1821            Some(Call::create_item(collection_id, _properties, _owner)) => {1822                <Collection<T>>::get(collection_id).sponsor1823            }1824            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1825                let _collection_mode = <Collection<T>>::get(collection_id).mode;18261827                // sponsor timeout1828                let sponsor_transfer = match _collection_mode {1829                    CollectionMode::NFT(_) => {1830                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1831                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1832                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1833                        if block_number >= limit_time {1834                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1835                            true1836                        }1837                        else {1838                            false1839                        }1840                    }1841                    CollectionMode::Fungible(_) => {1842                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1843                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1844                        if basket.iter().any(|i| i.address == _new_owner.clone())1845                        {1846                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1847                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1848                            if block_number >= limit_time {1849                                basket.retain(|x| x.address == item.address);1850                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1851                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1852                                true1853                            }1854                            else {1855                                false1856                            }1857                        }1858                        else {1859                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1860                            true1861                        }1862                    }1863                    CollectionMode::ReFungible(_, _) => {1864                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1865                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1866                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1867                        if block_number >= limit_time {1868                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1869                            true1870                        } else {1871                            false1872                        }1873                    }1874                    _ => {1875                        false1876                    },1877                };18781879                if !sponsor_transfer {1880                    T::AccountId::default()1881                } else {1882                    <Collection<T>>::get(collection_id).sponsor1883                }1884            }18851886            _ => T::AccountId::default(),1887        };18881889        let mut who_pays_fee: T::AccountId = sponsor.clone();1890        if sponsor == T::AccountId::default() {1891            who_pays_fee = who.clone();1892        }18931894        // Only mess with balances if fee is not zero.1895        if fee.is_zero() {1896            return Ok((fee, None));1897        }18981899        match <T as transaction_payment::Trait>::Currency::withdraw(1900            &who_pays_fee,1901            fee,1902            if tip.is_zero() {1903                WithdrawReason::TransactionPayment.into()1904            } else {1905                WithdrawReason::TransactionPayment | WithdrawReason::Tip1906            },1907            ExistenceRequirement::KeepAlive,1908        ) {1909            Ok(imbalance) => Ok((fee, Some(imbalance))),1910            Err(_) => Err(InvalidTransaction::Payment.into()),1911        }1912    }1913}19141915impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1916    for ChargeTransactionPayment<T>1917where1918    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1919    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1920{1921    const IDENTIFIER: &'static str = "ChargeTransactionPayment";1922    type AccountId = T::AccountId;1923    type Call = T::Call;1924    type AdditionalSigned = ();1925    type Pre = (1926        BalanceOf<T>,1927        Self::AccountId,1928        Option<NegativeImbalanceOf<T>>,1929        BalanceOf<T>,1930    );1931    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1932        Ok(())1933    }19341935    fn validate(1936        &self,1937        who: &Self::AccountId,1938        call: &Self::Call,1939        info: &DispatchInfoOf<Self::Call>,1940        len: usize,1941    ) -> TransactionValidity {1942        let (fee, _) = self.withdraw_fee(who, call, info, len)?;19431944        let mut r = ValidTransaction::default();1945        // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which1946        // will be a bit more than setting the priority to tip. For now, this is enough.1947        r.priority = fee.saturated_into::<TransactionPriority>();1948        Ok(r)1949    }19501951    fn pre_dispatch(1952        self,1953        who: &Self::AccountId,1954        call: &Self::Call,1955        info: &DispatchInfoOf<Self::Call>,1956        len: usize,1957    ) -> Result<Self::Pre, TransactionValidityError> {1958        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1959        Ok((self.0, who.clone(), imbalance, fee))1960    }19611962    fn post_dispatch(1963        pre: Self::Pre,1964        info: &DispatchInfoOf<Self::Call>,1965        post_info: &PostDispatchInfoOf<Self::Call>,1966        len: usize,1967        _result: &DispatchResult,1968    ) -> Result<(), TransactionValidityError> {1969        let (tip, who, imbalance, fee) = pre;1970        if let Some(payed) = imbalance {1971            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1972                len as u32, info, post_info, tip,1973            );1974            let refund = fee.saturating_sub(actual_fee);1975            let actual_payment =1976                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1977                    &who, refund,1978                ) {1979                    Ok(refund_imbalance) => {1980                        // The refund cannot be larger than the up front payed max weight.1981                        // `PostDispatchInfo::calc_unspent` guards against such a case.1982                        match payed.offset(refund_imbalance) {1983                            Ok(actual_payment) => actual_payment,1984                            Err(_) => return Err(InvalidTransaction::Payment.into()),1985                        }1986                    }1987                    // We do not recreate the account using the refund. The up front payment1988                    // is gone in that case.1989                    Err(_) => payed,1990                };1991            let imbalances = actual_payment.split(tip);1992            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1993                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1994            );1995        }1996        Ok(())1997    }1998}1999// #endregion20002001
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();