123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566#![recursion_limit = "1024"]67#![cfg_attr(not(feature = "std"), no_std)]68#![allow(69 clippy::too_many_arguments,70 clippy::unnecessary_mut_passed,71 clippy::unused_unit72)]7374extern crate alloc;7576use frame_support::pallet_prelude::*;77use frame_system::pallet_prelude::*;78pub use pallet::*;79pub mod eth;8081#[cfg(feature = "runtime-benchmarks")]82pub mod benchmarking;83pub mod weights;8485#[frame_support::pallet]86pub mod pallet {87 use frame_support::{88 dispatch::{DispatchErrorWithPostInfo, DispatchResult, PostDispatchInfo},89 ensure, fail,90 storage::Key,91 BoundedVec,92 };93 use frame_system::{ensure_root, ensure_signed};94 use pallet_common::{95 dispatch::{dispatch_tx, CollectionDispatch},96 CollectionHandle, CommonCollectionOperations, CommonWeightInfo, Pallet as PalletCommon,97 RefungibleExtensionsWeightInfo,98 };99 use pallet_evm::account::CrossAccountId;100 use pallet_structure::weights::WeightInfo as StructureWeightInfo;101 use scale_info::TypeInfo;102 use sp_std::{vec, vec::Vec};103 use up_data_structs::{104 budget, CollectionId, CollectionLimits, CollectionMode, CollectionPermissions,105 CreateCollectionData, CreateItemData, CreateItemExData, Property, PropertyKey,106 PropertyKeyPermission, TokenId, COLLECTION_ADMINS_LIMIT, MAX_COLLECTION_DESCRIPTION_LENGTH,107 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_PROPERTIES_SIZE, MAX_PROPERTIES_PER_ITEM,108 MAX_PROPERTY_KEY_LENGTH, MAX_PROPERTY_VALUE_LENGTH, MAX_TOKEN_PREFIX_LENGTH,109 MAX_TOKEN_PROPERTIES_SIZE,110 };111 use weights::WeightInfo;112113 use super::*;114115 116 #[pallet::error]117 pub enum Error<T> {118 119 CollectionDecimalPointLimitExceeded,120 121 EmptyArgument,122 123 RepartitionCalledOnNonRefungibleCollection,124 }125126 127 #[pallet::config]128 pub trait Config: frame_system::Config + pallet_common::Config + Sized + TypeInfo {129 130 type WeightInfo: WeightInfo;131132 133 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;134135 type StructureWeightInfo: StructureWeightInfo;136137 138 type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo;139 }140141 #[pallet::pallet]142 pub struct Pallet<T>(_);143144 pub type SelfWeightOf<T> = <T as Config>::WeightInfo;145146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168169 170 171 #[pallet::storage]172 pub type ChainVersion<T> = StorageValue<_, u64, ValueQuery>;173 174175 176 177 178 #[pallet::storage]179 #[pallet::getter(fn create_item_busket)]180 pub type CreateItemBasket<T: Config> = StorageMap<181 Hasher = Blake2_128Concat,182 Key = (CollectionId, T::AccountId),183 Value = BlockNumberFor<T>,184 QueryKind = OptionQuery,185 >;186 187 #[pallet::storage]188 #[pallet::getter(fn nft_transfer_basket)]189 pub type NftTransferBasket<T: Config> = StorageDoubleMap<190 Hasher1 = Blake2_128Concat,191 Key1 = CollectionId,192 Hasher2 = Blake2_128Concat,193 Key2 = TokenId,194 Value = BlockNumberFor<T>,195 QueryKind = OptionQuery,196 >;197 198 #[pallet::storage]199 #[pallet::getter(fn fungible_transfer_basket)]200 pub type FungibleTransferBasket<T: Config> = StorageDoubleMap<201 Hasher1 = Blake2_128Concat,202 Key1 = CollectionId,203 Hasher2 = Twox64Concat,204 Key2 = T::AccountId,205 Value = BlockNumberFor<T>,206 QueryKind = OptionQuery,207 >;208 209 #[pallet::storage]210 #[pallet::getter(fn refungible_transfer_basket)]211 pub type ReFungibleTransferBasket<T: Config> = StorageNMap<212 Key = (213 Key<Blake2_128Concat, CollectionId>,214 Key<Blake2_128Concat, TokenId>,215 Key<Twox64Concat, T::AccountId>,216 ),217 Value = BlockNumberFor<T>,218 QueryKind = OptionQuery,219 >;220 221222 223 #[pallet::storage]224 #[pallet::getter(fn token_property_basket)]225 pub type TokenPropertyBasket<T: Config> = StorageDoubleMap<226 Hasher1 = Blake2_128Concat,227 Key1 = CollectionId,228 Hasher2 = Blake2_128Concat,229 Key2 = TokenId,230 Value = BlockNumberFor<T>,231 QueryKind = OptionQuery,232 >;233234 235 #[pallet::storage]236 #[pallet::getter(fn nft_approve_basket)]237 pub type NftApproveBasket<T: Config> = StorageDoubleMap<238 Hasher1 = Blake2_128Concat,239 Key1 = CollectionId,240 Hasher2 = Blake2_128Concat,241 Key2 = TokenId,242 Value = BlockNumberFor<T>,243 QueryKind = OptionQuery,244 >;245 246 #[pallet::storage]247 #[pallet::getter(fn fungible_approve_basket)]248 pub type FungibleApproveBasket<T: Config> = StorageDoubleMap<249 Hasher1 = Blake2_128Concat,250 Key1 = CollectionId,251 Hasher2 = Twox64Concat,252 Key2 = T::AccountId,253 Value = BlockNumberFor<T>,254 QueryKind = OptionQuery,255 >;256 257 #[pallet::storage]258 #[pallet::getter(fn refungible_approve_basket)]259 pub type RefungibleApproveBasket<T: Config> = StorageNMap<260 Key = (261 Key<Blake2_128Concat, CollectionId>,262 Key<Blake2_128Concat, TokenId>,263 Key<Twox64Concat, T::AccountId>,264 ),265 Value = BlockNumberFor<T>,266 QueryKind = OptionQuery,267 >;268269 #[pallet::extra_constants]270 impl<T: Config> Pallet<T> {271 272 fn nesting_budget() -> u32 {273 5274 }275276 277 fn max_collection_name_length() -> u32 {278 MAX_COLLECTION_NAME_LENGTH279 }280281 282 fn max_collection_description_length() -> u32 {283 MAX_COLLECTION_DESCRIPTION_LENGTH284 }285286 287 fn max_token_prefix_length() -> u32 {288 MAX_TOKEN_PREFIX_LENGTH289 }290291 292 fn collection_admins_limit() -> u32 {293 COLLECTION_ADMINS_LIMIT294 }295296 297 fn max_property_key_length() -> u32 {298 MAX_PROPERTY_KEY_LENGTH299 }300301 302 fn max_property_value_length() -> u32 {303 MAX_PROPERTY_VALUE_LENGTH304 }305306 307 fn max_properties_per_item() -> u32 {308 MAX_PROPERTIES_PER_ITEM309 }310311 312 fn max_collection_properties_size() -> u32 {313 MAX_COLLECTION_PROPERTIES_SIZE314 }315316 317 fn max_token_properties_size() -> u32 {318 MAX_TOKEN_PROPERTIES_SIZE319 }320321 322 fn nft_default_collection_limits() -> CollectionLimits {323 CollectionLimits::with_default_limits(CollectionMode::NFT)324 }325326 327 fn rft_default_collection_limits() -> CollectionLimits {328 CollectionLimits::with_default_limits(CollectionMode::ReFungible)329 }330331 332 fn ft_default_collection_limits() -> CollectionLimits {333 CollectionLimits::with_default_limits(CollectionMode::Fungible(0))334 }335 }336337 338 #[pallet::call]339 impl<T: Config> Pallet<T> {340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 #[pallet::call_index(0)]366 #[pallet::weight(<SelfWeightOf<T>>::create_collection())]367 pub fn create_collection(368 origin: OriginFor<T>,369 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,370 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,371 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,372 mode: CollectionMode,373 ) -> DispatchResult {374 let data: CreateCollectionData<T::CrossAccountId> = CreateCollectionData {375 name: collection_name,376 description: collection_description,377 token_prefix,378 mode,379 ..Default::default()380 };381 Self::create_collection_ex(origin, data)382 }383384 385 386 387 388 389 390 391 392 393 394 395 #[pallet::call_index(1)]396 #[pallet::weight(<SelfWeightOf<T>>::create_collection())]397 pub fn create_collection_ex(398 origin: OriginFor<T>,399 data: CreateCollectionData<T::CrossAccountId>,400 ) -> DispatchResult {401 let sender = ensure_signed(origin)?;402403 404 let sender = T::CrossAccountId::from_sub(sender);405 let _id = T::CollectionDispatch::create(sender.clone(), sender, data)?;406407 Ok(())408 }409410 411 412 413 414 415 416 417 418 419 #[pallet::call_index(2)]420 #[pallet::weight(<SelfWeightOf<T>>::destroy_collection())]421 pub fn destroy_collection(422 origin: OriginFor<T>,423 collection_id: CollectionId,424 ) -> DispatchResult {425 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);426427 Self::destroy_collection_internal(sender, collection_id)428 }429430 431 432 433 434 435 436 437 438 439 440 441 #[pallet::call_index(3)]442 #[pallet::weight(<SelfWeightOf<T>>::add_to_allow_list())]443 pub fn add_to_allow_list(444 origin: OriginFor<T>,445 collection_id: CollectionId,446 address: T::CrossAccountId,447 ) -> DispatchResult {448 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {449 fail!(<pallet_common::Error<T>>::UnsupportedOperation);450 }451452 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);453 let collection = <CollectionHandle<T>>::try_get(collection_id)?;454 collection.check_is_internal()?;455456 <PalletCommon<T>>::toggle_allowlist(&collection, &sender, &address, true)?;457458 Ok(())459 }460461 462 463 464 465 466 467 468 469 470 471 472 #[pallet::call_index(4)]473 #[pallet::weight(<SelfWeightOf<T>>::remove_from_allow_list())]474 pub fn remove_from_allow_list(475 origin: OriginFor<T>,476 collection_id: CollectionId,477 address: T::CrossAccountId,478 ) -> DispatchResult {479 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {480 fail!(<pallet_common::Error<T>>::UnsupportedOperation);481 }482483 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);484 let collection = <CollectionHandle<T>>::try_get(collection_id)?;485 collection.check_is_internal()?;486487 <PalletCommon<T>>::toggle_allowlist(&collection, &sender, &address, false)?;488489 Ok(())490 }491492 493 494 495 496 497 498 499 500 501 502 #[pallet::call_index(5)]503 #[pallet::weight(<SelfWeightOf<T>>::change_collection_owner())]504 pub fn change_collection_owner(505 origin: OriginFor<T>,506 collection_id: CollectionId,507 new_owner: T::AccountId,508 ) -> DispatchResult {509 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {510 fail!(<pallet_common::Error<T>>::UnsupportedOperation);511 }512 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);513 let new_owner = T::CrossAccountId::from_sub(new_owner);514 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;515 target_collection.change_owner(sender, new_owner)516 }517518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 #[pallet::call_index(6)]535 #[pallet::weight(<SelfWeightOf<T>>::add_collection_admin())]536 pub fn add_collection_admin(537 origin: OriginFor<T>,538 collection_id: CollectionId,539 new_admin_id: T::CrossAccountId,540 ) -> DispatchResult {541 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {542 fail!(<pallet_common::Error<T>>::UnsupportedOperation);543 }544 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);545 let collection = <CollectionHandle<T>>::try_get(collection_id)?;546 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)547 }548549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 #[pallet::call_index(7)]564 #[pallet::weight(<SelfWeightOf<T>>::remove_collection_admin())]565 pub fn remove_collection_admin(566 origin: OriginFor<T>,567 collection_id: CollectionId,568 account_id: T::CrossAccountId,569 ) -> DispatchResult {570 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {571 fail!(<pallet_common::Error<T>>::UnsupportedOperation);572 }573 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);574 let collection = <CollectionHandle<T>>::try_get(collection_id)?;575 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)576 }577578 579 580 581 582 583 584 585 586 587 588 589 590 591 #[pallet::call_index(8)]592 #[pallet::weight(<SelfWeightOf<T>>::set_collection_sponsor())]593 pub fn set_collection_sponsor(594 origin: OriginFor<T>,595 collection_id: CollectionId,596 new_sponsor: T::AccountId,597 ) -> DispatchResult {598 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {599 fail!(<pallet_common::Error<T>>::UnsupportedOperation);600 }601 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);602 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;603 target_collection.set_sponsor(&sender, new_sponsor.clone())604 }605606 607 608 609 610 611 612 613 614 615 616 617 618 619 #[pallet::call_index(9)]620 #[pallet::weight(<SelfWeightOf<T>>::confirm_sponsorship())]621 pub fn confirm_sponsorship(622 origin: OriginFor<T>,623 collection_id: CollectionId,624 ) -> DispatchResult {625 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {626 fail!(<pallet_common::Error<T>>::UnsupportedOperation);627 }628 let sender = ensure_signed(origin)?;629 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;630 target_collection.confirm_sponsorship(&sender)631 }632633 634 635 636 637 638 639 640 641 642 #[pallet::call_index(10)]643 #[pallet::weight(<SelfWeightOf<T>>::remove_collection_sponsor())]644 pub fn remove_collection_sponsor(645 origin: OriginFor<T>,646 collection_id: CollectionId,647 ) -> DispatchResult {648 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {649 fail!(<pallet_common::Error<T>>::UnsupportedOperation);650 }651 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);652 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;653 target_collection.remove_sponsor(&sender)654 }655656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 #[pallet::call_index(11)]675 #[pallet::weight(T::CommonWeightInfo::create_item(data) + <Pallet<T>>::nesting_budget_predispatch_weight())]676 pub fn create_item(677 origin: OriginFor<T>,678 collection_id: CollectionId,679 owner: T::CrossAccountId,680 data: CreateItemData,681 ) -> DispatchResultWithPostInfo {682 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);683 let budget = Self::structure_nesting_budget();684685 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {686 d.create_item(sender, owner, data, &budget)687 })688 }689690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 #[pallet::call_index(12)]709 #[pallet::weight(T::CommonWeightInfo::create_multiple_items(items_data) + <Pallet<T>>::nesting_budget_predispatch_weight())]710 pub fn create_multiple_items(711 origin: OriginFor<T>,712 collection_id: CollectionId,713 owner: T::CrossAccountId,714 items_data: Vec<CreateItemData>,715 ) -> DispatchResultWithPostInfo {716 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);717 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);718 let budget = Self::structure_nesting_budget();719720 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {721 d.create_multiple_items(sender, owner, items_data, &budget)722 })723 }724725 726 727 728 729 730 731 732 733 734 735 736 737 #[pallet::call_index(13)]738 #[pallet::weight(T::CommonWeightInfo::set_collection_properties(properties.len() as u32))]739 pub fn set_collection_properties(740 origin: OriginFor<T>,741 collection_id: CollectionId,742 properties: Vec<Property>,743 ) -> DispatchResultWithPostInfo {744 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);745746 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);747748 dispatch_tx::<T, _>(collection_id, |d| {749 d.set_collection_properties(sender, properties)750 })751 }752753 754 755 756 757 758 759 760 761 762 763 764 765 #[pallet::call_index(14)]766 #[pallet::weight(T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32))]767 pub fn delete_collection_properties(768 origin: OriginFor<T>,769 collection_id: CollectionId,770 property_keys: Vec<PropertyKey>,771 ) -> DispatchResultWithPostInfo {772 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);773774 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);775776 dispatch_tx::<T, _>(collection_id, |d| {777 d.delete_collection_properties(&sender, property_keys)778 })779 }780781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 #[pallet::call_index(15)]800 #[pallet::weight(T::CommonWeightInfo::set_token_properties(properties.len() as u32) + <Pallet<T>>::nesting_budget_predispatch_weight())]801 pub fn set_token_properties(802 origin: OriginFor<T>,803 collection_id: CollectionId,804 token_id: TokenId,805 properties: Vec<Property>,806 ) -> DispatchResultWithPostInfo {807 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);808809 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);810 let budget = Self::structure_nesting_budget();811812 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {813 d.set_token_properties(sender, token_id, properties, &budget)814 })815 }816817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 #[pallet::call_index(16)]833 #[pallet::weight(T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32) + <Pallet<T>>::nesting_budget_predispatch_weight())]834 pub fn delete_token_properties(835 origin: OriginFor<T>,836 collection_id: CollectionId,837 token_id: TokenId,838 property_keys: Vec<PropertyKey>,839 ) -> DispatchResultWithPostInfo {840 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);841842 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);843 let budget = Self::structure_nesting_budget();844845 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {846 d.delete_token_properties(sender, token_id, property_keys, &budget)847 })848 }849850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 #[pallet::call_index(17)]866 #[pallet::weight(T::CommonWeightInfo::set_token_property_permissions(property_permissions.len() as u32))]867 pub fn set_token_property_permissions(868 origin: OriginFor<T>,869 collection_id: CollectionId,870 property_permissions: Vec<PropertyKeyPermission>,871 ) -> DispatchResultWithPostInfo {872 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);873874 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);875876 dispatch_tx::<T, _>(collection_id, |d| {877 d.set_token_property_permissions(&sender, property_permissions)878 })879 }880881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 #[pallet::call_index(18)]897 #[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(data) + <Pallet<T>>::nesting_budget_predispatch_weight())]898 pub fn create_multiple_items_ex(899 origin: OriginFor<T>,900 collection_id: CollectionId,901 data: CreateItemExData<T::CrossAccountId>,902 ) -> DispatchResultWithPostInfo {903 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);904 let budget = Self::structure_nesting_budget();905906 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {907 d.create_multiple_items_ex(sender, data, &budget)908 })909 }910911 912 913 914 915 916 917 918 919 920 921 #[pallet::call_index(19)]922 #[pallet::weight(<SelfWeightOf<T>>::set_transfers_enabled_flag())]923 pub fn set_transfers_enabled_flag(924 origin: OriginFor<T>,925 collection_id: CollectionId,926 value: bool,927 ) -> DispatchResult {928 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {929 fail!(<pallet_common::Error<T>>::UnsupportedOperation);930 }931 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);932 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;933 target_collection.check_is_internal()?;934 target_collection.check_is_owner(&sender)?;935936 937938 target_collection.limits.transfers_enabled = Some(value);939 target_collection.save()940 }941942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 #[pallet::call_index(20)]959 #[pallet::weight(T::CommonWeightInfo::burn_item())]960 pub fn burn_item(961 origin: OriginFor<T>,962 collection_id: CollectionId,963 item_id: TokenId,964 value: u128,965 ) -> DispatchResultWithPostInfo {966 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);967968 let post_info =969 dispatch_tx::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;970 if value == 1 {971 <NftTransferBasket<T>>::remove(collection_id, item_id);972 <NftApproveBasket<T>>::remove(collection_id, item_id);973 }974 975 976 977 Ok(post_info)978 }979980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 #[pallet::call_index(21)]1004 #[pallet::weight(T::CommonWeightInfo::burn_from() + <Pallet<T>>::nesting_budget_predispatch_weight())]1005 pub fn burn_from(1006 origin: OriginFor<T>,1007 collection_id: CollectionId,1008 from: T::CrossAccountId,1009 item_id: TokenId,1010 value: u128,1011 ) -> DispatchResultWithPostInfo {1012 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1013 let budget = Self::structure_nesting_budget();10141015 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {1016 d.burn_from(sender, from, item_id, value, &budget)1017 })1018 }10191020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 #[pallet::call_index(22)]1042 #[pallet::weight(T::CommonWeightInfo::transfer() + <Pallet<T>>::nesting_budget_predispatch_weight())]1043 pub fn transfer(1044 origin: OriginFor<T>,1045 recipient: T::CrossAccountId,1046 collection_id: CollectionId,1047 item_id: TokenId,1048 value: u128,1049 ) -> DispatchResultWithPostInfo {1050 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1051 let budget = Self::structure_nesting_budget();10521053 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {1054 d.transfer(sender, recipient, item_id, value, &budget)1055 })1056 }10571058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 #[pallet::call_index(23)]1074 #[pallet::weight(T::CommonWeightInfo::approve())]1075 pub fn approve(1076 origin: OriginFor<T>,1077 spender: T::CrossAccountId,1078 collection_id: CollectionId,1079 item_id: TokenId,1080 amount: u128,1081 ) -> DispatchResultWithPostInfo {1082 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);10831084 dispatch_tx::<T, _>(collection_id, |d| {1085 d.approve(sender, spender, item_id, amount)1086 })1087 }10881089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 #[pallet::call_index(24)]1106 #[pallet::weight(T::CommonWeightInfo::approve_from())]1107 pub fn approve_from(1108 origin: OriginFor<T>,1109 from: T::CrossAccountId,1110 to: T::CrossAccountId,1111 collection_id: CollectionId,1112 item_id: TokenId,1113 amount: u128,1114 ) -> DispatchResultWithPostInfo {1115 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);11161117 dispatch_tx::<T, _>(collection_id, |d| {1118 d.approve_from(sender, from, to, item_id, amount)1119 })1120 }11211122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 #[pallet::call_index(25)]1147 #[pallet::weight(T::CommonWeightInfo::transfer_from() + <Pallet<T>>::nesting_budget_predispatch_weight())]1148 pub fn transfer_from(1149 origin: OriginFor<T>,1150 from: T::CrossAccountId,1151 recipient: T::CrossAccountId,1152 collection_id: CollectionId,1153 item_id: TokenId,1154 value: u128,1155 ) -> DispatchResultWithPostInfo {1156 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1157 let budget = Self::structure_nesting_budget();11581159 Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| {1160 d.transfer_from(sender, from, recipient, item_id, value, &budget)1161 })1162 }11631164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 #[pallet::call_index(26)]1177 #[pallet::weight(<SelfWeightOf<T>>::set_collection_limits())]1178 pub fn set_collection_limits(1179 origin: OriginFor<T>,1180 collection_id: CollectionId,1181 new_limit: CollectionLimits,1182 ) -> DispatchResult {1183 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1184 fail!(<pallet_common::Error<T>>::UnsupportedOperation);1185 }1186 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1187 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1188 <PalletCommon<T>>::update_limits(&sender, &mut target_collection, new_limit)1189 }11901191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 #[pallet::call_index(27)]1204 #[pallet::weight(<SelfWeightOf<T>>::set_collection_limits())]1205 pub fn set_collection_permissions(1206 origin: OriginFor<T>,1207 collection_id: CollectionId,1208 new_permission: CollectionPermissions,1209 ) -> DispatchResult {1210 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1211 fail!(<pallet_common::Error<T>>::UnsupportedOperation);1212 }1213 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1214 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1215 <PalletCommon<T>>::update_permissions(&sender, &mut target_collection, new_permission)1216 }12171218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 #[pallet::call_index(28)]1230 #[pallet::weight(T::RefungibleExtensionsWeightInfo::repartition())]1231 pub fn repartition(1232 origin: OriginFor<T>,1233 collection_id: CollectionId,1234 token_id: TokenId,1235 amount: u128,1236 ) -> DispatchResultWithPostInfo {1237 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1238 dispatch_tx::<T, _>(collection_id, |d| {1239 if let Some(refungible_extensions) = d.refungible_extensions() {1240 refungible_extensions.repartition(&sender, token_id, amount)1241 } else {1242 fail!(<Error<T>>::RepartitionCalledOnNonRefungibleCollection)1243 }1244 })1245 }12461247 1248 1249 1250 1251 1252 1253 1254 1255 1256 #[pallet::call_index(29)]1257 #[pallet::weight(T::CommonWeightInfo::set_allowance_for_all())]1258 pub fn set_allowance_for_all(1259 origin: OriginFor<T>,1260 collection_id: CollectionId,1261 operator: T::CrossAccountId,1262 approve: bool,1263 ) -> DispatchResultWithPostInfo {1264 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1265 dispatch_tx::<T, _>(collection_id, |d| {1266 d.set_allowance_for_all(sender, operator, approve)1267 })1268 }12691270 1271 1272 1273 1274 1275 #[pallet::call_index(30)]1276 #[pallet::weight(<SelfWeightOf<T>>::force_repair_collection())]1277 pub fn force_repair_collection(1278 origin: OriginFor<T>,1279 collection_id: CollectionId,1280 ) -> DispatchResult {1281 if collection_id == pallet_common::NATIVE_FUNGIBLE_COLLECTION_ID {1282 fail!(<pallet_common::Error<T>>::UnsupportedOperation);1283 }1284 ensure_root(origin)?;1285 <PalletCommon<T>>::repair_collection(collection_id)1286 }12871288 1289 1290 1291 1292 1293 1294 #[pallet::call_index(31)]1295 #[pallet::weight(T::CommonWeightInfo::force_repair_item())]1296 pub fn force_repair_item(1297 origin: OriginFor<T>,1298 collection_id: CollectionId,1299 item_id: TokenId,1300 ) -> DispatchResultWithPostInfo {1301 ensure_root(origin)?;1302 dispatch_tx::<T, _>(collection_id, |d| d.repair_item(item_id))1303 }1304 }13051306 impl<T: Config> Pallet<T> {1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 pub fn force_set_sponsor(1317 sponsor: T::AccountId,1318 collection_id: CollectionId,1319 ) -> DispatchResult {1320 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1321 target_collection.force_set_sponsor(sponsor)1322 }13231324 1325 1326 1327 1328 1329 1330 1331 1332 pub fn force_remove_collection_sponsor(collection_id: CollectionId) -> DispatchResult {1333 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;1334 target_collection.force_remove_sponsor()1335 }13361337 #[inline(always)]1338 pub(crate) fn destroy_collection_internal(1339 sender: T::CrossAccountId,1340 collection_id: CollectionId,1341 ) -> DispatchResult {1342 T::CollectionDispatch::destroy(sender, collection_id)?;13431344 1345 13461347 let _ = <NftTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1348 let _ = <FungibleTransferBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1349 let _ = <ReFungibleTransferBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);13501351 let _ = <NftApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1352 let _ = <FungibleApproveBasket<T>>::clear_prefix(collection_id, u32::MAX, None);1353 let _ = <RefungibleApproveBasket<T>>::clear_prefix((collection_id,), u32::MAX, None);13541355 Ok(())1356 }13571358 fn structure_nesting_budget() -> budget::Value {1359 budget::Value::new(Self::nesting_budget())1360 }13611362 fn nesting_budget_weight(value: &budget::Value) -> Weight {1363 T::StructureWeightInfo::find_parent().saturating_mul(value.remaining() as u64)1364 }13651366 fn nesting_budget_predispatch_weight() -> Weight {1367 Self::nesting_budget_weight(&Self::structure_nesting_budget())1368 }13691370 pub fn dispatch_tx_with_nesting_budget<1371 C: FnOnce(&dyn CommonCollectionOperations<T>) -> DispatchResultWithPostInfo,1372 >(1373 collection: CollectionId,1374 budget: &budget::Value,1375 call: C,1376 ) -> DispatchResultWithPostInfo {1377 let mut result = dispatch_tx::<T, _>(collection, call);13781379 match &mut result {1380 Ok(PostDispatchInfo {1381 actual_weight: Some(weight),1382 ..1383 })1384 | Err(DispatchErrorWithPostInfo {1385 post_info: PostDispatchInfo {1386 actual_weight: Some(weight),1387 ..1388 },1389 ..1390 }) => *weight += Self::nesting_budget_weight(budget),1391 _ => {}1392 }13931394 result1395 }1396 }1397}