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
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 }