difftreelog
feat approval chain extensions
in: master
2 files changed
pallets/nft/src/lib.rsdiffbeforeafterboth1259 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {1259 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {126012601261 let sender = ensure_signed(origin)?;1261 let sender = ensure_signed(origin)?;1262 let target_collection = Self::get_collection(collection_id)?;1262 let collection = Self::get_collection(collection_id)?;126312631264 Self::token_exists(&target_collection, item_id)?;1264 Self::approve_internal(sender, spender, &collection, item_id, amount)?;126512651266 // Transfer permissions check1267 let bypasses_limits = target_collection.limits.owner_can_transfer &&1268 Self::is_owner_or_admin_permissions(1269 &target_collection,1270 sender.clone(),1271 );12721273 let allowance_limit = if bypasses_limits {1274 None1275 } else if let Some(amount) = Self::owned_amount(1276 sender.clone(),1277 &target_collection,1278 item_id,1279 ) {1280 Some(amount)1281 } else {1282 fail!(Error::<T>::NoPermission);1283 };12841285 if target_collection.access == AccessMode::WhiteList {1286 Self::check_white_list(&target_collection, &sender)?;1287 Self::check_white_list(&target_collection, &spender)?;1288 }12891290 let allowance: u128 = amount1291 .checked_add(<Allowances<T>>::get(collection_id, (item_id, &sender, &spender)))1292 .ok_or(Error::<T>::NumOverflow)?;1293 if let Some(limit) = allowance_limit {1294 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1295 }1296 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);12971298 Self::deposit_event(RawEvent::Approved(target_collection.id, item_id, sender, spender, allowance));1299 Ok(())1266 Ok(())1300 }1267 }1301 1268 1323 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {1290 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {132412911325 let sender = ensure_signed(origin)?;1292 let sender = ensure_signed(origin)?;1326 let target_collection = Self::get_collection(collection_id)?;1293 let collection = Self::get_collection(collection_id)?;132712941328 // Check approval1329 let approval: u128 = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));13301331 // Limits check1332 Self::is_correct_transfer(&target_collection, &recipient)?;1295 Self::transfer_from_internal(sender, from, recipient, &collection, item_id, value)?;133312961334 // Transfer permissions check 1335 ensure!(1336 approval >= value || 1337 (1338 target_collection.limits.owner_can_transfer &&1339 Self::is_owner_or_admin_permissions(&target_collection, sender.clone())1340 ),1341 Error::<T>::NoPermission1342 );13431344 if target_collection.access == AccessMode::WhiteList {1345 Self::check_white_list(&target_collection, &sender)?;1346 Self::check_white_list(&target_collection, &recipient)?;1347 }13481349 // Reduce approval by transferred amount or remove if remaining approval drops to 01350 if approval.saturating_sub(value) > 0 {1351 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1352 }1353 else {1354 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1355 }13561357 match target_collection.mode1358 {1359 CollectionMode::NFT => Self::transfer_nft(&target_collection, item_id, from.clone(), recipient.clone())?,1360 CollectionMode::Fungible(_) => Self::transfer_fungible(&target_collection, value, &from, &recipient)?,1361 CollectionMode::ReFungible => Self::transfer_refungible(&target_collection, item_id, value, from.clone(), recipient.clone())?,1362 _ => ()1363 };13641365 Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, from, recipient, value));1366 Ok(())1297 Ok(())1367 }1298 }136812991792 Ok(())1723 Ok(())1793 }1724 }17251726 pub fn approve_internal(1727 sender: T::AccountId,1728 spender: T::AccountId,1729 collection: &CollectionHandle<T>,1730 item_id: TokenId,1731 amount: u128,1732 ) -> DispatchResult {1733 Self::token_exists(&collection, item_id)?;17341735 // Transfer permissions check1736 let bypasses_limits = collection.limits.owner_can_transfer &&1737 Self::is_owner_or_admin_permissions(1738 &collection,1739 sender.clone(),1740 );17411742 let allowance_limit = if bypasses_limits {1743 None1744 } else if let Some(amount) = Self::owned_amount(1745 sender.clone(),1746 &collection,1747 item_id,1748 ) {1749 Some(amount)1750 } else {1751 fail!(Error::<T>::NoPermission);1752 };17531754 if collection.access == AccessMode::WhiteList {1755 Self::check_white_list(&collection, &sender)?;1756 Self::check_white_list(&collection, &spender)?;1757 }17581759 let allowance: u128 = amount1760 .checked_add(<Allowances<T>>::get(collection.id, (item_id, &sender, &spender)))1761 .ok_or(Error::<T>::NumOverflow)?;1762 if let Some(limit) = allowance_limit {1763 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1764 }1765 <Allowances<T>>::insert(collection.id, (item_id, &sender, &spender), allowance);17661767 Self::deposit_event(RawEvent::Approved(collection.id, item_id, sender, spender, allowance));1768 Ok(())1769 }17701771 pub fn transfer_from_internal(1772 sender: T::AccountId,1773 from: T::AccountId,1774 recipient: T::AccountId,1775 collection: &CollectionHandle<T>,1776 item_id: TokenId,1777 amount: u128,1778 ) -> DispatchResult {1779 // Check approval1780 let approval: u128 = <Allowances<T>>::get(collection.id, (item_id, &from, &sender));17811782 // Limits check1783 Self::is_correct_transfer(&collection, &recipient)?;17841785 // Transfer permissions check1786 ensure!(1787 approval >= amount || 1788 (1789 collection.limits.owner_can_transfer &&1790 Self::is_owner_or_admin_permissions(&collection, sender.clone())1791 ),1792 Error::<T>::NoPermission1793 );17941795 if collection.access == AccessMode::WhiteList {1796 Self::check_white_list(&collection, &sender)?;1797 Self::check_white_list(&collection, &recipient)?;1798 }17991800 // Reduce approval by transferred amount or remove if remaining approval drops to 01801 let allowance = approval.saturating_sub(amount);1802 if allowance > 0 {1803 <Allowances<T>>::insert(collection.id, (item_id, &from, &sender), allowance);1804 } else {1805 <Allowances<T>>::remove(collection.id, (item_id, &from, &sender));1806 }18071808 match collection.mode {1809 CollectionMode::NFT => {1810 Self::transfer_nft(&collection, item_id, from.clone(), recipient.clone())?1811 }1812 CollectionMode::Fungible(_) => {1813 Self::transfer_fungible(&collection, amount, &from, &recipient)?1814 }1815 CollectionMode::ReFungible => {1816 Self::transfer_refungible(&collection, item_id, amount, from.clone(), recipient.clone())?1817 }1818 _ => ()1819 };18201821 Ok(())1822 }179418231795 pub fn create_multiple_items_internal(1824 pub fn create_multiple_items_internal(1796 sender: T::AccountId,1825 sender: T::AccountId,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 }