git.delta.rocks / unique-network / refs/commits / 72221d0d47e3

difftreelog

Merge pull request #6 from usetech-llc/feature/white_list_nft_62-64

usetech-llc2020-09-25parents: #8d30d14 #0053d9a.patch.diff
in: master
Feature/white list nft 62 64

4 files changed

modifiedREADME.mddiffbeforeafterboth
142 "enable_println": "bool",142 "enable_println": "bool",
143 "max_subject_len": "u32"143 "max_subject_len": "u32"
144 },144 },
145 "AccessMode": {
146 "_enum": [
147 "Normal",
148 "WhiteList"
149 ]
150 },
145 "CollectionMode": {151 "CollectionMode": {
146 "_enum": {152 "_enum": {
147 "Invalid": null,153 "Invalid": null,
181 "CollectionType": {187 "CollectionType": {
182 "Owner": "AccountId",188 "Owner": "AccountId",
183 "Mode": "CollectionMode",189 "Mode": "CollectionMode",
184 "Access": "u8",190 "Access": "AccessMode",
185 "DecimalPoints": "u32",191 "DecimalPoints": "u32",
186 "Name": "Vec<u16>",192 "Name": "Vec<u16>",
187 "Description": "Vec<u16>",193 "Description": "Vec<u16>",
188 "TokenPrefix": "Vec<u8>",194 "TokenPrefix": "Vec<u8>",
189 "CustomDataSize": "u32",195 "CustomDataSize": "u32",
196 "MintMode": "bool",
190 "OffchainSchema": "Vec<u8>",197 "OffchainSchema": "Vec<u8>",
191 "Sponsor": "AccountId",198 "Sponsor": "AccountId",
192 "UnconfirmedSponsor": "AccountId"199 "UnconfirmedSponsor": "AccountId"
196 "LookupSource": "AccountId",203 "LookupSource": "AccountId",
197 "Weight": "u64"204 "Weight": "u64"
198}205}
206
199```207```
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
97 pub description: Vec<u16>, // 256 include null escape char97 pub description: Vec<u16>, // 256 include null escape char
98 pub token_prefix: Vec<u8>, // 16 include null escape char98 pub token_prefix: Vec<u8>, // 16 include null escape char
99 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 sender
102 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship103 pub unconfirmed_sponsor: AccountId, // Sponsor address that has not yet confirmed sponsorship
179 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>;
181
182 // Active vesting list
183 // pub VestingList get(fn vesting): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => VestingItem<T::AccountId, T::Moment>;
184182
185 /// Index list183 /// Index list
186 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>;
209207
210 fn on_initialize(now: T::BlockNumber) -> Weight {208 fn on_initialize(now: T::BlockNumber) -> Weight {
211209
212 if ChainVersion::get() == 0210 if ChainVersion::get() < 2
213 {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 }
310309
311 #[weight = 0]310 #[weight = 0]
311 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
312
313 let sender = ensure_signed(origin)?;
314 Self::check_owner_or_admin_permissions(collection_id, sender)?;
315
316 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 }
328
329 <WhiteList<T>>::insert(collection_id, white_list_collection);
330 Ok(())
331 }
332
333 #[weight = 0]
334 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{
335
336 let sender = ensure_signed(origin)?;
337 Self::check_owner_or_admin_permissions(collection_id, sender)?;
338
339 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 }
347
348 Ok(())
349 }
350
351 #[weight = 0]
352 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult
353 {
354 let sender = ensure_signed(origin)?;
355
356 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);
360
361 Ok(())
362 }
363
364 #[weight = 0]
365 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult
366 {
367 let sender = ensure_signed(origin)?;
368
369 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);
373
374 Ok(())
375 }
376
377 #[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 {
313379
314 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 {
406472
407 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);
476
409 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 }
410481
411 match target_collection.mode482 match target_collection.mode
412 {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 {
470541
471 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_owner
474 {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);
478552
494 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 {
495569
496 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);
500574
501 // TODO: implement other modes
502 match target_collection.mode575 match target_collection.mode
503 {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 stub
519 let amount = 100000000;592 let amount = 100000000;
520593
521 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 }
522598
523 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()));
624
548 if approved_list_exists625 ensure!(approved_list_exists, "Only approved addresses can call this method");
549 {626
627 Self::check_white_list(collection_id, from.clone())?;
628 Self::check_white_list(collection_id, recipient.clone())?;
629
550 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 else
561 {
562 Self::check_owner_or_admin_permissions(collection_id, sender)?;
563 }
564639
565 let target_collection = <Collection<T>>::get(collection_id);640 let target_collection = <Collection<T>>::get(collection_id);
566641
770 Ok(())841 Ok(())
771 }842 }
772843
773 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)?;
778845
779 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;
781
782 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);
784849
785 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 = true
790 );853 }
791 }854 }
792 Ok(())855
856 result
793 }857 }
858
859 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());
863
864 ensure!(result, "You do not have permissions to modify this collection");
865 Ok(())
866 }
794867
795 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 }
887
888 fn check_white_list(collection_id: u64, address: T::AccountId) -> DispatchResult {
889
890 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);
894
895 Ok(())
896 }
814897
815 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 {
905
906 ensure!(
907 <FungibleItemList<T>>::contains_key(collection_id, item_id),
908 "Item not exists"
909 );
910
822 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 {
995
996 ensure!(
997 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),
998 "Item not exists"
999 );
1000
906 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_item
984 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 );
1086
986 let mut item = <NftItemList<T>>::get(collection_id, item_id);1087 let mut item = <NftItemList<T>>::get(collection_id, item_id);
9871088
modifiedpallets/nft/src/tests.rsdiffbeforeafterboth
1// Tests to be written here1// Tests to be written here
2use crate::mock::*;2use crate::mock::*;
3use crate::{ApprovePermissions, CollectionMode, Ownership};3use crate::{ApprovePermissions, CollectionMode, AccessMode, Ownership};
4use frame_support::{assert_noop, assert_ok};4use frame_support::{assert_noop, assert_ok};
55
6#[test]6#[test]
321 assert_eq!(TemplateModule::balance_count(1, 1), 1);321 assert_eq!(TemplateModule::balance_count(1, 1), 1);
322 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);322 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
323323
324 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
325 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
324 assert_noop!(326 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
325 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),327 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
326 "You do not have permissions to modify this collection"328 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
327 );
328329
329 // do approve330 // do approve
390 assert_eq!(TemplateModule::balance_count(1, 1), 1000);391 assert_eq!(TemplateModule::balance_count(1, 1), 1000);
391 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);392 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
392393
394 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
395 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
393 assert_noop!(396 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
394 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),397 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
395 "You do not have permissions to modify this collection"398 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
396 );
397399
398 // do approve400 // do approve
461 assert_eq!(TemplateModule::balance_count(1, 1), 1000);463 assert_eq!(TemplateModule::balance_count(1, 1), 1000);
462 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);464 assert_eq!(TemplateModule::address_tokens(1, 1), [1]);
463465
466 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
467 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
464 assert_noop!(468 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
465 TemplateModule::transfer_from(origin2.clone(), 1, 3, 1, 1, 1),469 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
466 "You do not have permissions to modify this collection"470 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
467 );
468471
469 // do approve472 // do approve
573 let mode: CollectionMode = CollectionMode::NFT(2000);576 let mode: CollectionMode = CollectionMode::NFT(2000);
574577
575 let origin1 = Origin::signed(1);578 let origin1 = Origin::signed(1);
576 let origin2 = Origin::signed(2);
577 assert_ok!(TemplateModule::create_collection(579 assert_ok!(TemplateModule::create_collection(
578 origin1.clone(),580 origin1.clone(),
579 col_name1.clone(),581 col_name1.clone(),
583 ));585 ));
584 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));586 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
585 assert_ok!(TemplateModule::create_item(587 assert_ok!(TemplateModule::create_item(
586 origin2.clone(),588 origin1.clone(),
587 1,589 1,
588 [1, 2, 3].to_vec(),590 [1, 2, 3].to_vec(),
589 1591 1
614 let mode: CollectionMode = CollectionMode::Fungible(3);616 let mode: CollectionMode = CollectionMode::Fungible(3);
615617
616 let origin1 = Origin::signed(1);618 let origin1 = Origin::signed(1);
617 let origin2 = Origin::signed(2);
618 assert_ok!(TemplateModule::create_collection(619 assert_ok!(TemplateModule::create_collection(
619 origin1.clone(),620 origin1.clone(),
620 col_name1.clone(),621 col_name1.clone(),
624 ));625 ));
625 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));626 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
626 assert_ok!(TemplateModule::create_item(627 assert_ok!(TemplateModule::create_item(
627 origin2.clone(),628 origin1.clone(),
628 1,629 1,
629 [].to_vec(),630 [].to_vec(),
630 1631 1
662 mode663 mode
663 ));664 ));
665
666 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
667 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
668 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
669
664 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));670 assert_ok!(TemplateModule::add_collection_admin(origin1.clone(), 1, 2));
665 assert_ok!(TemplateModule::create_item(671 assert_ok!(TemplateModule::create_item(
929 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));935 assert_ok!(TemplateModule::approve(origin1.clone(), 2, 1, 1));
930 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);936 assert_eq!(TemplateModule::approved(1, (1, 1))[0].approved, 2);
937
938 assert_ok!(TemplateModule::set_mint_permission(origin1.clone(), 1, true));
939 assert_ok!(TemplateModule::set_public_access_mode(origin1.clone(), 1, AccessMode::WhiteList));
940 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 1));
941 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 2));
942 assert_ok!(TemplateModule::add_to_white_list(origin1.clone(), 1, 3));
943
931 assert_ok!(TemplateModule::transfer_from(944 assert_ok!(TemplateModule::transfer_from(
932 origin2.clone(),945 origin2.clone(),
modifiedruntime/src/lib.rsdiffbeforeafterboth
111 spec_name: create_runtime_str!("nft"),111 spec_name: create_runtime_str!("nft"),
112 impl_name: create_runtime_str!("nft"),112 impl_name: create_runtime_str!("nft"),
113 authoring_version: 1,113 authoring_version: 1,
114 spec_version: 1,114 spec_version: 2,
115 impl_version: 1,115 impl_version: 1,
116 apis: RUNTIME_API_VERSIONS,116 apis: RUNTIME_API_VERSIONS,
117 transaction_version: 1,117 transaction_version: 1,