--- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "Inflector" version = "0.11.4" @@ -3606,6 +3608,7 @@ "pallet-contracts-primitives", "pallet-contracts-rpc-runtime-api", "pallet-grandpa", + "pallet-inflation", "pallet-nft", "pallet-randomness-collective-flip", "pallet-sudo", @@ -3920,6 +3923,24 @@ ] [[package]] +name = "pallet-inflation" +version = "3.0.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "pallet-balances", + "pallet-randomness-collective-flip", + "pallet-timestamp", + "parity-scale-codec", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "sp-std", +] + +[[package]] name = "pallet-nft" version = "3.0.0" dependencies = [ --- /dev/null +++ b/pallets/inflation/Cargo.toml @@ -0,0 +1,48 @@ +[package] +authors = ['Substrate DevHub '] +description = 'Unqiue pallet inflation' +edition = '2018' +homepage = 'https://substrate.io' +license = 'Unlicense' +name = 'pallet-inflation' +repository = 'https://github.com/usetech-llc/nft_private/' +version = '3.0.0' + +[package.metadata.docs.rs] +targets = ['x86_64-unknown-linux-gnu'] + +# alias "parity-scale-code" to "codec" +[dependencies.codec] +default-features = false +features = ['derive'] +package = 'parity-scale-codec' +version = '2.0.0' + +[dependencies] +serde = { version = "1.0.119" } +frame-support = { default-features = false, version = '3.0.0' } +frame-system = { default-features = false, version = '3.0.0' } +pallet-balances = { default-features = false, version = '3.0.0' } +pallet-timestamp = { default-features = false, version = '3.0.0' } +pallet-randomness-collective-flip = { default-features = false, version = '3.0.0' } +sp-std = { default-features = false, version = '3.0.0' } +frame-benchmarking = { default-features = false, version = "3.0.0", optional = true } +sp-core = { default-features = false, version = '3.0.0' } +sp-io = { default-features = false, version = '3.0.0' } +sp-runtime = { default-features = false, version = '3.0.0' } + +[features] +default = ['std'] +std = [ + 'codec/std', + 'serde/std', + 'frame-support/std', + 'frame-system/std', + 'pallet-balances/std', + 'pallet-timestamp/std', + 'pallet-randomness-collective-flip/std', + 'sp-std/std', + 'sp-runtime/std', + 'frame-benchmarking/std', +] +runtime-benchmarks = ["frame-benchmarking"] --- /dev/null +++ b/pallets/inflation/src/benchmarking.rs @@ -0,0 +1,19 @@ +#![cfg(feature = "runtime-benchmarks")] + +use super::*; +use crate::Module as Inflation; + +use sp_std::prelude::*; +use frame_system::RawOrigin; +use frame_benchmarking::{benchmarks}; +use frame_support::traits::OnInitialize; + +benchmarks! { + + on_initialize { + let block1: T::BlockNumber = T::BlockNumber::from(1u32); + let block2: T::BlockNumber = T::BlockNumber::from(2u32); + Inflation::::on_initialize(block1); // Create Treasury account + }: { Inflation::::on_initialize(block2); } // Benchmark deposit_into_existing path + +} --- /dev/null +++ b/pallets/inflation/src/lib.rs @@ -0,0 +1,130 @@ +// +// This file is subject to the terms and conditions defined in +// file 'LICENSE', which is part of this source code package. +// + +#![recursion_limit = "1024"] + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "std")] +pub use std::*; + +#[cfg(feature = "std")] +pub use serde::*; + +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + +#[cfg(test)] +mod tests; + +pub use frame_support::{ + construct_runtime, decl_module, decl_storage, + ensure, + traits::{ + Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, + Randomness, IsSubType, WithdrawReasons, + }, + weights::{ + constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND}, + DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight, + WeightToFeePolynomial, DispatchClass, + }, + StorageValue, + transactional, +}; + +// #[cfg(feature = "runtime-benchmarks")] +pub use frame_support::dispatch::DispatchResult; + +use sp_runtime::{ + Perbill, + traits::{Zero} +}; +use sp_std::convert::TryInto; + +use frame_system::{self as system}; + +/// The balance type of this module. +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +pub const YEAR: u32 = 5_259_600; +pub const TOTAL_YEARS_UNTIL_FLAT: u32 = 9; +pub const START_INFLATION_PERCENT: u32 = 10; +pub const END_INFLATION_PERCENT: u32 = 4; + +pub trait Config: system::Config { + type Currency: Currency; + type TreasuryAccountId: Get; + type InflationBlockInterval: Get; +} + +decl_storage! { + trait Store for Module as Inflation { + /// starting year total issuance + pub StartingYearTotalIssuance get(fn starting_year_total_issuance): BalanceOf; + + /// Current block inflation + pub BlockInflation get(fn block_inflation): BalanceOf; + } +} + +decl_module! { + pub struct Module for enum Call + where + origin: T::Origin, + { + const InflationBlockInterval: T::BlockNumber = T::InflationBlockInterval::get(); + + fn on_initialize(now: T::BlockNumber) -> Weight + { + let mut consumed_weight = 0; + let mut add_weight = |reads, writes, weight| { + consumed_weight += T::DbWeight::get().reads_writes(reads, writes); + consumed_weight += weight; + }; + + let block_interval: u32 = T::InflationBlockInterval::get().try_into().unwrap_or(0); + + // Recalculate inflation on the first block of the year (or if it is not initialized yet) + if (now % T::BlockNumber::from(YEAR)).is_zero() || >::get().is_zero() { + let current_year: u32 = (now / T::BlockNumber::from(YEAR)).try_into().unwrap_or(0); + + let one_percent = Perbill::from_percent(1); + + if current_year <= TOTAL_YEARS_UNTIL_FLAT { + let amount: BalanceOf = Perbill::from_rational_approximation( + block_interval * (START_INFLATION_PERCENT * TOTAL_YEARS_UNTIL_FLAT - current_year * (START_INFLATION_PERCENT - END_INFLATION_PERCENT)), + YEAR * TOTAL_YEARS_UNTIL_FLAT + ) * ( one_percent * T::Currency::total_issuance() ); + >::put(amount); + } + else { + let amount: BalanceOf = Perbill::from_rational_approximation( + block_interval * END_INFLATION_PERCENT, + YEAR + ) * (one_percent * T::Currency::total_issuance()); + >::put(amount); + } + >::set(T::Currency::total_issuance()); + + // First time deposit + T::Currency::deposit_creating(&T::TreasuryAccountId::get(), >::get()); + + add_weight(7, 6, 28_300_000); + } + + // Apply inflation every InflationBlockInterval blocks and in the 1st block to initialize Treasury account + else if (now % T::BlockNumber::from(block_interval)).is_zero() { + T::Currency::deposit_into_existing(&T::TreasuryAccountId::get(), >::get()).ok(); + + add_weight(3, 2, 12_900_000); + } + + consumed_weight + } + + } +} --- /dev/null +++ b/pallets/inflation/src/tests.rs @@ -0,0 +1,192 @@ +#[cfg(test)] +mod tests { + use crate as pallet_inflation; + + use frame_system; + use frame_support::{traits::{Currency}, parameter_types}; + use frame_support::{traits::OnInitialize}; + use sp_core::H256; + use sp_runtime::{traits::{BlakeTwo256, IdentityLookup}, testing::Header}; + + type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic; + type Block = frame_system::mocking::MockBlock; + + const YEAR: u64 = 5_259_600; + + parameter_types! { + pub const ExistentialDeposit: u64 = 1; + pub const MaxLocks: u32 = 50; + } + + impl pallet_balances::Config for Test { + type AccountStore = System; + type Balance = u64; + type DustRemoval = (); + type Event = (); + type ExistentialDeposit = ExistentialDeposit; + type WeightInfo = (); + type MaxLocks = MaxLocks; + } + + frame_support::construct_runtime!( + pub enum Test where + Block = Block, + NodeBlock = Block, + UncheckedExtrinsic = UncheckedExtrinsic, + { + Balances: pallet_balances::{Module, Call, Storage}, + System: frame_system::{Module, Call, Config, Storage, Event}, + Inflation: pallet_inflation::{Module, Call, Storage}, + } + ); + + parameter_types! { + pub const BlockHashCount: u64 = 250; + pub BlockWeights: frame_system::limits::BlockWeights = + frame_system::limits::BlockWeights::simple_max(1024); + pub const SS58Prefix: u8 = 42; + } + + impl frame_system::Config for Test { + type BaseCallFilter = (); + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type Origin = Origin; + type Call = Call; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = u64; + type Lookup = IdentityLookup; + type Header = Header; + type Event = (); + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + } + + parameter_types! { + pub TreasuryAccountId: u64 = 1234; + pub const InflationBlockInterval: u32 = 100; // every time per how many blocks inflation is applied + } + + impl pallet_inflation::Config for Test { + type Currency = Balances; + type TreasuryAccountId = TreasuryAccountId; + type InflationBlockInterval = InflationBlockInterval; + } + + // Build genesis storage according to the mock runtime. + pub fn new_test_ext() -> sp_io::TestExternalities { + frame_system::GenesisConfig::default().build_storage::().unwrap().into() + } + + #[test] + fn inflation_works() { + new_test_ext().execute_with(|| { + // Total issuance = 1_000_000_000 + let initial_issuance: u64 = 1_000_000_000; + let _ = >::deposit_creating(&1234, initial_issuance); + assert_eq!(Balances::free_balance(1234), initial_issuance); + + // BlockInflation should be set after 1st block and + // first inflation deposit should be equal to BlockInflation + Inflation::on_initialize(1); + assert!(Inflation::block_inflation() > 0); + assert_eq!(Balances::free_balance(1234) - initial_issuance, Inflation::block_inflation()); + }); + } + + #[test] + fn inflation_second_deposit() { + new_test_ext().execute_with(|| { + // Total issuance = 1_000_000_000 + let initial_issuance: u64 = 1_000_000_000; + let _ = >::deposit_creating(&1234, initial_issuance); + assert_eq!(Balances::free_balance(1234), initial_issuance); + Inflation::on_initialize(1); + + // Next inflation deposit happens when block is multiple of InflationBlockInterval + let mut block: u32 = 2; + let balance_before: u64 = Balances::free_balance(1234); + while block % InflationBlockInterval::get() != 0 { + Inflation::on_initialize(block as u64); + block += 1; + } + let balance_just_before: u64 = Balances::free_balance(1234); + assert_eq!(balance_before, balance_just_before); + + // The block with inflation + Inflation::on_initialize(block as u64); + let balance_after: u64 = Balances::free_balance(1234); + assert_eq!(balance_after - balance_just_before, Inflation::block_inflation()); + }); + } + + #[test] + fn inflation_in_1_year() { + new_test_ext().execute_with(|| { + // Total issuance = 1_000_000_000 + let initial_issuance: u64 = 1_000_000_000; + let _ = >::deposit_creating(&1234, initial_issuance); + assert_eq!(Balances::free_balance(1234), initial_issuance); + Inflation::on_initialize(1); + let block_inflation_year_0 = Inflation::block_inflation(); + + Inflation::on_initialize(YEAR); + let block_inflation_year_1 = Inflation::block_inflation(); + + // Assert that year 1 inflation is less than year 0 + assert!(block_inflation_year_0 > block_inflation_year_1); + }); + } + + #[test] + fn inflation_in_1_to_9_years() { + new_test_ext().execute_with(|| { + // Total issuance = 1_000_000_000 + let initial_issuance: u64 = 1_000_000_000; + let _ = >::deposit_creating(&1234, initial_issuance); + assert_eq!(Balances::free_balance(1234), initial_issuance); + Inflation::on_initialize(1); + + for year in 1..=9 { + let block_inflation_year_before = Inflation::block_inflation(); + Inflation::on_initialize(YEAR * year); + let block_inflation_year_after = Inflation::block_inflation(); + + // Assert that next year inflation is less than previous year inflation + assert!(block_inflation_year_before > block_inflation_year_after); + } + + }); + } + + #[test] + fn inflation_after_year_10_is_flat() { + new_test_ext().execute_with(|| { + // Total issuance = 1_000_000_000 + let initial_issuance: u64 = 1_000_000_000; + let _ = >::deposit_creating(&1234, initial_issuance); + assert_eq!(Balances::free_balance(1234), initial_issuance); + Inflation::on_initialize(YEAR * 9); + + for year in 10..=20 { + let block_inflation_year_before = Inflation::block_inflation(); + Inflation::on_initialize(YEAR * year); + let block_inflation_year_after = Inflation::block_inflation(); + + // Assert that next year inflation is equal to previous year inflation + assert_eq!(block_inflation_year_before, block_inflation_year_after); + } + }); + } + +} --- a/pallets/nft/src/benchmarking.rs +++ b/pallets/nft/src/benchmarking.rs @@ -1,420 +1,419 @@ -#[cfg(feature = "runtime-benchmarks")] -// mod benchmarking { - use super::*; - use sp_std::prelude::*; - use frame_system::RawOrigin; - // use frame_support::{ensure, traits::OnFinalize}; - use frame_benchmarking::{benchmarks, account, whitelisted_caller}; // , TrackedStorageKey, - use crate::Module as Nft; +#![cfg(feature = "runtime-benchmarks")] - const SEED: u32 = 1; +use super::*; +use crate::Module as Nft; - fn default_nft_data() -> CreateItemData { - CreateItemData::NFT(CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }) - } - - fn default_fungible_data () -> CreateItemData { - CreateItemData::Fungible(CreateFungibleData { }) - } - - fn default_re_fungible_data () -> CreateItemData { - CreateItemData::ReFungible(CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }) - } +use sp_std::prelude::*; +use frame_system::RawOrigin; +use frame_benchmarking::{benchmarks, account, whitelisted_caller}; // , TrackedStorageKey, +const SEED: u32 = 1; +/* +fn default_nft_data() -> CreateItemData { + CreateItemData::NFT(CreateNftData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }) +} - benchmarks! { +fn default_fungible_data () -> CreateItemData { + CreateItemData::Fungible(CreateFungibleData { }) +} - _ {} +fn default_re_fungible_data () -> CreateItemData { + CreateItemData::ReFungible(CreateReFungibleData { const_data: vec![1, 2, 3], variable_data: vec![3, 2, 1] }) +} +*/ - create_collection { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = account("caller", 0, SEED); - }: create_collection(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode) - verify { - assert_eq!(Nft::::collection(2).owner, caller); - } +benchmarks! { - destroy_collection { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: destroy_collection(RawOrigin::Signed(caller.clone()), 2) + create_collection { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = account("caller", 0, SEED); + }: _(RawOrigin::Signed(caller.clone()), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode) +/* + verify { + assert_eq!(Nft::::collection_id(2).owner, caller); + } + destroy_collection { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: _(RawOrigin::Signed(caller.clone()), 2) - add_to_white_list { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - let whitelist_account: T::AccountId = account("admin", 0, SEED); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: add_to_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account) + add_to_white_list { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + let whitelist_account: T::AccountId = account("admin", 0, SEED); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: add_to_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account) - remove_from_white_list { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - let whitelist_account: T::AccountId = account("admin", 0, SEED); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - Nft::::add_to_white_list(RawOrigin::Signed(caller.clone()).into(), 2, whitelist_account.clone())?; - }: remove_from_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account) + remove_from_white_list { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + let whitelist_account: T::AccountId = account("admin", 0, SEED); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + Nft::::add_to_white_list(RawOrigin::Signed(caller.clone()).into(), 2, whitelist_account.clone())?; + }: remove_from_white_list(RawOrigin::Signed(caller.clone()), 2, whitelist_account) - set_public_access_mode { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_public_access_mode(RawOrigin::Signed(caller.clone()), 2, AccessMode::WhiteList) + set_public_access_mode { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_public_access_mode(RawOrigin::Signed(caller.clone()), 2, AccessMode::WhiteList) - set_mint_permission { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_mint_permission(RawOrigin::Signed(caller.clone()), 2, true) + set_mint_permission { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_mint_permission(RawOrigin::Signed(caller.clone()), 2, true) - change_collection_owner { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let new_owner: T::AccountId = account("admin", 0, SEED); - }: change_collection_owner(RawOrigin::Signed(caller.clone()), 2, new_owner) + change_collection_owner { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let new_owner: T::AccountId = account("admin", 0, SEED); + }: change_collection_owner(RawOrigin::Signed(caller.clone()), 2, new_owner) - add_collection_admin { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let new_admin: T::AccountId = account("admin", 0, SEED); - }: add_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin) + add_collection_admin { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let new_admin: T::AccountId = account("admin", 0, SEED); + }: add_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin) - remove_collection_admin { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let new_admin: T::AccountId = account("admin", 0, SEED); - Nft::::add_collection_admin(RawOrigin::Signed(caller.clone()).into(), 2, new_admin.clone())?; - }: remove_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin) + remove_collection_admin { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let new_admin: T::AccountId = account("admin", 0, SEED); + Nft::::add_collection_admin(RawOrigin::Signed(caller.clone()).into(), 2, new_admin.clone())?; + }: remove_collection_admin(RawOrigin::Signed(caller.clone()), 2, new_admin) - set_collection_sponsor { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_collection_sponsor(RawOrigin::Signed(caller.clone()), 2, caller.clone()) + set_collection_sponsor { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_collection_sponsor(RawOrigin::Signed(caller.clone()), 2, caller.clone()) - confirm_sponsorship { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - Nft::::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?; - }: confirm_sponsorship(RawOrigin::Signed(caller.clone()), 2) + confirm_sponsorship { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + Nft::::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?; + }: confirm_sponsorship(RawOrigin::Signed(caller.clone()), 2) - remove_collection_sponsor { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - Nft::::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?; - Nft::::confirm_sponsorship(RawOrigin::Signed(caller.clone()).into(), 2)?; - }: remove_collection_sponsor(RawOrigin::Signed(caller.clone()), 2) + remove_collection_sponsor { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + Nft::::set_collection_sponsor(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone())?; + Nft::::confirm_sponsorship(RawOrigin::Signed(caller.clone()).into(), 2)?; + }: remove_collection_sponsor(RawOrigin::Signed(caller.clone()), 2) - // nft item - create_item_nft { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_nft_data(); - - }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) + // nft item + create_item_nft { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_nft_data(); + + }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) - #[extra] - create_item_nft_large { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - let mut nft_data = CreateNftData { - const_data: vec![], - variable_data: vec![] - }; - for i in 0..1998 { - nft_data.const_data.push(10); - nft_data.variable_data.push(10); - } - let data = CreateItemData::NFT(nft_data); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + #[extra] + create_item_nft_large { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + let mut nft_data = CreateNftData { + const_data: vec![], + variable_data: vec![] + }; + for i in 0..1998 { + nft_data.const_data.push(10); + nft_data.variable_data.push(10); + } + let data = CreateItemData::NFT(nft_data); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) + }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) - // fungible item - create_item_fungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::Fungible(3); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_fungible_data(); + // fungible item + create_item_fungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::Fungible(3); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_fungible_data(); - }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) + }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) - // refungible item - create_item_refungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_re_fungible_data(); + // refungible item + create_item_refungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_re_fungible_data(); - }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) + }: create_item(RawOrigin::Signed(caller.clone()), 2, caller.clone(), data) - burn_item { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_nft_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + burn_item { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_nft_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: burn_item(RawOrigin::Signed(caller.clone()), 2, 1) + }: burn_item(RawOrigin::Signed(caller.clone()), 2, 1) - transfer_nft { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_nft_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + transfer_nft { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_nft_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) - - transfer_fungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::Fungible(3); - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_fungible_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) + + transfer_fungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::Fungible(3); + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_fungible_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) + }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) - transfer_refungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_re_fungible_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + transfer_refungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_re_fungible_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) + }: transfer(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1, 1) - approve { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_re_fungible_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + approve { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_re_fungible_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: approve(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1) + }: approve(RawOrigin::Signed(caller.clone()), recipient.clone(), 2, 1) - // Nft - transfer_from_nft { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_nft_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; + // Nft + transfer_from_nft { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_nft_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; - }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) + }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) - // Fungible - transfer_from_fungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::Fungible(3); - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_fungible_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; + // Fungible + transfer_from_fungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::Fungible(3); + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_fungible_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; - }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) + }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) - // ReFungible - transfer_from_refungible { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let recipient: T::AccountId = account("recipient", 0, SEED); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_re_fungible_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; + // ReFungible + transfer_from_refungible { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let recipient: T::AccountId = account("recipient", 0, SEED); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_re_fungible_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + Nft::::approve(RawOrigin::Signed(caller.clone()).into(), recipient.clone(), 2, 1)?; - }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) + }: transfer_from(RawOrigin::Signed(caller.clone()), caller.clone(), recipient.clone(), 2, 1, 1) - enable_contract_sponsoring { - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + enable_contract_sponsoring { + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - }: enable_contract_sponsoring(RawOrigin::Signed(caller.clone()), caller.clone(), true) + }: enable_contract_sponsoring(RawOrigin::Signed(caller.clone()), caller.clone(), true) - set_offchain_schema { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + set_offchain_schema { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_offchain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) + }: set_offchain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) - set_const_on_chain_schema { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_const_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) - - set_variable_on_chain_schema { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::ReFungible(3); - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_variable_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) + set_const_on_chain_schema { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_const_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) + + set_variable_on_chain_schema { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::ReFungible(3); + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_variable_on_chain_schema(RawOrigin::Signed(caller.clone()), 2, [1,2,3].to_vec()) - set_variable_meta_data { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let data = default_nft_data(); - Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; + set_variable_meta_data { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let data = default_nft_data(); + Nft::::create_item(RawOrigin::Signed(caller.clone()).into(), 2, caller.clone(), data)?; - }: set_variable_meta_data(RawOrigin::Signed(caller.clone()), 2, 1, [1, 2, 3].to_vec()) + }: set_variable_meta_data(RawOrigin::Signed(caller.clone()), 2, 1, [1, 2, 3].to_vec()) - set_schema_version { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - }: set_schema_version(RawOrigin::Signed(caller.clone()), 2, SchemaVersion::Unique) + set_schema_version { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + }: set_schema_version(RawOrigin::Signed(caller.clone()), 2, SchemaVersion::Unique) - set_chain_limits { - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - let limits = ChainLimits { - collection_numbers_limit: 0, - account_token_ownership_limit: 0, - collections_admins_limit: 0, - custom_data_limit: 0, - nft_sponsor_transfer_timeout: 0, - fungible_sponsor_transfer_timeout: 0, - refungible_sponsor_transfer_timeout: 0 - }; - }: set_chain_limits(RawOrigin::Signed(caller.clone()), limits) + set_chain_limits { + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + let limits = ChainLimits { + collection_numbers_limit: 0, + account_token_ownership_limit: 0, + collections_admins_limit: 0, + custom_data_limit: 0, + nft_sponsor_transfer_timeout: 0, + fungible_sponsor_transfer_timeout: 0, + refungible_sponsor_transfer_timeout: 0 + }; + }: set_chain_limits(RawOrigin::Signed(caller.clone()), limits) - set_contract_sponsoring_rate_limit { - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - let block_number: T::BlockNumber = 0.into(); - }: set_contract_sponsoring_rate_limit(RawOrigin::Signed(caller.clone()), caller.clone(), block_number) + set_contract_sponsoring_rate_limit { + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + let block_number: T::BlockNumber = 0.into(); + }: set_contract_sponsoring_rate_limit(RawOrigin::Signed(caller.clone()), caller.clone(), block_number) - set_collection_limits{ - let col_name1: Vec = "Test1".encode_utf16().collect::>(); - let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); - let token_prefix1: Vec = b"token_prefix1".to_vec(); - let mode: CollectionMode = CollectionMode::NFT; - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; - - let cl = CollectionLimits { - account_token_ownership_limit: 0, - sponsored_data_size: 0, - token_limit: 0, - sponsor_transfer_timeout: 0 - }; + set_collection_limits{ + let col_name1: Vec = "Test1".encode_utf16().collect::>(); + let col_desc1: Vec = "TestDescription1".encode_utf16().collect::>(); + let token_prefix1: Vec = b"token_prefix1".to_vec(); + let mode: CollectionMode = CollectionMode::NFT; + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::create_collection(RawOrigin::Signed(caller.clone()).into(), col_name1.clone(), col_desc1.clone(), token_prefix1.clone(), mode.clone())?; + + let cl = CollectionLimits { + account_token_ownership_limit: 0, + sponsored_data_size: 0, + token_limit: 0, + sponsor_transfer_timeout: 0 + }; - }: set_collection_limits(RawOrigin::Signed(caller.clone()), 2, cl) + }: set_collection_limits(RawOrigin::Signed(caller.clone()), 2, cl) - add_to_contract_white_list{ - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - }: add_to_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), caller.clone()) + add_to_contract_white_list{ + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + }: add_to_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), caller.clone()) - remove_from_contract_white_list{ - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - Nft::::add_to_contract_white_list(RawOrigin::Signed(caller.clone()).into(), caller.clone(), caller.clone())?; - }: remove_from_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), caller.clone()) + remove_from_contract_white_list{ + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + Nft::::add_to_contract_white_list(RawOrigin::Signed(caller.clone()).into(), caller.clone(), caller.clone())?; + }: remove_from_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), caller.clone()) - toggle_contract_white_list{ - let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); - }: toggle_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), true) -} \ No newline at end of file + toggle_contract_white_list{ + let caller: T::AccountId = T::AccountId::from(whitelisted_caller()); + }: toggle_contract_white_list(RawOrigin::Signed(caller.clone()), caller.clone(), true) +*/ +} --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -26,6 +26,7 @@ # local dependencies pallet-nft = { path = '../pallets/nft', default-features = false, version = '3.0.0' } +pallet-inflation = { path = '../pallets/inflation', default-features = false, version = '3.0.0' } # Substrate dependencies frame-benchmarking = { default-features = false, optional = true, version = '3.0.0' } @@ -72,6 +73,7 @@ 'pallet-balances/runtime-benchmarks', 'pallet-timestamp/runtime-benchmarks', 'pallet-nft/runtime-benchmarks', + 'pallet-inflation/runtime-benchmarks', 'sp-runtime/runtime-benchmarks', ] std = [ @@ -95,6 +97,7 @@ 'pallet-treasury/std', 'pallet-vesting/std', + 'pallet-inflation/std', 'pallet-nft/std', 'sp-api/std', 'sp-block-builder/std', --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -525,7 +525,7 @@ pub const CollectionCreationPrice: Balance = 100 * UNIQUE; } -/// Used for the module nft in `./nft.rs` +/// Used for the pallet nft in `./nft.rs` impl pallet_nft::Config for Runtime { type Event = Event; type WeightInfo = nft_weights::WeightInfo; @@ -534,6 +534,21 @@ type TreasuryAccountId = TreasuryAccountId; } +/// Reimport pallet inflation +extern crate pallet_inflation; +pub use pallet_inflation::*; + +parameter_types! { + pub const InflationBlockInterval: BlockNumber = 100; // every time per how many blocks inflation is applied +} + +/// Used for the pallet inflation +impl pallet_inflation::Config for Runtime { + type Currency = Balances; + type TreasuryAccountId = TreasuryAccountId; + type InflationBlockInterval = InflationBlockInterval; +} + construct_runtime!( pub enum Runtime where Block = Block, @@ -549,6 +564,7 @@ Balances: pallet_balances::{Module, Call, Storage, Config, Event}, TransactionPayment: pallet_transaction_payment::{Module, Storage}, Sudo: pallet_sudo::{Module, Call, Config, Storage, Event}, + Inflation: pallet_inflation::{Module, Call, Storage}, Nft: pallet_nft::{Module, Call, Config, Storage, Event}, Treasury: pallet_treasury::{Module, Call, Storage, Config, Event}, Vesting: pallet_vesting::{Module, Call, Config, Storage, Event}, @@ -759,6 +775,7 @@ let params = (&config, &whitelist); add_benchmark!(params, batches, pallet_nft, Nft); + add_benchmark!(params, batches, pallet_inflation, Inflation); if batches.is_empty() { return Err("Benchmark not found for this pallet.".into()) } Ok(batches) --- a/tests/package.json +++ b/tests/package.json @@ -50,7 +50,8 @@ "testSetContractSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setContractSponsoringRateLimit.test.ts", "testSetOffchainSchema": "mocha --timeout 9999999 -r ts-node/register ./**/setOffchainSchema.test.ts", "testOverflow": "mocha --timeout 9999999 -r ts-node/register ./**/overflow.test.ts", - "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts" + "testSetVariableMetadataSponsoringRateLimit": "mocha --timeout 9999999 -r ts-node/register ./**/setVariableMetadataSponsoringRateLimit.test.ts", + "testInflation": "mocha --timeout 9999999 -r ts-node/register ./**/inflation.test.ts" }, "author": "", "license": "SEE LICENSE IN ../LICENSE", --- a/tests/src/creditFeesToTreasury.test.ts +++ b/tests/src/creditFeesToTreasury.test.ts @@ -18,6 +18,7 @@ } from './util/helpers'; import { default as waitNewBlocks } from './substrate/wait-new-blocks'; +import { ApiPromise } from '@polkadot/api'; chai.use(chaiAsPromised); const expect = chai.expect; @@ -30,6 +31,25 @@ let alice: IKeyringPair; let bob: IKeyringPair; +// Skip the inflation block pauses if the block is close to inflation block +// until the inflation happens +function skipInflationBlock(api: ApiPromise): Promise { + const promise = new Promise(async (resolve, reject) => { + const blockInterval = parseInt((await api.consts.inflation.inflationBlockInterval).toString()); + const unsubscribe = await api.rpc.chain.subscribeNewHeads(head => { + const currentBlock = parseInt(head.number.toString()); + if (currentBlock % blockInterval < blockInterval - 10) { + unsubscribe(); + resolve(); + } else { + console.log(`Skipping inflation block, current block: ${currentBlock}`); + } + }); + }); + + return promise; +} + describe('integration test: Fees must be credited to Treasury:', () => { before(async () => { await usingApi(async (api) => { @@ -40,6 +60,7 @@ it('Total issuance does not change', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const totalBefore = new BigNumber((await api.query.balances.totalIssuance()).toString()); @@ -59,6 +80,7 @@ it('Sender balance decreased by fee+sent amount, Treasury balance increased by fee', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const alicePrivateKey = privateKey('//Alice'); @@ -81,6 +103,7 @@ it('Treasury balance increased by failed tx fee', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const bobPrivateKey = privateKey('//Bob'); @@ -101,6 +124,7 @@ it('NFT Transactions also send fees to Treasury', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const treasuryBalanceBefore = new BigNumber((await api.query.system.account(Treasury)).data.free.toString()); @@ -119,6 +143,7 @@ it('Fees are sane', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const aliceBalanceBefore = new BigNumber((await api.query.system.account(alicesPublicKey)).data.free.toString()); @@ -135,6 +160,7 @@ it('NFT Transfer fee is close to 0.1 Unique', async () => { await usingApi(async (api) => { + await skipInflationBlock(api); await waitNewBlocks(api, 1); const collectionId = await createCollectionExpectSuccess(); @@ -147,7 +173,7 @@ // console.log(fee.toString()); const expectedTransferFee = 0.1; - const tolerance = 0.00001; + const tolerance = 0.001; expect(fee.dividedBy(1e15).minus(expectedTransferFee).abs().toNumber()).to.be.lessThan(tolerance); }); }); --- /dev/null +++ b/tests/src/inflation.test.ts @@ -0,0 +1,49 @@ +// +// 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, submitTransactionExpectFailAsync } from "./substrate/substrate-api"; +import { alicesPublicKey, bobsPublicKey } from "./accounts"; +import privateKey from "./substrate/privateKey"; +import { BigNumber } from 'bignumber.js'; +import { IKeyringPair } from '@polkadot/types/types'; +import { + getGenericResult, +} from './util/helpers'; + +chai.use(chaiAsPromised); +const expect = chai.expect; + +let alice: IKeyringPair; +let bob: IKeyringPair; + +describe('integration test: Inflation', () => { + before(async () => { + await usingApi(async (api) => { + alice = privateKey('//Alice'); + bob = privateKey('//Bob'); + }); + }); + + it('First year inflation is 10%', async () => { + await usingApi(async (api) => { + + const blockInterval = parseInt((await api.consts.inflation.inflationBlockInterval).toString()); + const totalIssuanceStart = new BigNumber((await api.query.inflation.startingYearTotalIssuance()).toString()); + const blockInflation = new BigNumber((await api.query.inflation.blockInflation()).toString()); + + const YEAR = 5259600; // Blocks in one year + const totalExpectedInflation = totalIssuanceStart.multipliedBy(0.1); + const totalActualInflation = blockInflation.multipliedBy(YEAR / blockInterval); + + const tolerance = 0.00001; // Relative difference per year between theoretical and actual inflation + expect(totalExpectedInflation.dividedBy(totalActualInflation).minus(1).abs().toNumber()).to.be.lessThan(tolerance); + }); + }); + + +}); +