difftreelog
Merge pull request #6 from usetech-llc/feature/white_list_nft_62-64
in: master
Feature/white list nft 62 64
4 files changed
README.mddiffbeforeafterboth--- a/README.md
+++ b/README.md
@@ -142,6 +142,12 @@
"enable_println": "bool",
"max_subject_len": "u32"
},
+ "AccessMode": {
+ "_enum": [
+ "Normal",
+ "WhiteList"
+ ]
+ },
"CollectionMode": {
"_enum": {
"Invalid": null,
@@ -181,12 +187,13 @@
"CollectionType": {
"Owner": "AccountId",
"Mode": "CollectionMode",
- "Access": "u8",
+ "Access": "AccessMode",
"DecimalPoints": "u32",
"Name": "Vec<u16>",
"Description": "Vec<u16>",
"TokenPrefix": "Vec<u8>",
"CustomDataSize": "u32",
+ "MintMode": "bool",
"OffchainSchema": "Vec<u8>",
"Sponsor": "AccountId",
"UnconfirmedSponsor": "AccountId"
@@ -196,4 +203,5 @@
"LookupSource": "AccountId",
"Weight": "u64"
}
+
```
\ No newline at end of file
pallets/nft/src/lib.rsdiffbeforeafterboth97 pub description: Vec<u16>, // 256 include null escape char97 pub description: Vec<u16>, // 256 include null escape char98 pub token_prefix: Vec<u8>, // 16 include null escape char98 pub token_prefix: Vec<u8>, // 16 include null escape char99 pub custom_data_size: u32,99 pub custom_data_size: u32,100 pub mint_mode: bool,100 pub offchain_schema: Vec<u8>,101 pub offchain_schema: Vec<u8>,101 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender102 pub sponsor: AccountId, // Who pays fees. If set to default address, the fees are applied to the transaction sender102 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship103 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship179 pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;180 pub FungibleItemList get(fn fungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;180 pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;181 pub ReFungibleItemList get(fn refungible_item_id): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;181182 // Active vesting list183 // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;184182185 /// Index list183 /// Index list186 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;184 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;209207210 fn on_initialize(now: T::BlockNumber) -> Weight {208 fn on_initialize(now: T::BlockNumber) -> Weight {211209212 if ChainVersion::get() == 0210 if ChainVersion::get() < 2213 {211 {214 let value = NextCollectionID::get();212 let value = NextCollectionID::get();215 CreatedCollectionCount::put(value);213 CreatedCollectionCount::put(value);271 owner: who.clone(),269 owner: who.clone(),272 name: name,270 name: name,273 mode: mode.clone(),271 mode: mode.clone(),272 mint_mode: false,274 access: AccessMode::Normal,273 access: AccessMode::Normal,275 description: description,274 description: description,276 decimal_points: decimal_points,275 decimal_points: decimal_points,309 }308 }310309311 #[weight = 0]310 #[weight = 0]311 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{312313 let sender = ensure_signed(origin)?;314 Self::check_owner_or_admin_permissions(collection_id, sender)?;315316 let mut white_list_collection: Vec<T::AccountId>;317 if <WhiteList<T>>::contains_key(collection_id) {318 white_list_collection = <WhiteList<T>>::get(collection_id);319 if !white_list_collection.contains(&address.clone())320 {321 white_list_collection.push(address.clone());322 }323 }324 else {325 white_list_collection = Vec::new();326 white_list_collection.push(address.clone());327 }328329 <WhiteList<T>>::insert(collection_id, white_list_collection);330 Ok(())331 }332333 #[weight = 0]334 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{335336 let sender = ensure_signed(origin)?;337 Self::check_owner_or_admin_permissions(collection_id, sender)?;338339 if <WhiteList<T>>::contains_key(collection_id) {340 let mut white_list_collection = <WhiteList<T>>::get(collection_id);341 if white_list_collection.contains(&address.clone())342 {343 white_list_collection.retain(|i| *i != address.clone());344 <WhiteList<T>>::insert(collection_id, white_list_collection);345 }346 }347348 Ok(())349 }350351 #[weight = 0]352 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult353 {354 let sender = ensure_signed(origin)?;355356 Self::check_owner_permissions(collection_id, sender)?;357 let mut target_collection = <Collection<T>>::get(collection_id);358 target_collection.access = mode;359 <Collection<T>>::insert(collection_id, target_collection);360361 Ok(())362 }363364 #[weight = 0]365 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult366 {367 let sender = ensure_signed(origin)?;368369 Self::check_owner_permissions(collection_id, sender)?;370 let mut target_collection = <Collection<T>>::get(collection_id);371 target_collection.mint_mode = mint_permission;372 <Collection<T>>::insert(collection_id, target_collection);373374 Ok(())375 }376377 #[weight = 0]312 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {378 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {313379314 let sender = ensure_signed(origin)?;380 let sender = ensure_signed(origin)?;405 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {471 pub fn create_item(origin, collection_id: u64, properties: Vec<u8>, owner: T::AccountId) -> DispatchResult {406472407 let sender = ensure_signed(origin)?;473 let sender = ensure_signed(origin)?;474 Self::collection_exists(collection_id)?;408 let target_collection = <Collection<T>>::get(collection_id);475 let target_collection = <Collection<T>>::get(collection_id);476409 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;477 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {478 ensure!(target_collection.mint_mode == true, "Collection is not in mint mode");479 Self::check_white_list(collection_id, owner.clone())?;480 }410481411 match target_collection.mode482 match target_collection.mode412 {483 {469 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {540 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {470541471 let sender = ensure_signed(origin)?;542 let sender = ensure_signed(origin)?;543 Self::collection_exists(collection_id)?;472 let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);544 let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);473 if !item_owner545 if !item_owner474 {546 {475 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;547 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) { 548 Self::check_white_list(collection_id, sender.clone())?;549 }476 }550 }477 let target_collection = <Collection<T>>::get(collection_id);551 let target_collection = <Collection<T>>::get(collection_id);478552494 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {568 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {495569496 let sender = ensure_signed(origin)?;570 let sender = ensure_signed(origin)?;497 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");571 Self::check_white_list(collection_id, sender.clone())?;498572 Self::check_white_list(collection_id, recipient.clone())?;499 let target_collection = <Collection<T>>::get(collection_id);573 let target_collection = <Collection<T>>::get(collection_id);500574501 // TODO: implement other modes502 match target_collection.mode575 match target_collection.mode503 {576 {504 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,577 CollectionMode::NFT(_) => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,518 // amount param stub591 // amount param stub519 let amount = 100000000;592 let amount = 100000000;520593521 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id), "Only item owner can call transfer method");594 let item_owner = Self::is_item_owner(sender.clone(), collection_id, item_id);595 if !item_owner {596 Self::check_white_list(collection_id, approved.clone())?;597 }522598523 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));599 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));524 if list_exists {600 if list_exists {546 let sender = ensure_signed(origin)?;622 let sender = ensure_signed(origin)?;547 let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));623 let approved_list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone()));624548 if approved_list_exists625 ensure!(approved_list_exists, "Only approved addresses can call this method");549 {626627 Self::check_white_list(collection_id, from.clone())?;628 Self::check_white_list(collection_id, recipient.clone())?;629550 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));630 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));551 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());631 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());556 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))636 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))557 .into_iter().filter(|i| i.approved != sender.clone()).collect();637 .into_iter().filter(|i| i.approved != sender.clone()).collect();558 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);638 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);559 }560 else561 {562 Self::check_owner_or_admin_permissions(collection_id, sender)?;563 }564639565 let target_collection = <Collection<T>>::get(collection_id);640 let target_collection = <Collection<T>>::get(collection_id);566641770 Ok(())841 Ok(())771 }842 }772843773 fn check_owner_or_admin_permissions(844 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {774 collection_id: u64,775 subject: T::AccountId,776 ) -> DispatchResult {777 Self::collection_exists(collection_id)?;778845779 let target_collection = <Collection<T>>::get(collection_id);846 let target_collection = <Collection<T>>::get(collection_id);780 let is_owner = subject == target_collection.owner;847 let mut result: bool = subject == target_collection.owner;781782 let no_perm_mes = "You do not have permissions to modify this collection";783 let exists = <AdminList<T>>::contains_key(collection_id);848 let exists = <AdminList<T>>::contains_key(collection_id);784849785 if !is_owner {850 if !result & exists {786 ensure!(exists, no_perm_mes);787 ensure!(788 <AdminList<T>>::get(collection_id).contains(&subject),851 if <AdminList<T>>::get(collection_id).contains(&subject) {789 no_perm_mes852 result = true790 );853 }791 }854 }792 Ok(())855856 result793 }857 }858859 fn check_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {860 861 Self::collection_exists(collection_id)?;862 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());863864 ensure!(result, "You do not have permissions to modify this collection");865 Ok(())866 }794867795 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {868 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {796 let target_collection = <Collection<T>>::get(collection_id);869 let target_collection = <Collection<T>>::get(collection_id);812 }885 }813 }886 }887888 fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {889890 let mes = "Address is not in white list";891 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);892 let wl = <WhiteList<T>>::get(collection_id);893 ensure!(wl.contains(&address.clone()), mes);894895 Ok(())896 }814897815 fn transfer_fungible(898 fn transfer_fungible(816 collection_id: u64,899 collection_id: u64,820 new_owner: T::AccountId,903 new_owner: T::AccountId,821 ) -> DispatchResult {904 ) -> DispatchResult {905906 ensure!(907 <FungibleItemList<T>>::contains_key(collection_id, item_id),908 "Item not exists"909 );910822 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);911 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);823 let amount = full_item.value;912 let amount = full_item.value;904 new_owner: T::AccountId,993 new_owner: T::AccountId,905 ) -> DispatchResult {994 ) -> DispatchResult {995996 ensure!(997 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),998 "Item not exists"999 );1000906 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1001 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);907 let item = full_item1002 let item = full_item984 new_owner: T::AccountId,1079 new_owner: T::AccountId,985 ) -> DispatchResult {1080 ) -> DispatchResult {1081 1082 ensure!(1083 <NftItemList<T>>::contains_key(collection_id, item_id),1084 "Item not exists"1085 );1086986 let mut item = <NftItemList<T>>::get(collection_id, item_id);1087 let mut item = <NftItemList<T>>::get(collection_id, item_id);9871088pallets/nft/src/tests.rsdiffbeforeafterboth--- a/pallets/nft/src/tests.rs
+++ b/pallets/nft/src/tests.rs
@@ -1,6 +1,6 @@
// Tests to be written here
use crate::mock::*;
-use crate::{ApprovePermissions, CollectionMode, Ownership};
+use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
use frame_support::{assert_noop, assert_ok};
#[test]
@@ -321,10 +321,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ 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::add_to_white_list(origin1.clone(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -390,10 +391,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ 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::add_to_white_list(origin1.clone(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -461,10 +463,11 @@
assert_eq!(TemplateModule::balance_count(1, 1), 1000);
assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
- assert_noop!(
- TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),
- "You do not have permissions to modify this collection"
- );
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ 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::add_to_white_list(origin1.clone(), 1, 3));
// do approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
@@ -573,7 +576,6 @@
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(),
@@ -583,7 +585,7 @@
));
assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
assert_ok!(TemplateModule::create_item(
- origin2.clone(),
+ origin1.clone(),
1,
[1, 2, 3].to_vec(),
1
@@ -614,7 +616,6 @@
let mode: CollectionMode = CollectionMode::Fungible(3);
let origin1 = Origin::signed(1);
- let origin2 = Origin::signed(2);
assert_ok!(TemplateModule::create_collection(
origin1.clone(),
col_name1.clone(),
@@ -624,7 +625,7 @@
));
assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
assert_ok!(TemplateModule::create_item(
- origin2.clone(),
+ origin1.clone(),
1,
[].to_vec(),
1
@@ -661,6 +662,11 @@
token_prefix1.clone(),
mode
));
+
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ 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_collection_admin(origin1.clone(), 1, 2));
assert_ok!(TemplateModule::create_item(
origin2.clone(),
@@ -928,6 +934,13 @@
// approve
assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
+
+ assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
+ 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::add_to_white_list(origin1.clone(), 1, 3));
+
assert_ok!(TemplateModule::transfer_from(
origin2.clone(),
1,
runtime/src/lib.rsdiffbeforeafterboth--- a/runtime/src/lib.rs
+++ b/runtime/src/lib.rs
@@ -111,7 +111,7 @@
spec_name: create_runtime_str!("nft"),
impl_name: create_runtime_str!("nft"),
authoring_version: 1,
- spec_version: 1,
+ spec_version: 2,
impl_version: 1,
apis: RUNTIME_API_VERSIONS,
transaction_version: 1,