difftreelog
Fix all unit test execution
in: master
6 files changed
pallets/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;
pallets/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);
});
}
pallets/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 {
pallets/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);
pallets/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()
}
}
primitives/nft/src/lib.rsdiffbeforeafterboth1#![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}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}