difftreelog
Merge pull request #3 from usetech-llc/feature/white_list_tests
in: master
Feature/white list tests
4 files changed
node/src/chain_spec.rsdiffbeforeafterboth1// use nft_runtime::{2// AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,3// SystemConfig, WASM_BINARY,4// };5// use nft_runtime::{ContractsConfig, ContractsSchedule, NftConfig, CollectionType};1use nft_runtime::{6use nft_runtime::*;2 AccountId, AuraConfig, BalancesConfig, GenesisConfig, GrandpaConfig, Signature, SudoConfig,3 SystemConfig, WASM_BINARY,4};5use nft_runtime::{ContractsConfig, ContractsSchedule};6use sc_service::ChainType;7use sc_service::ChainType;7use sp_consensus_aura::sr25519::AuthorityId as AuraId;8use sp_consensus_aura::sr25519::AuthorityId as AuraId;8use sp_core::{sr25519, Pair, Public};9use sp_core::{sr25519, Pair, Public};128 .collect(),129 .collect(),129 }),130 }),130 sudo: Some(SudoConfig { key: root_key }),131 sudo: Some(SudoConfig { key: root_key }),132 nft: Some(NftConfig {133 collection: vec![(1, CollectionType { 134 owner: get_account_id_from_seed::<sr25519::Public>("Alice"),135 mode: CollectionMode::NFT(50),136 access: AccessMode::Normal,137 decimal_points: 0,138 name: vec!(),139 description: vec!(),140 token_prefix: vec!(),141 custom_data_size: 50,142 mint_mode: false,143 offchain_schema: vec!(),144 sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),145 unconfirmed_sponsor: get_account_id_from_seed::<sr25519::Public>("Alice"),146 })],147 nft_item_id: vec!(),148 fungible_item_id: vec!(),149 refungible_item_id: vec!(),150 }),131 contracts: Some(ContractsConfig {151 contracts: Some(ContractsConfig {132 current_schedule: ContractsSchedule {152 current_schedule: ContractsSchedule {133 enable_println,153 enable_println,pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -1,7 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
-/// For more guidance on Substrate FRAME, see the example pallet
-/// https://github.com/paritytech/substrate/blob/master/frame/example/src/lib.rs
+#[cfg(feature = "std")]
+pub use serde::*;
+
use codec::{Decode, Encode};
pub use frame_support::{
construct_runtime, decl_event, decl_module, decl_storage,
@@ -32,7 +33,6 @@
},
FixedPointOperand, FixedU128,
};
-use sp_std::prelude::*;
#[cfg(test)]
mod mock;
@@ -40,7 +40,11 @@
#[cfg(test)]
mod tests;
-#[derive(Encode, Decode, Debug, Eq, Clone, PartialEq)]
+// Structs
+// #region
+
+#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum CollectionMode {
Invalid,
// custom data size
@@ -62,7 +66,8 @@
}
}
-#[derive(Encode, Decode, Debug, Clone, PartialEq)]
+#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub enum AccessMode {
Normal,
WhiteList,
@@ -79,15 +84,15 @@
}
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct Ownership<AccountId> {
pub owner: AccountId,
pub fraction: u128,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct CollectionType<AccountId> {
pub owner: AccountId,
pub mode: CollectionMode,
@@ -103,46 +108,46 @@
pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct CollectionAdminsType<AccountId> {
pub admin: AccountId,
pub collection_id: u64,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct NftItemType<AccountId> {
pub collection: u64,
pub owner: AccountId,
pub data: Vec<u8>,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct FungibleItemType<AccountId> {
pub collection: u64,
pub owner: AccountId,
pub value: u128,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ReFungibleItemType<AccountId> {
pub collection: u64,
pub owner: Vec<Ownership<AccountId>>,
pub data: Vec<u8>,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct ApprovePermissions<AccountId> {
pub approved: AccountId,
pub amount: u64,
}
-#[derive(Encode, Decode, Default, Clone, PartialEq)]
-#[cfg_attr(feature = "std", derive(Debug))]
+#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct VestingItem<AccountId, Moment> {
pub sender: AccountId,
pub recipient: AccountId,
@@ -156,6 +161,8 @@
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
+// #endregion
+
decl_storage! {
trait Store for Module<T: Trait> as Nft {
@@ -165,7 +172,7 @@
ChainVersion: u64;
ItemListIndex: map hasher(blake2_128_concat) u64 => u64;
- pub Collection get(fn collection): map hasher(identity) u64 => CollectionType<T::AccountId>;
+ pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;
pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;
pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;
@@ -176,9 +183,9 @@
pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;
/// Item collections
- pub NftItemList get(fn nft_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
- pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
- pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
+ pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;
+ pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;
+ pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;
/// Index list
pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;
@@ -187,6 +194,26 @@
pub ContractSponsor get(fn contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;
pub UnconfirmedContractSponsor get(fn unconfirmed_contract_sponsor): map hasher(identity) T::AccountId => T::AccountId;
}
+ add_extra_genesis {
+ build(|config: &GenesisConfig<T>| {
+ // Modification of storage
+ for (_num, _c) in &config.collection {
+ <Module<T>>::init_collection(_c);
+ }
+
+ for (_num, _q, _i) in &config.nft_item_id {
+ <Module<T>>::init_nft_token(_i);
+ }
+
+ for (_num, _q, _i) in &config.fungible_item_id {
+ <Module<T>>::init_fungible_token(_i);
+ }
+
+ for (_num, _q, _i) in &config.refungible_item_id {
+ <Module<T>>::init_refungible_token(_i);
+ }
+ })
+ }
}
decl_event!(
@@ -541,14 +568,16 @@
let sender = ensure_signed(origin)?;
Self::collection_exists(collection_id)?;
- let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
- if !item_owner
- {
- if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {
- Self::check_white_list(collection_id, sender.clone())?;
- }
+
+ // Transfer permissions check
+ let target_collection = <Collection<T>>::get(collection_id);
+ ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
+ Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+ "Only item owner, collection owner and admins can modify item");
+
+ if target_collection.access == AccessMode::WhiteList {
+ Self::check_white_list(collection_id, sender.clone())?;
}
- let target_collection = <Collection<T>>::get(collection_id);
match target_collection.mode
{
@@ -568,10 +597,18 @@
pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {
let sender = ensure_signed(origin)?;
- Self::check_white_list(collection_id, sender.clone())?;
- Self::check_white_list(collection_id, recipient.clone())?;
+
+ // Transfer permissions check
let target_collection = <Collection<T>>::get(collection_id);
+ ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
+ Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+ "Only item owner, collection owner and admins can modify item");
+ if target_collection.access == AccessMode::WhiteList {
+ Self::check_white_list(collection_id, sender.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
+ }
+
match target_collection.mode
{
CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,
@@ -588,14 +625,20 @@
let sender = ensure_signed(origin)?;
- // amount param stub
- let amount = 100000000;
+ // Transfer permissions check
+ let target_collection = <Collection<T>>::get(collection_id);
+ ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||
+ Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+ "Only item owner, collection owner and admins can approve");
- let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);
- if !item_owner {
+ if target_collection.access == AccessMode::WhiteList {
+ Self::check_white_list(collection_id, sender.clone())?;
Self::check_white_list(collection_id, approved.clone())?;
}
+ // amount param stub
+ let amount = 100000000;
+
let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));
if list_exists {
@@ -620,24 +663,31 @@
pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {
let sender = ensure_signed(origin)?;
- let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));
+ let mut appoved_transfer = false;
- ensure!(approved_list_exists, "Only approved addresses can call this method");
+ // Check approve
+ if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {
+ let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
+ let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
+ appoved_transfer = opt_item.is_some();
+ ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
+ }
- Self::check_white_list(collection_id, from.clone())?;
- Self::check_white_list(collection_id, recipient.clone())?;
+ // Transfer permissions check
+ let target_collection = <Collection<T>>::get(collection_id);
+ ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),
+ "Only item owner, collection owner and admins can modify items");
- let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));
- let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());
- ensure!(opt_item.is_some(), "No approve found");
- ensure!(opt_item.unwrap().amount >= value, "Requested value more than approved");
+ if target_collection.access == AccessMode::WhiteList {
+ Self::check_white_list(collection_id, sender.clone())?;
+ Self::check_white_list(collection_id, recipient.clone())?;
+ }
// remove approve
let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))
.into_iter().filter(|i| i.approved != sender.clone()).collect();
<ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);
- let target_collection = <Collection<T>>::get(collection_id);
match target_collection.mode
{
@@ -1115,6 +1165,80 @@
Ok(())
}
+ fn init_collection(item: &CollectionType<T::AccountId>){
+
+ // check params
+ assert!(item.decimal_points <= 4, "decimal_points parameter must be lower than 4");
+ assert!(item.name.len() <= 64, "Collection name can not be longer than 63 char");
+ assert!(item.name.len() <= 256, "Collection description can not be longer than 255 char");
+ assert!(item.token_prefix.len() <= 16, "Token prefix can not be longer than 15 char");
+
+ // Generate next collection ID
+ let next_id = CreatedCollectionCount::get()
+ .checked_add(1)
+ .expect("collection id error");
+
+ CreatedCollectionCount::put(next_id);
+ }
+
+ fn init_nft_token(item: &NftItemType<T::AccountId>){
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+
+ let item_owner = item.owner.clone();
+ let collection_id = item.collection.clone();
+ Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();
+
+ <ItemListIndex>::insert(collection_id, current_index);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())
+ .checked_add(1)
+ .unwrap();
+ <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);
+ }
+
+ fn init_fungible_token(item: &FungibleItemType<T::AccountId>){
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+ let owner = item.owner.clone();
+ let value = item.value as u64;
+
+ Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();
+
+ <ItemListIndex>::insert(item.collection, current_index);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(item.collection, owner.clone())
+ .checked_add(value)
+ .unwrap();
+ <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+ }
+
+ fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>){
+
+ let current_index = <ItemListIndex>::get(item.collection)
+ .checked_add(1)
+ .expect("Item list index id error");
+
+ let value = item.owner.first().unwrap().fraction as u64;
+ let owner = item.owner.first().unwrap().owner.clone();
+
+ Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();
+
+ <ItemListIndex>::insert(item.collection, current_index);
+
+ // Update balance
+ let new_balance = <Balance<T>>::get(item.collection, owner.clone())
+ .checked_add(value)
+ .unwrap();
+ <Balance<T>>::insert(item.collection, owner.clone(), new_balance);
+ }
+
fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {
let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());
if list_exists {
@@ -1169,6 +1293,7 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// Economic models
+// #region
/// Fee multiplier.
pub type Multiplier = FixedU128;
@@ -1363,3 +1488,4 @@
Ok(())
}
}
+// #endregion
\ No newline at end of file
pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -3,6 +3,8 @@
use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
use frame_support::{assert_noop, assert_ok};
+// Use cases tests region
+// #region
#[test]
fn create_nft_item() {
new_test_ext().execute_with(|| {
@@ -330,7 +332,7 @@
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
- assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+ assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
assert_eq!(
TemplateModule::approved(1, (1, 1))[0],
@@ -400,7 +402,7 @@
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
- assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+ assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
assert_eq!(
TemplateModule::approved(1, (1, 1))[0],
@@ -427,7 +429,7 @@
assert_eq!(
TemplateModule::approved(1, (1, 1))[0],
ApprovePermissions {
- approved: 10,
+ approved: 3,
amount: 100000000
}
);
@@ -472,7 +474,7 @@
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
- assert_ok!(TemplateModule::approve(origin1.clone(), 10, 1, 1));
+ assert_ok!(TemplateModule::approve(origin1.clone(), 3, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 2);
assert_eq!(
TemplateModule::approved(1, (1, 1))[0],
@@ -499,7 +501,7 @@
assert_eq!(
TemplateModule::approved(1, (1, 1))[0],
ApprovePermissions {
- approved: 10,
+ approved: 3,
amount: 100000000
}
);
@@ -955,3 +957,833 @@
assert_eq!(TemplateModule::balance_count(1, 2), 1);
});
}
+
+// #endregion
+
+// Coverage tests region
+// #region
+
+#[test]
+fn owner_can_add_address_to_white_list() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_eq!(TemplateModule::white_list(1)[0], 2);
+ });
+}
+
+#[test]
+fn admin_can_add_address_to_white_list() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3));
+ assert_eq!(TemplateModule::white_list(1)[0], 3);
+ });
+}
+
+#[test]
+fn nonprivileged_user_cannot_add_address_to_white_list() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_noop!(TemplateModule::add_to_white_list(origin2.clone(), 1, 3), "You do not have permissions to modify this collection");
+ });
+}
+
+#[test]
+fn nobody_can_add_address_to_white_list_of_nonexisting_collection() {
+ new_test_ext().execute_with(|| {
+
+ let origin1 = Origin::signed(1);
+ assert_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist");
+ });
+}
+
+#[test]
+fn nobody_can_add_address_to_white_list_of_deleted_collection() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+ assert_noop!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2), "This collection does not exist");
+ });
+}
+
+// If address is already added to white list, nothing happens
+#[test]
+fn address_is_already_added_to_white_list() {
+ new_test_ext().execute_with(|| {
+
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_eq!(TemplateModule::white_list(1)[0], 2);
+ assert_eq!(TemplateModule::white_list(1).len(), 1);
+ });
+}
+
+#[test]
+fn owner_can_remove_address_from_white_list() {
+ new_test_ext().execute_with(|| {
+
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
+ assert_eq!(TemplateModule::white_list(1).len(), 0);
+ });
+}
+
+#[test]
+fn admin_can_remove_address_from_white_list() {
+ new_test_ext().execute_with(|| {
+
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
+ assert_ok!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 3));
+ assert_eq!(TemplateModule::white_list(1).len(), 0);
+ });
+}
+
+#[test]
+fn nonprivileged_user_cannot_remove_address_from_white_list() {
+ new_test_ext().execute_with(|| {
+
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "You do not have permissions to modify this collection");
+ assert_eq!(TemplateModule::white_list(1)[0], 2);
+ });
+}
+
+#[test]
+fn nobody_can_remove_address_from_white_list_of_nonexisting_collection() {
+ new_test_ext().execute_with(|| {
+
+ let origin1 = Origin::signed(1);
+ assert_noop!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2), "This collection does not exist");
+ });
+}
+
+#[test]
+fn nobody_can_remove_address_from_white_list_of_deleted_collection() {
+ new_test_ext().execute_with(|| {
+
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::destroy_collection(origin1.clone(), 1));
+ assert_noop!(TemplateModule::remove_from_white_list(origin2.clone(), 1, 2), "This collection does not exist");
+ assert_eq!(TemplateModule::white_list(1).len(), 0);
+ });
+}
+
+// If address is already removed from white list, nothing happens
+#[test]
+fn address_is_already_removed_from_white_list() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+ let origin1 = Origin::signed(1);
+
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
+ assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
+ assert_eq!(TemplateModule::white_list(1).len(), 0);
+ });
+}
+
+// If Public Access mode is set to WhiteList, tokens can’t be transferred from a non-whitelisted address with transfer or transferFrom (2 tests)
+#[test]
+fn white_list_test_1() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ assert_noop!(TemplateModule::transfer(
+ origin1.clone(),
+ 3,
+ 1,
+ 1,
+ 1
+ ), "Address is not in white list");
+ });
+}
+
+#[test]
+fn white_list_test_2() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ // do approve
+ assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
+ assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
+
+ assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 1));
+
+ assert_noop!(TemplateModule::transfer_from(
+ origin1.clone(),
+ 1,
+ 3,
+ 1,
+ 1,
+ 1
+ ), "Address is not in white list");
+ });
+}
+
+// If Public Access mode is set to WhiteList, tokens can’t be transferred to a non-whitelisted address with transfer or transferFrom (2 tests)
+#[test]
+fn white_list_test_3() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+
+ assert_noop!(TemplateModule::transfer(
+ origin1.clone(),
+ 3,
+ 1,
+ 1,
+ 1
+ ), "Address is not in white list");
+ });
+}
+
+#[test]
+fn white_list_test_4() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ // do approve
+ assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
+ assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
+
+ assert_ok!(TemplateModule::remove_from_white_list(origin1.clone(), 1, 2));
+
+ assert_noop!(TemplateModule::transfer_from(
+ origin1.clone(),
+ 1,
+ 3,
+ 1,
+ 1,
+ 1
+ ), "Address is not in white list");
+ });
+}
+
+// If Public Access mode is set to WhiteList, tokens can’t be destroyed by a non-whitelisted address (even if it owned them before enabling WhiteList mode)
+#[test]
+fn white_list_test_5() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_noop!(TemplateModule::burn_item(origin1.clone(), 1, 1), "Address is not in white list");
+ });
+}
+
+// If Public Access mode is set to WhiteList, oken transfers can’t be Approved by a non-whitelisted address (see Approve method).
+#[test]
+fn white_list_test_6() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+
+ // do approve
+ assert_noop!(TemplateModule::approve(origin1.clone(), 1, 1, 1), "Address is not in white list");
+ });
+}
+
+// If Public Access mode is set to WhiteList, tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests) and
+// tokens can be transferred from a whitelisted address with transfer or transferFrom (2 tests)
+#[test]
+fn white_list_test_7() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ assert_ok!(TemplateModule::transfer(
+ origin1.clone(),
+ 2,
+ 1,
+ 1,
+ 1
+ ));
+ });
+}
+
+#[test]
+fn white_list_test_8() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+ assert_eq!(TemplateModule::collection(1).owner, 1);
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ // do approve
+ assert_ok!(TemplateModule::approve(origin1.clone(), 1, 1, 1));
+ assert_eq!(TemplateModule::approved(1, (1, 1)).len(), 1);
+
+ assert_ok!(TemplateModule::transfer_from(
+ origin1.clone(),
+ 1,
+ 2,
+ 1,
+ 1,
+ 1
+ ));
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by owner.
+#[test]
+fn white_list_test_9() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens can be created by admin.
+#[test]
+fn white_list_test_10() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
+
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+
+ assert_ok!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ));
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and white listed address.
+#[test]
+fn white_list_test_11() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ assert_noop!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ), "Collection is not in mint mode");
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to false, tokens cannot be created by non-privileged and non-white listed address.
+#[test]
+fn white_list_test_12() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, false));
+
+ assert_noop!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ), "Collection is not in mint mode");
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by owner.
+#[test]
+fn white_list_test_13() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+
+ assert_ok!(TemplateModule::create_item(
+ origin1.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 1
+ ));
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by admin.
+#[test]
+fn white_list_test_14() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+
+ assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
+
+ assert_ok!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ));
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens cannot be created by non-privileged and non-white listed address.
+#[test]
+fn white_list_test_15() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+
+ assert_noop!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ), "Address is not in white list");
+ });
+}
+
+// If Public Access mode is set to WhiteList, and Mint Permission is set to true, tokens can be created by non-privileged and white listed address.
+#[test]
+fn white_list_test_16() {
+ new_test_ext().execute_with(|| {
+ let col_name1: Vec<u16> = "Test1\0".encode_utf16().collect::<Vec<u16>>();
+ let col_desc1: Vec<u16> = "TestDescription1\0".encode_utf16().collect::<Vec<u16>>();
+ let token_prefix1: Vec<u8> = b"token_prefix1\0".to_vec();
+ let mode: CollectionMode = CollectionMode::NFT(2000);
+
+ let origin1 = Origin::signed(1);
+ let origin2 = Origin::signed(2);
+ assert_ok!(TemplateModule::create_collection(
+ origin1.clone(),
+ col_name1.clone(),
+ col_desc1.clone(),
+ token_prefix1.clone(),
+ mode
+ ));
+
+ assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
+
+ assert_ok!(TemplateModule::create_item(
+ origin2.clone(),
+ 1,
+ [1, 2, 3].to_vec(),
+ 2
+ ));
+ });
+}
+
+// #endregion
\ No newline at end of file
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -53,8 +53,10 @@
pub use timestamp::Call as TimestampCall;
-/// Importing a nft pallet
-pub use nft;
+/// Re-export a nft pallet
+/// TODO: Check this re-export. Is this safe and good style?
+extern crate nft;
+pub use nft::*;
/// An index to a block.
pub type BlockNumber = u32;
@@ -318,7 +320,7 @@
Balances: balances::{Module, Call, Storage, Config<T>, Event<T>},
TransactionPayment: transaction_payment::{Module, Storage},
Sudo: sudo::{Module, Call, Config<T>, Storage, Event<T>},
- Nft: nft::{Module, Call, Storage, Event<T>},
+ Nft: nft::{Module, Call, Config<T>, Storage, Event<T>},
}
);