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
before · runtime/src/chain_extension.rs
1//! NFT Chain Extension23//4// This file is subject to the terms and conditions defined in5// file 'LICENSE', which is part of this source code package.6//78use codec::{Decode, Encode};910pub use pallet_contracts::chain_extension::RetVal;11use pallet_contracts::chain_extension::{12    ChainExtension, Environment, Ext, InitState, SysConfig, UncheckedFrom,13};1415pub use frame_support::debug;16use frame_support::dispatch::DispatchError;1718extern crate pallet_nft;19pub use pallet_nft::*;20use crate::Vec;2122/// Create item parameters23#[derive(Debug, PartialEq, Encode, Decode)]24pub struct NFTExtCreateItem<E: Ext> {25    pub owner: <E::T as SysConfig>::AccountId,26    pub collection_id: u32,27    pub data: CreateItemData,28}2930/// Transfer parameters31#[derive(Debug, PartialEq, Encode, Decode)]32pub struct NFTExtTransfer<E: Ext> {33    pub recipient: <E::T as SysConfig>::AccountId,34    pub collection_id: u32,35    pub token_id: u32,36    pub amount: u128,37}3839#[derive(Debug, PartialEq, Encode, Decode)]40pub struct NFTExtCreateMultipleItems<E: Ext> {41    pub owner: <E::T as SysConfig>::AccountId,42    pub collection_id: u32,43    pub data: Vec<CreateItemData>,44}4546/// The chain Extension of NFT pallet47pub struct NFTExtension;4849impl<C: Config> ChainExtension<C> for NFTExtension {50    fn call<E: Ext>(func_id: u32, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>51    where52        E: Ext<T = C>,53        <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,54    {55        // The memory of the vm stores buf in scale-codec56        match func_id {57            0 => {58                let mut env = env.buf_in_buf_out();59                let input: NFTExtTransfer<E> = env.read_as()?;6061                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;6263                match pallet_nft::Module::<C>::transfer_internal(64                    env.ext().caller().clone(),65                    input.recipient,66                    &collection,67                    input.token_id,68                    input.amount,69                ) {70                    Ok(_) => Ok(RetVal::Converging(func_id)),71                    _ => Err(DispatchError::Other("Transfer error"))72                }73            },74            1 => {75                // Create Item76                let mut env = env.buf_in_buf_out();77                let input: NFTExtCreateItem<E> = env.read_as()?;7879                match pallet_nft::Module::<C>::create_item_internal(80                    env.ext().address().clone(),81                    input.collection_id,82                    input.owner,83                    input.data,84                ) {85                    Ok(_) => Ok(RetVal::Converging(func_id)),86                    _ => Err(DispatchError::Other("CreateItem error"))87                }88            },89            2 => {90                // Create multiple items91                let mut env = env.buf_in_buf_out();92                let input: NFTExtCreateMultipleItems<E> = env.read_as()?;9394                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;9596                match pallet_nft::Module::<C>::create_multiple_items_internal(97                    env.ext().address().clone(),98                    &collection,99                    input.owner,100                    input.data,101                ) {102                    Ok(_) => Ok(RetVal::Converging(func_id)),103                    _ => Err(DispatchError::Other("CreateMultipleItems error"))104                }105            },106            _ => {107                panic!("Passed unknown func_id to test chain extension: {}", func_id);108            }109        }110    }111}
after · runtime/src/chain_extension.rs
1//! NFT Chain Extension23//4// This file is subject to the terms and conditions defined in5// file 'LICENSE', which is part of this source code package.6//78use codec::{Decode, Encode};910pub use pallet_contracts::chain_extension::RetVal;11use pallet_contracts::chain_extension::{12    ChainExtension, Environment, Ext, InitState, SysConfig, UncheckedFrom,13};1415pub use frame_support::debug;16use frame_support::dispatch::DispatchError;1718extern crate pallet_nft;19pub use pallet_nft::*;20use crate::Vec;2122/// Create item parameters23#[derive(Debug, PartialEq, Encode, Decode)]24pub struct NFTExtCreateItem<E: Ext> {25    pub owner: <E::T as SysConfig>::AccountId,26    pub collection_id: u32,27    pub data: CreateItemData,28}2930/// Transfer parameters31#[derive(Debug, PartialEq, Encode, Decode)]32pub struct NFTExtTransfer<E: Ext> {33    pub recipient: <E::T as SysConfig>::AccountId,34    pub collection_id: u32,35    pub token_id: u32,36    pub amount: u128,37}3839#[derive(Debug, PartialEq, Encode, Decode)]40pub struct NFTExtCreateMultipleItems<E: Ext> {41    pub owner: <E::T as SysConfig>::AccountId,42    pub collection_id: u32,43    pub data: Vec<CreateItemData>,44}4546#[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}5354#[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}6263/// The chain Extension of NFT pallet64pub struct NFTExtension;6566impl<C: Config> ChainExtension<C> for NFTExtension {67    fn call<E: Ext>(func_id: u32, env: Environment<E, InitState>) -> Result<RetVal, DispatchError>68    where69        E: Ext<T = C>,70        <E::T as SysConfig>::AccountId: UncheckedFrom<<E::T as SysConfig>::Hash> + AsRef<[u8]>,71    {72        // The memory of the vm stores buf in scale-codec73        match func_id {74            0 => {75                let mut env = env.buf_in_buf_out();76                let input: NFTExtTransfer<E> = env.read_as()?;7778                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;7980                match pallet_nft::Module::<C>::transfer_internal(81                    env.ext().caller().clone(),82                    input.recipient,83                    &collection,84                    input.token_id,85                    input.amount,86                ) {87                    Ok(_) => Ok(RetVal::Converging(func_id)),88                    _ => Err(DispatchError::Other("Transfer error"))89                }90            },91            1 => {92                // Create Item93                let mut env = env.buf_in_buf_out();94                let input: NFTExtCreateItem<E> = env.read_as()?;9596                match pallet_nft::Module::<C>::create_item_internal(97                    env.ext().address().clone(),98                    input.collection_id,99                    input.owner,100                    input.data,101                ) {102                    Ok(_) => Ok(RetVal::Converging(func_id)),103                    _ => Err(DispatchError::Other("CreateItem error"))104                }105            },106            2 => {107                // Create multiple items108                let mut env = env.buf_in_buf_out();109                let input: NFTExtCreateMultipleItems<E> = env.read_as()?;110111                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;112113                match pallet_nft::Module::<C>::create_multiple_items_internal(114                    env.ext().address().clone(),115                    &collection,116                    input.owner,117                    input.data,118                ) {119                    Ok(_) => Ok(RetVal::Converging(func_id)),120                    _ => Err(DispatchError::Other("CreateMultipleItems error"))121                }122            },123            3 => {124                // Approve125                let mut env = env.buf_in_buf_out();126                let input: NFTExtApprove<E> = env.read_as()?;127128                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;129130                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 from141                let mut env = env.buf_in_buf_out();142                let input: NFTExtTransferFrom<E> = env.read_as()?;143144                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;145146                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.amount153                )?;154                Ok(RetVal::Converging(func_id))155            },156            _ => {157                panic!("Passed unknown func_id to test chain extension: {}", func_id);158            }159        }160    }161}