git.delta.rocks / unique-network / refs/commits / 455ab69b4262

difftreelog

Fix all unit test execution

Greg Zaitsev2021-11-24parent: #a1bffc7.patch.diff
in: master

6 files changed

modifiedpallets/inflation/src/lib.rsdiffbeforeafterboth
--- a/pallets/inflation/src/lib.rs
+++ b/pallets/inflation/src/lib.rs
@@ -46,7 +46,8 @@
 pub type BalanceOf<T> =
 	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
 
-pub const YEAR: u32 = 5_259_600;
+// pub const YEAR: u32 = 5_259_600; // 6-second block 
+pub const YEAR: u32 = 2_629_800; // 12-second block 
 pub const TOTAL_YEARS_UNTIL_FLAT: u32 = 9;
 pub const START_INFLATION_PERCENT: u32 = 10;
 pub const END_INFLATION_PERCENT: u32 = 4;
modifiedpallets/inflation/src/tests.rsdiffbeforeafterboth
--- a/pallets/inflation/src/tests.rs
+++ b/pallets/inflation/src/tests.rs
@@ -18,7 +18,7 @@
 type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
 type Block = frame_system::mocking::MockBlock<Test>;
 
-const YEAR: u64 = 5_259_600;
+const YEAR: u64 = 2_629_800;
 
 parameter_types! {
 	pub const ExistentialDeposit: u64 = 1;
@@ -112,8 +112,8 @@
 		// first inflation deposit should be equal to BlockInflation
 		Inflation::on_initialize(1);
 
-		// SBP M2 review: Verify expected block inflation for year 1
-		assert_eq!(Inflation::block_inflation(), 1901);
+		// Expected 100-block inflation for year 1 is 100 * 100_000_000 / YEAR = 3803
+		assert_eq!(Inflation::block_inflation(), 3803);
 		assert_eq!(
 			Balances::free_balance(1234) - initial_issuance,
 			Inflation::block_inflation()
@@ -158,26 +158,21 @@
 		let _ = <Balances as Currency<_>>::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();
 
-		// SBP M2 review: go through all the block inflations for year 1,
+		// Go through all the block inflations for year 1,
 		// total issuance will be updated accordingly
 		for block in (100..YEAR).step_by(100) {
 			Inflation::on_initialize(block);
 		}
 		assert_eq!(
-			initial_issuance + (1901 * (YEAR / 100)),
+			initial_issuance + (3803 * (YEAR / 100)),
 			<Balances as Currency<_>>::total_issuance()
 		);
 
 		Inflation::on_initialize(YEAR);
 		let block_inflation_year_1 = Inflation::block_inflation();
-		// SBP M2 review: Verify expected block inflation for year 2
-		assert_eq!(block_inflation_year_1, 1952);
-
-		// SBP M2 review: this is actually not true
-		// Assert that year 1 inflation is less than year 0
-		// assert!(block_inflation_year_0 > block_inflation_year_1);
+		// Expected 100-block inflation for year 2: 100 * 9.33% * initial issuance * 110% / YEAR = 3904
+		assert_eq!(block_inflation_year_1, 3904);
 	});
 }
 
modifiedpallets/nft/src/mock.rsdiffbeforeafterboth
--- a/pallets/nft/src/mock.rs
+++ b/pallets/nft/src/mock.rs
@@ -27,6 +27,10 @@
 		System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
 		TemplateModule: pallet_template::{Pallet, Call, Storage},
 		Balances: pallet_balances::{Pallet, Call, Storage},
+		Common: pallet_common::{Pallet, Storage, Event<T>},
+		Fungible: pallet_fungible::{Pallet, Storage},
+		Refungible: pallet_refungible::{Pallet, Storage},
+		Nonfungible: pallet_nonfungible::{Pallet, Storage},
 	}
 );
 
@@ -151,7 +155,6 @@
 		Self::from_sub(0)
 	}
 }
-
 
 pub struct TestEtheremTransactionSender;
 impl pallet_ethereum::EthereumTransactionSender for TestEtheremTransactionSender {
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -3,10 +3,9 @@
 use crate::mock::*;
 use crate::{AccessMode, CollectionMode};
 use nft_data_structs::{
-	COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, CreateFungibleData, 
-	CreateNftData, CreateReFungibleData, ExistenceRequirement, MAX_COLLECTION_DESCRIPTION_LENGTH, 
-	MAX_COLLECTION_NAME_LENGTH, MAX_DECIMAL_POINTS, MAX_TOKEN_PREFIX_LENGTH, COLLECTION_ADMINS_LIMIT, 
-	MetaUpdatePermission, Pays, PostDispatchInfo, TokenId, Weight, WithdrawReasons,
+	COLLECTION_NUMBER_LIMIT, CollectionId, CreateItemData, CreateFungibleData, 
+	CreateNftData, CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, 
+	MetaUpdatePermission, TokenId,
 };
 
 use frame_support::{assert_noop, assert_ok};
@@ -213,7 +212,7 @@
 				.collect()
 		));
 		for (index, data) in items_data.into_iter().enumerate() {
-			let item = <pallet_nonfungible::TokenData<Test>>::get((CollectionId(1), TokenId((index + 1) as u32))).unwrap();
+			let item = <pallet_refungible::TokenData<Test>>::get((CollectionId(1), TokenId((index + 1) as u32)));
 			let balance = <pallet_refungible::Balance<Test>>::get((CollectionId(1), TokenId(1), account(1)));
 			assert_eq!(item.const_data.to_vec(), data.const_data.into_inner());
 			assert_eq!(item.variable_data.to_vec(), data.variable_data.into_inner());
@@ -274,7 +273,7 @@
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))), 5);
 
 		// change owner scenario
-		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 5));
+		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(0), 5));
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(1))), 0);
 
 		// split item scenario
@@ -282,12 +281,12 @@
 			origin2.clone(),
 			account(3),
 			CollectionId(1),
-			TokenId(1),
+			TokenId(0),
 			3
 		));
 
 		// split item and new owner has account scenario
-		assert_ok!(TemplateModule::transfer(origin2, account(3), CollectionId(1), TokenId(1), 1));
+		assert_ok!(TemplateModule::transfer(origin2, account(3), CollectionId(1), TokenId(0), 1));
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(2))), 1);
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((CollectionId(1), account(3))), 4);
 	});
@@ -298,33 +297,27 @@
 	new_test_ext().execute_with(|| {
 		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
 
+		// Create RFT 1 in 1023 pieces for account 1
 		let data = default_re_fungible_data();
 		create_test_item(collection_id, &data.clone().into());
+		let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
+		assert_eq!(item.const_data, data.const_data.into_inner());
+		assert_eq!(item.variable_data, data.variable_data.into_inner());
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))), 1023);
+		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
 
+		// Account 1 transfers all 1023 pieces of RFT 1 to account 2
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
-		{
-			let item = <pallet_refungible::TokenData<Test>>::get((collection_id, TokenId(1)));
-			let balance = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1)));
-			assert_eq!(item.const_data, data.const_data.into_inner());
-			assert_eq!(item.variable_data, data.variable_data.into_inner());
-			assert_eq!(balance, 1023);
-		}
-		
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1023);
-		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
-
-		// change owner scenario
 		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1023));
-
-		let balance2 = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2)));
-		assert_eq!(balance2, 1023);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))), 1023);
 		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 1023);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 1);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), false);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))), true);
 
-		// split item scenario
+		// Account 2 transfers 500 pieces of RFT 1 to account 3
 		assert_ok!(TemplateModule::transfer(
 			origin2.clone(),
 			account(3),
@@ -332,29 +325,19 @@
 			TokenId(1),
 			500
 		));
-		{
-			let item = <pallet_refungible::TokenData<Test>>::get((CollectionId(1), TokenId(1)));
-			let balance2 = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2)));
-			let balance3 = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3)));
-			assert_eq!(balance2, 523);
-			assert_eq!(balance3, 500);
-		}
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 523);
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 500);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))), 523);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))), 500);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 1);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 1);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))), true);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))), true);
 
-		// split item and new owner has account scenario
+		// Account 2 transfers 200 more pieces of RFT 1 to account 3 with pre-existing balance
 		assert_ok!(TemplateModule::transfer(origin2, account(3), CollectionId(1), TokenId(1), 200));
-		{
-			let item = <pallet_refungible::TokenData<Test>>::get((CollectionId(1), TokenId(1)));
-			let balance2 = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2)));
-			let balance3 = <pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3)));
-			assert_eq!(balance2, 323);
-			assert_eq!(balance3, 700);
-		}
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 323);
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 700);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(2))), 323);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))), 700);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(2))), 1);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 1);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))), true);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(3), TokenId(1))), true);
 	});
@@ -373,7 +356,7 @@
 
 		let origin1 = Origin::signed(1);
 		// default scenario
-		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1000));
+		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1));
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(2))), 1);
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), false);
@@ -382,6 +365,45 @@
 }
 
 #[test]
+fn transfer_nft_item_wrong_value() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
+
+		let origin1 = Origin::signed(1);
+
+		assert_noop!(
+			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 2).map_err(|e| e.error),
+			<pallet_nonfungible::Error::<Test>>::NonfungibleItemsHaveNoAmount
+		);
+	});
+}
+
+#[test]
+fn transfer_nft_item_zero_value() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
+
+		let origin1 = Origin::signed(1);
+
+		// Transferring 0 amount works on NFT...
+		assert_ok!(TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 0));
+		// ... and results in no transfer
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
+	});
+}
+
+#[test]
 fn nft_approve_and_transfer_from() {
 	new_test_ext().execute_with(|| {
 		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
@@ -395,14 +417,14 @@
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
 
-		// neg transfer
+		// neg transfer_from
 		assert_noop!(
-			TemplateModule::transfer_from(origin2.clone(), account(1), account(2), CollectionId(1), TokenId(1), 1),
-			CommonError::<Test>::NoPermission
+			TemplateModule::transfer_from(origin2.clone(), account(1), account(2), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueNotEnough
 		);
 
 		// do approve
-		assert_ok!(TemplateModule::approve(origin1, account(2), CollectionId(1), TokenId(1), 5));
+		assert_ok!(TemplateModule::approve(origin1, account(2), CollectionId(1), TokenId(1), 1));
 		assert_eq!(<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(), account(2));
 
 		assert_ok!(TemplateModule::transfer_from(
@@ -425,9 +447,9 @@
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
 
+		// Create NFT 1 for account 1
 		let data = default_nft_data();
 		create_test_item(collection_id, &data.clone().into());
-
 		assert_eq!(
 			&<pallet_nonfungible::TokenData<Test>>::get((collection_id, TokenId(1))).unwrap().const_data,
 			&data.const_data.into_inner()
@@ -435,6 +457,7 @@
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
 
+		// Allow allow-list users to mint and add accounts 1, 2, and 3 to allow-list
 		assert_ok!(TemplateModule::set_mint_permission(
 			origin1.clone(),
 			CollectionId(1),
@@ -461,18 +484,17 @@
 			account(3)
 		));
 
-		// do approve
+		// Account 1 approves account 2 for NFT 1 
 		assert_ok!(TemplateModule::approve(
 			origin1.clone(),
 			account(2),
 			CollectionId(1),
 			TokenId(1),
-			5
+			1
 		));
 		assert_eq!(<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(), account(2));
-		assert_ok!(TemplateModule::approve(origin1, account(3), CollectionId(1), TokenId(1), 5));
-		assert_eq!(<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(), account(3));
 
+		// Account 2 transfers NFT 1 from account 1 to account 3
 		assert_ok!(TemplateModule::transfer_from(
 			origin2,
 			account(1),
@@ -493,12 +515,15 @@
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
 
+		// Create RFT 1 in 1023 pieces for account 1
 		let data = default_re_fungible_data();
 		create_test_item(collection_id, &data.into());
 
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1023);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))), 1023);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
 
+		// Allow public minting, enable allow-list and add accounts 1, 2, 3 to allow-list
 		assert_ok!(TemplateModule::set_mint_permission(
 			origin1.clone(),
 			CollectionId(1),
@@ -525,10 +550,11 @@
 			account(3)
 		));
 
-		// do approve
+		// Account 1 approves account 2 for 1023 pieces of RFT 1
 		assert_ok!(TemplateModule::approve(origin1, account(2), CollectionId(1), TokenId(1), 1023));
 		assert_eq!(<pallet_refungible::Allowance<Test>>::get((CollectionId(1), TokenId(1), account(1), account(2))), 1023);
 
+		// Account 2 transfers 100 pieces of RFT 1 from account 1 to account 3
 		assert_ok!(TemplateModule::transfer_from(
 			origin2,
 			account(1),
@@ -537,10 +563,12 @@
 			TokenId(1),
 			100
 		));
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 923);
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 100);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(3))), 1);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))), 923);
+		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(3))), 100);
+		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
 		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), true);
-		assert_eq!(<pallet_refungible::Owned<Test>>::get((collection_id, account(1), TokenId(3))), true);
 		assert_eq!(<pallet_refungible::Allowance<Test>>::get((CollectionId(1), TokenId(1), account(1), account(2))), 923);
 	});
 }
@@ -587,11 +615,11 @@
 			origin1.clone(),
 			account(2),
 			CollectionId(1),
-			TokenId(1),
+			TokenId(0),
 			5
 		));
 		assert_eq!(<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))), 5);
-		assert_ok!(TemplateModule::approve(origin1, account(3), CollectionId(1), TokenId(1), 5));
+		assert_ok!(TemplateModule::approve(origin1, account(3), CollectionId(1), TokenId(0), 5));
 		assert_eq!(<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))), 5);
 		assert_eq!(<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(3))), 5);
 
@@ -600,15 +628,15 @@
 			account(1),
 			account(3),
 			CollectionId(1),
-			TokenId(1),
+			TokenId(0),
 			4
 		));
 
 		assert_eq!(<pallet_fungible::Allowance<Test>>::get((CollectionId(1), account(1), account(2))), 1);
 
 		assert_noop!(
-			TemplateModule::transfer_from(origin2, account(1), account(3), CollectionId(1), TokenId(1), 4),
-			CommonError::<Test>::NoPermission
+			TemplateModule::transfer_from(origin2, account(1), account(3), CollectionId(1), TokenId(0), 4).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueNotEnough
 		);
 	});
 }
@@ -647,17 +675,36 @@
 		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
 
 		let origin1 = Origin::signed(1);
-		assert_ok!(TemplateModule::add_collection_admin(
+
+		let data = default_nft_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+
+		// burn item
+		assert_ok!(TemplateModule::burn_item(
 			origin1.clone(),
 			collection_id,
-			account(2)
+			TokenId(1),
+			1
 		));
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
+	});
+}
+
+#[test]
+fn burn_same_nft_item_twice() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
+
+		let origin1 = Origin::signed(1);
 
 		let data = default_nft_data();
 		create_test_item(collection_id, &data.into());
 
 		// check balance (collection with id = 1, user id = 1)
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
 
 		// burn item
 		assert_ok!(TemplateModule::burn_item(
@@ -666,12 +713,14 @@
 			TokenId(1),
 			1
 		));
+		
+		// burn item again
 		assert_noop!(
-			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1),
+			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::TokenNotFound
 		);
 
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
+		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
 	});
 }
 
@@ -694,10 +743,10 @@
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((collection_id, account(1))), 5);
 
 		// burn item
-		assert_ok!(TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 5));
+		assert_ok!(TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(0), 5));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(1), 5),
-			CommonError::<Test>::TokenValueNotEnough
+			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(0), 5).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueTooLow
 		);
 
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((collection_id, account(1))), 0);
@@ -705,6 +754,31 @@
 }
 
 #[test]
+fn burn_fungible_item_with_token_id() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+		assert_ok!(TemplateModule::add_collection_admin(
+			origin1.clone(),
+			collection_id,
+			account(2)
+		));
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		// check balance (collection with id = 1, user id = 1)
+		assert_eq!(<pallet_fungible::Balance<Test>>::get((collection_id, account(1))), 5);
+
+		// Try to burn item using Token ID
+		assert_noop!(
+			TemplateModule::burn_item(origin1, CollectionId(1), TokenId(1), 5).map_err(|e| e.error),
+			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId
+		);
+	});
+}
+#[test]
 fn burn_refungible_item() {
 	new_test_ext().execute_with(|| {
 		let collection_id = create_test_collection(&CollectionMode::ReFungible, CollectionId(1));
@@ -736,14 +810,14 @@
 		create_test_item(collection_id, &data.into());
 
 		// check balance (collection with id = 1, user id = 2)
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1023);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
 		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))), 1023);
 
 		// burn item
 		assert_ok!(TemplateModule::burn_item(origin1.clone(), collection_id, TokenId(1), 1023));
 		assert_noop!(
-			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1023),
-			CommonError::<Test>::TokenNotFound
+			TemplateModule::burn_item(origin1, collection_id, TokenId(1), 1023).map_err(|e| e.error),
+			CommonError::<Test>::TokenValueTooLow
 		);
 
 		assert_eq!(<pallet_refungible::Balance<Test>>::get((collection_id, TokenId(1), account(1))), 0);
@@ -754,12 +828,9 @@
 fn add_collection_admin() {
 	new_test_ext().execute_with(|| {
 		let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(2));
-		create_test_collection_for_owner(&CollectionMode::NFT, 3, CollectionId(3));
-
 		let origin1 = Origin::signed(1);
 
-		// collection admin
+		// Add collection admins
 		assert_ok!(TemplateModule::add_collection_admin(
 			origin1.clone(),
 			collection1_id,
@@ -771,7 +842,8 @@
 			account(3)
 		));
 
-		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))));
+		// Owner is not an admin by default
+		assert_eq!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(1))), false);
 		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(2))));
 		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))));
 	});
@@ -781,13 +853,10 @@
 fn remove_collection_admin() {
 	new_test_ext().execute_with(|| {
 		let collection1_id = create_test_collection_for_owner(&CollectionMode::NFT, 1, CollectionId(1));
-		create_test_collection_for_owner(&CollectionMode::NFT, 2, CollectionId(2));
-		create_test_collection_for_owner(&CollectionMode::NFT, 3, CollectionId(3));
-
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
 
-		// collection admin
+		// Add collection admins 2 and 3
 		assert_ok!(TemplateModule::add_collection_admin(
 			origin1.clone(),
 			collection1_id,
@@ -802,14 +871,16 @@
 		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(2))));
 		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))));
 
-		// remove admin
+		// remove admin 3
 		assert_ok!(TemplateModule::remove_collection_admin(
 			origin2,
 			CollectionId(1),
 			account(3)
 		));
-		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))));
-		assert_eq!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(2))), false);
+
+		// 2 is still admin, 3 is not an admin anymore
+		assert!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(2))));
+		assert_eq!(<pallet_common::IsAdmin<Test>>::get((CollectionId(1), account(3))), false);
 	});
 }
 
@@ -837,10 +908,10 @@
 		// check balance (collection with id = 1, user id = 1)
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((nft_collection_id, account(1))), 1);
 		assert_eq!(<pallet_fungible::Balance<Test>>::get((fungible_collection_id, account(1))), 5);
-		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))), 1023);
+		assert_eq!(<pallet_refungible::AccountBalance<Test>>::get((re_fungible_collection_id, account(1))), 1);
 
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))), true);
-		assert_eq!(<pallet_refungible::Owned<Test>>::get((nft_collection_id, account(1), TokenId(1))), true);
+		assert_eq!(<pallet_refungible::Owned<Test>>::get((re_fungible_collection_id, account(1), TokenId(1))), true);
 	});
 }
 
@@ -1037,7 +1108,7 @@
 			collection_id,
 			account(2)
 		));
-		assert!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))));
+		assert_eq!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))), false);
 	});
 }
 
@@ -1048,23 +1119,27 @@
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
 
+		// Owner adds admin
 		assert_ok!(TemplateModule::add_collection_admin(
 			origin1.clone(),
 			collection_id,
 			account(2)
 		));
 
+		// Owner adds address 3 to allow list
 		assert_ok!(TemplateModule::add_to_allow_list(
 			origin1,
 			collection_id,
 			account(3)
 		));
+
+		// Admin removes address 3 from allow list
 		assert_ok!(TemplateModule::remove_from_allow_list(
 			origin2,
 			collection_id,
 			account(3)
 		));
-		assert!(<pallet_common::Allowlist<Test>>::get((collection_id, account(3))));
+		assert_eq!(<pallet_common::Allowlist<Test>>::get((collection_id, account(3))), false);
 	});
 }
 
@@ -1107,17 +1182,27 @@
 		let origin1 = Origin::signed(1);
 		let origin2 = Origin::signed(2);
 
+		// Add account 2 to allow list
 		assert_ok!(TemplateModule::add_to_allow_list(
 			origin1.clone(),
 			collection_id,
 			account(2)
 		));
+
+		// Account 2 is in collection allow-list
+		assert!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))));
+
+		// Destroy collection
 		assert_ok!(TemplateModule::destroy_collection(origin1, collection_id));
+
+		// Attempt to remove account 2 from collection allow-list => error
 		assert_noop!(
 			TemplateModule::remove_from_allow_list(origin2, collection_id, account(2)),
 			CommonError::<Test>::CollectionNotFound
 		);
-		assert!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))));
+
+		// Account 2 is not found in collection allow-list anyway
+		assert_eq!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))), false);
 	});
 }
 
@@ -1138,12 +1223,13 @@
 			collection_id,
 			account(2)
 		));
+		assert_eq!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))), false);
 		assert_ok!(TemplateModule::remove_from_allow_list(
 			origin1,
 			collection_id,
 			account(2)
 		));
-		assert!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))));
+		assert_eq!(<pallet_common::Allowlist<Test>>::get((collection_id, account(2))), false);
 	});
 }
 
@@ -1170,7 +1256,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1),
+			TemplateModule::transfer(origin1, account(3), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1218,7 +1304,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::transfer_from(origin1, account(1), account(3), CollectionId(1), TokenId(1), 1),
+			TemplateModule::transfer_from(origin1, account(1), account(3), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1247,7 +1333,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::transfer(origin1, account(3), collection_id, TokenId(1), 1),
+			TemplateModule::transfer(origin1, account(3), collection_id, TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1296,7 +1382,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::transfer_from(origin1, account(1), account(3), collection_id, TokenId(1), 1),
+			TemplateModule::transfer_from(origin1, account(1), account(3), collection_id, TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1319,7 +1405,7 @@
 			AccessMode::AllowList
 		));
 		assert_noop!(
-			TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 5),
+			TemplateModule::burn_item(origin1.clone(), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1344,7 +1430,7 @@
 
 		// do approve
 		assert_noop!(
-			TemplateModule::approve(origin1, account(1), CollectionId(1), TokenId(1), 5),
+			TemplateModule::approve(origin1, account(1), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1387,11 +1473,13 @@
 	new_test_ext().execute_with(|| {
 		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
 
+		// Create NFT for account 1
 		let data = default_nft_data();
 		create_test_item(collection_id, &data.into());
 
 		let origin1 = Origin::signed(1);
 
+		// Toggle Allow List mode and add accounts 1 and 2
 		assert_ok!(TemplateModule::set_public_access_mode(
 			origin1.clone(),
 			collection_id,
@@ -1408,16 +1496,17 @@
 			account(2)
 		));
 
-		// do approve
+		// Sself-approve account 1 for NFT 1
 		assert_ok!(TemplateModule::approve(
 			origin1.clone(),
 			account(1),
 			CollectionId(1), 
 			TokenId(1),
-			5
+			1
 		));
 		assert_eq!(<pallet_nonfungible::Allowance<Test>>::get((CollectionId(1), TokenId(1))).unwrap(), account(1));
 
+		// Transfer from 1 to 2
 		assert_ok!(TemplateModule::transfer_from(
 			origin1,
 			account(1),
@@ -1513,7 +1602,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::create_item(origin2, CollectionId(1), account(2), default_nft_data().into()),
+			TemplateModule::create_item(origin2, CollectionId(1), account(2), default_nft_data().into()).map_err(|e| e.error),
 			CommonError::<Test>::PublicMintingNotAllowed
 		);
 	});
@@ -1540,7 +1629,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::create_item(origin2, CollectionId(1), account(2), default_nft_data().into()),
+			TemplateModule::create_item(origin2, CollectionId(1), account(2), default_nft_data().into()).map_err(|e| e.error),
 			CommonError::<Test>::PublicMintingNotAllowed
 		);
 	});
@@ -1626,7 +1715,7 @@
 		));
 
 		assert_noop!(
-			TemplateModule::create_item(origin2, collection_id, account(2), default_nft_data().into()),
+			TemplateModule::create_item(origin2, collection_id, account(2), default_nft_data().into()).map_err(|e| e.error),
 			CommonError::<Test>::AddressNotInAllowlist
 		);
 	});
@@ -1674,14 +1763,23 @@
 	});
 }
 
-// Total number of collections. Negotive test
 #[test]
+fn create_max_collections() {
+	new_test_ext().execute_with(|| {
+		for i in 1..=COLLECTION_NUMBER_LIMIT {
+			create_test_collection(&CollectionMode::NFT, CollectionId(i));
+		}
+	});
+}
+
+// Total number of collections. Negative test
+#[test]
 fn total_number_collections_bound_neg() {
 	new_test_ext().execute_with(|| {
 		let origin1 = Origin::signed(1);
 
-		for i in 0..COLLECTION_NUMBER_LIMIT {
-			create_test_collection(&CollectionMode::NFT, CollectionId(i + 1));
+		for i in 1..=COLLECTION_NUMBER_LIMIT {
+			create_test_collection(&CollectionMode::NFT, CollectionId(i));
 		}
 
 		let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
@@ -1722,14 +1820,14 @@
 
 		let origin1 = Origin::signed(1);
 
-		for _ in 0..MAX_TOKEN_OWNERSHIP {
+		for _ in 1..=MAX_TOKEN_OWNERSHIP {
 			let data = default_nft_data();
 			create_test_item(collection_id, &data.clone().into());
 		}
 
 		let data = default_nft_data();
 		assert_noop!(
-			TemplateModule::create_item(origin1, CollectionId(1), account(1), data.into()),
+			TemplateModule::create_item(origin1, CollectionId(1), account(1), data.into()).map_err(|e| e.error),
 			CommonError::<Test>::AccountTokenLimitExceeded
 		);
 	});
@@ -1902,13 +2000,31 @@
 
 		let variable_data = b"test data".to_vec();
 		assert_noop!(
-			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data),
+			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(0), variable_data).map_err(|e| e.error),
 			<pallet_fungible::Error<Test>>::FungibleItemsDontHaveData
 		);
 	});
 }
 
 #[test]
+fn set_variable_meta_data_on_fungible_token_with_token_id_fails() {
+	new_test_ext().execute_with(|| {
+		let collection_id = create_test_collection(&CollectionMode::Fungible(3), CollectionId(1));
+
+		let origin1 = Origin::signed(1);
+
+		let data = default_fungible_data();
+		create_test_item(collection_id, &data.into());
+
+		let variable_data = b"test data".to_vec();
+		assert_noop!(
+			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data).map_err(|e| e.error),
+			<pallet_fungible::Error::<Test>>::FungibleItemsHaveNoId
+		);
+	});
+}
+
+#[test]
 fn set_variable_meta_data_on_nft_token_fails_for_big_data() {
 	new_test_ext().execute_with(|| {
 		let collection_id = create_test_collection(&CollectionMode::NFT, CollectionId(1));
@@ -1920,7 +2036,7 @@
 
 		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();
 		assert_noop!(
-			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data),
+			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data).map_err(|e| e.error),
 			CommonError::<Test>::TokenVariableDataLimitExceeded
 		);
 	});
@@ -1938,7 +2054,7 @@
 
 		let variable_data = b"test set_variable_meta_data method, bigger than limits.".to_vec();
 		assert_noop!(
-			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data),
+			TemplateModule::set_variable_meta_data(origin1, collection_id, TokenId(1), variable_data).map_err(|e| e.error),
 			CommonError::<Test>::TokenVariableDataLimitExceeded
 		);
 	});
@@ -2013,7 +2129,7 @@
 				collection_id,
 				TokenId(1),
 				variable_data.clone()
-			),
+			).map_err(|e| e.error),
 			CommonError::<Test>::TokenVariableDataLimitExceeded
 		);
 	})
@@ -2035,7 +2151,7 @@
 		let origin1 = Origin::signed(1);
 
 		// default scenario
-		assert_ok!(TemplateModule::transfer(origin1, account(2), collection_id, TokenId(1), 1000));
+		assert_ok!(TemplateModule::transfer(origin1, account(2), collection_id, TokenId(1), 1));
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(1), TokenId(1))), false);
 		assert_eq!(<pallet_nonfungible::Owned<Test>>::get((collection_id, account(2), TokenId(1))), true);
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 0);
@@ -2133,7 +2249,7 @@
 				collection_id,
 				TokenId(1),
 				variable_data.clone()
-			),
+			).map_err(|e| e.error),
 			CommonError::<Test>::NoPermission
 		);
 	});
@@ -2188,7 +2304,7 @@
 				collection_id,
 				TokenId(1),
 				variable_data.clone()
-			),
+			).map_err(|e| e.error),
 			CommonError::<Test>::NoPermission
 		);
 	});
@@ -2213,7 +2329,7 @@
 
 		// default scenario
 		assert_noop!(
-			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1000),
+			TemplateModule::transfer(origin1, account(2), CollectionId(1), TokenId(1), 1).map_err(|e| e.error),
 			CommonError::<Test>::TransferNotAllowed
 		);
 		assert_eq!(<pallet_nonfungible::AccountBalance<Test>>::get((collection_id, account(1))), 1);
modifiedpallets/scheduler/src/lib.rsdiffbeforeafterboth
--- a/pallets/scheduler/src/lib.rs
+++ b/pallets/scheduler/src/lib.rs
@@ -795,8 +795,8 @@
 	use super::*;
 
 	use frame_support::{
-		Hashable, assert_err, assert_noop, assert_ok, ord_parameter_types, parameter_types,
-		traits::{Contains, OnFinalize, OnInitialize},
+		ord_parameter_types, parameter_types,
+		traits::Contains,
 		weights::constants::RocksDbWeight,
 	};
 	use sp_core::H256;
@@ -806,7 +806,6 @@
 		traits::{BlakeTwo256, IdentityLookup},
 	};
 	use frame_system::{EnsureOneOf, EnsureRoot, EnsureSignedBy};
-	use substrate_test_utils::assert_eq_uvec;
 	use crate as scheduler;
 
 	mod logger {
@@ -815,9 +814,6 @@
 
 		thread_local! {
 			static LOG: RefCell<Vec<(OriginCaller, u32)>> = RefCell::new(Vec::new());
-		}
-		pub fn log() -> Vec<(OriginCaller, u32)> {
-			LOG.with(|log| log.borrow().clone())
 		}
 		pub trait Config: system::Config {
 			type Event: From<Event> + Into<<Self as system::Config>::Event>;
@@ -928,24 +924,5 @@
 		type MaxScheduledPerBlock = MaxScheduledPerBlock;
 		type WeightInfo = ();
 		type SponsorshipHandler = ();
-	}
-
-	pub fn new_test_ext() -> sp_io::TestExternalities {
-		let t = system::GenesisConfig::default()
-			.build_storage::<Test>()
-			.unwrap();
-		t.into()
-	}
-
-	fn run_to_block(n: u64) {
-		while System::block_number() < n {
-			Scheduler::on_finalize(System::block_number());
-			System::set_block_number(System::block_number() + 1);
-			Scheduler::on_initialize(System::block_number());
-		}
-	}
-
-	fn root() -> OriginCaller {
-		system::RawOrigin::Root.into()
 	}
 }
modifiedprimitives/nft/src/lib.rsdiffbeforeafterboth
before · primitives/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23use core::convert::{TryFrom, TryInto};45#[cfg(feature = "serde")]6pub use serde::{Serialize, Deserialize};78use sp_core::U256;9use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};10use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};11pub use frame_support::{12	BoundedVec, construct_runtime, decl_event, decl_module, decl_storage, decl_error,13	dispatch::DispatchResult,14	ensure, fail, parameter_types,15	traits::{16		Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,17		Randomness, IsSubType, WithdrawReasons,18	},19	weights::{20		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},21		DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,22		WeightToFeePolynomial, DispatchClass,23	},24	StorageValue, transactional,25};26use derivative::Derivative;27use scale_info::TypeInfo;2829pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;30pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;31pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;32pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;3334pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {35	10000036} else {37	1038};39pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {40	204841} else {42	1043};44pub const COLLECTION_ADMINS_LIMIT: u32 = 5;45pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;46pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {47	100000048} else {49	1050};5152// Timeouts for item types in passed blocks53pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;54pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;55pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;5657// Schema limits58pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;59pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;60pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;6162pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;63pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;64pub const MAX_TOKEN_PREFIX_LENGTH: usize = 16;6566/// How much items can be created per single67/// create_many call68pub const MAX_ITEMS_PER_BATCH: u32 = 200;6970parameter_types! {71	pub const CustomDataLimit: u32 = CUSTOM_DATA_LIMIT;72}7374#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]75#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]76pub struct CollectionId(pub u32);77impl EncodeLike<u32> for CollectionId {}78impl EncodeLike<CollectionId> for u32 {}7980#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]81#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]82pub struct TokenId(pub u32);83impl EncodeLike<u32> for TokenId {}84impl EncodeLike<TokenId> for u32 {}8586impl TokenId {87	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {88		self.089			.checked_add(1)90			.ok_or(ArithmeticError::Overflow)91			.map(Self)92	}93}9495impl From<TokenId> for U256 {96	fn from(t: TokenId) -> Self {97		t.0.into()98	}99}100101impl TryFrom<U256> for TokenId {102	type Error = &'static str;103104	fn try_from(value: U256) -> Result<Self, Self::Error> {105		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))106	}107}108109pub struct OverflowError;110impl From<OverflowError> for &'static str {111	fn from(_: OverflowError) -> Self {112		"overflow occured"113	}114}115116pub type DecimalPoints = u8;117118#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]119#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]120pub enum CollectionMode {121	NFT,122	// decimal points123	Fungible(DecimalPoints),124	ReFungible,125}126127impl CollectionMode {128	pub fn id(&self) -> u8 {129		match self {130			CollectionMode::NFT => 1,131			CollectionMode::Fungible(_) => 2,132			CollectionMode::ReFungible => 3,133		}134	}135}136137pub trait SponsoringResolve<AccountId, Call> {138	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;139}140141#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]142#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]143pub enum AccessMode {144	Normal,145	AllowList,146}147impl Default for AccessMode {148	fn default() -> Self {149		Self::Normal150	}151}152153#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]154#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]155pub enum SchemaVersion {156	ImageURL,157	Unique,158}159impl Default for SchemaVersion {160	fn default() -> Self {161		Self::ImageURL162	}163}164165#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]166#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]167pub struct Ownership<AccountId> {168	pub owner: AccountId,169	pub fraction: u128,170}171172#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]173#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]174pub enum SponsorshipState<AccountId> {175	/// The fees are applied to the transaction sender176	Disabled,177	Unconfirmed(AccountId),178	/// Transactions are sponsored by specified account179	Confirmed(AccountId),180}181182impl<AccountId> SponsorshipState<AccountId> {183	pub fn sponsor(&self) -> Option<&AccountId> {184		match self {185			Self::Confirmed(sponsor) => Some(sponsor),186			_ => None,187		}188	}189190	pub fn pending_sponsor(&self) -> Option<&AccountId> {191		match self {192			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),193			_ => None,194		}195	}196197	pub fn confirmed(&self) -> bool {198		matches!(self, Self::Confirmed(_))199	}200}201202impl<T> Default for SponsorshipState<T> {203	fn default() -> Self {204		Self::Disabled205	}206}207208#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]209#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]210pub struct Collection<T: frame_system::Config> {211	pub owner: T::AccountId,212	pub mode: CollectionMode,213	pub access: AccessMode,214	pub name: Vec<u16>,        // 64 include null escape char215	pub description: Vec<u16>, // 256 include null escape char216	pub token_prefix: Vec<u8>, // 16 include null escape char217	pub mint_mode: bool,218	pub offchain_schema: Vec<u8>,219	pub schema_version: SchemaVersion,220	pub sponsorship: SponsorshipState<T::AccountId>,221	pub limits: CollectionLimits,          // Collection private restrictions222	pub variable_on_chain_schema: Vec<u8>, //223	pub const_on_chain_schema: Vec<u8>,    //224	pub meta_update_permission: MetaUpdatePermission,225}226227#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]228#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]229pub struct NftItemType<AccountId> {230	pub owner: AccountId,231	pub const_data: Vec<u8>,232	pub variable_data: Vec<u8>,233}234235#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]236#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]237pub struct FungibleItemType {238	pub value: u128,239}240241#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]242#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]243pub struct ReFungibleItemType<AccountId> {244	pub owner: Vec<Ownership<AccountId>>,245	pub const_data: Vec<u8>,246	pub variable_data: Vec<u8>,247}248249#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo)]250#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]251pub struct CollectionLimits {252	pub account_token_ownership_limit: Option<u32>,253	pub sponsored_data_size: Option<u32>,254	/// None - setVariableMetadata is not sponsored255	/// Some(v) - setVariableMetadata is sponsored256	///           if there is v block between txs257	pub sponsored_data_rate_limit: Option<u32>,258	pub token_limit: Option<u32>,259260	// Timeouts for item types in passed blocks261	pub sponsor_transfer_timeout: Option<u32>,262	pub owner_can_transfer: Option<bool>,263	pub owner_can_destroy: Option<bool>,264	pub transfers_enabled: Option<bool>,265}266267impl CollectionLimits {268	pub fn account_token_ownership_limit(&self) -> u32 {269		self.account_token_ownership_limit270			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)271			.min(MAX_TOKEN_OWNERSHIP)272	}273	pub fn sponsored_data_size(&self) -> u32 {274		self.sponsored_data_size275			.unwrap_or(CUSTOM_DATA_LIMIT)276			.min(CUSTOM_DATA_LIMIT)277	}278	pub fn token_limit(&self) -> u32 {279		self.token_limit280			.unwrap_or(COLLECTION_TOKEN_LIMIT)281			.min(COLLECTION_TOKEN_LIMIT)282	}283	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {284		self.sponsor_transfer_timeout285			.unwrap_or(default)286			.min(MAX_SPONSOR_TIMEOUT)287	}288	pub fn owner_can_transfer(&self) -> bool {289		self.owner_can_transfer.unwrap_or(true)290	}291	pub fn owner_can_destroy(&self) -> bool {292		self.owner_can_destroy.unwrap_or(true)293	}294	pub fn transfers_enabled(&self) -> bool {295		self.transfers_enabled.unwrap_or(true)296	}297	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {298		self.sponsored_data_rate_limit299			.map(|v| v.min(MAX_SPONSOR_TIMEOUT))300	}301}302303/// BoundedVec doesn't supports serde304#[cfg(feature = "serde1")]305mod bounded_serde {306	use core::convert::TryFrom;307	use frame_support::{BoundedVec, traits::Get};308	use serde::{309		ser::{self, Serialize},310		de::{self, Deserialize, Error},311	};312	use sp_std::vec::Vec;313314	pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>315	where316		D: ser::Serializer,317		V: Serialize,318	{319		let vec: &Vec<_> = &value;320		vec.serialize(serializer)321	}322323	pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>324	where325		D: de::Deserializer<'de>,326		V: de::Deserialize<'de>,327		S: Get<u32>,328	{329		// TODO: Implement custom visitor, which will limit vec size at parse time? Will serde only be used by chainspec?330		let vec = <Vec<V>>::deserialize(deserializer)?;331		let len = vec.len();332		TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))333	}334}335336#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]337#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]338#[derivative(Debug)]339pub struct CreateNftData {340	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]341	#[derivative(Debug = "ignore")]342	pub const_data: BoundedVec<u8, CustomDataLimit>,343	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]344	#[derivative(Debug = "ignore")]345	pub variable_data: BoundedVec<u8, CustomDataLimit>,346}347348#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]349#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]350pub struct CreateFungibleData {351	pub value: u128,352}353354#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]355#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]356#[derivative(Debug)]357pub struct CreateReFungibleData {358	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]359	#[derivative(Debug = "ignore")]360	pub const_data: BoundedVec<u8, CustomDataLimit>,361	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]362	#[derivative(Debug = "ignore")]363	pub variable_data: BoundedVec<u8, CustomDataLimit>,364	pub pieces: u128,365}366367#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]368#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]369pub enum MetaUpdatePermission {370	ItemOwner,371	Admin,372	None,373}374375impl Default for MetaUpdatePermission {376	fn default() -> Self {377		Self::ItemOwner378	}379}380381#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]382#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]383pub enum CreateItemData {384	NFT(CreateNftData),385	Fungible(CreateFungibleData),386	ReFungible(CreateReFungibleData),387}388389impl CreateItemData {390	pub fn data_size(&self) -> usize {391		match self {392			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),393			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),394			_ => 0,395		}396	}397}398399impl From<CreateNftData> for CreateItemData {400	fn from(item: CreateNftData) -> Self {401		CreateItemData::NFT(item)402	}403}404405impl From<CreateReFungibleData> for CreateItemData {406	fn from(item: CreateReFungibleData) -> Self {407		CreateItemData::ReFungible(item)408	}409}410411impl From<CreateFungibleData> for CreateItemData {412	fn from(item: CreateFungibleData) -> Self {413		CreateItemData::Fungible(item)414	}415}
after · primitives/nft/src/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]23use core::convert::{TryFrom, TryInto};45#[cfg(feature = "serde")]6pub use serde::{Serialize, Deserialize};78use sp_core::U256;9use sp_runtime::{ArithmeticError, sp_std::prelude::Vec};10use codec::{Decode, Encode, EncodeLike, MaxEncodedLen};11pub use frame_support::{12	BoundedVec, construct_runtime, decl_event, decl_module, decl_storage, decl_error,13	dispatch::DispatchResult,14	ensure, fail, parameter_types,15	traits::{16		Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,17		Randomness, IsSubType, WithdrawReasons,18	},19	weights::{20		constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},21		DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,22		WeightToFeePolynomial, DispatchClass,23	},24	StorageValue, transactional,25};26use derivative::Derivative;27use scale_info::TypeInfo;2829pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;30pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;31pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;3233pub const MAX_TOKEN_OWNERSHIP: u32 = if cfg!(not(feature = "limit-testing")) {34	10_000_00035} else {36	1037};38pub const COLLECTION_NUMBER_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {39	100_00040} else {41	1042};43pub const CUSTOM_DATA_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {44	204845} else {46	1047};48pub const COLLECTION_ADMINS_LIMIT: u32 = 5;49pub const COLLECTION_TOKEN_LIMIT: u32 = u32::MAX;50pub const ACCOUNT_TOKEN_OWNERSHIP_LIMIT: u32 = if cfg!(not(feature = "limit-testing")) {51	1_000_00052} else {53	1054};5556// Timeouts for item types in passed blocks57pub const NFT_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;58pub const FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;59pub const REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT: u32 = 5;6061// Schema limits62pub const OFFCHAIN_SCHEMA_LIMIT: u32 = 1024;63pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;64pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 1024;6566pub const MAX_COLLECTION_NAME_LENGTH: usize = 64;67pub const MAX_COLLECTION_DESCRIPTION_LENGTH: usize = 256;68pub const MAX_TOKEN_PREFIX_LENGTH: usize = 16;6970/// How much items can be created per single71/// create_many call72pub const MAX_ITEMS_PER_BATCH: u32 = 200;7374parameter_types! {75	pub const CustomDataLimit: u32 = CUSTOM_DATA_LIMIT;76}7778#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]79#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]80pub struct CollectionId(pub u32);81impl EncodeLike<u32> for CollectionId {}82impl EncodeLike<CollectionId> for u32 {}8384#[derive(Encode, Decode, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Default, TypeInfo)]85#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]86pub struct TokenId(pub u32);87impl EncodeLike<u32> for TokenId {}88impl EncodeLike<TokenId> for u32 {}8990impl TokenId {91	pub fn try_next(self) -> Result<TokenId, ArithmeticError> {92		self.093			.checked_add(1)94			.ok_or(ArithmeticError::Overflow)95			.map(Self)96	}97}9899impl From<TokenId> for U256 {100	fn from(t: TokenId) -> Self {101		t.0.into()102	}103}104105impl TryFrom<U256> for TokenId {106	type Error = &'static str;107108	fn try_from(value: U256) -> Result<Self, Self::Error> {109		Ok(TokenId(value.try_into().map_err(|_| "too large token id")?))110	}111}112113pub struct OverflowError;114impl From<OverflowError> for &'static str {115	fn from(_: OverflowError) -> Self {116		"overflow occured"117	}118}119120pub type DecimalPoints = u8;121122#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]123#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]124pub enum CollectionMode {125	NFT,126	// decimal points127	Fungible(DecimalPoints),128	ReFungible,129}130131impl CollectionMode {132	pub fn id(&self) -> u8 {133		match self {134			CollectionMode::NFT => 1,135			CollectionMode::Fungible(_) => 2,136			CollectionMode::ReFungible => 3,137		}138	}139}140141pub trait SponsoringResolve<AccountId, Call> {142	fn resolve(who: &AccountId, call: &Call) -> Option<AccountId>;143}144145#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]146#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]147pub enum AccessMode {148	Normal,149	AllowList,150}151impl Default for AccessMode {152	fn default() -> Self {153		Self::Normal154	}155}156157#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq, TypeInfo)]158#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]159pub enum SchemaVersion {160	ImageURL,161	Unique,162}163impl Default for SchemaVersion {164	fn default() -> Self {165		Self::ImageURL166	}167}168169#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]170#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]171pub struct Ownership<AccountId> {172	pub owner: AccountId,173	pub fraction: u128,174}175176#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]177#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]178pub enum SponsorshipState<AccountId> {179	/// The fees are applied to the transaction sender180	Disabled,181	Unconfirmed(AccountId),182	/// Transactions are sponsored by specified account183	Confirmed(AccountId),184}185186impl<AccountId> SponsorshipState<AccountId> {187	pub fn sponsor(&self) -> Option<&AccountId> {188		match self {189			Self::Confirmed(sponsor) => Some(sponsor),190			_ => None,191		}192	}193194	pub fn pending_sponsor(&self) -> Option<&AccountId> {195		match self {196			Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),197			_ => None,198		}199	}200201	pub fn confirmed(&self) -> bool {202		matches!(self, Self::Confirmed(_))203	}204}205206impl<T> Default for SponsorshipState<T> {207	fn default() -> Self {208		Self::Disabled209	}210}211212#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]213#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]214pub struct Collection<T: frame_system::Config> {215	pub owner: T::AccountId,216	pub mode: CollectionMode,217	pub access: AccessMode,218	pub name: Vec<u16>,        // 64 include null escape char219	pub description: Vec<u16>, // 256 include null escape char220	pub token_prefix: Vec<u8>, // 16 include null escape char221	pub mint_mode: bool,222	pub offchain_schema: Vec<u8>,223	pub schema_version: SchemaVersion,224	pub sponsorship: SponsorshipState<T::AccountId>,225	pub limits: CollectionLimits,          // Collection private restrictions226	pub variable_on_chain_schema: Vec<u8>, //227	pub const_on_chain_schema: Vec<u8>,    //228	pub meta_update_permission: MetaUpdatePermission,229}230231#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]232#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]233pub struct NftItemType<AccountId> {234	pub owner: AccountId,235	pub const_data: Vec<u8>,236	pub variable_data: Vec<u8>,237}238239#[derive(Encode, Decode, Default, Debug, Clone, PartialEq, TypeInfo)]240#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]241pub struct FungibleItemType {242	pub value: u128,243}244245#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]246#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]247pub struct ReFungibleItemType<AccountId> {248	pub owner: Vec<Ownership<AccountId>>,249	pub const_data: Vec<u8>,250	pub variable_data: Vec<u8>,251}252253#[derive(Encode, Decode, Debug, Default, Clone, PartialEq, TypeInfo)]254#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]255pub struct CollectionLimits {256	pub account_token_ownership_limit: Option<u32>,257	pub sponsored_data_size: Option<u32>,258	/// None - setVariableMetadata is not sponsored259	/// Some(v) - setVariableMetadata is sponsored260	///           if there is v block between txs261	pub sponsored_data_rate_limit: Option<u32>,262	pub token_limit: Option<u32>,263264	// Timeouts for item types in passed blocks265	pub sponsor_transfer_timeout: Option<u32>,266	pub owner_can_transfer: Option<bool>,267	pub owner_can_destroy: Option<bool>,268	pub transfers_enabled: Option<bool>,269}270271impl CollectionLimits {272	pub fn account_token_ownership_limit(&self) -> u32 {273		self.account_token_ownership_limit274			.unwrap_or(ACCOUNT_TOKEN_OWNERSHIP_LIMIT)275			.min(MAX_TOKEN_OWNERSHIP)276	}277	pub fn sponsored_data_size(&self) -> u32 {278		self.sponsored_data_size279			.unwrap_or(CUSTOM_DATA_LIMIT)280			.min(CUSTOM_DATA_LIMIT)281	}282	pub fn token_limit(&self) -> u32 {283		self.token_limit284			.unwrap_or(COLLECTION_TOKEN_LIMIT)285			.min(COLLECTION_TOKEN_LIMIT)286	}287	pub fn sponsor_transfer_timeout(&self, default: u32) -> u32 {288		self.sponsor_transfer_timeout289			.unwrap_or(default)290			.min(MAX_SPONSOR_TIMEOUT)291	}292	pub fn owner_can_transfer(&self) -> bool {293		self.owner_can_transfer.unwrap_or(true)294	}295	pub fn owner_can_destroy(&self) -> bool {296		self.owner_can_destroy.unwrap_or(true)297	}298	pub fn transfers_enabled(&self) -> bool {299		self.transfers_enabled.unwrap_or(true)300	}301	pub fn sponsored_data_rate_limit(&self) -> Option<u32> {302		self.sponsored_data_rate_limit303			.map(|v| v.min(MAX_SPONSOR_TIMEOUT))304	}305}306307/// BoundedVec doesn't supports serde308#[cfg(feature = "serde1")]309mod bounded_serde {310	use core::convert::TryFrom;311	use frame_support::{BoundedVec, traits::Get};312	use serde::{313		ser::{self, Serialize},314		de::{self, Deserialize, Error},315	};316	use sp_std::vec::Vec;317318	pub fn serialize<D, V, S>(value: &BoundedVec<V, S>, serializer: D) -> Result<D::Ok, D::Error>319	where320		D: ser::Serializer,321		V: Serialize,322	{323		let vec: &Vec<_> = &value;324		vec.serialize(serializer)325	}326327	pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result<BoundedVec<V, S>, D::Error>328	where329		D: de::Deserializer<'de>,330		V: de::Deserialize<'de>,331		S: Get<u32>,332	{333		// TODO: Implement custom visitor, which will limit vec size at parse time? Will serde only be used by chainspec?334		let vec = <Vec<V>>::deserialize(deserializer)?;335		let len = vec.len();336		TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size"))337	}338}339340#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]341#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]342#[derivative(Debug)]343pub struct CreateNftData {344	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]345	#[derivative(Debug = "ignore")]346	pub const_data: BoundedVec<u8, CustomDataLimit>,347	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]348	#[derivative(Debug = "ignore")]349	pub variable_data: BoundedVec<u8, CustomDataLimit>,350}351352#[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq, TypeInfo)]353#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]354pub struct CreateFungibleData {355	pub value: u128,356}357358#[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)]359#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]360#[derivative(Debug)]361pub struct CreateReFungibleData {362	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]363	#[derivative(Debug = "ignore")]364	pub const_data: BoundedVec<u8, CustomDataLimit>,365	#[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))]366	#[derivative(Debug = "ignore")]367	pub variable_data: BoundedVec<u8, CustomDataLimit>,368	pub pieces: u128,369}370371#[derive(Encode, Decode, Debug, Clone, PartialEq, TypeInfo)]372#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]373pub enum MetaUpdatePermission {374	ItemOwner,375	Admin,376	None,377}378379impl Default for MetaUpdatePermission {380	fn default() -> Self {381		Self::ItemOwner382	}383}384385#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]386#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]387pub enum CreateItemData {388	NFT(CreateNftData),389	Fungible(CreateFungibleData),390	ReFungible(CreateReFungibleData),391}392393impl CreateItemData {394	pub fn data_size(&self) -> usize {395		match self {396			CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),397			CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),398			_ => 0,399		}400	}401}402403impl From<CreateNftData> for CreateItemData {404	fn from(item: CreateNftData) -> Self {405		CreateItemData::NFT(item)406	}407}408409impl From<CreateReFungibleData> for CreateItemData {410	fn from(item: CreateReFungibleData) -> Self {411		CreateItemData::ReFungible(item)412	}413}414415impl From<CreateFungibleData> for CreateItemData {416	fn from(item: CreateFungibleData) -> Self {417		CreateItemData::Fungible(item)418	}419}