git.delta.rocks / unique-network / refs/commits / 144732746abe

difftreelog

Finished smart contract sponsoring

Greg Zaitsev2020-11-05parent: #31c3cec.patch.diff
in: master

3 files changed

modifiedpallets/nft/src/default_weights.rsdiffbeforeafterboth
--- a/pallets/nft/src/default_weights.rs
+++ b/pallets/nft/src/default_weights.rs
@@ -92,4 +92,9 @@
             .saturating_add(DbWeight::get().reads(2 as Weight))
             .saturating_add(DbWeight::get().writes(1 as Weight))
     }
+    // fn enable_contract_sponsoring() -> Weight {
+    //     (0 as Weight)
+    //         .saturating_add(DbWeight::get().reads(1 as Weight))
+    //         .saturating_add(DbWeight::get().writes(1 as Weight))
+    // }
 }
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11    construct_runtime, decl_event, decl_module, decl_storage,12    dispatch::DispatchResult,13    ensure, parameter_types,14    debug,15    traits::{16        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,17        Randomness, WithdrawReason,18    },19    weights::{20        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},21        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,22        WeightToFeePolynomial,23    },24    IsSubType, StorageValue,25};26use sp_runtime::print;27// use frame_support::weights::{Weight, constants::RocksDbWeight as DbWeight};2829use frame_system::{self as system, ensure_signed, ensure_root};30use sp_runtime::sp_std::prelude::Vec;31use sp_runtime::{32    traits::{33        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,34        SignedExtension, Zero,35    },36    transaction_validity::{37        InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,38        ValidTransaction,39    },40    FixedPointOperand, FixedU128,41};4243#[cfg(test)]44mod mock;4546#[cfg(test)]47mod tests;4849mod default_weights;5051// Structs52// #region5354#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]55#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]56pub enum CollectionMode {57    Invalid,58    // custom data size59    NFT(u32),60    // decimal points61    Fungible(u32),62    // custom data size and decimal points63    ReFungible(u32, u32),64}6566impl Into<u8> for CollectionMode {67    fn into(self) -> u8 {68        match self {69            CollectionMode::Invalid => 0,70            CollectionMode::NFT(_) => 1,71            CollectionMode::Fungible(_) => 2,72            CollectionMode::ReFungible(_, _) => 3,73        }74    }75}7677#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]78#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]79pub enum AccessMode {80    Normal,81    WhiteList,82}83impl Default for AccessMode {84    fn default() -> Self {85        Self::Normal86    }87}8889impl Default for CollectionMode {90    fn default() -> Self {91        Self::Invalid92    }93}9495#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub struct Ownership<AccountId> {98    pub owner: AccountId,99    pub fraction: u128,100}101102#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]103#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]104pub struct CollectionType<AccountId> {105    pub owner: AccountId,106    pub mode: CollectionMode,107    pub access: AccessMode,108    pub decimal_points: u32,109    pub name: Vec<u16>,        // 64 include null escape char110    pub description: Vec<u16>, // 256 include null escape char111    pub token_prefix: Vec<u8>, // 16 include null escape char112    pub custom_data_size: u32,113    pub mint_mode: bool,114    pub offchain_schema: Vec<u8>,115    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender116    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct CollectionAdminsType<AccountId> {122    pub admin: AccountId,123    pub collection_id: u64,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct NftItemType<AccountId> {129    pub collection: u64,130    pub owner: AccountId,131    pub data: Vec<u8>,132}133134#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]135#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]136pub struct FungibleItemType<AccountId> {137    pub collection: u64,138    pub owner: AccountId,139    pub value: u128,140}141142#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]143#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]144pub struct ReFungibleItemType<AccountId> {145    pub collection: u64,146    pub owner: Vec<Ownership<AccountId>>,147    pub data: Vec<u8>,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct ApprovePermissions<AccountId> {153    pub approved: AccountId,154    pub amount: u64,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct VestingItem<AccountId, Moment> {160    pub sender: AccountId,161    pub recipient: AccountId,162    pub collection_id: u64,163    pub item_id: u64,164    pub amount: u64,165    pub vesting_date: Moment,166}167168#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct BasketItem<AccountId, BlockNumber> {171    pub address: AccountId,172    pub start_block: BlockNumber,173}174175#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]176#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]177pub struct ChainLimits {178    pub collection_numbers_limit: u64,179    pub account_token_ownership_limit: u64,180    pub collections_admins_limit: u64,181    pub custom_data_limit: u32,182183    // Timeouts for item types in passed blocks184    pub nft_sponsor_transfer_timeout: u32,185    pub fungible_sponsor_transfer_timeout: u32,186    pub refungible_sponsor_transfer_timeout: u32,187}188189pub trait WeightInfo {190	fn create_collection() -> Weight;191	fn destroy_collection() -> Weight;192	fn add_to_white_list() -> Weight;193	fn remove_from_white_list() -> Weight;194    fn set_public_access_mode() -> Weight;195    fn set_mint_permission() -> Weight;196    fn change_collection_owner() -> Weight;197    fn add_collection_admin() -> Weight;198    fn remove_collection_admin() -> Weight;199    fn set_collection_sponsor() -> Weight;200    fn confirm_sponsorship() -> Weight;201    fn remove_collection_sponsor() -> Weight;202    fn create_item(s: usize, ) -> Weight;203    fn burn_item() -> Weight;204    fn transfer() -> Weight;205    fn approve() -> Weight;206    fn transfer_from() -> Weight;207    fn set_offchain_schema() -> Weight;208}209210pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {211    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;212213    /// Weight information for extrinsics in this pallet.214	type WeightInfo: WeightInfo;215}216217#[cfg(feature = "runtime-benchmarks")]218mod benchmarking;219220// #endregion221222decl_storage! {223    trait Store for Module<T: Trait> as Nft {224225        // Private members226        NextCollectionID: u64;227        CreatedCollectionCount: u64;228        ChainVersion: u64;229        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;230231        // Chain limits struct232        pub ChainLimit get(fn chain_limit) config(): ChainLimits;233234        // Bound counters235        CollectionCount: u64;236        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;237238        // Basic collections239        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;240        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;241        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;242243        /// Balance owner per collection map244        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;245246        /// second parameter: item id + owner account id247        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;248249        /// Item collections250        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;251        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;252        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;253254        /// Index list255        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;256257        /// Tokens transfer baskets258        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;259        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>>;260        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;261262        // Sponsorship263        pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;264        pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;265    }266    add_extra_genesis {267        build(|config: &GenesisConfig<T>| {268            // Modification of storage269            for (_num, _c) in &config.collection {270                <Module<T>>::init_collection(_c);271            }272273            for (_num, _q, _i) in &config.nft_item_id {274                <Module<T>>::init_nft_token(_i);275            }276277            for (_num, _q, _i) in &config.fungible_item_id {278                <Module<T>>::init_fungible_token(_i);279            }280281            for (_num, _q, _i) in &config.refungible_item_id {282                <Module<T>>::init_refungible_token(_i);283            }284        })285    }286}287288decl_event!(289    pub enum Event<T>290    where291        AccountId = <T as system::Trait>::AccountId,292    {293        /// New collection was created294        /// 295        /// # Arguments296        /// 297        /// * collection_id: Globally unique identifier of newly created collection.298        /// 299        /// * mode: [CollectionMode] converted into u8.300        /// 301        /// * account_id: Collection owner.302        Created(u64, u8, AccountId),303304        /// New item was created.305        /// 306        /// # Arguments307        /// 308        /// * collection_id: Id of the collection where item was created.309        /// 310        /// * item_id: Id of an item. Unique within the collection.311        ItemCreated(u64, u64),312313        /// Collection item was burned.314        /// 315        /// # Arguments316        /// 317        /// collection_id.318        /// 319        /// item_id: Identifier of burned NFT.320        ItemDestroyed(u64, u64),321    }322);323324decl_module! {325    pub struct Module<T: Trait> for enum Call where origin: T::Origin {326327        fn deposit_event() = default;328329        fn on_initialize(now: T::BlockNumber) -> Weight {330331            if ChainVersion::get() < 2332            {333                let value = NextCollectionID::get();334                CreatedCollectionCount::put(value);335                ChainVersion::put(2);336            }337338            0339        }340341        /// 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.342        /// 343        /// # Permissions344        /// 345        /// * Anyone.346        /// 347        /// # Arguments348        /// 349        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.350        /// 351        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.352        /// 353        /// * token_prefix: UTF-8 string with token prefix.354        /// 355        /// * mode: [CollectionMode] collection type and type dependent data.356        // returns collection ID357        #[weight = T::WeightInfo::create_collection()]358        pub fn create_collection(origin,359                                 collection_name: Vec<u16>,360                                 collection_description: Vec<u16>,361                                 token_prefix: Vec<u8>,362                                 mode: CollectionMode) -> DispatchResult {363364            // Anyone can create a collection365            let who = ensure_signed(origin)?;366            let custom_data_size = match mode {367                CollectionMode::NFT(size) => {368369                    // bound Custom data size370                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");371                    size372                },373                CollectionMode::ReFungible(size, _) => {374375                    // bound Custom data size376                    ensure!(size < ChainLimit::get().custom_data_limit, "Custom data size bound exceeded");377                    size378                },379                _ => 0380            };381382            let decimal_points = match mode {383                CollectionMode::Fungible(points) => points,384                CollectionMode::ReFungible(_, points) => points,385                _ => 0386            };387388            // bound Total number of collections389            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");390391            // check params392            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");393394            let mut name = collection_name.to_vec();395            name.push(0);396            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");397398            let mut description = collection_description.to_vec();399            description.push(0);400            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");401402            let mut prefix = token_prefix.to_vec();403            prefix.push(0);404            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");405406            // Generate next collection ID407            let next_id = CreatedCollectionCount::get()408                .checked_add(1)409                .expect("collection id error");410411            // bound counter412            let total = CollectionCount::get()413                .checked_add(1)414                .expect("collection counter error");415416            CreatedCollectionCount::put(next_id);417            CollectionCount::put(total);418419            // Create new collection420            let new_collection = CollectionType {421                owner: who.clone(),422                name: name,423                mode: mode.clone(),424                mint_mode: false,425                access: AccessMode::Normal,426                description: description,427                decimal_points: decimal_points,428                token_prefix: prefix,429                offchain_schema: Vec::new(),430                custom_data_size: custom_data_size,431                sponsor: T::AccountId::default(),432                unconfirmed_sponsor: T::AccountId::default(),433            };434435            // Add new collection to map436            <Collection<T>>::insert(next_id, new_collection);437438            // call event439            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));440441            Ok(())442        }443444        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.445        /// 446        /// # Permissions447        /// 448        /// * Collection Owner.449        /// 450        /// # Arguments451        /// 452        /// * collection_id: collection to destroy.453        #[weight = T::WeightInfo::destroy_collection()]454        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {455456            let sender = ensure_signed(origin)?;457            Self::check_owner_permissions(collection_id, sender)?;458459            <AddressTokens<T>>::remove_prefix(collection_id);460            <ApprovedList<T>>::remove_prefix(collection_id);461            <Balance<T>>::remove_prefix(collection_id);462            <ItemListIndex>::remove(collection_id);463            <AdminList<T>>::remove(collection_id);464            <Collection<T>>::remove(collection_id);465            <WhiteList<T>>::remove(collection_id);466467            <NftItemList<T>>::remove_prefix(collection_id);468            <FungibleItemList<T>>::remove_prefix(collection_id);469            <ReFungibleItemList<T>>::remove_prefix(collection_id);470471            <NftTransferBasket<T>>::remove_prefix(collection_id);472            <FungibleTransferBasket<T>>::remove_prefix(collection_id);473            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);474475            if CollectionCount::get() > 0476            {477                // bound couter478                let total = CollectionCount::get()479                    .checked_sub(1)480                    .expect("collection counter error");481482                CollectionCount::put(total);483            }484485            Ok(())486        }487488        /// Add an address to white list.489        /// 490        /// # Permissions491        /// 492        /// * Collection Owner493        /// * Collection Admin494        /// 495        /// # Arguments496        /// 497        /// * collection_id.498        /// 499        /// * address.500        #[weight = T::WeightInfo::add_to_white_list()]501        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{502503            let sender = ensure_signed(origin)?;504            Self::check_owner_or_admin_permissions(collection_id, sender)?;505506            let mut white_list_collection: Vec<T::AccountId>;507            if <WhiteList<T>>::contains_key(collection_id) {508                white_list_collection = <WhiteList<T>>::get(collection_id);509                if !white_list_collection.contains(&address.clone())510                {511                    white_list_collection.push(address.clone());512                }513            }514            else {515                white_list_collection = Vec::new();516                white_list_collection.push(address.clone());517            }518519            <WhiteList<T>>::insert(collection_id, white_list_collection);520            Ok(())521        }522523        /// Remove an address from white list.524        /// 525        /// # Permissions526        /// 527        /// * Collection Owner528        /// * Collection Admin529        /// 530        /// # Arguments531        /// 532        /// * collection_id.533        /// 534        /// * address.535        #[weight = T::WeightInfo::remove_from_white_list()]536        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{537538            let sender = ensure_signed(origin)?;539            Self::check_owner_or_admin_permissions(collection_id, sender)?;540541            if <WhiteList<T>>::contains_key(collection_id) {542                let mut white_list_collection = <WhiteList<T>>::get(collection_id);543                if white_list_collection.contains(&address.clone())544                {545                    white_list_collection.retain(|i| *i != address.clone());546                    <WhiteList<T>>::insert(collection_id, white_list_collection);547                }548            }549550            Ok(())551        }552553        /// Toggle between normal and white list access for the methods with access for `Anyone`.554        /// 555        /// # Permissions556        /// 557        /// * Collection Owner.558        /// 559        /// # Arguments560        /// 561        /// * collection_id.562        /// 563        /// * mode: [AccessMode]564        #[weight = T::WeightInfo::set_public_access_mode()]565        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult566        {567            let sender = ensure_signed(origin)?;568569            Self::check_owner_permissions(collection_id, sender)?;570            let mut target_collection = <Collection<T>>::get(collection_id);571            target_collection.access = mode;572            <Collection<T>>::insert(collection_id, target_collection);573574            Ok(())575        }576577        /// Allows Anyone to create tokens if:578        /// * White List is enabled, and579        /// * Address is added to white list, and580        /// * This method was called with True parameter581        /// 582        /// # Permissions583        /// * Collection Owner584        ///585        /// # Arguments586        /// 587        /// * collection_id.588        /// 589        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.590        #[weight = T::WeightInfo::set_mint_permission()]591        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult592        {593            let sender = ensure_signed(origin)?;594595            Self::check_owner_permissions(collection_id, sender)?;596            let mut target_collection = <Collection<T>>::get(collection_id);597            target_collection.mint_mode = mint_permission;598            <Collection<T>>::insert(collection_id, target_collection);599600            Ok(())601        }602603        /// Change the owner of the collection.604        /// 605        /// # Permissions606        /// 607        /// * Collection Owner.608        /// 609        /// # Arguments610        /// 611        /// * collection_id.612        /// 613        /// * new_owner.614        #[weight = T::WeightInfo::change_collection_owner()]615        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {616617            let sender = ensure_signed(origin)?;618            Self::check_owner_permissions(collection_id, sender)?;619            let mut target_collection = <Collection<T>>::get(collection_id);620            target_collection.owner = new_owner;621            <Collection<T>>::insert(collection_id, target_collection);622623            Ok(())624        }625626        /// Adds an admin of the Collection.627        /// 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. 628        /// 629        /// # Permissions630        /// 631        /// * Collection Owner.632        /// * Collection Admin.633        /// 634        /// # Arguments635        /// 636        /// * collection_id: ID of the Collection to add admin for.637        /// 638        /// * new_admin_id: Address of new admin to add.639        #[weight = T::WeightInfo::add_collection_admin()]640        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {641642            let sender = ensure_signed(origin)?;643            Self::check_owner_or_admin_permissions(collection_id, sender)?;644            let mut admin_arr: Vec<T::AccountId> = Vec::new();645646            if <AdminList<T>>::contains_key(collection_id)647            {648                admin_arr = <AdminList<T>>::get(collection_id);649                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");650            }651652            // Number of collection admins653            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");654655            admin_arr.push(new_admin_id);656            <AdminList<T>>::insert(collection_id, admin_arr);657658            Ok(())659        }660661        /// 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.662        ///663        /// # Permissions664        /// 665        /// * Collection Owner.666        /// * Collection Admin.667        /// 668        /// # Arguments669        /// 670        /// * collection_id: ID of the Collection to remove admin for.671        /// 672        /// * account_id: Address of admin to remove.673        #[weight = T::WeightInfo::remove_collection_admin()]674        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {675676            let sender = ensure_signed(origin)?;677            Self::check_owner_or_admin_permissions(collection_id, sender)?;678679            if <AdminList<T>>::contains_key(collection_id)680            {681                let mut admin_arr = <AdminList<T>>::get(collection_id);682                admin_arr.retain(|i| *i != account_id);683                <AdminList<T>>::insert(collection_id, admin_arr);684            }685686            Ok(())687        }688689        /// # Permissions690        /// 691        /// * Collection Owner692        /// 693        /// # Arguments694        /// 695        /// * collection_id.696        /// 697        /// * new_sponsor.698        #[weight = T::WeightInfo::set_collection_sponsor()]699        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {700701            let sender = ensure_signed(origin)?;702            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");703704            let mut target_collection = <Collection<T>>::get(collection_id);705            ensure!(sender == target_collection.owner, "You do not own this collection");706707            target_collection.unconfirmed_sponsor = new_sponsor;708            <Collection<T>>::insert(collection_id, target_collection);709710            Ok(())711        }712713        /// # Permissions714        /// 715        /// * Sponsor.716        /// 717        /// # Arguments718        /// 719        /// * collection_id.720        #[weight = T::WeightInfo::confirm_sponsorship()]721        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {722723            let sender = ensure_signed(origin)?;724            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");725726            let mut target_collection = <Collection<T>>::get(collection_id);727            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");728729            target_collection.sponsor = target_collection.unconfirmed_sponsor;730            target_collection.unconfirmed_sponsor = T::AccountId::default();731            <Collection<T>>::insert(collection_id, target_collection);732733            Ok(())734        }735736        /// Switch back to pay-per-own-transaction model.737        ///738        /// # Permissions739        ///740        /// * Collection owner.741        /// 742        /// # Arguments743        /// 744        /// * collection_id.745        #[weight = T::WeightInfo::remove_collection_sponsor()]746        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {747748            let sender = ensure_signed(origin)?;749            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");750751            let mut target_collection = <Collection<T>>::get(collection_id);752            ensure!(sender == target_collection.owner, "You do not own this collection");753754            target_collection.sponsor = T::AccountId::default();755            <Collection<T>>::insert(collection_id, target_collection);756757            Ok(())758        }759760        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.761        /// 762        /// # Permissions763        /// 764        /// * Collection Owner.765        /// * Collection Admin.766        /// * Anyone if767        ///     * White List is enabled, and768        ///     * Address is added to white list, and769        ///     * MintPermission is enabled (see SetMintPermission method)770        /// 771        /// # Arguments772        /// 773        /// * collection_id: ID of the collection.774        /// 775        /// * 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.776        /// 777        /// * owner: Address, initial owner of the NFT.778        // #[weight =779        // (130_000_000 as Weight)780        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))781        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))782        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]783784        #[weight = T::WeightInfo::create_item(properties.len())]785        pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {786787            let sender = ensure_signed(origin)?;788            Self::collection_exists(collection_id)?;789            let target_collection = <Collection<T>>::get(collection_id);790791            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {792                ensure!(target_collection.mint_mode == true, "Public minting is not allowed for this collection");793                Self::check_white_list(collection_id, &owner)?;794                Self::check_white_list(collection_id, &sender)?;795            }796797            match target_collection.mode798            {799                CollectionMode::NFT(_) => {800801                    // check size802                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");803804                    // Create nft item805                    let item = NftItemType {806                        collection: collection_id,807                        owner: owner,808                        data: properties.clone(),809                    };810811                    Self::add_nft_item(item)?;812813                },814                CollectionMode::Fungible(_) => {815816                    // check size817                    ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");818819                    let item = FungibleItemType {820                        collection: collection_id,821                        owner: owner,822                        value: (10 as u128).pow(target_collection.decimal_points)823                    };824825                    Self::add_fungible_item(item)?;826                },827                CollectionMode::ReFungible(_, _) => {828829                    // check size830                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");831832                    let mut owner_list = Vec::new();833                    let value = (10 as u128).pow(target_collection.decimal_points);834                    owner_list.push(Ownership {owner: owner.clone(), fraction: value});835836                    let item = ReFungibleItemType {837                        collection: collection_id,838                        owner: owner_list,839                        data: properties.clone()840                    };841842                    Self::add_refungible_item(item)?;843                },844                _ => { ensure!(1 == 0,"just error"); }845846            };847848            // call event849            Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));850851            Ok(())852        }853854        /// Destroys a concrete instance of NFT.855        /// 856        /// # Permissions857        /// 858        /// * Collection Owner.859        /// * Collection Admin.860        /// * Current NFT Owner.861        /// 862        /// # Arguments863        /// 864        /// * collection_id: ID of the collection.865        /// 866        /// * item_id: ID of NFT to burn.867        #[weight = T::WeightInfo::burn_item()]868        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {869870            let sender = ensure_signed(origin)?;871            Self::collection_exists(collection_id)?;872873            // Transfer permissions check874            let target_collection = <Collection<T>>::get(collection_id);875            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||876                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),877                "Only item owner, collection owner and admins can modify item");878879            if target_collection.access == AccessMode::WhiteList {880                Self::check_white_list(collection_id, &sender)?;881            }882883            match target_collection.mode884            {885                CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,886                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,887                CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,888                _ => ()889            };890891            // call event892            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));893894            Ok(())895        }896897        /// Change ownership of the token.898        /// 899        /// # Permissions900        /// 901        /// * Collection Owner902        /// * Collection Admin903        /// * Current NFT owner904        ///905        /// # Arguments906        /// 907        /// * recipient: Address of token recipient.908        /// 909        /// * collection_id.910        /// 911        /// * item_id: ID of the item912        ///     * Non-Fungible Mode: Required.913        ///     * Fungible Mode: Ignored.914        ///     * Re-Fungible Mode: Required.915        /// 916        /// * value: Amount to transfer.917        ///     * Non-Fungible Mode: Ignored918        ///     * Fungible Mode: Must specify transferred amount919        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)920        #[weight = T::WeightInfo::transfer()]921        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {922923            let sender = ensure_signed(origin)?;924925            // Transfer permissions check926            let target_collection = <Collection<T>>::get(collection_id);927            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||928                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),929                "Only item owner, collection owner and admins can modify item");930931            if target_collection.access == AccessMode::WhiteList {932                Self::check_white_list(collection_id, &sender)?;933                Self::check_white_list(collection_id, &recipient)?;934            }935936            match target_collection.mode937            {938                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,939                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,940                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,941                _ => ()942            };943944            Ok(())945        }946947        /// Set, change, or remove approved address to transfer the ownership of the NFT.948        /// 949        /// # Permissions950        /// 951        /// * Collection Owner952        /// * Collection Admin953        /// * Current NFT owner954        /// 955        /// # Arguments956        /// 957        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).958        /// 959        /// * collection_id.960        /// 961        /// * item_id: ID of the item.962        #[weight = T::WeightInfo::approve()]963        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {964965            let sender = ensure_signed(origin)?;966967            // Transfer permissions check968            let target_collection = <Collection<T>>::get(collection_id);969            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||970                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),971                "Only item owner, collection owner and admins can approve");972973            if target_collection.access == AccessMode::WhiteList {974                Self::check_white_list(collection_id, &sender)?;975                Self::check_white_list(collection_id, &approved)?;976            }977978            // amount param stub979            let amount = 100000000;980981            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));982            if list_exists {983984                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));985                let item_contains = list.iter().any(|i| i.approved == approved);986987                if !item_contains {988                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });989                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);990                }991            } else {992993                let mut list = Vec::new();994                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });995                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);996            }997998            Ok(())999        }1000        1001        /// 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.1002        /// 1003        /// # Permissions1004        /// * Collection Owner1005        /// * Collection Admin1006        /// * Current NFT owner1007        /// * Address approved by current NFT owner1008        /// 1009        /// # Arguments1010        /// 1011        /// * from: Address that owns token.1012        /// 1013        /// * recipient: Address of token recipient.1014        /// 1015        /// * collection_id.1016        /// 1017        /// * item_id: ID of the item.1018        /// 1019        /// * value: Amount to transfer.1020        #[weight = T::WeightInfo::transfer_from()]1021        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10221023            let sender = ensure_signed(origin)?;1024            let mut appoved_transfer = false;10251026            // Check approve1027            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1028                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1029                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1030                if opt_item.is_some()1031                {1032                    appoved_transfer = true;1033                    ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1034                }1035            }10361037            // Transfer permissions check1038            let target_collection = <Collection<T>>::get(collection_id);1039            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1040                "Only item owner, collection owner and admins can modify items");10411042            if target_collection.access == AccessMode::WhiteList {1043                Self::check_white_list(collection_id, &sender)?;1044                Self::check_white_list(collection_id, &recipient)?;1045            }10461047            // remove approve1048            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1049                .into_iter().filter(|i| i.approved != sender.clone()).collect();1050            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);105110521053            match target_collection.mode1054            {1055                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,1056                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1057                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1058                _ => ()1059            };10601061            Ok(())1062        }10631064        ///1065        #[weight = 0]1066        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10671068            // let no_perm_mes = "You do not have permissions to modify this collection";1069            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1070            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1071            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);10721073            // // on_nft_received  call10741075            // Self::transfer(origin, collection_id, item_id, new_owner)?;10761077            Ok(())1078        }10791080        /// Set off-chain data schema.1081        /// 1082        /// # Permissions1083        /// 1084        /// * Collection Owner1085        /// * Collection Admin1086        /// 1087        /// # Arguments1088        /// 1089        /// * collection_id.1090        /// 1091        /// * schema: String representing the offchain data schema.1092        #[weight = T::WeightInfo::set_offchain_schema()]1093        pub fn set_offchain_schema(1094            origin,1095            collection_id: u64,1096            schema: Vec<u8>1097        ) -> DispatchResult {1098            let sender = ensure_signed(origin)?;1099            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11001101            let mut target_collection = <Collection<T>>::get(collection_id);1102            target_collection.offchain_schema = schema;1103            <Collection<T>>::insert(collection_id, target_collection);11041105            Ok(())1106        }11071108        // Sudo permissions function1109        #[weight = 0]1110        pub fn set_chain_limits(1111            origin,1112            limits: ChainLimits1113        ) -> DispatchResult {1114            ensure_root(origin)?;1115            <ChainLimit>::put(limits);1116            Ok(())1117        }        1118    }1119}11201121impl<T: Trait> Module<T> {1122    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1123        let current_index = <ItemListIndex>::get(item.collection)1124            .checked_add(1)1125            .expect("Item list index id error");1126        let itemcopy = item.clone();1127        let owner = item.owner.clone();1128        let value = item.value as u64;11291130        Self::add_token_index(item.collection, current_index, owner.clone())?;11311132        <ItemListIndex>::insert(item.collection, current_index);1133        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11341135        // Add current block1136        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1137        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1138        1139        // Update balance1140        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1141            .checked_add(value)1142            .unwrap();1143        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11441145        Ok(())1146    }11471148    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1149        let current_index = <ItemListIndex>::get(item.collection)1150            .checked_add(1)1151            .expect("Item list index id error");1152        let itemcopy = item.clone();11531154        let value = item.owner.first().unwrap().fraction as u64;1155        let owner = item.owner.first().unwrap().owner.clone();11561157        Self::add_token_index(item.collection, current_index, owner.clone())?;11581159        <ItemListIndex>::insert(item.collection, current_index);1160        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);11611162        // Add current block1163        let block_number: T::BlockNumber = 0.into();1164        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);11651166        // Update balance1167        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1168            .checked_add(value)1169            .unwrap();1170        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);11711172        Ok(())1173    }11741175    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1176        let current_index = <ItemListIndex>::get(item.collection)1177            .checked_add(1)1178            .expect("Item list index id error");11791180        let item_owner = item.owner.clone();1181        let collection_id = item.collection.clone();1182        Self::add_token_index(collection_id, current_index, item.owner.clone())?;11831184        <ItemListIndex>::insert(collection_id, current_index);1185        <NftItemList<T>>::insert(collection_id, current_index, item);11861187        // Add current block1188        let block_number: T::BlockNumber = 0.into();1189        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);11901191        // Update balance1192        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1193            .checked_add(1)1194            .unwrap();1195        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);11961197        Ok(())1198    }11991200    fn burn_refungible_item(1201        collection_id: u64,1202        item_id: u64,1203        owner: T::AccountId,1204    ) -> DispatchResult {1205        ensure!(1206            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1207            "Item does not exists"1208        );1209        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1210        let item = collection1211            .owner1212            .iter()1213            .filter(|&i| i.owner == owner)1214            .next()1215            .unwrap();1216        Self::remove_token_index(collection_id, item_id, owner.clone())?;12171218        // remove approve list1219        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));12201221        // update balance1222        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1223            .checked_sub(item.fraction as u64)1224            .unwrap();1225        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12261227        <ReFungibleItemList<T>>::remove(collection_id, item_id);12281229        Ok(())1230    }12311232    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1233        ensure!(1234            <NftItemList<T>>::contains_key(collection_id, item_id),1235            "Item does not exists"1236        );1237        let item = <NftItemList<T>>::get(collection_id, item_id);1238        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12391240        // remove approve list1241        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12421243        // update balance1244        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1245            .checked_sub(1)1246            .unwrap();1247        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1248        <NftItemList<T>>::remove(collection_id, item_id);12491250        Ok(())1251    }12521253    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1254        ensure!(1255            <FungibleItemList<T>>::contains_key(collection_id, item_id),1256            "Item does not exists"1257        );1258        let item = <FungibleItemList<T>>::get(collection_id, item_id);1259        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;12601261        // remove approve list1262        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));12631264        // update balance1265        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1266            .checked_sub(item.value as u64)1267            .unwrap();1268        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);12691270        <FungibleItemList<T>>::remove(collection_id, item_id);12711272        Ok(())1273    }12741275    fn collection_exists(collection_id: u64) -> DispatchResult {1276        ensure!(1277            <Collection<T>>::contains_key(collection_id),1278            "This collection does not exist"1279        );1280        Ok(())1281    }12821283    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1284        Self::collection_exists(collection_id)?;12851286        let target_collection = <Collection<T>>::get(collection_id);1287        ensure!(1288            subject == target_collection.owner,1289            "You do not own this collection"1290        );12911292        Ok(())1293    }12941295    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1296        let target_collection = <Collection<T>>::get(collection_id);1297        let mut result: bool = subject == target_collection.owner;1298        let exists = <AdminList<T>>::contains_key(collection_id);12991300        if !result & exists {1301            if <AdminList<T>>::get(collection_id).contains(&subject) {1302                result = true1303            }1304        }13051306        result1307    }13081309    fn check_owner_or_admin_permissions(1310        collection_id: u64,1311        subject: T::AccountId,1312    ) -> DispatchResult {1313        Self::collection_exists(collection_id)?;1314        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());13151316        ensure!(1317            result,1318            "You do not have permissions to modify this collection"1319        );1320        Ok(())1321    }13221323    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1324        let target_collection = <Collection<T>>::get(collection_id);13251326        match target_collection.mode {1327            CollectionMode::NFT(_) => {1328                <NftItemList<T>>::get(collection_id, item_id).owner == subject1329            }1330            CollectionMode::Fungible(_) => {1331                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1332            }1333            CollectionMode::ReFungible(_, _) => {1334                <ReFungibleItemList<T>>::get(collection_id, item_id)1335                    .owner1336                    .iter()1337                    .any(|i| i.owner == subject)1338            }1339            CollectionMode::Invalid => false,1340        }1341    }13421343    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1344        let mes = "Address is not in white list";1345        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1346        let wl = <WhiteList<T>>::get(collection_id);1347        ensure!(wl.contains(address), mes);13481349        Ok(())1350    }13511352    fn transfer_fungible(1353        collection_id: u64,1354        item_id: u64,1355        value: u64,1356        owner: T::AccountId,1357        new_owner: T::AccountId,1358    ) -> DispatchResult {1359        ensure!(1360            <FungibleItemList<T>>::contains_key(collection_id, item_id),1361            "Item not exists"1362        );13631364        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1365        let amount = full_item.value;13661367        ensure!(amount >= value.into(), "Item balance not enouth");13681369        // update balance1370        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1371            .checked_sub(value)1372            .unwrap();1373        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);13741375        let mut new_owner_account_id = 0;1376        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1377        if new_owner_items.len() > 0 {1378            new_owner_account_id = new_owner_items[0];1379        }13801381        let val64 = value.into();13821383        // transfer1384        if amount == val64 && new_owner_account_id == 0 {1385            // change owner1386            // new owner do not have account1387            let mut new_full_item = full_item.clone();1388            new_full_item.owner = new_owner.clone();1389            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);13901391            // update balance1392            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1393                .checked_add(value)1394                .unwrap();1395            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);13961397            // update index collection1398            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1399        } else {1400            let mut new_full_item = full_item.clone();1401            new_full_item.value -= val64;14021403            // separate amount1404            if new_owner_account_id > 0 {1405                // new owner has account1406                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1407                item.value += val64;14081409                // update balance1410                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1411                    .checked_add(value)1412                    .unwrap();1413                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14141415                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1416            } else {1417                // new owner do not have account1418                let item = FungibleItemType {1419                    collection: collection_id,1420                    owner: new_owner.clone(),1421                    value: val64,1422                };14231424                Self::add_fungible_item(item)?;1425            }14261427            if amount == val64 {1428                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;14291430                // remove approve list1431                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1432                <FungibleItemList<T>>::remove(collection_id, item_id);1433            }14341435            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1436        }14371438        Ok(())1439    }14401441    fn transfer_refungible(1442        collection_id: u64,1443        item_id: u64,1444        value: u64,1445        owner: T::AccountId,1446        new_owner: T::AccountId,1447    ) -> DispatchResult {1448        ensure!(1449            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1450            "Item not exists"1451        );14521453        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1454        let item = full_item1455            .owner1456            .iter()1457            .filter(|i| i.owner == owner)1458            .next()1459            .unwrap();1460        let amount = item.fraction;14611462        ensure!(amount >= value.into(), "Item balance not enouth");14631464        // update balance1465        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1466            .checked_sub(value)1467            .unwrap();1468        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);14691470        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1471            .checked_add(value)1472            .unwrap();1473        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);14741475        let old_owner = item.owner.clone();1476        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1477        let val64 = value.into();14781479        // transfer1480        if amount == val64 && !new_owner_has_account {1481            // change owner1482            // new owner do not have account1483            let mut new_full_item = full_item.clone();1484            new_full_item1485                .owner1486                .iter_mut()1487                .find(|i| i.owner == owner)1488                .unwrap()1489                .owner = new_owner.clone();1490            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);14911492            // update index collection1493            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1494        } else {1495            let mut new_full_item = full_item.clone();1496            new_full_item1497                .owner1498                .iter_mut()1499                .find(|i| i.owner == owner)1500                .unwrap()1501                .fraction -= val64;15021503            // separate amount1504            if new_owner_has_account {1505                // new owner has account1506                new_full_item1507                    .owner1508                    .iter_mut()1509                    .find(|i| i.owner == new_owner)1510                    .unwrap()1511                    .fraction += val64;1512            } else {1513                // new owner do not have account1514                new_full_item.owner.push(Ownership {1515                    owner: new_owner.clone(),1516                    fraction: val64,1517                });1518                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1519            }15201521            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1522        }15231524        Ok(())1525    }15261527    fn transfer_nft(1528        collection_id: u64,1529        item_id: u64,1530        sender: T::AccountId,1531        new_owner: T::AccountId,1532    ) -> DispatchResult {1533        ensure!(1534            <NftItemList<T>>::contains_key(collection_id, item_id),1535            "Item not exists"1536        );15371538        let mut item = <NftItemList<T>>::get(collection_id, item_id);15391540        ensure!(1541            sender == item.owner,1542            "sender parameter and item owner must be equal"1543        );15441545        // update balance1546        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1547            .checked_sub(1)1548            .unwrap();1549        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);15501551        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1552            .checked_add(1)1553            .unwrap();1554        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);15551556        // change owner1557        let old_owner = item.owner.clone();1558        item.owner = new_owner.clone();1559        <NftItemList<T>>::insert(collection_id, item_id, item);15601561        // update index collection1562        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;15631564        // reset approved list1565        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1566        Ok(())1567    }15681569    fn init_collection(item: &CollectionType<T::AccountId>) {1570        // check params1571        assert!(1572            item.decimal_points <= 4,1573            "decimal_points parameter must be lower than 4"1574        );1575        assert!(1576            item.name.len() <= 64,1577            "Collection name can not be longer than 63 char"1578        );1579        assert!(1580            item.name.len() <= 256,1581            "Collection description can not be longer than 255 char"1582        );1583        assert!(1584            item.token_prefix.len() <= 16,1585            "Token prefix can not be longer than 15 char"1586        );15871588        // Generate next collection ID1589        let next_id = CreatedCollectionCount::get()1590            .checked_add(1)1591            .expect("collection id error");15921593        CreatedCollectionCount::put(next_id);1594    }15951596    fn init_nft_token(item: &NftItemType<T::AccountId>) {1597        let current_index = <ItemListIndex>::get(item.collection)1598            .checked_add(1)1599            .expect("Item list index id error");16001601        let item_owner = item.owner.clone();1602        let collection_id = item.collection.clone();1603        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();16041605        <ItemListIndex>::insert(collection_id, current_index);16061607        // Update balance1608        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1609            .checked_add(1)1610            .unwrap();1611        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1612    }16131614    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1615        let current_index = <ItemListIndex>::get(item.collection)1616            .checked_add(1)1617            .expect("Item list index id error");1618        let owner = item.owner.clone();1619        let value = item.value as u64;16201621        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16221623        <ItemListIndex>::insert(item.collection, current_index);16241625        // Update balance1626        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1627            .checked_add(value)1628            .unwrap();1629        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1630    }16311632    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1633        let current_index = <ItemListIndex>::get(item.collection)1634            .checked_add(1)1635            .expect("Item list index id error");16361637        let value = item.owner.first().unwrap().fraction as u64;1638        let owner = item.owner.first().unwrap().owner.clone();16391640        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();16411642        <ItemListIndex>::insert(item.collection, current_index);16431644        // Update balance1645        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1646            .checked_add(value)1647            .unwrap();1648        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1649    }16501651    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {16521653        // add to account limit1654        if <AccountItemCount<T>>::contains_key(owner.clone()) {16551656            // bound Owned tokens by a single address1657            let count = <AccountItemCount<T>>::get(owner.clone());1658            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");16591660            <AccountItemCount<T>>::insert(owner.clone(), 1661                count.checked_add(1).unwrap());1662        }1663        else {1664            <AccountItemCount<T>>::insert(owner.clone(), 1);1665        }16661667        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1668        if list_exists {1669            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1670            let item_contains = list.contains(&item_index.clone());16711672            if !item_contains {1673                list.push(item_index.clone());1674            }16751676            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1677        } else {1678            let mut itm = Vec::new();1679            itm.push(item_index.clone());1680            <AddressTokens<T>>::insert(collection_id, owner, itm);1681            1682        }16831684        Ok(())1685    }16861687    fn remove_token_index(1688        collection_id: u64,1689        item_index: u64,1690        owner: T::AccountId,1691    ) -> DispatchResult {16921693        // update counter1694        <AccountItemCount<T>>::insert(owner.clone(), 1695            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());169616971698        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1699        if list_exists {1700            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1701            let item_contains = list.contains(&item_index.clone());17021703            if item_contains {1704                list.retain(|&item| item != item_index);1705                <AddressTokens<T>>::insert(collection_id, owner, list);1706            }1707        }17081709        Ok(())1710    }17111712    fn move_token_index(1713        collection_id: u64,1714        item_index: u64,1715        old_owner: T::AccountId,1716        new_owner: T::AccountId,1717    ) -> DispatchResult {1718        Self::remove_token_index(collection_id, item_index, old_owner)?;1719        Self::add_token_index(collection_id, item_index, new_owner)?;17201721        Ok(())1722    }1723}17241725////////////////////////////////////////////////////////////////////////////////////////////////////1726// Economic models1727// #region17281729/// Fee multiplier.1730pub type Multiplier = FixedU128;17311732type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1733    <T as system::Trait>::AccountId,1734>>::Balance;1735type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1736    <T as system::Trait>::AccountId,1737>>::NegativeImbalance;17381739/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1740/// in the queue.1741#[derive(Encode, Decode, Clone, Eq, PartialEq)]1742pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(1743    #[codec(compact)] BalanceOf<T>1744);17451746impl<T: Trait + Send + Sync> sp_std::fmt::Debug1747    for ChargeTransactionPayment<T>1748{1749    #[cfg(feature = "std")]1750    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1751        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1752    }1753    #[cfg(not(feature = "std"))]1754    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1755        Ok(())1756    }1757}17581759impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>1760where1761    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1762    BalanceOf<T>: Send + Sync + FixedPointOperand,1763{1764    /// utility constructor. Used only in client/factory code.1765    pub fn from(fee: BalanceOf<T>) -> Self {1766        Self(fee)1767    }17681769    pub fn traditional_fee(1770        len: usize,1771        info: &DispatchInfoOf<T::Call>,1772        tip: BalanceOf<T>,1773    ) -> BalanceOf<T>1774    where1775        T::Call: Dispatchable<Info = DispatchInfo>,1776    {1777        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1778    }17791780    fn withdraw_fee(1781        &self,1782        who: &T::AccountId,1783        call: &T::Call,1784        info: &DispatchInfoOf<T::Call>,1785        len: usize,1786    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1787        let tip = self.0;17881789        // Set fee based on call type. Creating collection costs 1 Unique.1790        // All other transactions have traditional fees so far1791        // let fee = match call.is_sub_type() {1792        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1793        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1794        //                                                 // _ => <BalanceOf<T>>::from(100)1795        // };1796        let fee = Self::traditional_fee(len, info, tip);17971798        // Determine who is paying transaction fee based on ecnomic model1799        // Parse call to extract collection ID and access collection sponsor1800        let sponsor: T::AccountId = match call.is_sub_type() {1801            Some(Call::create_item(collection_id, _properties, _owner)) => {1802                <Collection<T>>::get(collection_id).sponsor1803            }1804            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1805                let _collection_mode = <Collection<T>>::get(collection_id).mode;18061807                // sponsor timeout1808                let sponsor_transfer = match _collection_mode {1809                    CollectionMode::NFT(_) => {1810                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);1811                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1812                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1813                        if block_number >= limit_time {1814                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);1815                            true1816                        }1817                        else {1818                            false1819                        }1820                    }1821                    CollectionMode::Fungible(_) => {1822                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);1823                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1824                        if basket.iter().any(|i| i.address == _new_owner.clone())1825                        {1826                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();1827                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();1828                            if block_number >= limit_time {1829                                basket.retain(|x| x.address == item.address);1830                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });1831                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);1832                                true1833                            }1834                            else {1835                                false1836                            }1837                        }1838                        else {1839                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});1840                            true1841                        }1842                    }1843                    CollectionMode::ReFungible(_, _) => {1844                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);1845                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;1846                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();1847                        if block_number >= limit_time {1848                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);1849                            true1850                        } else {1851                            false1852                        }1853                    }1854                    _ => {1855                        false1856                    },1857                };18581859                if !sponsor_transfer {1860                    T::AccountId::default()1861                } else {1862                    <Collection<T>>::get(collection_id).sponsor1863                }1864            }18651866            // Some(pallet_contracts::Call::call(_dest, _value, _gas_limit, _data)) => {1867            // Some(pallet_contracts::Call::call(..)) => {1868            //     T::AccountId::default()1869            // }18701871            _ => T::AccountId::default(),1872        };18731874        let mut who_pays_fee: T::AccountId = sponsor.clone();1875        if sponsor == T::AccountId::default() {1876            who_pays_fee = who.clone();1877        }18781879        // Only mess with balances if fee is not zero.1880        if fee.is_zero() {1881            return Ok((fee, None));1882        }18831884        match <T as transaction_payment::Trait>::Currency::withdraw(1885            &who_pays_fee,1886            fee,1887            if tip.is_zero() {1888                WithdrawReason::TransactionPayment.into()1889            } else {1890                WithdrawReason::TransactionPayment | WithdrawReason::Tip1891            },1892            ExistenceRequirement::KeepAlive,1893        ) {1894            Ok(imbalance) => Ok((fee, Some(imbalance))),1895            Err(_) => Err(InvalidTransaction::Payment.into()),1896        }1897    }1898}189919001901impl<T: Trait + Send + Sync> SignedExtension1902    for ChargeTransactionPayment<T>1903where1904    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1905    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>>,1906{1907    const IDENTIFIER: &'static str = "ChargeTransactionPayment";1908    type AccountId = T::AccountId;1909    type Call = T::Call;1910    type AdditionalSigned = ();1911    type Pre = ();1912    // type Pre = (1913    //     BalanceOf<T>,1914    //     Self::AccountId,1915    //     Option<NegativeImbalanceOf<T>>,1916    //     BalanceOf<T>,1917    // );1918    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1919        Ok(())1920    }19211922    fn validate(1923        &self,1924        who: &Self::AccountId,1925        call: &Self::Call,1926        info: &DispatchInfoOf<Self::Call>,1927        len: usize,1928    ) -> TransactionValidity {1929        let (fee, _) = self.withdraw_fee(who, call, info, len)?;19301931        print("====== validate");19321933        Ok(ValidTransaction::default())1934    }19351936    fn pre_dispatch(1937        self,1938        who: &Self::AccountId,1939        call: &Self::Call,1940        info: &DispatchInfoOf<Self::Call>,1941        len: usize,1942    ) -> Result<Self::Pre, TransactionValidityError> {19431944        print("========= PreDispatch");19451946        // let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;19471948        // debug::info!("Fee: {:?}", fee);19491950        // Ok((self.0, who.clone(), imbalance, fee))1951        Ok(())1952    }19531954    fn post_dispatch(1955        pre: Self::Pre,1956        info: &DispatchInfoOf<Self::Call>,1957        post_info: &PostDispatchInfoOf<Self::Call>,1958        len: usize,1959        _result: &DispatchResult,1960    ) -> Result<(), TransactionValidityError> {1961        // let (tip, who, imbalance, fee) = pre;1962        // if let Some(payed) = imbalance {1963        //     let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1964        //         len as u32, info, post_info, tip,1965        //     );1966        //     let refund = fee.saturating_sub(actual_fee);1967        //     let actual_payment =1968        //         match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1969        //             &who, refund,1970        //         ) {1971        //             Ok(refund_imbalance) => {1972        //                 // The refund cannot be larger than the up front payed max weight.1973        //                 // `PostDispatchInfo::calc_unspent` guards against such a case.1974        //                 match payed.offset(refund_imbalance) {1975        //                     Ok(actual_payment) => actual_payment,1976        //                     Err(_) => return Err(InvalidTransaction::Payment.into()),1977        //                 }1978        //             }1979        //             // We do not recreate the account using the refund. The up front payment1980        //             // is gone in that case.1981        //             Err(_) => payed,1982        //         };1983        //     let imbalances = actual_payment.split(tip);1984        //     <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1985        //         Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1986        //     );1987        // }1988        Ok(())1989    }1990}19911992/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////199319941995#[derive(Encode, Decode, Clone, Eq, PartialEq)]1996pub struct ChargeContractTransactionPayment<T: Trait + Send + Sync>(1997    #[codec(compact)] BalanceOf<T>1998);19992000impl<T: Trait + Send + Sync> sp_std::fmt::Debug2001    for ChargeContractTransactionPayment<T>2002{2003    #[cfg(feature = "std")]2004    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2005        write!(f, "ChargeContractTransactionPayment<{:?}>", self.0)2006    }2007    #[cfg(not(feature = "std"))]2008    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2009        Ok(())2010    }2011}20122013// impl<T: Trait + Send + Sync> ChargeContractTransactionPayment<T>2014// where2015//     // T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,2016//     T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<pallet_contracts::Call<T>>,2017//     BalanceOf<T>: Send + Sync + FixedPointOperand,2018// {2019//     // /// utility constructor. Used only in client/factory code.2020//     // pub fn from(fee: BalanceOf<T>) -> Self {2021//     //     Self(fee)2022//     // }20232024//     pub fn traditional_fee(2025//         len: usize,2026//         info: &DispatchInfoOf<T::Call>,2027//         tip: BalanceOf<T>,2028//     ) -> BalanceOf<T>2029//     where2030//         T::Call: Dispatchable<Info = DispatchInfo>,2031//     {2032//         <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2033//     }20342035//     fn withdraw_fee(2036//         &self,2037//         who: &T::AccountId,2038//         call: &T::Call,2039//         info: &DispatchInfoOf<T::Call>,2040//         len: usize,2041//     ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2042//         let tip = self.0;20432044//         let mut fee = Self::traditional_fee(len, info, tip);20452046//         // Determine who is paying transaction fee based on ecnomic model2047//         // Parse call to extract collection ID and access collection sponsor2048//         // let sponsor: T::AccountId = match call.is_sub_type() {2049//         //     // Some(pallet_contracts::Call::call(_dest, _value, _gas_limit, _data)) => {2050//         //     Some(pallet_contracts::Call::call(..)) => {2051//         //         // fee = <BalanceOf<T>>::from(0);2052//         //         T::AccountId::default()2053//         //     }2054//         //     _ => T::AccountId::default(),2055//         // };2056//         let sponsor = T::AccountId::default();20572058//         let mut who_pays_fee: T::AccountId = sponsor.clone();2059//         if sponsor == T::AccountId::default() {2060//             who_pays_fee = who.clone();2061//         }20622063//         // Only mess with balances if fee is not zero.2064//         if fee.is_zero() {2065//             return Ok((fee, None));2066//         }20672068//         match <T as transaction_payment::Trait>::Currency::withdraw(2069//             &who_pays_fee,2070//             fee,2071//             if tip.is_zero() {2072//                 WithdrawReason::TransactionPayment.into()2073//             } else {2074//                 WithdrawReason::TransactionPayment | WithdrawReason::Tip2075//             },2076//             ExistenceRequirement::KeepAlive,2077//         ) {2078//             Ok(imbalance) => Ok((fee, Some(imbalance))),2079//             Err(_) => Err(InvalidTransaction::Payment.into()),2080//         }2081//     }2082// }2083208420852086impl<T: Trait + Send + Sync> SignedExtension2087    for ChargeContractTransactionPayment<T>2088where2089    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2090    // T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,2091    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<pallet_contracts::Call<T>>,2092{2093    const IDENTIFIER: &'static str = "ChargeContractTransactionPayment";2094    type AccountId = T::AccountId;2095    type Call = T::Call;2096    type AdditionalSigned = ();2097    type Pre = ();20982099    // type Pre = (2100    //     BalanceOf<T>,2101    //     Self::AccountId,2102    //     Option<NegativeImbalanceOf<T>>,2103    //     BalanceOf<T>,2104    // );2105    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2106        Ok(())2107    }21082109    fn validate(2110        &self,2111        who: &Self::AccountId,2112        call: &Self::Call,2113        info: &DispatchInfoOf<Self::Call>,2114        len: usize,2115    ) -> TransactionValidity {2116        // let (fee, _) = self.withdraw_fee(who, call, info, len)?;21172118        print("====== Contracts validate");21192120        Ok(ValidTransaction::default())2121    }21222123    fn pre_dispatch(2124        self,2125        who: &Self::AccountId,2126        call: &Self::Call,2127        info: &DispatchInfoOf<Self::Call>,2128        len: usize,2129    ) -> Result<Self::Pre, TransactionValidityError> {2130        // let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2131        // Ok((self.0, who.clone(), imbalance, fee))21322133        print("====== Contracts pre-dispatch");2134        // debug::info!("Fee: {:?}", fee);21352136        Ok(())2137    }21382139    fn post_dispatch(2140        pre: Self::Pre,2141        info: &DispatchInfoOf<Self::Call>,2142        post_info: &PostDispatchInfoOf<Self::Call>,2143        len: usize,2144        _result: &DispatchResult,2145    ) -> Result<(), TransactionValidityError> {2146        // let (tip, who, imbalance, fee) = pre;2147        // if let Some(payed) = imbalance {2148        //     let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2149        //         len as u32, info, post_info, tip,2150        //     );2151        //     let refund = fee.saturating_sub(actual_fee);2152        //     let actual_payment =2153        //         match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2154        //             &who, refund,2155        //         ) {2156        //             Ok(refund_imbalance) => {2157        //                 // The refund cannot be larger than the up front payed max weight.2158        //                 // `PostDispatchInfo::calc_unspent` guards against such a case.2159        //                 match payed.offset(refund_imbalance) {2160        //                     Ok(actual_payment) => actual_payment,2161        //                     Err(_) => return Err(InvalidTransaction::Payment.into()),2162        //                 }2163        //             }2164        //             // We do not recreate the account using the refund. The up front payment2165        //             // is gone in that case.2166        //             Err(_) => payed,2167        //         };2168        //     let imbalances = actual_payment.split(tip);2169        //     <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2170        //         Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2171        //     );2172        // }2173        Ok(())2174    }2175}217621772178// #endregion21792180
modifiedruntime/src/lib.rsdiffbeforeafterboth
--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -352,7 +352,6 @@
     system::CheckNonce<Runtime>,
     system::CheckWeight<Runtime>,
     pallet_nft::ChargeTransactionPayment<Runtime>,
-    pallet_nft::ChargeContractTransactionPayment<Runtime>,
 );
 /// Unchecked extrinsic type as expected by this runtime.
 pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;