git.delta.rocks / unique-network / refs/commits / 0ba1adb79fd8

difftreelog

misk: generalize 2 methods

Trubnikov Sergey2023-02-01parent: #e31d9d0.patch.diff
in: master

3 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
66 ensure,66 ensure,
67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},67 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},
68 dispatch::Pays,68 dispatch::Pays,
69 transactional,69 transactional, fail,
70};70};
71use pallet_evm::GasWeightMapping;71use pallet_evm::GasWeightMapping;
72use up_data_structs::{72use up_data_structs::{
73 AccessMode,
73 COLLECTION_NUMBER_LIMIT,74 COLLECTION_NUMBER_LIMIT,
74 Collection,75 Collection,
75 RpcCollection,76 RpcCollection,
125use sp_core::H160;126use sp_core::H160;
126use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};127use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};
128
129use crate::erc::CollectionHelpersEvents;
127#[cfg(feature = "runtime-benchmarks")]130#[cfg(feature = "runtime-benchmarks")]
128pub mod benchmarking;131pub mod benchmarking;
129pub mod dispatch;132pub mod dispatch;
1264 Ok(())1267 Ok(())
1265 }1268 }
1269
1270 /// A batch operation to add, edit or remove properties for a token.
1271 /// It sets or removes a token's properties according to
1272 /// `properties_updates` contents:
1273 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`
1274 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.
1275 ///
1276 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.
1277 /// - `is_token_create`: Indicates that method is called during token initialization.
1278 /// Allows to bypass ownership check.
1279 ///
1280 /// All affected properties should have `mutable` permission
1281 /// to be **deleted** or to be **set more than once**,
1282 /// and the sender should have permission to edit those properties.
1283 ///
1284 /// This function fires an event for each property change.
1285 /// In case of an error, all the changes (including the events) will be reverted
1286 /// since the function is transactional.
1287 pub fn modify_token_properties(
1288 collection: &CollectionHandle<T>,
1289 sender: &T::CrossAccountId,
1290 token_id: TokenId,
1291 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
1292 is_token_create: bool,
1293 mut stored_properties: Properties,
1294 is_token_owner: impl Fn() -> Result<bool, DispatchError>,
1295 set_token_properties: impl FnOnce(Properties),
1296 ) -> DispatchResult {
1297 let is_collection_admin = collection.is_owner_or_admin(sender);
1298 let permissions = Self::property_permissions(collection.id);
1299
1300 for (key, value) in properties_updates {
1301 let permission = permissions
1302 .get(&key)
1303 .cloned()
1304 .unwrap_or_else(PropertyPermission::none);
1305
1306 let is_property_exists = stored_properties.get(&key).is_some();
1307
1308 match permission {
1309 PropertyPermission { mutable: false, .. } if is_property_exists => {
1310 return Err(<Error<T>>::NoPermission.into());
1311 }
1312
1313 PropertyPermission {
1314 collection_admin,
1315 token_owner,
1316 ..
1317 } => {
1318 //TODO: investigate threats during public minting.
1319 let is_token_create =
1320 is_token_create && (collection_admin || token_owner) && value.is_some();
1321 if !(is_token_create
1322 || (collection_admin && is_collection_admin)
1323 || (token_owner && is_token_owner()?))
1324 {
1325 fail!(<Error<T>>::NoPermission);
1326 }
1327 }
1328 }
1329
1330 match value {
1331 Some(value) => {
1332 stored_properties
1333 .try_set(key.clone(), value)
1334 .map_err(<Error<T>>::from)?;
1335
1336 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));
1337 }
1338 None => {
1339 stored_properties.remove(&key).map_err(<Error<T>>::from)?;
1340
1341 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));
1342 }
1343 }
1344
1345 <PalletEvm<T>>::deposit_log(
1346 CollectionHelpersEvents::TokenChanged {
1347 collection_id: eth::collection_id_to_address(collection.id),
1348 token_id: token_id.into(),
1349 }
1350 .to_log(T::ContractAddress::get()),
1351 );
1352 }
1353
1354 set_token_properties(stored_properties);
1355
1356 Ok(())
1357 }
1358
1359 /// Sets or unsets the approval of a given operator.
1360 ///
1361 /// The `operator` is allowed to transfer all token pieces of the `owner` on their behalf.
1362 /// - `owner`: Token owner
1363 /// - `operator`: Operator
1364 /// - `approve`: Should operator status be granted or revoked?
1365 pub fn set_allowance_for_all(
1366 collection: &CollectionHandle<T>,
1367 owner: &T::CrossAccountId,
1368 operator: &T::CrossAccountId,
1369 approve: bool,
1370 set_allowance: impl FnOnce(),
1371 log: evm_coder::ethereum::Log,
1372 ) -> DispatchResult {
1373 if collection.permissions.access() == AccessMode::AllowList {
1374 collection.check_allowlist(owner)?;
1375 collection.check_allowlist(operator)?;
1376 }
1377
1378 Self::ensure_correct_receiver(operator)?;
1379
1380 set_allowance();
1381
1382 <PalletEvm<T>>::deposit_log(log);
1383 Self::deposit_event(Event::ApprovedForAll(
1384 collection.id,
1385 owner.clone(),
1386 operator.clone(),
1387 approve,
1388 ));
1389 Ok(())
1390 }
12661391
1267 /// Set collection property.1392 /// Set collection property.
1268 ///1393 ///
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -101,18 +101,18 @@
 };
 use up_data_structs::{
 	AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,
-	CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,
-	PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,
-	TokenChild, AuxPropertyValue, PropertiesPermissionMap,
+	CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyKey,
+	PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, TokenChild,
+	AuxPropertyValue, PropertiesPermissionMap,
 };
 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
 use pallet_common::{
 	Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,
-	eth::collection_id_to_address, erc::CollectionHelpersEvents,
+	eth::collection_id_to_address,
 };
 use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
 use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
-use sp_core::{H160, Get};
+use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
 use core::ops::Deref;
@@ -578,10 +578,6 @@
 	}
 
 	/// A batch operation to add, edit or remove properties for a token.
-	/// It sets or removes a token's properties according to
-	/// `properties_updates` contents:
-	/// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`
-	/// * removes a property under the <key> if the value is `None` `(<key>, None)`.
 	///
 	/// - `nesting_budget`: Limit for searching parents in-depth to check ownership.
 	/// - `is_token_create`: Indicates that method is called during token initialization.
@@ -603,97 +599,30 @@
 		is_token_create: bool,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
-		let mut collection_admin_status = None;
-		let mut token_owner_result = None;
-
-		let mut is_collection_admin =
-			|| *collection_admin_status.get_or_insert_with(|| collection.is_owner_or_admin(sender));
+		let is_token_owner = || {
+			let is_owned = <PalletStructure<T>>::check_indirectly_owned(
+				sender.clone(),
+				collection.id,
+				token_id,
+				None,
+				nesting_budget,
+			)?;
 
-		let mut is_token_owner = || {
-			*token_owner_result.get_or_insert_with(|| -> Result<bool, DispatchError> {
-				let is_owned = <PalletStructure<T>>::check_indirectly_owned(
-					sender.clone(),
-					collection.id,
-					token_id,
-					None,
-					nesting_budget,
-				)?;
-
-				Ok(is_owned)
-			})
+			Ok(is_owned)
 		};
-
-		let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
-		let permissions = <PalletCommon<T>>::property_permissions(collection.id);
-
-		for (key, value) in properties_updates {
-			let permission = permissions
-				.get(&key)
-				.cloned()
-				.unwrap_or_else(PropertyPermission::none);
-
-			let is_property_exists = stored_properties.get(&key).is_some();
-
-			match permission {
-				PropertyPermission { mutable: false, .. } if is_property_exists => {
-					return Err(<CommonError<T>>::NoPermission.into());
-				}
-
-				PropertyPermission {
-					collection_admin,
-					token_owner,
-					..
-				} => {
-					//TODO: investigate threats during public minting.
-					if is_token_create && (collection_admin || token_owner) && value.is_some() {
-						// Pass
-					} else if collection_admin && is_collection_admin() {
-						// Pass
-					} else if token_owner && is_token_owner()? {
-						// Pass
-					} else {
-						fail!(<CommonError<T>>::NoPermission);
-					}
-				}
-			}
 
-			match value {
-				Some(value) => {
-					stored_properties
-						.try_set(key.clone(), value)
-						.map_err(<CommonError<T>>::from)?;
-
-					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(
-						collection.id,
-						token_id,
-						key,
-					));
-				}
-				None => {
-					stored_properties
-						.remove(&key)
-						.map_err(<CommonError<T>>::from)?;
-
-					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
-						collection.id,
-						token_id,
-						key,
-					));
-				}
-			}
-
-			<PalletEvm<T>>::deposit_log(
-				CollectionHelpersEvents::TokenChanged {
-					collection_id: collection_id_to_address(collection.id),
-					token_id: token_id.into(),
-				}
-				.to_log(T::ContractAddress::get()),
-			);
-		}
-
-		<TokenProperties<T>>::set((collection.id, token_id), stored_properties);
+		let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
 
-		Ok(())
+		<PalletCommon<T>>::modify_token_properties(
+			collection,
+			sender,
+			token_id,
+			properties_updates,
+			is_token_create,
+			stored_properties,
+			is_token_owner,
+			|properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
+		)
 	}
 
 	/// Batch operation to add or edit properties for the token
@@ -1418,31 +1347,19 @@
 		operator: &T::CrossAccountId,
 		approve: bool,
 	) -> DispatchResult {
-		if collection.permissions.access() == AccessMode::AllowList {
-			collection.check_allowlist(owner)?;
-			collection.check_allowlist(operator)?;
-		}
-
-		<PalletCommon<T>>::ensure_correct_receiver(operator)?;
-
-		// =========
-
-		<CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);
-		<PalletEvm<T>>::deposit_log(
+		<PalletCommon<T>>::set_allowance_for_all(
+			collection,
+			owner,
+			operator,
+			approve,
+			|| <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),
 			ERC721Events::ApprovalForAll {
 				owner: *owner.as_eth(),
 				operator: *operator.as_eth(),
 				approved: approve,
 			}
 			.to_log(collection_id_to_address(collection.id)),
-		);
-		<PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
-			collection.id,
-			owner.clone(),
-			operator.clone(),
-			approve,
-		));
-		Ok(())
+		)
 	}
 
 	/// Tells whether the given `owner` approves the `operator`.
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -92,22 +92,22 @@
 
 use core::ops::Deref;
 use evm_coder::ToLog;
-use frame_support::{ensure, fail, storage::with_transaction, transactional};
+use frame_support::{ensure, storage::with_transaction, transactional};
 use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
 use pallet_evm_coder_substrate::WithRecorder;
 use pallet_common::{
 	CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,
-	Event as CommonEvent, Pallet as PalletCommon, erc::CollectionHelpersEvents,
+	Event as CommonEvent, Pallet as PalletCommon,
 };
 use pallet_structure::Pallet as PalletStructure;
-use sp_core::{Get, H160};
+use sp_core::H160;
 use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};
 use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};
 use up_data_structs::{
 	AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,
 	mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,
-	PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId,
-	TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,
+	PropertyKeyPermission, PropertyScope, PropertyValue, TokenId, TrySetProperty,
+	PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,
 };
 
 pub use pallet::*;
@@ -245,8 +245,8 @@
 	pub type CollectionAllowance<T: Config> = StorageNMap<
 		Key = (
 			Key<Twox64Concat, CollectionId>,
-			Key<Blake2_128Concat, T::CrossAccountId>,
-			Key<Blake2_128Concat, T::CrossAccountId>,
+			Key<Blake2_128Concat, T::CrossAccountId>, // Owner
+			Key<Blake2_128Concat, T::CrossAccountId>, // Operator
 		),
 		Value = bool,
 		QueryKind = ValueQuery,
@@ -541,7 +541,6 @@
 		is_token_create: bool,
 		nesting_budget: &dyn Budget,
 	) -> DispatchResult {
-		let is_collection_admin = || collection.is_owner_or_admin(sender);
 		let is_token_owner = || -> Result<bool, DispatchError> {
 			let balance = collection.balance(sender.clone(), token_id);
 			let total_pieces: u128 =
@@ -560,77 +559,19 @@
 
 			Ok(is_bundle_owner)
 		};
-
-		let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
-		let permissions = <PalletCommon<T>>::property_permissions(collection.id);
-
-		for (key, value) in properties_updates {
-			let permission = permissions
-				.get(&key)
-				.cloned()
-				.unwrap_or_else(PropertyPermission::none);
-
-			let is_property_exists = stored_properties.get(&key).is_some();
-
-			match permission {
-				PropertyPermission { mutable: false, .. } if is_property_exists => {
-					return Err(<CommonError<T>>::NoPermission.into());
-				}
 
-				PropertyPermission {
-					collection_admin,
-					token_owner,
-					..
-				} => {
-					//TODO: investigate threats during public minting.
-					let is_token_create =
-						is_token_create && (collection_admin || token_owner) && value.is_some();
-					if !(is_token_create
-						|| (collection_admin && is_collection_admin())
-						|| (token_owner && is_token_owner()?))
-					{
-						fail!(<CommonError<T>>::NoPermission);
-					}
-				}
-			}
-
-			match value {
-				Some(value) => {
-					stored_properties
-						.try_set(key.clone(), value)
-						.map_err(<CommonError<T>>::from)?;
-
-					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(
-						collection.id,
-						token_id,
-						key,
-					));
-				}
-				None => {
-					stored_properties
-						.remove(&key)
-						.map_err(<CommonError<T>>::from)?;
+		let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
 
-					<PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
-						collection.id,
-						token_id,
-						key,
-					));
-				}
-			}
-
-			<PalletEvm<T>>::deposit_log(
-				CollectionHelpersEvents::TokenChanged {
-					collection_id: collection_id_to_address(collection.id),
-					token_id: token_id.into(),
-				}
-				.to_log(T::ContractAddress::get()),
-			);
-		}
-
-		<TokenProperties<T>>::set((collection.id, token_id), stored_properties);
-
-		Ok(())
+		<PalletCommon<T>>::modify_token_properties(
+			collection,
+			sender,
+			token_id,
+			properties_updates,
+			is_token_create,
+			stored_properties,
+			is_token_owner,
+			|properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
+		)
 	}
 
 	pub fn set_token_properties(
@@ -1465,31 +1406,19 @@
 		operator: &T::CrossAccountId,
 		approve: bool,
 	) -> DispatchResult {
-		if collection.permissions.access() == AccessMode::AllowList {
-			collection.check_allowlist(owner)?;
-			collection.check_allowlist(operator)?;
-		}
-
-		<PalletCommon<T>>::ensure_correct_receiver(operator)?;
-
-		// =========
-
-		<CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);
-		<PalletEvm<T>>::deposit_log(
+		<PalletCommon<T>>::set_allowance_for_all(
+			collection,
+			owner,
+			operator,
+			approve,
+			|| <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),
 			ERC721Events::ApprovalForAll {
 				owner: *owner.as_eth(),
 				operator: *operator.as_eth(),
 				approved: approve,
 			}
 			.to_log(collection_id_to_address(collection.id)),
-		);
-		<PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(
-			collection.id,
-			owner.clone(),
-			operator.clone(),
-			approve,
-		));
-		Ok(())
+		)
 	}
 
 	/// Tells whether the given `owner` approves the `operator`.