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
101};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 }
579579
580 /// 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 to
582 /// `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;
608
609 let mut is_collection_admin =
610 || *collection_admin_status.get_or_insert_with(|| collection.is_owner_or_admin(sender));
611
612 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 )?;
621610
622 Ok(is_owned)611 Ok(is_owned)
623 })
624 };612 };
625613
626 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));614 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
615
627 let permissions = <PalletCommon<T>>::property_permissions(collection.id);616 <PalletCommon<T>>::modify_token_properties(
628
629 for (key, value) in properties_updates {617 collection,
630 let permission = permissions
631 .get(&key)
632 .cloned()
633 .unwrap_or_else(PropertyPermission::none);
634
635 let is_property_exists = stored_properties.get(&key).is_some();
636
637 match permission {
638 PropertyPermission { mutable: false, .. } if is_property_exists => {618 sender,
639 return Err(<CommonError<T>>::NoPermission.into());
640 }
641
642 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 // Pass
650 } else if collection_admin && is_collection_admin() {
651 // Pass
652 } else if token_owner && is_token_owner()? {
653 // Pass
654 } else {
655 fail!(<CommonError<T>>::NoPermission);
656 }
657 }
658 }
659
660 match value {
661 Some(value) => {
662 stored_properties
663 .try_set(key.clone(), value)
664 .map_err(<CommonError<T>>::from)?;
665
666 <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)?;
676
677 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
678 collection.id,
679 token_id,
680 key,
681 ));
682 }
683 }
684
685 <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 }
693
694 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);624 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
695625 )
696 Ok(())
697 }626 }
698627
699 /// Batch operation to add or edit properties for the token628 /// Batch operation to add or edit properties for the token
1418 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)?;
1427
1428 // =========
1429
1430 <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 }
14471364
1448 /// Tells whether the given `owner` approves the `operator`.1365 /// Tells whether the given `owner` approves the `operator`.
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
9292
93use 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};
112112
245 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>, // Owner
249 Key<Blake2_128Concat, T::CrossAccountId>,249 Key<Blake2_128Concat, T::CrossAccountId>, // Operator
250 ),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 };
563562
564 let mut stored_properties = <TokenProperties<T>>::get((collection.id, token_id));563 let stored_properties = <TokenProperties<T>>::get((collection.id, token_id));
564
565 let permissions = <PalletCommon<T>>::property_permissions(collection.id);565 <PalletCommon<T>>::modify_token_properties(
566
567 for (key, value) in properties_updates {566 collection,
568 let permission = permissions
569 .get(&key)
570 .cloned()
571 .unwrap_or_else(PropertyPermission::none);
572
573 let is_property_exists = stored_properties.get(&key).is_some();
574
575 match permission {
576 PropertyPermission { mutable: false, .. } if is_property_exists => {567 sender,
577 return Err(<CommonError<T>>::NoPermission.into());
578 }
579
580 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_create
589 || (collection_admin && is_collection_admin())
590 || (token_owner && is_token_owner()?))
591 {
592 fail!(<CommonError<T>>::NoPermission);
593 }
594 }
595 }
596
597 match value {
598 Some(value) => {
599 stored_properties
600 .try_set(key.clone(), value)
601 .map_err(<CommonError<T>>::from)?;
602
603 <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)?;
613
614 <PalletCommon<T>>::deposit_event(CommonEvent::TokenPropertyDeleted(
615 collection.id,
616 token_id,
617 key,
618 ));
619 }
620 }
621
622 <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 }
630
631 <TokenProperties<T>>::set((collection.id, token_id), stored_properties);573 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
632574 )
633 Ok(())
634 }575 }
635576
636 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)?;
1474
1475 // =========
1476
1477 <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 }
14941423
1495 /// Tells whether the given `owner` approves the `operator`.1424 /// Tells whether the given `owner` approves the `operator`.