git.delta.rocks / unique-network / refs/commits / 5ecbc869df92

difftreelog

source

pallets/nft/src/lib.rs81.5 KiBsourcehistory
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, fail, parameter_types,14    traits::{15        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16        Randomness, WithdrawReason,17    },18    weights::{19        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21        WeightToFeePolynomial,22    },23    IsSubType, StorageValue,24};2526use frame_system::{self as system, ensure_signed, ensure_root};27use sp_runtime::sp_std::prelude::Vec;28use sp_runtime::{29    traits::{30        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero,31    },32    transaction_validity::{33        InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,34    },35    FixedPointOperand, FixedU128,36};37use pallet_contracts::ContractAddressFor;38use sp_runtime::traits::StaticLookup;3940#[cfg(test)]41mod mock;4243#[cfg(test)]44mod tests;4546mod default_weights;4748// Structs49// #region5051#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]52#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]53pub enum CollectionMode {54    Invalid,55    NFT,56    // decimal points57    Fungible(u32),58    // decimal points59    ReFungible(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 mint_mode: bool,109    pub offchain_schema: Vec<u8>,110    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender111    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship112    pub variable_on_chain_schema: Vec<u8>, //113    pub const_on_chain_schema: Vec<u8>, //114}115116#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]117#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]118pub struct CollectionAdminsType<AccountId> {119    pub admin: AccountId,120    pub collection_id: u64,121}122123#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]124#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]125pub struct NftItemType<AccountId> {126    pub collection: u64,127    pub owner: AccountId,128    pub const_data: Vec<u8>,129    pub variable_data: Vec<u8>,130}131132#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]133#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]134pub struct FungibleItemType<AccountId> {135    pub collection: u64,136    pub owner: AccountId,137    pub value: u128,138}139140#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]141#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]142pub struct ReFungibleItemType<AccountId> {143    pub collection: u64,144    pub owner: Vec<Ownership<AccountId>>,145    pub const_data: Vec<u8>,146    pub variable_data: Vec<u8>,147}148149#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]150#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]151pub struct ApprovePermissions<AccountId> {152    pub approved: AccountId,153    pub amount: u64,154}155156#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]157#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]158pub struct VestingItem<AccountId, Moment> {159    pub sender: AccountId,160    pub recipient: AccountId,161    pub collection_id: u64,162    pub item_id: u64,163    pub amount: u64,164    pub vesting_date: Moment,165}166167#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]168#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]169pub struct BasketItem<AccountId, BlockNumber> {170    pub address: AccountId,171    pub start_block: BlockNumber,172}173174#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]175#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]176pub struct ChainLimits {177    pub collection_numbers_limit: u64,178    pub account_token_ownership_limit: u64,179    pub collections_admins_limit: u64,180    pub custom_data_limit: u32,181182    // Timeouts for item types in passed blocks183    pub nft_sponsor_transfer_timeout: u32,184    pub fungible_sponsor_transfer_timeout: u32,185    pub refungible_sponsor_transfer_timeout: u32,186}187188pub trait WeightInfo {189	fn create_collection() -> Weight;190	fn destroy_collection() -> Weight;191	fn add_to_white_list() -> Weight;192	fn remove_from_white_list() -> Weight;193    fn set_public_access_mode() -> Weight;194    fn set_mint_permission() -> Weight;195    fn change_collection_owner() -> Weight;196    fn add_collection_admin() -> Weight;197    fn remove_collection_admin() -> Weight;198    fn set_collection_sponsor() -> Weight;199    fn confirm_sponsorship() -> Weight;200    fn remove_collection_sponsor() -> Weight;201    fn create_item(s: usize) -> Weight;202    fn burn_item() -> Weight;203    fn transfer() -> Weight;204    fn approve() -> Weight;205    fn transfer_from() -> Weight;206    fn set_offchain_schema() -> Weight;207    fn set_const_on_chain_schema() -> Weight;208    fn set_variable_on_chain_schema() -> Weight;209    fn set_variable_meta_data() -> Weight;210    // fn enable_contract_sponsoring() -> Weight;211}212213#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]214#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]215pub struct CreateNftData {216    pub const_data: Vec<u8>,217    pub variable_data: Vec<u8>,218}219220#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]221#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]222pub struct CreateFungibleData {223}224225#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]226#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]227pub struct CreateReFungibleData {228    pub const_data: Vec<u8>,229    pub variable_data: Vec<u8>,230}231232#[derive(Encode, Decode, Debug, Clone, PartialEq)]233#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]234pub enum CreateItemData {235    NFT(CreateNftData),236    Fungible(CreateFungibleData),237    ReFungible(CreateReFungibleData)238}239240impl CreateItemData {241    pub fn len(&self) -> usize {242        let len = match self {243            CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),244            CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),245            _ => 0246        };247        248        return len;249    }250}251252impl From<CreateNftData> for CreateItemData {253    fn from(item: CreateNftData) -> Self {254        CreateItemData::NFT(item)255    }256}257258impl From<CreateReFungibleData> for CreateItemData {259    fn from(item: CreateReFungibleData) -> Self {260        CreateItemData::ReFungible(item)261    }262}263264impl From<CreateFungibleData> for CreateItemData {265    fn from(item: CreateFungibleData) -> Self {266        CreateItemData::Fungible(item)267    }268}269270pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {271    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;272273    /// Weight information for extrinsics in this pallet.274	type WeightInfo: WeightInfo;275}276277#[cfg(feature = "runtime-benchmarks")]278mod benchmarking;279280// #endregion281282decl_storage! {283    trait Store for Module<T: Trait> as Nft {284285        // Private members286        NextCollectionID: u64;287        CreatedCollectionCount: u64;288        ChainVersion: u64;289        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;290291        // Chain limits struct292        pub ChainLimit get(fn chain_limit) config(): ChainLimits;293294        // Bound counters295        CollectionCount: u64;296        pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;297298        // Basic collections299        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;300        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;301        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;302303        /// Balance owner per collection map304        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;305306        /// second parameter: item id + owner account id307        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;308309        /// Item collections310        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;311        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;312        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;313314        /// Index list315        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;316317        /// Tokens transfer baskets318        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;319        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>>;320        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;321322        // Contract Sponsorship and Ownership323        pub ContractOwner get(fn contract_owner): map hasher(identity) T::AccountId => T::AccountId;324        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(identity) T::AccountId => bool;325    }326    add_extra_genesis {327        build(|config: &GenesisConfig<T>| {328            // Modification of storage329            for (_num, _c) in &config.collection {330                <Module<T>>::init_collection(_c);331            }332333            for (_num, _q, _i) in &config.nft_item_id {334                <Module<T>>::init_nft_token(_i);335            }336337            for (_num, _q, _i) in &config.fungible_item_id {338                <Module<T>>::init_fungible_token(_i);339            }340341            for (_num, _q, _i) in &config.refungible_item_id {342                <Module<T>>::init_refungible_token(_i);343            }344        })345    }346}347348decl_event!(349    pub enum Event<T>350    where351        AccountId = <T as system::Trait>::AccountId,352    {353        /// New collection was created354        /// 355        /// # Arguments356        /// 357        /// * collection_id: Globally unique identifier of newly created collection.358        /// 359        /// * mode: [CollectionMode] converted into u8.360        /// 361        /// * account_id: Collection owner.362        Created(u64, u8, AccountId),363364        /// New item was created.365        /// 366        /// # Arguments367        /// 368        /// * collection_id: Id of the collection where item was created.369        /// 370        /// * item_id: Id of an item. Unique within the collection.371        ItemCreated(u64, u64),372373        /// Collection item was burned.374        /// 375        /// # Arguments376        /// 377        /// collection_id.378        /// 379        /// item_id: Identifier of burned NFT.380        ItemDestroyed(u64, u64),381    }382);383384decl_module! {385    pub struct Module<T: Trait> for enum Call where origin: T::Origin {386387        fn deposit_event() = default;388389        fn on_initialize(now: T::BlockNumber) -> Weight {390391            if ChainVersion::get() < 2392            {393                let value = NextCollectionID::get();394                CreatedCollectionCount::put(value);395                ChainVersion::put(2);396            }397398            0399        }400401        /// 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.402        /// 403        /// # Permissions404        /// 405        /// * Anyone.406        /// 407        /// # Arguments408        /// 409        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.410        /// 411        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.412        /// 413        /// * token_prefix: UTF-8 string with token prefix.414        /// 415        /// * mode: [CollectionMode] collection type and type dependent data.416        // returns collection ID417        #[weight = T::WeightInfo::create_collection()]418        pub fn create_collection(origin,419                                 collection_name: Vec<u16>,420                                 collection_description: Vec<u16>,421                                 token_prefix: Vec<u8>,422                                 mode: CollectionMode) -> DispatchResult {423424            // Anyone can create a collection425            let who = ensure_signed(origin)?;426427            let decimal_points = match mode {428                CollectionMode::Fungible(points) => points,429                CollectionMode::ReFungible(points) => points,430                _ => 0431            };432433            // bound Total number of collections434            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, "Total collections bound exceeded");435436            // check params437            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");438439            let mut name = collection_name.to_vec();440            name.push(0);441            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");442443            let mut description = collection_description.to_vec();444            description.push(0);445            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");446447            let mut prefix = token_prefix.to_vec();448            prefix.push(0);449            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");450451            // Generate next collection ID452            let next_id = CreatedCollectionCount::get()453                .checked_add(1)454                .expect("collection id error");455456            // bound counter457            let total = CollectionCount::get()458                .checked_add(1)459                .expect("collection counter error");460461            CreatedCollectionCount::put(next_id);462            CollectionCount::put(total);463464            // Create new collection465            let new_collection = CollectionType {466                owner: who.clone(),467                name: name,468                mode: mode.clone(),469                mint_mode: false,470                access: AccessMode::Normal,471                description: description,472                decimal_points: decimal_points,473                token_prefix: prefix,474                offchain_schema: Vec::new(),475                sponsor: T::AccountId::default(),476                unconfirmed_sponsor: T::AccountId::default(),477                variable_on_chain_schema: Vec::new(),478                const_on_chain_schema: Vec::new(),479            };480481            // Add new collection to map482            <Collection<T>>::insert(next_id, new_collection);483484            // call event485            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));486487            Ok(())488        }489490        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.491        /// 492        /// # Permissions493        /// 494        /// * Collection Owner.495        /// 496        /// # Arguments497        /// 498        /// * collection_id: collection to destroy.499        #[weight = T::WeightInfo::destroy_collection()]500        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {501502            let sender = ensure_signed(origin)?;503            Self::check_owner_permissions(collection_id, sender)?;504505            <AddressTokens<T>>::remove_prefix(collection_id);506            <ApprovedList<T>>::remove_prefix(collection_id);507            <Balance<T>>::remove_prefix(collection_id);508            <ItemListIndex>::remove(collection_id);509            <AdminList<T>>::remove(collection_id);510            <Collection<T>>::remove(collection_id);511            <WhiteList<T>>::remove(collection_id);512513            <NftItemList<T>>::remove_prefix(collection_id);514            <FungibleItemList<T>>::remove_prefix(collection_id);515            <ReFungibleItemList<T>>::remove_prefix(collection_id);516517            <NftTransferBasket<T>>::remove_prefix(collection_id);518            <FungibleTransferBasket<T>>::remove_prefix(collection_id);519            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);520521            if CollectionCount::get() > 0522            {523                // bound couter524                let total = CollectionCount::get()525                    .checked_sub(1)526                    .expect("collection counter error");527528                CollectionCount::put(total);529            }530531            Ok(())532        }533534        /// Add an address to white list.535        /// 536        /// # Permissions537        /// 538        /// * Collection Owner539        /// * Collection Admin540        /// 541        /// # Arguments542        /// 543        /// * collection_id.544        /// 545        /// * address.546        #[weight = T::WeightInfo::add_to_white_list()]547        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{548549            let sender = ensure_signed(origin)?;550            Self::check_owner_or_admin_permissions(collection_id, sender)?;551552            let mut white_list_collection: Vec<T::AccountId>;553            if <WhiteList<T>>::contains_key(collection_id) {554                white_list_collection = <WhiteList<T>>::get(collection_id);555                if !white_list_collection.contains(&address.clone())556                {557                    white_list_collection.push(address.clone());558                }559            }560            else {561                white_list_collection = Vec::new();562                white_list_collection.push(address.clone());563            }564565            <WhiteList<T>>::insert(collection_id, white_list_collection);566            Ok(())567        }568569        /// Remove an address from white list.570        /// 571        /// # Permissions572        /// 573        /// * Collection Owner574        /// * Collection Admin575        /// 576        /// # Arguments577        /// 578        /// * collection_id.579        /// 580        /// * address.581        #[weight = T::WeightInfo::remove_from_white_list()]582        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{583584            let sender = ensure_signed(origin)?;585            Self::check_owner_or_admin_permissions(collection_id, sender)?;586587            if <WhiteList<T>>::contains_key(collection_id) {588                let mut white_list_collection = <WhiteList<T>>::get(collection_id);589                if white_list_collection.contains(&address.clone())590                {591                    white_list_collection.retain(|i| *i != address.clone());592                    <WhiteList<T>>::insert(collection_id, white_list_collection);593                }594            }595596            Ok(())597        }598599        /// Toggle between normal and white list access for the methods with access for `Anyone`.600        /// 601        /// # Permissions602        /// 603        /// * Collection Owner.604        /// 605        /// # Arguments606        /// 607        /// * collection_id.608        /// 609        /// * mode: [AccessMode]610        #[weight = T::WeightInfo::set_public_access_mode()]611        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult612        {613            let sender = ensure_signed(origin)?;614615            Self::check_owner_permissions(collection_id, sender)?;616            let mut target_collection = <Collection<T>>::get(collection_id);617            target_collection.access = mode;618            <Collection<T>>::insert(collection_id, target_collection);619620            Ok(())621        }622623        /// Allows Anyone to create tokens if:624        /// * White List is enabled, and625        /// * Address is added to white list, and626        /// * This method was called with True parameter627        /// 628        /// # Permissions629        /// * Collection Owner630        ///631        /// # Arguments632        /// 633        /// * collection_id.634        /// 635        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.636        #[weight = T::WeightInfo::set_mint_permission()]637        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult638        {639            let sender = ensure_signed(origin)?;640641            Self::check_owner_permissions(collection_id, sender)?;642            let mut target_collection = <Collection<T>>::get(collection_id);643            target_collection.mint_mode = mint_permission;644            <Collection<T>>::insert(collection_id, target_collection);645646            Ok(())647        }648649        /// Change the owner of the collection.650        /// 651        /// # Permissions652        /// 653        /// * Collection Owner.654        /// 655        /// # Arguments656        /// 657        /// * collection_id.658        /// 659        /// * new_owner.660        #[weight = T::WeightInfo::change_collection_owner()]661        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {662663            let sender = ensure_signed(origin)?;664            Self::check_owner_permissions(collection_id, sender)?;665            let mut target_collection = <Collection<T>>::get(collection_id);666            target_collection.owner = new_owner;667            <Collection<T>>::insert(collection_id, target_collection);668669            Ok(())670        }671672        /// Adds an admin of the Collection.673        /// 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. 674        /// 675        /// # Permissions676        /// 677        /// * Collection Owner.678        /// * Collection Admin.679        /// 680        /// # Arguments681        /// 682        /// * collection_id: ID of the Collection to add admin for.683        /// 684        /// * new_admin_id: Address of new admin to add.685        #[weight = T::WeightInfo::add_collection_admin()]686        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {687688            let sender = ensure_signed(origin)?;689            Self::check_owner_or_admin_permissions(collection_id, sender)?;690            let mut admin_arr: Vec<T::AccountId> = Vec::new();691692            if <AdminList<T>>::contains_key(collection_id)693            {694                admin_arr = <AdminList<T>>::get(collection_id);695                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");696            }697698            // Number of collection admins699            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, "Number of collection admins bound exceeded");700701            admin_arr.push(new_admin_id);702            <AdminList<T>>::insert(collection_id, admin_arr);703704            Ok(())705        }706707        /// 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.708        ///709        /// # Permissions710        /// 711        /// * Collection Owner.712        /// * Collection Admin.713        /// 714        /// # Arguments715        /// 716        /// * collection_id: ID of the Collection to remove admin for.717        /// 718        /// * account_id: Address of admin to remove.719        #[weight = T::WeightInfo::remove_collection_admin()]720        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {721722            let sender = ensure_signed(origin)?;723            Self::check_owner_or_admin_permissions(collection_id, sender)?;724725            if <AdminList<T>>::contains_key(collection_id)726            {727                let mut admin_arr = <AdminList<T>>::get(collection_id);728                admin_arr.retain(|i| *i != account_id);729                <AdminList<T>>::insert(collection_id, admin_arr);730            }731732            Ok(())733        }734735        /// # Permissions736        /// 737        /// * Collection Owner738        /// 739        /// # Arguments740        /// 741        /// * collection_id.742        /// 743        /// * new_sponsor.744        #[weight = T::WeightInfo::set_collection_sponsor()]745        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {746747            let sender = ensure_signed(origin)?;748            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");749750            let mut target_collection = <Collection<T>>::get(collection_id);751            ensure!(sender == target_collection.owner, "You do not own this collection");752753            target_collection.unconfirmed_sponsor = new_sponsor;754            <Collection<T>>::insert(collection_id, target_collection);755756            Ok(())757        }758759        /// # Permissions760        /// 761        /// * Sponsor.762        /// 763        /// # Arguments764        /// 765        /// * collection_id.766        #[weight = T::WeightInfo::confirm_sponsorship()]767        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {768769            let sender = ensure_signed(origin)?;770            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");771772            let mut target_collection = <Collection<T>>::get(collection_id);773            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");774775            target_collection.sponsor = target_collection.unconfirmed_sponsor;776            target_collection.unconfirmed_sponsor = T::AccountId::default();777            <Collection<T>>::insert(collection_id, target_collection);778779            Ok(())780        }781782        /// Switch back to pay-per-own-transaction model.783        ///784        /// # Permissions785        ///786        /// * Collection owner.787        /// 788        /// # Arguments789        /// 790        /// * collection_id.791        #[weight = T::WeightInfo::remove_collection_sponsor()]792        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {793794            let sender = ensure_signed(origin)?;795            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");796797            let mut target_collection = <Collection<T>>::get(collection_id);798            ensure!(sender == target_collection.owner, "You do not own this collection");799800            target_collection.sponsor = T::AccountId::default();801            <Collection<T>>::insert(collection_id, target_collection);802803            Ok(())804        }805806        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.807        /// 808        /// # Permissions809        /// 810        /// * Collection Owner.811        /// * Collection Admin.812        /// * Anyone if813        ///     * White List is enabled, and814        ///     * Address is added to white list, and815        ///     * MintPermission is enabled (see SetMintPermission method)816        /// 817        /// # Arguments818        /// 819        /// * collection_id: ID of the collection.820        /// 821        /// * owner: Address, initial owner of the NFT.822        ///823        /// * data: Token data to store on chain.824        // #[weight =825        // (130_000_000 as Weight)826        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))827        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))828        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]829830        #[weight = T::WeightInfo::create_item(data.len())]831        pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {832833            let sender = ensure_signed(origin)?;834835            Self::collection_exists(collection_id)?;836837            let target_collection = <Collection<T>>::get(collection_id);838839            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;840            Self::validate_create_item_args(&target_collection, &properties)?;841            Self::create_item_no_validation(collection_id, &target_collection, &properties, &owner)?;842843            Ok(())844        }845846        /// This method creates multiple instances of NFT Collection created with CreateCollection method.847        /// 848        /// # Permissions849        /// 850        /// * Collection Owner.851        /// * Collection Admin.852        /// * Anyone if853        ///     * White List is enabled, and854        ///     * Address is added to white list, and855        ///     * MintPermission is enabled (see SetMintPermission method)856        /// 857        /// # Arguments858        /// 859        /// * collection_id: ID of the collection.860        /// 861        /// * properties: Array items properties. Each property is an array of bytes itself, see [create_item].862        /// 863        /// * owner: Address, initial owner of the NFT.864        #[weight = 0]865        pub fn create_multiple_items(origin, collection_id: u64, properties: Vec<Vec<u8>>, owner: T::AccountId) -> DispatchResult {866867            ensure!(properties.len() > 0, "Length of items properties must be greater than 0.");868            let sender = ensure_signed(origin)?;869870            Self::collection_exists(collection_id)?;871            let target_collection = <Collection<T>>::get(collection_id);872873            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;874875            for prop in &properties {876                Self::validate_create_item_args(&target_collection, prop)?;877            }878            for prop in &properties {879                Self::create_item_no_validation(collection_id, &target_collection, prop, &owner)?;880            }881882            Ok(())883        }884885        /// Destroys a concrete instance of NFT.886        /// 887        /// # Permissions888        /// 889        /// * Collection Owner.890        /// * Collection Admin.891        /// * Current NFT Owner.892        /// 893        /// # Arguments894        /// 895        /// * collection_id: ID of the collection.896        /// 897        /// * item_id: ID of NFT to burn.898        #[weight = T::WeightInfo::burn_item()]899        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {900901            let sender = ensure_signed(origin)?;902            Self::collection_exists(collection_id)?;903904            // Transfer permissions check905            let target_collection = <Collection<T>>::get(collection_id);906            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||907                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),908                "Only item owner, collection owner and admins can modify item");909910            if target_collection.access == AccessMode::WhiteList {911                Self::check_white_list(collection_id, &sender)?;912            }913914            match target_collection.mode915            {916                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,917                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,918                CollectionMode::ReFungible(_)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,919                _ => ()920            };921922            // call event923            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));924925            Ok(())926        }927928        /// Change ownership of the token.929        /// 930        /// # Permissions931        /// 932        /// * Collection Owner933        /// * Collection Admin934        /// * Current NFT owner935        ///936        /// # Arguments937        /// 938        /// * recipient: Address of token recipient.939        /// 940        /// * collection_id.941        /// 942        /// * item_id: ID of the item943        ///     * Non-Fungible Mode: Required.944        ///     * Fungible Mode: Ignored.945        ///     * Re-Fungible Mode: Required.946        /// 947        /// * value: Amount to transfer.948        ///     * Non-Fungible Mode: Ignored949        ///     * Fungible Mode: Must specify transferred amount950        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)951        #[weight = T::WeightInfo::transfer()]952        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {953954            let sender = ensure_signed(origin)?;955956            // Transfer permissions check957            let target_collection = <Collection<T>>::get(collection_id);958            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||959                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),960                "Only item owner, collection owner and admins can modify item");961962            if target_collection.access == AccessMode::WhiteList {963                Self::check_white_list(collection_id, &sender)?;964                Self::check_white_list(collection_id, &recipient)?;965            }966967            match target_collection.mode968            {969                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,970                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,971                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,972                _ => ()973            };974975            Ok(())976        }977978        /// Set, change, or remove approved address to transfer the ownership of the NFT.979        /// 980        /// # Permissions981        /// 982        /// * Collection Owner983        /// * Collection Admin984        /// * Current NFT owner985        /// 986        /// # Arguments987        /// 988        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).989        /// 990        /// * collection_id.991        /// 992        /// * item_id: ID of the item.993        #[weight = T::WeightInfo::approve()]994        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {995996            let sender = ensure_signed(origin)?;997998            // Transfer permissions check999            let target_collection = <Collection<T>>::get(collection_id);1000            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1001                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1002                "Only item owner, collection owner and admins can approve");10031004            if target_collection.access == AccessMode::WhiteList {1005                Self::check_white_list(collection_id, &sender)?;1006                Self::check_white_list(collection_id, &approved)?;1007            }10081009            // amount param stub1010            let amount = 100000000;10111012            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1013            if list_exists {10141015                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1016                let item_contains = list.iter().any(|i| i.approved == approved);10171018                if !item_contains {1019                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1020                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1021                }1022            } else {10231024                let mut list = Vec::new();1025                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1026                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1027            }10281029            Ok(())1030        }1031        1032        /// 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.1033        /// 1034        /// # Permissions1035        /// * Collection Owner1036        /// * Collection Admin1037        /// * Current NFT owner1038        /// * Address approved by current NFT owner1039        /// 1040        /// # Arguments1041        /// 1042        /// * from: Address that owns token.1043        /// 1044        /// * recipient: Address of token recipient.1045        /// 1046        /// * collection_id.1047        /// 1048        /// * item_id: ID of the item.1049        /// 1050        /// * value: Amount to transfer.1051        #[weight = T::WeightInfo::transfer_from()]1052        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {10531054            let sender = ensure_signed(origin)?;1055            let mut appoved_transfer = false;10561057            // Check approve1058            if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1059                let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1060                let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1061                if opt_item.is_some()1062                {1063                    appoved_transfer = true;1064                    ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");1065                }1066            }10671068            // Transfer permissions check1069            let target_collection = <Collection<T>>::get(collection_id);1070            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1071                "Only item owner, collection owner and admins can modify items");10721073            if target_collection.access == AccessMode::WhiteList {1074                Self::check_white_list(collection_id, &sender)?;1075                Self::check_white_list(collection_id, &recipient)?;1076            }10771078            // remove approve1079            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1080                .into_iter().filter(|i| i.approved != sender.clone()).collect();1081            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);108210831084            match target_collection.mode1085            {1086                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1087                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1088                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1089                _ => ()1090            };10911092            Ok(())1093        }10941095        ///1096        #[weight = 0]1097        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {10981099            // let no_perm_mes = "You do not have permissions to modify this collection";1100            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1101            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1102            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);11031104            // // on_nft_received  call11051106            // Self::transfer(origin, collection_id, item_id, new_owner)?;11071108            Ok(())1109        }11101111        /// Set off-chain data schema.1112        /// 1113        /// # Permissions1114        /// 1115        /// * Collection Owner1116        /// * Collection Admin1117        /// 1118        /// # Arguments1119        /// 1120        /// * collection_id.1121        /// 1122        /// * schema: String representing the offchain data schema.1123        #[weight = T::WeightInfo::set_variable_meta_data()]1124        pub fn set_variable_meta_data (1125            origin,1126            collection_id: u64,1127            item_id: u64,1128            data: Vec<u8>1129        ) -> DispatchResult {1130            let sender = ensure_signed(origin)?;1131            1132            Self::collection_exists(collection_id)?;11331134            // Modify permissions check1135            let target_collection = <Collection<T>>::get(collection_id);1136            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1137                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1138                "Only item owner, collection owner and admins can modify item");11391140            Self::item_exists(collection_id, item_id, &target_collection.mode)?;11411142            match target_collection.mode1143            {1144                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1145                CollectionMode::ReFungible(_)  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1146                _ => ()1147            };11481149            Ok(())1150        }1151        11521153        /// Set off-chain data schema.1154        /// 1155        /// # Permissions1156        /// 1157        /// * Collection Owner1158        /// * Collection Admin1159        /// 1160        /// # Arguments1161        /// 1162        /// * collection_id.1163        /// 1164        /// * schema: String representing the offchain data schema.1165        #[weight = T::WeightInfo::set_offchain_schema()]1166        pub fn set_offchain_schema(1167            origin,1168            collection_id: u64,1169            schema: Vec<u8>1170        ) -> DispatchResult {1171            let sender = ensure_signed(origin)?;1172            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;11731174            let mut target_collection = <Collection<T>>::get(collection_id);1175            target_collection.offchain_schema = schema;1176            <Collection<T>>::insert(collection_id, target_collection);11771178            Ok(())1179        }11801181        /// Set const on-chain data schema.1182        /// 1183        /// # Permissions1184        /// 1185        /// * Collection Owner1186        /// * Collection Admin1187        /// 1188        /// # Arguments1189        /// 1190        /// * collection_id.1191        /// 1192        /// * schema: String representing the const on-chain data schema.1193        #[weight = T::WeightInfo::set_const_on_chain_schema()]1194        pub fn set_const_on_chain_schema (1195            origin,1196            collection_id: u64,1197            schema: Vec<u8>1198        ) -> DispatchResult {1199            let sender = ensure_signed(origin)?;1200            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12011202            let mut target_collection = <Collection<T>>::get(collection_id);1203            target_collection.const_on_chain_schema = schema;1204            <Collection<T>>::insert(collection_id, target_collection);12051206            Ok(())1207        }12081209        /// Set variable on-chain data schema.1210        /// 1211        /// # Permissions1212        /// 1213        /// * Collection Owner1214        /// * Collection Admin1215        /// 1216        /// # Arguments1217        /// 1218        /// * collection_id.1219        /// 1220        /// * schema: String representing the variable on-chain data schema.1221        #[weight = T::WeightInfo::set_const_on_chain_schema()]1222        pub fn set_variable_on_chain_schema (1223            origin,1224            collection_id: u64,1225            schema: Vec<u8>1226        ) -> DispatchResult {1227            let sender = ensure_signed(origin)?;1228            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12291230            let mut target_collection = <Collection<T>>::get(collection_id);1231            target_collection.variable_on_chain_schema = schema;1232            <Collection<T>>::insert(collection_id, target_collection);12331234            Ok(())1235        }12361237        // Sudo permissions function1238        #[weight = 0]1239        pub fn set_chain_limits(1240            origin,1241            limits: ChainLimits1242        ) -> DispatchResult {1243            ensure_root(origin)?;1244            <ChainLimit>::put(limits);1245            Ok(())1246        }12471248        /// Enable smart contract self-sponsoring.1249        /// 1250        /// # Permissions1251        /// 1252        /// * Contract Owner1253        /// 1254        /// # Arguments1255        /// 1256        /// * contract address1257        /// * enable flag1258        /// 1259        #[weight = 0]1260        pub fn enable_contract_sponsoring(1261            origin,1262            contract_address: T::AccountId,1263            enable: bool1264        ) -> DispatchResult {1265            let sender = ensure_signed(origin)?;1266            let mut is_owner = false;1267            if <ContractOwner<T>>::contains_key(contract_address.clone()) {1268                let owner = <ContractOwner<T>>::get(&contract_address);1269                is_owner = sender == owner;1270            }1271            ensure!(is_owner, "Only contract owner may call this method");12721273            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1274            Ok(())1275        }12761277    }1278}12791280impl<T: Trait> Module<T> {12811282    fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {12831284        if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1285            ensure!(collection.mint_mode == true, "Public minting is not allowed for this collection");1286            Self::check_white_list(collection_id, owner)?;1287            Self::check_white_list(collection_id, sender)?;1288        }12891290        Ok(())1291    }12921293    fn validate_create_item_args(collection: &CollectionType<T::AccountId>, properties: &Vec<u8>) -> DispatchResult {12941295        match collection.mode1296        {1297            CollectionMode::NFT(_) => {12981299                // check size1300                ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")1301            },1302            CollectionMode::Fungible(_) => {13031304                // check size1305                ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type")1306            },1307            CollectionMode::ReFungible(_, _) => {13081309                // check size1310                ensure!(collection.custom_data_size >= properties.len() as u32, "Size of item is too large")1311            },1312            _ => {1313                fail!("Unexpected collection mode")1314            }1315        }13161317        Ok(())1318    }13191320    fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, properties: &Vec<u8>, owner: &T::AccountId) -> DispatchResult {1321        match collection.mode1322        {1323            CollectionMode::NFT(_) => {13241325                // Create nft item1326                let item = NftItemType {1327                    collection: collection_id,1328                    owner: owner.clone(),1329                    data: properties.clone(),1330                };13311332                Self::add_nft_item(item)?;13331334            },1335            CollectionMode::Fungible(_) => {13361337                let item = FungibleItemType {1338                    collection: collection_id,1339                    owner: owner.clone(),1340                    value: (10 as u128).pow(collection.decimal_points)1341                };13421343                Self::add_fungible_item(item)?;1344            },1345            CollectionMode::ReFungible(_, _) => {13461347                let mut owner_list = Vec::new();1348                let value = (10 as u128).pow(collection.decimal_points);1349                owner_list.push(Ownership {owner: owner.clone(), fraction: value});13501351                let item = ReFungibleItemType {1352                    collection: collection_id,1353                    owner: owner_list,1354                    data: properties.clone()1355                };13561357                Self::add_refungible_item(item)?;1358            },1359            _ => { ensure!(1 == 0,"just error"); }13601361        };13621363        // call event1364        Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));13651366        Ok(())1367    }13681369    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1370        let current_index = <ItemListIndex>::get(item.collection)1371            .checked_add(1)1372            .expect("Item list index id error");1373        let itemcopy = item.clone();1374        let owner = item.owner.clone();1375        let value = item.value as u64;13761377        Self::add_token_index(item.collection, current_index, owner.clone())?;13781379        <ItemListIndex>::insert(item.collection, current_index);1380        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);13811382        // Add current block1383        let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1384        <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1385        1386        // Update balance1387        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1388            .checked_add(value)1389            .unwrap();1390        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);13911392        Ok(())1393    }13941395    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1396        let current_index = <ItemListIndex>::get(item.collection)1397            .checked_add(1)1398            .expect("Item list index id error");1399        let itemcopy = item.clone();14001401        let value = item.owner.first().unwrap().fraction as u64;1402        let owner = item.owner.first().unwrap().owner.clone();14031404        Self::add_token_index(item.collection, current_index, owner.clone())?;14051406        <ItemListIndex>::insert(item.collection, current_index);1407        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);14081409        // Add current block1410        let block_number: T::BlockNumber = 0.into();1411        <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);14121413        // Update balance1414        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1415            .checked_add(value)1416            .unwrap();1417        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);14181419        Ok(())1420    }14211422    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1423        let current_index = <ItemListIndex>::get(item.collection)1424            .checked_add(1)1425            .expect("Item list index id error");14261427        let item_owner = item.owner.clone();1428        let collection_id = item.collection.clone();1429        Self::add_token_index(collection_id, current_index, item.owner.clone())?;14301431        <ItemListIndex>::insert(collection_id, current_index);1432        <NftItemList<T>>::insert(collection_id, current_index, item);14331434        // Add current block1435        let block_number: T::BlockNumber = 0.into();1436        <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);14371438        // Update balance1439        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1440            .checked_add(1)1441            .unwrap();1442        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);14431444        Ok(())1445    }14461447    fn burn_refungible_item(1448        collection_id: u64,1449        item_id: u64,1450        owner: T::AccountId,1451    ) -> DispatchResult {1452        ensure!(1453            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1454            "Item does not exists"1455        );1456        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1457        let item = collection1458            .owner1459            .iter()1460            .filter(|&i| i.owner == owner)1461            .next()1462            .unwrap();1463        Self::remove_token_index(collection_id, item_id, owner.clone())?;14641465        // remove approve list1466        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));14671468        // update balance1469        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1470            .checked_sub(item.fraction as u64)1471            .unwrap();1472        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);14731474        <ReFungibleItemList<T>>::remove(collection_id, item_id);14751476        Ok(())1477    }14781479    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1480        ensure!(1481            <NftItemList<T>>::contains_key(collection_id, item_id),1482            "Item does not exists"1483        );1484        let item = <NftItemList<T>>::get(collection_id, item_id);1485        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;14861487        // remove approve list1488        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));14891490        // update balance1491        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1492            .checked_sub(1)1493            .unwrap();1494        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1495        <NftItemList<T>>::remove(collection_id, item_id);14961497        Ok(())1498    }14991500    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1501        ensure!(1502            <FungibleItemList<T>>::contains_key(collection_id, item_id),1503            "Item does not exists"1504        );1505        let item = <FungibleItemList<T>>::get(collection_id, item_id);1506        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;15071508        // remove approve list1509        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));15101511        // update balance1512        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1513            .checked_sub(item.value as u64)1514            .unwrap();1515        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);15161517        <FungibleItemList<T>>::remove(collection_id, item_id);15181519        Ok(())1520    }15211522    fn collection_exists(collection_id: u64) -> DispatchResult {1523        ensure!(1524            <Collection<T>>::contains_key(collection_id),1525            "This collection does not exist"1526        );1527        Ok(())1528    }15291530    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1531        Self::collection_exists(collection_id)?;15321533        let target_collection = <Collection<T>>::get(collection_id);1534        ensure!(1535            subject == target_collection.owner,1536            "You do not own this collection"1537        );15381539        Ok(())1540    }15411542    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1543        let target_collection = <Collection<T>>::get(collection_id);1544        let mut result: bool = subject == target_collection.owner;1545        let exists = <AdminList<T>>::contains_key(collection_id);15461547        if !result & exists {1548            if <AdminList<T>>::get(collection_id).contains(&subject) {1549                result = true1550            }1551        }15521553        result1554    }15551556    fn check_owner_or_admin_permissions(1557        collection_id: u64,1558        subject: T::AccountId,1559    ) -> DispatchResult {1560        Self::collection_exists(collection_id)?;1561        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());15621563        ensure!(1564            result,1565            "You do not have permissions to modify this collection"1566        );1567        Ok(())1568    }15691570    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1571        let target_collection = <Collection<T>>::get(collection_id);15721573        match target_collection.mode {1574            CollectionMode::NFT => {1575                <NftItemList<T>>::get(collection_id, item_id).owner == subject1576            }1577            CollectionMode::Fungible(_) => {1578                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1579            }1580            CollectionMode::ReFungible(_) => {1581                <ReFungibleItemList<T>>::get(collection_id, item_id)1582                    .owner1583                    .iter()1584                    .any(|i| i.owner == subject)1585            }1586            CollectionMode::Invalid => false,1587        }1588    }15891590    fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1591        let mes = "Address is not in white list";1592        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1593        let wl = <WhiteList<T>>::get(collection_id);1594        ensure!(wl.contains(address), mes);15951596        Ok(())1597    }15981599    fn transfer_fungible(1600        collection_id: u64,1601        item_id: u64,1602        value: u64,1603        owner: T::AccountId,1604        new_owner: T::AccountId,1605    ) -> DispatchResult {1606        ensure!(1607            <FungibleItemList<T>>::contains_key(collection_id, item_id),1608            "Item not exists"1609        );16101611        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1612        let amount = full_item.value;16131614        ensure!(amount >= value.into(), "Item balance not enouth");16151616        // update balance1617        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1618            .checked_sub(value)1619            .unwrap();1620        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);16211622        let mut new_owner_account_id = 0;1623        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1624        if new_owner_items.len() > 0 {1625            new_owner_account_id = new_owner_items[0];1626        }16271628        let val64 = value.into();16291630        // transfer1631        if amount == val64 && new_owner_account_id == 0 {1632            // change owner1633            // new owner do not have account1634            let mut new_full_item = full_item.clone();1635            new_full_item.owner = new_owner.clone();1636            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);16371638            // update balance1639            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1640                .checked_add(value)1641                .unwrap();1642            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16431644            // update index collection1645            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1646        } else {1647            let mut new_full_item = full_item.clone();1648            new_full_item.value -= val64;16491650            // separate amount1651            if new_owner_account_id > 0 {1652                // new owner has account1653                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1654                item.value += val64;16551656                // update balance1657                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1658                    .checked_add(value)1659                    .unwrap();1660                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);16611662                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1663            } else {1664                // new owner do not have account1665                let item = FungibleItemType {1666                    collection: collection_id,1667                    owner: new_owner.clone(),1668                    value: val64,1669                };16701671                Self::add_fungible_item(item)?;1672            }16731674            if amount == val64 {1675                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;16761677                // remove approve list1678                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1679                <FungibleItemList<T>>::remove(collection_id, item_id);1680            }16811682            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1683        }16841685        Ok(())1686    }16871688    fn transfer_refungible(1689        collection_id: u64,1690        item_id: u64,1691        value: u64,1692        owner: T::AccountId,1693        new_owner: T::AccountId,1694    ) -> DispatchResult {1695        ensure!(1696            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1697            "Item not exists"1698        );16991700        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1701        let item = full_item1702            .owner1703            .iter()1704            .filter(|i| i.owner == owner)1705            .next()1706            .unwrap();1707        let amount = item.fraction;17081709        ensure!(amount >= value.into(), "Item balance not enouth");17101711        // update balance1712        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1713            .checked_sub(value)1714            .unwrap();1715        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);17161717        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1718            .checked_add(value)1719            .unwrap();1720        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);17211722        let old_owner = item.owner.clone();1723        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1724        let val64 = value.into();17251726        // transfer1727        if amount == val64 && !new_owner_has_account {1728            // change owner1729            // new owner do not have account1730            let mut new_full_item = full_item.clone();1731            new_full_item1732                .owner1733                .iter_mut()1734                .find(|i| i.owner == owner)1735                .unwrap()1736                .owner = new_owner.clone();1737            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);17381739            // update index collection1740            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1741        } else {1742            let mut new_full_item = full_item.clone();1743            new_full_item1744                .owner1745                .iter_mut()1746                .find(|i| i.owner == owner)1747                .unwrap()1748                .fraction -= val64;17491750            // separate amount1751            if new_owner_has_account {1752                // new owner has account1753                new_full_item1754                    .owner1755                    .iter_mut()1756                    .find(|i| i.owner == new_owner)1757                    .unwrap()1758                    .fraction += val64;1759            } else {1760                // new owner do not have account1761                new_full_item.owner.push(Ownership {1762                    owner: new_owner.clone(),1763                    fraction: val64,1764                });1765                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1766            }17671768            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1769        }17701771        Ok(())1772    }17731774    fn transfer_nft(1775        collection_id: u64,1776        item_id: u64,1777        sender: T::AccountId,1778        new_owner: T::AccountId,1779    ) -> DispatchResult {1780        ensure!(1781            <NftItemList<T>>::contains_key(collection_id, item_id),1782            "Item not exists"1783        );17841785        let mut item = <NftItemList<T>>::get(collection_id, item_id);17861787        ensure!(1788            sender == item.owner,1789            "sender parameter and item owner must be equal"1790        );17911792        // update balance1793        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1794            .checked_sub(1)1795            .unwrap();1796        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);17971798        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1799            .checked_add(1)1800            .unwrap();1801        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18021803        // change owner1804        let old_owner = item.owner.clone();1805        item.owner = new_owner.clone();1806        <NftItemList<T>>::insert(collection_id, item_id, item);18071808        // update index collection1809        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;18101811        // reset approved list1812        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1813        Ok(())1814    }1815    1816    fn item_exists(1817        collection_id: u64,1818        item_id: u64,1819        mode: &CollectionMode1820    ) -> DispatchResult {1821        match mode {1822            CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1823            CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1824            CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), "Item does not exists"),1825            _ => ()1826        };1827        1828        Ok(())1829    }18301831    fn set_re_fungible_variable_data(1832        collection_id: u64,1833        item_id: u64,1834        data: Vec<u8>1835    ) -> DispatchResult {1836        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);18371838        item.variable_data = data;18391840        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);18411842        Ok(())1843    }18441845    fn set_nft_variable_data(1846        collection_id: u64,1847        item_id: u64,1848        data: Vec<u8>1849    ) -> DispatchResult {1850        let mut item = <NftItemList<T>>::get(collection_id, item_id);1851        1852        item.variable_data = data;18531854        <NftItemList<T>>::insert(collection_id, item_id, item);1855        1856        Ok(())1857    }18581859    fn init_collection(item: &CollectionType<T::AccountId>) {1860        // check params1861        assert!(1862            item.decimal_points <= 4,1863            "decimal_points parameter must be lower than 4"1864        );1865        assert!(1866            item.name.len() <= 64,1867            "Collection name can not be longer than 63 char"1868        );1869        assert!(1870            item.name.len() <= 256,1871            "Collection description can not be longer than 255 char"1872        );1873        assert!(1874            item.token_prefix.len() <= 16,1875            "Token prefix can not be longer than 15 char"1876        );18771878        // Generate next collection ID1879        let next_id = CreatedCollectionCount::get()1880            .checked_add(1)1881            .expect("collection id error");18821883        CreatedCollectionCount::put(next_id);1884    }18851886    fn init_nft_token(item: &NftItemType<T::AccountId>) {1887        let current_index = <ItemListIndex>::get(item.collection)1888            .checked_add(1)1889            .expect("Item list index id error");18901891        let item_owner = item.owner.clone();1892        let collection_id = item.collection.clone();1893        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();18941895        <ItemListIndex>::insert(collection_id, current_index);18961897        // Update balance1898        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1899            .checked_add(1)1900            .unwrap();1901        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1902    }19031904    fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {1905        let current_index = <ItemListIndex>::get(item.collection)1906            .checked_add(1)1907            .expect("Item list index id error");1908        let owner = item.owner.clone();1909        let value = item.value as u64;19101911        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();19121913        <ItemListIndex>::insert(item.collection, current_index);19141915        // Update balance1916        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1917            .checked_add(value)1918            .unwrap();1919        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1920    }19211922    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {1923        let current_index = <ItemListIndex>::get(item.collection)1924            .checked_add(1)1925            .expect("Item list index id error");19261927        let value = item.owner.first().unwrap().fraction as u64;1928        let owner = item.owner.first().unwrap().owner.clone();19291930        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();19311932        <ItemListIndex>::insert(item.collection, current_index);19331934        // Update balance1935        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1936            .checked_add(value)1937            .unwrap();1938        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1939    }19401941    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {19421943        // add to account limit1944        if <AccountItemCount<T>>::contains_key(owner.clone()) {19451946            // bound Owned tokens by a single address1947            let count = <AccountItemCount<T>>::get(owner.clone());1948            ensure!(count < ChainLimit::get().account_token_ownership_limit, "Owned tokens by a single address bound exceeded");19491950            <AccountItemCount<T>>::insert(owner.clone(), 1951                count.checked_add(1).unwrap());1952        }1953        else {1954            <AccountItemCount<T>>::insert(owner.clone(), 1);1955        }19561957        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1958        if list_exists {1959            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1960            let item_contains = list.contains(&item_index.clone());19611962            if !item_contains {1963                list.push(item_index.clone());1964            }19651966            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1967        } else {1968            let mut itm = Vec::new();1969            itm.push(item_index.clone());1970            <AddressTokens<T>>::insert(collection_id, owner, itm);1971            1972        }19731974        Ok(())1975    }19761977    fn remove_token_index(1978        collection_id: u64,1979        item_index: u64,1980        owner: T::AccountId,1981    ) -> DispatchResult {19821983        // update counter1984        <AccountItemCount<T>>::insert(owner.clone(), 1985            <AccountItemCount<T>>::get(owner.clone()).checked_sub(1).unwrap());198619871988        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1989        if list_exists {1990            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1991            let item_contains = list.contains(&item_index.clone());19921993            if item_contains {1994                list.retain(|&item| item != item_index);1995                <AddressTokens<T>>::insert(collection_id, owner, list);1996            }1997        }19981999        Ok(())2000    }20012002    fn move_token_index(2003        collection_id: u64,2004        item_index: u64,2005        old_owner: T::AccountId,2006        new_owner: T::AccountId,2007    ) -> DispatchResult {2008        Self::remove_token_index(collection_id, item_index, old_owner)?;2009        Self::add_token_index(collection_id, item_index, new_owner)?;20102011        Ok(())2012    }2013}20142015////////////////////////////////////////////////////////////////////////////////////////////////////2016// Economic models2017// #region20182019/// Fee multiplier.2020pub type Multiplier = FixedU128;20212022type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2023    <T as system::Trait>::AccountId,2024>>::Balance;2025type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2026    <T as system::Trait>::AccountId,2027>>::NegativeImbalance;20282029/// Require the transactor pay for themselves and maybe include a tip to gain additional priority2030/// in the queue.2031#[derive(Encode, Decode, Clone, Eq, PartialEq)]2032pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2033    #[codec(compact)] BalanceOf<T>2034);20352036impl<T: Trait + Send + Sync> sp_std::fmt::Debug2037    for ChargeTransactionPayment<T>2038{2039    #[cfg(feature = "std")]2040    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2041        write!(f, "ChargeTransactionPayment<{:?}>", self.0)2042    }2043    #[cfg(not(feature = "std"))]2044    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2045        Ok(())2046    }2047}20482049impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2050where2051    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2052    BalanceOf<T>: Send + Sync + FixedPointOperand,2053{2054    /// utility constructor. Used only in client/factory code.2055    pub fn from(fee: BalanceOf<T>) -> Self {2056        Self(fee)2057    }20582059    pub fn traditional_fee(2060        len: usize,2061        info: &DispatchInfoOf<T::Call>,2062        tip: BalanceOf<T>,2063    ) -> BalanceOf<T>2064    where2065        T::Call: Dispatchable<Info = DispatchInfo>,2066    {2067        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2068    }20692070    fn withdraw_fee(2071        &self,2072        who: &T::AccountId,2073        call: &T::Call,2074        info: &DispatchInfoOf<T::Call>,2075        len: usize,2076    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2077        let tip = self.0;20782079        // Set fee based on call type. Creating collection costs 1 Unique.2080        // All other transactions have traditional fees so far2081        // let fee = match call.is_sub_type() {2082        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),2083        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes2084        //                                                 // _ => <BalanceOf<T>>::from(100)2085        // };2086        let fee = Self::traditional_fee(len, info, tip);20872088        // Determine who is paying transaction fee based on ecnomic model2089        // Parse call to extract collection ID and access collection sponsor2090        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2091            Some(Call::create_item(collection_id, _properties, _owner)) => {2092                <Collection<T>>::get(collection_id).sponsor2093            }2094            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2095                let _collection_mode = <Collection<T>>::get(collection_id).mode;20962097                // sponsor timeout2098                let sponsor_transfer = match _collection_mode {2099                    CollectionMode::NFT => {2100                        let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2101                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2102                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2103                        if block_number >= limit_time {2104                            <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2105                            true2106                        }2107                        else {2108                            false2109                        }2110                    }2111                    CollectionMode::Fungible(_) => {2112                        let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2113                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2114                        if basket.iter().any(|i| i.address == _new_owner.clone())2115                        {2116                            let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2117                            let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();2118                            if block_number >= limit_time {2119                                basket.retain(|x| x.address == item.address);2120                                basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2121                                <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2122                                true2123                            }2124                            else {2125                                false2126                            }2127                        }2128                        else {2129                            basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2130                            true2131                        }2132                    }2133                    CollectionMode::ReFungible(_) => {2134                        let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2135                        let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2136                        let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2137                        if block_number >= limit_time {2138                            <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2139                            true2140                        } else {2141                            false2142                        }2143                    }2144                    _ => {2145                        false2146                    },2147                };21482149                if !sponsor_transfer {2150                    T::AccountId::default()2151                } else {2152                    <Collection<T>>::get(collection_id).sponsor2153                }2154            }21552156            _ => T::AccountId::default(),2157        };21582159        // Sponsor smart contracts2160        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {21612162            // On instantiation: set the contract owner2163            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {21642165                let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2166                    code_hash,2167                    &data,2168                    &who,2169                );2170                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());21712172                T::AccountId::default()2173            },21742175            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2176            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {21772178                let mut sp = T::AccountId::default();2179                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());2180                if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2181                    if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2182                        sp = called_contract;2183                    }2184                }21852186                sp2187            },21882189            _ => sponsor,2190        };21912192        let mut who_pays_fee: T::AccountId = sponsor.clone();2193        if sponsor == T::AccountId::default() {2194            who_pays_fee = who.clone();2195        }21962197        // Only mess with balances if fee is not zero.2198        if fee.is_zero() {2199            return Ok((fee, None));2200        }22012202        match <T as transaction_payment::Trait>::Currency::withdraw(2203            &who_pays_fee,2204            fee,2205            if tip.is_zero() {2206                WithdrawReason::TransactionPayment.into()2207            } else {2208                WithdrawReason::TransactionPayment | WithdrawReason::Tip2209            },2210            ExistenceRequirement::KeepAlive,2211        ) {2212            Ok(imbalance) => Ok((fee, Some(imbalance))),2213            Err(_) => Err(InvalidTransaction::Payment.into()),2214        }2215    }2216}221722182219impl<T: Trait + Send + Sync> SignedExtension2220    for ChargeTransactionPayment<T>2221where2222    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2223    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2224{2225    const IDENTIFIER: &'static str = "ChargeTransactionPayment";2226    type AccountId = T::AccountId;2227    type Call = T::Call;2228    type AdditionalSigned = ();2229    type Pre = (2230        BalanceOf<T>,2231        Self::AccountId,2232        Option<NegativeImbalanceOf<T>>,2233        BalanceOf<T>,2234    );2235    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2236        Ok(())2237    }22382239    fn validate(2240        &self,2241        _who: &Self::AccountId,2242        _call: &Self::Call,2243        _info: &DispatchInfoOf<Self::Call>,2244        _len: usize,2245    ) -> TransactionValidity {2246        Ok(ValidTransaction::default())2247    }22482249    fn pre_dispatch(2250        self,2251        who: &Self::AccountId,2252        call: &Self::Call,2253        info: &DispatchInfoOf<Self::Call>,2254        len: usize,2255    ) -> Result<Self::Pre, TransactionValidityError> {2256        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2257        Ok((self.0, who.clone(), imbalance, fee))2258    }22592260    fn post_dispatch(2261        pre: Self::Pre,2262        info: &DispatchInfoOf<Self::Call>,2263        post_info: &PostDispatchInfoOf<Self::Call>,2264        len: usize,2265        _result: &DispatchResult,2266    ) -> Result<(), TransactionValidityError> {2267        let (tip, who, imbalance, fee) = pre;2268        if let Some(payed) = imbalance {2269            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2270                len as u32, info, post_info, tip,2271            );2272            let refund = fee.saturating_sub(actual_fee);2273            let actual_payment =2274                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2275                    &who, refund,2276                ) {2277                    Ok(refund_imbalance) => {2278                        // The refund cannot be larger than the up front payed max weight.2279                        // `PostDispatchInfo::calc_unspent` guards against such a case.2280                        match payed.offset(refund_imbalance) {2281                            Ok(actual_payment) => actual_payment,2282                            Err(_) => return Err(InvalidTransaction::Payment.into()),2283                        }2284                    }2285                    // We do not recreate the account using the refund. The up front payment2286                    // is gone in that case.2287                    Err(_) => payed,2288                };2289            let imbalances = actual_payment.split(tip);2290            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2291                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2292            );2293        }2294        Ok(())2295    }2296}22972298// #endregion