git.delta.rocks / unique-network / refs/commits / 3c083fe10539

difftreelog

feat approval chain extensions

Yaroslav Bolyukin2021-05-06parent: #f600776.patch.diff
in: master

2 files changed

modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -1259,43 +1259,10 @@
         pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            let target_collection = Self::get_collection(collection_id)?;
-
-            Self::token_exists(&target_collection, item_id)?;
+            let collection = Self::get_collection(collection_id)?;
 
-            // Transfer permissions check
-            let bypasses_limits = target_collection.limits.owner_can_transfer &&
-                Self::is_owner_or_admin_permissions(
-                    &target_collection,
-                    sender.clone(),
-                );
-
-            let allowance_limit = if bypasses_limits {
-                None
-            } else if let Some(amount) = Self::owned_amount(
-                sender.clone(),
-                &target_collection,
-                item_id,
-            ) {
-                Some(amount)
-            } else {
-                fail!(Error::<T>::NoPermission);
-            };
-
-            if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(&target_collection, &sender)?;
-                Self::check_white_list(&target_collection, &spender)?;
-            }
-
-            let allowance: u128 = amount
-                .checked_add(<Allowances<T>>::get(collection_id, (item_id, &sender, &spender)))
-                .ok_or(Error::<T>::NumOverflow)?;
-            if let Some(limit) = allowance_limit {
-                ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);
-            }
-            <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);
+            Self::approve_internal(sender, spender, &collection, item_id, amount)?;
 
-            Self::deposit_event(RawEvent::Approved(target_collection.id, item_id, sender, spender, allowance));
             Ok(())
         }
         
@@ -1323,46 +1290,10 @@
         pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {
 
             let sender = ensure_signed(origin)?;
-            let target_collection = Self::get_collection(collection_id)?;
-
-            // Check approval
-            let approval: u128 = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));
+            let collection = Self::get_collection(collection_id)?;
 
-            // Limits check
-            Self::is_correct_transfer(&target_collection, &recipient)?;
-
-            // Transfer permissions check         
-            ensure!(
-                approval >= value || 
-                (
-                    target_collection.limits.owner_can_transfer &&
-                    Self::is_owner_or_admin_permissions(&target_collection, sender.clone())
-                ),
-                Error::<T>::NoPermission
-            );
-
-            if target_collection.access == AccessMode::WhiteList {
-                Self::check_white_list(&target_collection, &sender)?;
-                Self::check_white_list(&target_collection, &recipient)?;
-            }
-
-            // Reduce approval by transferred amount or remove if remaining approval drops to 0
-            if approval.saturating_sub(value) > 0 {
-                <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);
-            }
-            else {
-                <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));
-            }
+            Self::transfer_from_internal(sender, from, recipient, &collection, item_id, value)?;
 
-            match target_collection.mode
-            {
-                CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from.clone(), recipient.clone())?,
-                CollectionMode::Fungible(_)  => Self::transfer_fungible(&target_collection, value, &from, &recipient)?,
-                CollectionMode::ReFungible  => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient.clone())?,
-                _ => ()
-            };
-
-            Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, from, recipient, value));
             Ok(())
         }
 
@@ -1792,6 +1723,104 @@
         Ok(())
     }
 
+	pub fn approve_internal(
+		sender: T::AccountId,
+		spender: T::AccountId,
+		collection: &CollectionHandle<T>,
+		item_id: TokenId,
+		amount: u128,
+	) -> DispatchResult {
+		Self::token_exists(&collection, item_id)?;
+
+		// Transfer permissions check
+		let bypasses_limits = collection.limits.owner_can_transfer &&
+			Self::is_owner_or_admin_permissions(
+				&collection,
+				sender.clone(),
+			);
+
+		let allowance_limit = if bypasses_limits {
+			None
+		} else if let Some(amount) = Self::owned_amount(
+			sender.clone(),
+			&collection,
+			item_id,
+		) {
+			Some(amount)
+		} else {
+			fail!(Error::<T>::NoPermission);
+		};
+
+		if collection.access == AccessMode::WhiteList {
+			Self::check_white_list(&collection, &sender)?;
+			Self::check_white_list(&collection, &spender)?;
+		}
+
+		let allowance: u128 = amount
+			.checked_add(<Allowances<T>>::get(collection.id, (item_id, &sender, &spender)))
+			.ok_or(Error::<T>::NumOverflow)?;
+		if let Some(limit) = allowance_limit {
+			ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);
+		}
+		<Allowances<T>>::insert(collection.id, (item_id, &sender, &spender), allowance);
+
+		Self::deposit_event(RawEvent::Approved(collection.id, item_id, sender, spender, allowance));
+		Ok(())
+	}
+
+	pub fn transfer_from_internal(
+		sender: T::AccountId,
+		from: T::AccountId,
+		recipient: T::AccountId,
+		collection: &CollectionHandle<T>,
+		item_id: TokenId,
+		amount: u128,
+	) -> DispatchResult {
+		// Check approval
+		let approval: u128 = <Allowances<T>>::get(collection.id, (item_id, &from, &sender));
+
+		// Limits check
+		Self::is_correct_transfer(&collection, &recipient)?;
+
+		// Transfer permissions check
+		ensure!(
+			approval >= amount || 
+			(
+				collection.limits.owner_can_transfer &&
+				Self::is_owner_or_admin_permissions(&collection, sender.clone())
+			),
+			Error::<T>::NoPermission
+		);
+
+		if collection.access == AccessMode::WhiteList {
+			Self::check_white_list(&collection, &sender)?;
+			Self::check_white_list(&collection, &recipient)?;
+		}
+
+		// Reduce approval by transferred amount or remove if remaining approval drops to 0
+		let allowance = approval.saturating_sub(amount);
+		if allowance > 0 {
+			<Allowances<T>>::insert(collection.id, (item_id, &from, &sender), allowance);
+		} else {
+			<Allowances<T>>::remove(collection.id, (item_id, &from, &sender));
+		}
+
+		match collection.mode {
+			CollectionMode::NFT => {
+				Self::transfer_nft(&collection, item_id, from.clone(), recipient.clone())?
+			}
+			CollectionMode::Fungible(_) => {
+				Self::transfer_fungible(&collection, amount, &from, &recipient)?
+			}
+			CollectionMode::ReFungible => {
+				Self::transfer_refungible(&collection, item_id, amount, from.clone(), recipient.clone())?
+			}
+			_ => ()
+		};
+
+		Ok(())
+	}
+
     pub fn create_multiple_items_internal(
         sender: T::AccountId,
         collection: &CollectionHandle<T>,
modifiedruntime/src/chain_extension.rsdiffbeforeafterboth
43 pub data: Vec<CreateItemData>,43 pub data: Vec<CreateItemData>,
44}44}
45
46#[derive(Debug, PartialEq, Encode, Decode)]
47pub struct NFTExtApprove<E: Ext> {
48 pub spender: <E::T as SysConfig>::AccountId,
49 pub collection_id: u32,
50 pub item_id: u32,
51 pub amount: u128,
52}
53
54#[derive(Debug, PartialEq, Encode, Decode)]
55pub struct NFTExtTransferFrom<E: Ext> {
56 pub owner: <E::T as SysConfig>::AccountId,
57 pub recipient: <E::T as SysConfig>::AccountId,
58 pub collection_id: u32,
59 pub item_id: u32,
60 pub amount: u128,
61}
4562
46/// The chain Extension of NFT pallet63/// The chain Extension of NFT pallet
47pub struct NFTExtension;64pub struct NFTExtension;
103 _ => Err(DispatchError::Other("CreateMultipleItems error"))120 _ => Err(DispatchError::Other("CreateMultipleItems error"))
104 }121 }
105 },122 },
123 3 => {
124 // Approve
125 let mut env = env.buf_in_buf_out();
126 let input: NFTExtApprove<E> = env.read_as()?;
127
128 let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;
129
130 pallet_nft::Module::<C>::approve_internal(
131 env.ext().address().clone(),
132 input.spender,
133 &collection,
134 input.item_id,
135 input.amount,
136 )?;
137 Ok(RetVal::Converging(func_id))
138 },
139 4 => {
140 // Transfer from
141 let mut env = env.buf_in_buf_out();
142 let input: NFTExtTransferFrom<E> = env.read_as()?;
143
144 let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;
145
146 pallet_nft::Module::<C>::transfer_from_internal(
147 env.ext().address().clone(),
148 input.owner,
149 input.recipient,
150 &collection,
151 input.item_id,
152 input.amount
153 )?;
154 Ok(RetVal::Converging(func_id))
155 },
106 _ => {156 _ => {
107 panic!("Passed unknown func_id to test chain extension: {}", func_id);157 panic!("Passed unknown func_id to test chain extension: {}", func_id);
108 }158 }