difftreelog
misk: generalize 2 methods
in: master
3 files changed
pallets/common/src/lib.rsdiffbeforeafterboth66 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};128129use 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 }12691270 /// A batch operation to add, edit or remove properties for a token.1271 /// It sets or removes a token's properties according to1272 /// `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` permission1281 /// 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 reverted1286 /// 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);12991300 for (key, value) in properties_updates {1301 let permission = permissions1302 .get(&key)1303 .cloned()1304 .unwrap_or_else(PropertyPermission::none);13051306 let is_property_exists = stored_properties.get(&key).is_some();13071308 match permission {1309 PropertyPermission { mutable: false, .. } if is_property_exists => {1310 return Err(<Error<T>>::NoPermission.into());1311 }13121313 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_create1322 || (collection_admin && is_collection_admin)1323 || (token_owner && is_token_owner()?))1324 {1325 fail!(<Error<T>>::NoPermission);1326 }1327 }1328 }13291330 match value {1331 Some(value) => {1332 stored_properties1333 .try_set(key.clone(), value)1334 .map_err(<Error<T>>::from)?;13351336 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));1337 }1338 None => {1339 stored_properties.remove(&key).map_err(<Error<T>>::from)?;13401341 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));1342 }1343 }13441345 <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 }13531354 set_token_properties(stored_properties);13551356 Ok(())1357 }13581359 /// 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 owner1363 /// - `operator`: Operator1364 /// - `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 }13771378 Self::ensure_correct_receiver(operator)?;13791380 set_allowance();13811382 <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 }126613911267 /// Set collection property.1392 /// Set collection property.1268 ///1393 ///pallets/nonfungible/src/lib.rsdiffbeforeafterboth101};101};102use up_data_structs::{102use up_data_structs::{103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,103 AccessMode, CollectionId, CollectionFlags, CustomDataLimit, TokenId, CreateCollectionData,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyPermission,104 CreateNftExData, mapping::TokenAddressMapping, budget::Budget, Property, PropertyKey,105 PropertyKey, PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,105 PropertyValue, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, TokenChild,106 TokenChild, AuxPropertyValue, PropertiesPermissionMap,106 AuxPropertyValue, PropertiesPermissionMap,107};107};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};108use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};109use pallet_common::{109use pallet_common::{110 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,110 Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, CollectionHandle,111 eth::collection_id_to_address, erc::CollectionHelpersEvents,111 eth::collection_id_to_address,112};112};113use pallet_structure::{Pallet as PalletStructure, Error as StructureError};113use pallet_structure::{Pallet as PalletStructure, Error as StructureError};114use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};114use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};115use sp_core::{H160, Get};115use sp_core::H160;116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};116use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};117use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};117use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};118use core::ops::Deref;118use core::ops::Deref;578 }578 }579579580 /// A batch operation to add, edit or remove properties for a token.580 /// A batch operation to add, edit or remove properties for a token.581 /// It sets or removes a token's properties according to582 /// `properties_updates` contents:583 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`584 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.585 ///581 ///586 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.582 /// - `nesting_budget`: Limit for searching parents in-depth to check ownership.587 /// - `is_token_create`: Indicates that method is called during token initialization.583 /// - `is_token_create`: Indicates that method is called during token initialization.603 is_token_create: bool,599 is_token_create: bool,604 nesting_budget: &dyn Budget,600 nesting_budget: &dyn Budget,605 ) -> DispatchResult {601 ) -> DispatchResult {606 let mut collection_admin_status = None;607 let mut token_owner_result = None;608609 let mut is_collection_admin =610 || *collection_admin_status.get_or_insert_with(|| collection.is_owner_or_admin(sender));611612 let mut is_token_owner = || {602 let is_token_owner = || {613 *token_owner_result.get_or_insert_with(|| -> Result<bool, DispatchError> {614 let is_owned = <PalletStructure<T>>::check_indirectly_owned(603 let is_owned = <PalletStructure<T>>::check_indirectly_owned(615 sender.clone(),604 sender.clone(),616 collection.id,605 collection.id,620 )?;609 )?;621610622 Ok(is_owned)611 Ok(is_owned)623 })624 };612 };625613626 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));614 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));615627 let permissions = <PalletCommon<T>>::property_permissions(collection.id);616 <PalletCommon<T>>::modify_token_properties(628629 for (key, value) in properties_updates {617 collection,630 let permission = permissions631 .get(&key)632 .cloned()633 .unwrap_or_else(PropertyPermission::none);634635 let is_property_exists = stored_properties.get(&key).is_some();636637 match permission {638 PropertyPermission { mutable: false, .. } if is_property_exists => {618 sender,639 return Err(<CommonError<T>>::NoPermission.into());640 }641642 PropertyPermission {643 collection_admin,619 token_id,644 token_owner,620 properties_updates,645 ..646 } => {647 //TODO: investigate threats during public minting.648 if is_token_create && (collection_admin || token_owner) && value.is_some() {621 is_token_create,649 // Pass650 } else if collection_admin && is_collection_admin() {651 // Pass652 } else if token_owner && is_token_owner()? {653 // Pass654 } else {655 fail!(<CommonError<T>>::NoPermission);656 }657 }658 }659660 match value {661 Some(value) => {662 stored_properties663 .try_set(key.clone(), value)664 .map_err(<CommonError<T>>::from)?;665666 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(667 collection.id,668 token_id,669 key,670 ));671 }672 None => {673 stored_properties622 stored_properties,674 .remove(&key)675 .map_err(<CommonError<T>>::from)?;676677 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(678 collection.id,679 token_id,680 key,681 ));682 }683 }684685 <PalletEvm<T>>::deposit_log(686 CollectionHelpersEvents::TokenChanged {687 collection_id: collection_id_to_address(collection.id),688 token_id: token_id.into(),689 }690 .to_log(T::ContractAddress::get()),623 is_token_owner,691 );692 }693694 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);624 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),695625 )696 Ok(())697 }626 }698627699 /// Batch operation to add or edit properties for the token628 /// Batch operation to add or edit properties for the token1418 operator: &T::CrossAccountId,1347 operator: &T::CrossAccountId,1419 approve: bool,1348 approve: bool,1420 ) -> DispatchResult {1349 ) -> DispatchResult {1421 if collection.permissions.access() == AccessMode::AllowList {1350 <PalletCommon<T>>::set_allowance_for_all(1422 collection.check_allowlist(owner)?;1351 collection,1423 collection.check_allowlist(operator)?;1352 owner,1424 }1353 operator,14251354 approve,1426 <PalletCommon<T>>::ensure_correct_receiver(operator)?;14271428 // =========14291430 <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);1355 || <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),1431 <PalletEvm<T>>::deposit_log(1432 ERC721Events::ApprovalForAll {1356 ERC721Events::ApprovalForAll {1433 owner: *owner.as_eth(),1357 owner: *owner.as_eth(),1434 operator: *operator.as_eth(),1358 operator: *operator.as_eth(),1435 approved: approve,1359 approved: approve,1436 }1360 }1437 .to_log(collection_id_to_address(collection.id)),1361 .to_log(collection_id_to_address(collection.id)),1438 );1362 )1439 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(1440 collection.id,1441 owner.clone(),1442 operator.clone(),1443 approve,1444 ));1445 Ok(())1446 }1363 }144713641448 /// Tells whether the given `owner` approves the `operator`.1365 /// Tells whether the given `owner` approves the `operator`.pallets/refungible/src/lib.rsdiffbeforeafterboth929293use core::ops::Deref;93use core::ops::Deref;94use evm_coder::ToLog;94use evm_coder::ToLog;95use frame_support::{ensure, fail, storage::with_transaction, transactional};95use frame_support::{ensure, storage::with_transaction, transactional};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};96use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};97use pallet_evm_coder_substrate::WithRecorder;97use pallet_evm_coder_substrate::WithRecorder;98use pallet_common::{98use pallet_common::{99 CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,99 CommonCollectionOperations, Error as CommonError, eth::collection_id_to_address,100 Event as CommonEvent, Pallet as PalletCommon, erc::CollectionHelpersEvents,100 Event as CommonEvent, Pallet as PalletCommon,101};101};102use pallet_structure::Pallet as PalletStructure;102use pallet_structure::Pallet as PalletStructure;103use sp_core::{Get, H160};103use sp_core::H160;104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};104use sp_runtime::{ArithmeticError, DispatchError, DispatchResult, TransactionOutcome};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};105use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap};106use up_data_structs::{106use up_data_structs::{107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,107 AccessMode, budget::Budget, CollectionId, CollectionFlags, CreateCollectionData,108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,108 mapping::TokenAddressMapping, MAX_REFUNGIBLE_PIECES, Property, PropertyKey,109 PropertyKeyPermission, PropertyPermission, PropertyScope, PropertyValue, TokenId,109 PropertyKeyPermission, PropertyScope, PropertyValue, TokenId, TrySetProperty,110 TrySetProperty, PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,110 PropertiesPermissionMap, CreateRefungibleExMultipleOwners, TokenOwnerError,111};111};112112245 pub type CollectionAllowance<T: Config> = StorageNMap<245 pub type CollectionAllowance<T: Config> = StorageNMap<246 Key = (246 Key = (247 Key<Twox64Concat, CollectionId>,247 Key<Twox64Concat, CollectionId>,248 Key<Blake2_128Concat, T::CrossAccountId>,248 Key<Blake2_128Concat, T::CrossAccountId>, // Owner249 Key<Blake2_128Concat, T::CrossAccountId>,249 Key<Blake2_128Concat, T::CrossAccountId>, // Operator250 ),250 ),251 Value = bool,251 Value = bool,252 QueryKind = ValueQuery,252 QueryKind = ValueQuery,541 is_token_create: bool,541 is_token_create: bool,542 nesting_budget: &dyn Budget,542 nesting_budget: &dyn Budget,543 ) -> DispatchResult {543 ) -> DispatchResult {544 let is_collection_admin = || collection.is_owner_or_admin(sender);545 let is_token_owner = || -> Result<bool, DispatchError> {544 let is_token_owner = || -> Result<bool, DispatchError> {546 let balance = collection.balance(sender.clone(), token_id);545 let balance = collection.balance(sender.clone(), token_id);547 let total_pieces: u128 =546 let total_pieces: u128 =561 Ok(is_bundle_owner)560 Ok(is_bundle_owner)562 };561 };563562564 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));563 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));564565 let permissions = <PalletCommon<T>>::property_permissions(collection.id);565 <PalletCommon<T>>::modify_token_properties(566567 for (key, value) in properties_updates {566 collection,568 let permission = permissions569 .get(&key)570 .cloned()571 .unwrap_or_else(PropertyPermission::none);572573 let is_property_exists = stored_properties.get(&key).is_some();574575 match permission {576 PropertyPermission { mutable: false, .. } if is_property_exists => {567 sender,577 return Err(<CommonError<T>>::NoPermission.into());578 }579580 PropertyPermission {581 collection_admin,568 token_id,582 token_owner,569 properties_updates,583 ..584 } => {585 //TODO: investigate threats during public minting.586 let is_token_create =570 is_token_create,587 is_token_create && (collection_admin || token_owner) && value.is_some();588 if !(is_token_create589 || (collection_admin && is_collection_admin())590 || (token_owner && is_token_owner()?))591 {592 fail!(<CommonError<T>>::NoPermission);593 }594 }595 }596597 match value {598 Some(value) => {599 stored_properties600 .try_set(key.clone(), value)601 .map_err(<CommonError<T>>::from)?;602603 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertySet(604 collection.id,605 token_id,606 key,607 ));608 }609 None => {610 stored_properties571 stored_properties,611 .remove(&key)612 .map_err(<CommonError<T>>::from)?;613614 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(615 collection.id,616 token_id,617 key,618 ));619 }620 }621622 <PalletEvm<T>>::deposit_log(623 CollectionHelpersEvents::TokenChanged {624 collection_id: collection_id_to_address(collection.id),625 token_id: token_id.into(),626 }627 .to_log(T::ContractAddress::get()),572 is_token_owner,628 );629 }630631 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);573 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),632574 )633 Ok(())634 }575 }635576636 pub fn set_token_properties(577 pub fn set_token_properties(1465 operator: &T::CrossAccountId,1406 operator: &T::CrossAccountId,1466 approve: bool,1407 approve: bool,1467 ) -> DispatchResult {1408 ) -> DispatchResult {1468 if collection.permissions.access() == AccessMode::AllowList {1409 <PalletCommon<T>>::set_allowance_for_all(1469 collection.check_allowlist(owner)?;1410 collection,1470 collection.check_allowlist(operator)?;1411 owner,1471 }1412 operator,14721413 approve,1473 <PalletCommon<T>>::ensure_correct_receiver(operator)?;14741475 // =========14761477 <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve);1414 || <CollectionAllowance<T>>::insert((collection.id, owner, operator), approve),1478 <PalletEvm<T>>::deposit_log(1479 ERC721Events::ApprovalForAll {1415 ERC721Events::ApprovalForAll {1480 owner: *owner.as_eth(),1416 owner: *owner.as_eth(),1481 operator: *operator.as_eth(),1417 operator: *operator.as_eth(),1482 approved: approve,1418 approved: approve,1483 }1419 }1484 .to_log(collection_id_to_address(collection.id)),1420 .to_log(collection_id_to_address(collection.id)),1485 );1421 )1486 <PalletCommon<T>>::deposit_event(CommonEvent::ApprovedForAll(1487 collection.id,1488 owner.clone(),1489 operator.clone(),1490 approve,1491 ));1492 Ok(())1493 }1422 }149414231495 /// Tells whether the given `owner` approves the `operator`.1424 /// Tells whether the given `owner` approves the `operator`.