git.delta.rocks / unique-network / refs/commits / 44071b633884

difftreelog

refactor use type-safe propertywriter to set/delete properties

Daniel Shiposha2023-09-30parent: #d2c9363.patch.diff
in: master

12 files changed

modifiedpallets/balances-adapter/src/common.rsdiffbeforeafterboth
172 fail!(<pallet_common::Error<T>>::UnsupportedOperation);172 fail!(<pallet_common::Error<T>>::UnsupportedOperation);
173 }173 }
174
175 fn get_token_properties_map(&self, _token_id: TokenId) -> up_data_structs::TokenProperties {
176 // No token properties are defined on fungibles
177 up_data_structs::TokenProperties::new()
178 }
179
180 fn set_token_properties_map(&self, _token_id: TokenId, _map: up_data_structs::TokenProperties) {
181 // No token properties are defined on fungibles
182 }
183
184 fn properties_exist(&self, _token: TokenId) -> bool {
185 // No token properties are defined on fungibles
186 false
187 }
174188
175 fn set_token_property_permissions(189 fn set_token_property_permissions(
176 &self,190 &self,
277 Err(up_data_structs::TokenOwnerError::MultipleOwners)291 Err(up_data_structs::TokenOwnerError::MultipleOwners)
278 }292 }
293
294 fn check_token_indirect_owner(
295 &self,
296 _token: TokenId,
297 _maybe_owner: &<T>::CrossAccountId,
298 _nesting_budget: &dyn up_data_structs::budget::Budget,
299 ) -> Result<bool, frame_support::sp_runtime::DispatchError> {
300 Ok(false)
301 }
279302
280 fn token_owners(&self, _token: TokenId) -> Vec<<T>::CrossAccountId> {303 fn token_owners(&self, _token: TokenId) -> Vec<<T>::CrossAccountId> {
281 vec![]304 vec![]
modifiedpallets/common/src/benchmarking.rsdiffbeforeafterboth
22use frame_benchmarking::{benchmarks, account};22use frame_benchmarking::{benchmarks, account};
23use up_data_structs::{23use up_data_structs::{
24 CollectionMode, CreateCollectionData, CollectionId, Property, PropertyKey, PropertyValue,24 CollectionMode, CreateCollectionData, CollectionId, Property, PropertyKey, PropertyValue,
25 CollectionPermissions, NestingPermissions, AccessMode, MAX_COLLECTION_NAME_LENGTH,25 CollectionPermissions, NestingPermissions, AccessMode, PropertiesPermissionMap,
26 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, MAX_PROPERTIES_PER_ITEM,26 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
27 MAX_PROPERTIES_PER_ITEM,
27};28};
123 )124 )
124}125}
126
127pub fn load_is_admin_and_property_permissions<T: Config>(
128 collection: &CollectionHandle<T>,
129 sender: &T::CrossAccountId,
130) -> (bool, PropertiesPermissionMap) {
131 (
132 collection.is_owner_or_admin(sender),
133 <Pallet<T>>::property_permissions(collection.id),
134 )
135}
125136
126/// Helper macros, which handles all benchmarking preparation in semi-declarative way137/// Helper macros, which handles all benchmarking preparation in semi-declarative way
127///138///
216227
217 }: {collection_handle.check_allowlist(&sender)?;}228 }: {collection_handle.check_allowlist(&sender)?;}
229
230 init_token_properties_common {
231 bench_init!{
232 owner: sub; collection: collection(owner);
233 sender: sub;
234 sender: cross_from_sub(sender);
235 };
236 }: {load_is_admin_and_property_permissions(&collection, &sender);}
218}237}
219238
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
56use core::{56use core::{
57 ops::{Deref, DerefMut},57 ops::{Deref, DerefMut},
58 slice::from_ref,58 slice::from_ref,
59 marker::PhantomData,
59};60};
60use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};61use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
61use sp_std::vec::Vec;62use sp_std::vec::Vec;
98#[allow(missing_docs)]99#[allow(missing_docs)]
99pub mod weights;100pub mod weights;
101
102use weights::WeightInfo;
103
100/// Weight info.104/// Weight info.
101pub type SelfWeightOf<T> = <T as Config>::WeightInfo;105pub type SelfWeightOf<T> = <T as Config>::WeightInfo;
865 >;869 >;
866}870}
867
868/// Represents the change mode for the token property.
869pub enum SetPropertyMode {
870 /// The token already exists.
871 ExistingToken,
872
873 /// New token.
874 NewToken {
875 /// The creator of the token is the recipient.
876 mint_target_is_sender: bool,
877 },
878}
879871
880/// Value representation with delayed initialization time.872/// Value representation with delayed initialization time.
881pub struct LazyValue<T, F: FnOnce() -> T> {873pub struct LazyValue<T, F: FnOnce() -> T> {
892 }884 }
893 }885 }
894886
895 /// Get the value. If it call furst time the value will be initialized.887 /// Get the value. If it is called the first time, the value will be initialized.
896 pub fn value(&mut self) -> &T {888 pub fn value(&mut self) -> &T {
897 if self.value.is_none() {889 self.compute_value_if_not_already();
898 self.value = Some(self.f.take().unwrap()())
899 }
900
901 self.value.as_ref().unwrap()890 self.value.as_ref().unwrap()
902 }891 }
892
893 /// Get the value. If it is called the first time, the value will be initialized.
894 pub fn value_mut(&mut self) -> &mut T {
895 self.compute_value_if_not_already();
896 self.value.as_mut().unwrap()
897 }
898
899 fn into_inner(mut self) -> T {
900 self.compute_value_if_not_already();
901 self.value.unwrap()
902 }
903903
904 /// Is value initialized.904 /// Is value initialized?
905 pub fn has_value(&self) -> bool {905 pub fn has_value(&self) -> bool {
906 self.value.is_some()906 self.value.is_some()
907 }907 }
908
909 fn compute_value_if_not_already(&mut self) {
910 if self.value.is_none() {
911 self.value = Some(self.f.take().unwrap()())
912 }
913 }
908}914}
909915
910fn check_token_permissions<T, FCA, FTO, FTE>(916fn check_token_permissions<T, FCA, FTO, FTE>(
926 fail!(<Error<T>>::NoPermission);932 fail!(<Error<T>>::NoPermission);
927 }933 }
928934
929 let token_certainly_exist = is_token_owner.has_value() && (*is_token_owner.value())?;935 let token_exist_due_to_owner_check_success =
936 is_token_owner.has_value() && (*is_token_owner.value())?;
937
938 // If the token owner check has occurred and succeeded,
939 // we know the token exists (otherwise, the owner check must fail).
930 if !token_certainly_exist && !is_token_exist.value() {940 if !token_exist_due_to_owner_check_success {
941 // If the token owner check didn't occur,
942 // we must check the token's existence ourselves.
943 if !is_token_exist.value() {
931 fail!(<Error<T>>::TokenNotFound);944 fail!(<Error<T>>::TokenNotFound);
932 }945 }
946 }
947
933 Ok(())948 Ok(())
934}949}
1312 Ok(())1327 Ok(())
1313 }1328 }
1314
1315 /// A batch operation to add, edit or remove properties for a token.
1316 /// It sets or removes a token's properties according to
1317 /// `properties_updates` contents:
1318 /// * sets a property under the <key> with the value provided `(<key>, Some(<value>))`
1319 /// * removes a property under the <key> if the value is `None` `(<key>, None)`.
1320 ///
1321 /// All affected properties should have `mutable` permission
1322 /// to be **deleted** or to be **set more than once**,
1323 /// and the sender should have permission to edit those properties.
1324 ///
1325 /// This function fires an event for each property change.
1326 /// In case of an error, all the changes (including the events) will be reverted
1327 /// since the function is transactional.
1328 #[allow(clippy::too_many_arguments)]
1329 pub fn modify_token_properties<FTO, FTE>(
1330 collection: &CollectionHandle<T>,
1331 sender: &T::CrossAccountId,
1332 token_id: TokenId,
1333 is_token_exist: &mut LazyValue<bool, FTE>,
1334 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
1335 mut stored_properties: TokenProperties,
1336 is_token_owner: &mut LazyValue<Result<bool, DispatchError>, FTO>,
1337 set_token_properties: impl FnOnce(TokenProperties),
1338 log: evm_coder::ethereum::Log,
1339 ) -> DispatchResult
1340 where
1341 FTO: FnOnce() -> Result<bool, DispatchError>,
1342 FTE: FnOnce() -> bool,
1343 {
1344 let mut is_collection_admin = LazyValue::new(|| collection.is_owner_or_admin(sender));
1345 let mut permissions = LazyValue::new(|| Self::property_permissions(collection.id));
1346
1347 let mut changed = false;
1348 for (key, value) in properties_updates {
1349 let permission = permissions
1350 .value()
1351 .get(&key)
1352 .cloned()
1353 .unwrap_or_else(PropertyPermission::none);
1354
1355 let property_exists = stored_properties.get(&key).is_some();
1356
1357 match permission {
1358 PropertyPermission { mutable: false, .. } if property_exists => {
1359 return Err(<Error<T>>::NoPermission.into());
1360 }
1361
1362 PropertyPermission {
1363 collection_admin,
1364 token_owner,
1365 ..
1366 } => check_token_permissions::<T, _, FTO, FTE>(
1367 collection_admin,
1368 token_owner,
1369 &mut is_collection_admin,
1370 is_token_owner,
1371 is_token_exist,
1372 )?,
1373 }
1374
1375 match value {
1376 Some(value) => {
1377 stored_properties
1378 .try_set(key.clone(), value)
1379 .map_err(<Error<T>>::from)?;
1380
1381 Self::deposit_event(Event::TokenPropertySet(collection.id, token_id, key));
1382 }
1383 None => {
1384 stored_properties.remove(&key).map_err(<Error<T>>::from)?;
1385
1386 Self::deposit_event(Event::TokenPropertyDeleted(collection.id, token_id, key));
1387 }
1388 }
1389
1390 changed = true;
1391 }
1392
1393 if changed {
1394 <PalletEvm<T>>::deposit_log(log);
1395 set_token_properties(stored_properties);
1396 }
1397
1398 Ok(())
1399 }
14001329
1401 /// Sets or unsets the approval of a given operator.1330 /// Sets or unsets the approval of a given operator.
1402 ///1331 ///
2166 budget: &dyn Budget,2095 budget: &dyn Budget,
2167 ) -> DispatchResultWithPostInfo;2096 ) -> DispatchResultWithPostInfo;
2097
2098 /// Get token properties raw map.
2099 ///
2100 /// * `token_id` - The token which properties are needed.
2101 fn get_token_properties_map(&self, token_id: TokenId) -> TokenProperties;
2102
2103 /// Set token properties raw map.
2104 ///
2105 /// * `token_id` - The token for which the properties are being set.
2106 /// * `map` - The raw map containing the token's properties.
2107 fn set_token_properties_map(&self, token_id: TokenId, map: TokenProperties);
2108
2109 /// Whether the given token has properties.
2110 ///
2111 /// * `token_id` - The token in question.
2112 fn properties_exist(&self, token: TokenId) -> bool;
21682113
2169 /// Set token property permissions.2114 /// Set token property permissions.
2170 ///2115 ///
2309 /// * `token` - The token for which you need to find out the owner.2254 /// * `token` - The token for which you need to find out the owner.
2310 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;2255 fn token_owner(&self, token: TokenId) -> Result<T::CrossAccountId, TokenOwnerError>;
2256
2257 /// Checks if the `maybe_owner` is the indirect owner of the `token`.
2258 ///
2259 /// * `token` - Id token to check.
2260 /// * `maybe_owner` - The account to check.
2261 /// * `nesting_budget` - A budget that can be spent on nesting tokens.
2262 fn check_token_indirect_owner(
2263 &self,
2264 token: TokenId,
2265 maybe_owner: &T::CrossAccountId,
2266 nesting_budget: &dyn Budget,
2267 ) -> Result<bool, DispatchError>;
23112268
2312 /// Returns 10 tokens owners in no particular order.2269 /// Returns 10 tokens owners in no particular order.
2313 ///2270 ///
2420 }2377 }
2421}2378}
2379
2380/// A marker structure that enables the writer implementation
2381/// to provide the interface to write properties to **newly created** tokens.
2382pub struct NewTokenPropertyWriter;
2383
2384/// A marker structure that enables the writer implementation
2385/// to provide the interface to write properties to **already existing** tokens.
2386pub struct ExistingTokenPropertyWriter;
2387
2388/// The type-safe interface for writing properties (setting or deleting) to tokens.
2389/// It has two distinct implementations for newly created tokens and existing ones.
2390///
2391/// This type utilizes the lazy evaluation to avoid repeating the computation
2392/// of several performance-heavy or PoV-heavy tasks,
2393/// such as checking the indirect ownership or reading the token property permissions.
2394pub struct PropertyWriter<
2395 'a,
2396 T,
2397 Handle,
2398 WriterVariant,
2399 FIsAdmin,
2400 FPropertyPermissions,
2401 FCheckTokenExist,
2402 FGetProperties,
2403> where
2404 T: Config,
2405 FIsAdmin: FnOnce() -> bool,
2406 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,
2407{
2408 collection: &'a Handle,
2409 is_collection_admin: LazyValue<bool, FIsAdmin>,
2410 property_permissions: LazyValue<PropertiesPermissionMap, FPropertyPermissions>,
2411 check_token_exist: FCheckTokenExist,
2412 get_properties: FGetProperties,
2413 _phantom: PhantomData<(T, WriterVariant)>,
2414}
2415
2416impl<'a, T, Handle, FIsAdmin, FPropertyPermissions, FCheckTokenExist, FGetProperties>
2417 PropertyWriter<
2418 'a,
2419 T,
2420 Handle,
2421 NewTokenPropertyWriter,
2422 FIsAdmin,
2423 FPropertyPermissions,
2424 FCheckTokenExist,
2425 FGetProperties,
2426 > where
2427 T: Config,
2428 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2429 FIsAdmin: FnOnce() -> bool,
2430 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,
2431 FCheckTokenExist: Copy + FnOnce(TokenId) -> bool,
2432 FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties,
2433{
2434 /// A function to write properties to a **newly created** token.
2435 pub fn write_token_properties(
2436 &mut self,
2437 mint_target_is_sender: bool,
2438 token_id: TokenId,
2439 properties_updates: impl Iterator<Item = Property>,
2440 log: evm_coder::ethereum::Log,
2441 ) -> DispatchResult {
2442 self.internal_write_token_properties(
2443 token_id,
2444 properties_updates.map(|p| (p.key, Some(p.value))),
2445 |_| Ok(mint_target_is_sender),
2446 log,
2447 )
2448 }
2449}
2450
2451impl<'a, T, Handle, FIsAdmin, FPropertyPermissions, FCheckTokenExist, FGetProperties>
2452 PropertyWriter<
2453 'a,
2454 T,
2455 Handle,
2456 ExistingTokenPropertyWriter,
2457 FIsAdmin,
2458 FPropertyPermissions,
2459 FCheckTokenExist,
2460 FGetProperties,
2461 > where
2462 T: Config,
2463 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2464 FIsAdmin: FnOnce() -> bool,
2465 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,
2466 FCheckTokenExist: Copy + FnOnce(TokenId) -> bool,
2467 FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties,
2468{
2469 /// A function to write properties to an **already existing** token.
2470 pub fn write_token_properties(
2471 &mut self,
2472 sender: &T::CrossAccountId,
2473 token_id: TokenId,
2474 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
2475 nesting_budget: &dyn Budget,
2476 log: evm_coder::ethereum::Log,
2477 ) -> DispatchResult {
2478 self.internal_write_token_properties(
2479 token_id,
2480 properties_updates,
2481 |collection| collection.check_token_indirect_owner(token_id, sender, nesting_budget),
2482 log,
2483 )
2484 }
2485}
2486
2487impl<
2488 'a,
2489 T,
2490 Handle,
2491 WriterVariant,
2492 FIsAdmin,
2493 FPropertyPermissions,
2494 FCheckTokenExist,
2495 FGetProperties,
2496 >
2497 PropertyWriter<
2498 'a,
2499 T,
2500 Handle,
2501 WriterVariant,
2502 FIsAdmin,
2503 FPropertyPermissions,
2504 FCheckTokenExist,
2505 FGetProperties,
2506 > where
2507 T: Config,
2508 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2509 FIsAdmin: FnOnce() -> bool,
2510 FPropertyPermissions: FnOnce() -> PropertiesPermissionMap,
2511 FCheckTokenExist: Copy + FnOnce(TokenId) -> bool,
2512 FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties,
2513{
2514 fn internal_write_token_properties<FCheckTokenOwner>(
2515 &mut self,
2516 token_id: TokenId,
2517 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
2518 check_token_owner: FCheckTokenOwner,
2519 log: evm_coder::ethereum::Log,
2520 ) -> DispatchResult
2521 where
2522 FCheckTokenOwner: FnOnce(&Handle) -> Result<bool, DispatchError>,
2523 {
2524 let get_properties = self.get_properties;
2525 let mut stored_properties = LazyValue::new(move || get_properties(token_id));
2526
2527 let mut is_token_owner = LazyValue::new(|| check_token_owner(self.collection));
2528
2529 let check_token_exist = self.check_token_exist;
2530 let mut is_token_exist = LazyValue::new(move || check_token_exist(token_id));
2531
2532 for (key, value) in properties_updates {
2533 let permission = self
2534 .property_permissions
2535 .value()
2536 .get(&key)
2537 .cloned()
2538 .unwrap_or_else(PropertyPermission::none);
2539
2540 match permission {
2541 PropertyPermission { mutable: false, .. }
2542 if stored_properties.value().get(&key).is_some() =>
2543 {
2544 return Err(<Error<T>>::NoPermission.into());
2545 }
2546
2547 PropertyPermission {
2548 collection_admin,
2549 token_owner,
2550 ..
2551 } => check_token_permissions::<T, _, _, _>(
2552 collection_admin,
2553 token_owner,
2554 &mut self.is_collection_admin,
2555 &mut is_token_owner,
2556 &mut is_token_exist,
2557 )?,
2558 }
2559
2560 match value {
2561 Some(value) => {
2562 stored_properties
2563 .value_mut()
2564 .try_set(key.clone(), value)
2565 .map_err(<Error<T>>::from)?;
2566
2567 <Pallet<T>>::deposit_event(Event::TokenPropertySet(
2568 self.collection.id,
2569 token_id,
2570 key,
2571 ));
2572 }
2573 None => {
2574 stored_properties
2575 .value_mut()
2576 .remove(&key)
2577 .map_err(<Error<T>>::from)?;
2578
2579 <Pallet<T>>::deposit_event(Event::TokenPropertyDeleted(
2580 self.collection.id,
2581 token_id,
2582 key,
2583 ));
2584 }
2585 }
2586 }
2587
2588 let properties_changed = stored_properties.has_value();
2589 if properties_changed {
2590 <PalletEvm<T>>::deposit_log(log);
2591
2592 self.collection
2593 .set_token_properties_map(token_id, stored_properties.into_inner());
2594 }
2595
2596 Ok(())
2597 }
2598}
2599
2600/// Create a [`PropertyWriter`] for newly created tokens.
2601pub fn property_writer_for_new_token<'a, T, Handle>(
2602 collection: &'a Handle,
2603 sender: &'a T::CrossAccountId,
2604) -> PropertyWriter<
2605 'a,
2606 T,
2607 Handle,
2608 NewTokenPropertyWriter,
2609 impl FnOnce() -> bool + 'a,
2610 impl FnOnce() -> PropertiesPermissionMap + 'a,
2611 impl Copy + FnOnce(TokenId) -> bool + 'a,
2612 impl Copy + FnOnce(TokenId) -> TokenProperties + 'a,
2613>
2614where
2615 T: Config,
2616 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2617{
2618 PropertyWriter {
2619 collection,
2620 is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)),
2621 property_permissions: LazyValue::new(|| <Pallet<T>>::property_permissions(collection.id)),
2622 check_token_exist: |token_id| {
2623 debug_assert!(collection.token_exists(token_id));
2624 true
2625 },
2626 get_properties: |token_id| {
2627 debug_assert!(!collection.properties_exist(token_id));
2628 TokenProperties::new()
2629 },
2630 _phantom: PhantomData,
2631 }
2632}
2633
2634#[cfg(feature = "runtime-benchmarks")]
2635/// Create a `PropertyWriter` with preloaded `is_collection_admin` and `property_permissions.
2636/// Also:
2637/// * it will return `true` for the token ownership check.
2638/// * it will return empty stored properties without reading them from the storage.
2639pub fn collection_info_loaded_property_writer<T, Handle>(
2640 collection: &Handle,
2641 is_collection_admin: bool,
2642 property_permissions: PropertiesPermissionMap,
2643) -> PropertyWriter<
2644 T,
2645 Handle,
2646 NewTokenPropertyWriter,
2647 impl FnOnce() -> bool,
2648 impl FnOnce() -> PropertiesPermissionMap,
2649 impl Copy + FnOnce(TokenId) -> bool,
2650 impl Copy + FnOnce(TokenId) -> TokenProperties,
2651>
2652where
2653 T: Config,
2654 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2655{
2656 PropertyWriter {
2657 collection,
2658 is_collection_admin: LazyValue::new(move || is_collection_admin),
2659 property_permissions: LazyValue::new(move || property_permissions),
2660 check_token_exist: |_token_id| true,
2661 get_properties: |_token_id| TokenProperties::new(),
2662 _phantom: PhantomData,
2663 }
2664}
2665
2666/// Create a [`PropertyWriter`] for already existing tokens.
2667pub fn property_writer_for_existing_token<'a, T, Handle>(
2668 collection: &'a Handle,
2669 sender: &'a T::CrossAccountId,
2670) -> PropertyWriter<
2671 'a,
2672 T,
2673 Handle,
2674 ExistingTokenPropertyWriter,
2675 impl FnOnce() -> bool + 'a,
2676 impl FnOnce() -> PropertiesPermissionMap + 'a,
2677 impl Copy + FnOnce(TokenId) -> bool + 'a,
2678 impl Copy + FnOnce(TokenId) -> TokenProperties + 'a,
2679>
2680where
2681 T: Config,
2682 Handle: CommonCollectionOperations<T> + Deref<Target = CollectionHandle<T>>,
2683{
2684 PropertyWriter {
2685 collection,
2686 is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)),
2687 property_permissions: LazyValue::new(|| <Pallet<T>>::property_permissions(collection.id)),
2688 check_token_exist: |token_id| collection.token_exists(token_id),
2689 get_properties: |token_id| collection.get_token_properties_map(token_id),
2690 _phantom: PhantomData,
2691 }
2692}
2693
2694/// Computes the weight delta for newly created tokens with properties.
2695/// * `properties_nums` - The properties num of each created token.
2696/// * `init_token_properties` - The function to obtain the weight from a token's properties num.
2697pub fn init_token_properties_delta<T: Config, I: Fn(u32) -> Weight>(
2698 properties_nums: impl Iterator<Item = u32>,
2699 init_token_properties: I,
2700) -> Weight {
2701 let mut delta = properties_nums
2702 .filter_map(|properties_num| {
2703 if properties_num > 0 {
2704 Some(init_token_properties(properties_num))
2705 } else {
2706 None
2707 }
2708 })
2709 .fold(Weight::zero(), |a, b| a.saturating_add(b));
2710
2711 // If at least once the `init_token_properties` was called,
2712 // it means at least one newly created token has properties.
2713 // Becuase of that, some common collection data also was loaded and we need to add this weight.
2714 // However, these common data was loaded only once which is guaranteed by the `PropertyWriter`.
2715 if !delta.is_zero() {
2716 delta = delta.saturating_add(<SelfWeightOf<T>>::init_token_properties_common())
2717 }
2718
2719 delta
2720}
24222721
2423#[cfg(any(feature = "tests", test))]2722#[cfg(any(feature = "tests", test))]
2424#[allow(missing_docs)]2723#[allow(missing_docs)]
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
25 weights::WeightInfo as _, SelfWeightOf as PalletCommonWeightOf,25 weights::WeightInfo as _, SelfWeightOf as PalletCommonWeightOf,
26};26};
27use pallet_structure::Error as StructureError;27use pallet_structure::Error as StructureError;
28use sp_runtime::ArithmeticError;28use sp_runtime::{ArithmeticError, DispatchError};
29use sp_std::{vec::Vec, vec};29use sp_std::{vec::Vec, vec};
30use up_data_structs::{Property, PropertyKey, PropertyValue, PropertyKeyPermission};30use up_data_structs::{Property, PropertyKey, PropertyValue, PropertyKeyPermission};
3131
364 fail!(<Error<T>>::SettingPropertiesNotAllowed)364 fail!(<Error<T>>::SettingPropertiesNotAllowed)
365 }365 }
366
367 fn get_token_properties_map(&self, _token_id: TokenId) -> up_data_structs::TokenProperties {
368 // No token properties are defined on fungibles
369 up_data_structs::TokenProperties::new()
370 }
371
372 fn set_token_properties_map(&self, _token_id: TokenId, _map: up_data_structs::TokenProperties) {
373 // No token properties are defined on fungibles
374 }
375
376 fn properties_exist(&self, _token: TokenId) -> bool {
377 // No token properties are defined on fungibles
378 false
379 }
366380
367 fn check_nesting(381 fn check_nesting(
368 &self,382 &self,
402 Err(TokenOwnerError::MultipleOwners)416 Err(TokenOwnerError::MultipleOwners)
403 }417 }
418
419 fn check_token_indirect_owner(
420 &self,
421 _token: TokenId,
422 _maybe_owner: &T::CrossAccountId,
423 _nesting_budget: &dyn Budget,
424 ) -> Result<bool, DispatchError> {
425 Ok(false)
426 }
404427
405 /// Returns 10 tokens owners in no particular order.428 /// Returns 10 tokens owners in no particular order.
406 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {429 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
modifiedpallets/nonfungible/src/benchmarking.rsdiffbeforeafterboth
21use pallet_common::{21use pallet_common::{
22 bench_init,22 bench_init,
23 benchmarking::{create_collection_raw, property_key, property_value},23 benchmarking::{
24 create_collection_raw, property_key, property_value, load_is_admin_and_property_permissions,
25 },
24 CommonCollectionOperations,26 CommonCollectionOperations,
25};27};
198 value: property_value(),200 value: property_value(),
199 }).collect::<Vec<_>>();201 }).collect::<Vec<_>>();
200 let item = create_max_item(&collection, &owner, owner.clone())?;202 let item = create_max_item(&collection, &owner, owner.clone())?;
201 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::ExistingToken, &Unlimited)?}203 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?}
202204
203 reset_token_properties {205 init_token_properties {
204 let b in 0..MAX_PROPERTIES_PER_ITEM;206 let b in 0..MAX_PROPERTIES_PER_ITEM;
205 bench_init!{207 bench_init!{
206 owner: sub; collection: collection(owner);208 owner: sub; collection: collection(owner);
221 }).collect::<Vec<_>>();224 }).collect::<Vec<_>>();
222 let item = create_max_item(&collection, &owner, owner.clone())?;225 let item = create_max_item(&collection, &owner, owner.clone())?;
226
227 let (is_collection_admin, property_permissions) = load_is_admin_and_property_permissions(&collection, &owner);
223 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::NewToken { mint_target_is_sender: true }, &Unlimited)?}228 }: {
229 let mut property_writer = pallet_common::collection_info_loaded_property_writer(
230 &collection,
231 is_collection_admin,
232 property_permissions,
233 );
234
235 property_writer.write_token_properties(
236 true,
237 item,
238 props.into_iter(),
239 crate::erc::ERC721TokenEvent::TokenChanged {
240 token_id: item.into(),
241 }
242 .to_log(T::ContractAddress::get()),
243 )?
244 }
224245
225 delete_token_properties {246 delete_token_properties {
242 value: property_value(),263 value: property_value(),
243 }).collect::<Vec<_>>();264 }).collect::<Vec<_>>();
244 let item = create_max_item(&collection, &owner, owner.clone())?;265 let item = create_max_item(&collection, &owner, owner.clone())?;
245 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::ExistingToken, &Unlimited)?;266 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?;
246 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();267 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
247 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}268 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}
248269
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
23};23};
24use pallet_common::{24use pallet_common::{
25 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,25 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
26 weights::WeightInfo as _, SelfWeightOf as PalletCommonWeightOf,26 weights::WeightInfo as _, SelfWeightOf as PalletCommonWeightOf, init_token_properties_delta,
27};27};
28use pallet_structure::Pallet as PalletStructure;
28use sp_runtime::DispatchError;29use sp_runtime::DispatchError;
29use sp_std::{vec::Vec, vec};30use sp_std::{vec::Vec, vec};
3031
31use crate::{32use crate::{
32 AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,33 AccountBalance, Allowance, Config, CreateItemData, Error, NonfungibleHandle, Owned, Pallet,
33 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted,34 SelfWeightOf, TokenData, weights::WeightInfo, TokensMinted, TokenProperties,
34};35};
3536
36pub struct CommonWeights<T: Config>(PhantomData<T>);37pub struct CommonWeights<T: Config>(PhantomData<T>);
37impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {38impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
38 fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {39 fn create_multiple_items_ex(data: &CreateItemExData<T::CrossAccountId>) -> Weight {
39 match data {40 match data {
40 CreateItemExData::NFT(t) => {41 CreateItemExData::NFT(t) => <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)
41 <SelfWeightOf<T>>::create_multiple_items_ex(t.len() as u32)42 .saturating_add(init_token_properties_delta::<T, _>(
42 + t.iter()43 t.iter().map(|t| t.properties.len() as u32),
43 .filter_map(|t| {
44 if t.properties.len() > 0 {
45 Some(<SelfWeightOf<T>>::reset_token_properties(
46 t.properties.len() as u32,
47 ))
48 } else {
49 None
50 }
51 })
52 .fold(Weight::zero(), |a, b| a.saturating_add(b))44 <SelfWeightOf<T>>::init_token_properties,
53 }45 )),
54 _ => Weight::zero(),46 _ => Weight::zero(),
55 }47 }
56 }48 }
5749
58 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {50 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
59 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32)51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
52 init_token_properties_delta::<T, _>(
60 + data53 data.iter().map(|t| match t {
61 .iter()
62 .filter_map(|t| match t {
63 up_data_structs::CreateItemData::NFT(n) if n.properties.len() > 0 => Some(54 up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32,
64 <SelfWeightOf<T>>::reset_token_properties(n.properties.len() as u32),
65 ),
66 _ => None,55 _ => 0,
67 })56 }),
68 .fold(Weight::zero(), |a, b| a.saturating_add(b))57 <SelfWeightOf<T>>::init_token_properties,
58 ),
59 )
69 }60 }
7061
71 fn burn_item() -> Weight {62 fn burn_item() -> Weight {
247 &sender,238 &sender,
248 token_id,239 token_id,
249 properties.into_iter(),240 properties.into_iter(),
250 pallet_common::SetPropertyMode::ExistingToken,
251 nesting_budget,241 nesting_budget,
252 ),242 ),
253 weight,243 weight,
275 )265 )
276 }266 }
267
268 fn get_token_properties_map(&self, token_id: TokenId) -> up_data_structs::TokenProperties {
269 <TokenProperties<T>>::get((self.id, token_id))
270 }
271
272 fn set_token_properties_map(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {
273 <TokenProperties<T>>::set((self.id, token_id), map)
274 }
277275
278 fn set_token_property_permissions(276 fn set_token_property_permissions(
279 &self,277 &self,
289 )287 )
290 }288 }
289
290 fn properties_exist(&self, token: TokenId) -> bool {
291 <TokenProperties<T>>::contains_key((self.id, token))
292 }
291293
292 fn burn_item(294 fn burn_item(
293 &self,295 &self,
459 .ok_or(TokenOwnerError::NotFound)461 .ok_or(TokenOwnerError::NotFound)
460 }462 }
463
464 fn check_token_indirect_owner(
465 &self,
466 token: TokenId,
467 maybe_owner: &T::CrossAccountId,
468 nesting_budget: &dyn Budget,
469 ) -> Result<bool, DispatchError> {
470 <PalletStructure<T>>::check_indirectly_owned(
471 maybe_owner.clone(),
472 self.id,
473 token,
474 None,
475 nesting_budget,
476 )
477 }
461478
462 /// Returns token owners.479 /// Returns token owners.
463 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {480 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
203 &caller,203 &caller,
204 TokenId(token_id),204 TokenId(token_id),
205 properties.into_iter(),205 properties.into_iter(),
206 pallet_common::SetPropertyMode::ExistingToken,
207 &nesting_budget,206 &nesting_budget,
208 )207 )
209 .map_err(dispatch_to_evm::<T>)208 .map_err(dispatch_to_evm::<T>)
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
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, SelfWeightOf as PalletCommonWeightOf,111 eth::collection_id_to_address, SelfWeightOf as PalletCommonWeightOf,
112 weights::WeightInfo as CommonWeightInfo, helpers::add_weight_to_post_info, SetPropertyMode,112 weights::WeightInfo as CommonWeightInfo, helpers::add_weight_to_post_info,
113};113};
114use pallet_structure::{Pallet as PalletStructure, Error as StructureError};114use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
115use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};115use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};
598 sender: &T::CrossAccountId,598 sender: &T::CrossAccountId,
599 token_id: TokenId,599 token_id: TokenId,
600 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,600 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
601 mode: SetPropertyMode,
602 nesting_budget: &dyn Budget,601 nesting_budget: &dyn Budget,
603 ) -> DispatchResult {602 ) -> DispatchResult {
604 let mut is_token_owner = pallet_common::LazyValue::new(|| {603 let mut property_writer =
605 if let SetPropertyMode::NewToken {
606 mint_target_is_sender,
607 } = mode
608 {
609 return Ok(mint_target_is_sender);
610 }
611
612 let is_owned = <PalletStructure<T>>::check_indirectly_owned(
613 sender.clone(),
614 collection.id,604 pallet_common::property_writer_for_existing_token(collection, sender);
615 token_id,
616 None,
617 nesting_budget,
618 )?;
619
620 Ok(is_owned)
621 });
622
623 let is_new_token = matches!(mode, SetPropertyMode::NewToken { .. });
624
625 let mut is_token_exist = pallet_common::LazyValue::new(|| {
626 if is_new_token {
627 debug_assert!(Self::token_exists(collection, token_id));
628 true
629 } else {
630 Self::token_exists(collection, token_id)
631 }
632 });
633
634 let stored_properties = if is_new_token {
635 debug_assert!(!<TokenProperties<T>>::contains_key((
636 collection.id,
637 token_id
638 )));
639 TokenPropertiesT::new()
640 } else {
641 <TokenProperties<T>>::get((collection.id, token_id))
642 };
643605
644 <PalletCommon<T>>::modify_token_properties(606 property_writer.write_token_properties(
645 collection,
646 sender,607 sender,
647 token_id,608 token_id,
648 &mut is_token_exist,
649 properties_updates,609 properties_updates,
650 stored_properties,610 nesting_budget,
651 &mut is_token_owner,
652 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
653 erc::ERC721TokenEvent::TokenChanged {611 erc::ERC721TokenEvent::TokenChanged {
654 token_id: token_id.into(),612 token_id: token_id.into(),
655 }613 }
680 sender: &T::CrossAccountId,638 sender: &T::CrossAccountId,
681 token_id: TokenId,639 token_id: TokenId,
682 properties: impl Iterator<Item = Property>,640 properties: impl Iterator<Item = Property>,
683 mode: SetPropertyMode,
684 nesting_budget: &dyn Budget,641 nesting_budget: &dyn Budget,
685 ) -> DispatchResult {642 ) -> DispatchResult {
686 Self::modify_token_properties(643 Self::modify_token_properties(
687 collection,644 collection,
688 sender,645 sender,
689 token_id,646 token_id,
690 properties.map(|p| (p.key, Some(p.value))),647 properties.map(|p| (p.key, Some(p.value))),
691 mode,
692 nesting_budget,648 nesting_budget,
693 )649 )
694 }650 }
710 sender,666 sender,
711 token_id,667 token_id,
712 [property].into_iter(),668 [property].into_iter(),
713 SetPropertyMode::ExistingToken,
714 nesting_budget,669 nesting_budget,
715 )670 )
716 }671 }
732 sender,687 sender,
733 token_id,688 token_id,
734 property_keys.into_iter().map(|key| (key, None)),689 property_keys.into_iter().map(|key| (key, None)),
735 SetPropertyMode::ExistingToken,
736 nesting_budget,690 nesting_budget,
737 )691 )
738 }692 }
994948
995 // =========949 // =========
950
951 let mut property_writer = pallet_common::property_writer_for_new_token(collection, sender);
996952
997 with_transaction(|| {953 with_transaction(|| {
998 for (i, data) in data.iter().enumerate() {954 for (i, data) in data.iter().enumerate() {
1006 },962 },
1007 );963 );
964
965 let token = TokenId(token);
1008966
1009 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(967 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(
1010 &data.owner,968 &data.owner,
1011 collection.id,969 collection.id,
1012 TokenId(token),970 token,
1013 );971 );
1014972
1015 if let Err(e) = Self::set_token_properties(973 if let Err(e) = property_writer.write_token_properties(
1016 collection,
1017 sender,974 sender.conv_eq(&data.owner),
1018 TokenId(token),975 token,
1019 data.properties.clone().into_iter(),976 data.properties.clone().into_iter(),
1020 SetPropertyMode::NewToken {977 erc::ERC721TokenEvent::TokenChanged {
1021 mint_target_is_sender: sender.conv_eq(&data.owner),978 token_id: token.into(),
1022 },979 }
1023 nesting_budget,980 .to_log(T::ContractAddress::get()),
1024 ) {981 ) {
1025 return TransactionOutcome::Rollback(Err(e));982 return TransactionOutcome::Rollback(Err(e));
1026 }983 }
modifiedpallets/refungible/src/benchmarking.rsdiffbeforeafterboth
23use pallet_common::{23use pallet_common::{
24 bench_init,24 bench_init,
25 benchmarking::{create_collection_raw, property_key, property_value},25 benchmarking::{
26 create_collection_raw, property_key, property_value, load_is_admin_and_property_permissions,
27 },
26};28};
27use sp_std::prelude::*;29use sp_std::prelude::*;
255 value: property_value(),257 value: property_value(),
256 }).collect::<Vec<_>>();258 }).collect::<Vec<_>>();
257 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;259 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
258 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::ExistingToken, &Unlimited)?}260 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?}
259261
260 reset_token_properties {262 init_token_properties {
261 let b in 0..MAX_PROPERTIES_PER_ITEM;263 let b in 0..MAX_PROPERTIES_PER_ITEM;
262 bench_init!{264 bench_init!{
263 owner: sub; collection: collection(owner);265 owner: sub; collection: collection(owner);
278 }).collect::<Vec<_>>();281 }).collect::<Vec<_>>();
279 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;282 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
283
284 let (is_collection_admin, property_permissions) = load_is_admin_and_property_permissions(&collection, &owner);
280 }: {<Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::NewToken { mint_target_is_sender: true }, &Unlimited)?}285 }: {
286 let mut property_writer = pallet_common::collection_info_loaded_property_writer(
287 &collection,
288 is_collection_admin,
289 property_permissions,
290 );
291
292 property_writer.write_token_properties(
293 true,
294 item,
295 props.into_iter(),
296 crate::erc::ERC721TokenEvent::TokenChanged {
297 token_id: item.into(),
298 }
299 .to_log(T::ContractAddress::get()),
300 )?
301 }
281302
282 delete_token_properties {303 delete_token_properties {
299 value: property_value(),320 value: property_value(),
300 }).collect::<Vec<_>>();321 }).collect::<Vec<_>>();
301 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;322 let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?;
302 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), SetPropertyMode::ExistingToken, &Unlimited)?;323 <Pallet<T>>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?;
303 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();324 let to_delete = (0..b).map(|k| property_key(k as usize)).collect::<Vec<_>>();
304 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}325 }: {<Pallet<T>>::delete_token_properties(&collection, &owner, item, to_delete.into_iter(), &Unlimited)?}
305326
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};20use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, traits::Get};
21use up_data_structs::{21use up_data_structs::{
22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,22 CollectionId, TokenId, CreateItemExData, budget::Budget, Property, PropertyKey, PropertyValue,
23 PropertyKeyPermission, CollectionPropertiesVec, CreateRefungibleExMultipleOwners,23 PropertyKeyPermission, CreateRefungibleExMultipleOwners, CreateRefungibleExSingleOwner,
24 CreateRefungibleExSingleOwner, TokenOwnerError,24 TokenOwnerError,
25};25};
26use pallet_common::{26use pallet_common::{
27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,27 CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, with_weight,
28 weights::WeightInfo as _,28 weights::WeightInfo as _, init_token_properties_delta,
29};29};
30use pallet_structure::Error as StructureError;30use pallet_structure::{Pallet as PalletStructure, Error as StructureError};
31use sp_runtime::{DispatchError};31use sp_runtime::{DispatchError};
32use sp_std::{vec::Vec, vec};32use sp_std::{vec::Vec, vec};
3333
34use crate::{34use crate::{
35 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,35 AccountBalance, Allowance, Balance, Config, Error, Owned, Pallet, RefungibleHandle,
36 SelfWeightOf, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData,36 SelfWeightOf, weights::WeightInfo, TokensMinted, TotalSupply, CreateItemData, TokenProperties,
37};37};
3838
39macro_rules! max_weight_of {39macro_rules! max_weight_of {
45 };45 };
46}46}
47
48fn properties_weight<T: Config>(properties: &CollectionPropertiesVec) -> Weight {
49 if properties.len() > 0 {
50 <SelfWeightOf<T>>::reset_token_properties(properties.len() as u32)
51 } else {
52 Weight::zero()
53 }
54}
5547
56pub struct CommonWeights<T: Config>(PhantomData<T>);48pub struct CommonWeights<T: Config>(PhantomData<T>);
57impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {49impl<T: Config> CommonWeightInfo<T::CrossAccountId> for CommonWeights<T> {
58 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {50 fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight {
59 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(51 <SelfWeightOf<T>>::create_multiple_items(data.len() as u32).saturating_add(
52 init_token_properties_delta::<T, _>(
60 data.iter()53 data.iter().map(|data| match data {
61 .map(|data| match data {
62 up_data_structs::CreateItemData::ReFungible(rft_data) => {54 up_data_structs::CreateItemData::ReFungible(rft_data) => {
63 properties_weight::<T>(&rft_data.properties)55 rft_data.properties.len() as u32
64 }56 }
65 _ => Weight::zero(),57 _ => 0,
66 })58 }),
67 .fold(Weight::zero(), |a, b| a.saturating_add(b)),59 <SelfWeightOf<T>>::init_token_properties,
60 ),
68 )61 )
69 }62 }
7063
71 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {64 fn create_multiple_items_ex(call: &CreateItemExData<T::CrossAccountId>) -> Weight {
72 match call {65 match call {
73 CreateItemExData::RefungibleMultipleOwners(i) => {66 CreateItemExData::RefungibleMultipleOwners(i) => {
74 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)67 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_owners(i.users.len() as u32)
75 .saturating_add(properties_weight::<T>(&i.properties))68 .saturating_add(init_token_properties_delta::<T, _>(
69 [i.properties.len() as u32].into_iter(),
70 <SelfWeightOf<T>>::init_token_properties,
71 ))
76 }72 }
77 CreateItemExData::RefungibleMultipleItems(i) => {73 CreateItemExData::RefungibleMultipleItems(i) => {
78 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)74 <SelfWeightOf<T>>::create_multiple_items_ex_multiple_items(i.len() as u32)
79 .saturating_add(75 .saturating_add(init_token_properties_delta::<T, _>(
80 i.iter()76 i.iter().map(|d| d.properties.len() as u32),
81 .map(|d| properties_weight::<T>(&d.properties))
82 .fold(Weight::zero(), |a, b| a.saturating_add(b)),77 <SelfWeightOf<T>>::init_token_properties,
83 )78 ))
84 }79 }
85 _ => Weight::zero(),80 _ => Weight::zero(),
86 }81 }
399 &sender,394 &sender,
400 token_id,395 token_id,
401 properties.into_iter(),396 properties.into_iter(),
402 pallet_common::SetPropertyMode::ExistingToken,
403 nesting_budget,397 nesting_budget,
404 ),398 ),
405 weight,399 weight,
441 )435 )
442 }436 }
437
438 fn get_token_properties_map(&self, token_id: TokenId) -> up_data_structs::TokenProperties {
439 <TokenProperties<T>>::get((self.id, token_id))
440 }
441
442 fn set_token_properties_map(&self, token_id: TokenId, map: up_data_structs::TokenProperties) {
443 <TokenProperties<T>>::set((self.id, token_id), map)
444 }
445
446 fn properties_exist(&self, token: TokenId) -> bool {
447 <TokenProperties<T>>::contains_key((self.id, token))
448 }
443449
444 fn check_nesting(450 fn check_nesting(
445 &self,451 &self,
479 <Pallet<T>>::token_owner(self.id, token)485 <Pallet<T>>::token_owner(self.id, token)
480 }486 }
487
488 fn check_token_indirect_owner(
489 &self,
490 token: TokenId,
491 maybe_owner: &T::CrossAccountId,
492 nesting_budget: &dyn Budget,
493 ) -> Result<bool, DispatchError> {
494 let balance = self.balance(maybe_owner.clone(), token);
495 let total_pieces: u128 = <Pallet<T>>::total_pieces(self.id, token).unwrap_or(u128::MAX);
496 if balance != total_pieces {
497 return Ok(false);
498 }
499
500 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(
501 maybe_owner.clone(),
502 self.id,
503 token,
504 None,
505 nesting_budget,
506 )?;
507
508 Ok(is_bundle_owner)
509 }
481510
482 /// Returns 10 token in no particular order.511 /// Returns 10 token in no particular order.
483 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {512 fn token_owners(&self, token: TokenId) -> Vec<T::CrossAccountId> {
modifiedpallets/refungible/src/erc.rsdiffbeforeafterboth
214 &caller,214 &caller,
215 TokenId(token_id),215 TokenId(token_id),
216 properties.into_iter(),216 properties.into_iter(),
217 pallet_common::SetPropertyMode::ExistingToken,
218 &nesting_budget,217 &nesting_budget,
219 )218 )
220 .map_err(dispatch_to_evm::<T>)219 .map_err(dispatch_to_evm::<T>)
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
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 Error as CommonError, eth::collection_id_to_address, Event as CommonEvent,
100 Event as CommonEvent, Pallet as PalletCommon, SetPropertyMode,100 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::{Get, H160};
533 sender: &T::CrossAccountId,533 sender: &T::CrossAccountId,
534 token_id: TokenId,534 token_id: TokenId,
535 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,535 properties_updates: impl Iterator<Item = (PropertyKey, Option<PropertyValue>)>,
536 mode: SetPropertyMode,
537 nesting_budget: &dyn Budget,536 nesting_budget: &dyn Budget,
538 ) -> DispatchResult {537 ) -> DispatchResult {
539 let mut is_token_owner =538 let mut property_writer =
540 pallet_common::LazyValue::new(|| -> Result<bool, DispatchError> {539 pallet_common::property_writer_for_existing_token(collection, sender);
541 if let SetPropertyMode::NewToken {
542 mint_target_is_sender,
543 } = mode
544 {
545 return Ok(mint_target_is_sender);
546 }
547
548 let balance = collection.balance(sender.clone(), token_id);
549 let total_pieces: u128 =
550 Self::total_pieces(collection.id, token_id).unwrap_or(u128::MAX);
551 if balance != total_pieces {
552 return Ok(false);
553 }
554
555 let is_bundle_owner = <PalletStructure<T>>::check_indirectly_owned(
556 sender.clone(),
557 collection.id,
558 token_id,
559 None,
560 nesting_budget,
561 )?;
562
563 Ok(is_bundle_owner)
564 });
565
566 let is_new_token = matches!(mode, SetPropertyMode::NewToken { .. });
567
568 let mut is_token_exist = pallet_common::LazyValue::new(|| {
569 if is_new_token {
570 debug_assert!(Self::token_exists(collection, token_id));
571 true
572 } else {
573 Self::token_exists(collection, token_id)
574 }
575 });
576
577 let stored_properties = if is_new_token {
578 debug_assert!(!<TokenProperties<T>>::contains_key((
579 collection.id,
580 token_id
581 )));
582 TokenPropertiesT::new()
583 } else {
584 <TokenProperties<T>>::get((collection.id, token_id))
585 };
586540
587 <PalletCommon<T>>::modify_token_properties(541 property_writer.write_token_properties(
588 collection,
589 sender,542 sender,
590 token_id,543 token_id,
591 &mut is_token_exist,
592 properties_updates,544 properties_updates,
593 stored_properties,545 nesting_budget,
594 &mut is_token_owner,
595 |properties| <TokenProperties<T>>::set((collection.id, token_id), properties),
596 erc::ERC721TokenEvent::TokenChanged {546 erc::ERC721TokenEvent::TokenChanged {
597 token_id: token_id.into(),547 token_id: token_id.into(),
598 }548 }
618 sender: &T::CrossAccountId,568 sender: &T::CrossAccountId,
619 token_id: TokenId,569 token_id: TokenId,
620 properties: impl Iterator<Item = Property>,570 properties: impl Iterator<Item = Property>,
621 mode: SetPropertyMode,
622 nesting_budget: &dyn Budget,571 nesting_budget: &dyn Budget,
623 ) -> DispatchResult {572 ) -> DispatchResult {
624 Self::modify_token_properties(573 Self::modify_token_properties(
625 collection,574 collection,
626 sender,575 sender,
627 token_id,576 token_id,
628 properties.map(|p| (p.key, Some(p.value))),577 properties.map(|p| (p.key, Some(p.value))),
629 mode,
630 nesting_budget,578 nesting_budget,
631 )579 )
632 }580 }
643 sender,591 sender,
644 token_id,592 token_id,
645 [property].into_iter(),593 [property].into_iter(),
646 SetPropertyMode::ExistingToken,
647 nesting_budget,594 nesting_budget,
648 )595 )
649 }596 }
660 sender,607 sender,
661 token_id,608 token_id,
662 property_keys.into_iter().map(|key| (key, None)),609 property_keys.into_iter().map(|key| (key, None)),
663 SetPropertyMode::ExistingToken,
664 nesting_budget,610 nesting_budget,
665 )611 )
666 }612 }
941887
942 // =========888 // =========
889
890 let mut property_writer = pallet_common::property_writer_for_new_token(collection, sender);
943891
944 with_transaction(|| {892 with_transaction(|| {
945 for (i, data) in data.iter().enumerate() {893 for (i, data) in data.iter().enumerate() {
946 let token_id = first_token_id + i as u32 + 1;894 let token_id = first_token_id + i as u32 + 1;
947 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);895 <TotalSupply<T>>::insert((collection.id, token_id), totals[i]);
896
897 let token = TokenId(token_id);
948898
949 let mut mint_target_is_sender = true;899 let mut mint_target_is_sender = true;
950 for (user, amount) in data.users.iter() {900 for (user, amount) in data.users.iter() {
955 mint_target_is_sender = mint_target_is_sender && sender.conv_eq(user);905 mint_target_is_sender = mint_target_is_sender && sender.conv_eq(user);
956906
957 <Balance<T>>::insert((collection.id, token_id, &user), amount);907 <Balance<T>>::insert((collection.id, token_id, &user), amount);
958 <Owned<T>>::insert((collection.id, &user, TokenId(token_id)), true);908 <Owned<T>>::insert((collection.id, &user, token), true);
959 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(909 <PalletStructure<T>>::nest_if_sent_to_token_unchecked(
960 user,910 user,
961 collection.id,911 collection.id,
962 TokenId(token_id),912 token,
963 );913 );
964 }914 }
965915
966 if let Err(e) = Self::set_token_properties(916 if let Err(e) = property_writer.write_token_properties(
967 collection,917 mint_target_is_sender,
968 sender,918 token,
969 TokenId(token_id),
970 data.properties.clone().into_iter(),919 data.properties.clone().into_iter(),
971 SetPropertyMode::NewToken {920 erc::ERC721TokenEvent::TokenChanged {
972 mint_target_is_sender,921 token_id: token.into(),
973 },922 }
974 nesting_budget,923 .to_log(T::ContractAddress::get()),
975 ) {924 ) {
976 return TransactionOutcome::Rollback(Err(e));925 return TransactionOutcome::Rollback(Err(e));
977 }926 }