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
1259 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 {
12601260
1261 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)?;
12631263
1264 Self::token_exists(&target_collection, item_id)?;1264 Self::approve_internal(sender, spender, &collection, item_id, amount)?;
12651265
1266 // Transfer permissions check
1267 let bypasses_limits = target_collection.limits.owner_can_transfer &&
1268 Self::is_owner_or_admin_permissions(
1269 &target_collection,
1270 sender.clone(),
1271 );
1272
1273 let allowance_limit = if bypasses_limits {
1274 None
1275 } 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 };
1284
1285 if target_collection.access == AccessMode::WhiteList {
1286 Self::check_white_list(&target_collection, &sender)?;
1287 Self::check_white_list(&target_collection, &spender)?;
1288 }
1289
1290 let allowance: u128 = amount
1291 .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);
1297
1298 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 {
13241291
1325 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)?;
13271294
1328 // Check approval
1329 let approval: u128 = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));
1330
1331 // Limits check
1332 Self::is_correct_transfer(&target_collection, &recipient)?;1295 Self::transfer_from_internal(sender, from, recipient, &collection, item_id, value)?;
13331296
1334 // 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>::NoPermission
1342 );
1343
1344 if target_collection.access == AccessMode::WhiteList {
1345 Self::check_white_list(&target_collection, &sender)?;
1346 Self::check_white_list(&target_collection, &recipient)?;
1347 }
1348
1349 // Reduce approval by transferred amount or remove if remaining approval drops to 0
1350 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 }
1356
1357 match target_collection.mode
1358 {
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 };
1364
1365 Self::deposit_event(RawEvent::Transfer(target_collection.id, item_id, from, recipient, value));
1366 Ok(())1297 Ok(())
1367 }1298 }
13681299
1792 Ok(())1723 Ok(())
1793 }1724 }
1725
1726 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)?;
1734
1735 // Transfer permissions check
1736 let bypasses_limits = collection.limits.owner_can_transfer &&
1737 Self::is_owner_or_admin_permissions(
1738 &collection,
1739 sender.clone(),
1740 );
1741
1742 let allowance_limit = if bypasses_limits {
1743 None
1744 } 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 };
1753
1754 if collection.access == AccessMode::WhiteList {
1755 Self::check_white_list(&collection, &sender)?;
1756 Self::check_white_list(&collection, &spender)?;
1757 }
1758
1759 let allowance: u128 = amount
1760 .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);
1766
1767 Self::deposit_event(RawEvent::Approved(collection.id, item_id, sender, spender, allowance));
1768 Ok(())
1769 }
1770
1771 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 approval
1780 let approval: u128 = <Allowances<T>>::get(collection.id, (item_id, &from, &sender));
1781
1782 // Limits check
1783 Self::is_correct_transfer(&collection, &recipient)?;
1784
1785 // Transfer permissions check
1786 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>::NoPermission
1793 );
1794
1795 if collection.access == AccessMode::WhiteList {
1796 Self::check_white_list(&collection, &sender)?;
1797 Self::check_white_list(&collection, &recipient)?;
1798 }
1799
1800 // Reduce approval by transferred amount or remove if remaining approval drops to 0
1801 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 }
1807
1808 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 };
1820
1821 Ok(())
1822 }
17941823
1795 pub fn create_multiple_items_internal(1824 pub fn create_multiple_items_internal(
1796 sender: T::AccountId,1825 sender: T::AccountId,
modifiedruntime/src/chain_extension.rsdiffbeforeafterboth
--- a/runtime/src/chain_extension.rs
+++ b/runtime/src/chain_extension.rs
@@ -43,6 +43,23 @@
     pub data: Vec<CreateItemData>,
 }
 
+#[derive(Debug, PartialEq, Encode, Decode)]
+pub struct NFTExtApprove<E: Ext> {
+    pub spender: <E::T as SysConfig>::AccountId,
+    pub collection_id: u32,
+    pub item_id: u32,
+    pub amount: u128,
+}
+
+#[derive(Debug, PartialEq, Encode, Decode)]
+pub struct NFTExtTransferFrom<E: Ext> {
+    pub owner: <E::T as SysConfig>::AccountId,
+    pub recipient: <E::T as SysConfig>::AccountId,
+    pub collection_id: u32,
+    pub item_id: u32,
+    pub amount: u128,
+}
+
 /// The chain Extension of NFT pallet
 pub struct NFTExtension;
 
@@ -103,6 +120,39 @@
                     _ => Err(DispatchError::Other("CreateMultipleItems error"))
                 }
             },
+            3 => {
+                // Approve
+                let mut env = env.buf_in_buf_out();
+                let input: NFTExtApprove<E> = env.read_as()?;
+
+                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;
+
+                pallet_nft::Module::<C>::approve_internal(
+                    env.ext().address().clone(),
+                    input.spender,
+                    &collection,
+                    input.item_id,
+                    input.amount,
+                )?;
+                Ok(RetVal::Converging(func_id))
+            },
+            4 => {
+                // Transfer from
+                let mut env = env.buf_in_buf_out();
+                let input: NFTExtTransferFrom<E> = env.read_as()?;
+
+                let collection = pallet_nft::Module::<C>::get_collection(input.collection_id)?;
+
+                pallet_nft::Module::<C>::transfer_from_internal(
+                    env.ext().address().clone(),
+                    input.owner,
+                    input.recipient,
+                    &collection,
+                    input.item_id,
+                    input.amount
+                )?;
+                Ok(RetVal::Converging(func_id))
+            },
             _ => {
                 panic!("Passed unknown func_id to test chain extension: {}", func_id);
             }