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)]2425use frame_support::{26 decl_module, decl_storage, decl_error, decl_event,27 dispatch::DispatchResult,28 ensure,29 weights::{Weight},30 transactional,31 pallet_prelude::{DispatchResultWithPostInfo, ConstU32},32 BoundedVec,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_COLLECTION_NAME_LENGTH,39 MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH, AccessMode, CreateItemData,40 CollectionLimits, CollectionPermissions, CollectionId, CollectionMode, TokenId, SponsorshipState,41 CreateCollectionData, CreateItemExData, budget, Property, PropertyKey,42 PropertyKeyPermission,43};44use pallet_evm::account::CrossAccountId;45use pallet_common::{46 CollectionHandle, Pallet as PalletCommon, CommonWeightInfo, dispatch::dispatch_call,47 dispatch::CollectionDispatch,48};49pub use eth::pallet_evm_collection;5051#[cfg(feature = "runtime-benchmarks")]52mod benchmarking;53pub mod weights;54use weights::WeightInfo;5556decl_error! {57 58 pub enum Error for Module<T: Config> {59 60 CollectionDecimalPointLimitExceeded,61 62 ConfirmUnsetSponsorFail,63 64 EmptyArgument,65 }66}6768pub trait Config: system::Config + pallet_common::Config + Sized + TypeInfo {69 type Event: From<Event<Self>> + Into<<Self as frame_system::Config>::Event>;7071 72 type WeightInfo: WeightInfo;73 type CommonWeightInfo: CommonWeightInfo<Self::CrossAccountId>;74}7576decl_event! {77 pub enum Event<T>78 where79 <T as frame_system::Config>::AccountId,80 <T as pallet_evm::account::Config>::CrossAccountId,81 {82 83 84 85 86 87 CollectionSponsorRemoved(CollectionId),8889 90 91 92 93 94 95 96 CollectionAdminAdded(CollectionId, CrossAccountId),9798 99 100 101 102 103 104 105 CollectionOwnedChanged(CollectionId, AccountId),106107 108 109 110 111 112 113 114 CollectionSponsorSet(CollectionId, AccountId),115116 117 118 119 120 121 ConstOnChainSchemaSet(CollectionId),122123 124 125 126 127 128 129 130 SponsorshipConfirmed(CollectionId, AccountId),131132 133 134 135 136 137 138 139 CollectionAdminRemoved(CollectionId, CrossAccountId),140141 142 143 144 145 146 147 148 AllowListAddressRemoved(CollectionId, CrossAccountId),149150 151 152 153 154 155 156 157 AllowListAddressAdded(CollectionId, CrossAccountId),158159 160 161 162 163 164 CollectionLimitSet(CollectionId),165166 CollectionPermissionSet(CollectionId),167168 169 170 171 172 173 MintPermissionSet(CollectionId),174175 176 177 178 179 180 OffchainSchemaSet(CollectionId),181182 183 184 185 186 187 188 189 PublicAccessModeSet(CollectionId, AccessMode),190191 192 193 194 195 196 SchemaVersionSet(CollectionId),197 }198}199200type SelfWeightOf<T> = <T as Config>::WeightInfo;201202203204205206207208209210211212213214215216217218219220221222223224decl_storage! {225 trait Store for Module<T: Config> as Unique {226227 228 229 ChainVersion: u64;230 231232 233 234 235 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;236 237 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;238 239 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;240 241 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>;242 243244 245 246 #[deprecated]247 pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;248 pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;249250 251 pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;252 pub FungibleApproveBasket get(fn fungible_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;253 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>;254 }255}256257decl_module! {258 pub struct Module<T: Config> for enum Call259 where260 origin: T::Origin261 {262 type Error = Error<T>;263264 fn deposit_event() = default;265266 fn on_initialize(_now: T::BlockNumber) -> Weight {267 0268 }269270 fn on_runtime_upgrade() -> Weight {271 let limit = None;272273 <VariableMetaDataBasket<T>>::remove_all(limit);274275 0276 }277278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 #[weight = <SelfWeightOf<T>>::create_collection()]295 #[transactional]296 #[deprecated]297 pub fn create_collection(origin,298 collection_name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,299 collection_description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,300 token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,301 mode: CollectionMode) -> DispatchResult {302 let data: CreateCollectionData<T::AccountId> = CreateCollectionData {303 name: collection_name,304 description: collection_description,305 token_prefix,306 mode,307 ..Default::default()308 };309 Self::create_collection_ex(origin, data)310 }311312 313 314 315 #[weight = <SelfWeightOf<T>>::create_collection()]316 #[transactional]317 pub fn create_collection_ex(origin, data: CreateCollectionData<T::AccountId>) -> DispatchResult {318 let sender = ensure_signed(origin)?;319320 321322 T::CollectionDispatch::create(sender, data)?;323324 Ok(())325 }326327 328 329 330 331 332 333 334 335 336 #[weight = <SelfWeightOf<T>>::destroy_collection()]337 #[transactional]338 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {339 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);340 let collection = <CollectionHandle<T>>::try_get(collection_id)?;341342 343344 T::CollectionDispatch::destroy(sender, collection)?;345346 <NftTransferBasket<T>>::remove_prefix(collection_id, None);347 <FungibleTransferBasket<T>>::remove_prefix(collection_id, None);348 <ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);349350 <NftApproveBasket<T>>::remove_prefix(collection_id, None);351 <FungibleApproveBasket<T>>::remove_prefix(collection_id, None);352 <RefungibleApproveBasket<T>>::remove_prefix((collection_id,), None);353354 Ok(())355 }356357 358 359 360 361 362 363 364 365 366 367 368 369 #[weight = <SelfWeightOf<T>>::add_to_allow_list()]370 #[transactional]371 pub fn add_to_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{372373 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);374 let collection = <CollectionHandle<T>>::try_get(collection_id)?;375376 <PalletCommon<T>>::toggle_allowlist(377 &collection,378 &sender,379 &address,380 true,381 )?;382383 Self::deposit_event(Event::<T>::AllowListAddressAdded(384 collection_id,385 address386 ));387388 Ok(())389 }390391 392 393 394 395 396 397 398 399 400 401 402 403 #[weight = <SelfWeightOf<T>>::remove_from_allow_list()]404 #[transactional]405 pub fn remove_from_allow_list(origin, collection_id: CollectionId, address: T::CrossAccountId) -> DispatchResult{406407 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);408 let collection = <CollectionHandle<T>>::try_get(collection_id)?;409410 <PalletCommon<T>>::toggle_allowlist(411 &collection,412 &sender,413 &address,414 false,415 )?;416417 <Pallet<T>>::deposit_event(Event::<T>::AllowListAddressRemoved(418 collection_id,419 address420 ));421422 Ok(())423 }424425 426 427 428 429 430 431 432 433 434 435 436 #[weight = <SelfWeightOf<T>>::change_collection_owner()]437 #[transactional]438 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {439440 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);441442 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;443 target_collection.check_is_owner(&sender)?;444445 target_collection.owner = new_owner.clone();446 <Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(447 collection_id,448 new_owner449 ));450451 target_collection.save()452 }453454 455 456 457 458 459 460 461 462 463 464 465 466 467 #[weight = <SelfWeightOf<T>>::add_collection_admin()]468 #[transactional]469 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::CrossAccountId) -> DispatchResult {470 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);471 let collection = <CollectionHandle<T>>::try_get(collection_id)?;472473 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminAdded(474 collection_id,475 new_admin_id.clone()476 ));477478 <PalletCommon<T>>::toggle_admin(&collection, &sender, &new_admin_id, true)479 }480481 482 483 484 485 486 487 488 489 490 491 492 493 #[weight = <SelfWeightOf<T>>::remove_collection_admin()]494 #[transactional]495 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::CrossAccountId) -> DispatchResult {496 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);497 let collection = <CollectionHandle<T>>::try_get(collection_id)?;498499 <Pallet<T>>::deposit_event(Event::<T>::CollectionAdminRemoved(500 collection_id,501 account_id.clone()502 ));503504 <PalletCommon<T>>::toggle_admin(&collection, &sender, &account_id, false)505 }506507 508 509 510 511 512 513 514 515 516 #[weight = <SelfWeightOf<T>>::set_collection_sponsor()]517 #[transactional]518 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {519 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);520521 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;522 target_collection.check_is_owner(&sender)?;523524 target_collection.set_sponsor(new_sponsor.clone());525526 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorSet(527 collection_id,528 new_sponsor529 ));530531 target_collection.save()532 }533534 535 536 537 538 539 540 541 #[weight = <SelfWeightOf<T>>::confirm_sponsorship()]542 #[transactional]543 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {544 let sender = ensure_signed(origin)?;545546 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;547 ensure!(548 target_collection.confirm_sponsorship(&sender),549 Error::<T>::ConfirmUnsetSponsorFail550 );551552 <Pallet<T>>::deposit_event(Event::<T>::SponsorshipConfirmed(553 collection_id,554 sender555 ));556557 target_collection.save()558 }559560 561 562 563 564 565 566 567 568 569 #[weight = <SelfWeightOf<T>>::remove_collection_sponsor()]570 #[transactional]571 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {572 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);573574 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;575 target_collection.check_is_owner(&sender)?;576577 target_collection.sponsorship = SponsorshipState::Disabled;578579 <Pallet<T>>::deposit_event(Event::<T>::CollectionSponsorRemoved(580 collection_id581 ));582 target_collection.save()583 }584585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 #[weight = T::CommonWeightInfo::create_item()]604 #[transactional]605 pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResultWithPostInfo {606 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);607 let budget = budget::Value::new(2);608609 dispatch_call::<T, _>(collection_id, |d| d.create_item(sender, owner, data, &budget))610 }611612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 #[weight = T::CommonWeightInfo::create_multiple_items(&items_data)]631 #[transactional]632 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec<CreateItemData>) -> DispatchResultWithPostInfo {633 ensure!(!items_data.is_empty(), Error::<T>::EmptyArgument);634 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);635 let budget = budget::Value::new(2);636637 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items(sender, owner, items_data, &budget))638 }639640 #[weight = T::CommonWeightInfo::set_collection_properties(properties.len() as u32)]641 #[transactional]642 pub fn set_collection_properties(643 origin,644 collection_id: CollectionId,645 properties: Vec<Property>646 ) -> DispatchResultWithPostInfo {647 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);648649 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);650651 dispatch_call::<T, _>(collection_id, |d| d.set_collection_properties(sender, properties))652 }653654 #[weight = T::CommonWeightInfo::delete_collection_properties(property_keys.len() as u32)]655 #[transactional]656 pub fn delete_collection_properties(657 origin,658 collection_id: CollectionId,659 property_keys: Vec<PropertyKey>,660 ) -> DispatchResultWithPostInfo {661 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);662663 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);664665 dispatch_call::<T, _>(collection_id, |d| d.delete_collection_properties(&sender, property_keys))666 }667668 #[weight = T::CommonWeightInfo::set_token_properties(properties.len() as u32)]669 #[transactional]670 pub fn set_token_properties(671 origin,672 collection_id: CollectionId,673 token_id: TokenId,674 properties: Vec<Property>675 ) -> DispatchResultWithPostInfo {676 ensure!(!properties.is_empty(), Error::<T>::EmptyArgument);677678 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);679680 dispatch_call::<T, _>(collection_id, |d| d.set_token_properties(sender, token_id, properties))681 }682683 #[weight = T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32)]684 #[transactional]685 pub fn delete_token_properties(686 origin,687 collection_id: CollectionId,688 token_id: TokenId,689 property_keys: Vec<PropertyKey>690 ) -> DispatchResultWithPostInfo {691 ensure!(!property_keys.is_empty(), Error::<T>::EmptyArgument);692693 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);694695 dispatch_call::<T, _>(collection_id, |d| d.delete_token_properties(sender, token_id, property_keys))696 }697698 #[weight = T::CommonWeightInfo::set_property_permissions(property_permissions.len() as u32)]699 #[transactional]700 pub fn set_property_permissions(701 origin,702 collection_id: CollectionId,703 property_permissions: Vec<PropertyKeyPermission>,704 ) -> DispatchResultWithPostInfo {705 ensure!(!property_permissions.is_empty(), Error::<T>::EmptyArgument);706707 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);708709 dispatch_call::<T, _>(collection_id, |d| d.set_property_permissions(&sender, property_permissions))710 }711712 #[weight = T::CommonWeightInfo::create_multiple_items_ex(&data)]713 #[transactional]714 pub fn create_multiple_items_ex(origin, collection_id: CollectionId, data: CreateItemExData<T::CrossAccountId>) -> DispatchResultWithPostInfo {715 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);716 let budget = budget::Value::new(2);717718 dispatch_call::<T, _>(collection_id, |d| d.create_multiple_items_ex(sender, data, &budget))719 }720721 722723 724 725 726 727 728 729 730 731 732 733 734 #[weight = <SelfWeightOf<T>>::set_transfers_enabled_flag()]735 #[transactional]736 pub fn set_transfers_enabled_flag(origin, collection_id: CollectionId, value: bool) -> DispatchResult {737 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);738 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;739 target_collection.check_is_owner(&sender)?;740741 742743 target_collection.limits.transfers_enabled = Some(value);744 target_collection.save()745 }746747 748 749 750 751 752 753 754 755 756 757 758 759 760 #[weight = T::CommonWeightInfo::burn_item()]761 #[transactional]762 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {763 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);764765 let post_info = dispatch_call::<T, _>(collection_id, |d| d.burn_item(sender, item_id, value))?;766 if value == 1 {767 <NftTransferBasket<T>>::remove(collection_id, item_id);768 <NftApproveBasket<T>>::remove(collection_id, item_id);769 }770 771 772 773 Ok(post_info)774 }775776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 #[weight = T::CommonWeightInfo::burn_from()]793 #[transactional]794 pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {795 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);796 let budget = budget::Value::new(2);797798 dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value, &budget))799 }800801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 #[weight = T::CommonWeightInfo::transfer()]825 #[transactional]826 pub fn transfer(origin, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {827 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);828 let budget = budget::Value::new(2);829830 dispatch_call::<T, _>(collection_id, |d| d.transfer(sender, recipient, item_id, value, &budget))831 }832833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 #[weight = T::CommonWeightInfo::approve()]849 #[transactional]850 pub fn approve(origin, spender: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResultWithPostInfo {851 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);852853 dispatch_call::<T, _>(collection_id, |d| d.approve(sender, spender, item_id, amount))854 }855856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 #[weight = T::CommonWeightInfo::transfer_from()]876 #[transactional]877 pub fn transfer_from(origin, from: T::CrossAccountId, recipient: T::CrossAccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResultWithPostInfo {878 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);879 let budget = budget::Value::new(2);880881 dispatch_call::<T, _>(collection_id, |d| d.transfer_from(sender, from, recipient, item_id, value, &budget))882 }883884 #[weight = <SelfWeightOf<T>>::set_collection_limits()]885 #[transactional]886 pub fn set_collection_limits(887 origin,888 collection_id: CollectionId,889 new_limit: CollectionLimits,890 ) -> DispatchResult {891 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);892 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;893 target_collection.check_is_owner(&sender)?;894 let old_limit = &target_collection.limits;895896 target_collection.limits = <PalletCommon<T>>::clamp_limits(target_collection.mode.clone(), &old_limit, new_limit)?;897898 <Pallet<T>>::deposit_event(Event::<T>::CollectionLimitSet(899 collection_id900 ));901902 target_collection.save()903 }904905 #[weight = <SelfWeightOf<T>>::set_collection_limits()]906 #[transactional]907 pub fn set_collection_permissions(908 origin,909 collection_id: CollectionId,910 new_limit: CollectionPermissions,911 ) -> DispatchResult {912 let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);913 let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;914 target_collection.check_is_owner(&sender)?;915 let old_limit = &target_collection.permissions;916917 target_collection.permissions = <PalletCommon<T>>::clamp_permissions(target_collection.mode.clone(), &old_limit, new_limit)?;918919 <Pallet<T>>::deposit_event(Event::<T>::CollectionPermissionSet(920 collection_id921 ));922923 target_collection.save()924 }925 }926}