123456#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, IsSubType, WithdrawReasons,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial, DispatchClass,29 },30 StorageValue,31 transactional,32};3334use frame_system::{self as system, ensure_signed, ensure_root};35use sp_runtime::sp_std::prelude::Vec;36use sp_runtime::{37 traits::{38 Hash, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,39 },40 transaction_validity::{41 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,42 },43 FixedPointOperand, FixedU128,44};45use sp_runtime::traits::StaticLookup;46use pallet_contracts::chain_extension::UncheckedFrom;47use pallet_transaction_payment::OnChargeTransaction;4849#[cfg(test)]50mod mock;5152#[cfg(test)]53mod tests;5455mod default_weights;5657pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;58pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;59pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;60pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;6162636465pub type CollectionId = u32;66pub type TokenId = u32;67pub type DecimalPoints = u8;6869#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]70#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]71pub enum CollectionMode {72 Invalid,73 NFT,74 75 Fungible(DecimalPoints),76 ReFungible,77}7879impl Default for CollectionMode {80 fn default() -> Self {81 Self::Invalid82 }83}8485impl Into<u8> for CollectionMode {86 fn into(self) -> u8 {87 match self {88 CollectionMode::Invalid => 0,89 CollectionMode::NFT => 1,90 CollectionMode::Fungible(_) => 2,91 CollectionMode::ReFungible => 3,92 }93 }94}9596#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]97#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]98pub enum AccessMode {99 Normal,100 WhiteList,101}102impl Default for AccessMode {103 fn default() -> Self {104 Self::Normal105 }106}107108#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]109#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]110pub enum SchemaVersion {111 ImageURL,112 Unique,113}114impl Default for SchemaVersion {115 fn default() -> Self {116 Self::ImageURL117 }118}119120#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]121#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]122pub struct Ownership<AccountId> {123 pub owner: AccountId,124 pub fraction: u128,125}126127#[derive(Encode, Decode, Debug, Clone, PartialEq)]128#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]129pub enum SponsorshipState<AccountId> {130 131 Disabled,132 Unconfirmed(AccountId),133 134 Confirmed(AccountId),135}136137impl<AccountId> SponsorshipState<AccountId> {138 fn sponsor(&self) -> Option<&AccountId> {139 match self {140 Self::Confirmed(sponsor) => Some(sponsor),141 _ => None,142 }143 }144145 fn pending_sponsor(&self) -> Option<&AccountId> {146 match self {147 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),148 _ => None,149 }150 }151152 fn confirmed(&self) -> bool {153 matches!(self, Self::Confirmed(_))154 }155}156157impl<T> Default for SponsorshipState<T> {158 fn default() -> Self {159 Self::Disabled160 }161}162163#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]164#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]165pub struct CollectionType<AccountId> {166 pub owner: AccountId,167 pub mode: CollectionMode,168 pub access: AccessMode,169 pub decimal_points: DecimalPoints,170 pub name: Vec<u16>, 171 pub description: Vec<u16>, 172 pub token_prefix: Vec<u8>, 173 pub mint_mode: bool,174 pub offchain_schema: Vec<u8>,175 pub schema_version: SchemaVersion,176 pub sponsorship: SponsorshipState<AccountId>,177 pub limits: CollectionLimits, 178 pub variable_on_chain_schema: Vec<u8>, 179 pub const_on_chain_schema: Vec<u8>, 180}181182#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]183#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]184pub struct NftItemType<AccountId> {185 pub owner: AccountId,186 pub const_data: Vec<u8>,187 pub variable_data: Vec<u8>,188}189190#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]191#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]192pub struct FungibleItemType {193 pub value: u128,194}195196#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]197#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]198pub struct ReFungibleItemType<AccountId> {199 pub owner: Vec<Ownership<AccountId>>,200 pub const_data: Vec<u8>,201 pub variable_data: Vec<u8>,202}203204205206207208209210211212213214215#[derive(Encode, Decode, Debug, Clone, PartialEq)]216#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]217pub struct CollectionLimits {218 pub account_token_ownership_limit: u32,219 pub sponsored_data_size: u32,220 pub token_limit: u32,221222 223 pub sponsor_transfer_timeout: u32,224 pub owner_can_transfer: bool,225 pub owner_can_destroy: bool,226}227228impl Default for CollectionLimits {229 fn default() -> CollectionLimits {230 CollectionLimits { 231 account_token_ownership_limit: 10_000_000, 232 token_limit: u32::max_value(),233 sponsored_data_size: u32::MAX,234 sponsor_transfer_timeout: 14400,235 owner_can_transfer: true,236 owner_can_destroy: true237 }238 }239}240241#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]242#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]243pub struct ChainLimits {244 pub collection_numbers_limit: u32,245 pub account_token_ownership_limit: u32,246 pub collections_admins_limit: u64,247 pub custom_data_limit: u32,248249 250 pub nft_sponsor_transfer_timeout: u32,251 pub fungible_sponsor_transfer_timeout: u32,252 pub refungible_sponsor_transfer_timeout: u32,253254 255 pub offchain_schema_limit: u32,256 pub variable_on_chain_schema_limit: u32,257 pub const_on_chain_schema_limit: u32,258}259260pub trait WeightInfo {261 fn create_collection() -> Weight;262 fn destroy_collection() -> Weight;263 fn add_to_white_list() -> Weight;264 fn remove_from_white_list() -> Weight;265 fn set_public_access_mode() -> Weight;266 fn set_mint_permission() -> Weight;267 fn change_collection_owner() -> Weight;268 fn add_collection_admin() -> Weight;269 fn remove_collection_admin() -> Weight;270 fn set_collection_sponsor() -> Weight;271 fn confirm_sponsorship() -> Weight;272 fn remove_collection_sponsor() -> Weight;273 fn create_item(s: usize) -> Weight;274 fn burn_item() -> Weight;275 fn transfer() -> Weight;276 fn approve() -> Weight;277 fn transfer_from() -> Weight;278 fn set_offchain_schema() -> Weight;279 fn set_const_on_chain_schema() -> Weight;280 fn set_variable_on_chain_schema() -> Weight;281 fn set_variable_meta_data() -> Weight;282 fn enable_contract_sponsoring() -> Weight;283 fn set_schema_version() -> Weight;284 fn set_chain_limits() -> Weight;285 fn set_contract_sponsoring_rate_limit() -> Weight;286 fn toggle_contract_white_list() -> Weight;287 fn add_to_contract_white_list() -> Weight;288 fn remove_from_contract_white_list() -> Weight;289 fn set_collection_limits() -> Weight;290}291292#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]293#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]294pub struct CreateNftData {295 pub const_data: Vec<u8>,296 pub variable_data: Vec<u8>,297}298299#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]300#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]301pub struct CreateFungibleData {302 pub value: u128,303}304305#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]306#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]307pub struct CreateReFungibleData {308 pub const_data: Vec<u8>,309 pub variable_data: Vec<u8>,310 pub pieces: u128,311}312313#[derive(Encode, Decode, Debug, Clone, PartialEq)]314#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]315pub enum CreateItemData {316 NFT(CreateNftData),317 Fungible(CreateFungibleData),318 ReFungible(CreateReFungibleData),319}320321impl CreateItemData {322 pub fn len(&self) -> usize {323 let len = match self {324 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),325 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),326 _ => 0327 };328 329 return len;330 }331}332333impl From<CreateNftData> for CreateItemData {334 fn from(item: CreateNftData) -> Self {335 CreateItemData::NFT(item)336 }337}338339impl From<CreateReFungibleData> for CreateItemData {340 fn from(item: CreateReFungibleData) -> Self {341 CreateItemData::ReFungible(item)342 }343}344345impl From<CreateFungibleData> for CreateItemData {346 fn from(item: CreateFungibleData) -> Self {347 CreateItemData::Fungible(item)348 }349}350351352decl_error! {353 354 pub enum Error for Module<T: Config> {355 356 TotalCollectionsLimitExceeded,357 358 CollectionDecimalPointLimitExceeded, 359 360 CollectionNameLimitExceeded, 361 362 CollectionDescriptionLimitExceeded, 363 364 CollectionTokenPrefixLimitExceeded,365 366 CollectionNotFound,367 368 TokenNotFound,369 370 AdminNotFound,371 372 NumOverflow, 373 374 AlreadyAdmin, 375 376 NoPermission,377 378 ConfirmUnsetSponsorFail,379 380 PublicMintingNotAllowed,381 382 MustBeTokenOwner,383 384 TokenValueTooLow,385 386 NftSizeLimitExceeded,387 388 ApproveNotFound,389 390 TokenValueNotEnough,391 392 ApproveRequired,393 394 AddresNotInWhiteList,395 396 CollectionAdminsLimitExceeded,397 398 AddressOwnershipLimitExceeded,399 400 EmptyArgument,401 402 TokenConstDataLimitExceeded,403 404 TokenVariableDataLimitExceeded,405 406 NotNftDataUsedToMintNftCollectionToken,407 408 NotFungibleDataUsedToMintFungibleCollectionToken,409 410 NotReFungibleDataUsedToMintReFungibleCollectionToken,411 412 UnexpectedCollectionType,413 414 CantStoreMetadataInFungibleTokens,415 416 CollectionTokenLimitExceeded,417 418 AccountTokenLimitExceeded,419 420 CollectionLimitBoundsExceeded,421 422 OwnerPermissionsCantBeReverted,423 424 SchemaDataLimitExceeded,425 426 WrongRefungiblePieces,427 428 BadCreateRefungibleCall,429 }430}431432pub trait Config: system::Config + Sized + pallet_transaction_payment::Config + pallet_contracts::Config {433 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;434435 436 type WeightInfo: WeightInfo;437438 type Currency: Currency<Self::AccountId>;439 type CollectionCreationPrice: Get<<<Self as Config>::Currency as Currency<Self::AccountId>>::Balance>;440 type TreasuryAccountId: Get<Self::AccountId>;441}442443#[cfg(feature = "runtime-benchmarks")]444mod benchmarking;445446447448449450451452453454455456457458459460461462463464465466467468469470decl_storage! {471 trait Store for Module<T: Config> as Nft {472473 474 475 CreatedCollectionCount: u32;476 477 ChainVersion: u64;478 479 480 ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;481 482483 484 pub ChainLimit get(fn chain_limit) config(): ChainLimits;485 486487 488 489 490 DestroyedCollectionCount: u32;491 492 493 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;494 495496 497 498 499 pub Collection get(fn collection) config(): map hasher(blake2_128_concat) CollectionId => CollectionType<T::AccountId>;500 501 502 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;503 504 505 pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;506 507508 509 510 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;511512 513 514 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;515516 517 518 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => NftItemType<T::AccountId>;519 520 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;521 522 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => ReFungibleItemType<T::AccountId>;523 524525 526 527 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;528 529530 531 532 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;533 534 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;535 536 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;537 538 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;539 540541 542 543 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;544 545 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;546 547 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;548 549 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;550 551 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 552 553 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(blake2_128_concat) T::AccountId => bool; 554 555 }556 add_extra_genesis {557 build(|config: &GenesisConfig<T>| {558 559 for (_num, _c) in &config.collection {560 <Module<T>>::init_collection(_c);561 }562563 for (_num, _c, _i) in &config.nft_item_id {564 <Module<T>>::init_nft_token(*_c, _i);565 }566567 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {568 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);569 }570571 for (_num, _c, _i) in &config.refungible_item_id {572 <Module<T>>::init_refungible_token(*_c, _i);573 }574 })575 }576}577578decl_event!(579 pub enum Event<T>580 where581 AccountId = <T as system::Config>::AccountId,582 {583 584 585 586 587 588 589 590 591 592 Created(CollectionId, u8, AccountId),593594 595 596 597 598 599 600 601 602 603 ItemCreated(CollectionId, TokenId, AccountId),604605 606 607 608 609 610 611 612 ItemDestroyed(CollectionId, TokenId),613614 615 616 617 618 619 620 621 622 623 624 625 Transfer(CollectionId, TokenId, AccountId, AccountId, u128),626 }627);628629decl_module! {630 pub struct Module<T: Config> for enum Call 631 where 632 origin: T::Origin633 {634 fn deposit_event() = default;635 type Error = Error<T>;636637 fn on_initialize(now: T::BlockNumber) -> Weight {638 0639 }640641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 #[weight = <T as Config>::WeightInfo::create_collection()]658 #[transactional]659 pub fn create_collection(origin,660 collection_name: Vec<u16>,661 collection_description: Vec<u16>,662 token_prefix: Vec<u8>,663 mode: CollectionMode) -> DispatchResult {664665 666 let who = ensure_signed(origin)?;667668 669 let mut imbalance = <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();670 imbalance.subsume(<<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(671 &T::TreasuryAccountId::get(),672 T::CollectionCreationPrice::get(),673 ));674 <T as Config>::Currency::settle(675 &who,676 imbalance,677 WithdrawReasons::TRANSFER,678 ExistenceRequirement::KeepAlive,679 ).map_err(|_| Error::<T>::NoPermission)?;680681 let decimal_points = match mode {682 CollectionMode::Fungible(points) => points,683 _ => 0684 };685686 let chain_limit = ChainLimit::get();687688 let created_count = CreatedCollectionCount::get();689 let destroyed_count = DestroyedCollectionCount::get();690691 692 ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);693694 695 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);696 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);697 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);698 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);699700 701 let next_id = created_count702 .checked_add(1)703 .ok_or(Error::<T>::NumOverflow)?;704705 CreatedCollectionCount::put(next_id);706707 let limits = CollectionLimits {708 sponsored_data_size: chain_limit.custom_data_limit,709 ..Default::default()710 };711712 713 let new_collection = CollectionType {714 owner: who.clone(),715 name: collection_name,716 mode: mode.clone(),717 mint_mode: false,718 access: AccessMode::Normal,719 description: collection_description,720 decimal_points: decimal_points,721 token_prefix: token_prefix,722 offchain_schema: Vec::new(),723 schema_version: SchemaVersion::ImageURL,724 sponsorship: SponsorshipState::Disabled,725 variable_on_chain_schema: Vec::new(),726 const_on_chain_schema: Vec::new(),727 limits,728 };729730 731 <Collection<T>>::insert(next_id, new_collection);732733 734 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));735736 Ok(())737 }738739 740 741 742 743 744 745 746 747 748 #[weight = <T as Config>::WeightInfo::destroy_collection()]749 #[transactional]750 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {751752 let sender = ensure_signed(origin)?;753 Self::check_owner_permissions(collection_id, sender)?;754755 let target_collection = <Collection<T>>::get(collection_id);756 if !target_collection.limits.owner_can_destroy {757 fail!(Error::<T>::NoPermission);758 }759760 <AddressTokens<T>>::remove_prefix(collection_id);761 <Allowances<T>>::remove_prefix(collection_id);762 <Balance<T>>::remove_prefix(collection_id);763 <ItemListIndex>::remove(collection_id);764 <AdminList<T>>::remove(collection_id);765 <Collection<T>>::remove(collection_id);766 <WhiteList<T>>::remove_prefix(collection_id);767768 <NftItemList<T>>::remove_prefix(collection_id);769 <FungibleItemList<T>>::remove_prefix(collection_id);770 <ReFungibleItemList<T>>::remove_prefix(collection_id);771772 <NftTransferBasket<T>>::remove_prefix(collection_id);773 <FungibleTransferBasket<T>>::remove_prefix(collection_id);774 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);775776 DestroyedCollectionCount::put(DestroyedCollectionCount::get()777 .checked_add(1)778 .ok_or(Error::<T>::NumOverflow)?);779780 Ok(())781 }782783 784 785 786 787 788 789 790 791 792 793 794 795 #[weight = <T as Config>::WeightInfo::add_to_white_list()]796 #[transactional]797 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{798799 let sender = ensure_signed(origin)?;800 Self::check_owner_or_admin_permissions(collection_id, sender)?;801802 <WhiteList<T>>::insert(collection_id, address, true);803 804 Ok(())805 }806807 808 809 810 811 812 813 814 815 816 817 818 819 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]820 #[transactional]821 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{822823 let sender = ensure_signed(origin)?;824 Self::check_owner_or_admin_permissions(collection_id, sender)?;825826 <WhiteList<T>>::remove(collection_id, address);827828 Ok(())829 }830831 832 833 834 835 836 837 838 839 840 841 842 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]843 #[transactional]844 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult845 {846 let sender = ensure_signed(origin)?;847848 Self::check_owner_permissions(collection_id, sender)?;849 let mut target_collection = <Collection<T>>::get(collection_id);850 target_collection.access = mode;851 <Collection<T>>::insert(collection_id, target_collection);852853 Ok(())854 }855856 857 858 859 860 861 862 863 864 865 866 867 868 869 #[weight = <T as Config>::WeightInfo::set_mint_permission()]870 #[transactional]871 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult872 {873 let sender = ensure_signed(origin)?;874875 Self::check_owner_permissions(collection_id, sender)?;876 let mut target_collection = <Collection<T>>::get(collection_id);877 target_collection.mint_mode = mint_permission;878 <Collection<T>>::insert(collection_id, target_collection);879880 Ok(())881 }882883 884 885 886 887 888 889 890 891 892 893 894 #[weight = <T as Config>::WeightInfo::change_collection_owner()]895 #[transactional]896 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {897898 let sender = ensure_signed(origin)?;899 Self::check_owner_permissions(collection_id, sender)?;900 let mut target_collection = <Collection<T>>::get(collection_id);901 target_collection.owner = new_owner;902 <Collection<T>>::insert(collection_id, target_collection);903904 Ok(())905 }906907 908 909 910 911 912 913 914 915 916 917 918 919 920 #[weight = <T as Config>::WeightInfo::add_collection_admin()]921 #[transactional]922 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {923924 let sender = ensure_signed(origin)?;925 Self::check_owner_or_admin_permissions(collection_id, sender)?;926 let mut admin_arr: Vec<T::AccountId> = Vec::new();927928 if <AdminList<T>>::contains_key(collection_id)929 {930 admin_arr = <AdminList<T>>::get(collection_id);931 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);932 }933934 935 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);936937 admin_arr.push(new_admin_id);938 <AdminList<T>>::insert(collection_id, admin_arr);939940 Ok(())941 }942943 944 945 946 947 948 949 950 951 952 953 954 955 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]956 #[transactional]957 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {958959 let sender = ensure_signed(origin)?;960 Self::check_owner_or_admin_permissions(collection_id, sender)?;961 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);962963 let mut admin_arr = <AdminList<T>>::get(collection_id);964 admin_arr.retain(|i| *i != account_id);965 <AdminList<T>>::insert(collection_id, admin_arr);966967 Ok(())968 }969970 971 972 973 974 975 976 977 978 979 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]980 #[transactional]981 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {982983 let sender = ensure_signed(origin)?;984 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);985986 let mut target_collection = <Collection<T>>::get(collection_id);987 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);988989 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);990 <Collection<T>>::insert(collection_id, target_collection);991992 Ok(())993 }994995 996 997 998 999 1000 1001 1002 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]1003 #[transactional]1004 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {10051006 let sender = ensure_signed(origin)?;1007 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);10081009 let mut target_collection = <Collection<T>>::get(collection_id);1010 ensure!(1011 target_collection.sponsorship.pending_sponsor() == Some(&sender),1012 Error::<T>::ConfirmUnsetSponsorFail1013 );10141015 target_collection.sponsorship = SponsorshipState::Confirmed(sender);1016 <Collection<T>>::insert(collection_id, target_collection);10171018 Ok(())1019 }10201021 1022 1023 1024 1025 1026 1027 1028 1029 1030 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]1031 #[transactional]1032 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {10331034 let sender = ensure_signed(origin)?;1035 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);10361037 let mut target_collection = <Collection<T>>::get(collection_id);1038 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);10391040 target_collection.sponsorship = SponsorshipState::Disabled;1041 <Collection<T>>::insert(collection_id, target_collection);10421043 Ok(())1044 }10451046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 10691070 #[weight = <T as Config>::WeightInfo::create_item(data.len())]1071 #[transactional]1072 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {10731074 let sender = ensure_signed(origin)?;10751076 Self::collection_exists(collection_id)?;10771078 let target_collection = <Collection<T>>::get(collection_id);10791080 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, 1)?;1081 Self::validate_create_item_args(&target_collection, &data)?;1082 Self::create_item_no_validation(collection_id, owner, data)?;10831084 Ok(())1085 }10861087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()1106 .map(|data| { data.len() })1107 .sum())]1108 #[transactional]1109 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {11101111 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1112 let sender = ensure_signed(origin)?;11131114 Self::collection_exists(collection_id)?;1115 let target_collection = <Collection<T>>::get(collection_id);11161117 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner, items_data.len() as u32)?;11181119 for data in &items_data {1120 Self::validate_create_item_args(&target_collection, data)?;1121 }1122 for data in &items_data {1123 Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1124 }11251126 Ok(())1127 }11281129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 #[weight = <T as Config>::WeightInfo::burn_item()]1143 #[transactional]1144 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {11451146 let sender = ensure_signed(origin)?;1147 Self::collection_exists(collection_id)?;11481149 1150 let target_collection = <Collection<T>>::get(collection_id);1151 ensure!(1152 Self::is_item_owner(sender.clone(), collection_id, item_id) ||1153 (1154 target_collection.limits.owner_can_transfer &&1155 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1156 ),1157 Error::<T>::NoPermission1158 );11591160 if target_collection.access == AccessMode::WhiteList {1161 Self::check_white_list(collection_id, &sender)?;1162 }11631164 match target_collection.mode1165 {1166 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1167 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1168 CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?,1169 _ => ()1170 };11711172 1173 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));11741175 Ok(())1176 }11771178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 #[weight = <T as Config>::WeightInfo::transfer()]1202 #[transactional]1203 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1204 let sender = ensure_signed(origin)?;1205 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1206 }12071208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 #[weight = <T as Config>::WeightInfo::approve()]1224 #[transactional]1225 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {12261227 let sender = ensure_signed(origin)?;12281229 Self::collection_exists(collection_id)?;1230 Self::token_exists(collection_id, item_id, &sender)?;12311232 1233 let target_collection = <Collection<T>>::get(collection_id);12341235 let bypasses_limits = target_collection.limits.owner_can_transfer &&1236 Self::is_owner_or_admin_permissions(1237 collection_id,1238 sender.clone(),1239 );12401241 let allowance_limit = if bypasses_limits {1242 None1243 } else if let Some(amount) = Self::owned_amount(1244 sender.clone(),1245 collection_id,1246 item_id,1247 ) {1248 Some(amount)1249 } else {1250 fail!(Error::<T>::NoPermission);1251 };12521253 if target_collection.access == AccessMode::WhiteList {1254 Self::check_white_list(collection_id, &sender)?;1255 Self::check_white_list(collection_id, &spender)?;1256 }12571258 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1259 let mut allowance: u128 = amount;1260 if allowance_exists {1261 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1262 }1263 if let Some(limit) = allowance_limit {1264 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1265 }1266 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);12671268 Ok(())1269 }1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 #[weight = <T as Config>::WeightInfo::transfer_from()]1291 #[transactional]1292 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {12931294 let sender = ensure_signed(origin)?;1295 let mut appoved_transfer = false;12961297 1298 let mut approval: u128 = 0;1299 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1300 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1301 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1302 appoved_transfer = true;1303 }13041305 let target_collection = <Collection<T>>::get(collection_id);13061307 1308 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;13091310 1311 ensure!(1312 appoved_transfer || 1313 (1314 target_collection.limits.owner_can_transfer &&1315 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1316 ),1317 Error::<T>::NoPermission1318 );13191320 if target_collection.access == AccessMode::WhiteList {1321 Self::check_white_list(collection_id, &sender)?;1322 Self::check_white_list(collection_id, &recipient)?;1323 }13241325 1326 if approval.saturating_sub(value) > 0 {1327 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1328 }1329 else {1330 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1331 }13321333 match target_collection.mode1334 {1335 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1336 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1337 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1338 _ => ()1339 };13401341 Ok(())1342 }13431344 1345 13461347 1348 1349 1350 13511352 13531354 13551356 1357 13581359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1372 #[transactional]1373 pub fn set_variable_meta_data (1374 origin,1375 collection_id: CollectionId,1376 item_id: TokenId,1377 data: Vec<u8>1378 ) -> DispatchResult {1379 let sender = ensure_signed(origin)?;1380 1381 Self::collection_exists(collection_id)?;1382 Self::token_exists(collection_id, item_id, &sender)?;13831384 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);13851386 1387 let target_collection = <Collection<T>>::get(collection_id);1388 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1389 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1390 Error::<T>::NoPermission);13911392 match target_collection.mode1393 {1394 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1395 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1396 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1397 _ => fail!(Error::<T>::UnexpectedCollectionType)1398 };13991400 Ok(())1401 }1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 #[weight = <T as Config>::WeightInfo::set_schema_version()]1418 #[transactional]1419 pub fn set_schema_version(1420 origin,1421 collection_id: CollectionId,1422 version: SchemaVersion1423 ) -> DispatchResult {1424 let sender = ensure_signed(origin)?;1425 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1426 let mut target_collection = <Collection<T>>::get(collection_id);1427 target_collection.schema_version = version;1428 <Collection<T>>::insert(collection_id, target_collection);14291430 Ok(())1431 }14321433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1446 #[transactional]1447 pub fn set_offchain_schema(1448 origin,1449 collection_id: CollectionId,1450 schema: Vec<u8>1451 ) -> DispatchResult {1452 let sender = ensure_signed(origin)?;1453 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14541455 1456 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");14571458 let mut target_collection = <Collection<T>>::get(collection_id);1459 target_collection.offchain_schema = schema;1460 <Collection<T>>::insert(collection_id, target_collection);14611462 Ok(())1463 }14641465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1478 #[transactional]1479 pub fn set_const_on_chain_schema (1480 origin,1481 collection_id: CollectionId,1482 schema: Vec<u8>1483 ) -> DispatchResult {1484 let sender = ensure_signed(origin)?;1485 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14861487 1488 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");14891490 let mut target_collection = <Collection<T>>::get(collection_id);1491 target_collection.const_on_chain_schema = schema;1492 <Collection<T>>::insert(collection_id, target_collection);14931494 Ok(())1495 }14961497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1510 #[transactional]1511 pub fn set_variable_on_chain_schema (1512 origin,1513 collection_id: CollectionId,1514 schema: Vec<u8>1515 ) -> DispatchResult {1516 let sender = ensure_signed(origin)?;1517 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;15181519 1520 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");15211522 let mut target_collection = <Collection<T>>::get(collection_id);1523 target_collection.variable_on_chain_schema = schema;1524 <Collection<T>>::insert(collection_id, target_collection);15251526 Ok(())1527 }15281529 1530 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1531 #[transactional]1532 pub fn set_chain_limits(1533 origin,1534 limits: ChainLimits1535 ) -> DispatchResult {15361537 #[cfg(not(feature = "runtime-benchmarks"))]1538 ensure_root(origin)?;15391540 <ChainLimit>::put(limits);1541 Ok(())1542 }15431544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1556 #[transactional]1557 pub fn enable_contract_sponsoring(1558 origin,1559 contract_address: T::AccountId,1560 enable: bool1561 ) -> DispatchResult {15621563 let sender = ensure_signed(origin)?;15641565 #[cfg(feature = "runtime-benchmarks")]1566 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15671568 Self::ensure_contract_owned(sender, &contract_address)?;15691570 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1571 Ok(())1572 }15731574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1592 #[transactional]1593 pub fn set_contract_sponsoring_rate_limit(1594 origin,1595 contract_address: T::AccountId,1596 rate_limit: T::BlockNumber1597 ) -> DispatchResult {1598 let sender = ensure_signed(origin)?;15991600 #[cfg(feature = "runtime-benchmarks")]1601 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16021603 Self::ensure_contract_owned(sender, &contract_address)?;1604 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1605 Ok(())1606 }16071608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1620 #[transactional]1621 pub fn toggle_contract_white_list(1622 origin,1623 contract_address: T::AccountId,1624 enable: bool1625 ) -> DispatchResult {1626 let sender = ensure_signed(origin)?;16271628 #[cfg(feature = "runtime-benchmarks")]1629 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16301631 Self::ensure_contract_owned(sender, &contract_address)?;1632 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1633 Ok(())1634 }1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1648 #[transactional]1649 pub fn add_to_contract_white_list(1650 origin,1651 contract_address: T::AccountId,1652 account_address: T::AccountId1653 ) -> DispatchResult {1654 let sender = ensure_signed(origin)?;16551656 #[cfg(feature = "runtime-benchmarks")]1657 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1658 1659 Self::ensure_contract_owned(sender, &contract_address)?; 1660 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1661 Ok(())1662 }16631664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1676 #[transactional]1677 pub fn remove_from_contract_white_list(1678 origin,1679 contract_address: T::AccountId,1680 account_address: T::AccountId1681 ) -> DispatchResult {1682 let sender = ensure_signed(origin)?;16831684 #[cfg(feature = "runtime-benchmarks")]1685 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16861687 Self::ensure_contract_owned(sender, &contract_address)?;1688 <ContractWhiteList<T>>::remove(contract_address, account_address);1689 Ok(())1690 }16911692 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1693 #[transactional]1694 pub fn set_collection_limits(1695 origin,1696 collection_id: u32,1697 new_limits: CollectionLimits,1698 ) -> DispatchResult {1699 let sender = ensure_signed(origin)?;1700 Self::check_owner_permissions(collection_id, sender.clone())?;1701 let mut target_collection = <Collection<T>>::get(collection_id);1702 let old_limits = target_collection.limits;1703 let chain_limits = ChainLimit::get();17041705 1706 ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1707 new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1708 new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1709 Error::<T>::CollectionLimitBoundsExceeded);17101711 1712 ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1713 ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);17141715 ensure!(1716 (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1717 (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1718 Error::<T>::OwnerPermissionsCantBeReverted,1719 );17201721 target_collection.limits = new_limits;1722 <Collection<T>>::insert(collection_id, target_collection);17231724 Ok(())1725 } 1726 }1727}17281729impl<T: Config> Module<T> {17301731 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {17321733 let target_collection = <Collection<T>>::get(collection_id);17341735 1736 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;17371738 1739 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1740 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1741 Error::<T>::NoPermission);17421743 if target_collection.access == AccessMode::WhiteList {1744 Self::check_white_list(collection_id, &sender)?;1745 Self::check_white_list(collection_id, &recipient)?;1746 }17471748 match target_collection.mode1749 {1750 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1751 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1752 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1753 _ => ()1754 };17551756 Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));17571758 Ok(())1759 }176017611762 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {17631764 1765 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1766 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1767 1768 Ok(())1769 }17701771 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId, amount: u32) -> DispatchResult {17721773 1774 let total_items: u32 = ItemListIndex::get(collection_id)1775 .checked_add(amount)1776 .ok_or(Error::<T>::CollectionTokenLimitExceeded)?;1777 let account_items: u32 = (<AddressTokens<T>>::get(collection_id, owner).len() as u32)1778 .checked_add(amount)1779 .ok_or(Error::<T>::AccountTokenLimitExceeded)?;1780 ensure!(collection.limits.token_limit >= total_items, Error::<T>::CollectionTokenLimitExceeded);1781 ensure!(collection.limits.account_token_ownership_limit >= account_items, Error::<T>::AccountTokenLimitExceeded);17821783 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1784 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1785 Self::check_white_list(collection_id, owner)?;1786 Self::check_white_list(collection_id, sender)?;1787 }17881789 Ok(())1790 }17911792 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1793 match target_collection.mode1794 {1795 CollectionMode::NFT => {1796 if let CreateItemData::NFT(data) = data {1797 1798 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1799 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1800 } else {1801 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1802 }1803 },1804 CollectionMode::Fungible(_) => {1805 if let CreateItemData::Fungible(_) = data {1806 } else {1807 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1808 }1809 },1810 CollectionMode::ReFungible => {1811 if let CreateItemData::ReFungible(data) = data {18121813 1814 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1815 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);18161817 1818 ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1819 ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1820 } else {1821 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1822 }1823 },1824 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1825 };18261827 Ok(())1828 }18291830 fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1831 match data1832 {1833 CreateItemData::NFT(data) => {1834 let item = NftItemType {1835 owner: owner.clone(),1836 const_data: data.const_data,1837 variable_data: data.variable_data1838 };18391840 Self::add_nft_item(collection_id, item)?;1841 },1842 CreateItemData::Fungible(data) => {1843 Self::add_fungible_item(collection_id, &owner, data.value)?;1844 },1845 CreateItemData::ReFungible(data) => {1846 let mut owner_list = Vec::new();1847 owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});18481849 let item = ReFungibleItemType {1850 owner: owner_list,1851 const_data: data.const_data,1852 variable_data: data.variable_data1853 };18541855 Self::add_refungible_item(collection_id, item)?;1856 }1857 };18581859 Ok(())1860 }18611862 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {18631864 1865 let mut balance: u128 = 0;1866 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1867 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1868 } 18691870 1871 let item = FungibleItemType {1872 value: balance + value1873 };1874 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);18751876 1877 let new_balance = <Balance<T>>::get(collection_id, owner)1878 .checked_add(value)1879 .ok_or(Error::<T>::NumOverflow)?;1880 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18811882 Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));1883 Ok(())1884 }18851886 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1887 let current_index = <ItemListIndex>::get(collection_id)1888 .checked_add(1)1889 .ok_or(Error::<T>::NumOverflow)?;1890 let itemcopy = item.clone();18911892 ensure!(1893 item.owner.len() == 1,1894 Error::<T>::BadCreateRefungibleCall,1895 );1896 let item_owner = item.owner.first().expect("only one owner is defined");18971898 let value = item_owner.fraction;1899 let owner = item_owner.owner.clone();19001901 Self::add_token_index(collection_id, current_index, &owner)?;19021903 <ItemListIndex>::insert(collection_id, current_index);1904 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);19051906 1907 let new_balance = <Balance<T>>::get(collection_id, &owner)1908 .checked_add(value)1909 .ok_or(Error::<T>::NumOverflow)?;1910 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);19111912 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner));1913 Ok(())1914 }19151916 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1917 let current_index = <ItemListIndex>::get(collection_id)1918 .checked_add(1)1919 .ok_or(Error::<T>::NumOverflow)?;19201921 let item_owner = item.owner.clone();1922 Self::add_token_index(collection_id, current_index, &item.owner)?;19231924 <ItemListIndex>::insert(collection_id, current_index);1925 <NftItemList<T>>::insert(collection_id, current_index, item);19261927 1928 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1929 .checked_add(1)1930 .ok_or(Error::<T>::NumOverflow)?;1931 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);19321933 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner));1934 Ok(())1935 }19361937 fn burn_refungible_item(1938 collection_id: CollectionId,1939 item_id: TokenId,1940 owner: &T::AccountId,1941 ) -> DispatchResult {1942 ensure!(1943 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1944 Error::<T>::TokenNotFound1945 );1946 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1947 let rft_balance = token1948 .owner1949 .iter()1950 .find(|&i| i.owner == *owner)1951 .ok_or(Error::<T>::TokenNotFound)?;1952 Self::remove_token_index(collection_id, item_id, owner)?;19531954 1955 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1956 .checked_sub(rft_balance.fraction)1957 .ok_or(Error::<T>::NumOverflow)?;1958 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);19591960 1961 let index = token1962 .owner1963 .iter()1964 .position(|i| i.owner == *owner)1965 .expect("owned item is exists");1966 token.owner.remove(index);1967 let owner_count = token.owner.len();19681969 1970 if owner_count == 0 {1971 <ReFungibleItemList<T>>::remove(collection_id, item_id);1972 }1973 else {1974 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1975 }19761977 Ok(())1978 }19791980 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1981 ensure!(1982 <NftItemList<T>>::contains_key(collection_id, item_id),1983 Error::<T>::TokenNotFound1984 );1985 let item = <NftItemList<T>>::get(collection_id, item_id);1986 Self::remove_token_index(collection_id, item_id, &item.owner)?;19871988 1989 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1990 .checked_sub(1)1991 .ok_or(Error::<T>::NumOverflow)?;1992 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1993 <NftItemList<T>>::remove(collection_id, item_id);19941995 Ok(())1996 }19971998 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1999 ensure!(2000 <FungibleItemList<T>>::contains_key(collection_id, owner),2001 Error::<T>::TokenNotFound2002 );2003 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2004 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);20052006 2007 let new_balance = <Balance<T>>::get(collection_id, owner)2008 .checked_sub(value)2009 .ok_or(Error::<T>::NumOverflow)?;2010 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);20112012 if balance.value - value > 0 {2013 balance.value -= value;2014 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2015 }2016 else {2017 <FungibleItemList<T>>::remove(collection_id, owner);2018 }20192020 Ok(())2021 }20222023 fn collection_exists(collection_id: CollectionId) -> DispatchResult {2024 ensure!(2025 <Collection<T>>::contains_key(collection_id),2026 Error::<T>::CollectionNotFound2027 );2028 Ok(())2029 }20302031 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {2032 Self::collection_exists(collection_id)?;20332034 let target_collection = <Collection<T>>::get(collection_id);2035 ensure!(2036 subject == target_collection.owner,2037 Error::<T>::NoPermission2038 );20392040 Ok(())2041 }20422043 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {2044 let target_collection = <Collection<T>>::get(collection_id);2045 let mut result: bool = subject == target_collection.owner;2046 let exists = <AdminList<T>>::contains_key(collection_id);20472048 if !result & exists {2049 if <AdminList<T>>::get(collection_id).contains(&subject) {2050 result = true2051 }2052 }20532054 result2055 }20562057 fn check_owner_or_admin_permissions(2058 collection_id: CollectionId,2059 subject: T::AccountId,2060 ) -> DispatchResult {2061 Self::collection_exists(collection_id)?;2062 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());20632064 ensure!(2065 result,2066 Error::<T>::NoPermission2067 );2068 Ok(())2069 }20702071 fn owned_amount(2072 subject: T::AccountId,2073 collection_id: CollectionId,2074 item_id: TokenId,2075 ) -> Option<u128> {2076 let target_collection = <Collection<T>>::get(collection_id);20772078 match target_collection.mode {2079 CollectionMode::NFT => {2080 if <NftItemList<T>>::get(collection_id, item_id).owner == subject {2081 return Some(1)2082 }2083 None2084 },2085 CollectionMode::Fungible(_) => {2086 if <FungibleItemList<T>>::contains_key(collection_id, &subject) {2087 return Some(<FungibleItemList<T>>::get(collection_id, &subject)2088 .value);2089 }2090 None2091 },2092 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)2093 .owner2094 .iter()2095 .find(|i| i.owner == subject)2096 .map(|i| i.fraction),2097 CollectionMode::Invalid => None,2098 }2099 }21002101 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {2102 let target_collection = <Collection<T>>::get(collection_id);21032104 match target_collection.mode {2105 CollectionMode::NFT => {2106 <NftItemList<T>>::get(collection_id, item_id).owner == subject2107 }2108 CollectionMode::Fungible(_) => {2109 <FungibleItemList<T>>::contains_key(collection_id, &subject)2110 }2111 CollectionMode::ReFungible => {2112 <ReFungibleItemList<T>>::get(collection_id, item_id)2113 .owner2114 .iter()2115 .any(|i| i.owner == subject)2116 }2117 CollectionMode::Invalid => false,2118 }2119 }21202121 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {2122 let mes = Error::<T>::AddresNotInWhiteList;2123 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);21242125 Ok(())2126 }21272128 2129 2130 fn token_exists(2131 collection_id: CollectionId,2132 item_id: TokenId,2133 owner: &T::AccountId2134 ) -> DispatchResult {2135 let target_collection = <Collection<T>>::get(collection_id);2136 let exists = match target_collection.mode2137 {2138 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2139 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),2140 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2141 _ => false2142 };21432144 ensure!(exists == true, Error::<T>::TokenNotFound);2145 Ok(())2146 }21472148 fn transfer_fungible(2149 collection_id: CollectionId,2150 value: u128,2151 owner: &T::AccountId,2152 recipient: &T::AccountId,2153 ) -> DispatchResult {2154 Self::token_exists(collection_id, 0, owner)?;21552156 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2157 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);21582159 2160 Self::add_fungible_item(collection_id, recipient, value)?;21612162 2163 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);21642165 2166 if balance.value == value {2167 <FungibleItemList<T>>::remove(collection_id, owner);2168 }2169 else {2170 balance.value -= value;2171 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2172 }21732174 Ok(())2175 }21762177 fn transfer_refungible(2178 collection_id: CollectionId,2179 item_id: TokenId,2180 value: u128,2181 owner: T::AccountId,2182 new_owner: T::AccountId,2183 ) -> DispatchResult {2184 Self::token_exists(collection_id, item_id, &owner)?;21852186 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2187 let item = full_item2188 .owner2189 .iter()2190 .filter(|i| i.owner == owner)2191 .next()2192 .ok_or(Error::<T>::TokenNotFound)?;2193 let amount = item.fraction;21942195 ensure!(amount >= value, Error::<T>::TokenValueTooLow);21962197 2198 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2199 .checked_sub(value)2200 .ok_or(Error::<T>::NumOverflow)?;2201 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);22022203 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2204 .checked_add(value)2205 .ok_or(Error::<T>::NumOverflow)?;2206 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);22072208 let old_owner = item.owner.clone();2209 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);22102211 2212 if amount == value && !new_owner_has_account {2213 2214 2215 let mut new_full_item = full_item.clone();2216 new_full_item2217 .owner2218 .iter_mut()2219 .find(|i| i.owner == owner)2220 .expect("old owner does present in refungible")2221 .owner = new_owner.clone();2222 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);22232224 2225 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;2226 } else {2227 let mut new_full_item = full_item.clone();2228 new_full_item2229 .owner2230 .iter_mut()2231 .find(|i| i.owner == owner)2232 .expect("old owner does present in refungible")2233 .fraction -= value;22342235 2236 if new_owner_has_account {2237 2238 new_full_item2239 .owner2240 .iter_mut()2241 .find(|i| i.owner == new_owner)2242 .expect("new owner has account")2243 .fraction += value;2244 } else {2245 2246 new_full_item.owner.push(Ownership {2247 owner: new_owner.clone(),2248 fraction: value,2249 });2250 Self::add_token_index(collection_id, item_id, &new_owner)?;2251 }22522253 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2254 }22552256 Ok(())2257 }22582259 fn transfer_nft(2260 collection_id: CollectionId,2261 item_id: TokenId,2262 sender: T::AccountId,2263 new_owner: T::AccountId,2264 ) -> DispatchResult {2265 Self::token_exists(collection_id, item_id, &sender)?;22662267 let mut item = <NftItemList<T>>::get(collection_id, item_id);22682269 ensure!(2270 sender == item.owner,2271 Error::<T>::MustBeTokenOwner2272 );22732274 2275 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2276 .checked_sub(1)2277 .ok_or(Error::<T>::NumOverflow)?;2278 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);22792280 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2281 .checked_add(1)2282 .ok_or(Error::<T>::NumOverflow)?;2283 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);22842285 2286 let old_owner = item.owner.clone();2287 item.owner = new_owner.clone();2288 <NftItemList<T>>::insert(collection_id, item_id, item);22892290 2291 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;22922293 Ok(())2294 }2295 2296 fn set_re_fungible_variable_data(2297 collection_id: CollectionId,2298 item_id: TokenId,2299 data: Vec<u8>2300 ) -> DispatchResult {2301 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);23022303 item.variable_data = data;23042305 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);23062307 Ok(())2308 }23092310 fn set_nft_variable_data(2311 collection_id: CollectionId,2312 item_id: TokenId,2313 data: Vec<u8>2314 ) -> DispatchResult {2315 let mut item = <NftItemList<T>>::get(collection_id, item_id);2316 2317 item.variable_data = data;23182319 <NftItemList<T>>::insert(collection_id, item_id, item);2320 2321 Ok(())2322 }23232324 fn init_collection(item: &CollectionType<T::AccountId>) {2325 2326 assert!(2327 item.decimal_points <= MAX_DECIMAL_POINTS,2328 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2329 );2330 assert!(2331 item.name.len() <= 64,2332 "Collection name can not be longer than 63 char"2333 );2334 assert!(2335 item.name.len() <= 256,2336 "Collection description can not be longer than 255 char"2337 );2338 assert!(2339 item.token_prefix.len() <= 16,2340 "Token prefix can not be longer than 15 char"2341 );23422343 2344 let next_id = CreatedCollectionCount::get()2345 .checked_add(1)2346 .unwrap();23472348 CreatedCollectionCount::put(next_id);2349 }23502351 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2352 let current_index = <ItemListIndex>::get(collection_id)2353 .checked_add(1)2354 .unwrap();23552356 let item_owner = item.owner.clone();2357 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();23582359 <ItemListIndex>::insert(collection_id, current_index);23602361 2362 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2363 .checked_add(1)2364 .unwrap();2365 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2366 }23672368 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2369 let current_index = <ItemListIndex>::get(collection_id)2370 .checked_add(1)2371 .unwrap();23722373 Self::add_token_index(collection_id, current_index, owner).unwrap();23742375 <ItemListIndex>::insert(collection_id, current_index);23762377 2378 let new_balance = <Balance<T>>::get(collection_id, owner)2379 .checked_add(item.value)2380 .unwrap();2381 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2382 }23832384 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2385 let current_index = <ItemListIndex>::get(collection_id)2386 .checked_add(1)2387 .unwrap();23882389 let value = item.owner.first().unwrap().fraction;2390 let owner = item.owner.first().unwrap().owner.clone();23912392 Self::add_token_index(collection_id, current_index, &owner).unwrap();23932394 <ItemListIndex>::insert(collection_id, current_index);23952396 2397 let new_balance = <Balance<T>>::get(collection_id, &owner)2398 .checked_add(value)2399 .unwrap();2400 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2401 }24022403 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {24042405 2406 if <AccountItemCount<T>>::contains_key(owner) {24072408 2409 let count = <AccountItemCount<T>>::get(owner);2410 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);24112412 <AccountItemCount<T>>::insert(owner.clone(), count2413 .checked_add(1)2414 .ok_or(Error::<T>::NumOverflow)?);2415 }2416 else {2417 <AccountItemCount<T>>::insert(owner.clone(), 1);2418 }24192420 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2421 if list_exists {2422 let mut list = <AddressTokens<T>>::get(collection_id, owner);2423 let item_contains = list.contains(&item_index.clone());24242425 if !item_contains {2426 list.push(item_index.clone());2427 }24282429 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2430 } else {2431 let mut itm = Vec::new();2432 itm.push(item_index.clone());2433 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2434 }24352436 Ok(())2437 }24382439 fn remove_token_index(2440 collection_id: CollectionId,2441 item_index: TokenId,2442 owner: &T::AccountId,2443 ) -> DispatchResult {24442445 2446 <AccountItemCount<T>>::insert(owner.clone(), 2447 <AccountItemCount<T>>::get(owner)2448 .checked_sub(1)2449 .ok_or(Error::<T>::NumOverflow)?);245024512452 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2453 if list_exists {2454 let mut list = <AddressTokens<T>>::get(collection_id, owner);2455 let item_contains = list.contains(&item_index.clone());24562457 if item_contains {2458 list.retain(|&item| item != item_index);2459 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2460 }2461 }24622463 Ok(())2464 }24652466 fn move_token_index(2467 collection_id: CollectionId,2468 item_index: TokenId,2469 old_owner: &T::AccountId,2470 new_owner: &T::AccountId,2471 ) -> DispatchResult {2472 Self::remove_token_index(collection_id, item_index, old_owner)?;2473 Self::add_token_index(collection_id, item_index, new_owner)?;24742475 Ok(())2476 }2477 2478 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2479 if <ContractOwner<T>>::contains_key(contract.clone()) {2480 let owner = <ContractOwner<T>>::get(contract);2481 ensure!(account == owner, Error::<T>::NoPermission);2482 } else {2483 fail!(Error::<T>::NoPermission);2484 }24852486 Ok(())2487 }2488}2489249024912492249324942495pub type Multiplier = FixedU128;24962497type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;2498249925002501#[derive(Encode, Decode, Clone, Eq, PartialEq)]2502pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);25032504impl<T: Config + Send + Sync> sp_std::fmt::Debug 2505 for ChargeTransactionPayment<T>2506{2507 #[cfg(feature = "std")]2508 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2509 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2510 }2511 #[cfg(not(feature = "std"))]2512 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2513 Ok(())2514 }2515}25162517impl<T: Config> ChargeTransactionPayment<T>2518where2519 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2520 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2521 T::AccountId: AsRef<[u8]>,2522 T::AccountId: UncheckedFrom<T::Hash>,2523{2524 fn traditional_fee(2525 len: usize,2526 info: &DispatchInfoOf<T::Call>,2527 tip: BalanceOf<T>,2528 ) -> BalanceOf<T>2529 where2530 T::Call: Dispatchable<Info = DispatchInfo>,2531 {2532 <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2533 }25342535 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2536 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2537 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2538 let len_saturation = max_block_length as u64 / (len as u64).max(1);2539 let coefficient: BalanceOf<T> = weight_saturation2540 .min(len_saturation)2541 .saturated_into::<BalanceOf<T>>();2542 final_fee2543 .saturating_mul(coefficient)2544 .saturated_into::<TransactionPriority>()2545 }25462547 fn withdraw_fee(2548 &self,2549 who: &T::AccountId,2550 call: &T::Call,2551 info: &DispatchInfoOf<T::Call>,2552 len: usize,2553 ) -> Result<2554 (2555 BalanceOf<T>,2556 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2557 ),2558 TransactionValidityError,2559 > {2560 let tip = self.0;25612562 let fee = Self::traditional_fee(len, info, tip);25632564 2565 if fee.is_zero() {2566 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2567 .map(|i| (fee, i));2568 }25692570 2571 2572 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2573 Some(Call::create_item(collection_id, _owner, _properties)) => {25742575 2576 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;25772578 let collection = <Collection<T>>::get(collection_id);25792580 let limit = collection.limits.sponsor_transfer_timeout;2581 let mut sponsored = true;2582 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2583 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2584 let limit_time = last_tx_block + limit.into();2585 if block_number <= limit_time {2586 sponsored = false;2587 }2588 }2589 if sponsored {2590 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2591 }25922593 2594 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&2595 (sponsored)2596 {2597 collection.sponsorship.sponsor()2598 .cloned()2599 .unwrap_or_default()2600 } else {2601 T::AccountId::default()2602 }2603 }2604 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2605 2606 let mut sponsor_transfer = false;2607 if <Collection<T>>::get(collection_id).sponsorship.confirmed() {26082609 let collection_limits = <Collection<T>>::get(collection_id).limits;2610 let collection_mode = <Collection<T>>::get(collection_id).mode;2611 2612 2613 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2614 sponsor_transfer = match collection_mode {2615 CollectionMode::NFT => {2616 2617 2618 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2619 collection_limits.sponsor_transfer_timeout2620 } else {2621 ChainLimit::get().nft_sponsor_transfer_timeout2622 };2623 2624 let mut sponsored = true;2625 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2626 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2627 let limit_time = last_tx_block + limit.into();2628 if block_number <= limit_time {2629 sponsored = false;2630 }2631 }2632 if sponsored {2633 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2634 }26352636 sponsored2637 }2638 CollectionMode::Fungible(_) => {2639 2640 2641 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2642 collection_limits.sponsor_transfer_timeout2643 } else {2644 ChainLimit::get().fungible_sponsor_transfer_timeout2645 };2646 2647 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2648 let mut sponsored = true;2649 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2650 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2651 let limit_time = last_tx_block + limit.into();2652 if block_number <= limit_time {2653 sponsored = false;2654 }2655 }2656 if sponsored {2657 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2658 }26592660 sponsored2661 }2662 CollectionMode::ReFungible => {2663 2664 2665 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2666 collection_limits.sponsor_transfer_timeout2667 } else {2668 ChainLimit::get().refungible_sponsor_transfer_timeout2669 };2670 2671 let mut sponsored = true;2672 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2673 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2674 let limit_time = last_tx_block + limit.into();2675 if block_number <= limit_time {2676 sponsored = false;2677 }2678 }2679 if sponsored {2680 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2681 }26822683 sponsored2684 }2685 _ => {2686 false2687 },2688 };2689 }26902691 if !sponsor_transfer {2692 T::AccountId::default()2693 } else {2694 <Collection<T>>::get(collection_id).sponsorship.sponsor()2695 .cloned()2696 .unwrap_or_default()2697 }2698 }26992700 _ => T::AccountId::default(),2701 };27022703 2704 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {27052706 2707 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {27082709 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2710 &who,2711 code_hash,2712 salt,2713 );2714 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());27152716 T::AccountId::default()2717 },27182719 2720 Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt)) => {27212722 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2723 &who,2724 &T::Hashing::hash(&_code),2725 _salt,2726 );27272728 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());27292730 T::AccountId::default()2731 }27322733 2734 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {27352736 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());27372738 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2739 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2740 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2741 2742 if !owned_contract && white_list_enabled {2743 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2744 return Err(InvalidTransaction::Call.into());2745 }2746 }27472748 let mut sponsor_transfer = false;2749 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2750 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2751 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2752 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2753 let limit_time = last_tx_block + rate_limit;27542755 if block_number >= limit_time {2756 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2757 sponsor_transfer = true;2758 }2759 } else {2760 sponsor_transfer = false;2761 }2762 2763 2764 let mut sp = T::AccountId::default();2765 if sponsor_transfer {2766 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2767 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2768 sp = called_contract;2769 }2770 }2771 }27722773 sp2774 },27752776 _ => sponsor,2777 };27782779 let mut who_pays_fee: T::AccountId = sponsor.clone();2780 if sponsor == T::AccountId::default() {2781 who_pays_fee = who.clone();2782 }27832784 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2785 .map(|i| (fee, i))2786 }2787}278827892790impl<T: Config + Send + Sync> SignedExtension2791 for ChargeTransactionPayment<T>2792where2793 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2794 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2795 T::AccountId: AsRef<[u8]>,2796 T::AccountId: UncheckedFrom<T::Hash>,2797{2798 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2799 type AccountId = T::AccountId;2800 type Call = T::Call;2801 type AdditionalSigned = ();2802 type Pre = (2803 2804 BalanceOf<T>,2805 2806 Self::AccountId,2807 2808 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2809 );2810 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2811 Ok(())2812 }28132814 fn validate(2815 &self,2816 who: &Self::AccountId,2817 call: &Self::Call,2818 info: &DispatchInfoOf<Self::Call>,2819 len: usize,2820 ) -> TransactionValidity {2821 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2822 Ok(ValidTransaction {2823 priority: Self::get_priority(len, info, fee),2824 ..Default::default()2825 })2826 }28272828 fn pre_dispatch(2829 self,2830 who: &Self::AccountId,2831 call: &Self::Call,2832 info: &DispatchInfoOf<Self::Call>,2833 len: usize,2834 ) -> Result<Self::Pre, TransactionValidityError> {2835 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2836 Ok((self.0, who.clone(), imbalance))2837 }28382839 fn post_dispatch(2840 pre: Self::Pre,2841 info: &DispatchInfoOf<Self::Call>,2842 post_info: &PostDispatchInfoOf<Self::Call>,2843 len: usize,2844 _result: &DispatchResult,2845 ) -> Result<(), TransactionValidityError> {2846 let (tip, who, imbalance) = pre;2847 let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(2848 len as u32,2849 info,2850 post_info,2851 tip,2852 );2853 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2854 Ok(())2855 }2856}28572858