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

difftreelog

source

pallets/nft/src/lib.rs53.0 KiBsourcehistory
1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use serde::*;56use codec::{Decode, Encode};7pub use frame_support::{8    construct_runtime, decl_event, decl_module, decl_storage,9    dispatch::DispatchResult,10    ensure, parameter_types,11    traits::{12        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,13        Randomness, WithdrawReason,14    },15    weights::{16        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},17        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,18        WeightToFeePolynomial,19    },20    IsSubType, StorageValue,21};2223use frame_system::{self as system, ensure_signed};24use sp_runtime::sp_std::prelude::Vec;25use sp_runtime::{26    traits::{27        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, SaturatedConversion, Saturating,28        SignedExtension, Zero,29    },30    transaction_validity::{31        InvalidTransaction, TransactionPriority, TransactionValidity, TransactionValidityError,32        ValidTransaction,33    },34    FixedPointOperand, FixedU128,35};3637#[cfg(test)]38mod mock;3940#[cfg(test)]41mod tests;4243#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]44#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]45pub enum CollectionMode {46    Invalid,47    // custom data size48    NFT(u32),49    // decimal points50    Fungible(u32),51    // custom data size and decimal points52    ReFungible(u32, u32),53}5455impl Into<u8> for CollectionMode {56    fn into(self) -> u8 {57        match self {58            CollectionMode::Invalid => 0,59            CollectionMode::NFT(_) => 1,60            CollectionMode::Fungible(_) => 2,61            CollectionMode::ReFungible(_, _) => 3,62        }63    }64}6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum AccessMode {69    Normal,70    WhiteList,71}72impl Default for AccessMode {73    fn default() -> Self {74        Self::Normal75    }76}7778impl Default for CollectionMode {79    fn default() -> Self {80        Self::Invalid81    }82}8384#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]85#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]86pub struct Ownership<AccountId> {87    pub owner: AccountId,88    pub fraction: u128,89}9091#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]92#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]93pub struct CollectionType<AccountId> {94    pub owner: AccountId,95    pub mode: CollectionMode,96    pub access: AccessMode,97    pub decimal_points: u32,98    pub name: Vec<u16>,        // 64 include null escape char99    pub description: Vec<u16>, // 256 include null escape char100    pub token_prefix: Vec<u8>, // 16 include null escape char101    pub custom_data_size: u32,102    pub mint_mode: bool,103    pub offchain_schema: Vec<u8>,104    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender105    pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship106}107108#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]109#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]110pub struct CollectionAdminsType<AccountId> {111    pub admin: AccountId,112    pub collection_id: u64,113}114115#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]116#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]117pub struct NftItemType<AccountId> {118    pub collection: u64,119    pub owner: AccountId,120    pub data: Vec<u8>,121}122123#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]124#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]125pub struct FungibleItemType<AccountId> {126    pub collection: u64,127    pub owner: AccountId,128    pub value: u128,129}130131#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]132#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]133pub struct ReFungibleItemType<AccountId> {134    pub collection: u64,135    pub owner: Vec<Ownership<AccountId>>,136    pub data: Vec<u8>,137}138139#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]140#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]141pub struct ApprovePermissions<AccountId> {142    pub approved: AccountId,143    pub amount: u64,144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct VestingItem<AccountId, Moment> {149    pub sender: AccountId,150    pub recipient: AccountId,151    pub collection_id: u64,152    pub item_id: u64,153    pub amount: u64,154    pub vesting_date: Moment,155}156157pub trait Trait: system::Trait {158    type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;159}160161decl_storage! {162    trait Store for Module<T: Trait> as Nft {163164        // Private members165        NextCollectionID: u64;166        CreatedCollectionCount: u64;167        ChainVersion: u64;168        ItemListIndex: map hasher(blake2_128_concat) u64 => u64;169170        pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;171        pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;172        pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;173174        /// Balance owner per collection map175        pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;176177        /// second parameter: item id + owner account id178        pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;179180        /// Item collections181        pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;182        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;183        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;184185        /// Index list186        pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;187188        // Sponsorship189        pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;190        pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;191    }192    add_extra_genesis {193        build(|config: &GenesisConfig<T>| {194			// Modification of storage195            for (_num, _c) in &config.collection {196                <Module<T>>::init_collection(_c);197            }198199            for (_num, _q, _i) in &config.nft_item_id {200                <Module<T>>::init_nft_token(_i);201            }202203            for (_num, _q, _i) in &config.fungible_item_id {204                <Module<T>>::init_fungible_token(_i);205            }206207            for (_num, _q, _i) in &config.refungible_item_id {208                <Module<T>>::init_refungible_token(_i);209            }210		})211    }212}213214decl_event!(215    pub enum Event<T>216    where217        AccountId = <T as system::Trait>::AccountId,218    {219        Created(u64, u8, AccountId),220        ItemCreated(u64, u64),221        ItemDestroyed(u64, u64),222    }223);224225decl_module! {226    pub struct Module<T: Trait> for enum Call where origin: T::Origin {227228        fn deposit_event() = default;229230        fn on_initialize(now: T::BlockNumber) -> Weight {231232            if ChainVersion::get() < 2233            {234                let value = NextCollectionID::get();235                CreatedCollectionCount::put(value);236                ChainVersion::put(2);237            }238239            0240        }241242        // Create collection of NFT with given parameters243        //244        // @param customDataSz size of custom data in each collection item245        // returns collection ID246        #[weight = 0]247        pub fn create_collection(origin,248                                 collection_name: Vec<u16>,249                                 collection_description: Vec<u16>,250                                 token_prefix: Vec<u8>,251                                 mode: CollectionMode) -> DispatchResult {252253            // Anyone can create a collection254            let who = ensure_signed(origin)?;255            let custom_data_size = match mode {256                CollectionMode::NFT(size) => size,257                CollectionMode::ReFungible(size, _) => size,258                _ => 0259            };260261            let decimal_points = match mode {262                CollectionMode::Fungible(points) => points,263                CollectionMode::ReFungible(_, points) => points,264                _ => 0265            };266267            // check params268            ensure!(decimal_points <= 4, "decimal_points parameter must be lower than 4");269270            let mut name = collection_name.to_vec();271            name.push(0);272            ensure!(name.len() <= 64, "Collection name can not be longer than 63 char");273274            let mut description = collection_description.to_vec();275            description.push(0);276            ensure!(name.len() <= 256, "Collection description can not be longer than 255 char");277278            let mut prefix = token_prefix.to_vec();279            prefix.push(0);280            ensure!(prefix.len() <= 16, "Token prefix can not be longer than 15 char");281282            // Generate next collection ID283            let next_id = CreatedCollectionCount::get()284                .checked_add(1)285                .expect("collection id error");286287            CreatedCollectionCount::put(next_id);288289            // Create new collection290            let new_collection = CollectionType {291                owner: who.clone(),292                name: name,293                mode: mode.clone(),294                mint_mode: false,295                access: AccessMode::Normal,296                description: description,297                decimal_points: decimal_points,298                token_prefix: prefix,299                offchain_schema: Vec::new(),300                custom_data_size: custom_data_size,301                sponsor: T::AccountId::default(),302                unconfirmed_sponsor: T::AccountId::default(),303            };304305            // Add new collection to map306            <Collection<T>>::insert(next_id, new_collection);307308            // call event309            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));310311            Ok(())312        }313314        #[weight = 0]315        pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {316317            let sender = ensure_signed(origin)?;318            Self::check_owner_permissions(collection_id, sender)?;319320            // TODO Items remove321            <AddressTokens<T>>::remove_prefix(collection_id);322            <ApprovedList<T>>::remove_prefix(collection_id);323            <Balance<T>>::remove_prefix(collection_id);324            <ItemListIndex>::remove(collection_id);325            <AdminList<T>>::remove(collection_id);326            <Collection<T>>::remove(collection_id);327            <WhiteList<T>>::remove(collection_id);328329            Ok(())330        }331332        #[weight = 0]333        pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{334335            let sender = ensure_signed(origin)?;336            Self::check_owner_or_admin_permissions(collection_id, sender)?;337338            let mut white_list_collection: Vec<T::AccountId>;339            if <WhiteList<T>>::contains_key(collection_id) {340                white_list_collection = <WhiteList<T>>::get(collection_id);341                if !white_list_collection.contains(&address.clone())342                {343                    white_list_collection.push(address.clone());344                }345            }346            else {347                white_list_collection = Vec::new();348                white_list_collection.push(address.clone());349            }350351            <WhiteList<T>>::insert(collection_id, white_list_collection);352            Ok(())353        }354355        #[weight = 0]356        pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{357358            let sender = ensure_signed(origin)?;359            Self::check_owner_or_admin_permissions(collection_id, sender)?;360361            if <WhiteList<T>>::contains_key(collection_id) {362                let mut white_list_collection = <WhiteList<T>>::get(collection_id);363                if white_list_collection.contains(&address.clone())364                {365                    white_list_collection.retain(|i| *i != address.clone());366                    <WhiteList<T>>::insert(collection_id, white_list_collection);367                }368            }369370            Ok(())371        }372373        #[weight = 0]374        pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult375        {376            let sender = ensure_signed(origin)?;377378            Self::check_owner_permissions(collection_id, sender)?;379            let mut target_collection = <Collection<T>>::get(collection_id);380            target_collection.access = mode;381            <Collection<T>>::insert(collection_id, target_collection);382383            Ok(())384        }385386        #[weight = 0]387        pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult388        {389            let sender = ensure_signed(origin)?;390391            Self::check_owner_permissions(collection_id, sender)?;392            let mut target_collection = <Collection<T>>::get(collection_id);393            target_collection.mint_mode = mint_permission;394            <Collection<T>>::insert(collection_id, target_collection);395396            Ok(())397        }398399        #[weight = 0]400        pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {401402            let sender = ensure_signed(origin)?;403            Self::check_owner_permissions(collection_id, sender)?;404            let mut target_collection = <Collection<T>>::get(collection_id);405            target_collection.owner = new_owner;406            <Collection<T>>::insert(collection_id, target_collection);407408            Ok(())409        }410411        #[weight = 0]412        pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {413414            let sender = ensure_signed(origin)?;415            Self::check_owner_or_admin_permissions(collection_id, sender)?;416            let mut admin_arr: Vec<T::AccountId> = Vec::new();417418            if <AdminList<T>>::contains_key(collection_id)419            {420                admin_arr = <AdminList<T>>::get(collection_id);421                ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");422            }423424            admin_arr.push(new_admin_id);425            <AdminList<T>>::insert(collection_id, admin_arr);426427            Ok(())428        }429430        #[weight = 0]431        pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {432433            let sender = ensure_signed(origin)?;434            Self::check_owner_or_admin_permissions(collection_id, sender)?;435436            if <AdminList<T>>::contains_key(collection_id)437            {438                let mut admin_arr = <AdminList<T>>::get(collection_id);439                admin_arr.retain(|i| *i != account_id);440                <AdminList<T>>::insert(collection_id, admin_arr);441            }442443            Ok(())444        }445446        #[weight = 0]447        pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {448449            let sender = ensure_signed(origin)?;450            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");451452            let mut target_collection = <Collection<T>>::get(collection_id);453            ensure!(sender == target_collection.owner, "You do not own this collection");454455            target_collection.unconfirmed_sponsor = new_sponsor;456            <Collection<T>>::insert(collection_id, target_collection);457458            Ok(())459        }460461        #[weight = 0]462        pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {463464            let sender = ensure_signed(origin)?;465            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");466467            let mut target_collection = <Collection<T>>::get(collection_id);468            ensure!(sender == target_collection.unconfirmed_sponsor, "This address is not set as sponsor, use setCollectionSponsor first");469470            target_collection.sponsor = target_collection.unconfirmed_sponsor;471            target_collection.unconfirmed_sponsor = T::AccountId::default();472            <Collection<T>>::insert(collection_id, target_collection);473474            Ok(())475        }476477        #[weight = 0]478        pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {479480            let sender = ensure_signed(origin)?;481            ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");482483            let mut target_collection = <Collection<T>>::get(collection_id);484            ensure!(sender == target_collection.owner, "You do not own this collection");485486            target_collection.sponsor = T::AccountId::default();487            <Collection<T>>::insert(collection_id, target_collection);488489            Ok(())490        }491492        #[weight = 0]493        pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {494495            let sender = ensure_signed(origin)?;496            Self::collection_exists(collection_id)?;497            let target_collection = <Collection<T>>::get(collection_id);498499            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {500                ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");501                Self::check_white_list(collection_id, owner.clone())?;502            }503504            match target_collection.mode505            {506                CollectionMode::NFT(_) => {507508                    // check size509                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");510511                    // Create nft item512                    let item = NftItemType {513                        collection: collection_id,514                        owner: owner,515                        data: properties,516                    };517518                    Self::add_nft_item(item)?;519520                },521                CollectionMode::Fungible(_) => {522523                    // check size524                    ensure!(properties.len() as u32 == 0, "Size of item must be 0 with fungible type");525526                    let item = FungibleItemType {527                        collection: collection_id,528                        owner: owner,529                        value: (10 as u128).pow(target_collection.decimal_points)530                    };531532                    Self::add_fungible_item(item)?;533                },534                CollectionMode::ReFungible(_, _) => {535536                    // check size537                    ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");538539                    let mut owner_list = Vec::new();540                    let value = (10 as u128).pow(target_collection.decimal_points);541                    owner_list.push(Ownership {owner: owner, fraction: value});542543                    let item = ReFungibleItemType {544                        collection: collection_id,545                        owner: owner_list,546                        data: properties547                    };548549                    Self::add_refungible_item(item)?;550                },551                _ => ()552            };553554            // call event555            Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));556557            Ok(())558        }559560        #[weight = 0]561        pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {562563            let sender = ensure_signed(origin)?;564            Self::collection_exists(collection_id)?;565            let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);566            if !item_owner567            {568                if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {  569                    Self::check_white_list(collection_id, sender.clone())?;570                }571            }572            let target_collection = <Collection<T>>::get(collection_id);573574            match target_collection.mode575            {576                CollectionMode::NFT(_) => Self::burn_nft_item(collection_id, item_id)?,577                CollectionMode::Fungible(_)  => Self::burn_fungible_item(collection_id, item_id)?,578                CollectionMode::ReFungible(_, _)  => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,579                _ => ()580            };581582            // call event583            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));584585            Ok(())586        }587588        #[weight = 0]589        pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {590591            let sender = ensure_signed(origin)?;592593            // Check access and mint mode 594            let target_collection = <Collection<T>>::get(collection_id);595            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {596597                Self::check_white_list(collection_id, sender.clone())?;598                Self::check_white_list(collection_id, recipient.clone())?;599                ensure!(target_collection.access == AccessMode::WhiteList, "Collection must have WhiteList access");600                ensure!(target_collection.mint_mode == true, "Collection must be in mint mode");601            }602603            match target_collection.mode604            {605                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,606                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,607                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,608                _ => ()609            };610611            Ok(())612        }613614        #[weight = 0]615        pub fn approve(origin, approved: T::AccountId, collection_id: u64, item_id: u64) -> DispatchResult {616617            let sender = ensure_signed(origin)?;618619            // amount param stub620            let amount = 100000000;621622            let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);623            if !item_owner {624                Self::check_white_list(collection_id, approved.clone())?;625            }626627            let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));628            if list_exists {629630                let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));631                let item_contains = list.iter().any(|i| i.approved == approved);632633                if !item_contains {634                    list.push(ApprovePermissions { approved: approved.clone(), amount: amount });635                    <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);636                }637            } else {638639                let mut list = Vec::new();640                list.push(ApprovePermissions { approved: approved.clone(), amount: amount });641                <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);642            }643644            Ok(())645        }646647        #[weight = 0]648        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {649650            let sender = ensure_signed(origin)?;651            let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));652            ensure!(approved_list_exists, "Only approved addresses can call this method");653654            let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));655            let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());656            ensure!(opt_item.is_some(), "No approve found");657            ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");658659            // Check access and mint mode 660            let target_collection = <Collection<T>>::get(collection_id);661            if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {662663                Self::check_white_list(collection_id, sender.clone())?;664                Self::check_white_list(collection_id, recipient.clone())?;665                ensure!(target_collection.access == AccessMode::WhiteList, "Collection must have WhiteList access");666                ensure!(target_collection.mint_mode == true, "Collection must be in mint mode");667            }668669            // remove approve670            let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))671                .into_iter().filter(|i| i.approved != sender.clone()).collect();672            <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);673674675            match target_collection.mode676            {677                CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, from, recipient)?,678                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,679                CollectionMode::ReFungible(_, _)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,680                _ => ()681            };682683            Ok(())684        }685686        #[weight = 0]687        pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {688689            // let no_perm_mes = "You do not have permissions to modify this collection";690            // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);691            // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));692            // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);693694            // // on_nft_received  call695696            // Self::transfer(origin, collection_id, item_id, new_owner)?;697698            Ok(())699        }700701        #[weight = 0]702        pub fn set_offchain_schema(703            origin,704            collection_id: u64,705            schema: Vec<u8>706        ) -> DispatchResult {707            let sender = ensure_signed(origin)?;708            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;709710            let mut target_collection = <Collection<T>>::get(collection_id);711            target_collection.offchain_schema = schema;712            <Collection<T>>::insert(collection_id, target_collection);713714            Ok(())715        }716    }717}718719impl<T: Trait> Module<T> {720    fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {721        let current_index = <ItemListIndex>::get(item.collection)722            .checked_add(1)723            .expect("Item list index id error");724        let itemcopy = item.clone();725        let owner = item.owner.clone();726        let value = item.value as u64;727728        Self::add_token_index(item.collection, current_index, owner.clone())?;729730        <ItemListIndex>::insert(item.collection, current_index);731        <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);732733        // Update balance734        let new_balance = <Balance<T>>::get(item.collection, owner.clone())735            .checked_add(value)736            .unwrap();737        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);738739        Ok(())740    }741742    fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {743        let current_index = <ItemListIndex>::get(item.collection)744            .checked_add(1)745            .expect("Item list index id error");746        let itemcopy = item.clone();747748        let value = item.owner.first().unwrap().fraction as u64;749        let owner = item.owner.first().unwrap().owner.clone();750751        Self::add_token_index(item.collection, current_index, owner.clone())?;752753        <ItemListIndex>::insert(item.collection, current_index);754        <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);755756        // Update balance757        let new_balance = <Balance<T>>::get(item.collection, owner.clone())758            .checked_add(value)759            .unwrap();760        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);761762        Ok(())763    }764765    fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {766        let current_index = <ItemListIndex>::get(item.collection)767            .checked_add(1)768            .expect("Item list index id error");769770        let item_owner = item.owner.clone();771        let collection_id = item.collection.clone();772        Self::add_token_index(collection_id, current_index, item.owner.clone())?;773774        <ItemListIndex>::insert(collection_id, current_index);775        <NftItemList<T>>::insert(collection_id, current_index, item);776777        // Update balance778        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())779            .checked_add(1)780            .unwrap();781        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);782783        Ok(())784    }785786    fn burn_refungible_item(collection_id: u64, item_id: u64, owner: T::AccountId) -> DispatchResult {787        ensure!(788            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),789            "Item does not exists"790        );791        let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);792        let item = collection793            .owner794            .iter()795            .filter(|&i| i.owner == owner)796            .next()797            .unwrap();798        Self::remove_token_index(collection_id, item_id, owner.clone())?;799800        // remove approve list801        <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));802803        // update balance804        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())805            .checked_sub(item.fraction as u64)806            .unwrap();807        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);808809        <ReFungibleItemList<T>>::remove(collection_id, item_id);810811        Ok(())812    }813814    fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {815        ensure!(816            <NftItemList<T>>::contains_key(collection_id, item_id),817            "Item does not exists"818        );819        let item = <NftItemList<T>>::get(collection_id, item_id);820        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;821822        // remove approve list823        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));824825        // update balance826        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())827            .checked_sub(1)828            .unwrap();829        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);830        <NftItemList<T>>::remove(collection_id, item_id);831832        Ok(())833    }834835    fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {836        ensure!(837            <FungibleItemList<T>>::contains_key(collection_id, item_id),838            "Item does not exists"839        );840        let item = <FungibleItemList<T>>::get(collection_id, item_id);841        Self::remove_token_index(collection_id, item_id, item.owner.clone())?;842843        // remove approve list844        <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));845846        // update balance847        let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())848            .checked_sub(item.value as u64)849            .unwrap();850        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);851852        <FungibleItemList<T>>::remove(collection_id, item_id);853854        Ok(())855    }856857    fn collection_exists(collection_id: u64) -> DispatchResult {858        ensure!(859            <Collection<T>>::contains_key(collection_id),860            "This collection does not exist"861        );862        Ok(())863    }864865    fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {866        Self::collection_exists(collection_id)?;867868        let target_collection = <Collection<T>>::get(collection_id);869        ensure!(870            subject == target_collection.owner,871            "You do not own this collection"872        );873874        Ok(())875    }876877    fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {878879        let target_collection = <Collection<T>>::get(collection_id);880        let mut result: bool = subject == target_collection.owner;881        let exists = <AdminList<T>>::contains_key(collection_id);882883        if !result & exists {884            if <AdminList<T>>::get(collection_id).contains(&subject) {885                result = true886            }887        }888889        result890    }891892    fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {893        894        Self::collection_exists(collection_id)?;895        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());896897        ensure!(result, "You do not have permissions to modify this collection");898        Ok(())899    }900901    fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {902        let target_collection = <Collection<T>>::get(collection_id);903904        match target_collection.mode {905            CollectionMode::NFT(_) => {906                <NftItemList<T>>::get(collection_id, item_id).owner == subject907            }908            CollectionMode::Fungible(_) => {909                <FungibleItemList<T>>::get(collection_id, item_id).owner == subject910            }911            CollectionMode::ReFungible(_, _) => {912                <ReFungibleItemList<T>>::get(collection_id, item_id)913                    .owner914                    .iter()915                    .any(|i| i.owner == subject)916            }917            CollectionMode::Invalid => false,918        }919    }920921    fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {922923        let mes = "Address is not in white list";924        ensure!(<WhiteList<T>>::contains_key(collection_id), mes);925        let wl = <WhiteList<T>>::get(collection_id);926        ensure!(wl.contains(&address.clone()), mes);927928        Ok(())929    }930931    fn transfer_fungible(932        collection_id: u64,933        item_id: u64,934        value: u64,935        owner: T::AccountId,936        new_owner: T::AccountId,937    ) -> DispatchResult {938939        ensure!(940            <FungibleItemList<T>>::contains_key(collection_id, item_id),941            "Item not exists"942        );943944        let full_item = <FungibleItemList<T>>::get(collection_id, item_id);945        let amount = full_item.value;946947        ensure!(amount >= value.into(), "Item balance not enouth");948949        // update balance950        let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())951            .checked_sub(value)952            .unwrap();953        <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);954955        let mut new_owner_account_id = 0;956        let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());957        if new_owner_items.len() > 0 {958            new_owner_account_id = new_owner_items[0];959        }960961        let val64 = value.into();962963        // transfer964        if amount == val64 && new_owner_account_id == 0 {965            // change owner966            // new owner do not have account967            let mut new_full_item = full_item.clone();968            new_full_item.owner = new_owner.clone();969            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);970971            // update balance972            let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())973                .checked_add(value)974                .unwrap();975            <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);976977            // update index collection978            Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;979        } else {980            let mut new_full_item = full_item.clone();981            new_full_item.value -= val64;982983            // separate amount984            if new_owner_account_id > 0 {985                // new owner has account986                let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);987                item.value += val64;988989                // update balance990                let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())991                    .checked_add(value)992                    .unwrap();993                <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);994995                <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);996            } else {997                // new owner do not have account998                let item = FungibleItemType {999                    collection: collection_id,1000                    owner: new_owner.clone(),1001                    value: val64,1002                };10031004                Self::add_fungible_item(item)?;1005            }10061007            if amount == val64 {1008                Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;10091010                // remove approve list1011                <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1012                <FungibleItemList<T>>::remove(collection_id, item_id);1013            }10141015            <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1016        }10171018        Ok(())1019    }10201021    fn transfer_refungible(1022        collection_id: u64,1023        item_id: u64,1024        value: u64,1025        owner: T::AccountId,1026        new_owner: T::AccountId,1027    ) -> DispatchResult {10281029        ensure!(1030            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1031            "Item not exists"1032        );10331034        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1035        let item = full_item1036            .owner1037            .iter()1038            .filter(|i| i.owner == owner)1039            .next()1040            .unwrap();1041        let amount = item.fraction;10421043        ensure!(amount >= value.into(), "Item balance not enouth");10441045        // update balance1046        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1047            .checked_sub(value)1048            .unwrap();1049        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);10501051        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1052            .checked_add(value)1053            .unwrap();1054        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);10551056        let old_owner = item.owner.clone();1057        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1058        let val64 = value.into();10591060        // transfer1061        if amount == val64 && !new_owner_has_account {1062            // change owner1063            // new owner do not have account1064            let mut new_full_item = full_item.clone();1065            new_full_item1066                .owner1067                .iter_mut()1068                .find(|i| i.owner == owner)1069                .unwrap()1070                .owner = new_owner.clone();1071            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);10721073            // update index collection1074            Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1075        } else {1076            let mut new_full_item = full_item.clone();1077            new_full_item1078                .owner1079                .iter_mut()1080                .find(|i| i.owner == owner)1081                .unwrap()1082                .fraction -= val64;10831084            // separate amount1085            if new_owner_has_account {1086                // new owner has account1087                new_full_item1088                    .owner1089                    .iter_mut()1090                    .find(|i| i.owner == new_owner)1091                    .unwrap()1092                    .fraction += val64;1093            } else {1094                // new owner do not have account1095                new_full_item.owner.push(Ownership {1096                    owner: new_owner.clone(),1097                    fraction: val64,1098                });1099                Self::add_token_index(collection_id, item_id, new_owner.clone())?;1100            }11011102            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1103        }11041105        Ok(())1106    }11071108    fn transfer_nft(1109        collection_id: u64,1110        item_id: u64,1111        sender: T::AccountId,1112        new_owner: T::AccountId,1113    ) -> DispatchResult {1114    1115        ensure!(1116            <NftItemList<T>>::contains_key(collection_id, item_id),1117            "Item not exists"1118        );11191120        let mut item = <NftItemList<T>>::get(collection_id, item_id);11211122        ensure!(1123            sender == item.owner,1124            "sender parameter and item owner must be equal"1125        );11261127        // update balance1128        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1129            .checked_sub(1)1130            .unwrap();1131        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);11321133        let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1134            .checked_add(1)1135            .unwrap();1136        <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);11371138        // change owner1139        let old_owner = item.owner.clone();1140        item.owner = new_owner.clone();1141        <NftItemList<T>>::insert(collection_id, item_id, item);11421143        // update index collection1144        Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;11451146        // reset approved list1147        <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1148        Ok(())1149    }11501151    fn init_collection(item: &CollectionType<T::AccountId>){11521153                // check params1154                assert!(item.decimal_points <= 4, "decimal_points parameter must be lower than 4");1155                assert!(item.name.len() <= 64, "Collection name can not be longer than 63 char");1156                assert!(item.name.len() <= 256, "Collection description can not be longer than 255 char");1157                assert!(item.token_prefix.len() <= 16, "Token prefix can not be longer than 15 char");1158    1159                // Generate next collection ID1160                let next_id = CreatedCollectionCount::get()1161                    .checked_add(1)1162                    .expect("collection id error");1163    1164                CreatedCollectionCount::put(next_id);  1165    }11661167    fn init_nft_token(item: &NftItemType<T::AccountId>){11681169        let current_index = <ItemListIndex>::get(item.collection)1170            .checked_add(1)1171            .expect("Item list index id error");11721173        let item_owner = item.owner.clone();1174        let collection_id = item.collection.clone();1175        Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();11761177        <ItemListIndex>::insert(collection_id, current_index);11781179        // Update balance1180        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1181            .checked_add(1)1182            .unwrap();1183        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);1184    }11851186    fn init_fungible_token(item: &FungibleItemType<T::AccountId>){11871188        let current_index = <ItemListIndex>::get(item.collection)1189            .checked_add(1)1190            .expect("Item list index id error");1191        let owner = item.owner.clone();1192        let value = item.value as u64;11931194        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();11951196        <ItemListIndex>::insert(item.collection, current_index);11971198        // Update balance1199        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1200            .checked_add(value)1201            .unwrap();1202        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1203    }12041205    fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>){12061207        let current_index = <ItemListIndex>::get(item.collection)1208            .checked_add(1)1209            .expect("Item list index id error");12101211        let value = item.owner.first().unwrap().fraction as u64;1212        let owner = item.owner.first().unwrap().owner.clone();12131214        Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();12151216        <ItemListIndex>::insert(item.collection, current_index);12171218        // Update balance1219        let new_balance = <Balance<T>>::get(item.collection, owner.clone())1220            .checked_add(value)1221            .unwrap();1222        <Balance<T>>::insert(item.collection, owner.clone(), new_balance);1223    }12241225    fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {1226        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1227        if list_exists {1228            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1229            let item_contains = list.contains(&item_index.clone());12301231            if !item_contains {1232                list.push(item_index.clone());1233            }12341235            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);1236        } else {1237            let mut itm = Vec::new();1238            itm.push(item_index.clone());1239            <AddressTokens<T>>::insert(collection_id, owner, itm);1240        }12411242        Ok(())1243    }12441245    fn remove_token_index(1246        collection_id: u64,1247        item_index: u64,1248        owner: T::AccountId,1249    ) -> DispatchResult {1250        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());1251        if list_exists {1252            let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());1253            let item_contains = list.contains(&item_index.clone());12541255            if item_contains {1256                list.retain(|&item| item != item_index);1257                <AddressTokens<T>>::insert(collection_id, owner, list);1258            }1259        }12601261        Ok(())1262    }12631264    fn move_token_index(1265        collection_id: u64,1266        item_index: u64,1267        old_owner: T::AccountId,1268        new_owner: T::AccountId,1269    ) -> DispatchResult {1270        Self::remove_token_index(collection_id, item_index, old_owner)?;1271        Self::add_token_index(collection_id, item_index, new_owner)?;12721273        Ok(())1274    }1275}12761277////////////////////////////////////////////////////////////////////////////////////////////////////1278// Economic models12791280/// Fee multiplier.1281pub type Multiplier = FixedU128;12821283type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1284    <T as system::Trait>::AccountId,1285>>::Balance;1286type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<1287    <T as system::Trait>::AccountId,1288>>::NegativeImbalance;12891290/// Require the transactor pay for themselves and maybe include a tip to gain additional priority1291/// in the queue.1292#[derive(Encode, Decode, Clone, Eq, PartialEq)]1293pub struct ChargeTransactionPayment<T: transaction_payment::Trait + Send + Sync>(1294    #[codec(compact)] BalanceOf<T>,1295);12961297impl<T: Trait + transaction_payment::Trait + Send + Sync> sp_std::fmt::Debug1298    for ChargeTransactionPayment<T>1299{1300    #[cfg(feature = "std")]1301    fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1302        write!(f, "ChargeTransactionPayment<{:?}>", self.0)1303    }1304    #[cfg(not(feature = "std"))]1305    fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {1306        Ok(())1307    }1308}13091310impl<T: Trait + transaction_payment::Trait + Send + Sync> ChargeTransactionPayment<T>1311where1312    T::Call:1313        Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1314    BalanceOf<T>: Send + Sync + FixedPointOperand,1315{1316    /// utility constructor. Used only in client/factory code.1317    pub fn from(fee: BalanceOf<T>) -> Self {1318        Self(fee)1319    }13201321    pub fn traditional_fee(1322        len: usize,1323        info: &DispatchInfoOf<T::Call>,1324        tip: BalanceOf<T>,1325    ) -> BalanceOf<T>1326    where1327        T::Call: Dispatchable<Info = DispatchInfo>,1328    {1329        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)1330    }13311332    fn withdraw_fee(1333        &self,1334        who: &T::AccountId,1335        call: &T::Call,1336        info: &DispatchInfoOf<T::Call>,1337        len: usize,1338    ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {1339        let tip = self.0;13401341        // Set fee based on call type. Creating collection costs 1 Unique.1342        // All other transactions have traditional fees so far1343        let fee = match call.is_sub_type() {1344            Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),1345            _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes1346                                                        // _ => <BalanceOf<T>>::from(100)1347        };13481349        // Determine who is paying transaction fee based on ecnomic model1350        // Parse call to extract collection ID and access collection sponsor1351        let sponsor: T::AccountId = match call.is_sub_type() {1352            Some(Call::create_item(collection_id, _properties, _owner)) => {1353                <Collection<T>>::get(collection_id).sponsor1354            }1355            Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {1356                <Collection<T>>::get(collection_id).sponsor1357            }13581359            _ => T::AccountId::default(),1360        };13611362        let mut who_pays_fee: T::AccountId = sponsor.clone();1363        if sponsor == T::AccountId::default() {1364            who_pays_fee = who.clone();1365        }13661367        // Only mess with balances if fee is not zero.1368        if fee.is_zero() {1369            return Ok((fee, None));1370        }13711372        match <T as transaction_payment::Trait>::Currency::withdraw(1373            &who_pays_fee,1374            fee,1375            if tip.is_zero() {1376                WithdrawReason::TransactionPayment.into()1377            } else {1378                WithdrawReason::TransactionPayment | WithdrawReason::Tip1379            },1380            ExistenceRequirement::KeepAlive,1381        ) {1382            Ok(imbalance) => Ok((fee, Some(imbalance))),1383            Err(_) => Err(InvalidTransaction::Payment.into()),1384        }1385    }1386}13871388impl<T: Trait + transaction_payment::Trait + Send + Sync> SignedExtension1389    for ChargeTransactionPayment<T>1390where1391    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,1392    T::Call:1393        Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Module<T>, T>,1394{1395    const IDENTIFIER: &'static str = "ChargeTransactionPayment";1396    type AccountId = T::AccountId;1397    type Call = T::Call;1398    type AdditionalSigned = ();1399    type Pre = (1400        BalanceOf<T>,1401        Self::AccountId,1402        Option<NegativeImbalanceOf<T>>,1403        BalanceOf<T>,1404    );1405    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {1406        Ok(())1407    }14081409    fn validate(1410        &self,1411        who: &Self::AccountId,1412        call: &Self::Call,1413        info: &DispatchInfoOf<Self::Call>,1414        len: usize,1415    ) -> TransactionValidity {1416        let (fee, _) = self.withdraw_fee(who, call, info, len)?;14171418        let mut r = ValidTransaction::default();1419        // NOTE: we probably want to maximize the _fee (of any type) per weight unit_ here, which1420        // will be a bit more than setting the priority to tip. For now, this is enough.1421        r.priority = fee.saturated_into::<TransactionPriority>();1422        Ok(r)1423    }14241425    fn pre_dispatch(1426        self,1427        who: &Self::AccountId,1428        call: &Self::Call,1429        info: &DispatchInfoOf<Self::Call>,1430        len: usize,1431    ) -> Result<Self::Pre, TransactionValidityError> {1432        let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;1433        Ok((self.0, who.clone(), imbalance, fee))1434    }14351436    fn post_dispatch(1437        pre: Self::Pre,1438        info: &DispatchInfoOf<Self::Call>,1439        post_info: &PostDispatchInfoOf<Self::Call>,1440        len: usize,1441        _result: &DispatchResult,1442    ) -> Result<(), TransactionValidityError> {1443        let (tip, who, imbalance, fee) = pre;1444        if let Some(payed) = imbalance {1445            let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(1446                len as u32, info, post_info, tip,1447            );1448            let refund = fee.saturating_sub(actual_fee);1449            let actual_payment =1450                match <T as transaction_payment::Trait>::Currency::deposit_into_existing(1451                    &who, refund,1452                ) {1453                    Ok(refund_imbalance) => {1454                        // The refund cannot be larger than the up front payed max weight.1455                        // `PostDispatchInfo::calc_unspent` guards against such a case.1456                        match payed.offset(refund_imbalance) {1457                            Ok(actual_payment) => actual_payment,1458                            Err(_) => return Err(InvalidTransaction::Payment.into()),1459                        }1460                    }1461                    // We do not recreate the account using the refund. The up front payment1462                    // is gone in that case.1463                    Err(_) => payed,1464                };1465            let imbalances = actual_payment.split(tip);1466            <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(1467                Some(imbalances.0).into_iter().chain(Some(imbalances.1)),1468            );1469        }1470        Ok(())1471    }1472}