1234567891011121314151617#![recursion_limit = "1024"]18#![cfg_attr(not(feature = "std"), no_std)]19#![allow(20 clippy::too_many_arguments,21 clippy::unnecessary_mut_passed,22 clippy::unused_unit23)]2425extern crate alloc;2627use frame_support::{28 decl_module, decl_storage, decl_error, decl_event,29 dispatch::DispatchResult,30 ensure, fail,31 weights::{Weight},32 transactional,33 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},34 BoundedVec,35};36use scale_info::TypeInfo;37use frame_system::{self as system, ensure_signed};38use sp_runtime::{sp_std::prelude::Vec};39use up_data_structs::{40 MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,41 CreateItemData, CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId,42 SponsorshipState, CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,43 PropertyKeyPermission,44};45use pallet_evm::account::CrossAccountId;46use pallet_common::{47 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_tx,48 dispatch::CollectionDispatch, RefungibleExtensionsWeightInfo,49};50pub mod eth;5152#[cfg(feature = "runtime-benchmarks")]53mod benchmarking;54pub mod weights;55use weights::WeightInfo;5657const NESTING_BUDGET: u32 = 5;5859decl_error! {60 61 pub enum Error for Module<T: Config> {62 63 CollectionDecimalPointLimitExceeded,64 65 ConfirmUnsetSponsorFail,66 67 EmptyArgument,68 69 RepartitionCalledOnNonRefungibleCollection,70 }71}7273pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {74 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;7576 77 type WeightInfo: WeightInfo;78 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;79 type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo;80}8182decl_event! {83 pub enum Event<T>84 where85 <T as frame_system::Config>::AccountId,86 <T as pallet_evm::account::Config>::CrossAccountId,87 {88 89 90 91 92 93 CollectionSponsorRemoved(CollectionId),9495 96 97 98 99 100 101 102 CollectionAdminAdded(CollectionId, CrossAccountId),103104 105 106 107 108 109 110 111 CollectionOwnedChanged(CollectionId, AccountId),112113 114 115 116 117 118 119 120 CollectionSponsorSet(CollectionId, AccountId),121122 123 124 125 126 127 128 129 SponsorshipConfirmed(CollectionId, AccountId),130131 132 133 134 135 136 137 138 CollectionAdminRemoved(CollectionId, CrossAccountId),139140 141 142 143 144 145 146 147 AllowListAddressRemoved(CollectionId, CrossAccountId),148149 150 151 152 153 154 155 156 AllowListAddressAdded(CollectionId, CrossAccountId),157158 159 160 161 162 163 CollectionLimitSet(CollectionId),164165 166 167 168 169 170 CollectionPermissionSet(CollectionId),171 }172}173174type SelfWeightOf<T> = <T as Config>::WeightInfo;175176177178179180181182183184185186187188189190191192193194195196197198decl_storage! {199 trait Store for Module<T: Config> as Unique {200201 202 203 ChainVersion: u64;204 205206 207 208 209 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;210 211 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;212 213 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;214 215 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>;216 217218 219 220 #[deprecated]221 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;222 223 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;224225 226 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;227 228 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;229 230 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>;231 }232}233234decl_module! {235 pub struct Module<T: Config> for enum Call236 where237 origin: T::Origin238 {239 type Error = Error<T>;240241 fn deposit_event() = default;242243 fn on_initialize(_now: T::BlockNumber) -> Weight {244 0245 }246247 fn on_runtime_upgrade() -> Weight {248 let limit = None;249250 <VariableMetaDataBasket<T>>::remove_all(limit);251252 0253 }254255 256 257 258 259 260 261 262 263 264 265 266 267 268 #[weight = <SelfWeightOf<T>>::create_collection()]269 #[transactional]270 #[deprecated]271 pub fn create_collection(origin,272 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,273 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,274 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,275 mode: CollectionMode) -> DispatchResult {276 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {277 name: collection_name,278 description: collection_description,279 token_prefix,280 mode,281 ..Default::default()282 };283 Self::create_collection_ex(origin, data)284 }285286 287 288 289 290 291 292 293 294 295 296 #[weight = <SelfWeightOf<T>>::create_collection()]297 #[transactional]298 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {299 let sender = ensure_signed(origin)?;300301 302303 T::CollectionDispatch::create(T::CrossAccountId::from_sub(sender), data)?;304305 Ok(())306 }307308 309 310 311 312 313 314 315 316 317 #[weight = <SelfWeightOf<T>>::destroy_collection()]318 #[transactional]319 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {320 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);321 let collection = <CollectionHandle<T>>::try_get(collection_id)?;322 collection.check_is_internal()?;323324 325326 T::CollectionDispatch::destroy(sender, collection)?;327328 <NftTransferBasket<T>>::remove_prefix(collection_id, None);329 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);330 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);331332 <NftApproveBasket<T>>::remove_prefix(collection_id, None);333 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);334 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);335336 Ok(())337 }338339 340 341 342 343 344 345 346 347 348 349 350 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]351 #[transactional]352 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{353354 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);355 let collection = <CollectionHandle<T>>::try_get(collection_id)?;356 collection.check_is_internal()?;357358 <PalletCommon<T>>::toggle_allowlist(359 &collection,360 &sender,361 &address,362 true,363 )?;364365 Self::deposit_event(Event::<T>::AllowListAddressAdded(366 collection_id,367 address368 ));369370 Ok(())371 }372373 374 375 376 377 378 379 380 381 382 383 384 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]385 #[transactional]386 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{387388 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);389 let collection = <CollectionHandle<T>>::try_get(collection_id)?;390 collection.check_is_internal()?;391392 <PalletCommon<T>>::toggle_allowlist(393 &collection,394 &sender,395 &address,396 false,397 )?;398399 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(400 collection_id,401 address402 ));403404 Ok(())405 }406407 408 409 410 411 412 413 414 415 416 417 #[weight = <SelfWeightOf<T>>::change_collection_owner()]418 #[transactional]419 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {420421 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);422423 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;424 target_collection.check_is_internal()?;425 target_collection.check_is_owner(&sender)?;426427 target_collection.owner = new_owner.clone();428 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(429 collection_id,430 new_owner431 ));432433 target_collection.save()434 }435436 437 438 439 440 441 442 443 444 445 446 447 448 #[weight = <SelfWeightOf<T>>::add_collection_admin()]449 #[transactional]450 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin: T::CrossAccountId) -> DispatchResult {451 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);452 let collection = <CollectionHandle<T>>::try_get(collection_id)?;453 collection.check_is_internal()?;454455 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(456 collection_id,457 new_admin.clone()458 ));459460 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin, true)461 }462463 464 465 466 467 468 469 470 471 472 473 474 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]475 #[transactional]476 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {477 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);478 let collection = <CollectionHandle<T>>::try_get(collection_id)?;479 collection.check_is_internal()?;480481 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(482 collection_id,483 account_id.clone()484 ));485486 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)487 }488489 490 491 492 493 494 495 496 497 498 499 500 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]501 #[transactional]502 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {503 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);504505 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;506 target_collection.check_is_owner_or_admin(&sender)?;507 target_collection.check_is_internal()?;508509 target_collection.set_sponsor(new_sponsor.clone())?;510511 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(512 collection_id,513 new_sponsor514 ));515516 target_collection.save()517 }518519 520 521 522 523 524 525 526 527 528 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]529 #[transactional]530 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {531 let sender = ensure_signed(origin)?;532533 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;534 target_collection.check_is_internal()?;535 ensure!(536 target_collection.confirm_sponsorship(&sender)?,537 Error::<T>::ConfirmUnsetSponsorFail538 );539540 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(541 collection_id,542 sender543 ));544545 target_collection.save()546 }547548 549 550 551 552 553 554 555 556 557 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]558 #[transactional]559 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {560 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);561562 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;563 target_collection.check_is_internal()?;564 target_collection.check_is_owner(&sender)?;565566 target_collection.sponsorship = SponsorshipState::Disabled;567568 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(569 collection_id570 ));571 target_collection.save()572 }573574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 #[weight = T::CommonWeightInfo::create_item()]591 #[transactional]592 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {593 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);594 let budget = budget::Value::new(NESTING_BUDGET);595596 dispatch_tx::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))597 }598599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 #[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]616 #[transactional]617 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {618 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);619 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);620 let budget = budget::Value::new(NESTING_BUDGET);621622 dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))623 }624625 626 627 628 629 630 631 632 633 634 635 636 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]637 #[transactional]638 pub fn set_collection_properties(639 origin,640 collection_id: CollectionId,641 properties: Vec<Property>642 ) -> DispatchResultWithPostInfo {643 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);644645 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);646647 dispatch_tx::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))648 }649650 651 652 653 654 655 656 657 658 659 660 661 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]662 #[transactional]663 pub fn delete_collection_properties(664 origin,665 collection_id: CollectionId,666 property_keys: Vec<PropertyKey>,667 ) -> DispatchResultWithPostInfo {668 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);669670 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);671672 dispatch_tx::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))673 }674675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]690 #[transactional]691 pub fn set_token_properties(692 origin,693 collection_id: CollectionId,694 token_id: TokenId,695 properties: Vec<Property>696 ) -> DispatchResultWithPostInfo {697 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);698699 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);700 let budget = budget::Value::new(NESTING_BUDGET);701702 dispatch_tx::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties, &budget))703 }704705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]720 #[transactional]721 pub fn delete_token_properties(722 origin,723 collection_id: CollectionId,724 token_id: TokenId,725 property_keys: Vec<PropertyKey>726 ) -> DispatchResultWithPostInfo {727 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);728729 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);730 let budget = budget::Value::new(NESTING_BUDGET);731732 dispatch_tx::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys, &budget))733 }734735 736 737 738 739 740 741 742 743 744 745 746 #[weight = T::CommonWeightInfo::set_token_property_permissions(property_permissions.len() as u32)]747 #[transactional]748 pub fn set_token_property_permissions(749 origin,750 collection_id: CollectionId,751 property_permissions: Vec<PropertyKeyPermission>,752 ) -> DispatchResultWithPostInfo {753 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);754755 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);756757 dispatch_tx::<T, _>(collection_id, |d| d.set_token_property_permissions(&sender, property_permissions))758 }759760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]776 #[transactional]777 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {778 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);779 let budget = budget::Value::new(NESTING_BUDGET);780781 dispatch_tx::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))782 }783784 785 786 787 788 789 790 791 792 793 794 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]795 #[transactional]796 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {797 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);798 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;799 target_collection.check_is_internal()?;800 target_collection.check_is_owner(&sender)?;801802 803804 target_collection.limits.transfers_enabled = Some(value);805 target_collection.save()806 }807808 809 810 811 812 813 814 815 816 817 818 819 820 #[weight = T::CommonWeightInfo::burn_item()]821 #[transactional]822 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {823 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);824825 let post_info = dispatch_tx::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;826 if value == 1 {827 <NftTransferBasket<T>>::remove(collection_id, item_id);828 <NftApproveBasket<T>>::remove(collection_id, item_id);829 }830 831 832 833 Ok(post_info)834 }835836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 #[weight = T::CommonWeightInfo::burn_from()]851 #[transactional]852 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {853 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);854 let budget = budget::Value::new(NESTING_BUDGET);855856 dispatch_tx::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))857 }858859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 #[weight = T::CommonWeightInfo::transfer()]883 #[transactional]884 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {885 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);886 let budget = budget::Value::new(NESTING_BUDGET);887888 dispatch_tx::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))889 }890891 892 893 894 895 896 897 898 899 900 901 902 903 904 #[weight = T::CommonWeightInfo::approve()]905 #[transactional]906 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {907 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);908909 dispatch_tx::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))910 }911912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 #[weight = T::CommonWeightInfo::transfer_from()]929 #[transactional]930 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {931 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);932 let budget = budget::Value::new(NESTING_BUDGET);933934 dispatch_tx::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))935 }936937 938 939 940 941 942 943 944 945 946 947 948 #[weight = <SelfWeightOf<T>>::set_collection_limits()]949 #[transactional]950 pub fn set_collection_limits(951 origin,952 collection_id: CollectionId,953 new_limit: CollectionLimits,954 ) -> DispatchResult {955 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);956 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;957 target_collection.check_is_internal()?;958 target_collection.check_is_owner_or_admin(&sender)?;959 let old_limit = &target_collection.limits;960961 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;962963 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(964 collection_id965 ));966967 target_collection.save()968 }969970 971 972 973 974 975 976 977 978 979 980 981 #[weight = <SelfWeightOf<T>>::set_collection_limits()]982 #[transactional]983 pub fn set_collection_permissions(984 origin,985 collection_id: CollectionId,986 new_permission: CollectionPermissions,987 ) -> DispatchResult {988 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);989 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;990 target_collection.check_is_internal()?;991 target_collection.check_is_owner_or_admin(&sender)?;992 let old_limit = &target_collection.permissions;993994 target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_permission)?;995996 <Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(997 collection_id998 ));9991000 target_collection.save()1001 }10021003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 #[weight = T::RefungibleExtensionsWeightInfo::repartition()]1015 #[transactional]1016 pub fn repartition(1017 origin,1018 collection_id: CollectionId,1019 token_id: TokenId,1020 amount: u128,1021 ) -> DispatchResultWithPostInfo {1022 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);1023 dispatch_tx::<T, _>(collection_id, |d| {1024 if let Some(refungible_extensions) = d.refungible_extensions() {1025 refungible_extensions.repartition(&sender, token, amount)1026 } else {1027 fail!(<Error<T>>::RepartitionCalledOnNonRefungibleCollection)1028 }1029 })1030 }1031 }1032}