git.delta.rocks / unique-network / refs/commits / 9e6c0bc65705

difftreelog

Resolve conflict in runtime_types

Greg Zaitsev2021-02-09parents: #c311337 #2109c86.patch.diff
in: master

32 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
before · pallets/nft/src/lib.rs
1//2// This file is subject to the terms and conditions defined in3// file 'LICENSE', which is part of this source code package.4//56#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18    construct_runtime, decl_event, decl_module, decl_storage, decl_error,19    dispatch::DispatchResult,20    ensure, fail, parameter_types,21    traits::{22        Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23        Randomness, IsSubType,24    },25    weights::{26        constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27        DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28        WeightToFeePolynomial, DispatchClass,29    },30    StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36    traits::{37        DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38    },39    transaction_validity::{40        TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41    },42    FixedPointOperand, FixedU128,43};44use sp_runtime::traits::StaticLookup;45use pallet_contracts::chain_extension::UncheckedFrom;46use transaction_payment::OnChargeTransaction;4748#[cfg(test)]49mod mock;5051#[cfg(test)]52mod tests;5354mod default_weights;5556pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;57pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;58pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5960// Structs61// #region6263pub type CollectionId = u32;64pub type TokenId = u32;65pub type DecimalPoints = u8;6667#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]68#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]69pub enum CollectionMode {70    Invalid,71    NFT,72    // decimal points73    Fungible(DecimalPoints),74    // decimal points75    ReFungible(DecimalPoints),76}7778impl Default for CollectionMode {79    fn default() -> Self {80        Self::Invalid81    }82}8384impl Into<u8> for CollectionMode {85    fn into(self) -> u8 {86        match self {87            CollectionMode::Invalid => 0,88            CollectionMode::NFT => 1,89            CollectionMode::Fungible(_) => 2,90            CollectionMode::ReFungible(_) => 3,91        }92    }93}9495#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub enum AccessMode {98    Normal,99    WhiteList,100}101impl Default for AccessMode {102    fn default() -> Self {103        Self::Normal104    }105}106107#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]108#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]109pub enum SchemaVersion {110    ImageURL,111    Unique,112}113impl Default for SchemaVersion {114    fn default() -> Self {115        Self::ImageURL116    }117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct Ownership<AccountId> {122    pub owner: AccountId,123    pub fraction: u128,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct CollectionType<AccountId> {129    pub owner: AccountId,130    pub mode: CollectionMode,131    pub access: AccessMode,132    pub decimal_points: DecimalPoints,133    pub name: Vec<u16>,        // 64 include null escape char134    pub description: Vec<u16>, // 256 include null escape char135    pub token_prefix: Vec<u8>, // 16 include null escape char136    pub mint_mode: bool,137    pub offchain_schema: Vec<u8>,138    pub schema_version: SchemaVersion,139    pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender140    pub sponsor_confirmed: bool, // False if sponsor address has not yet confirmed sponsorship. True otherwise.141    pub limits: CollectionLimits, // Collection private restrictions 142    pub variable_on_chain_schema: Vec<u8>, //143    pub const_on_chain_schema: Vec<u8>, //144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct NftItemType<AccountId> {149    pub owner: AccountId,150    pub const_data: Vec<u8>,151    pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType {157    pub value: u128,158}159160#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]161#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]162pub struct ReFungibleItemType<AccountId> {163    pub owner: Vec<Ownership<AccountId>>,164    pub const_data: Vec<u8>,165    pub variable_data: Vec<u8>,166}167168// #[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]169// #[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170// pub struct VestingItem<AccountId, Moment> {171//     pub sender: AccountId,172//     pub recipient: AccountId,173//     pub collection_id: CollectionId,174//     pub item_id: TokenId,175//     pub amount: u64,176//     pub vesting_date: Moment,177// }178179#[derive(Encode, Decode, Debug, Clone, PartialEq)]180#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]181pub struct CollectionLimits {182    pub account_token_ownership_limit: u32,183    pub sponsored_data_size: u32,184    pub token_limit: u32,185186    // Timeouts for item types in passed blocks187    pub sponsor_transfer_timeout: u32,188    pub owner_can_transfer: bool,189    pub owner_can_destroy: bool,190}191192impl Default for CollectionLimits {193    fn default() -> CollectionLimits {194        CollectionLimits { 195            account_token_ownership_limit: 10_000_000, 196            token_limit: u32::max_value(),197            sponsored_data_size: u32::max_value(), 198            sponsor_transfer_timeout: 14400,199            owner_can_transfer: true,200            owner_can_destroy: true201        }202    }203}204205#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]206#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]207pub struct ChainLimits {208    pub collection_numbers_limit: u32,209    pub account_token_ownership_limit: u32,210    pub collections_admins_limit: u64,211    pub custom_data_limit: u32,212213    // Timeouts for item types in passed blocks214    pub nft_sponsor_transfer_timeout: u32,215    pub fungible_sponsor_transfer_timeout: u32,216    pub refungible_sponsor_transfer_timeout: u32,217218    // Schema limits219    pub offchain_schema_limit: u32,220    pub variable_on_chain_schema_limit: u32,221    pub const_on_chain_schema_limit: u32,222}223224pub trait WeightInfo {225	fn create_collection() -> Weight;226	fn destroy_collection() -> Weight;227	fn add_to_white_list() -> Weight;228	fn remove_from_white_list() -> Weight;229    fn set_public_access_mode() -> Weight;230    fn set_mint_permission() -> Weight;231    fn change_collection_owner() -> Weight;232    fn add_collection_admin() -> Weight;233    fn remove_collection_admin() -> Weight;234    fn set_collection_sponsor() -> Weight;235    fn confirm_sponsorship() -> Weight;236    fn remove_collection_sponsor() -> Weight;237    fn create_item(s: usize) -> Weight;238    fn burn_item() -> Weight;239    fn transfer() -> Weight;240    fn approve() -> Weight;241    fn transfer_from() -> Weight;242    fn set_offchain_schema() -> Weight;243    fn set_const_on_chain_schema() -> Weight;244    fn set_variable_on_chain_schema() -> Weight;245    fn set_variable_meta_data() -> Weight;246    fn enable_contract_sponsoring() -> Weight;247    fn set_schema_version() -> Weight;248    fn set_chain_limits() -> Weight;249    fn set_contract_sponsoring_rate_limit() -> Weight;250    fn toggle_contract_white_list() -> Weight;251    fn add_to_contract_white_list() -> Weight;252    fn remove_from_contract_white_list() -> Weight;253    fn set_collection_limits() -> Weight;254}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259    pub const_data: Vec<u8>,260    pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266    pub value: u128,267}268269#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]270#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]271pub struct CreateReFungibleData {272    pub const_data: Vec<u8>,273    pub variable_data: Vec<u8>,274}275276#[derive(Encode, Decode, Debug, Clone, PartialEq)]277#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]278pub enum CreateItemData {279    NFT(CreateNftData),280    Fungible(CreateFungibleData),281    ReFungible(CreateReFungibleData),282}283284impl CreateItemData {285    pub fn len(&self) -> usize {286        let len = match self {287            CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),288            CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),289            _ => 0290        };291        292        return len;293    }294}295296impl From<CreateNftData> for CreateItemData {297    fn from(item: CreateNftData) -> Self {298        CreateItemData::NFT(item)299    }300}301302impl From<CreateReFungibleData> for CreateItemData {303    fn from(item: CreateReFungibleData) -> Self {304        CreateItemData::ReFungible(item)305    }306}307308impl From<CreateFungibleData> for CreateItemData {309    fn from(item: CreateFungibleData) -> Self {310        CreateItemData::Fungible(item)311    }312}313314315decl_error! {316	/// Error for non-fungible-token module.317	pub enum Error for Module<T: Config> {318        /// Total collections bound exceeded.319        TotalCollectionsLimitExceeded,320		/// Decimal_points parameter must be lower than MAX_DECIMAL_POINTS constant, currently it is 30.321        CollectionDecimalPointLimitExceeded, 322        /// Collection name can not be longer than 63 char.323        CollectionNameLimitExceeded, 324        /// Collection description can not be longer than 255 char.325        CollectionDescriptionLimitExceeded, 326        /// Token prefix can not be longer than 15 char.327        CollectionTokenPrefixLimitExceeded,328        /// This collection does not exist.329        CollectionNotFound,330        /// Item not exists.331        TokenNotFound,332        /// Admin not found333        AdminNotFound,334        /// Arithmetic calculation overflow.335        NumOverflow,       336        /// Account already has admin role.337        AlreadyAdmin,  338        /// You do not own this collection.339        NoPermission,340        /// This address is not set as sponsor, use setCollectionSponsor first.341        ConfirmUnsetSponsorFail,342        /// Collection is not in mint mode.343        PublicMintingNotAllowed,344        /// Sender parameter and item owner must be equal.345        MustBeTokenOwner,346        /// Item balance not enough.347        TokenValueTooLow,348        /// Size of item is too large.349        NftSizeLimitExceeded,350        /// No approve found351        ApproveNotFound,352        /// Requested value more than approved.353        TokenValueNotEnough,354        /// Only approved addresses can call this method.355        ApproveRequired,356        /// Address is not in white list.357        AddresNotInWhiteList,358        /// Number of collection admins bound exceeded.359        CollectionAdminsLimitExceeded,360        /// Owned tokens by a single address bound exceeded.361        AddressOwnershipLimitExceeded,362        /// Length of items properties must be greater than 0.363        EmptyArgument,364        /// const_data exceeded data limit.365        TokenConstDataLimitExceeded,366        /// variable_data exceeded data limit.367        TokenVariableDataLimitExceeded,368        /// Not NFT item data used to mint in NFT collection.369        NotNftDataUsedToMintNftCollectionToken,370        /// Not Fungible item data used to mint in Fungible collection.371        NotFungibleDataUsedToMintFungibleCollectionToken,372        /// Not Re Fungible item data used to mint in Re Fungible collection.373        NotReFungibleDataUsedToMintReFungibleCollectionToken,374        /// Unexpected collection type.375        UnexpectedCollectionType,376        /// Can't store metadata in fungible tokens.377        CantStoreMetadataInFungibleTokens,378        /// Collection token limit exceeded379        CollectionTokenLimitExceeded,380        /// Account token limit exceeded per collection381        AccountTokenLimitExceeded,382        /// Collection limit bounds per collection exceeded383        CollectionLimitBoundsExceeded,384        /// Schema data size limit bound exceeded385        SchemaDataLimitExceeded386	}387}388389pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config {390    type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;391392    /// Weight information for extrinsics in this pallet.393	type WeightInfo: WeightInfo;394}395396#[cfg(feature = "runtime-benchmarks")]397mod benchmarking;398399// #endregion400401decl_storage! {402    trait Store for Module<T: Config> as Nft {403404        // Private members405        NextCollectionID: CollectionId;406        CreatedCollectionCount: u32;407        ChainVersion: u64;408        ItemListIndex: map hasher(identity) CollectionId => TokenId;409410        // Chain limits struct411        pub ChainLimit get(fn chain_limit) config(): ChainLimits;412413        // Bound counters414        CollectionCount: u32;415        pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;416417        // Basic collections418        pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;419        pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;420        pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;421422        /// Balance owner per collection map423        pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;424425        /// second parameter: item id + owner account id + spender account id426        pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;427428        /// Item collections429        pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;430        pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;431        pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;432433        /// Index list434        pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;435436        /// Tokens transfer baskets437        pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;438        pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;439        pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;440        pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;441442        // Contract Sponsorship and Ownership443        pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;444        pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;445        pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;446        pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;447        pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 448        pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 449    }450    add_extra_genesis {451        build(|config: &GenesisConfig<T>| {452            // Modification of storage453            for (_num, _c) in &config.collection {454                <Module<T>>::init_collection(_c);455            }456457            for (_num, _c, _i) in &config.nft_item_id {458                <Module<T>>::init_nft_token(*_c, _i);459            }460461            for (collection_id, account_id, fungible_item) in &config.fungible_item_id {462                <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);463            }464465            for (_num, _c, _i) in &config.refungible_item_id {466                <Module<T>>::init_refungible_token(*_c, _i);467            }468        })469    }470}471472decl_event!(473    pub enum Event<T>474    where475        AccountId = <T as system::Config>::AccountId,476    {477        /// New collection was created478        /// 479        /// # Arguments480        /// 481        /// * collection_id: Globally unique identifier of newly created collection.482        /// 483        /// * mode: [CollectionMode] converted into u8.484        /// 485        /// * account_id: Collection owner.486        Created(CollectionId, u8, AccountId),487488        /// New item was created.489        /// 490        /// # Arguments491        /// 492        /// * collection_id: Id of the collection where item was created.493        /// 494        /// * item_id: Id of an item. Unique within the collection.495        ItemCreated(CollectionId, TokenId),496497        /// Collection item was burned.498        /// 499        /// # Arguments500        /// 501        /// collection_id.502        /// 503        /// item_id: Identifier of burned NFT.504        ItemDestroyed(CollectionId, TokenId),505    }506);507508decl_module! {509    pub struct Module<T: Config> for enum Call 510    where 511        origin: T::Origin512    {513        fn deposit_event() = default;514        type Error = Error<T>;515516        fn on_initialize(now: T::BlockNumber) -> Weight {517518            if ChainVersion::get() < 2519            {520                let value = NextCollectionID::get();521                CreatedCollectionCount::put(value);522                ChainVersion::put(2);523            }524525            0526        }527528        /// 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.529        /// 530        /// # Permissions531        /// 532        /// * Anyone.533        /// 534        /// # Arguments535        /// 536        /// * collection_name: UTF-16 string with collection name (limit 64 characters), will be stored as zero-terminated.537        /// 538        /// * collection_description: UTF-16 string with collection description (limit 256 characters), will be stored as zero-terminated.539        /// 540        /// * token_prefix: UTF-8 string with token prefix.541        /// 542        /// * mode: [CollectionMode] collection type and type dependent data.543        // returns collection ID544        #[weight = <T as Config>::WeightInfo::create_collection()]545        pub fn create_collection(origin,546                                 collection_name: Vec<u16>,547                                 collection_description: Vec<u16>,548                                 token_prefix: Vec<u8>,549                                 mode: CollectionMode) -> DispatchResult {550551            // Anyone can create a collection552            let who = ensure_signed(origin)?;553554            let decimal_points = match mode {555                CollectionMode::Fungible(points) => points,556                CollectionMode::ReFungible(points) => points,557                _ => 0558            };559560            // bound Total number of collections561            ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);562563            // check params564            ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);565            ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);566            ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);567            ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);568569            // Generate next collection ID570            let next_id = CreatedCollectionCount::get()571                .checked_add(1)572                .ok_or(Error::<T>::NumOverflow)?;573574            // bound counter575            let total = CollectionCount::get()576                .checked_add(1)577                .ok_or(Error::<T>::NumOverflow)?;578579            CreatedCollectionCount::put(next_id);580            CollectionCount::put(total);581582            // Create new collection583            let new_collection = CollectionType {584                owner: who.clone(),585                name: collection_name,586                mode: mode.clone(),587                mint_mode: false,588                access: AccessMode::Normal,589                description: collection_description,590                decimal_points: decimal_points,591                token_prefix: token_prefix,592                offchain_schema: Vec::new(),593                schema_version: SchemaVersion::ImageURL,594                sponsor: T::AccountId::default(),595                sponsor_confirmed: false,596                variable_on_chain_schema: Vec::new(),597                const_on_chain_schema: Vec::new(),598                limits: CollectionLimits::default()599            };600601            // Add new collection to map602            <Collection<T>>::insert(next_id, new_collection);603604            // call event605            Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));606607            Ok(())608        }609610        /// **DANGEROUS**: Destroys collection and all NFTs within this collection. Users irrecoverably lose their assets and may lose real money.611        /// 612        /// # Permissions613        /// 614        /// * Collection Owner.615        /// 616        /// # Arguments617        /// 618        /// * collection_id: collection to destroy.619        #[weight = <T as Config>::WeightInfo::destroy_collection()]620        pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {621622            let sender = ensure_signed(origin)?;623            Self::check_owner_permissions(collection_id, sender)?;624625            <AddressTokens<T>>::remove_prefix(collection_id);626            <Allowances<T>>::remove_prefix(collection_id);627            <Balance<T>>::remove_prefix(collection_id);628            <ItemListIndex>::remove(collection_id);629            <AdminList<T>>::remove(collection_id);630            <Collection<T>>::remove(collection_id);631            <WhiteList<T>>::remove_prefix(collection_id);632633            <NftItemList<T>>::remove_prefix(collection_id);634            <FungibleItemList<T>>::remove_prefix(collection_id);635            <ReFungibleItemList<T>>::remove_prefix(collection_id);636637            <NftTransferBasket<T>>::remove_prefix(collection_id);638            <FungibleTransferBasket<T>>::remove_prefix(collection_id);639            <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);640641            if CollectionCount::get() > 0642            {643                // bound couter644                let total = CollectionCount::get()645                    .checked_sub(1)646                    .ok_or(Error::<T>::NumOverflow)?;647648                CollectionCount::put(total);649            }650651            Ok(())652        }653654        /// Add an address to white list.655        /// 656        /// # Permissions657        /// 658        /// * Collection Owner659        /// * Collection Admin660        /// 661        /// # Arguments662        /// 663        /// * collection_id.664        /// 665        /// * address.666        #[weight = <T as Config>::WeightInfo::add_to_white_list()]667        pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{668669            let sender = ensure_signed(origin)?;670            Self::check_owner_or_admin_permissions(collection_id, sender)?;671672            <WhiteList<T>>::insert(collection_id, address, true);673            674            Ok(())675        }676677        /// Remove an address from white list.678        /// 679        /// # Permissions680        /// 681        /// * Collection Owner682        /// * Collection Admin683        /// 684        /// # Arguments685        /// 686        /// * collection_id.687        /// 688        /// * address.689        #[weight = <T as Config>::WeightInfo::remove_from_white_list()]690        pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{691692            let sender = ensure_signed(origin)?;693            Self::check_owner_or_admin_permissions(collection_id, sender)?;694695            <WhiteList<T>>::remove(collection_id, address);696697            Ok(())698        }699700        /// Toggle between normal and white list access for the methods with access for `Anyone`.701        /// 702        /// # Permissions703        /// 704        /// * Collection Owner.705        /// 706        /// # Arguments707        /// 708        /// * collection_id.709        /// 710        /// * mode: [AccessMode]711        #[weight = <T as Config>::WeightInfo::set_public_access_mode()]712        pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult713        {714            let sender = ensure_signed(origin)?;715716            Self::check_owner_permissions(collection_id, sender)?;717            let mut target_collection = <Collection<T>>::get(collection_id);718            target_collection.access = mode;719            <Collection<T>>::insert(collection_id, target_collection);720721            Ok(())722        }723724        /// Allows Anyone to create tokens if:725        /// * White List is enabled, and726        /// * Address is added to white list, and727        /// * This method was called with True parameter728        /// 729        /// # Permissions730        /// * Collection Owner731        ///732        /// # Arguments733        /// 734        /// * collection_id.735        /// 736        /// * mint_permission: Boolean parameter. If True, allows minting to Anyone with conditions above.737        #[weight = <T as Config>::WeightInfo::set_mint_permission()]738        pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult739        {740            let sender = ensure_signed(origin)?;741742            Self::check_owner_permissions(collection_id, sender)?;743            let mut target_collection = <Collection<T>>::get(collection_id);744            target_collection.mint_mode = mint_permission;745            <Collection<T>>::insert(collection_id, target_collection);746747            Ok(())748        }749750        /// Change the owner of the collection.751        /// 752        /// # Permissions753        /// 754        /// * Collection Owner.755        /// 756        /// # Arguments757        /// 758        /// * collection_id.759        /// 760        /// * new_owner.761        #[weight = <T as Config>::WeightInfo::change_collection_owner()]762        pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {763764            let sender = ensure_signed(origin)?;765            Self::check_owner_permissions(collection_id, sender)?;766            let mut target_collection = <Collection<T>>::get(collection_id);767            target_collection.owner = new_owner;768            <Collection<T>>::insert(collection_id, target_collection);769770            Ok(())771        }772773        /// Adds an admin of the Collection.774        /// 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. 775        /// 776        /// # Permissions777        /// 778        /// * Collection Owner.779        /// * Collection Admin.780        /// 781        /// # Arguments782        /// 783        /// * collection_id: ID of the Collection to add admin for.784        /// 785        /// * new_admin_id: Address of new admin to add.786        #[weight = <T as Config>::WeightInfo::add_collection_admin()]787        pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {788789            let sender = ensure_signed(origin)?;790            Self::check_owner_or_admin_permissions(collection_id, sender)?;791            let mut admin_arr: Vec<T::AccountId> = Vec::new();792793            if <AdminList<T>>::contains_key(collection_id)794            {795                admin_arr = <AdminList<T>>::get(collection_id);796                ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);797            }798799            // Number of collection admins800            ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);801802            admin_arr.push(new_admin_id);803            <AdminList<T>>::insert(collection_id, admin_arr);804805            Ok(())806        }807808        /// 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.809        ///810        /// # Permissions811        /// 812        /// * Collection Owner.813        /// * Collection Admin.814        /// 815        /// # Arguments816        /// 817        /// * collection_id: ID of the Collection to remove admin for.818        /// 819        /// * account_id: Address of admin to remove.820        #[weight = <T as Config>::WeightInfo::remove_collection_admin()]821        pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {822823            let sender = ensure_signed(origin)?;824            Self::check_owner_or_admin_permissions(collection_id, sender)?;825            ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);826827            let mut admin_arr = <AdminList<T>>::get(collection_id);828            admin_arr.retain(|i| *i != account_id);829            <AdminList<T>>::insert(collection_id, admin_arr);830831            Ok(())832        }833834        /// # Permissions835        /// 836        /// * Collection Owner837        /// 838        /// # Arguments839        /// 840        /// * collection_id.841        /// 842        /// * new_sponsor.843        #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]844        pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {845846            let sender = ensure_signed(origin)?;847            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);848849            let mut target_collection = <Collection<T>>::get(collection_id);850            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);851852            target_collection.sponsor = new_sponsor;853            target_collection.sponsor_confirmed = false;854            <Collection<T>>::insert(collection_id, target_collection);855856            Ok(())857        }858859        /// # Permissions860        /// 861        /// * Sponsor.862        /// 863        /// # Arguments864        /// 865        /// * collection_id.866        #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]867        pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {868869            let sender = ensure_signed(origin)?;870            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);871872            let mut target_collection = <Collection<T>>::get(collection_id);873            ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);874875            target_collection.sponsor_confirmed = true;876            <Collection<T>>::insert(collection_id, target_collection);877878            Ok(())879        }880881        /// Switch back to pay-per-own-transaction model.882        ///883        /// # Permissions884        ///885        /// * Collection owner.886        /// 887        /// # Arguments888        /// 889        /// * collection_id.890        #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]891        pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {892893            let sender = ensure_signed(origin)?;894            ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);895896            let mut target_collection = <Collection<T>>::get(collection_id);897            ensure!(sender == target_collection.owner, Error::<T>::NoPermission);898899            target_collection.sponsor = T::AccountId::default();900            target_collection.sponsor_confirmed = false;901            <Collection<T>>::insert(collection_id, target_collection);902903            Ok(())904        }905906        /// This method creates a concrete instance of NFT Collection created with CreateCollection method.907        /// 908        /// # Permissions909        /// 910        /// * Collection Owner.911        /// * Collection Admin.912        /// * Anyone if913        ///     * White List is enabled, and914        ///     * Address is added to white list, and915        ///     * MintPermission is enabled (see SetMintPermission method)916        /// 917        /// # Arguments918        /// 919        /// * collection_id: ID of the collection.920        /// 921        /// * owner: Address, initial owner of the NFT.922        ///923        /// * data: Token data to store on chain.924        // #[weight =925        // (130_000_000 as Weight)926        // .saturating_add((2135 as Weight).saturating_mul((properties.len() as u64) as Weight))927        // .saturating_add(RocksDbWeight::get().reads(10 as Weight))928        // .saturating_add(RocksDbWeight::get().writes(8 as Weight))]929930        #[weight = <T as Config>::WeightInfo::create_item(data.len())]931        pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {932933            let sender = ensure_signed(origin)?;934935            Self::collection_exists(collection_id)?;936937            let target_collection = <Collection<T>>::get(collection_id);938939            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;940            Self::validate_create_item_args(&target_collection, &data)?;941            Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;942943            Ok(())944        }945946        /// This method creates multiple instances of NFT Collection created with CreateCollection method.947        /// 948        /// # Permissions949        /// 950        /// * Collection Owner.951        /// * Collection Admin.952        /// * Anyone if953        ///     * White List is enabled, and954        ///     * Address is added to white list, and955        ///     * MintPermission is enabled (see SetMintPermission method)956        /// 957        /// # Arguments958        /// 959        /// * collection_id: ID of the collection.960        /// 961        /// * itemsData: Array items properties. Each property is an array of bytes itself, see [create_item].962        /// 963        /// * owner: Address, initial owner of the NFT.964        #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()965                               .map(|data| { data.len() })966                               .sum())]967        pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {968969            ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);970            let sender = ensure_signed(origin)?;971972            Self::collection_exists(collection_id)?;973            let target_collection = <Collection<T>>::get(collection_id);974975            Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;976977            for data in &items_data {978                Self::validate_create_item_args(&target_collection, data)?;979            }980            for data in &items_data {981                Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;982            }983984            Ok(())985        }986987        /// Destroys a concrete instance of NFT.988        /// 989        /// # Permissions990        /// 991        /// * Collection Owner.992        /// * Collection Admin.993        /// * Current NFT Owner.994        /// 995        /// # Arguments996        /// 997        /// * collection_id: ID of the collection.998        /// 999        /// * item_id: ID of NFT to burn.1000        #[weight = <T as Config>::WeightInfo::burn_item()]1001        pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10021003            let sender = ensure_signed(origin)?;1004            Self::collection_exists(collection_id)?;10051006            // Transfer permissions check1007            let target_collection = <Collection<T>>::get(collection_id);1008            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1009                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1010                Error::<T>::NoPermission);10111012            if target_collection.access == AccessMode::WhiteList {1013                Self::check_white_list(collection_id, &sender)?;1014            }10151016            match target_collection.mode1017            {1018                CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1019                CollectionMode::Fungible(_)  => Self::burn_fungible_item(&sender, collection_id, value)?,1020                CollectionMode::ReFungible(_)  => Self::burn_refungible_item(collection_id, item_id, &sender)?,1021                _ => ()1022            };10231024            // call event1025            Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10261027            Ok(())1028        }10291030        /// Change ownership of the token.1031        /// 1032        /// # Permissions1033        /// 1034        /// * Collection Owner1035        /// * Collection Admin1036        /// * Current NFT owner1037        ///1038        /// # Arguments1039        /// 1040        /// * recipient: Address of token recipient.1041        /// 1042        /// * collection_id.1043        /// 1044        /// * item_id: ID of the item1045        ///     * Non-Fungible Mode: Required.1046        ///     * Fungible Mode: Ignored.1047        ///     * Re-Fungible Mode: Required.1048        /// 1049        /// * value: Amount to transfer.1050        ///     * Non-Fungible Mode: Ignored1051        ///     * Fungible Mode: Must specify transferred amount1052        ///     * Re-Fungible Mode: Must specify transferred portion (between 0 and 1)1053        #[weight = <T as Config>::WeightInfo::transfer()]1054        pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1055            let sender = ensure_signed(origin)?;1056            Self::transfer_internal(sender, recipient, collection_id, item_id, value)1057        }10581059        /// Set, change, or remove approved address to transfer the ownership of the NFT.1060        /// 1061        /// # Permissions1062        /// 1063        /// * Collection Owner1064        /// * Collection Admin1065        /// * Current NFT owner1066        /// 1067        /// # Arguments1068        /// 1069        /// * approved: Address that is approved to transfer this NFT or zero (if needed to remove approval).1070        /// 1071        /// * collection_id.1072        /// 1073        /// * item_id: ID of the item.1074        #[weight = <T as Config>::WeightInfo::approve()]1075        pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10761077            let sender = ensure_signed(origin)?;10781079            Self::collection_exists(collection_id)?;1080            Self::token_exists(collection_id, item_id, &sender)?;10811082            // Transfer permissions check1083            let target_collection = <Collection<T>>::get(collection_id);1084            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1085                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1086                Error::<T>::NoPermission);10871088            if target_collection.access == AccessMode::WhiteList {1089                Self::check_white_list(collection_id, &sender)?;1090                Self::check_white_list(collection_id, &spender)?;1091            }10921093            let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1094            let mut allowance: u128 = amount;1095            if allowance_exists {1096                allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1097            }1098            <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);10991100            Ok(())1101        }1102        1103        /// 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.1104        /// 1105        /// # Permissions1106        /// * Collection Owner1107        /// * Collection Admin1108        /// * Current NFT owner1109        /// * Address approved by current NFT owner1110        /// 1111        /// # Arguments1112        /// 1113        /// * from: Address that owns token.1114        /// 1115        /// * recipient: Address of token recipient.1116        /// 1117        /// * collection_id.1118        /// 1119        /// * item_id: ID of the item.1120        /// 1121        /// * value: Amount to transfer.1122        #[weight = <T as Config>::WeightInfo::transfer_from()]1123        pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11241125            let sender = ensure_signed(origin)?;1126            let mut appoved_transfer = false;11271128            // Check approval1129            let mut approval: u128 = 0;1130            if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1131                approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1132                ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1133                appoved_transfer = true;1134            }11351136            let target_collection = <Collection<T>>::get(collection_id);11371138            // Limits check1139            Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11401141            // Transfer permissions check         1142            ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1143                Error::<T>::NoPermission);11441145            if target_collection.access == AccessMode::WhiteList {1146                Self::check_white_list(collection_id, &sender)?;1147                Self::check_white_list(collection_id, &recipient)?;1148            }11491150            // Reduce approval by transferred amount or remove if remaining approval drops to 01151            if approval.checked_sub(value).unwrap_or(0) > 0 {1152                <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1153            }1154            else {1155                <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1156            }11571158            match target_collection.mode1159            {1160                CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1161                CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1162                CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1163                _ => ()1164            };11651166            Ok(())1167        }11681169        // #[weight = 0]1170        // pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11711172        //     // let no_perm_mes = "You do not have permissions to modify this collection";1173        //     // ensure!(<ApprovedList<T>>::contains_key((collection_id, item_id)), no_perm_mes);1174        //     // let list_itm = <ApprovedList<T>>::get((collection_id, item_id));1175        //     // ensure!(list_itm.contains(&new_owner.clone()), no_perm_mes);11761177        //     // // on_nft_received  call11781179        //     // Self::transfer(origin, collection_id, item_id, new_owner)?;11801181        //     Ok(())1182        // }11831184        /// Set off-chain data schema.1185        /// 1186        /// # Permissions1187        /// 1188        /// * Collection Owner1189        /// * Collection Admin1190        /// 1191        /// # Arguments1192        /// 1193        /// * collection_id.1194        /// 1195        /// * schema: String representing the offchain data schema.1196        #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1197        pub fn set_variable_meta_data (1198            origin,1199            collection_id: CollectionId,1200            item_id: TokenId,1201            data: Vec<u8>1202        ) -> DispatchResult {1203            let sender = ensure_signed(origin)?;1204            1205            Self::collection_exists(collection_id)?;1206            Self::token_exists(collection_id, item_id, &sender)?;12071208            ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12091210            // Modify permissions check1211            let target_collection = <Collection<T>>::get(collection_id);1212            ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1213                Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1214                Error::<T>::NoPermission);12151216            match target_collection.mode1217            {1218                CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1219                CollectionMode::ReFungible(_)  => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1220                CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1221                _ => fail!(Error::<T>::UnexpectedCollectionType)1222            };12231224            Ok(())1225        }1226 1227        /// Set schema standard1228        /// ImageURL1229        /// Unique1230        /// 1231        /// # Permissions1232        /// 1233        /// * Collection Owner1234        /// * Collection Admin1235        /// 1236        /// # Arguments1237        /// 1238        /// * collection_id.1239        /// 1240        /// * schema: SchemaVersion: enum1241        #[weight = <T as Config>::WeightInfo::set_schema_version()]1242        pub fn set_schema_version(1243            origin,1244            collection_id: CollectionId,1245            version: SchemaVersion1246        ) -> DispatchResult {1247            let sender = ensure_signed(origin)?;1248            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1249            let mut target_collection = <Collection<T>>::get(collection_id);1250            target_collection.schema_version = version;1251            <Collection<T>>::insert(collection_id, target_collection);12521253            Ok(())1254        }12551256        /// Set off-chain data schema.1257        /// 1258        /// # Permissions1259        /// 1260        /// * Collection Owner1261        /// * Collection Admin1262        /// 1263        /// # Arguments1264        /// 1265        /// * collection_id.1266        /// 1267        /// * schema: String representing the offchain data schema.1268        #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1269        pub fn set_offchain_schema(1270            origin,1271            collection_id: CollectionId,1272            schema: Vec<u8>1273        ) -> DispatchResult {1274            let sender = ensure_signed(origin)?;1275            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12761277            // check schema limit1278            ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12791280            let mut target_collection = <Collection<T>>::get(collection_id);1281            target_collection.offchain_schema = schema;1282            <Collection<T>>::insert(collection_id, target_collection);12831284            Ok(())1285        }12861287        /// Set const on-chain data schema.1288        /// 1289        /// # Permissions1290        /// 1291        /// * Collection Owner1292        /// * Collection Admin1293        /// 1294        /// # Arguments1295        /// 1296        /// * collection_id.1297        /// 1298        /// * schema: String representing the const on-chain data schema.1299        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1300        pub fn set_const_on_chain_schema (1301            origin,1302            collection_id: CollectionId,1303            schema: Vec<u8>1304        ) -> DispatchResult {1305            let sender = ensure_signed(origin)?;1306            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13071308            // check schema limit1309            ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13101311            let mut target_collection = <Collection<T>>::get(collection_id);1312            target_collection.const_on_chain_schema = schema;1313            <Collection<T>>::insert(collection_id, target_collection);13141315            Ok(())1316        }13171318        /// Set variable on-chain data schema.1319        /// 1320        /// # Permissions1321        /// 1322        /// * Collection Owner1323        /// * Collection Admin1324        /// 1325        /// # Arguments1326        /// 1327        /// * collection_id.1328        /// 1329        /// * schema: String representing the variable on-chain data schema.1330        #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1331        pub fn set_variable_on_chain_schema (1332            origin,1333            collection_id: CollectionId,1334            schema: Vec<u8>1335        ) -> DispatchResult {1336            let sender = ensure_signed(origin)?;1337            Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13381339            // check schema limit1340            ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13411342            let mut target_collection = <Collection<T>>::get(collection_id);1343            target_collection.variable_on_chain_schema = schema;1344            <Collection<T>>::insert(collection_id, target_collection);13451346            Ok(())1347        }13481349        // Sudo permissions function1350        #[weight = <T as Config>::WeightInfo::set_chain_limits()]1351        pub fn set_chain_limits(1352            origin,1353            limits: ChainLimits1354        ) -> DispatchResult {13551356            #[cfg(not(feature = "runtime-benchmarks"))]1357            ensure_root(origin)?;13581359            <ChainLimit>::put(limits);1360            Ok(())1361        }13621363        /// Enable smart contract self-sponsoring.1364        /// 1365        /// # Permissions1366        /// 1367        /// * Contract Owner1368        /// 1369        /// # Arguments1370        /// 1371        /// * contract address1372        /// * enable flag1373        /// 1374        #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1375        pub fn enable_contract_sponsoring(1376            origin,1377            contract_address: T::AccountId,1378            enable: bool1379        ) -> DispatchResult {13801381            let sender = ensure_signed(origin)?;13821383            #[cfg(feature = "runtime-benchmarks")]1384            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13851386            Self::ensure_contract_owned(sender, &contract_address)?;13871388            <ContractSelfSponsoring<T>>::insert(contract_address, enable);1389            Ok(())1390        }13911392        /// Set the rate limit for contract sponsoring to specified number of blocks.1393        /// 1394        /// If not set (has the default value of 0 blocks), the sponsoring will be disabled. 1395        /// If set to the number B (for blocks), the transactions will be sponsored with a rate 1396        /// limit of B, i.e. fees for every transaction sent to this smart contract will be paid 1397        /// from contract endowment if there are at least B blocks between such transactions. 1398        /// Nonetheless, if transactions are sent more frequently, the fees are paid by the sender.1399        /// 1400        /// # Permissions1401        /// 1402        /// * Contract Owner1403        /// 1404        /// # Arguments1405        /// 1406        /// -`contract_address`: Address of the contract to sponsor1407        /// -`rate_limit`: Number of blocks to wait until the next sponsored transaction is allowed1408        /// 1409        #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1410        pub fn set_contract_sponsoring_rate_limit(1411            origin,1412            contract_address: T::AccountId,1413            rate_limit: T::BlockNumber1414        ) -> DispatchResult {1415            let sender = ensure_signed(origin)?;14161417            #[cfg(feature = "runtime-benchmarks")]1418            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14191420            Self::ensure_contract_owned(sender, &contract_address)?;1421            <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1422            Ok(())1423        }14241425        /// Enable the white list for a contract. Only addresses added to the white list with addToContractWhiteList will be able to call this smart contract.1426        /// 1427        /// # Permissions1428        /// 1429        /// * Address that deployed smart contract.1430        /// 1431        /// # Arguments1432        /// 1433        /// -`contract_address`: Address of the contract.1434        /// 1435        /// - `enable`: .  1436        #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1437        pub fn toggle_contract_white_list(1438            origin,1439            contract_address: T::AccountId,1440            enable: bool1441        ) -> DispatchResult {1442            let sender = ensure_signed(origin)?;14431444            #[cfg(feature = "runtime-benchmarks")]1445            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14461447            Self::ensure_contract_owned(sender, &contract_address)?;1448            <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1449            Ok(())1450        }1451        1452        /// Add an address to smart contract white list.1453        /// 1454        /// # Permissions1455        /// 1456        /// * Address that deployed smart contract.1457        /// 1458        /// # Arguments1459        /// 1460        /// -`contract_address`: Address of the contract.1461        ///1462        /// -`account_address`: Address to add.1463        #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1464        pub fn add_to_contract_white_list(1465            origin,1466            contract_address: T::AccountId,1467            account_address: T::AccountId1468        ) -> DispatchResult {1469            let sender = ensure_signed(origin)?;14701471            #[cfg(feature = "runtime-benchmarks")]1472            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1473            1474            Self::ensure_contract_owned(sender, &contract_address)?;      1475            <ContractWhiteList<T>>::insert(contract_address, account_address, true);1476            Ok(())1477        }14781479        /// Remove an address from smart contract white list.1480        /// 1481        /// # Permissions1482        /// 1483        /// * Address that deployed smart contract.1484        /// 1485        /// # Arguments1486        /// 1487        /// -`contract_address`: Address of the contract.1488        ///1489        /// -`account_address`: Address to remove.1490        #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1491        pub fn remove_from_contract_white_list(1492            origin,1493            contract_address: T::AccountId,1494            account_address: T::AccountId1495        ) -> DispatchResult {1496            let sender = ensure_signed(origin)?;14971498            #[cfg(feature = "runtime-benchmarks")]1499            <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15001501            Self::ensure_contract_owned(sender, &contract_address)?;1502            <ContractWhiteList<T>>::remove(contract_address, account_address);1503            Ok(())1504        }15051506        #[weight = <T as Config>::WeightInfo::set_collection_limits()]1507        pub fn set_collection_limits(1508            origin,1509            collection_id: u32,1510            limits: CollectionLimits,1511        ) -> DispatchResult {1512            let sender = ensure_signed(origin)?;1513            Self::check_owner_permissions(collection_id, sender.clone())?;1514            let mut target_collection = <Collection<T>>::get(collection_id);1515            let chain_limits = ChainLimit::get();1516            let climits = target_collection.limits;15171518            // collection bounds1519            ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1520                limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP,  1521                Error::<T>::CollectionLimitBoundsExceeded);15221523            // token_limit   check  prev1524            ensure!(climits.token_limit > limits.token_limit && 1525                limits.token_limit <= chain_limits.account_token_ownership_limit, 1526                Error::<T>::AccountTokenLimitExceeded);15271528            target_collection.limits = limits;1529            <Collection<T>>::insert(collection_id, target_collection);15301531            Ok(())1532        } 1533    }1534}15351536impl<T: Config> Module<T> {15371538    pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {15391540        let target_collection = <Collection<T>>::get(collection_id);15411542        // Limits check1543        Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;15441545        // Transfer permissions check1546        ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1547            Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1548            Error::<T>::NoPermission);15491550        if target_collection.access == AccessMode::WhiteList {1551            Self::check_white_list(collection_id, &sender)?;1552            Self::check_white_list(collection_id, &recipient)?;1553        }15541555        match target_collection.mode1556        {1557            CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1558            CollectionMode::Fungible(_)  => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1559            CollectionMode::ReFungible(_)  => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1560            _ => ()1561        };15621563        Ok(())1564    }156515661567    fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15681569        // check token limit and account token limit1570        let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1571        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);1572        1573        Ok(())1574    }15751576    fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15771578        // check token limit and account token limit1579        let total_items: u32 = ItemListIndex::get(collection_id);1580        let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1581        ensure!(collection.limits.token_limit > total_items,  Error::<T>::CollectionTokenLimitExceeded);1582        ensure!(collection.limits.account_token_ownership_limit > account_items,  Error::<T>::AccountTokenLimitExceeded);15831584        if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1585            ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1586            Self::check_white_list(collection_id, owner)?;1587            Self::check_white_list(collection_id, sender)?;1588        }15891590        Ok(())1591    }15921593    fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1594        match target_collection.mode1595        {1596            CollectionMode::NFT => {1597                if let CreateItemData::NFT(data) = data {1598                    // check sizes1599                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1600                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1601                } else {1602                    fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1603                }1604            },1605            CollectionMode::Fungible(_) => {1606                if let CreateItemData::Fungible(_) = data {1607                } else {1608                    fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1609                }1610            },1611            CollectionMode::ReFungible(_) => {1612                if let CreateItemData::ReFungible(data) = data {16131614                    // check sizes1615                    ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1616                    ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1617                } else {1618                    fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1619                }1620            },1621            _ => { fail!(Error::<T>::UnexpectedCollectionType); }1622        };16231624        Ok(())1625    }16261627    fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1628        match data1629        {1630            CreateItemData::NFT(data) => {1631                let item = NftItemType {1632                    owner,1633                    const_data: data.const_data,1634                    variable_data: data.variable_data1635                };16361637                Self::add_nft_item(collection_id, item)?;1638            },1639            CreateItemData::Fungible(data) => {1640                Self::add_fungible_item(collection_id, &owner, data.value)?;1641            },1642            CreateItemData::ReFungible(data) => {1643                let mut owner_list = Vec::new();1644                let value = (10 as u128).pow(collection.decimal_points as u32);1645                owner_list.push(Ownership {owner: owner.clone(), fraction: value});16461647                let item = ReFungibleItemType {1648                    owner: owner_list,1649                    const_data: data.const_data,1650                    variable_data: data.variable_data1651                };16521653                Self::add_refungible_item(collection_id, item)?;1654            }1655        };16561657        // call event1658        Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16591660        Ok(())1661    }16621663    fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16641665        // Does new owner already have an account?1666        let mut balance: u128 = 0;1667        if <FungibleItemList<T>>::contains_key(collection_id, owner) {1668            balance = <FungibleItemList<T>>::get(collection_id, owner).value;1669        } 16701671        // Mint 1672        let item = FungibleItemType {1673            value: balance + value1674        };1675        <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16761677        // Update balance1678        let new_balance = <Balance<T>>::get(collection_id, owner)1679            .checked_add(value)1680            .ok_or(Error::<T>::NumOverflow)?;1681        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16821683        Ok(())1684    }16851686    fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1687        let current_index = <ItemListIndex>::get(collection_id)1688            .checked_add(1)1689            .ok_or(Error::<T>::NumOverflow)?;1690        let itemcopy = item.clone();16911692        let value = item.owner.first().unwrap().fraction;1693        let owner = item.owner.first().unwrap().owner.clone();16941695        Self::add_token_index(collection_id, current_index, &owner)?;16961697        <ItemListIndex>::insert(collection_id, current_index);1698        <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16991700        // Update balance1701        let new_balance = <Balance<T>>::get(collection_id, &owner)1702            .checked_add(value)1703            .ok_or(Error::<T>::NumOverflow)?;1704        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);17051706        Ok(())1707    }17081709    fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1710        let current_index = <ItemListIndex>::get(collection_id)1711            .checked_add(1)1712            .ok_or(Error::<T>::NumOverflow)?;17131714        let item_owner = item.owner.clone();1715        Self::add_token_index(collection_id, current_index, &item.owner)?;17161717        <ItemListIndex>::insert(collection_id, current_index);1718        <NftItemList<T>>::insert(collection_id, current_index, item);17191720        // Update balance1721        let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1722            .checked_add(1)1723            .ok_or(Error::<T>::NumOverflow)?;1724        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17251726        Ok(())1727    }17281729    fn burn_refungible_item(1730        collection_id: CollectionId,1731        item_id: TokenId,1732        owner: &T::AccountId,1733    ) -> DispatchResult {1734        ensure!(1735            <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1736            Error::<T>::TokenNotFound1737        );1738        let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1739        let rft_balance = token1740            .owner1741            .iter()1742            .filter(|&i| i.owner == *owner)1743            .next()1744            .unwrap();1745        Self::remove_token_index(collection_id, item_id, owner)?;17461747        // update balance1748        let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1749            .checked_sub(rft_balance.fraction)1750            .ok_or(Error::<T>::NumOverflow)?;1751        <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17521753        // Re-create owners list with sender removed1754        let index = token1755            .owner1756            .iter()1757            .position(|i| i.owner == *owner)1758            .unwrap();1759        token.owner.remove(index);1760        let owner_count = token.owner.len();17611762        // Burn the token completely if this was the last (only) owner1763        if owner_count == 0 {1764            <ReFungibleItemList<T>>::remove(collection_id, item_id);1765        }1766        else {1767            <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1768        }17691770        Ok(())1771    }17721773    fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1774        ensure!(1775            <NftItemList<T>>::contains_key(collection_id, item_id),1776            Error::<T>::TokenNotFound1777        );1778        let item = <NftItemList<T>>::get(collection_id, item_id);1779        Self::remove_token_index(collection_id, item_id, &item.owner)?;17801781        // update balance1782        let new_balance = <Balance<T>>::get(collection_id, &item.owner)1783            .checked_sub(1)1784            .ok_or(Error::<T>::NumOverflow)?;1785        <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1786        <NftItemList<T>>::remove(collection_id, item_id);17871788        Ok(())1789    }17901791    fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1792        ensure!(1793            <FungibleItemList<T>>::contains_key(collection_id, owner),1794            Error::<T>::TokenNotFound1795        );1796        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1797        ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17981799        // update balance1800        let new_balance = <Balance<T>>::get(collection_id, owner)1801            .checked_sub(value)1802            .ok_or(Error::<T>::NumOverflow)?;1803        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18041805        if balance.value - value > 0 {1806            balance.value -= value;1807            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1808        }1809        else {1810            <FungibleItemList<T>>::remove(collection_id, owner);1811        }18121813        Ok(())1814    }18151816    fn collection_exists(collection_id: CollectionId) -> DispatchResult {1817        ensure!(1818            <Collection<T>>::contains_key(collection_id),1819            Error::<T>::CollectionNotFound1820        );1821        Ok(())1822    }18231824    fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1825        Self::collection_exists(collection_id)?;18261827        let target_collection = <Collection<T>>::get(collection_id);1828        ensure!(1829            subject == target_collection.owner,1830            Error::<T>::NoPermission1831        );18321833        Ok(())1834    }18351836    fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1837        let target_collection = <Collection<T>>::get(collection_id);1838        let mut result: bool = subject == target_collection.owner;1839        let exists = <AdminList<T>>::contains_key(collection_id);18401841        if !result & exists {1842            if <AdminList<T>>::get(collection_id).contains(&subject) {1843                result = true1844            }1845        }18461847        result1848    }18491850    fn check_owner_or_admin_permissions(1851        collection_id: CollectionId,1852        subject: T::AccountId,1853    ) -> DispatchResult {1854        Self::collection_exists(collection_id)?;1855        let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18561857        ensure!(1858            result,1859            Error::<T>::NoPermission1860        );1861        Ok(())1862    }18631864    fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1865        let target_collection = <Collection<T>>::get(collection_id);18661867        match target_collection.mode {1868            CollectionMode::NFT => {1869                <NftItemList<T>>::get(collection_id, item_id).owner == subject1870            }1871            CollectionMode::Fungible(_) => {1872                <FungibleItemList<T>>::contains_key(collection_id, &subject)1873            }1874            CollectionMode::ReFungible(_) => {1875                <ReFungibleItemList<T>>::get(collection_id, item_id)1876                    .owner1877                    .iter()1878                    .any(|i| i.owner == subject)1879            }1880            CollectionMode::Invalid => false,1881        }1882    }18831884    fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1885        let mes = Error::<T>::AddresNotInWhiteList;1886        ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18871888        Ok(())1889    }18901891    /// Check if token exists. In case of Fungible, check if there is an entry for 1892    /// the owner in fungible balances double map1893    fn token_exists(1894        collection_id: CollectionId,1895        item_id: TokenId,1896        owner: &T::AccountId1897    ) -> DispatchResult {1898        let target_collection = <Collection<T>>::get(collection_id);1899        let exists = match target_collection.mode1900        {1901            CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1902            CollectionMode::Fungible(_)  => <FungibleItemList<T>>::contains_key(collection_id, owner),1903            CollectionMode::ReFungible(_)  => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1904            _ => false1905        };19061907        ensure!(exists == true, Error::<T>::TokenNotFound);1908        Ok(())1909    }19101911    fn transfer_fungible(1912        collection_id: CollectionId,1913        value: u128,1914        owner: &T::AccountId,1915        recipient: &T::AccountId,1916    ) -> DispatchResult {1917        Self::token_exists(collection_id, 0, owner)?;19181919        let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1920        ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);19211922        // Send balance to recipient (updates balanceOf of recipient)1923        Self::add_fungible_item(collection_id, recipient, value)?;19241925        // update balanceOf of sender1926        <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);19271928        // Reduce or remove sender1929        if balance.value == value {1930            <FungibleItemList<T>>::remove(collection_id, owner);1931        }1932        else {1933            balance.value -= value;1934            <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1935        }19361937        Ok(())1938    }19391940    fn transfer_refungible(1941        collection_id: CollectionId,1942        item_id: TokenId,1943        value: u128,1944        owner: T::AccountId,1945        new_owner: T::AccountId,1946    ) -> DispatchResult {1947        Self::token_exists(collection_id, item_id, &owner)?;19481949        let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1950        let item = full_item1951            .owner1952            .iter()1953            .filter(|i| i.owner == owner)1954            .next()1955            .ok_or(Error::<T>::NumOverflow)?;1956        let amount = item.fraction;19571958        ensure!(amount >= value, Error::<T>::TokenValueTooLow);19591960        // update balance1961        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1962            .checked_sub(value)1963            .ok_or(Error::<T>::NumOverflow)?;1964        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19651966        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1967            .checked_add(value)1968            .ok_or(Error::<T>::NumOverflow)?;1969        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19701971        let old_owner = item.owner.clone();1972        let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19731974        // transfer1975        if amount == value && !new_owner_has_account {1976            // change owner1977            // new owner do not have account1978            let mut new_full_item = full_item.clone();1979            new_full_item1980                .owner1981                .iter_mut()1982                .find(|i| i.owner == owner)1983                .unwrap()1984                .owner = new_owner.clone();1985            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19861987            // update index collection1988            Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1989        } else {1990            let mut new_full_item = full_item.clone();1991            new_full_item1992                .owner1993                .iter_mut()1994                .find(|i| i.owner == owner)1995                .unwrap()1996                .fraction -= value;19971998            // separate amount1999            if new_owner_has_account {2000                // new owner has account2001                new_full_item2002                    .owner2003                    .iter_mut()2004                    .find(|i| i.owner == new_owner)2005                    .unwrap()2006                    .fraction += value;2007            } else {2008                // new owner do not have account2009                new_full_item.owner.push(Ownership {2010                    owner: new_owner.clone(),2011                    fraction: value,2012                });2013                Self::add_token_index(collection_id, item_id, &new_owner)?;2014            }20152016            <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2017        }20182019        Ok(())2020    }20212022    fn transfer_nft(2023        collection_id: CollectionId,2024        item_id: TokenId,2025        sender: T::AccountId,2026        new_owner: T::AccountId,2027    ) -> DispatchResult {2028        Self::token_exists(collection_id, item_id, &sender)?;20292030        let mut item = <NftItemList<T>>::get(collection_id, item_id);20312032        ensure!(2033            sender == item.owner,2034            Error::<T>::MustBeTokenOwner2035        );20362037        // update balance2038        let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2039            .checked_sub(1)2040            .ok_or(Error::<T>::NumOverflow)?;2041        <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20422043        let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2044            .checked_add(1)2045            .ok_or(Error::<T>::NumOverflow)?;2046        <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20472048        // change owner2049        let old_owner = item.owner.clone();2050        item.owner = new_owner.clone();2051        <NftItemList<T>>::insert(collection_id, item_id, item);20522053        // update index collection2054        Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20552056        Ok(())2057    }2058    2059    fn set_re_fungible_variable_data(2060        collection_id: CollectionId,2061        item_id: TokenId,2062        data: Vec<u8>2063    ) -> DispatchResult {2064        let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20652066        item.variable_data = data;20672068        <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20692070        Ok(())2071    }20722073    fn set_nft_variable_data(2074        collection_id: CollectionId,2075        item_id: TokenId,2076        data: Vec<u8>2077    ) -> DispatchResult {2078        let mut item = <NftItemList<T>>::get(collection_id, item_id);2079        2080        item.variable_data = data;20812082        <NftItemList<T>>::insert(collection_id, item_id, item);2083        2084        Ok(())2085    }20862087    fn init_collection(item: &CollectionType<T::AccountId>) {2088        // check params2089        assert!(2090            item.decimal_points <= MAX_DECIMAL_POINTS,2091            "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2092        );2093        assert!(2094            item.name.len() <= 64,2095            "Collection name can not be longer than 63 char"2096        );2097        assert!(2098            item.name.len() <= 256,2099            "Collection description can not be longer than 255 char"2100        );2101        assert!(2102            item.token_prefix.len() <= 16,2103            "Token prefix can not be longer than 15 char"2104        );21052106        // Generate next collection ID2107        let next_id = CreatedCollectionCount::get()2108            .checked_add(1)2109            .unwrap();21102111        CreatedCollectionCount::put(next_id);2112    }21132114    fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2115        let current_index = <ItemListIndex>::get(collection_id)2116            .checked_add(1)2117            .unwrap();21182119        let item_owner = item.owner.clone();2120        Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21212122        <ItemListIndex>::insert(collection_id, current_index);21232124        // Update balance2125        let new_balance = <Balance<T>>::get(collection_id, &item_owner)2126            .checked_add(1)2127            .unwrap();2128        <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2129    }21302131    fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2132        let current_index = <ItemListIndex>::get(collection_id)2133            .checked_add(1)2134            .unwrap();21352136        Self::add_token_index(collection_id, current_index, owner).unwrap();21372138        <ItemListIndex>::insert(collection_id, current_index);21392140        // Update balance2141        let new_balance = <Balance<T>>::get(collection_id, owner)2142            .checked_add(item.value)2143            .unwrap();2144        <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2145    }21462147    fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2148        let current_index = <ItemListIndex>::get(collection_id)2149            .checked_add(1)2150            .unwrap();21512152        let value = item.owner.first().unwrap().fraction;2153        let owner = item.owner.first().unwrap().owner.clone();21542155        Self::add_token_index(collection_id, current_index, &owner).unwrap();21562157        <ItemListIndex>::insert(collection_id, current_index);21582159        // Update balance2160        let new_balance = <Balance<T>>::get(collection_id, &owner)2161            .checked_add(value)2162            .unwrap();2163        <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2164    }21652166    fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {21672168        // add to account limit2169        if <AccountItemCount<T>>::contains_key(owner) {21702171            // bound Owned tokens by a single address2172            let count = <AccountItemCount<T>>::get(owner);2173            ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21742175            <AccountItemCount<T>>::insert(owner.clone(), count2176                .checked_add(1)2177                .ok_or(Error::<T>::NumOverflow)?);2178        }2179        else {2180            <AccountItemCount<T>>::insert(owner.clone(), 1);2181        }21822183        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2184        if list_exists {2185            let mut list = <AddressTokens<T>>::get(collection_id, owner);2186            let item_contains = list.contains(&item_index.clone());21872188            if !item_contains {2189                list.push(item_index.clone());2190            }21912192            <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2193        } else {2194            let mut itm = Vec::new();2195            itm.push(item_index.clone());2196            <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2197        }21982199        Ok(())2200    }22012202    fn remove_token_index(2203        collection_id: CollectionId,2204        item_index: TokenId,2205        owner: &T::AccountId,2206    ) -> DispatchResult {22072208        // update counter2209        <AccountItemCount<T>>::insert(owner.clone(), 2210            <AccountItemCount<T>>::get(owner)2211            .checked_sub(1)2212            .ok_or(Error::<T>::NumOverflow)?);221322142215        let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2216        if list_exists {2217            let mut list = <AddressTokens<T>>::get(collection_id, owner);2218            let item_contains = list.contains(&item_index.clone());22192220            if item_contains {2221                list.retain(|&item| item != item_index);2222                <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2223            }2224        }22252226        Ok(())2227    }22282229    fn move_token_index(2230        collection_id: CollectionId,2231        item_index: TokenId,2232        old_owner: &T::AccountId,2233        new_owner: &T::AccountId,2234    ) -> DispatchResult {2235        Self::remove_token_index(collection_id, item_index, old_owner)?;2236        Self::add_token_index(collection_id, item_index, new_owner)?;22372238        Ok(())2239    }2240    2241    fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2242        if <ContractOwner<T>>::contains_key(contract.clone()) {2243            let owner = <ContractOwner<T>>::get(contract);2244            ensure!(account == owner, Error::<T>::NoPermission);2245        } else {2246            fail!(Error::<T>::NoPermission);2247        }22482249        Ok(())2250    }2251}22522253////////////////////////////////////////////////////////////////////////////////////////////////////2254// Economic models2255// #region22562257/// Fee multiplier.2258pub type Multiplier = FixedU128;22592260type BalanceOf<T> = <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::Balance;22612262/// Require the transactor pay for themselves and maybe include a tip to gain additional priority2263/// in the queue.2264#[derive(Encode, Decode, Clone, Eq, PartialEq)]2265pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);22662267impl<T: Config + Send + Sync> sp_std::fmt::Debug 2268    for ChargeTransactionPayment<T>2269{2270	#[cfg(feature = "std")]2271	fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2272		write!(f, "ChargeTransactionPayment<{:?}>", self.0)2273	}2274	#[cfg(not(feature = "std"))]2275	fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2276		Ok(())2277	}2278}22792280impl<T: Config> ChargeTransactionPayment<T>2281where2282    T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2283    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2284    T::AccountId: AsRef<[u8]>,2285    T::AccountId: UncheckedFrom<T::Hash>,2286{2287    fn traditional_fee(2288        len: usize,2289        info: &DispatchInfoOf<T::Call>,2290        tip: BalanceOf<T>,2291    ) -> BalanceOf<T>2292    where2293        T::Call: Dispatchable<Info = DispatchInfo>,2294    {2295        <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2296    }22972298	fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2299        let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2300        let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2301        let len_saturation = max_block_length as u64 / (len as u64).max(1);2302        let coefficient: BalanceOf<T> = weight_saturation2303            .min(len_saturation)2304            .saturated_into::<BalanceOf<T>>();2305        final_fee2306            .saturating_mul(coefficient)2307            .saturated_into::<TransactionPriority>()2308    }23092310    fn withdraw_fee(2311        &self,2312        who: &T::AccountId,2313        call: &T::Call,2314        info: &DispatchInfoOf<T::Call>,2315        len: usize,2316	) -> Result<2317		(2318			BalanceOf<T>,2319			<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2320		),2321		TransactionValidityError,2322	> {2323        let tip = self.0;23242325        // Set fee based on call type. Creating collection costs 1 Unique.2326        // All other transactions have traditional fees so far2327        // let fee = match call.is_sub_type() {2328        //     Some(Call::create_collection(..)) => <BalanceOf<T>>::from(1_000_000_000),2329        //     _ => Self::traditional_fee(len, info, tip), // Flat fee model, use only for testing purposes2330        //                                                 // _ => <BalanceOf<T>>::from(100)2331        // };2332        let fee = Self::traditional_fee(len, info, tip);23332334        // Only mess with balances if fee is not zero.2335        if fee.is_zero() {2336            return <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2337			.map(|i| (fee, i));2338        }23392340        // Determine who is paying transaction fee based on ecnomic model2341        // Parse call to extract collection ID and access collection sponsor2342        let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2343            Some(Call::create_item(collection_id, _owner, _properties)) => {23442345                // sponsor timeout2346                let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23472348                let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2349                let mut sponsored = true;2350                if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2351                    let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2352                    let limit_time = last_tx_block + limit.into();2353                    if block_number <= limit_time {2354                        sponsored = false;2355                    }2356                }2357                if sponsored {2358                    <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2359                }23602361                // check free create limit2362                if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2363                   (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2364                   (sponsored)2365                {2366                    <Collection<T>>::get(collection_id).sponsor2367                } else {2368                    T::AccountId::default()2369                }2370            }2371            Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2372                2373                let mut sponsor_transfer = false;2374                if <Collection<T>>::get(collection_id).sponsor_confirmed {23752376                    let collection_limits = <Collection<T>>::get(collection_id).limits;2377                    let collection_mode = <Collection<T>>::get(collection_id).mode;2378    2379                    // sponsor timeout2380                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2381                    sponsor_transfer = match collection_mode {2382                        CollectionMode::NFT => {2383    2384                            // get correct limit2385                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2386                                collection_limits.sponsor_transfer_timeout2387                            } else {2388                                ChainLimit::get().nft_sponsor_transfer_timeout2389                            };2390    2391                            let mut sponsored = true;2392                            if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2393                                let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2394                                let limit_time = last_tx_block + limit.into();2395                                if block_number <= limit_time {2396                                    sponsored = false;2397                                }2398                            }2399                            if sponsored {2400                                <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2401                            }24022403                            sponsored2404                        }2405                        CollectionMode::Fungible(_) => {2406    2407                            // get correct limit2408                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2409                                collection_limits.sponsor_transfer_timeout2410                            } else {2411                                ChainLimit::get().fungible_sponsor_transfer_timeout2412                            };2413    2414                            let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2415                            let mut sponsored = true;2416                            if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2417                                let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2418                                let limit_time = last_tx_block + limit.into();2419                                if block_number <= limit_time {2420                                    sponsored = false;2421                                }2422                            }2423                            if sponsored {2424                                <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2425                            }24262427                            sponsored2428                        }2429                        CollectionMode::ReFungible(_) => {2430    2431                            // get correct limit2432                            let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2433                                collection_limits.sponsor_transfer_timeout2434                            } else {2435                                ChainLimit::get().refungible_sponsor_transfer_timeout2436                            };2437    2438                            let mut sponsored = true;2439                            if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2440                                let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2441                                let limit_time = last_tx_block + limit.into();2442                                if block_number <= limit_time {2443                                    sponsored = false;2444                                }2445                            }2446                            if sponsored {2447                                <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2448                            }24492450                            sponsored2451                        }2452                        _ => {2453                            false2454                        },2455                    };2456                }24572458                if !sponsor_transfer {2459                    T::AccountId::default()2460                } else {2461                    <Collection<T>>::get(collection_id).sponsor2462                }2463            }24642465            _ => T::AccountId::default(),2466        };24672468        // Sponsor smart contracts2469        sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24702471            // On instantiation: set the contract owner2472            Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {24732474                let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2475                    &who,2476                    code_hash,2477                    salt,2478                );2479                <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24802481                T::AccountId::default()2482            },24832484            // When the contract is called, check if the sponsoring is enabled and pay fees from contract endowment if it is2485            Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24862487                let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24882489                let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2490                  && <ContractOwner<T>>::get(called_contract.clone()) == *who;2491                let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2492                  2493                if !owned_contract && white_list_enabled {2494                    if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2495                        return Err(InvalidTransaction::Call.into());2496                    }2497                }24982499                let mut sponsor_transfer = false;2500                if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2501                    let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2502                    let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2503                    let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2504                    let limit_time = last_tx_block + rate_limit;25052506                    if block_number >= limit_time {2507                        <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2508                        sponsor_transfer = true;2509                    }2510                } else {2511                    sponsor_transfer = false;2512                }2513               2514                2515                let mut sp = T::AccountId::default();2516                if sponsor_transfer {2517                    if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2518                        if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2519                            sp = called_contract;2520                        }2521                    }2522                }25232524                sp2525            },25262527            _ => sponsor,2528        };25292530        let mut who_pays_fee: T::AccountId = sponsor.clone();2531        if sponsor == T::AccountId::default() {2532            who_pays_fee = who.clone();2533        }25342535		<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2536			.map(|i| (fee, i))2537    }2538}253925402541impl<T: Config + Send + Sync> SignedExtension2542    for ChargeTransactionPayment<T>2543where2544    BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2545    T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2546    T::AccountId: AsRef<[u8]>,2547    T::AccountId: UncheckedFrom<T::Hash>,2548{2549    const IDENTIFIER: &'static str = "ChargeTransactionPayment";2550    type AccountId = T::AccountId;2551    type Call = T::Call;2552    type AdditionalSigned = ();2553    type Pre = (2554        // tip2555        BalanceOf<T>,2556        // who pays fee2557        Self::AccountId,2558		// imbalance resulting from withdrawing the fee2559		<<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2560    );2561    fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2562        Ok(())2563    }25642565    fn validate(2566        &self,2567        who: &Self::AccountId,2568        call: &Self::Call,2569        info: &DispatchInfoOf<Self::Call>,2570        len: usize,2571    ) -> TransactionValidity {2572		let (fee, _) = self.withdraw_fee(who, call, info, len)?;2573		Ok(ValidTransaction {2574			priority: Self::get_priority(len, info, fee),2575			..Default::default()2576		})2577    }25782579    fn pre_dispatch(2580        self,2581        who: &Self::AccountId,2582        call: &Self::Call,2583        info: &DispatchInfoOf<Self::Call>,2584        len: usize,2585    ) -> Result<Self::Pre, TransactionValidityError> {2586        let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2587        Ok((self.0, who.clone(), imbalance))2588    }25892590    fn post_dispatch(2591        pre: Self::Pre,2592        info: &DispatchInfoOf<Self::Call>,2593        post_info: &PostDispatchInfoOf<Self::Call>,2594        len: usize,2595        _result: &DispatchResult,2596    ) -> Result<(), TransactionValidityError> {2597		let (tip, who, imbalance) = pre;2598		let actual_fee = transaction_payment::Module::<T>::compute_actual_fee(2599			len as u32,2600			info,2601			post_info,2602			tip,2603		);2604		<T as transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2605		Ok(())2606    }2607}26082609// #endregion
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -35,7 +35,7 @@
 }
 
 fn default_re_fungible_data () -> CreateReFungibleData {
-    CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }
+    CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1], pieces: 1023 }
 }
 
 fn create_test_collection_for_owner(mode: &CollectionMode, owner: u64, id: CollectionId) -> CollectionId {
@@ -114,26 +114,6 @@
 }
 
 #[test]
-fn create_re_fungible_collection_fails_with_large_decimal_numbers() {
-    new_test_ext().execute_with(|| {
-        default_limits();
-
-        let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
-        let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
-        let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
-
-        let origin1 = Origin::signed(1);
-        assert_noop!(TemplateModule::create_collection(
-            origin1,
-            col_name1,
-            col_desc1,
-            token_prefix1,
-            CollectionMode::ReFungible(MAX_DECIMAL_POINTS + 1)
-        ), Error::<Test>::CollectionDecimalPointLimitExceeded);
-    });
-}
-
-#[test]
 fn create_nft_item() {
     new_test_ext().execute_with(|| {
         default_limits();
@@ -176,7 +156,7 @@
 fn create_refungible_item() {
     new_test_ext().execute_with(|| {
         default_limits();
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
 
         let data = default_re_fungible_data();
         create_test_item(collection_id, &data.clone().into());
@@ -192,7 +172,7 @@
             TemplateModule::refungible_item_id(collection_id, 1).owner[0],
             Ownership {
                 owner: 1,
-                fraction: 1000
+                fraction: 1023
             }
         );
     });
@@ -203,7 +183,7 @@
     new_test_ext().execute_with(|| {
         default_limits();
         
-        create_test_collection(&CollectionMode::ReFungible(3), 1);
+        create_test_collection(&CollectionMode::ReFungible, 1);
 
         let origin1 = Origin::signed(1);
 
@@ -224,7 +204,7 @@
                 item.owner[0],
                 Ownership {
                     owner: 1,
-                    fraction: 1000
+                    fraction: 1023
                 }
             );
         }
@@ -312,7 +292,7 @@
     new_test_ext().execute_with(|| {
         default_limits();
         
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
 
         let data = default_re_fungible_data();
         create_test_item(collection_id, &data.clone().into());
@@ -331,23 +311,23 @@
             TemplateModule::refungible_item_id(collection_id, 1).owner[0],
             Ownership {
                 owner: 1,
-                fraction: 1000
+                fraction: 1023
             }
         );
-        assert_eq!(TemplateModule::balance_count(1, 1), 1000);
+        assert_eq!(TemplateModule::balance_count(1, 1), 1023);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
         // change owner scenario
-        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1000));
+        assert_ok!(TemplateModule::transfer(origin1.clone(), 2, 1, 1, 1023));
         assert_eq!(
             TemplateModule::refungible_item_id(1, 1).owner[0],
             Ownership {
                 owner: 2,
-                fraction: 1000
+                fraction: 1023
             }
         );
         assert_eq!(TemplateModule::balance_count(1, 1), 0);
-        assert_eq!(TemplateModule::balance_count(1, 2), 1000);
+        assert_eq!(TemplateModule::balance_count(1, 2), 1023);
         // assert_eq!(TemplateModule::address_tokens(1, 1), []);
         assert_eq!(TemplateModule::address_tokens(1, 2), [1]);
 
@@ -357,7 +337,7 @@
             TemplateModule::refungible_item_id(1, 1).owner[0],
             Ownership {
                 owner: 2,
-                fraction: 500
+                fraction: 523
             }
         );
         assert_eq!(
@@ -367,7 +347,7 @@
                 fraction: 500
             }
         );
-        assert_eq!(TemplateModule::balance_count(1, 2), 500);
+        assert_eq!(TemplateModule::balance_count(1, 2), 523);
         assert_eq!(TemplateModule::balance_count(1, 3), 500);
         assert_eq!(TemplateModule::address_tokens(1, 2), [1]);
         assert_eq!(TemplateModule::address_tokens(1, 3), [1]);
@@ -378,7 +358,7 @@
             TemplateModule::refungible_item_id(1, 1).owner[0],
             Ownership {
                 owner: 2,
-                fraction: 300
+                fraction: 323
             }
         );
         assert_eq!(
@@ -388,7 +368,7 @@
                 fraction: 700
             }
         );
-        assert_eq!(TemplateModule::balance_count(1, 2), 300);
+        assert_eq!(TemplateModule::balance_count(1, 2), 323);
         assert_eq!(TemplateModule::balance_count(1, 3), 700);
         assert_eq!(TemplateModule::address_tokens(1, 2), [1]);
         assert_eq!(TemplateModule::address_tokens(1, 3), [1]);
@@ -517,7 +497,7 @@
     new_test_ext().execute_with(|| {
         default_limits();
         
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
         
         let origin1 = Origin::signed(1);
         let origin2 = Origin::signed(2);
@@ -525,7 +505,7 @@
         let data = default_re_fungible_data();
         create_test_item(collection_id, &data.into());
 
-        assert_eq!(TemplateModule::balance_count(1, 1), 1000);
+        assert_eq!(TemplateModule::balance_count(1, 1), 1023);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
 
         assert_ok!(TemplateModule::set_mint_permission(
@@ -543,8 +523,8 @@
         assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
 
         // do approve
-        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1000));
-        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1000);
+        assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1, 1023));
+        assert_eq!(TemplateModule::approved(1, (1, 1, 2)), 1023);
 
         assert_ok!(TemplateModule::transfer_from(
             origin2.clone(),
@@ -554,14 +534,14 @@
             1,
             100
         ));
-        assert_eq!(TemplateModule::balance_count(1, 1), 900);
+        assert_eq!(TemplateModule::balance_count(1, 1), 923);
         assert_eq!(TemplateModule::balance_count(1, 3), 100);
         assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
         assert_eq!(TemplateModule::address_tokens(1, 3), [1]);
 
         assert_eq!(
             TemplateModule::approved(1, (1, 1, 2)),
-            900
+            923
         );
     });
 }
@@ -717,7 +697,7 @@
     new_test_ext().execute_with(|| {
         default_limits();
         
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
         let origin1 = Origin::signed(1);
 
         assert_ok!(TemplateModule::set_mint_permission(
@@ -738,12 +718,12 @@
         create_test_item(collection_id, &data.into());
 
         // check balance (collection with id = 1, user id = 2)
-        assert_eq!(TemplateModule::balance_count(1, 1), 1000);
+        assert_eq!(TemplateModule::balance_count(1, 1), 1023);
 
         // burn item
-        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1000));
+        assert_ok!(TemplateModule::burn_item(origin1.clone(), 1, 1, 1023));
         assert_noop!(
-            TemplateModule::burn_item(origin1.clone(), 1, 1, 1000),
+            TemplateModule::burn_item(origin1.clone(), 1, 1, 1023),
             Error::<Test>::TokenNotFound
         );
 
@@ -807,7 +787,7 @@
         
         let nft_collection_id = create_test_collection(&CollectionMode::NFT, 1);
         let fungible_collection_id = create_test_collection(&CollectionMode::Fungible(3), 2);
-        let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible(3), 3);
+        let re_fungible_collection_id = create_test_collection(&CollectionMode::ReFungible, 3);
         
         // check balance before
         assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 0);
@@ -826,7 +806,7 @@
         // check balance (collection with id = 1, user id = 1)
         assert_eq!(TemplateModule::balance_count(nft_collection_id, 1), 1);
         assert_eq!(TemplateModule::balance_count(fungible_collection_id, 1), 5);
-        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1000);
+        assert_eq!(TemplateModule::balance_count(re_fungible_collection_id, 1), 1023);
         assert_eq!(TemplateModule::nft_item_id(nft_collection_id, 1).owner, 1);
         assert_eq!(TemplateModule::fungible_item_id(fungible_collection_id, 1).value, 5);
         assert_eq!(TemplateModule::refungible_item_id(re_fungible_collection_id, 1).owner[0].owner, 1);
@@ -1905,7 +1885,7 @@
     new_test_ext().execute_with(|| {
         default_limits();
 
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
 
         let origin1 = Origin::signed(1);
 
@@ -1982,7 +1962,7 @@
         }));
 
 
-        let collection_id = create_test_collection(&CollectionMode::ReFungible(3), 1);
+        let collection_id = create_test_collection(&CollectionMode::ReFungible, 1);
 
         let origin1 = Origin::signed(1);
 
modifiedruntime_types.jsondiffbeforeafterboth
--- a/runtime_types.json
+++ b/runtime_types.json
@@ -1,27 +1,4 @@
 {
-    "Schedule": {
-      "version": "u32",
-      "put_code_per_byte_cost": "Gas",
-      "grow_mem_cost": "Gas",
-      "regular_op_cost": "Gas",
-      "return_data_per_byte_cost": "Gas",
-      "event_data_per_byte_cost": "Gas",
-      "event_per_topic_cost": "Gas",
-      "event_base_cost": "Gas",
-      "call_base_cost": "Gas",
-      "instantiate_base_cost": "Gas",
-      "dispatch_base_cost": "Gas",
-      "sandbox_data_read_cost": "Gas",
-      "sandbox_data_write_cost": "Gas",
-      "transfer_cost": "Gas",
-      "instantiate_cost": "Gas",
-      "max_event_topics": "u32",
-      "max_stack_height": "u32",
-      "max_memory_pages": "u32",
-      "max_table_size": "u32",
-      "enable_println": "bool",
-      "max_subject_len": "u32"
-    },
     "AccessMode": {
       "_enum": [
         "Normal",
@@ -34,7 +11,7 @@
         "Invalid": null,
         "NFT": null,
         "Fungible": "DecimalPoints",
-        "ReFungible": "DecimalPoints"
+        "ReFungible": null
       }
     },
     "Ownership": {
@@ -84,7 +61,8 @@
     },
     "CreateReFungibleData": {
       "const_data": "Vec<u8>",
-      "variable_data": "Vec<u8>" 
+      "variable_data": "Vec<u8>",
+      "pieces": "u128"
     },
     "CreateItemData": {
       "_enum": {
@@ -120,14 +98,5 @@
       "SponsorTimeout": "u32",
       "OwnerCanTransfer": "bool",
       "OwnerCanDestroy": "bool"
-    },
-    "AccountInfo": "AccountInfoWithProviders",
-    "AccountInfoWithProviders": {
-      "nonce": "Index",
-      "consumers": "RefCount",
-      "providers": "RefCount",
-      "data": "AccountData"
     }
-
-  }
-  
\ No newline at end of file
+}
\ No newline at end of file
modifiedtests/src/addCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/addCollectionAdmin.test.ts
+++ b/tests/src/addCollectionAdmin.test.ts
@@ -1,4 +1,9 @@
-import { ApiPromise } from '@polkadot/api';
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import { ApiPromise } from '@polkadot/api';
 import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
@@ -98,7 +103,7 @@
     });
   });
 
-  it('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
+  it.only('Add an admin to a collection that has reached the maximum number of admins limit', async () => {
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const accounts = [
@@ -112,8 +117,8 @@
       ];
       const collectionId = await createCollectionExpectSuccess();
 
-      const chainLimits: any = await api.query.nft.chainLimit();
-      const chainAdminLimit = chainLimits.CollectionAdminsLimit.toNumber();
+      const chainLimit = await api.query.nft.chainLimit() as unknown as { CollectionAdminsLimit: BN };
+      const chainAdminLimit = chainLimit.CollectionAdminsLimit.toNumber();
       expect(chainAdminLimit).to.be.equal(5);
 
       for (let i = 0; i < chainAdminLimit; i++) {
modifiedtests/src/addToContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/addToContractWhiteList.test.ts
+++ b/tests/src/addToContractWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/addToWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/addToWhiteList.test.ts
+++ b/tests/src/addToWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/approve.test.tsdiffbeforeafterboth
--- a/tests/src/approve.test.ts
+++ b/tests/src/approve.test.ts
@@ -34,7 +34,7 @@
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
     });
@@ -56,7 +56,7 @@
       await approveExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 0);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 1);
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 0);
@@ -95,7 +95,7 @@
       await approveExpectFail(fungibleCollectionId, 1, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await destroyCollectionExpectSuccess(reFungibleCollectionId);
       await approveExpectFail(reFungibleCollectionId, 1, Alice, Bob);
     });
@@ -113,7 +113,7 @@
       await approveExpectFail(fungibleCollectionId, 2, Alice, Bob);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       await approveExpectFail(reFungibleCollectionId, 2, Alice, Bob);
     });
   });
@@ -132,7 +132,7 @@
       await approveExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice);
       // reFungible
       const reFungibleCollectionId =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Bob, Alice);
     });
modifiedtests/src/burnItem.test.tsdiffbeforeafterboth
--- a/tests/src/burnItem.test.ts
+++ b/tests/src/burnItem.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from './substrate/substrate-api';
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
@@ -70,7 +75,7 @@
   });
   it('Burn item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode }});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
@@ -91,7 +96,7 @@
 
   it('Burn owned portion of item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 2 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: createMode}});
     const tokenId = await createItemExpectSuccess(alice, collectionId, createMode);
 
     await usingApi(async (api) => {
@@ -107,7 +112,7 @@
       const tx = api.tx.nft.burnItem(collectionId, tokenId, 0);
       const events2 = await submitTransactionAsync(bob, tx);
       const result2 = getGenericResult(events2);
-  
+
       // Get balances 
       const balance: any = (await api.query.nft.reFungibleItemList(collectionId, tokenId)).toJSON();
       // console.log(balance);
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -1,4 +1,9 @@
-import chai from 'chai';
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
+import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
 import { default as usingApi, submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -115,7 +115,7 @@
   });
 
   it('ReFungible: Transfer fees are paid by the sponsor after confirmation', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
 
@@ -247,7 +247,7 @@
   });
 
   it('ReFungible: Sponsoring is rate limited', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0 }});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
     await confirmSponsorshipExpectSuccess(collectionId, '//Bob');
 
modifiedtests/src/contracts.test.tsdiffbeforeafterboth
--- a/tests/src/contracts.test.ts
+++ b/tests/src/contracts.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/createCollection.test.tsdiffbeforeafterboth
--- a/tests/src/createCollection.test.ts
+++ b/tests/src/createCollection.test.ts
@@ -28,7 +28,7 @@
     await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
   });
   it('Create new ReFungible collection', async () => {
-    await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
   });
 });
 
modifiedtests/src/createItem.test.tsdiffbeforeafterboth
--- a/tests/src/createItem.test.ts
+++ b/tests/src/createItem.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { default as usingApi } from './substrate/substrate-api';
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
@@ -28,7 +33,7 @@
   });
   it('Create new item in ReFungible collection', async () => {
     const createMode = 'ReFungible';
-    const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode, decimalPoints: 0}});
+    const newCollectionID = await createCollectionExpectSuccess({mode: {type: createMode}});
     await createItemExpectSuccess(alice, newCollectionID, createMode);
   });
 });
modifiedtests/src/createMultipleItems.test.tsdiffbeforeafterboth
--- a/tests/src/createMultipleItems.test.ts
+++ b/tests/src/createMultipleItems.test.ts
@@ -56,14 +56,14 @@
 
   it('Create  0x31, 0x32, 0x33 items in active ReFungible collection and verify tokens data in chain', async () => {
     await usingApi(async (api: ApiPromise) => {
-      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const itemsListIndexBefore = await api.query.nft.itemListIndex(collectionId) as unknown as BN;
       expect(itemsListIndexBefore.toNumber()).to.be.equal(0);
       const Alice = privateKey('//Alice');
       const args = [
-        { Refungible: ['0x31', '0x31'] },
-        { Refungible: ['0x32', '0x32'] },
-        { Refungible: ['0x33', '0x33'] },
+        {refungible: {const_data: [0x31], variable_data: [0x31], pieces: 1}},
+        {refungible: {const_data: [0x32], variable_data: [0x32], pieces: 1}},
+        {refungible: {const_data: [0x33], variable_data: [0x33], pieces: 1}},
       ];
       const createMultipleItemsTx = await api.tx.nft
         .createMultipleItems(collectionId, Alice.address, args);
@@ -137,7 +137,7 @@
 
       // ReFungible
       const collectionIdReFungible =
-        await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const argsReFungible = [
         { ReFungible: ['1'.repeat(2049), '1'.repeat(2049)] },
         { ReFungible: ['2'.repeat(2049), '2'.repeat(2049)] },
modifiedtests/src/destroyCollection.test.tsdiffbeforeafterboth
--- a/tests/src/destroyCollection.test.ts
+++ b/tests/src/destroyCollection.test.ts
@@ -1,12 +1,14 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
-import { default as usingApi, submitTransactionAsync } from "./substrate/substrate-api";
-import { createCollectionExpectSuccess, createCollectionExpectFailure, destroyCollectionExpectSuccess, destroyCollectionExpectFailure } from "./util/helpers";
-import type { AccountId, EventRecord } from '@polkadot/types/interfaces';
-import privateKey from './substrate/privateKey';
+import { default as usingApi } from "./substrate/substrate-api";
+import { createCollectionExpectSuccess, destroyCollectionExpectSuccess, destroyCollectionExpectFailure } from "./util/helpers";
 
 chai.use(chaiAsPromised);
-const expect = chai.expect;
 
 describe('integration test: ext. destroyCollection():', () => {
   it('NFT collection can be destroyed', async () => {
@@ -18,7 +20,7 @@
     await destroyCollectionExpectSuccess(collectionId);
   });
   it('ReFungible collection can be destroyed', async () => {
-    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+    const collectionId = await createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await destroyCollectionExpectSuccess(collectionId);
   });
 });
modifiedtests/src/enableContractSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/enableContractSponsoring.test.ts
+++ b/tests/src/enableContractSponsoring.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -1,5 +1,9 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { ApiPromise } from '@polkadot/api';
-import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import privateKey from './substrate/privateKey';
modifiedtests/src/removeFromWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/removeFromWhiteList.test.ts
+++ b/tests/src/removeFromWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import { default as usingApi } from './substrate/substrate-api';
modifiedtests/src/setCollectionLimits.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionLimits.test.ts
+++ b/tests/src/setCollectionLimits.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setchainlimits
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
modifiedtests/src/setCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/setCollectionSponsor.test.ts
+++ b/tests/src/setCollectionSponsor.test.ts
@@ -9,7 +9,6 @@
 import { createCollectionExpectSuccess, setCollectionSponsorExpectSuccess, destroyCollectionExpectSuccess, setCollectionSponsorExpectFailure } from "./util/helpers";
 import { Keyring } from "@polkadot/api";
 import { IKeyringPair } from "@polkadot/types/types";
-import type { AccountId } from '@polkadot/types/interfaces';
 
 chai.use(chaiAsPromised);
 const expect = chai.expect;
@@ -34,7 +33,7 @@
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
   it('Set ReFungible collection sponsor', async () => {
-    const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible', decimalPoints: 0} });
+    const collectionId = await createCollectionExpectSuccess({ mode: {type: 'ReFungible'} });
     await setCollectionSponsorExpectSuccess(collectionId, bob.address);
   });
 
modifiedtests/src/setConstOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setConstOnChainSchema.test.ts
+++ b/tests/src/setConstOnChainSchema.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
modifiedtests/src/setContractSponsoringRateLimit.test.tsdiffbeforeafterboth
--- a/tests/src/setContractSponsoringRateLimit.test.ts
+++ b/tests/src/setContractSponsoringRateLimit.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import privateKey from './substrate/privateKey';
 import usingApi from './substrate/substrate-api';
modifiedtests/src/setMintPermission.test.tsdiffbeforeafterboth
--- a/tests/src/setMintPermission.test.ts
+++ b/tests/src/setMintPermission.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import privateKey from './substrate/privateKey';
 import usingApi from './substrate/substrate-api';
modifiedtests/src/setPublicAccessMode.test.tsdiffbeforeafterboth
--- a/tests/src/setPublicAccessMode.test.ts
+++ b/tests/src/setPublicAccessMode.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setschemaversion
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
modifiedtests/src/setSchemaVersion.test.tsdiffbeforeafterboth
--- a/tests/src/setSchemaVersion.test.ts
+++ b/tests/src/setSchemaVersion.test.ts
@@ -1,7 +1,11 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 // https://unique-network.readthedocs.io/en/latest/jsapi.html#setschemaversion
 import { ApiPromise, Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
-import BN from 'bn.js';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, {submitTransactionAsync, submitTransactionExpectFailAsync} from './substrate/substrate-api';
modifiedtests/src/setVariableMetaData.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableMetaData.test.ts
+++ b/tests/src/setVariableMetaData.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
 import chaiAsPromised from 'chai-as-promised';
modifiedtests/src/setVariableOnChainSchema.test.tsdiffbeforeafterboth
--- a/tests/src/setVariableOnChainSchema.test.ts
+++ b/tests/src/setVariableOnChainSchema.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import { Keyring } from '@polkadot/api';
 import { IKeyringPair } from '@polkadot/types/types';
 import chai from 'chai';
modifiedtests/src/toggleContractWhiteList.test.tsdiffbeforeafterboth
--- a/tests/src/toggleContractWhiteList.test.ts
+++ b/tests/src/toggleContractWhiteList.test.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import chai from "chai";
 import chaiAsPromised from 'chai-as-promised';
 import usingApi, { submitTransactionAsync, submitTransactionExpectFailAsync } from "./substrate/substrate-api";
modifiedtests/src/transfer.test.tsdiffbeforeafterboth
--- a/tests/src/transfer.test.ts
+++ b/tests/src/transfer.test.ts
@@ -63,7 +63,7 @@
     });
   });
 
-  it('Create collection, balance transfers and check balance', async () => {
+  it('User can transfer owned token', async () => {
     await usingApi(async (api) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
@@ -77,10 +77,10 @@
       await transferExpectSuccess(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await transferExpectSuccess(reFungibleCollectionId,
-        newReFungibleTokenId, Alice, Bob, 1, 'ReFungible');
+        newReFungibleTokenId, Alice, Bob, 100, 'ReFungible');
     });
   });
 });
@@ -119,7 +119,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await destroyCollectionExpectSuccess(reFungibleCollectionId);
     await transferExpectFail(reFungibleCollectionId,
@@ -134,7 +134,7 @@
     await transferExpectFail(fungibleCollectionId, 2, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     await transferExpectFail(reFungibleCollectionId,
       2, Alice, Bob, 1, 'ReFungible');
   });
@@ -151,7 +151,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Alice, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await burnItemExpectSuccess(Alice, reFungibleCollectionId, newReFungibleTokenId, 1);
     await transferExpectFail(reFungibleCollectionId,
@@ -168,7 +168,7 @@
     await transferExpectFail(fungibleCollectionId, newFungibleTokenId, Charlie, Bob, 1, 'Fungible');
     // reFungible
     const reFungibleCollectionId = await
-      createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+      createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
     const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
     await transferExpectFail(reFungibleCollectionId,
       newReFungibleTokenId, Charlie, Bob, 1, 'ReFungible');
modifiedtests/src/transferFrom.test.tsdiffbeforeafterboth
--- a/tests/src/transferFrom.test.ts
+++ b/tests/src/transferFrom.test.ts
@@ -25,7 +25,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -40,11 +40,11 @@
       await transferFromExpectSuccess(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1, 'Fungible');
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
-      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
+      await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob, 100);
       await transferFromExpectSuccess(reFungibleCollectionId,
-        newReFungibleTokenId, Bob, Alice, Charlie, 1, 'ReFungible');
+        newReFungibleTokenId, Bob, Alice, Charlie, 100, 'ReFungible');
     });
   });
 });
@@ -54,7 +54,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionCount = await api.query.nft.createdCollectionCount() as unknown as number;
       await approveExpectFail(nftCollectionCount + 1, 1, Alice, Bob);
@@ -96,7 +96,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -109,7 +109,7 @@
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 1);
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await transferFromExpectFail(reFungibleCollectionId,
         newReFungibleTokenId, Bob, Alice, Charlie, 1);
@@ -120,7 +120,7 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
+      const Charlie = privateKey('//Charlie');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -135,7 +135,7 @@
       await transferFromExpectFail(fungibleCollectionId, newFungibleTokenId, Bob, Alice, Charlie, 2);
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       await approveExpectSuccess(reFungibleCollectionId, newReFungibleTokenId, Alice, Bob);
       await transferFromExpectFail(reFungibleCollectionId,
@@ -147,8 +147,8 @@
     await usingApi(async (api: ApiPromise) => {
       const Alice = privateKey('//Alice');
       const Bob = privateKey('//Bob');
-      const Charlie = privateKey('//CHARLIE');
-      const Dave = privateKey('//DAVE');
+      const Charlie = privateKey('//Charlie');
+      const Dave = privateKey('//Dave');
       // nft
       const nftCollectionId = await createCollectionExpectSuccess();
       const newNftTokenId = await createItemExpectSuccess(Alice, nftCollectionId, 'NFT');
@@ -174,7 +174,7 @@
       }
       // reFungible
       const reFungibleCollectionId = await
-        createCollectionExpectSuccess({mode: {type: 'ReFungible', decimalPoints: 0}});
+        createCollectionExpectSuccess({mode: {type: 'ReFungible'}});
       const newReFungibleTokenId = await createItemExpectSuccess(Alice, reFungibleCollectionId, 'ReFungible');
       try {
         await approveExpectFail(reFungibleCollectionId, newReFungibleTokenId, Dave, Bob);
modifiedtests/src/types.tsdiffbeforeafterboth
--- a/tests/src/types.ts
+++ b/tests/src/types.ts
@@ -1,3 +1,8 @@
+//
+// This file is subject to the terms and conditions defined in
+// file 'LICENSE', which is part of this source code package.
+//
+
 import BN from 'bn.js';
 
 export interface ICollectionInterface {
modifiedtests/src/util/helpers.tsdiffbeforeafterboth
--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -124,21 +124,6 @@
 
 interface ReFungible {
   type: 'ReFungible';
-  decimalPoints: number;
-}
-
-interface Nft {
-  type: 'NFT'
-}
-
-interface Fungible {
-  type: 'Fungible',
-  decimalPoints: number
-}
-
-interface ReFungible {
-  type: 'ReFungible',
-  decimalPoints: number
 }
 
 type CollectionMode = Nft | Fungible | ReFungible | Invalid;
@@ -174,7 +159,7 @@
     } else if (mode.type === 'Fungible') {
       modeprm = {fungible: mode.decimalPoints};
     } else if (mode.type === 'ReFungible') {
-      modeprm = {refungible: mode.decimalPoints};
+      modeprm = {refungible: null};
     } else if (mode.type === 'Invalid') {
       modeprm = {invalid: null};
     }
@@ -216,7 +201,7 @@
   } else if (mode.type === 'Fungible') {
     modeprm = {fungible: mode.decimalPoints};
   } else if (mode.type === 'ReFungible') {
-    modeprm = {refungible: mode.decimalPoints};
+    modeprm = {refungible: null};
   } else if (mode.type === 'Invalid') {
     modeprm = {invalid: null};
   }
@@ -620,6 +605,9 @@
     if (createMode === 'Fungible') {
       const createData = {fungible: {value: 10}};
       tx = api.tx.nft.createItem(collectionId, owner, createData);
+    } else if (createMode === 'ReFungible') {
+      const createData = {refungible: {const_data: [], variable_data: [], pieces: 100}};
+      tx = api.tx.nft.createItem(collectionId, owner, createData);
     } else {
       tx = api.tx.nft.createItem(collectionId, owner, createMode);
     }