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};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36 traits::{37 Hash, DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38 },39 transaction_validity::{40 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41 },42 FixedPointOperand, FixedU128,43};44use sp_runtime::traits::StaticLookup;45use pallet_contracts::chain_extension::UncheckedFrom;46use pallet_transaction_payment::OnChargeTransaction;4748#[cfg(test)]49mod mock;5051#[cfg(test)]52mod tests;5354mod default_weights;5556pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;57pub const MAX_REFUNGIBLE_PIECES: u128 = 1_000_000_000_000_000_000_000;58pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;59pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;6061626364pub type CollectionId = u32;65pub type TokenId = u32;66pub type DecimalPoints = u8;6768#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]69#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]70pub enum CollectionMode {71 Invalid,72 NFT,73 74 Fungible(DecimalPoints),75 ReFungible,76}7778impl Default for CollectionMode {79 fn default() -> Self {80 Self::Invalid81 }82}8384impl Into<u8> for CollectionMode {85 fn into(self) -> u8 {86 match self {87 CollectionMode::Invalid => 0,88 CollectionMode::NFT => 1,89 CollectionMode::Fungible(_) => 2,90 CollectionMode::ReFungible => 3,91 }92 }93}9495#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]96#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]97pub enum AccessMode {98 Normal,99 WhiteList,100}101impl Default for AccessMode {102 fn default() -> Self {103 Self::Normal104 }105}106107#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]108#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]109pub enum SchemaVersion {110 ImageURL,111 Unique,112}113impl Default for SchemaVersion {114 fn default() -> Self {115 Self::ImageURL116 }117}118119#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]120#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]121pub struct Ownership<AccountId> {122 pub owner: AccountId,123 pub fraction: u128,124}125126#[derive(Encode, Decode, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub enum SponsorshipState<AccountId> {129 130 Disabled,131 Unconfirmed(AccountId),132 133 Confirmed(AccountId),134}135136impl<AccountId> SponsorshipState<AccountId> {137 fn sponsor(&self) -> Option<&AccountId> {138 match self {139 Self::Confirmed(sponsor) => Some(sponsor),140 _ => None,141 }142 }143144 fn pending_sponsor(&self) -> Option<&AccountId> {145 match self {146 Self::Unconfirmed(sponsor) | Self::Confirmed(sponsor) => Some(sponsor),147 _ => None,148 }149 }150151 fn confirmed(&self) -> bool {152 matches!(self, Self::Confirmed(_))153 }154}155156impl<T> Default for SponsorshipState<T> {157 fn default() -> Self {158 Self::Disabled159 }160}161162#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]163#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]164pub struct CollectionType<AccountId> {165 pub owner: AccountId,166 pub mode: CollectionMode,167 pub access: AccessMode,168 pub decimal_points: DecimalPoints,169 pub name: Vec<u16>, 170 pub description: Vec<u16>, 171 pub token_prefix: Vec<u8>, 172 pub mint_mode: bool,173 pub offchain_schema: Vec<u8>,174 pub schema_version: SchemaVersion,175 pub sponsorship: SponsorshipState<AccountId>,176 pub limits: CollectionLimits, 177 pub variable_on_chain_schema: Vec<u8>, 178 pub const_on_chain_schema: Vec<u8>, 179}180181#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]182#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]183pub struct NftItemType<AccountId> {184 pub owner: AccountId,185 pub const_data: Vec<u8>,186 pub variable_data: Vec<u8>,187}188189#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]190#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]191pub struct FungibleItemType {192 pub value: u128,193}194195#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]196#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]197pub struct ReFungibleItemType<AccountId> {198 pub owner: Vec<Ownership<AccountId>>,199 pub const_data: Vec<u8>,200 pub variable_data: Vec<u8>,201}202203204205206207208209210211212213214#[derive(Encode, Decode, Debug, Clone, PartialEq)]215#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]216pub struct CollectionLimits {217 pub account_token_ownership_limit: u32,218 pub sponsored_data_size: u32,219 pub token_limit: u32,220221 222 pub sponsor_transfer_timeout: u32,223 pub owner_can_transfer: bool,224 pub owner_can_destroy: bool,225}226227impl Default for CollectionLimits {228 fn default() -> CollectionLimits {229 CollectionLimits { 230 account_token_ownership_limit: 10_000_000, 231 token_limit: u32::max_value(),232 sponsored_data_size: u32::MAX,233 sponsor_transfer_timeout: 14400,234 owner_can_transfer: true,235 owner_can_destroy: true236 }237 }238}239240#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]241#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]242pub struct ChainLimits {243 pub collection_numbers_limit: u32,244 pub account_token_ownership_limit: u32,245 pub collections_admins_limit: u64,246 pub custom_data_limit: u32,247248 249 pub nft_sponsor_transfer_timeout: u32,250 pub fungible_sponsor_transfer_timeout: u32,251 pub refungible_sponsor_transfer_timeout: u32,252253 254 pub offchain_schema_limit: u32,255 pub variable_on_chain_schema_limit: u32,256 pub const_on_chain_schema_limit: u32,257}258259pub trait WeightInfo {260 fn create_collection() -> Weight;261 fn destroy_collection() -> Weight;262 fn add_to_white_list() -> Weight;263 fn remove_from_white_list() -> Weight;264 fn set_public_access_mode() -> Weight;265 fn set_mint_permission() -> Weight;266 fn change_collection_owner() -> Weight;267 fn add_collection_admin() -> Weight;268 fn remove_collection_admin() -> Weight;269 fn set_collection_sponsor() -> Weight;270 fn confirm_sponsorship() -> Weight;271 fn remove_collection_sponsor() -> Weight;272 fn create_item(s: usize) -> Weight;273 fn burn_item() -> Weight;274 fn transfer() -> Weight;275 fn approve() -> Weight;276 fn transfer_from() -> Weight;277 fn set_offchain_schema() -> Weight;278 fn set_const_on_chain_schema() -> Weight;279 fn set_variable_on_chain_schema() -> Weight;280 fn set_variable_meta_data() -> Weight;281 fn enable_contract_sponsoring() -> Weight;282 fn set_schema_version() -> Weight;283 fn set_chain_limits() -> Weight;284 fn set_contract_sponsoring_rate_limit() -> Weight;285 fn toggle_contract_white_list() -> Weight;286 fn add_to_contract_white_list() -> Weight;287 fn remove_from_contract_white_list() -> Weight;288 fn set_collection_limits() -> Weight;289}290291#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]292#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]293pub struct CreateNftData {294 pub const_data: Vec<u8>,295 pub variable_data: Vec<u8>,296}297298#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]299#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]300pub struct CreateFungibleData {301 pub value: u128,302}303304#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]305#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]306pub struct CreateReFungibleData {307 pub const_data: Vec<u8>,308 pub variable_data: Vec<u8>,309 pub pieces: u128,310}311312#[derive(Encode, Decode, Debug, Clone, PartialEq)]313#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]314pub enum CreateItemData {315 NFT(CreateNftData),316 Fungible(CreateFungibleData),317 ReFungible(CreateReFungibleData),318}319320impl CreateItemData {321 pub fn len(&self) -> usize {322 let len = match self {323 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),324 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),325 _ => 0326 };327 328 return len;329 }330}331332impl From<CreateNftData> for CreateItemData {333 fn from(item: CreateNftData) -> Self {334 CreateItemData::NFT(item)335 }336}337338impl From<CreateReFungibleData> for CreateItemData {339 fn from(item: CreateReFungibleData) -> Self {340 CreateItemData::ReFungible(item)341 }342}343344impl From<CreateFungibleData> for CreateItemData {345 fn from(item: CreateFungibleData) -> Self {346 CreateItemData::Fungible(item)347 }348}349350351decl_error! {352 353 pub enum Error for Module<T: Config> {354 355 TotalCollectionsLimitExceeded,356 357 CollectionDecimalPointLimitExceeded, 358 359 CollectionNameLimitExceeded, 360 361 CollectionDescriptionLimitExceeded, 362 363 CollectionTokenPrefixLimitExceeded,364 365 CollectionNotFound,366 367 TokenNotFound,368 369 AdminNotFound,370 371 NumOverflow, 372 373 AlreadyAdmin, 374 375 NoPermission,376 377 ConfirmUnsetSponsorFail,378 379 PublicMintingNotAllowed,380 381 MustBeTokenOwner,382 383 TokenValueTooLow,384 385 NftSizeLimitExceeded,386 387 ApproveNotFound,388 389 TokenValueNotEnough,390 391 ApproveRequired,392 393 AddresNotInWhiteList,394 395 CollectionAdminsLimitExceeded,396 397 AddressOwnershipLimitExceeded,398 399 EmptyArgument,400 401 TokenConstDataLimitExceeded,402 403 TokenVariableDataLimitExceeded,404 405 NotNftDataUsedToMintNftCollectionToken,406 407 NotFungibleDataUsedToMintFungibleCollectionToken,408 409 NotReFungibleDataUsedToMintReFungibleCollectionToken,410 411 UnexpectedCollectionType,412 413 CantStoreMetadataInFungibleTokens,414 415 CollectionTokenLimitExceeded,416 417 AccountTokenLimitExceeded,418 419 CollectionLimitBoundsExceeded,420 421 OwnerPermissionsCantBeReverted,422 423 SchemaDataLimitExceeded,424 425 WrongRefungiblePieces426 }427}428429pub trait Config: system::Config + Sized + pallet_transaction_payment::Config + pallet_contracts::Config {430 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;431432 433 type WeightInfo: WeightInfo;434}435436#[cfg(feature = "runtime-benchmarks")]437mod benchmarking;438439440441442443444445446447448449450451452453454455456457458459460461462463decl_storage! {464 trait Store for Module<T: Config> as Nft {465466 467 468 CreatedCollectionCount: u32;469 470 ChainVersion: u64;471 472 473 ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId;474 475476 477 pub ChainLimit get(fn chain_limit) config(): ChainLimits;478 479480 481 482 483 DestroyedCollectionCount: u32;484 485 486 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;487 488489 490 491 492 pub Collection get(fn collection) config(): map hasher(blake2_128_concat) CollectionId => CollectionType<T::AccountId>;493 494 495 pub AdminList get(fn admin_list_collection): map hasher(blake2_128_concat) CollectionId => Vec<T::AccountId>;496 497 498 pub WhiteList get(fn white_list): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => bool;499 500501 502 503 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => u128;504505 506 507 pub Allowances get(fn approved): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId, T::AccountId) => u128;508509 510 511 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => NftItemType<T::AccountId>;512 513 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => FungibleItemType;514 515 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => ReFungibleItemType<T::AccountId>;516 517518 519 520 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) T::AccountId => Vec<TokenId>;521 522523 524 525 pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;526 527 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;528 529 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;530 531 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;532 533534 535 536 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;537 538 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;539 540 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;541 542 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;543 544 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 545 546 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(blake2_128_concat) T::AccountId => bool; 547 548 }549 add_extra_genesis {550 build(|config: &GenesisConfig<T>| {551 552 for (_num, _c) in &config.collection {553 <Module<T>>::init_collection(_c);554 }555556 for (_num, _c, _i) in &config.nft_item_id {557 <Module<T>>::init_nft_token(*_c, _i);558 }559560 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {561 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);562 }563564 for (_num, _c, _i) in &config.refungible_item_id {565 <Module<T>>::init_refungible_token(*_c, _i);566 }567 })568 }569}570571decl_event!(572 pub enum Event<T>573 where574 AccountId = <T as system::Config>::AccountId,575 {576 577 578 579 580 581 582 583 584 585 Created(CollectionId, u8, AccountId),586587 588 589 590 591 592 593 594 595 596 ItemCreated(CollectionId, TokenId, AccountId),597598 599 600 601 602 603 604 605 ItemDestroyed(CollectionId, TokenId),606607 608 609 610 611 612 613 614 615 616 617 618 Transfer(CollectionId, TokenId, AccountId, AccountId, u128),619 }620);621622decl_module! {623 pub struct Module<T: Config> for enum Call 624 where 625 origin: T::Origin626 {627 fn deposit_event() = default;628 type Error = Error<T>;629630 fn on_initialize(now: T::BlockNumber) -> Weight {631 0632 }633634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 #[weight = <T as Config>::WeightInfo::create_collection()]651 pub fn create_collection(origin,652 collection_name: Vec<u16>,653 collection_description: Vec<u16>,654 token_prefix: Vec<u8>,655 mode: CollectionMode) -> DispatchResult {656657 658 let who = ensure_signed(origin)?;659660 let decimal_points = match mode {661 CollectionMode::Fungible(points) => points,662 _ => 0663 };664665 let chain_limit = ChainLimit::get();666667 let created_count = CreatedCollectionCount::get();668 let destroyed_count = DestroyedCollectionCount::get();669670 671 ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);672673 674 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);675 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);676 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);677 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);678679 680 let next_id = created_count681 .checked_add(1)682 .ok_or(Error::<T>::NumOverflow)?;683684 CreatedCollectionCount::put(next_id);685686 let limits = CollectionLimits {687 sponsored_data_size: chain_limit.custom_data_limit,688 ..Default::default()689 };690691 692 let new_collection = CollectionType {693 owner: who.clone(),694 name: collection_name,695 mode: mode.clone(),696 mint_mode: false,697 access: AccessMode::Normal,698 description: collection_description,699 decimal_points: decimal_points,700 token_prefix: token_prefix,701 offchain_schema: Vec::new(),702 schema_version: SchemaVersion::ImageURL,703 sponsorship: SponsorshipState::Disabled,704 variable_on_chain_schema: Vec::new(),705 const_on_chain_schema: Vec::new(),706 limits,707 };708709 710 <Collection<T>>::insert(next_id, new_collection);711712 713 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));714715 Ok(())716 }717718 719 720 721 722 723 724 725 726 727 #[weight = <T as Config>::WeightInfo::destroy_collection()]728 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {729730 let sender = ensure_signed(origin)?;731 Self::check_owner_permissions(collection_id, sender)?;732733 let target_collection = <Collection<T>>::get(collection_id);734 if !target_collection.limits.owner_can_destroy {735 fail!(Error::<T>::NoPermission);736 }737738 <AddressTokens<T>>::remove_prefix(collection_id);739 <Allowances<T>>::remove_prefix(collection_id);740 <Balance<T>>::remove_prefix(collection_id);741 <ItemListIndex>::remove(collection_id);742 <AdminList<T>>::remove(collection_id);743 <Collection<T>>::remove(collection_id);744 <WhiteList<T>>::remove_prefix(collection_id);745746 <NftItemList<T>>::remove_prefix(collection_id);747 <FungibleItemList<T>>::remove_prefix(collection_id);748 <ReFungibleItemList<T>>::remove_prefix(collection_id);749750 <NftTransferBasket<T>>::remove_prefix(collection_id);751 <FungibleTransferBasket<T>>::remove_prefix(collection_id);752 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);753754 DestroyedCollectionCount::put(DestroyedCollectionCount::get()755 .checked_add(1)756 .ok_or(Error::<T>::NumOverflow)?);757758 Ok(())759 }760761 762 763 764 765 766 767 768 769 770 771 772 773 #[weight = <T as Config>::WeightInfo::add_to_white_list()]774 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{775776 let sender = ensure_signed(origin)?;777 Self::check_owner_or_admin_permissions(collection_id, sender)?;778779 <WhiteList<T>>::insert(collection_id, address, true);780 781 Ok(())782 }783784 785 786 787 788 789 790 791 792 793 794 795 796 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]797 pub fn remove_from_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>>::remove(collection_id, address);803804 Ok(())805 }806807 808 809 810 811 812 813 814 815 816 817 818 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]819 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult820 {821 let sender = ensure_signed(origin)?;822823 Self::check_owner_permissions(collection_id, sender)?;824 let mut target_collection = <Collection<T>>::get(collection_id);825 target_collection.access = mode;826 <Collection<T>>::insert(collection_id, target_collection);827828 Ok(())829 }830831 832 833 834 835 836 837 838 839 840 841 842 843 844 #[weight = <T as Config>::WeightInfo::set_mint_permission()]845 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult846 {847 let sender = ensure_signed(origin)?;848849 Self::check_owner_permissions(collection_id, sender)?;850 let mut target_collection = <Collection<T>>::get(collection_id);851 target_collection.mint_mode = mint_permission;852 <Collection<T>>::insert(collection_id, target_collection);853854 Ok(())855 }856857 858 859 860 861 862 863 864 865 866 867 868 #[weight = <T as Config>::WeightInfo::change_collection_owner()]869 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {870871 let sender = ensure_signed(origin)?;872 Self::check_owner_permissions(collection_id, sender)?;873 let mut target_collection = <Collection<T>>::get(collection_id);874 target_collection.owner = new_owner;875 <Collection<T>>::insert(collection_id, target_collection);876877 Ok(())878 }879880 881 882 883 884 885 886 887 888 889 890 891 892 893 #[weight = <T as Config>::WeightInfo::add_collection_admin()]894 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {895896 let sender = ensure_signed(origin)?;897 Self::check_owner_or_admin_permissions(collection_id, sender)?;898 let mut admin_arr: Vec<T::AccountId> = Vec::new();899900 if <AdminList<T>>::contains_key(collection_id)901 {902 admin_arr = <AdminList<T>>::get(collection_id);903 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);904 }905906 907 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);908909 admin_arr.push(new_admin_id);910 <AdminList<T>>::insert(collection_id, admin_arr);911912 Ok(())913 }914915 916 917 918 919 920 921 922 923 924 925 926 927 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]928 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {929930 let sender = ensure_signed(origin)?;931 Self::check_owner_or_admin_permissions(collection_id, sender)?;932 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);933934 let mut admin_arr = <AdminList<T>>::get(collection_id);935 admin_arr.retain(|i| *i != account_id);936 <AdminList<T>>::insert(collection_id, admin_arr);937938 Ok(())939 }940941 942 943 944 945 946 947 948 949 950 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]951 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {952953 let sender = ensure_signed(origin)?;954 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);955956 let mut target_collection = <Collection<T>>::get(collection_id);957 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);958959 target_collection.sponsorship = SponsorshipState::Unconfirmed(new_sponsor);960 <Collection<T>>::insert(collection_id, target_collection);961962 Ok(())963 }964965 966 967 968 969 970 971 972 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]973 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {974975 let sender = ensure_signed(origin)?;976 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);977978 let mut target_collection = <Collection<T>>::get(collection_id);979 ensure!(980 target_collection.sponsorship.pending_sponsor() == Some(&sender),981 Error::<T>::ConfirmUnsetSponsorFail982 );983984 target_collection.sponsorship = SponsorshipState::Confirmed(sender);985 <Collection<T>>::insert(collection_id, target_collection);986987 Ok(())988 }989990 991 992 993 994 995 996 997 998 999 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]1000 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {10011002 let sender = ensure_signed(origin)?;1003 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);10041005 let mut target_collection = <Collection<T>>::get(collection_id);1006 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);10071008 target_collection.sponsorship = SponsorshipState::Disabled;1009 <Collection<T>>::insert(collection_id, target_collection);10101011 Ok(())1012 }10131014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 10371038 #[weight = <T as Config>::WeightInfo::create_item(data.len())]1039 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {10401041 let sender = ensure_signed(origin)?;10421043 Self::collection_exists(collection_id)?;10441045 let target_collection = <Collection<T>>::get(collection_id);10461047 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;1048 Self::validate_create_item_args(&target_collection, &data)?;1049 Self::create_item_no_validation(collection_id, owner, data)?;10501051 Ok(())1052 }10531054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()1073 .map(|data| { data.len() })1074 .sum())]1075 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {10761077 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);1078 let sender = ensure_signed(origin)?;10791080 Self::collection_exists(collection_id)?;1081 let target_collection = <Collection<T>>::get(collection_id);10821083 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;10841085 for data in &items_data {1086 Self::validate_create_item_args(&target_collection, data)?;1087 }1088 for data in &items_data {1089 Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;1090 }10911092 Ok(())1093 }10941095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 #[weight = <T as Config>::WeightInfo::burn_item()]1109 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {11101111 let sender = ensure_signed(origin)?;1112 Self::collection_exists(collection_id)?;11131114 1115 let target_collection = <Collection<T>>::get(collection_id);1116 ensure!(1117 Self::is_item_owner(sender.clone(), collection_id, item_id) ||1118 (1119 target_collection.limits.owner_can_transfer &&1120 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1121 ),1122 Error::<T>::NoPermission1123 );11241125 if target_collection.access == AccessMode::WhiteList {1126 Self::check_white_list(collection_id, &sender)?;1127 }11281129 match target_collection.mode1130 {1131 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1132 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1133 CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?,1134 _ => ()1135 };11361137 1138 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));11391140 Ok(())1141 }11421143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 #[weight = <T as Config>::WeightInfo::transfer()]1167 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1168 let sender = ensure_signed(origin)?;1169 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1170 }11711172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 #[weight = <T as Config>::WeightInfo::approve()]1188 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {11891190 let sender = ensure_signed(origin)?;11911192 Self::collection_exists(collection_id)?;1193 Self::token_exists(collection_id, item_id, &sender)?;11941195 1196 let target_collection = <Collection<T>>::get(collection_id);1197 let allowance_limit = if target_collection.limits.owner_can_transfer &&1198 Self::is_owner_or_admin_permissions(1199 collection_id,1200 sender.clone(),1201 ) {1202 None1203 } else if let Some(amount) = Self::owned_amount(1204 sender.clone(),1205 collection_id,1206 item_id,1207 ) {1208 Some(amount)1209 } else {1210 fail!(Error::<T>::NoPermission);1211 };12121213 if target_collection.access == AccessMode::WhiteList {1214 Self::check_white_list(collection_id, &sender)?;1215 Self::check_white_list(collection_id, &spender)?;1216 }12171218 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1219 let mut allowance: u128 = amount;1220 if allowance_exists {1221 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1222 }1223 if let Some(limit) = allowance_limit {1224 ensure!(limit >= allowance, Error::<T>::TokenValueTooLow);1225 }1226 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);12271228 Ok(())1229 }1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 #[weight = <T as Config>::WeightInfo::transfer_from()]1251 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {12521253 let sender = ensure_signed(origin)?;1254 let mut appoved_transfer = false;12551256 1257 let mut approval: u128 = 0;1258 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1259 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1260 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1261 appoved_transfer = true;1262 }12631264 let target_collection = <Collection<T>>::get(collection_id);12651266 1267 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;12681269 1270 ensure!(1271 appoved_transfer || 1272 (1273 target_collection.limits.owner_can_transfer &&1274 Self::is_owner_or_admin_permissions(collection_id, sender.clone())1275 ),1276 Error::<T>::NoPermission1277 );12781279 if target_collection.access == AccessMode::WhiteList {1280 Self::check_white_list(collection_id, &sender)?;1281 Self::check_white_list(collection_id, &recipient)?;1282 }12831284 1285 if approval.checked_sub(value).unwrap_or(0) > 0 {1286 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1287 }1288 else {1289 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1290 }12911292 match target_collection.mode1293 {1294 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1295 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1296 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1297 _ => ()1298 };12991300 Ok(())1301 }13021303 1304 13051306 1307 1308 1309 13101311 13121313 13141315 1316 13171318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1331 pub fn set_variable_meta_data (1332 origin,1333 collection_id: CollectionId,1334 item_id: TokenId,1335 data: Vec<u8>1336 ) -> DispatchResult {1337 let sender = ensure_signed(origin)?;1338 1339 Self::collection_exists(collection_id)?;1340 Self::token_exists(collection_id, item_id, &sender)?;13411342 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);13431344 1345 let target_collection = <Collection<T>>::get(collection_id);1346 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1347 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1348 Error::<T>::NoPermission);13491350 match target_collection.mode1351 {1352 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1353 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1354 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1355 _ => fail!(Error::<T>::UnexpectedCollectionType)1356 };13571358 Ok(())1359 }1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 #[weight = <T as Config>::WeightInfo::set_schema_version()]1376 pub fn set_schema_version(1377 origin,1378 collection_id: CollectionId,1379 version: SchemaVersion1380 ) -> DispatchResult {1381 let sender = ensure_signed(origin)?;1382 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1383 let mut target_collection = <Collection<T>>::get(collection_id);1384 target_collection.schema_version = version;1385 <Collection<T>>::insert(collection_id, target_collection);13861387 Ok(())1388 }13891390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1403 pub fn set_offchain_schema(1404 origin,1405 collection_id: CollectionId,1406 schema: Vec<u8>1407 ) -> DispatchResult {1408 let sender = ensure_signed(origin)?;1409 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14101411 1412 ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, "");14131414 let mut target_collection = <Collection<T>>::get(collection_id);1415 target_collection.offchain_schema = schema;1416 <Collection<T>>::insert(collection_id, target_collection);14171418 Ok(())1419 }14201421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1434 pub fn set_const_on_chain_schema (1435 origin,1436 collection_id: CollectionId,1437 schema: Vec<u8>1438 ) -> DispatchResult {1439 let sender = ensure_signed(origin)?;1440 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14411442 1443 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");14441445 let mut target_collection = <Collection<T>>::get(collection_id);1446 target_collection.const_on_chain_schema = schema;1447 <Collection<T>>::insert(collection_id, target_collection);14481449 Ok(())1450 }14511452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1465 pub fn set_variable_on_chain_schema (1466 origin,1467 collection_id: CollectionId,1468 schema: Vec<u8>1469 ) -> DispatchResult {1470 let sender = ensure_signed(origin)?;1471 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;14721473 1474 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");14751476 let mut target_collection = <Collection<T>>::get(collection_id);1477 target_collection.variable_on_chain_schema = schema;1478 <Collection<T>>::insert(collection_id, target_collection);14791480 Ok(())1481 }14821483 1484 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1485 pub fn set_chain_limits(1486 origin,1487 limits: ChainLimits1488 ) -> DispatchResult {14891490 #[cfg(not(feature = "runtime-benchmarks"))]1491 ensure_root(origin)?;14921493 <ChainLimit>::put(limits);1494 Ok(())1495 }14961497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1509 pub fn enable_contract_sponsoring(1510 origin,1511 contract_address: T::AccountId,1512 enable: bool1513 ) -> DispatchResult {15141515 let sender = ensure_signed(origin)?;15161517 #[cfg(feature = "runtime-benchmarks")]1518 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15191520 Self::ensure_contract_owned(sender, &contract_address)?;15211522 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1523 Ok(())1524 }15251526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1544 pub fn set_contract_sponsoring_rate_limit(1545 origin,1546 contract_address: T::AccountId,1547 rate_limit: T::BlockNumber1548 ) -> DispatchResult {1549 let sender = ensure_signed(origin)?;15501551 #[cfg(feature = "runtime-benchmarks")]1552 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15531554 Self::ensure_contract_owned(sender, &contract_address)?;1555 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1556 Ok(())1557 }15581559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1571 pub fn toggle_contract_white_list(1572 origin,1573 contract_address: T::AccountId,1574 enable: bool1575 ) -> 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 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1583 Ok(())1584 }1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1598 pub fn add_to_contract_white_list(1599 origin,1600 contract_address: T::AccountId,1601 account_address: T::AccountId1602 ) -> DispatchResult {1603 let sender = ensure_signed(origin)?;16041605 #[cfg(feature = "runtime-benchmarks")]1606 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1607 1608 Self::ensure_contract_owned(sender, &contract_address)?; 1609 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1610 Ok(())1611 }16121613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1625 pub fn remove_from_contract_white_list(1626 origin,1627 contract_address: T::AccountId,1628 account_address: T::AccountId1629 ) -> DispatchResult {1630 let sender = ensure_signed(origin)?;16311632 #[cfg(feature = "runtime-benchmarks")]1633 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());16341635 Self::ensure_contract_owned(sender, &contract_address)?;1636 <ContractWhiteList<T>>::remove(contract_address, account_address);1637 Ok(())1638 }16391640 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1641 pub fn set_collection_limits(1642 origin,1643 collection_id: u32,1644 new_limits: CollectionLimits,1645 ) -> DispatchResult {1646 let sender = ensure_signed(origin)?;1647 Self::check_owner_permissions(collection_id, sender.clone())?;1648 let mut target_collection = <Collection<T>>::get(collection_id);1649 let old_limits = target_collection.limits;1650 let chain_limits = ChainLimit::get();16511652 1653 ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1654 new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && 1655 new_limits.sponsored_data_size <= chain_limits.custom_data_limit,1656 Error::<T>::CollectionLimitBoundsExceeded);16571658 1659 ensure!(old_limits.token_limit >= new_limits.token_limit, Error::<T>::CollectionTokenLimitExceeded);1660 ensure!(new_limits.token_limit > 0, Error::<T>::CollectionTokenLimitExceeded);16611662 ensure!(1663 (old_limits.owner_can_transfer || !new_limits.owner_can_transfer) &&1664 (old_limits.owner_can_destroy || !new_limits.owner_can_destroy),1665 Error::<T>::OwnerPermissionsCantBeReverted,1666 );16671668 target_collection.limits = new_limits;1669 <Collection<T>>::insert(collection_id, target_collection);16701671 Ok(())1672 } 1673 }1674}16751676impl<T: Config> Module<T> {16771678 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {16791680 let target_collection = <Collection<T>>::get(collection_id);16811682 1683 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;16841685 1686 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1687 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1688 Error::<T>::NoPermission);16891690 if target_collection.access == AccessMode::WhiteList {1691 Self::check_white_list(collection_id, &sender)?;1692 Self::check_white_list(collection_id, &recipient)?;1693 }16941695 match target_collection.mode1696 {1697 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient.clone())?,1698 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1699 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient.clone())?,1700 _ => ()1701 };17021703 Self::deposit_event(RawEvent::Transfer(collection_id, item_id, sender, recipient, value));17041705 Ok(())1706 }170717081709 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {17101711 1712 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1713 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1714 1715 Ok(())1716 }17171718 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {17191720 1721 let total_items: u32 = ItemListIndex::get(collection_id);1722 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1723 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1724 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);17251726 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1727 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1728 Self::check_white_list(collection_id, owner)?;1729 Self::check_white_list(collection_id, sender)?;1730 }17311732 Ok(())1733 }17341735 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1736 match target_collection.mode1737 {1738 CollectionMode::NFT => {1739 if let CreateItemData::NFT(data) = data {1740 1741 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1742 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1743 } else {1744 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1745 }1746 },1747 CollectionMode::Fungible(_) => {1748 if let CreateItemData::Fungible(_) = data {1749 } else {1750 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1751 }1752 },1753 CollectionMode::ReFungible => {1754 if let CreateItemData::ReFungible(data) = data {17551756 1757 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1758 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);17591760 1761 ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1762 ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1763 } else {1764 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1765 }1766 },1767 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1768 };17691770 Ok(())1771 }17721773 fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1774 match data1775 {1776 CreateItemData::NFT(data) => {1777 let item = NftItemType {1778 owner: owner.clone(),1779 const_data: data.const_data,1780 variable_data: data.variable_data1781 };17821783 Self::add_nft_item(collection_id, item)?;1784 },1785 CreateItemData::Fungible(data) => {1786 Self::add_fungible_item(collection_id, &owner, data.value)?;1787 },1788 CreateItemData::ReFungible(data) => {1789 let mut owner_list = Vec::new();1790 owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});17911792 let item = ReFungibleItemType {1793 owner: owner_list,1794 const_data: data.const_data,1795 variable_data: data.variable_data1796 };17971798 Self::add_refungible_item(collection_id, item)?;1799 }1800 };18011802 1803 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id), owner));18041805 Ok(())1806 }18071808 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {18091810 1811 let mut balance: u128 = 0;1812 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1813 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1814 } 18151816 1817 let item = FungibleItemType {1818 value: balance + value1819 };1820 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);18211822 1823 let new_balance = <Balance<T>>::get(collection_id, owner)1824 .checked_add(value)1825 .ok_or(Error::<T>::NumOverflow)?;1826 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18271828 Ok(())1829 }18301831 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1832 let current_index = <ItemListIndex>::get(collection_id)1833 .checked_add(1)1834 .ok_or(Error::<T>::NumOverflow)?;1835 let itemcopy = item.clone();18361837 let value = item.owner.first().unwrap().fraction;1838 let owner = item.owner.first().unwrap().owner.clone();18391840 Self::add_token_index(collection_id, current_index, &owner)?;18411842 <ItemListIndex>::insert(collection_id, current_index);1843 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);18441845 1846 let new_balance = <Balance<T>>::get(collection_id, &owner)1847 .checked_add(value)1848 .ok_or(Error::<T>::NumOverflow)?;1849 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);18501851 Ok(())1852 }18531854 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1855 let current_index = <ItemListIndex>::get(collection_id)1856 .checked_add(1)1857 .ok_or(Error::<T>::NumOverflow)?;18581859 let item_owner = item.owner.clone();1860 Self::add_token_index(collection_id, current_index, &item.owner)?;18611862 <ItemListIndex>::insert(collection_id, current_index);1863 <NftItemList<T>>::insert(collection_id, current_index, item);18641865 1866 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1867 .checked_add(1)1868 .ok_or(Error::<T>::NumOverflow)?;1869 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);18701871 Ok(())1872 }18731874 fn burn_refungible_item(1875 collection_id: CollectionId,1876 item_id: TokenId,1877 owner: &T::AccountId,1878 ) -> DispatchResult {1879 ensure!(1880 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1881 Error::<T>::TokenNotFound1882 );1883 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1884 let rft_balance = token1885 .owner1886 .iter()1887 .filter(|&i| i.owner == *owner)1888 .next()1889 .unwrap();1890 Self::remove_token_index(collection_id, item_id, owner)?;18911892 1893 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1894 .checked_sub(rft_balance.fraction)1895 .ok_or(Error::<T>::NumOverflow)?;1896 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);18971898 1899 let index = token1900 .owner1901 .iter()1902 .position(|i| i.owner == *owner)1903 .unwrap();1904 token.owner.remove(index);1905 let owner_count = token.owner.len();19061907 1908 if owner_count == 0 {1909 <ReFungibleItemList<T>>::remove(collection_id, item_id);1910 }1911 else {1912 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1913 }19141915 Ok(())1916 }19171918 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1919 ensure!(1920 <NftItemList<T>>::contains_key(collection_id, item_id),1921 Error::<T>::TokenNotFound1922 );1923 let item = <NftItemList<T>>::get(collection_id, item_id);1924 Self::remove_token_index(collection_id, item_id, &item.owner)?;19251926 1927 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1928 .checked_sub(1)1929 .ok_or(Error::<T>::NumOverflow)?;1930 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1931 <NftItemList<T>>::remove(collection_id, item_id);19321933 Ok(())1934 }19351936 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1937 ensure!(1938 <FungibleItemList<T>>::contains_key(collection_id, owner),1939 Error::<T>::TokenNotFound1940 );1941 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1942 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);19431944 1945 let new_balance = <Balance<T>>::get(collection_id, owner)1946 .checked_sub(value)1947 .ok_or(Error::<T>::NumOverflow)?;1948 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);19491950 if balance.value - value > 0 {1951 balance.value -= value;1952 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1953 }1954 else {1955 <FungibleItemList<T>>::remove(collection_id, owner);1956 }19571958 Ok(())1959 }19601961 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1962 ensure!(1963 <Collection<T>>::contains_key(collection_id),1964 Error::<T>::CollectionNotFound1965 );1966 Ok(())1967 }19681969 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1970 Self::collection_exists(collection_id)?;19711972 let target_collection = <Collection<T>>::get(collection_id);1973 ensure!(1974 subject == target_collection.owner,1975 Error::<T>::NoPermission1976 );19771978 Ok(())1979 }19801981 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1982 let target_collection = <Collection<T>>::get(collection_id);1983 let mut result: bool = subject == target_collection.owner;1984 let exists = <AdminList<T>>::contains_key(collection_id);19851986 if !result & exists {1987 if <AdminList<T>>::get(collection_id).contains(&subject) {1988 result = true1989 }1990 }19911992 result1993 }19941995 fn check_owner_or_admin_permissions(1996 collection_id: CollectionId,1997 subject: T::AccountId,1998 ) -> DispatchResult {1999 Self::collection_exists(collection_id)?;2000 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());20012002 ensure!(2003 result,2004 Error::<T>::NoPermission2005 );2006 Ok(())2007 }20082009 fn owned_amount(2010 subject: T::AccountId,2011 collection_id: CollectionId,2012 item_id: TokenId,2013 ) -> Option<u128> {2014 let target_collection = <Collection<T>>::get(collection_id);20152016 match target_collection.mode {2017 CollectionMode::NFT => {2018 if <NftItemList<T>>::get(collection_id, item_id).owner == subject {2019 return Some(1)2020 }2021 None2022 },2023 CollectionMode::Fungible(_) => {2024 if <FungibleItemList<T>>::contains_key(collection_id, &subject) {2025 return Some(<FungibleItemList<T>>::get(collection_id, &subject)2026 .value);2027 }2028 None2029 },2030 CollectionMode::ReFungible => <ReFungibleItemList<T>>::get(collection_id, item_id)2031 .owner2032 .iter()2033 .find(|i| i.owner == subject)2034 .map(|i| i.fraction),2035 CollectionMode::Invalid => None,2036 }2037 }20382039 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {2040 let target_collection = <Collection<T>>::get(collection_id);20412042 match target_collection.mode {2043 CollectionMode::NFT => {2044 <NftItemList<T>>::get(collection_id, item_id).owner == subject2045 }2046 CollectionMode::Fungible(_) => {2047 <FungibleItemList<T>>::contains_key(collection_id, &subject)2048 }2049 CollectionMode::ReFungible => {2050 <ReFungibleItemList<T>>::get(collection_id, item_id)2051 .owner2052 .iter()2053 .any(|i| i.owner == subject)2054 }2055 CollectionMode::Invalid => false,2056 }2057 }20582059 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {2060 let mes = Error::<T>::AddresNotInWhiteList;2061 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);20622063 Ok(())2064 }20652066 2067 2068 fn token_exists(2069 collection_id: CollectionId,2070 item_id: TokenId,2071 owner: &T::AccountId2072 ) -> DispatchResult {2073 let target_collection = <Collection<T>>::get(collection_id);2074 let exists = match target_collection.mode2075 {2076 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),2077 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),2078 CollectionMode::ReFungible => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2079 _ => false2080 };20812082 ensure!(exists == true, Error::<T>::TokenNotFound);2083 Ok(())2084 }20852086 fn transfer_fungible(2087 collection_id: CollectionId,2088 value: u128,2089 owner: &T::AccountId,2090 recipient: &T::AccountId,2091 ) -> DispatchResult {2092 Self::token_exists(collection_id, 0, owner)?;20932094 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);2095 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);20962097 2098 Self::add_fungible_item(collection_id, recipient, value)?;20992100 2101 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);21022103 2104 if balance.value == value {2105 <FungibleItemList<T>>::remove(collection_id, owner);2106 }2107 else {2108 balance.value -= value;2109 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);2110 }21112112 Ok(())2113 }21142115 fn transfer_refungible(2116 collection_id: CollectionId,2117 item_id: TokenId,2118 value: u128,2119 owner: T::AccountId,2120 new_owner: T::AccountId,2121 ) -> DispatchResult {2122 Self::token_exists(collection_id, item_id, &owner)?;21232124 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2125 let item = full_item2126 .owner2127 .iter()2128 .filter(|i| i.owner == owner)2129 .next()2130 .ok_or(Error::<T>::NumOverflow)?;2131 let amount = item.fraction;21322133 ensure!(amount >= value, Error::<T>::TokenValueTooLow);21342135 2136 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2137 .checked_sub(value)2138 .ok_or(Error::<T>::NumOverflow)?;2139 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);21402141 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2142 .checked_add(value)2143 .ok_or(Error::<T>::NumOverflow)?;2144 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);21452146 let old_owner = item.owner.clone();2147 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);21482149 2150 if amount == value && !new_owner_has_account {2151 2152 2153 let mut new_full_item = full_item.clone();2154 new_full_item2155 .owner2156 .iter_mut()2157 .find(|i| i.owner == owner)2158 .unwrap()2159 .owner = new_owner.clone();2160 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);21612162 2163 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;2164 } else {2165 let mut new_full_item = full_item.clone();2166 new_full_item2167 .owner2168 .iter_mut()2169 .find(|i| i.owner == owner)2170 .unwrap()2171 .fraction -= value;21722173 2174 if new_owner_has_account {2175 2176 new_full_item2177 .owner2178 .iter_mut()2179 .find(|i| i.owner == new_owner)2180 .unwrap()2181 .fraction += value;2182 } else {2183 2184 new_full_item.owner.push(Ownership {2185 owner: new_owner.clone(),2186 fraction: value,2187 });2188 Self::add_token_index(collection_id, item_id, &new_owner)?;2189 }21902191 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2192 }21932194 Ok(())2195 }21962197 fn transfer_nft(2198 collection_id: CollectionId,2199 item_id: TokenId,2200 sender: T::AccountId,2201 new_owner: T::AccountId,2202 ) -> DispatchResult {2203 Self::token_exists(collection_id, item_id, &sender)?;22042205 let mut item = <NftItemList<T>>::get(collection_id, item_id);22062207 ensure!(2208 sender == item.owner,2209 Error::<T>::MustBeTokenOwner2210 );22112212 2213 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2214 .checked_sub(1)2215 .ok_or(Error::<T>::NumOverflow)?;2216 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);22172218 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2219 .checked_add(1)2220 .ok_or(Error::<T>::NumOverflow)?;2221 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);22222223 2224 let old_owner = item.owner.clone();2225 item.owner = new_owner.clone();2226 <NftItemList<T>>::insert(collection_id, item_id, item);22272228 2229 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;22302231 Ok(())2232 }2233 2234 fn set_re_fungible_variable_data(2235 collection_id: CollectionId,2236 item_id: TokenId,2237 data: Vec<u8>2238 ) -> DispatchResult {2239 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);22402241 item.variable_data = data;22422243 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);22442245 Ok(())2246 }22472248 fn set_nft_variable_data(2249 collection_id: CollectionId,2250 item_id: TokenId,2251 data: Vec<u8>2252 ) -> DispatchResult {2253 let mut item = <NftItemList<T>>::get(collection_id, item_id);2254 2255 item.variable_data = data;22562257 <NftItemList<T>>::insert(collection_id, item_id, item);2258 2259 Ok(())2260 }22612262 fn init_collection(item: &CollectionType<T::AccountId>) {2263 2264 assert!(2265 item.decimal_points <= MAX_DECIMAL_POINTS,2266 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2267 );2268 assert!(2269 item.name.len() <= 64,2270 "Collection name can not be longer than 63 char"2271 );2272 assert!(2273 item.name.len() <= 256,2274 "Collection description can not be longer than 255 char"2275 );2276 assert!(2277 item.token_prefix.len() <= 16,2278 "Token prefix can not be longer than 15 char"2279 );22802281 2282 let next_id = CreatedCollectionCount::get()2283 .checked_add(1)2284 .unwrap();22852286 CreatedCollectionCount::put(next_id);2287 }22882289 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2290 let current_index = <ItemListIndex>::get(collection_id)2291 .checked_add(1)2292 .unwrap();22932294 let item_owner = item.owner.clone();2295 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();22962297 <ItemListIndex>::insert(collection_id, current_index);22982299 2300 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2301 .checked_add(1)2302 .unwrap();2303 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2304 }23052306 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2307 let current_index = <ItemListIndex>::get(collection_id)2308 .checked_add(1)2309 .unwrap();23102311 Self::add_token_index(collection_id, current_index, owner).unwrap();23122313 <ItemListIndex>::insert(collection_id, current_index);23142315 2316 let new_balance = <Balance<T>>::get(collection_id, owner)2317 .checked_add(item.value)2318 .unwrap();2319 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2320 }23212322 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2323 let current_index = <ItemListIndex>::get(collection_id)2324 .checked_add(1)2325 .unwrap();23262327 let value = item.owner.first().unwrap().fraction;2328 let owner = item.owner.first().unwrap().owner.clone();23292330 Self::add_token_index(collection_id, current_index, &owner).unwrap();23312332 <ItemListIndex>::insert(collection_id, current_index);23332334 2335 let new_balance = <Balance<T>>::get(collection_id, &owner)2336 .checked_add(value)2337 .unwrap();2338 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2339 }23402341 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {23422343 2344 if <AccountItemCount<T>>::contains_key(owner) {23452346 2347 let count = <AccountItemCount<T>>::get(owner);2348 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);23492350 <AccountItemCount<T>>::insert(owner.clone(), count2351 .checked_add(1)2352 .ok_or(Error::<T>::NumOverflow)?);2353 }2354 else {2355 <AccountItemCount<T>>::insert(owner.clone(), 1);2356 }23572358 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2359 if list_exists {2360 let mut list = <AddressTokens<T>>::get(collection_id, owner);2361 let item_contains = list.contains(&item_index.clone());23622363 if !item_contains {2364 list.push(item_index.clone());2365 }23662367 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2368 } else {2369 let mut itm = Vec::new();2370 itm.push(item_index.clone());2371 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2372 }23732374 Ok(())2375 }23762377 fn remove_token_index(2378 collection_id: CollectionId,2379 item_index: TokenId,2380 owner: &T::AccountId,2381 ) -> DispatchResult {23822383 2384 <AccountItemCount<T>>::insert(owner.clone(), 2385 <AccountItemCount<T>>::get(owner)2386 .checked_sub(1)2387 .ok_or(Error::<T>::NumOverflow)?);238823892390 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2391 if list_exists {2392 let mut list = <AddressTokens<T>>::get(collection_id, owner);2393 let item_contains = list.contains(&item_index.clone());23942395 if item_contains {2396 list.retain(|&item| item != item_index);2397 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2398 }2399 }24002401 Ok(())2402 }24032404 fn move_token_index(2405 collection_id: CollectionId,2406 item_index: TokenId,2407 old_owner: &T::AccountId,2408 new_owner: &T::AccountId,2409 ) -> DispatchResult {2410 Self::remove_token_index(collection_id, item_index, old_owner)?;2411 Self::add_token_index(collection_id, item_index, new_owner)?;24122413 Ok(())2414 }2415 2416 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2417 if <ContractOwner<T>>::contains_key(contract.clone()) {2418 let owner = <ContractOwner<T>>::get(contract);2419 ensure!(account == owner, Error::<T>::NoPermission);2420 } else {2421 fail!(Error::<T>::NoPermission);2422 }24232424 Ok(())2425 }2426}2427242824292430243124322433pub type Multiplier = FixedU128;24342435type BalanceOf<T> = <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::Balance;2436243724382439#[derive(Encode, Decode, Clone, Eq, PartialEq)]2440pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);24412442impl<T: Config + Send + Sync> sp_std::fmt::Debug 2443 for ChargeTransactionPayment<T>2444{2445 #[cfg(feature = "std")]2446 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2447 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2448 }2449 #[cfg(not(feature = "std"))]2450 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2451 Ok(())2452 }2453}24542455impl<T: Config> ChargeTransactionPayment<T>2456where2457 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2458 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2459 T::AccountId: AsRef<[u8]>,2460 T::AccountId: UncheckedFrom<T::Hash>,2461{2462 fn traditional_fee(2463 len: usize,2464 info: &DispatchInfoOf<T::Call>,2465 tip: BalanceOf<T>,2466 ) -> BalanceOf<T>2467 where2468 T::Call: Dispatchable<Info = DispatchInfo>,2469 {2470 <pallet_transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2471 }24722473 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2474 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2475 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2476 let len_saturation = max_block_length as u64 / (len as u64).max(1);2477 let coefficient: BalanceOf<T> = weight_saturation2478 .min(len_saturation)2479 .saturated_into::<BalanceOf<T>>();2480 final_fee2481 .saturating_mul(coefficient)2482 .saturated_into::<TransactionPriority>()2483 }24842485 fn withdraw_fee(2486 &self,2487 who: &T::AccountId,2488 call: &T::Call,2489 info: &DispatchInfoOf<T::Call>,2490 len: usize,2491 ) -> Result<2492 (2493 BalanceOf<T>,2494 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2495 ),2496 TransactionValidityError,2497 > {2498 let tip = self.0;24992500 2501 2502 2503 2504 2505 2506 2507 let fee = Self::traditional_fee(len, info, tip);25082509 2510 if fee.is_zero() {2511 return <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2512 .map(|i| (fee, i));2513 }25142515 2516 2517 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2518 Some(Call::create_item(collection_id, _owner, _properties)) => {25192520 2521 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;25222523 let collection = <Collection<T>>::get(collection_id);25242525 let limit = collection.limits.sponsor_transfer_timeout;2526 let mut sponsored = true;2527 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2528 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2529 let limit_time = last_tx_block + limit.into();2530 if block_number <= limit_time {2531 sponsored = false;2532 }2533 }2534 if sponsored {2535 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2536 }25372538 2539 if (collection.limits.sponsored_data_size >= (_properties.len() as u32)) &&2540 (sponsored)2541 {2542 collection.sponsorship.sponsor()2543 .cloned()2544 .unwrap_or_default()2545 } else {2546 T::AccountId::default()2547 }2548 }2549 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2550 2551 let mut sponsor_transfer = false;2552 if <Collection<T>>::get(collection_id).sponsorship.confirmed() {25532554 let collection_limits = <Collection<T>>::get(collection_id).limits;2555 let collection_mode = <Collection<T>>::get(collection_id).mode;2556 2557 2558 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2559 sponsor_transfer = match collection_mode {2560 CollectionMode::NFT => {2561 2562 2563 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2564 collection_limits.sponsor_transfer_timeout2565 } else {2566 ChainLimit::get().nft_sponsor_transfer_timeout2567 };2568 2569 let mut sponsored = true;2570 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2571 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2572 let limit_time = last_tx_block + limit.into();2573 if block_number <= limit_time {2574 sponsored = false;2575 }2576 }2577 if sponsored {2578 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2579 }25802581 sponsored2582 }2583 CollectionMode::Fungible(_) => {2584 2585 2586 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2587 collection_limits.sponsor_transfer_timeout2588 } else {2589 ChainLimit::get().fungible_sponsor_transfer_timeout2590 };2591 2592 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2593 let mut sponsored = true;2594 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2595 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2596 let limit_time = last_tx_block + limit.into();2597 if block_number <= limit_time {2598 sponsored = false;2599 }2600 }2601 if sponsored {2602 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2603 }26042605 sponsored2606 }2607 CollectionMode::ReFungible => {2608 2609 2610 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2611 collection_limits.sponsor_transfer_timeout2612 } else {2613 ChainLimit::get().refungible_sponsor_transfer_timeout2614 };2615 2616 let mut sponsored = true;2617 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2618 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2619 let limit_time = last_tx_block + limit.into();2620 if block_number <= limit_time {2621 sponsored = false;2622 }2623 }2624 if sponsored {2625 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2626 }26272628 sponsored2629 }2630 _ => {2631 false2632 },2633 };2634 }26352636 if !sponsor_transfer {2637 T::AccountId::default()2638 } else {2639 <Collection<T>>::get(collection_id).sponsorship.sponsor()2640 .cloned()2641 .unwrap_or_default()2642 }2643 }26442645 _ => T::AccountId::default(),2646 };26472648 2649 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {26502651 2652 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {26532654 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2655 &who,2656 code_hash,2657 salt,2658 );2659 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());26602661 T::AccountId::default()2662 },26632664 2665 Some(pallet_contracts::Call::instantiate_with_code(_endowment, _gas_limit, _code, _data, _salt)) => {26662667 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2668 &who,2669 &T::Hashing::hash(&_code),2670 _salt,2671 );26722673 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());26742675 T::AccountId::default()2676 }26772678 2679 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {26802681 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());26822683 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2684 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2685 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2686 2687 if !owned_contract && white_list_enabled {2688 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2689 return Err(InvalidTransaction::Call.into());2690 }2691 }26922693 let mut sponsor_transfer = false;2694 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2695 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2696 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2697 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2698 let limit_time = last_tx_block + rate_limit;26992700 if block_number >= limit_time {2701 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2702 sponsor_transfer = true;2703 }2704 } else {2705 sponsor_transfer = false;2706 }2707 2708 2709 let mut sp = T::AccountId::default();2710 if sponsor_transfer {2711 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2712 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2713 sp = called_contract;2714 }2715 }2716 }27172718 sp2719 },27202721 _ => sponsor,2722 };27232724 let mut who_pays_fee: T::AccountId = sponsor.clone();2725 if sponsor == T::AccountId::default() {2726 who_pays_fee = who.clone();2727 }27282729 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2730 .map(|i| (fee, i))2731 }2732}273327342735impl<T: Config + Send + Sync> SignedExtension2736 for ChargeTransactionPayment<T>2737where2738 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2739 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2740 T::AccountId: AsRef<[u8]>,2741 T::AccountId: UncheckedFrom<T::Hash>,2742{2743 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2744 type AccountId = T::AccountId;2745 type Call = T::Call;2746 type AdditionalSigned = ();2747 type Pre = (2748 2749 BalanceOf<T>,2750 2751 Self::AccountId,2752 2753 <<T as pallet_transaction_payment::Config>::OnChargeTransaction as pallet_transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2754 );2755 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2756 Ok(())2757 }27582759 fn validate(2760 &self,2761 who: &Self::AccountId,2762 call: &Self::Call,2763 info: &DispatchInfoOf<Self::Call>,2764 len: usize,2765 ) -> TransactionValidity {2766 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2767 Ok(ValidTransaction {2768 priority: Self::get_priority(len, info, fee),2769 ..Default::default()2770 })2771 }27722773 fn pre_dispatch(2774 self,2775 who: &Self::AccountId,2776 call: &Self::Call,2777 info: &DispatchInfoOf<Self::Call>,2778 len: usize,2779 ) -> Result<Self::Pre, TransactionValidityError> {2780 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2781 Ok((self.0, who.clone(), imbalance))2782 }27832784 fn post_dispatch(2785 pre: Self::Pre,2786 info: &DispatchInfoOf<Self::Call>,2787 post_info: &PostDispatchInfoOf<Self::Call>,2788 len: usize,2789 _result: &DispatchResult,2790 ) -> Result<(), TransactionValidityError> {2791 let (tip, who, imbalance) = pre;2792 let actual_fee = pallet_transaction_payment::Module::<T>::compute_actual_fee(2793 len as u32,2794 info,2795 post_info,2796 tip,2797 );2798 <T as pallet_transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2799 Ok(())2800 }2801}28022803