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,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 WrongRefungiblePieces427 }428}429430pub trait Config: system::Config + Sized + pallet_transaction_payment::Config + pallet_contracts::Config {431 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;432433 434 type WeightInfo: WeightInfo;435}436437#[cfg(feature = "runtime-benchmarks")]438mod benchmarking;439440441442443444445446447448449450451452453454455456457458459460461462463464decl_storage! {465 trait Store for Module<T: Config> as Nft {466467 468 469 CreatedCollectionCount: u32;470 471 ChainVersion: u64;472 473 474 ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;475 476477 478 pub ChainLimit get(fn chain_limit) config(): ChainLimits;479 480481 482 483 484 DestroyedCollectionCount: u32;485 486 487 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;488 489490 491 492 493 pub Collection get(fn collection) config(): map hasher(blake2_128_concat) CollectionId => CollectionType<T::AccountId>;494 495 496 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;497 498 499 pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;500 501502 503 504 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;505506 507 508 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;509510 511 512 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => NftItemType<T::AccountId>;513 514 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;515 516 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => ReFungibleItemType<T::AccountId>;517 518519 520 521 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;522 523524 525 526 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;527 528 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;529 530 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;531 532 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;533 534535 536 537 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;538 539 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;540 541 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;542 543 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;544 545 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 546 547 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(blake2_128_concat) T::AccountId => bool; 548 549 }550 add_extra_genesis {551 build(|config: &GenesisConfig<T>| {552 553 for (_num, _c) in &config.collection {554 <Module<T>>::init_collection(_c);555 }556557 for (_num, _c, _i) in &config.nft_item_id {558 <Module<T>>::init_nft_token(*_c, _i);559 }560561 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {562 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);563 }564565 for (_num, _c, _i) in &config.refungible_item_id {566 <Module<T>>::init_refungible_token(*_c, _i);567 }568 })569 }570}571572decl_event!(573 pub enum Event<T>574 where575 AccountId = <T as system::Config>::AccountId,576 {577 578 579 580 581 582 583 584 585 586 Created(CollectionId, u8, AccountId),587588 589 590 591 592 593 594 595 596 597 ItemCreated(CollectionId, TokenId, AccountId),598599 600 601 602 603 604 605 606 ItemDestroyed(CollectionId, TokenId),607608 609 610 611 612 613 614 615 616 617 618 619 Transfer(CollectionId, TokenId, AccountId, AccountId, u128),620 }621);622623decl_module! {624 pub struct Module<T: Config> for enum Call 625 where 626 origin: T::Origin627 {628 fn deposit_event() = default;629 type Error = Error<T>;630631 fn on_initialize(now: T::BlockNumber) -> Weight {632 0633 }634635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 #[weight = <T as Config>::WeightInfo::create_collection()]652 #[transactional]653 pub fn create_collection(origin,654 collection_name: Vec<u16>,655 collection_description: Vec<u16>,656 token_prefix: Vec<u8>,657 mode: CollectionMode) -> DispatchResult {658659 660 let who = ensure_signed(origin)?;661662 let decimal_points = match mode {663 CollectionMode::Fungible(points) => points,664 _ => 0665 };666667 let chain_limit = ChainLimit::get();668669 let created_count = CreatedCollectionCount::get();670 let destroyed_count = DestroyedCollectionCount::get();671672 673 ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);674675 676 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);677 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);678 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);679 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);680681 682 let next_id = created_count683 .checked_add(1)684 .ok_or(Error::<T>::NumOverflow)?;685686 CreatedCollectionCount::put(next_id);687688 let limits = CollectionLimits {689 sponsored_data_size: chain_limit.custom_data_limit,690 ..Default::default()691 };692693 694 let new_collection = CollectionType {695 owner: who.clone(),696 name: collection_name,697 mode: mode.clone(),698 mint_mode: false,699 access: AccessMode::Normal,700 description: collection_description,701 decimal_points: decimal_points,702 token_prefix: token_prefix,703 offchain_schema: Vec::new(),704 schema_version: SchemaVersion::ImageURL,705 sponsorship: SponsorshipState::Disabled,706 variable_on_chain_schema: Vec::new(),707 const_on_chain_schema: Vec::new(),708 limits,709 };710711 712 <Collection<T>>::insert(next_id, new_collection);713714 715 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));716717 Ok(())718 }719720 721 722 723 724 725 726 727 728 729 #[weight = <T as Config>::WeightInfo::destroy_collection()]730 #[transactional]731 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {732733 let sender = ensure_signed(origin)?;734 Self::check_owner_permissions(collection_id, sender)?;735736 let target_collection = <Collection<T>>::get(collection_id);737 if !target_collection.limits.owner_can_destroy {738 fail!(Error::<T>::NoPermission);739 }740741 <AddressTokens<T>>::remove_prefix(collection_id);742 <Allowances<T>>::remove_prefix(collection_id);743 <Balance<T>>::remove_prefix(collection_id);744 <ItemListIndex>::remove(collection_id);745 <AdminList<T>>::remove(collection_id);746 <Collection<T>>::remove(collection_id);747 <WhiteList<T>>::remove_prefix(collection_id);748749 <NftItemList<T>>::remove_prefix(collection_id);750 <FungibleItemList<T>>::remove_prefix(collection_id);751 <ReFungibleItemList<T>>::remove_prefix(collection_id);752753 <NftTransferBasket<T>>::remove_prefix(collection_id);754 <FungibleTransferBasket<T>>::remove_prefix(collection_id);755 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);756757 DestroyedCollectionCount::put(DestroyedCollectionCount::get()758 .checked_add(1)759 .ok_or(Error::<T>::NumOverflow)?);760761 Ok(())762 }763764 765 766 767 768 769 770 771 772 773 774 775 776 #[weight = <T as Config>::WeightInfo::add_to_white_list()]777 #[transactional]778 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{779780 let sender = ensure_signed(origin)?;781 Self::check_owner_or_admin_permissions(collection_id, sender)?;782783 <WhiteList<T>>::insert(collection_id, address, true);784 785 Ok(())786 }787788 789 790 791 792 793 794 795 796 797 798 799 800 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]801 #[transactional]802 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{803804 let sender = ensure_signed(origin)?;805 Self::check_owner_or_admin_permissions(collection_id, sender)?;806807 <WhiteList<T>>::remove(collection_id, address);808809 Ok(())810 }811812 813 814 815 816 817 818 819 820 821 822 823 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]824 #[transactional]825 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult826 {827 let sender = ensure_signed(origin)?;828829 Self::check_owner_permissions(collection_id, sender)?;830 let mut target_collection = <Collection<T>>::get(collection_id);831 target_collection.access = mode;832 <Collection<T>>::insert(collection_id, target_collection);833834 Ok(())835 }836837 838 839 840 841 842 843 844 845 846 847 848 849 850 #[weight = <T as Config>::WeightInfo::set_mint_permission()]851 #[transactional]852 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult853 {854 let sender = ensure_signed(origin)?;855856 Self::check_owner_permissions(collection_id, sender)?;857 let mut target_collection = <Collection<T>>::get(collection_id);858 target_collection.mint_mode = mint_permission;859 <Collection<T>>::insert(collection_id, target_collection);860861 Ok(())862 }863864 865 866 867 868 869 870 871 872 873 874 875 #[weight = <T as Config>::WeightInfo::change_collection_owner()]876 #[transactional]877 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {878879 let sender = ensure_signed(origin)?;880 Self::check_owner_permissions(collection_id, sender)?;881 let mut target_collection = <Collection<T>>::get(collection_id);882 target_collection.owner = new_owner;883 <Collection<T>>::insert(collection_id, target_collection);884885 Ok(())886 }887888 889 890 891 892 893 894 895 896 897 898 899 900 901 #[weight = <T as Config>::WeightInfo::add_collection_admin()]902 #[transactional]903 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {904905 let sender = ensure_signed(origin)?;906 Self::check_owner_or_admin_permissions(collection_id, sender)?;907 let mut admin_arr: Vec<T::AccountId> = Vec::new();908909 if <AdminList<T>>::contains_key(collection_id)910 {911 admin_arr = <AdminList<T>>::get(collection_id);912 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);913 }914915 916 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);917918 admin_arr.push(new_admin_id);919 <AdminList<T>>::insert(collection_id, admin_arr);920921 Ok(())922 }923924 925 926 927 928 929 930 931 932 933 934 935 936 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]937 #[transactional]938 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {939940 let sender = ensure_signed(origin)?;941 Self::check_owner_or_admin_permissions(collection_id, sender)?;942 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);943944 let mut admin_arr = <AdminList<T>>::get(collection_id);945 admin_arr.retain(|i| *i != account_id);946 <AdminList<T>>::insert(collection_id, admin_arr);947948 Ok(())949 }950951 952 953 954 955 956 957 958 959 960 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]961 #[transactional]962 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {963964 let sender = ensure_signed(origin)?;965 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);966967 let mut target_collection = <Collection<T>>::get(collection_id);968 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);969970 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);971 <Collection<T>>::insert(collection_id, target_collection);972973 Ok(())974 }975976 977 978 979 980 981 982 983 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]984 #[transactional]985 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {986987 let sender = ensure_signed(origin)?;988 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);989990 let mut target_collection = <Collection<T>>::get(collection_id);991 ensure!(992 target_collection.sponsorship.pending_sponsor() == Some(&sender),993 Error::<T>::ConfirmUnsetSponsorFail994 );995996 target_collection.sponsorship = SponsorshipState::Confirmed(sender);997 <Collection<T>>::insert(collection_id, target_collection);998999 Ok(())1000 }10011002 1003 1004 1005 1006 1007 1008 1009 1010 1011 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]1012 #[transactional]1013 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {10141015 let sender = ensure_signed(origin)?;1016 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);10171018 let mut target_collection = <Collection<T>>::get(collection_id);1019 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);10201021 target_collection.sponsorship = SponsorshipState::Disabled;1022 <Collection<T>>::insert(collection_id, target_collection);10231024 Ok(())1025 }10261027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 10501051 #[weight = <T as Config>::WeightInfo::create_item(data.len())]1052 #[transactional]1053 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {10541055 let sender = ensure_signed(origin)?;10561057 Self::collection_exists(collection_id)?;10581059 let target_collection = <Collection<T>>::get(collection_id);10601061 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;1062 Self::validate_create_item_args(&target_collection, &data)?;1063 Self::create_item_no_validation(collection_id, owner, data)?;10641065 Ok(())1066 }10671068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()1087 .map(|data| { data.len() })1088 .sum())]1089 #[transactional]1090 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {10911092 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1093 let sender = ensure_signed(origin)?;10941095 Self::collection_exists(collection_id)?;1096 let target_collection = <Collection<T>>::get(collection_id);10971098 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;10991100 for data in &items_data {1101 Self::validate_create_item_args(&target_collection, data)?;1102 }1103 for data in &items_data {1104 Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1105 }11061107 Ok(())1108 }11091110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 #[weight = <T as Config>::WeightInfo::burn_item()]1124 #[transactional]1125 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {11261127 let sender = ensure_signed(origin)?;1128 Self::collection_exists(collection_id)?;11291130 1131 let target_collection = <Collection<T>>::get(collection_id);1132 ensure!(1133 Self::is_item_owner(sender.clone(), collection_id, item_id) ||1134 (1135 target_collection.limits.owner_can_transfer &&1136 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1137 ),1138 Error::<T>::NoPermission1139 );11401141 if target_collection.access == AccessMode::WhiteList {1142 Self::check_white_list(collection_id, &sender)?;1143 }11441145 match target_collection.mode1146 {1147 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1148 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1149 CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?,1150 _ => ()1151 };11521153 1154 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));11551156 Ok(())1157 }11581159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 #[weight = <T as Config>::WeightInfo::transfer()]1183 #[transactional]1184 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1185 let sender = ensure_signed(origin)?;1186 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1187 }11881189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 #[weight = <T as Config>::WeightInfo::approve()]1205 #[transactional]1206 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {12071208 let sender = ensure_signed(origin)?;12091210 Self::collection_exists(collection_id)?;1211 Self::token_exists(collection_id, item_id, &sender)?;12121213 1214 let target_collection = <Collection<T>>::get(collection_id);1215 let allowance_limit = if target_collection.limits.owner_can_transfer &&1216 Self::is_owner_or_admin_permissions(1217 collection_id,1218 sender.clone(),1219 ) {1220 None1221 } else if let Some(amount) = Self::owned_amount(1222 sender.clone(),1223 collection_id,1224 item_id,1225 ) {1226 Some(amount)1227 } else {1228 fail!(Error::<T>::NoPermission);1229 };12301231 if target_collection.access == AccessMode::WhiteList {1232 Self::check_white_list(collection_id, &sender)?;1233 Self::check_white_list(collection_id, &spender)?;1234 }12351236 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1237 let mut allowance: u128 = amount;1238 if allowance_exists {1239 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1240 }1241 if let Some(limit) = allowance_limit {1242 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1243 }1244 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);12451246 Ok(())1247 }1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 #[weight = <T as Config>::WeightInfo::transfer_from()]1269 #[transactional]1270 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {12711272 let sender = ensure_signed(origin)?;1273 let mut appoved_transfer = false;12741275 1276 let mut approval: u128 = 0;1277 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1278 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1279 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1280 appoved_transfer = true;1281 }12821283 let target_collection = <Collection<T>>::get(collection_id);12841285 1286 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;12871288 1289 ensure!(1290 appoved_transfer || 1291 (1292 target_collection.limits.owner_can_transfer &&1293 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1294 ),1295 Error::<T>::NoPermission1296 );12971298 if target_collection.access == AccessMode::WhiteList {1299 Self::check_white_list(collection_id, &sender)?;1300 Self::check_white_list(collection_id, &recipient)?;1301 }13021303 1304 if approval.checked_sub(value).unwrap_or(0) > 0 {1305 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1306 }1307 else {1308 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1309 }13101311 match target_collection.mode1312 {1313 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1314 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1315 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1316 _ => ()1317 };13181319 Ok(())1320 }13211322 1323 13241325 1326 1327 1328 13291330 13311332 13331334 1335 13361337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1350 #[transactional]1351 pub fn set_variable_meta_data (1352 origin,1353 collection_id: CollectionId,1354 item_id: TokenId,1355 data: Vec<u8>1356 ) -> DispatchResult {1357 let sender = ensure_signed(origin)?;1358 1359 Self::collection_exists(collection_id)?;1360 Self::token_exists(collection_id, item_id, &sender)?;13611362 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);13631364 1365 let target_collection = <Collection<T>>::get(collection_id);1366 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1367 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1368 Error::<T>::NoPermission);13691370 match target_collection.mode1371 {1372 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1373 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1374 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1375 _ => fail!(Error::<T>::UnexpectedCollectionType)1376 };13771378 Ok(())1379 }1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 #[weight = <T as Config>::WeightInfo::set_schema_version()]1396 #[transactional]1397 pub fn set_schema_version(1398 origin,1399 collection_id: CollectionId,1400 version: SchemaVersion1401 ) -> DispatchResult {1402 let sender = ensure_signed(origin)?;1403 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1404 let mut target_collection = <Collection<T>>::get(collection_id);1405 target_collection.schema_version = version;1406 <Collection<T>>::insert(collection_id, target_collection);14071408 Ok(())1409 }14101411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1424 #[transactional]1425 pub fn set_offchain_schema(1426 origin,1427 collection_id: CollectionId,1428 schema: Vec<u8>1429 ) -> DispatchResult {1430 let sender = ensure_signed(origin)?;1431 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14321433 1434 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");14351436 let mut target_collection = <Collection<T>>::get(collection_id);1437 target_collection.offchain_schema = schema;1438 <Collection<T>>::insert(collection_id, target_collection);14391440 Ok(())1441 }14421443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1456 #[transactional]1457 pub fn set_const_on_chain_schema (1458 origin,1459 collection_id: CollectionId,1460 schema: Vec<u8>1461 ) -> DispatchResult {1462 let sender = ensure_signed(origin)?;1463 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14641465 1466 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");14671468 let mut target_collection = <Collection<T>>::get(collection_id);1469 target_collection.const_on_chain_schema = schema;1470 <Collection<T>>::insert(collection_id, target_collection);14711472 Ok(())1473 }14741475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1488 #[transactional]1489 pub fn set_variable_on_chain_schema (1490 origin,1491 collection_id: CollectionId,1492 schema: Vec<u8>1493 ) -> DispatchResult {1494 let sender = ensure_signed(origin)?;1495 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14961497 1498 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");14991500 let mut target_collection = <Collection<T>>::get(collection_id);1501 target_collection.variable_on_chain_schema = schema;1502 <Collection<T>>::insert(collection_id, target_collection);15031504 Ok(())1505 }15061507 1508 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1509 #[transactional]1510 pub fn set_chain_limits(1511 origin,1512 limits: ChainLimits1513 ) -> DispatchResult {15141515 #[cfg(not(feature = "runtime-benchmarks"))]1516 ensure_root(origin)?;15171518 <ChainLimit>::put(limits);1519 Ok(())1520 }15211522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1534 #[transactional]1535 pub fn enable_contract_sponsoring(1536 origin,1537 contract_address: T::AccountId,1538 enable: bool1539 ) -> DispatchResult {15401541 let sender = ensure_signed(origin)?;15421543 #[cfg(feature = "runtime-benchmarks")]1544 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15451546 Self::ensure_contract_owned(sender, &contract_address)?;15471548 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1549 Ok(())1550 }15511552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1570 #[transactional]1571 pub fn set_contract_sponsoring_rate_limit(1572 origin,1573 contract_address: T::AccountId,1574 rate_limit: T::BlockNumber1575 ) -> DispatchResult {1576 let sender = ensure_signed(origin)?;15771578 #[cfg(feature = "runtime-benchmarks")]1579 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15801581 Self::ensure_contract_owned(sender, &contract_address)?;1582 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1583 Ok(())1584 }15851586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1598 #[transactional]1599 pub fn toggle_contract_white_list(1600 origin,1601 contract_address: T::AccountId,1602 enable: bool1603 ) -> DispatchResult {1604 let sender = ensure_signed(origin)?;16051606 #[cfg(feature = "runtime-benchmarks")]1607 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16081609 Self::ensure_contract_owned(sender, &contract_address)?;1610 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1611 Ok(())1612 }1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1626 #[transactional]1627 pub fn add_to_contract_white_list(1628 origin,1629 contract_address: T::AccountId,1630 account_address: T::AccountId1631 ) -> DispatchResult {1632 let sender = ensure_signed(origin)?;16331634 #[cfg(feature = "runtime-benchmarks")]1635 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1636 1637 Self::ensure_contract_owned(sender, &contract_address)?; 1638 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1639 Ok(())1640 }16411642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1654 #[transactional]1655 pub fn remove_from_contract_white_list(1656 origin,1657 contract_address: T::AccountId,1658 account_address: T::AccountId1659 ) -> DispatchResult {1660 let sender = ensure_signed(origin)?;16611662 #[cfg(feature = "runtime-benchmarks")]1663 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16641665 Self::ensure_contract_owned(sender, &contract_address)?;1666 <ContractWhiteList<T>>::remove(contract_address, account_address);1667 Ok(())1668 }16691670 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1671 #[transactional]1672 pub fn set_collection_limits(1673 origin,1674 collection_id: u32,1675 new_limits: CollectionLimits,1676 ) -> DispatchResult {1677 let sender = ensure_signed(origin)?;1678 Self::check_owner_permissions(collection_id, sender.clone())?;1679 let mut target_collection = <Collection<T>>::get(collection_id);1680 let old_limits = target_collection.limits;1681 let chain_limits = ChainLimit::get();16821683 1684 ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1685 new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1686 new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1687 Error::<T>::CollectionLimitBoundsExceeded);16881689 1690 ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1691 ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);16921693 ensure!(1694 (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1695 (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1696 Error::<T>::OwnerPermissionsCantBeReverted,1697 );16981699 target_collection.limits = new_limits;1700 <Collection<T>>::insert(collection_id, target_collection);17011702 Ok(())1703 } 1704 }1705}17061707impl<T: Config> Module<T> {17081709 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {17101711 let target_collection = <Collection<T>>::get(collection_id);17121713 1714 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;17151716 1717 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1718 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1719 Error::<T>::NoPermission);17201721 if target_collection.access == AccessMode::WhiteList {1722 Self::check_white_list(collection_id, &sender)?;1723 Self::check_white_list(collection_id, &recipient)?;1724 }17251726 match target_collection.mode1727 {1728 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1729 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1730 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1731 _ => ()1732 };17331734 Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));17351736 Ok(())1737 }173817391740 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {17411742 1743 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1744 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1745 1746 Ok(())1747 }17481749 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {17501751 1752 let total_items: u32 = ItemListIndex::get(collection_id);1753 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1754 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1755 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);17561757 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1758 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1759 Self::check_white_list(collection_id, owner)?;1760 Self::check_white_list(collection_id, sender)?;1761 }17621763 Ok(())1764 }17651766 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1767 match target_collection.mode1768 {1769 CollectionMode::NFT => {1770 if let CreateItemData::NFT(data) = data {1771 1772 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1773 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1774 } else {1775 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1776 }1777 },1778 CollectionMode::Fungible(_) => {1779 if let CreateItemData::Fungible(_) = data {1780 } else {1781 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1782 }1783 },1784 CollectionMode::ReFungible => {1785 if let CreateItemData::ReFungible(data) = data {17861787 1788 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1789 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);17901791 1792 ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1793 ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1794 } else {1795 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1796 }1797 },1798 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1799 };18001801 Ok(())1802 }18031804 fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1805 match data1806 {1807 CreateItemData::NFT(data) => {1808 let item = NftItemType {1809 owner: owner.clone(),1810 const_data: data.const_data,1811 variable_data: data.variable_data1812 };18131814 Self::add_nft_item(collection_id, item)?;1815 },1816 CreateItemData::Fungible(data) => {1817 Self::add_fungible_item(collection_id, &owner, data.value)?;1818 },1819 CreateItemData::ReFungible(data) => {1820 let mut owner_list = Vec::new();1821 owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});18221823 let item = ReFungibleItemType {1824 owner: owner_list,1825 const_data: data.const_data,1826 variable_data: data.variable_data1827 };18281829 Self::add_refungible_item(collection_id, item)?;1830 }1831 };18321833 Ok(())1834 }18351836 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {18371838 1839 let mut balance: u128 = 0;1840 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1841 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1842 } 18431844 1845 let item = FungibleItemType {1846 value: balance + value1847 };1848 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);18491850 1851 let new_balance = <Balance<T>>::get(collection_id, owner)1852 .checked_add(value)1853 .ok_or(Error::<T>::NumOverflow)?;1854 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18551856 Self::deposit_event(RawEvent::ItemCreated(collection_id, 0, owner.clone()));1857 Ok(())1858 }18591860 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1861 let current_index = <ItemListIndex>::get(collection_id)1862 .checked_add(1)1863 .ok_or(Error::<T>::NumOverflow)?;1864 let itemcopy = item.clone();18651866 let value = item.owner.first().unwrap().fraction;1867 let owner = item.owner.first().unwrap().owner.clone();18681869 Self::add_token_index(collection_id, current_index, &owner)?;18701871 <ItemListIndex>::insert(collection_id, current_index);1872 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);18731874 1875 let new_balance = <Balance<T>>::get(collection_id, &owner)1876 .checked_add(value)1877 .ok_or(Error::<T>::NumOverflow)?;1878 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);18791880 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, owner));1881 Ok(())1882 }18831884 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1885 let current_index = <ItemListIndex>::get(collection_id)1886 .checked_add(1)1887 .ok_or(Error::<T>::NumOverflow)?;18881889 let item_owner = item.owner.clone();1890 Self::add_token_index(collection_id, current_index, &item.owner)?;18911892 <ItemListIndex>::insert(collection_id, current_index);1893 <NftItemList<T>>::insert(collection_id, current_index, item);18941895 1896 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1897 .checked_add(1)1898 .ok_or(Error::<T>::NumOverflow)?;1899 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);19001901 Self::deposit_event(RawEvent::ItemCreated(collection_id, current_index, item_owner));1902 Ok(())1903 }19041905 fn burn_refungible_item(1906 collection_id: CollectionId,1907 item_id: TokenId,1908 owner: &T::AccountId,1909 ) -> DispatchResult {1910 ensure!(1911 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1912 Error::<T>::TokenNotFound1913 );1914 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1915 let rft_balance = token1916 .owner1917 .iter()1918 .filter(|&i| i.owner == *owner)1919 .next()1920 .unwrap();1921 Self::remove_token_index(collection_id, item_id, owner)?;19221923 1924 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1925 .checked_sub(rft_balance.fraction)1926 .ok_or(Error::<T>::NumOverflow)?;1927 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);19281929 1930 let index = token1931 .owner1932 .iter()1933 .position(|i| i.owner == *owner)1934 .unwrap();1935 token.owner.remove(index);1936 let owner_count = token.owner.len();19371938 1939 if owner_count == 0 {1940 <ReFungibleItemList<T>>::remove(collection_id, item_id);1941 }1942 else {1943 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1944 }19451946 Ok(())1947 }19481949 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1950 ensure!(1951 <NftItemList<T>>::contains_key(collection_id, item_id),1952 Error::<T>::TokenNotFound1953 );1954 let item = <NftItemList<T>>::get(collection_id, item_id);1955 Self::remove_token_index(collection_id, item_id, &item.owner)?;19561957 1958 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1959 .checked_sub(1)1960 .ok_or(Error::<T>::NumOverflow)?;1961 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1962 <NftItemList<T>>::remove(collection_id, item_id);19631964 Ok(())1965 }19661967 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1968 ensure!(1969 <FungibleItemList<T>>::contains_key(collection_id, owner),1970 Error::<T>::TokenNotFound1971 );1972 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1973 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);19741975 1976 let new_balance = <Balance<T>>::get(collection_id, owner)1977 .checked_sub(value)1978 .ok_or(Error::<T>::NumOverflow)?;1979 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);19801981 if balance.value - value > 0 {1982 balance.value -= value;1983 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1984 }1985 else {1986 <FungibleItemList<T>>::remove(collection_id, owner);1987 }19881989 Ok(())1990 }19911992 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1993 ensure!(1994 <Collection<T>>::contains_key(collection_id),1995 Error::<T>::CollectionNotFound1996 );1997 Ok(())1998 }19992000 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {2001 Self::collection_exists(collection_id)?;20022003 let target_collection = <Collection<T>>::get(collection_id);2004 ensure!(2005 subject == target_collection.owner,2006 Error::<T>::NoPermission2007 );20082009 Ok(())2010 }20112012 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {2013 let target_collection = <Collection<T>>::get(collection_id);2014 let mut result: bool = subject == target_collection.owner;2015 let exists = <AdminList<T>>::contains_key(collection_id);20162017 if !result & exists {2018 if <AdminList<T>>::get(collection_id).contains(&subject) {2019 result = true2020 }2021 }20222023 result2024 }20252026 fn check_owner_or_admin_permissions(2027 collection_id: CollectionId,2028 subject: T::AccountId,2029 ) -> DispatchResult {2030 Self::collection_exists(collection_id)?;2031 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());20322033 ensure!(2034 result,2035 Error::<T>::NoPermission2036 );2037 Ok(())2038 }20392040 fn owned_amount(2041 subject: T::AccountId,2042 collection_id: CollectionId,2043 item_id: TokenId,2044 ) -> Option<u128> {2045 let target_collection = <Collection<T>>::get(collection_id);20462047 match target_collection.mode {2048 CollectionMode::NFT => {2049 if <NftItemList<T>>::get(collection_id, item_id).owner == subject {2050 return Some(1)2051 }2052 None2053 },2054 CollectionMode::Fungible(_) => {2055 if <FungibleItemList<T>>::contains_key(collection_id, &subject) {2056 return Some(<FungibleItemList<T>>::get(collection_id, &subject)2057 .value);2058 }2059 None2060 },2061 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)2062 .owner2063 .iter()2064 .find(|i| i.owner == subject)2065 .map(|i| i.fraction),2066 CollectionMode::Invalid => None,2067 }2068 }20692070 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {2071 let target_collection = <Collection<T>>::get(collection_id);20722073 match target_collection.mode {2074 CollectionMode::NFT => {2075 <NftItemList<T>>::get(collection_id, item_id).owner == subject2076 }2077 CollectionMode::Fungible(_) => {2078 <FungibleItemList<T>>::contains_key(collection_id, &subject)2079 }2080 CollectionMode::ReFungible => {2081 <ReFungibleItemList<T>>::get(collection_id, item_id)2082 .owner2083 .iter()2084 .any(|i| i.owner == subject)2085 }2086 CollectionMode::Invalid => false,2087 }2088 }20892090 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {2091 let mes = Error::<T>::AddresNotInWhiteList;2092 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);20932094 Ok(())2095 }20962097 2098 2099 fn token_exists(2100 collection_id: CollectionId,2101 item_id: TokenId,2102 owner: &T::AccountId2103 ) -> DispatchResult {2104 let target_collection = <Collection<T>>::get(collection_id);2105 let exists = match target_collection.mode2106 {2107 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2108 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),2109 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2110 _ => false2111 };21122113 ensure!(exists == true, Error::<T>::TokenNotFound);2114 Ok(())2115 }21162117 fn transfer_fungible(2118 collection_id: CollectionId,2119 value: u128,2120 owner: &T::AccountId,2121 recipient: &T::AccountId,2122 ) -> DispatchResult {2123 Self::token_exists(collection_id, 0, owner)?;21242125 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2126 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);21272128 2129 Self::add_fungible_item(collection_id, recipient, value)?;21302131 2132 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);21332134 2135 if balance.value == value {2136 <FungibleItemList<T>>::remove(collection_id, owner);2137 }2138 else {2139 balance.value -= value;2140 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2141 }21422143 Ok(())2144 }21452146 fn transfer_refungible(2147 collection_id: CollectionId,2148 item_id: TokenId,2149 value: u128,2150 owner: T::AccountId,2151 new_owner: T::AccountId,2152 ) -> DispatchResult {2153 Self::token_exists(collection_id, item_id, &owner)?;21542155 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2156 let item = full_item2157 .owner2158 .iter()2159 .filter(|i| i.owner == owner)2160 .next()2161 .ok_or(Error::<T>::NumOverflow)?;2162 let amount = item.fraction;21632164 ensure!(amount >= value, Error::<T>::TokenValueTooLow);21652166 2167 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2168 .checked_sub(value)2169 .ok_or(Error::<T>::NumOverflow)?;2170 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);21712172 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2173 .checked_add(value)2174 .ok_or(Error::<T>::NumOverflow)?;2175 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);21762177 let old_owner = item.owner.clone();2178 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);21792180 2181 if amount == value && !new_owner_has_account {2182 2183 2184 let mut new_full_item = full_item.clone();2185 new_full_item2186 .owner2187 .iter_mut()2188 .find(|i| i.owner == owner)2189 .unwrap()2190 .owner = new_owner.clone();2191 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);21922193 2194 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;2195 } else {2196 let mut new_full_item = full_item.clone();2197 new_full_item2198 .owner2199 .iter_mut()2200 .find(|i| i.owner == owner)2201 .unwrap()2202 .fraction -= value;22032204 2205 if new_owner_has_account {2206 2207 new_full_item2208 .owner2209 .iter_mut()2210 .find(|i| i.owner == new_owner)2211 .unwrap()2212 .fraction += value;2213 } else {2214 2215 new_full_item.owner.push(Ownership {2216 owner: new_owner.clone(),2217 fraction: value,2218 });2219 Self::add_token_index(collection_id, item_id, &new_owner)?;2220 }22212222 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2223 }22242225 Ok(())2226 }22272228 fn transfer_nft(2229 collection_id: CollectionId,2230 item_id: TokenId,2231 sender: T::AccountId,2232 new_owner: T::AccountId,2233 ) -> DispatchResult {2234 Self::token_exists(collection_id, item_id, &sender)?;22352236 let mut item = <NftItemList<T>>::get(collection_id, item_id);22372238 ensure!(2239 sender == item.owner,2240 Error::<T>::MustBeTokenOwner2241 );22422243 2244 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2245 .checked_sub(1)2246 .ok_or(Error::<T>::NumOverflow)?;2247 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);22482249 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2250 .checked_add(1)2251 .ok_or(Error::<T>::NumOverflow)?;2252 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);22532254 2255 let old_owner = item.owner.clone();2256 item.owner = new_owner.clone();2257 <NftItemList<T>>::insert(collection_id, item_id, item);22582259 2260 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;22612262 Ok(())2263 }2264 2265 fn set_re_fungible_variable_data(2266 collection_id: CollectionId,2267 item_id: TokenId,2268 data: Vec<u8>2269 ) -> DispatchResult {2270 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);22712272 item.variable_data = data;22732274 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);22752276 Ok(())2277 }22782279 fn set_nft_variable_data(2280 collection_id: CollectionId,2281 item_id: TokenId,2282 data: Vec<u8>2283 ) -> DispatchResult {2284 let mut item = <NftItemList<T>>::get(collection_id, item_id);2285 2286 item.variable_data = data;22872288 <NftItemList<T>>::insert(collection_id, item_id, item);2289 2290 Ok(())2291 }22922293 fn init_collection(item: &CollectionType<T::AccountId>) {2294 2295 assert!(2296 item.decimal_points <= MAX_DECIMAL_POINTS,2297 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2298 );2299 assert!(2300 item.name.len() <= 64,2301 "Collection name can not be longer than 63 char"2302 );2303 assert!(2304 item.name.len() <= 256,2305 "Collection description can not be longer than 255 char"2306 );2307 assert!(2308 item.token_prefix.len() <= 16,2309 "Token prefix can not be longer than 15 char"2310 );23112312 2313 let next_id = CreatedCollectionCount::get()2314 .checked_add(1)2315 .unwrap();23162317 CreatedCollectionCount::put(next_id);2318 }23192320 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2321 let current_index = <ItemListIndex>::get(collection_id)2322 .checked_add(1)2323 .unwrap();23242325 let item_owner = item.owner.clone();2326 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();23272328 <ItemListIndex>::insert(collection_id, current_index);23292330 2331 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2332 .checked_add(1)2333 .unwrap();2334 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2335 }23362337 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2338 let current_index = <ItemListIndex>::get(collection_id)2339 .checked_add(1)2340 .unwrap();23412342 Self::add_token_index(collection_id, current_index, owner).unwrap();23432344 <ItemListIndex>::insert(collection_id, current_index);23452346 2347 let new_balance = <Balance<T>>::get(collection_id, owner)2348 .checked_add(item.value)2349 .unwrap();2350 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2351 }23522353 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2354 let current_index = <ItemListIndex>::get(collection_id)2355 .checked_add(1)2356 .unwrap();23572358 let value = item.owner.first().unwrap().fraction;2359 let owner = item.owner.first().unwrap().owner.clone();23602361 Self::add_token_index(collection_id, current_index, &owner).unwrap();23622363 <ItemListIndex>::insert(collection_id, current_index);23642365 2366 let new_balance = <Balance<T>>::get(collection_id, &owner)2367 .checked_add(value)2368 .unwrap();2369 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2370 }23712372 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {23732374 2375 if <AccountItemCount<T>>::contains_key(owner) {23762377 2378 let count = <AccountItemCount<T>>::get(owner);2379 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);23802381 <AccountItemCount<T>>::insert(owner.clone(), count2382 .checked_add(1)2383 .ok_or(Error::<T>::NumOverflow)?);2384 }2385 else {2386 <AccountItemCount<T>>::insert(owner.clone(), 1);2387 }23882389 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2390 if list_exists {2391 let mut list = <AddressTokens<T>>::get(collection_id, owner);2392 let item_contains = list.contains(&item_index.clone());23932394 if !item_contains {2395 list.push(item_index.clone());2396 }23972398 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2399 } else {2400 let mut itm = Vec::new();2401 itm.push(item_index.clone());2402 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2403 }24042405 Ok(())2406 }24072408 fn remove_token_index(2409 collection_id: CollectionId,2410 item_index: TokenId,2411 owner: &T::AccountId,2412 ) -> DispatchResult {24132414 2415 <AccountItemCount<T>>::insert(owner.clone(), 2416 <AccountItemCount<T>>::get(owner)2417 .checked_sub(1)2418 .ok_or(Error::<T>::NumOverflow)?);241924202421 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2422 if list_exists {2423 let mut list = <AddressTokens<T>>::get(collection_id, owner);2424 let item_contains = list.contains(&item_index.clone());24252426 if item_contains {2427 list.retain(|&item| item != item_index);2428 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2429 }2430 }24312432 Ok(())2433 }24342435 fn move_token_index(2436 collection_id: CollectionId,2437 item_index: TokenId,2438 old_owner: &T::AccountId,2439 new_owner: &T::AccountId,2440 ) -> DispatchResult {2441 Self::remove_token_index(collection_id, item_index, old_owner)?;2442 Self::add_token_index(collection_id, item_index, new_owner)?;24432444 Ok(())2445 }2446 2447 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2448 if <ContractOwner<T>>::contains_key(contract.clone()) {2449 let owner = <ContractOwner<T>>::get(contract);2450 ensure!(account == owner, Error::<T>::NoPermission);2451 } else {2452 fail!(Error::<T>::NoPermission);2453 }24542455 Ok(())2456 }2457}2458245924602461246224632464pub type Multiplier = FixedU128;24652466type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;2467246824692470#[derive(Encode, Decode, Clone, Eq, PartialEq)]2471pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);24722473impl<T: Config + Send + Sync> sp_std::fmt::Debug 2474 for ChargeTransactionPayment<T>2475{2476 #[cfg(feature = "std")]2477 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2478 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2479 }2480 #[cfg(not(feature = "std"))]2481 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2482 Ok(())2483 }2484}24852486impl<T: Config> ChargeTransactionPayment<T>2487where2488 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2489 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2490 T::AccountId: AsRef<[u8]>,2491 T::AccountId: UncheckedFrom<T::Hash>,2492{2493 fn traditional_fee(2494 len: usize,2495 info: &DispatchInfoOf<T::Call>,2496 tip: BalanceOf<T>,2497 ) -> BalanceOf<T>2498 where2499 T::Call: Dispatchable<Info = DispatchInfo>,2500 {2501 <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2502 }25032504 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2505 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2506 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2507 let len_saturation = max_block_length as u64 / (len as u64).max(1);2508 let coefficient: BalanceOf<T> = weight_saturation2509 .min(len_saturation)2510 .saturated_into::<BalanceOf<T>>();2511 final_fee2512 .saturating_mul(coefficient)2513 .saturated_into::<TransactionPriority>()2514 }25152516 fn withdraw_fee(2517 &self,2518 who: &T::AccountId,2519 call: &T::Call,2520 info: &DispatchInfoOf<T::Call>,2521 len: usize,2522 ) -> Result<2523 (2524 BalanceOf<T>,2525 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2526 ),2527 TransactionValidityError,2528 > {2529 let tip = self.0;25302531 2532 2533 2534 2535 2536 2537 2538 let fee = Self::traditional_fee(len, info, tip);25392540 2541 if fee.is_zero() {2542 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2543 .map(|i| (fee, i));2544 }25452546 2547 2548 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2549 Some(Call::create_item(collection_id, _owner, _properties)) => {25502551 2552 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;25532554 let collection = <Collection<T>>::get(collection_id);25552556 let limit = collection.limits.sponsor_transfer_timeout;2557 let mut sponsored = true;2558 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2559 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2560 let limit_time = last_tx_block + limit.into();2561 if block_number <= limit_time {2562 sponsored = false;2563 }2564 }2565 if sponsored {2566 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2567 }25682569 2570 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&2571 (sponsored)2572 {2573 collection.sponsorship.sponsor()2574 .cloned()2575 .unwrap_or_default()2576 } else {2577 T::AccountId::default()2578 }2579 }2580 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2581 2582 let mut sponsor_transfer = false;2583 if <Collection<T>>::get(collection_id).sponsorship.confirmed() {25842585 let collection_limits = <Collection<T>>::get(collection_id).limits;2586 let collection_mode = <Collection<T>>::get(collection_id).mode;2587 2588 2589 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2590 sponsor_transfer = match collection_mode {2591 CollectionMode::NFT => {2592 2593 2594 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2595 collection_limits.sponsor_transfer_timeout2596 } else {2597 ChainLimit::get().nft_sponsor_transfer_timeout2598 };2599 2600 let mut sponsored = true;2601 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2602 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2603 let limit_time = last_tx_block + limit.into();2604 if block_number <= limit_time {2605 sponsored = false;2606 }2607 }2608 if sponsored {2609 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2610 }26112612 sponsored2613 }2614 CollectionMode::Fungible(_) => {2615 2616 2617 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2618 collection_limits.sponsor_transfer_timeout2619 } else {2620 ChainLimit::get().fungible_sponsor_transfer_timeout2621 };2622 2623 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2624 let mut sponsored = true;2625 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2626 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2627 let limit_time = last_tx_block + limit.into();2628 if block_number <= limit_time {2629 sponsored = false;2630 }2631 }2632 if sponsored {2633 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2634 }26352636 sponsored2637 }2638 CollectionMode::ReFungible => {2639 2640 2641 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2642 collection_limits.sponsor_transfer_timeout2643 } else {2644 ChainLimit::get().refungible_sponsor_transfer_timeout2645 };2646 2647 let mut sponsored = true;2648 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2649 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2650 let limit_time = last_tx_block + limit.into();2651 if block_number <= limit_time {2652 sponsored = false;2653 }2654 }2655 if sponsored {2656 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2657 }26582659 sponsored2660 }2661 _ => {2662 false2663 },2664 };2665 }26662667 if !sponsor_transfer {2668 T::AccountId::default()2669 } else {2670 <Collection<T>>::get(collection_id).sponsorship.sponsor()2671 .cloned()2672 .unwrap_or_default()2673 }2674 }26752676 _ => T::AccountId::default(),2677 };26782679 2680 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {26812682 2683 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {26842685 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2686 &who,2687 code_hash,2688 salt,2689 );2690 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());26912692 T::AccountId::default()2693 },26942695 2696 Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt)) => {26972698 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2699 &who,2700 &T::Hashing::hash(&_code),2701 _salt,2702 );27032704 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());27052706 T::AccountId::default()2707 }27082709 2710 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {27112712 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());27132714 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2715 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2716 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2717 2718 if !owned_contract && white_list_enabled {2719 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2720 return Err(InvalidTransaction::Call.into());2721 }2722 }27232724 let mut sponsor_transfer = false;2725 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2726 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2727 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2728 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2729 let limit_time = last_tx_block + rate_limit;27302731 if block_number >= limit_time {2732 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2733 sponsor_transfer = true;2734 }2735 } else {2736 sponsor_transfer = false;2737 }2738 2739 2740 let mut sp = T::AccountId::default();2741 if sponsor_transfer {2742 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2743 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2744 sp = called_contract;2745 }2746 }2747 }27482749 sp2750 },27512752 _ => sponsor,2753 };27542755 let mut who_pays_fee: T::AccountId = sponsor.clone();2756 if sponsor == T::AccountId::default() {2757 who_pays_fee = who.clone();2758 }27592760 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2761 .map(|i| (fee, i))2762 }2763}276427652766impl<T: Config + Send + Sync> SignedExtension2767 for ChargeTransactionPayment<T>2768where2769 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2770 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2771 T::AccountId: AsRef<[u8]>,2772 T::AccountId: UncheckedFrom<T::Hash>,2773{2774 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2775 type AccountId = T::AccountId;2776 type Call = T::Call;2777 type AdditionalSigned = ();2778 type Pre = (2779 2780 BalanceOf<T>,2781 2782 Self::AccountId,2783 2784 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2785 );2786 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2787 Ok(())2788 }27892790 fn validate(2791 &self,2792 who: &Self::AccountId,2793 call: &Self::Call,2794 info: &DispatchInfoOf<Self::Call>,2795 len: usize,2796 ) -> TransactionValidity {2797 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2798 Ok(ValidTransaction {2799 priority: Self::get_priority(len, info, fee),2800 ..Default::default()2801 })2802 }28032804 fn pre_dispatch(2805 self,2806 who: &Self::AccountId,2807 call: &Self::Call,2808 info: &DispatchInfoOf<Self::Call>,2809 len: usize,2810 ) -> Result<Self::Pre, TransactionValidityError> {2811 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2812 Ok((self.0, who.clone(), imbalance))2813 }28142815 fn post_dispatch(2816 pre: Self::Pre,2817 info: &DispatchInfoOf<Self::Call>,2818 post_info: &PostDispatchInfoOf<Self::Call>,2819 len: usize,2820 _result: &DispatchResult,2821 ) -> Result<(), TransactionValidityError> {2822 let (tip, who, imbalance) = pre;2823 let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(2824 len as u32,2825 info,2826 post_info,2827 tip,2828 );2829 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2830 Ok(())2831 }2832}28332834