difftreelog
feat approval chain extensions
in: master
2 files changed
pallets/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>,
runtime/src/chain_extension.rsdiffbeforeafterboth43 pub data: Vec<CreateItemData>,43 pub data: Vec<CreateItemData>,44}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}456246/// The chain Extension of NFT pallet63/// The chain Extension of NFT pallet47pub struct NFTExtension;64pub struct NFTExtension;103 _ => Err(DispatchError::Other("CreateMultipleItems error"))120 _ => Err(DispatchError::Other("CreateMultipleItems error"))104 }121 }105 },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 },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 }