git.delta.rocks / unique-network / refs/commits / d16b1c1c96a6

difftreelog

Substrate 2

str-mv2020-05-06parent: #6aa91b6.patch.diff
in: master

4 files changed

modifiedCargo.lockdiffbeforeafterboth
2859 "sp-core",2859 "sp-core",
2860 "sp-io",2860 "sp-io",
2861 "sp-runtime",2861 "sp-runtime",
2862 "sp-std",
2862]2863]
28632864
2864[[package]]2865[[package]]
modifiedpallets/template/Cargo.tomldiffbeforeafterboth
--- a/pallets/template/Cargo.toml
+++ b/pallets/template/Cargo.toml
@@ -17,6 +17,14 @@
 package = 'parity-scale-codec'
 version = '1.3.0'
 
+[dependencies.sp-std]
+default-features = false
+version = '2.0.0-alpha.6'
+
+[dependencies.sp-runtime]
+default-features = false
+version = '2.0.0-alpha.6'
+
 [dependencies.frame-support]
 default-features = false
 version = '2.0.0-alpha.6'
@@ -32,14 +40,15 @@
 default-features = false
 version = '2.0.0-alpha.6'
 
-[dev-dependencies.sp-runtime]
-default-features = false
-version = '2.0.0-alpha.6'
 
+
 [features]
 default = ['std']
 std = [
     'codec/std',
     'frame-support/std',
     'frame-system/std',
+    "sp-io/std",
+    "sp-runtime/std",
+    'sp-std/std',
 ]
modifiedpallets/template/src/lib.rsdiffbeforeafterboth
--- a/pallets/template/src/lib.rs
+++ b/pallets/template/src/lib.rs
@@ -9,8 +9,14 @@
 /// For more guidance on Substrate FRAME, see the example pallet
 /// https://github.com/paritytech/substrate/blob/master/frame/example/src/lib.rs
 
-use frame_support::{decl_module, decl_storage, decl_event, decl_error, dispatch};
-use frame_system::{self as system, ensure_signed};
+use frame_support::{
+	dispatch::DispatchResult, decl_module, decl_storage, decl_event,
+	weights::{DispatchClass, ClassifyDispatch, WeighData, Weight},
+	ensure,
+};
+use frame_system::{self as system, ensure_signed };
+use codec::{Encode, Decode};
+use sp_runtime::sp_std::prelude::Vec;
 
 #[cfg(test)]
 mod mock;
@@ -18,6 +24,29 @@
 #[cfg(test)]
 mod tests;
 
+#[derive(Encode, Decode, Default, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct CollectionType<AccountId> {
+	pub owner: AccountId,
+	pub next_item_id: u64,
+	pub custom_data_size: u32,
+}
+
+#[derive(Encode, Decode, Default, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct CollectionAdminsType<AccountId> {
+	pub admin: AccountId,
+	pub collection_id: u64,
+}
+
+#[derive(Encode, Decode, Default, Clone, PartialEq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct NftItemType<AccountId> {
+	pub collection: u64,
+	pub owner: AccountId,
+	pub data: Vec<u8>,
+}
+
 /// The pallet's configuration trait.
 pub trait Trait: system::Trait {
 	// Add other types and constants required to configure this pallet.
@@ -30,80 +59,258 @@
 decl_storage! {
 	// It is important to update your storage name so that your pallet's
 	// storage items are isolated from other pallets.
-	// ---------------------------------vvvvvvvvvvvvvv
 	trait Store for Module<T: Trait> as TemplateModule {
-		// Just a dummy storage item.
-		// Here we are declaring a StorageValue, `Something` as a Option<u32>
-		// `get(fn something)` is the default getter which returns either the stored `u32` or `None` if nothing stored
-		Something get(fn something): Option<u32>;
+
+		/// Next available collection ID
+		pub NextCollectionID get(next_collection_id): u64;
+
+		/// Collection map
+		pub Collection get(collection): map hasher(blake2_128_concat) u64 => CollectionType<T::AccountId>;
+
+		/// Admins map (collection)
+		pub AdminList get(admin_list_collection): map hasher(blake2_128_concat) u64 => Vec<T::AccountId>;
+
+		/// Balance owner per collection map
+		pub Balance get(balance_count): map hasher(blake2_128_concat) (u64, T::AccountId) => u64;
+
+		/// Item double map (collection)
+		pub ItemList get(item_id): map hasher(blake2_128_concat) (u64, u64) => NftItemType<T::AccountId>;
+		pub ItemListIndex get(item_index): map hasher(blake2_128_concat) u64 => u64;
 	}
 }
 
 // The pallet's events
 decl_event!(
 	pub enum Event<T> where AccountId = <T as system::Trait>::AccountId {
-		/// Just a dummy event.
-		/// Event `Something` is declared with a parameter of the type `u32` and `AccountId`
-		/// To emit this event, we call the deposit function, from our runtime functions
-		SomethingStored(u32, AccountId),
+		Created(u32, AccountId),
 	}
 );
 
-// The pallet's errors
-decl_error! {
-	pub enum Error for Module<T: Trait> {
-		/// Value was None
-		NoneValue,
-		/// Value reached maximum and cannot be incremented further
-		StorageOverflow,
-	}
-}
-
 // The pallet's dispatchable functions.
 decl_module! {
 	/// The module declaration.
 	pub struct Module<T: Trait> for enum Call where origin: T::Origin {
-		// Initializing errors
-		// this includes information about your errors in the node's metadata.
-		// it is needed only if you are using errors in your pallet
-		type Error = Error<T>;
 
 		// Initializing events
 		// this is needed only if you are using events in your pallet
 		fn deposit_event() = default;
 
-		/// Just a dummy entry point.
-		/// function that can be called by the external world as an extrinsics call
-		/// takes a parameter of the type `AccountId`, stores it, and emits an event
+		// Initializing events
+		// this is needed only if you are using events in your module
+		// fn deposit_event<T>() = default;
+
+		// Create collection of NFT with given parameters
+		//
+		// @param customDataSz size of custom data in each collection item
+		// returns collection ID
+
+		// Create collection of NFT with given parameters
+		//
+		// @param customDataSz size of custom data in each collection item
+		// returns collection ID
 		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
-		pub fn do_something(origin, something: u32) -> dispatch::DispatchResult {
-			// Check it was signed and get the signer. See also: ensure_root and ensure_none
+		pub fn create_collection(origin, custom_data_sz: u32) -> DispatchResult {
+			// Anyone can create a collection
 			let who = ensure_signed(origin)?;
 
-			// Code to execute when something calls this.
-			// For example: the following line stores the passed in u32 in the storage
-			Something::put(something);
+			// Generate next collection ID
+			let next_id = Self::next_collection_id();
+			<NextCollectionID>::put(next_id+1);
+
+			// Create new collection
+			let new_collection = CollectionType {
+				owner: who,
+				next_item_id: next_id,
+				custom_data_size: custom_data_sz,
+			};
+			
+			// Add new collection to map
+			<Collection<T>>::insert(next_id, new_collection);
+
+			Ok(())
+		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let owner = <Collection<T>>::get(collection_id).owner;
+			ensure!(sender == owner, "You do not own this collection");
+			<Collection<T>>::remove(collection_id);
+
+			Ok(())
+		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let mut target_collection = <Collection<T>>::get(collection_id);
+			ensure!(sender == target_collection.owner, "You do not own this collection");
+
+			target_collection.owner = new_owner;
+			<Collection<T>>::insert(collection_id, target_collection);
 
-			// Here we are raising the Something event
-			Self::deposit_event(RawEvent::SomethingStored(something, who));
 			Ok(())
 		}
 
-		/// Another dummy entry point.
-		/// takes no parameters, attempts to increment storage value, and possibly throws an error
 		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
-		pub fn cause_error(origin) -> dispatch::DispatchResult {
-			// Check it was signed and get the signer. See also: ensure_root and ensure_none
-			let _who = ensure_signed(origin)?;
+		pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {
 
-			match Something::get() {
-				None => Err(Error::<T>::NoneValue)?,
-				Some(old) => {
-					let new = old.checked_add(1).ok_or(Error::<T>::StorageOverflow)?;
-					Something::put(new);
-					Ok(())
-				},
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let target_collection = <Collection<T>>::get(collection_id);
+			let is_owner = sender == target_collection.owner;
+
+			let no_perm_mes = "You do not have permissions to modify this collection";
+			let exists = <AdminList<T>>::contains_key(collection_id);
+
+			if !is_owner 
+			{
+				 ensure!(exists, no_perm_mes);
+				 ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
+			}
+			
+			let mut admin_arr: Vec<T::AccountId> = Vec::new();
+			if exists
+			{
+				admin_arr = <AdminList<T>>::get(collection_id);
+				ensure!(!admin_arr.contains(&new_admin_id), "Account already has admin role");
+			}
+
+			admin_arr.push(new_admin_id);
+			<AdminList<T>>::insert(collection_id, admin_arr);
+
+			Ok(())
+		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let target_collection = <Collection<T>>::get(collection_id);
+			let is_owner = sender == target_collection.owner;
+
+			let no_perm_mes = "You do not have permissions to modify this collection";
+			let exists = <AdminList<T>>::contains_key(collection_id);
+
+			if !is_owner 
+			{
+				ensure!(exists, no_perm_mes);
+				ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
 			}
+
+			if exists
+			{
+				let mut admin_arr = <AdminList<T>>::get(collection_id);
+				admin_arr.retain(|i| *i != account_id);
+				<AdminList<T>>::insert(collection_id, admin_arr);
+			}
+
+			Ok(())
 		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn create_item(origin, collection_id: u64, properties: Vec<u8>) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let target_collection = <Collection<T>>::get(collection_id);
+			ensure!(target_collection.custom_data_size >= properties.len() as u32, "Size of item is too large");
+			let is_owner = sender == target_collection.owner;
+
+			let no_perm_mes = "You do not have permissions to modify this collection";
+			let exists = <AdminList<T>>::contains_key(collection_id);
+
+			if !is_owner 
+			{
+				ensure!(exists, no_perm_mes);
+				ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
+			}
+
+			let new_balance = <Balance<T>>::get((collection_id, sender.clone())) + 1;
+			<Balance<T>>::insert((collection_id, sender.clone()), new_balance);
+
+			// Create new item
+			let new_item = NftItemType {
+				collection: collection_id,
+				owner: sender,
+				data: properties,
+			};
+
+			let current_index = <ItemListIndex>::get(collection_id);
+			<ItemListIndex>::insert(collection_id, current_index+1);
+			<ItemList<T>>::insert((collection_id, current_index), new_item);
+
+			Ok(())
+		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let target_collection = <Collection<T>>::get(collection_id);
+			let is_owner = sender == target_collection.owner;
+
+			ensure!(<ItemList<T>>::contains_key((collection_id, item_id)), "Item does not exists");
+			let item = <ItemList<T>>::get((collection_id, item_id));
+
+			if !is_owner 
+			{
+				// check if item owner
+				if item.owner != sender 
+				{
+					let no_perm_mes = "You do not have permissions to modify this collection";
+
+					ensure!(<AdminList<T>>::contains_key(collection_id), no_perm_mes);
+					ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
+				}
+			}
+			<ItemList<T>>::remove((collection_id, item_id));
+
+			Ok(())
+		}
+
+		#[weight = frame_support::weights::SimpleDispatchInfo::default()]
+		pub fn transfer(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {
+
+			let sender = ensure_signed(origin)?;
+			ensure!(<Collection<T>>::contains_key(collection_id), "This collection does not exist");
+
+			let target_collection = <Collection<T>>::get(collection_id);
+			let is_owner = sender == target_collection.owner;
+
+			ensure!(<ItemList<T>>::contains_key((collection_id, item_id)), "Item does not exists");
+			let mut item = <ItemList<T>>::get((collection_id, item_id));
+
+			if !is_owner 
+			{
+				// check if item owner
+				if item.owner != sender 
+				{
+					let no_perm_mes = "You do not have permissions to modify this collection";
+
+					ensure!(<AdminList<T>>::contains_key(collection_id), no_perm_mes);
+					ensure!(<AdminList<T>>::get(collection_id).contains(&sender), no_perm_mes);
+				}
+			}
+			<ItemList<T>>::remove((collection_id, item_id));
+
+			// change owner
+			item.owner = new_owner;
+			<ItemList<T>>::insert((collection_id, item_id), item);
+
+			Ok(())
+		}
 	}
-}
+}
\ No newline at end of file
modifiedpallets/template/src/tests.rsdiffbeforeafterboth
--- a/pallets/template/src/tests.rs
+++ b/pallets/template/src/tests.rs
@@ -1,26 +1,24 @@
 // Tests to be written here
-
-use crate::{Error, mock::*};
 use frame_support::{assert_ok, assert_noop};
 
-#[test]
-fn it_works_for_default_value() {
-	new_test_ext().execute_with(|| {
-		// Just a dummy test for the dummy function `do_something`
-		// calling the `do_something` function with a value 42
-		assert_ok!(TemplateModule::do_something(Origin::signed(1), 42));
-		// asserting that the stored value is equal to what we stored
-		assert_eq!(TemplateModule::something(), Some(42));
-	});
-}
+// #[test]
+// fn it_works_for_default_value() {
+// 	new_test_ext().execute_with(|| {
+// 		// Just a dummy test for the dummy function `do_something`
+// 		// calling the `do_something` function with a value 42
+// 		assert_ok!(TemplateModule::do_something(Origin::signed(1), 42));
+// 		// asserting that the stored value is equal to what we stored
+// 		assert_eq!(TemplateModule::something(), Some(42));
+// 	});
+// }
 
-#[test]
-fn correct_error_for_none_value() {
-	new_test_ext().execute_with(|| {
-		// Ensure the correct error is thrown on None value
-		assert_noop!(
-			TemplateModule::cause_error(Origin::signed(1)),
-			Error::<Test>::NoneValue
-		);
-	});
-}
+// #[test]
+// fn correct_error_for_none_value() {
+// 	new_test_ext().execute_with(|| {
+// 		// Ensure the correct error is thrown on None value
+// 		assert_noop!(
+// 			TemplateModule::cause_error(Origin::signed(1)),
+// 			Error::<Test>::NoneValue
+// 		);
+// 	});
+// }