123456#![recursion_limit = "1024"]7#![cfg_attr(not(feature = "std"), no_std)]8#![allow(9 clippy::too_many_arguments,10 clippy::unnecessary_mut_passed,11 clippy::unused_unit12)]1314extern crate alloc;1516pub use serde::{Serialize, Deserialize};1718pub use frame_support::{19 construct_runtime, decl_module, decl_storage, decl_error,20 dispatch::DispatchResult,21 ensure, fail, parameter_types,22 traits::{23 ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced, Randomness,24 IsSubType, WithdrawReasons,25 },26 weights::{27 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},28 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,29 WeightToFeePolynomial, DispatchClass,30 },31 StorageValue, transactional,32 pallet_prelude::DispatchResultWithPostInfo,33};34use scale_info::TypeInfo;35use frame_system::{self as system, ensure_signed};36use sp_runtime::{sp_std::prelude::Vec};37use up_data_structs::{38 MAX_DECIMAL_POINTS, MAX_SPONSOR_TIMEOUT, MAX_TOKEN_OWNERSHIP, CUSTOM_DATA_LIMIT,39 VARIABLE_ON_CHAIN_SCHEMA_LIMIT, CONST_ON_CHAIN_SCHEMA_LIMIT, OFFCHAIN_SCHEMA_LIMIT,40 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,41 NFT_SPONSOR_TRANSFER_TIMEOUT, AccessMode, Collection, CreateItemData, CollectionLimits,42 CollectionId, CollectionMode, TokenId, SchemaVersion, SponsorshipState, MetaUpdatePermission,43};44use pallet_common::{45 account::CrossAccountId, CollectionHandle, Pallet as PalletCommon, Error as CommonError,46 CommonWeightInfo,47};48use pallet_refungible::{Pallet as PalletRefungible, RefungibleHandle};49use pallet_fungible::{Pallet as PalletFungible, FungibleHandle};50use pallet_nonfungible::{Pallet as PalletNonfungible, NonfungibleHandle};5152#[cfg(test)]53mod mock;5455#[cfg(test)]56mod tests;5758mod eth;59mod sponsorship;60pub use sponsorship::UniqueSponsorshipHandler;61pub use eth::sponsoring::UniqueEthSponsorshipHandler;6263pub use eth::UniqueErcSupport;6465pub mod common;66use common::CommonWeights;67pub mod dispatch;68use dispatch::dispatch_call;6970#[cfg(feature = "runtime-benchmarks")]71mod benchmarking;72pub mod weights;73use weights::WeightInfo;7475decl_error! {76 77 pub enum Error for Module<T: Config> {78 79 CollectionDecimalPointLimitExceeded,80 81 ConfirmUnsetSponsorFail,82 83 EmptyArgument,84 85 CollectionLimitBoundsExceeded,86 87 OwnerPermissionsCantBeReverted,88 }89}90pub trait Config:91 system::Config92 + pallet_evm_coder_substrate::Config93 + pallet_common::Config94 + pallet_nonfungible::Config95 + pallet_refungible::Config96 + pallet_fungible::Config97 + Sized98 + TypeInfo99{100 101 type WeightInfo: WeightInfo;102}103104type SelfWeightOf<T> = <T as Config>::WeightInfo;105106107108109110111112113114115116117118119120121122123124125126127128decl_storage! {129 trait Store for Module<T: Config> as Unique {130131 132 133 ChainVersion: u64;134 135136 137 138 139 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;140 141 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;142 143 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;144 145 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;146 147148 149 150 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;151 152 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;153 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;154 pub RefungibleApproveBasket get(fn refungible_approve_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;155 }156}157158decl_module! {159 pub struct Module<T: Config> for enum Call160 where161 origin: T::Origin162 {163 type Error = Error<T>;164165 fn on_initialize(_now: T::BlockNumber) -> Weight {166 0167 }168169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 #[weight = <SelfWeightOf<T>>::create_collection()]186 #[transactional]187 pub fn create_collection(origin,188 collection_name: Vec<u16>,189 collection_description: Vec<u16>,190 token_prefix: Vec<u8>,191 mode: CollectionMode) -> DispatchResult {192193 194 let who = ensure_signed(origin)?;195196 197 let new_collection = Collection {198 owner: who.clone(),199 name: collection_name,200 mode: mode.clone(),201 mint_mode: false,202 access: AccessMode::Normal,203 description: collection_description,204 token_prefix,205 offchain_schema: Vec::new(),206 schema_version: SchemaVersion::ImageURL,207 sponsorship: SponsorshipState::Disabled,208 variable_on_chain_schema: Vec::new(),209 const_on_chain_schema: Vec::new(),210 limits: Default::default(),211 meta_update_permission: Default::default(),212 };213214 let _id = match mode {215 CollectionMode::NFT => {<PalletNonfungible<T>>::init_collection(new_collection)?},216 CollectionMode::Fungible(decimal_points) => {217 218 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);219 <PalletFungible<T>>::init_collection(new_collection)?220 }221 CollectionMode::ReFungible => {222 <PalletRefungible<T>>::init_collection(new_collection)?223 }224 };225226 Ok(())227 }228229 230 231 232 233 234 235 236 237 238 #[weight = <SelfWeightOf<T>>::destroy_collection()]239 #[transactional]240 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {241 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);242243 let collection = <CollectionHandle<T>>::try_get(collection_id)?;244 collection.check_is_owner(&sender)?;245246 247248 match collection.mode {249 CollectionMode::ReFungible => PalletRefungible::destroy_collection(RefungibleHandle::cast(collection), &sender)?,250 CollectionMode::Fungible(_) => PalletFungible::destroy_collection(FungibleHandle::cast(collection), &sender)?,251 CollectionMode::NFT => PalletNonfungible::destroy_collection(NonfungibleHandle::cast(collection), &sender)?,252 }253254 <NftTransferBasket<T>>::remove_prefix(collection_id, None);255 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);256 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);257258 <VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);259 <NftApproveBasket<T>>::remove_prefix(collection_id, None);260 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);261 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);262263 Ok(())264 }265266 267 268 269 270 271 272 273 274 275 276 277 278 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]279 #[transactional]280 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{281282 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);283 let collection = <CollectionHandle<T>>::try_get(collection_id)?;284285 <PalletCommon<T>>::toggle_allowlist(286 &collection,287 &sender,288 &address,289 true,290 )?;291292 Ok(())293 }294295 296 297 298 299 300 301 302 303 304 305 306 307 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]308 #[transactional]309 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{310311 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);312 let collection = <CollectionHandle<T>>::try_get(collection_id)?;313314 <PalletCommon<T>>::toggle_allowlist(315 &collection,316 &sender,317 &address,318 false,319 )?;320321 Ok(())322 }323324 325 326 327 328 329 330 331 332 333 334 335 #[weight = <SelfWeightOf<T>>::set_public_access_mode()]336 #[transactional]337 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult338 {339 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);340341 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;342 target_collection.check_is_owner(&sender)?;343344 target_collection.access = mode;345 target_collection.save()346 }347348 349 350 351 352 353 354 355 356 357 358 359 360 361 #[weight = <SelfWeightOf<T>>::set_mint_permission()]362 #[transactional]363 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult364 {365 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);366367 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;368 target_collection.check_is_owner(&sender)?;369370 target_collection.mint_mode = mint_permission;371 target_collection.save()372 }373374 375 376 377 378 379 380 381 382 383 384 385 #[weight = <SelfWeightOf<T>>::change_collection_owner()]386 #[transactional]387 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {388389 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);390391 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;392 target_collection.check_is_owner(&sender)?;393394 target_collection.owner = new_owner;395 target_collection.save()396 }397398 399 400 401 402 403 404 405 406 407 408 409 410 411 #[weight = <SelfWeightOf<T>>::add_collection_admin()]412 #[transactional]413 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {414 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);415 let collection = <CollectionHandle<T>>::try_get(collection_id)?;416417 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)418 }419420 421 422 423 424 425 426 427 428 429 430 431 432 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]433 #[transactional]434 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {435 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);436 let collection = <CollectionHandle<T>>::try_get(collection_id)?;437438 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)439 }440441 442 443 444 445 446 447 448 449 450 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]451 #[transactional]452 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {453 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);454455 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;456 target_collection.check_is_owner(&sender)?;457458 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);459 target_collection.save()460 }461462 463 464 465 466 467 468 469 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]470 #[transactional]471 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {472 let sender = ensure_signed(origin)?;473474 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;475 ensure!(476 target_collection.sponsorship.pending_sponsor() == Some(&sender),477 Error::<T>::ConfirmUnsetSponsorFail478 );479480 target_collection.sponsorship = SponsorshipState::Confirmed(sender);481 target_collection.save()482 }483484 485 486 487 488 489 490 491 492 493 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]494 #[transactional]495 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {496 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);497498 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;499 target_collection.check_is_owner(&sender)?;500501 target_collection.sponsorship = SponsorshipState::Disabled;502 target_collection.save()503 }504505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 #[weight = <CommonWeights<T>>::create_item()]524 #[transactional]525 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {526 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);527528 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data))529 }530531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 #[weight = <CommonWeights<T>>::create_multiple_items(items_data.len() as u32)]550 #[transactional]551 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {552 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);553 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);554555 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data))556 }557558 559560 561 562 563 564 565 566 567 568 569 570 571 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]572 #[transactional]573 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {574 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);575 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;576 target_collection.check_is_owner(&sender)?;577578 579580 target_collection.limits.transfers_enabled = Some(value);581 target_collection.save()582 }583584 585 586 587 588 589 590 591 592 593 594 595 596 597 #[weight = <CommonWeights<T>>::burn_item()]598 #[transactional]599 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {600 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);601602 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;603 if value == 1 {604 <NftTransferBasket<T>>::remove(collection_id, item_id);605 <NftApproveBasket<T>>::remove(collection_id, item_id);606 }607 608 609 610 Ok(post_info)611 }612613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 #[weight = <CommonWeights<T>>::burn_from()]630 #[transactional]631 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {632 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);633634 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))635 }636637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 #[weight = <CommonWeights<T>>::transfer()]661 #[transactional]662 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {663 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);664665 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value))666 }667668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 #[weight = <CommonWeights<T>>::approve()]684 #[transactional]685 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {686 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);687688 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))689 }690691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 #[weight = <CommonWeights<T>>::transfer_from()]711 #[transactional]712 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {713 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);714715 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value))716 }717718 719 720 721 722 723 724 725 726 727 728 729 730 #[weight = <CommonWeights<T>>::set_variable_metadata(data.len() as u32)]731 #[transactional]732 pub fn set_variable_meta_data (733 origin,734 collection_id: CollectionId,735 item_id: TokenId,736 data: Vec<u8>737 ) -> DispatchResultWithPostInfo {738 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);739740 dispatch_call::<T, _>(collection_id, |d| d.set_variable_metadata(sender, item_id, data))741 }742743 744 745 746 747 748 749 750 751 752 753 754 #[weight = <SelfWeightOf<T>>::set_meta_update_permission_flag()]755 #[transactional]756 pub fn set_meta_update_permission_flag(origin, collection_id: CollectionId, value: MetaUpdatePermission) -> DispatchResult {757 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);758 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;759760 ensure!(761 target_collection.meta_update_permission != MetaUpdatePermission::None,762 <CommonError<T>>::MetadataFlagFrozen,763 );764 target_collection.check_is_owner(&sender)?;765766 target_collection.meta_update_permission = value;767768 target_collection.save()769 }770771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 #[weight = <SelfWeightOf<T>>::set_schema_version()]786 #[transactional]787 pub fn set_schema_version(788 origin,789 collection_id: CollectionId,790 version: SchemaVersion791 ) -> DispatchResult {792 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);793 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;794 target_collection.check_is_owner_or_admin(&sender)?;795 target_collection.schema_version = version;796 target_collection.save()797 }798799 800 801 802 803 804 805 806 807 808 809 810 811 #[weight = <SelfWeightOf<T>>::set_offchain_schema(schema.len() as u32)]812 #[transactional]813 pub fn set_offchain_schema(814 origin,815 collection_id: CollectionId,816 schema: Vec<u8>817 ) -> DispatchResult {818 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);819 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;820 target_collection.check_is_owner_or_admin(&sender)?;821822 823 ensure!(schema.len() as u32 <= OFFCHAIN_SCHEMA_LIMIT, "");824825 target_collection.offchain_schema = schema;826 target_collection.save()827 }828829 830 831 832 833 834 835 836 837 838 839 840 841 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]842 #[transactional]843 pub fn set_const_on_chain_schema (844 origin,845 collection_id: CollectionId,846 schema: Vec<u8>847 ) -> DispatchResult {848 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);849 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;850 target_collection.check_is_owner_or_admin(&sender)?;851852 853 ensure!(schema.len() as u32 <= CONST_ON_CHAIN_SCHEMA_LIMIT, "");854855 target_collection.const_on_chain_schema = schema;856 target_collection.save()857 }858859 860 861 862 863 864 865 866 867 868 869 870 871 #[weight = <SelfWeightOf<T>>::set_const_on_chain_schema(schema.len() as u32)]872 #[transactional]873 pub fn set_variable_on_chain_schema (874 origin,875 collection_id: CollectionId,876 schema: Vec<u8>877 ) -> DispatchResult {878 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);879 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;880 target_collection.check_is_owner_or_admin(&sender)?;881882 883 ensure!(schema.len() as u32 <= VARIABLE_ON_CHAIN_SCHEMA_LIMIT, "");884885 target_collection.variable_on_chain_schema = schema;886 target_collection.save()887 }888889 #[weight = <SelfWeightOf<T>>::set_collection_limits()]890 #[transactional]891 pub fn set_collection_limits(892 origin,893 collection_id: CollectionId,894 new_limit: CollectionLimits,895 ) -> DispatchResult {896 let mut new_limit = new_limit;897 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);898 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;899 target_collection.check_is_owner(&sender)?;900 let old_limit = &target_collection.limits;901902 macro_rules! limit_default {903 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{904 $(905 if let Some($new) = $new.$field {906 let $old = $old.$field($($arg)?);907 let _ = $new;908 let _ = $old;909 $check910 } else {911 $new.$field = $old.$field912 }913 )*914 }};915 }916917 limit_default!(old_limit, new_limit,918 account_token_ownership_limit => ensure!(919 new_limit <= MAX_TOKEN_OWNERSHIP,920 <Error<T>>::CollectionLimitBoundsExceeded,921 ),922 sponsor_transfer_timeout(match target_collection.mode {923 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,924 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,925 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,926 }) => ensure!(927 new_limit <= MAX_SPONSOR_TIMEOUT,928 <Error<T>>::CollectionLimitBoundsExceeded,929 ),930 sponsored_data_size => ensure!(931 new_limit <= CUSTOM_DATA_LIMIT,932 <Error<T>>::CollectionLimitBoundsExceeded,933 ),934 token_limit => ensure!(935 old_limit >= new_limit && new_limit > 0,936 <CommonError<T>>::CollectionTokenLimitExceeded937 ),938 owner_can_transfer => ensure!(939 old_limit || !new_limit,940 <Error<T>>::OwnerPermissionsCantBeReverted,941 ),942 owner_can_destroy => ensure!(943 old_limit || !new_limit,944 <Error<T>>::OwnerPermissionsCantBeReverted,945 ),946 sponsored_data_rate_limit => {},947 transfers_enabled => {},948 );949950 target_collection.limits = new_limit;951952 target_collection.save()953 }954 }955}