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 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 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_SPONSOR_TIMEOUT: u32 = 10_368_000;58pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5960616263pub type CollectionId = u32;64pub type TokenId = u32;65pub type DecimalPoints = u8;6667#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]68#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]69pub enum CollectionMode {70 Invalid,71 NFT,72 73 Fungible(DecimalPoints),74 75 ReFungible(DecimalPoints),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, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct CollectionType<AccountId> {129 pub owner: AccountId,130 pub mode: CollectionMode,131 pub access: AccessMode,132 pub decimal_points: DecimalPoints,133 pub name: Vec<u16>, 134 pub description: Vec<u16>, 135 pub token_prefix: Vec<u8>, 136 pub mint_mode: bool,137 pub offchain_schema: Vec<u8>,138 pub schema_version: SchemaVersion,139 pub sponsor: AccountId, 140 pub sponsor_confirmed: bool, 141 pub limits: CollectionLimits, 142 pub variable_on_chain_schema: Vec<u8>, 143 pub const_on_chain_schema: Vec<u8>, 144}145146#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]147#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]148pub struct NftItemType<AccountId> {149 pub owner: AccountId,150 pub const_data: Vec<u8>,151 pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType {157 pub value: u128,158}159160#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]161#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]162pub struct ReFungibleItemType<AccountId> {163 pub owner: Vec<Ownership<AccountId>>,164 pub const_data: Vec<u8>,165 pub variable_data: Vec<u8>,166}167168169170171172173174175176177178179#[derive(Encode, Decode, Debug, Clone, PartialEq)]180#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]181pub struct CollectionLimits {182 pub account_token_ownership_limit: u32,183 pub sponsored_data_size: u32,184 pub token_limit: u32,185186 187 pub sponsor_transfer_timeout: u32,188 pub owner_can_transfer: bool,189 pub owner_can_destroy: bool,190}191192impl Default for CollectionLimits {193 fn default() -> CollectionLimits {194 CollectionLimits { 195 account_token_ownership_limit: 10_000_000, 196 token_limit: u32::max_value(),197 sponsored_data_size: u32::max_value(), 198 sponsor_transfer_timeout: 14400,199 owner_can_transfer: true,200 owner_can_destroy: true201 }202 }203}204205#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]206#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]207pub struct ChainLimits {208 pub collection_numbers_limit: u32,209 pub account_token_ownership_limit: u32,210 pub collections_admins_limit: u64,211 pub custom_data_limit: u32,212213 214 pub nft_sponsor_transfer_timeout: u32,215 pub fungible_sponsor_transfer_timeout: u32,216 pub refungible_sponsor_transfer_timeout: u32,217218 219 pub offchain_schema_limit: u32,220 pub variable_on_chain_schema_limit: u32,221 pub const_on_chain_schema_limit: u32,222}223224pub trait WeightInfo {225 fn create_collection() -> Weight;226 fn destroy_collection() -> Weight;227 fn add_to_white_list() -> Weight;228 fn remove_from_white_list() -> Weight;229 fn set_public_access_mode() -> Weight;230 fn set_mint_permission() -> Weight;231 fn change_collection_owner() -> Weight;232 fn add_collection_admin() -> Weight;233 fn remove_collection_admin() -> Weight;234 fn set_collection_sponsor() -> Weight;235 fn confirm_sponsorship() -> Weight;236 fn remove_collection_sponsor() -> Weight;237 fn create_item(s: usize) -> Weight;238 fn burn_item() -> Weight;239 fn transfer() -> Weight;240 fn approve() -> Weight;241 fn transfer_from() -> Weight;242 fn set_offchain_schema() -> Weight;243 fn set_const_on_chain_schema() -> Weight;244 fn set_variable_on_chain_schema() -> Weight;245 fn set_variable_meta_data() -> Weight;246 fn enable_contract_sponsoring() -> Weight;247 fn set_schema_version() -> Weight;248 fn set_chain_limits() -> Weight;249 fn set_contract_sponsoring_rate_limit() -> Weight;250 fn toggle_contract_white_list() -> Weight;251 fn add_to_contract_white_list() -> Weight;252 fn remove_from_contract_white_list() -> Weight;253 fn set_collection_limits() -> Weight;254}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259 pub const_data: Vec<u8>,260 pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266 pub value: u128,267}268269#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]270#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]271pub struct CreateReFungibleData {272 pub const_data: Vec<u8>,273 pub variable_data: Vec<u8>,274}275276#[derive(Encode, Decode, Debug, Clone, PartialEq)]277#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]278pub enum CreateItemData {279 NFT(CreateNftData),280 Fungible(CreateFungibleData),281 ReFungible(CreateReFungibleData),282}283284impl CreateItemData {285 pub fn len(&self) -> usize {286 let len = match self {287 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),288 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),289 _ => 0290 };291 292 return len;293 }294}295296impl From<CreateNftData> for CreateItemData {297 fn from(item: CreateNftData) -> Self {298 CreateItemData::NFT(item)299 }300}301302impl From<CreateReFungibleData> for CreateItemData {303 fn from(item: CreateReFungibleData) -> Self {304 CreateItemData::ReFungible(item)305 }306}307308impl From<CreateFungibleData> for CreateItemData {309 fn from(item: CreateFungibleData) -> Self {310 CreateItemData::Fungible(item)311 }312}313314315decl_error! {316 317 pub enum Error for Module<T: Config> {318 319 TotalCollectionsLimitExceeded,320 321 CollectionDecimalPointLimitExceeded, 322 323 CollectionNameLimitExceeded, 324 325 CollectionDescriptionLimitExceeded, 326 327 CollectionTokenPrefixLimitExceeded,328 329 CollectionNotFound,330 331 TokenNotFound,332 333 AdminNotFound,334 335 NumOverflow, 336 337 AlreadyAdmin, 338 339 NoPermission,340 341 ConfirmUnsetSponsorFail,342 343 PublicMintingNotAllowed,344 345 MustBeTokenOwner,346 347 TokenValueTooLow,348 349 NftSizeLimitExceeded,350 351 ApproveNotFound,352 353 TokenValueNotEnough,354 355 ApproveRequired,356 357 AddresNotInWhiteList,358 359 CollectionAdminsLimitExceeded,360 361 AddressOwnershipLimitExceeded,362 363 EmptyArgument,364 365 TokenConstDataLimitExceeded,366 367 TokenVariableDataLimitExceeded,368 369 NotNftDataUsedToMintNftCollectionToken,370 371 NotFungibleDataUsedToMintFungibleCollectionToken,372 373 NotReFungibleDataUsedToMintReFungibleCollectionToken,374 375 UnexpectedCollectionType,376 377 CantStoreMetadataInFungibleTokens,378 379 CollectionTokenLimitExceeded,380 381 AccountTokenLimitExceeded,382 383 CollectionLimitBoundsExceeded,384 385 SchemaDataLimitExceeded386 }387}388389pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config {390 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;391392 393 type WeightInfo: WeightInfo;394}395396#[cfg(feature = "runtime-benchmarks")]397mod benchmarking;398399400401decl_storage! {402 trait Store for Module<T: Config> as Nft {403404 405 NextCollectionID: CollectionId;406 CreatedCollectionCount: u32;407 ChainVersion: u64;408 ItemListIndex: map hasher(identity) CollectionId => TokenId;409410 411 pub ChainLimit get(fn chain_limit) config(): ChainLimits;412413 414 CollectionCount: u32;415 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;416417 418 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;419 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;420 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;421422 423 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;424425 426 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;427428 429 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;430 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;431 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;432433 434 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;435436 437 pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;438 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;439 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;440 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;441442 443 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;444 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;445 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;446 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;447 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 448 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 449 }450 add_extra_genesis {451 build(|config: &GenesisConfig<T>| {452 453 for (_num, _c) in &config.collection {454 <Module<T>>::init_collection(_c);455 }456457 for (_num, _c, _i) in &config.nft_item_id {458 <Module<T>>::init_nft_token(*_c, _i);459 }460461 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {462 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);463 }464465 for (_num, _c, _i) in &config.refungible_item_id {466 <Module<T>>::init_refungible_token(*_c, _i);467 }468 })469 }470}471472decl_event!(473 pub enum Event<T>474 where475 AccountId = <T as system::Config>::AccountId,476 {477 478 479 480 481 482 483 484 485 486 Created(CollectionId, u8, AccountId),487488 489 490 491 492 493 494 495 ItemCreated(CollectionId, TokenId),496497 498 499 500 501 502 503 504 ItemDestroyed(CollectionId, TokenId),505 }506);507508decl_module! {509 pub struct Module<T: Config> for enum Call 510 where 511 origin: T::Origin512 {513 fn deposit_event() = default;514 type Error = Error<T>;515516 fn on_initialize(now: T::BlockNumber) -> Weight {517518 if ChainVersion::get() < 2519 {520 let value = NextCollectionID::get();521 CreatedCollectionCount::put(value);522 ChainVersion::put(2);523 }524525 0526 }527528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 #[weight = <T as Config>::WeightInfo::create_collection()]545 pub fn create_collection(origin,546 collection_name: Vec<u16>,547 collection_description: Vec<u16>,548 token_prefix: Vec<u8>,549 mode: CollectionMode) -> DispatchResult {550551 552 let who = ensure_signed(origin)?;553554 let decimal_points = match mode {555 CollectionMode::Fungible(points) => points,556 CollectionMode::ReFungible(points) => points,557 _ => 0558 };559560 561 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);562563 564 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);565 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);566 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);567 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);568569 570 let next_id = CreatedCollectionCount::get()571 .checked_add(1)572 .ok_or(Error::<T>::NumOverflow)?;573574 575 let total = CollectionCount::get()576 .checked_add(1)577 .ok_or(Error::<T>::NumOverflow)?;578579 CreatedCollectionCount::put(next_id);580 CollectionCount::put(total);581582 583 let new_collection = CollectionType {584 owner: who.clone(),585 name: collection_name,586 mode: mode.clone(),587 mint_mode: false,588 access: AccessMode::Normal,589 description: collection_description,590 decimal_points: decimal_points,591 token_prefix: token_prefix,592 offchain_schema: Vec::new(),593 schema_version: SchemaVersion::ImageURL,594 sponsor: T::AccountId::default(),595 sponsor_confirmed: false,596 variable_on_chain_schema: Vec::new(),597 const_on_chain_schema: Vec::new(),598 limits: CollectionLimits::default()599 };600601 602 <Collection<T>>::insert(next_id, new_collection);603604 605 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));606607 Ok(())608 }609610 611 612 613 614 615 616 617 618 619 #[weight = <T as Config>::WeightInfo::destroy_collection()]620 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {621622 let sender = ensure_signed(origin)?;623 Self::check_owner_permissions(collection_id, sender)?;624625 <AddressTokens<T>>::remove_prefix(collection_id);626 <Allowances<T>>::remove_prefix(collection_id);627 <Balance<T>>::remove_prefix(collection_id);628 <ItemListIndex>::remove(collection_id);629 <AdminList<T>>::remove(collection_id);630 <Collection<T>>::remove(collection_id);631 <WhiteList<T>>::remove_prefix(collection_id);632633 <NftItemList<T>>::remove_prefix(collection_id);634 <FungibleItemList<T>>::remove_prefix(collection_id);635 <ReFungibleItemList<T>>::remove_prefix(collection_id);636637 <NftTransferBasket<T>>::remove_prefix(collection_id);638 <FungibleTransferBasket<T>>::remove_prefix(collection_id);639 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);640641 if CollectionCount::get() > 0642 {643 644 let total = CollectionCount::get()645 .checked_sub(1)646 .ok_or(Error::<T>::NumOverflow)?;647648 CollectionCount::put(total);649 }650651 Ok(())652 }653654 655 656 657 658 659 660 661 662 663 664 665 666 #[weight = <T as Config>::WeightInfo::add_to_white_list()]667 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{668669 let sender = ensure_signed(origin)?;670 Self::check_owner_or_admin_permissions(collection_id, sender)?;671672 <WhiteList<T>>::insert(collection_id, address, true);673 674 Ok(())675 }676677 678 679 680 681 682 683 684 685 686 687 688 689 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]690 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{691692 let sender = ensure_signed(origin)?;693 Self::check_owner_or_admin_permissions(collection_id, sender)?;694695 <WhiteList<T>>::remove(collection_id, address);696697 Ok(())698 }699700 701 702 703 704 705 706 707 708 709 710 711 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]712 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult713 {714 let sender = ensure_signed(origin)?;715716 Self::check_owner_permissions(collection_id, sender)?;717 let mut target_collection = <Collection<T>>::get(collection_id);718 target_collection.access = mode;719 <Collection<T>>::insert(collection_id, target_collection);720721 Ok(())722 }723724 725 726 727 728 729 730 731 732 733 734 735 736 737 #[weight = <T as Config>::WeightInfo::set_mint_permission()]738 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult739 {740 let sender = ensure_signed(origin)?;741742 Self::check_owner_permissions(collection_id, sender)?;743 let mut target_collection = <Collection<T>>::get(collection_id);744 target_collection.mint_mode = mint_permission;745 <Collection<T>>::insert(collection_id, target_collection);746747 Ok(())748 }749750 751 752 753 754 755 756 757 758 759 760 761 #[weight = <T as Config>::WeightInfo::change_collection_owner()]762 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {763764 let sender = ensure_signed(origin)?;765 Self::check_owner_permissions(collection_id, sender)?;766 let mut target_collection = <Collection<T>>::get(collection_id);767 target_collection.owner = new_owner;768 <Collection<T>>::insert(collection_id, target_collection);769770 Ok(())771 }772773 774 775 776 777 778 779 780 781 782 783 784 785 786 #[weight = <T as Config>::WeightInfo::add_collection_admin()]787 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {788789 let sender = ensure_signed(origin)?;790 Self::check_owner_or_admin_permissions(collection_id, sender)?;791 let mut admin_arr: Vec<T::AccountId> = Vec::new();792793 if <AdminList<T>>::contains_key(collection_id)794 {795 admin_arr = <AdminList<T>>::get(collection_id);796 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);797 }798799 800 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);801802 admin_arr.push(new_admin_id);803 <AdminList<T>>::insert(collection_id, admin_arr);804805 Ok(())806 }807808 809 810 811 812 813 814 815 816 817 818 819 820 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]821 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {822823 let sender = ensure_signed(origin)?;824 Self::check_owner_or_admin_permissions(collection_id, sender)?;825 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);826827 let mut admin_arr = <AdminList<T>>::get(collection_id);828 admin_arr.retain(|i| *i != account_id);829 <AdminList<T>>::insert(collection_id, admin_arr);830831 Ok(())832 }833834 835 836 837 838 839 840 841 842 843 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]844 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {845846 let sender = ensure_signed(origin)?;847 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);848849 let mut target_collection = <Collection<T>>::get(collection_id);850 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);851852 target_collection.sponsor = new_sponsor;853 target_collection.sponsor_confirmed = false;854 <Collection<T>>::insert(collection_id, target_collection);855856 Ok(())857 }858859 860 861 862 863 864 865 866 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]867 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {868869 let sender = ensure_signed(origin)?;870 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);871872 let mut target_collection = <Collection<T>>::get(collection_id);873 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);874875 target_collection.sponsor_confirmed = true;876 <Collection<T>>::insert(collection_id, target_collection);877878 Ok(())879 }880881 882 883 884 885 886 887 888 889 890 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]891 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {892893 let sender = ensure_signed(origin)?;894 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);895896 let mut target_collection = <Collection<T>>::get(collection_id);897 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);898899 target_collection.sponsor = T::AccountId::default();900 target_collection.sponsor_confirmed = false;901 <Collection<T>>::insert(collection_id, target_collection);902903 Ok(())904 }905906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929930 #[weight = <T as Config>::WeightInfo::create_item(data.len())]931 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {932933 let sender = ensure_signed(origin)?;934935 Self::collection_exists(collection_id)?;936937 let target_collection = <Collection<T>>::get(collection_id);938939 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;940 Self::validate_create_item_args(&target_collection, &data)?;941 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;942943 Ok(())944 }945946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()965 .map(|data| { data.len() })966 .sum())]967 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {968969 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);970 let sender = ensure_signed(origin)?;971972 Self::collection_exists(collection_id)?;973 let target_collection = <Collection<T>>::get(collection_id);974975 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;976977 for data in &items_data {978 Self::validate_create_item_args(&target_collection, data)?;979 }980 for data in &items_data {981 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;982 }983984 Ok(())985 }986987 988 989 990 991 992 993 994 995 996 997 998 999 1000 #[weight = <T as Config>::WeightInfo::burn_item()]1001 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10021003 let sender = ensure_signed(origin)?;1004 Self::collection_exists(collection_id)?;10051006 1007 let target_collection = <Collection<T>>::get(collection_id);1008 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1009 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1010 Error::<T>::NoPermission);10111012 if target_collection.access == AccessMode::WhiteList {1013 Self::check_white_list(collection_id, &sender)?;1014 }10151016 match target_collection.mode1017 {1018 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1019 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1020 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, &sender)?,1021 _ => ()1022 };10231024 1025 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10261027 Ok(())1028 }10291030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 #[weight = <T as Config>::WeightInfo::transfer()]1054 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1055 let sender = ensure_signed(origin)?;1056 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1057 }10581059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 #[weight = <T as Config>::WeightInfo::approve()]1075 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10761077 let sender = ensure_signed(origin)?;10781079 Self::collection_exists(collection_id)?;1080 Self::token_exists(collection_id, item_id, &sender)?;10811082 1083 let target_collection = <Collection<T>>::get(collection_id);1084 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1085 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1086 Error::<T>::NoPermission);10871088 if target_collection.access == AccessMode::WhiteList {1089 Self::check_white_list(collection_id, &sender)?;1090 Self::check_white_list(collection_id, &spender)?;1091 }10921093 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1094 let mut allowance: u128 = amount;1095 if allowance_exists {1096 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1097 }1098 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);10991100 Ok(())1101 }1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 #[weight = <T as Config>::WeightInfo::transfer_from()]1123 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11241125 let sender = ensure_signed(origin)?;1126 let mut appoved_transfer = false;11271128 1129 let mut approval: u128 = 0;1130 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1131 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1132 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1133 appoved_transfer = true;1134 }11351136 let target_collection = <Collection<T>>::get(collection_id);11371138 1139 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11401141 1142 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1143 Error::<T>::NoPermission);11441145 if target_collection.access == AccessMode::WhiteList {1146 Self::check_white_list(collection_id, &sender)?;1147 Self::check_white_list(collection_id, &recipient)?;1148 }11491150 1151 if approval.checked_sub(value).unwrap_or(0) > 0 {1152 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1153 }1154 else {1155 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1156 }11571158 match target_collection.mode1159 {1160 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1161 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1162 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1163 _ => ()1164 };11651166 Ok(())1167 }11681169 1170 11711172 1173 1174 1175 11761177 11781179 11801181 1182 11831184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1197 pub fn set_variable_meta_data (1198 origin,1199 collection_id: CollectionId,1200 item_id: TokenId,1201 data: Vec<u8>1202 ) -> DispatchResult {1203 let sender = ensure_signed(origin)?;1204 1205 Self::collection_exists(collection_id)?;1206 Self::token_exists(collection_id, item_id, &sender)?;12071208 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12091210 1211 let target_collection = <Collection<T>>::get(collection_id);1212 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1213 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1214 Error::<T>::NoPermission);12151216 match target_collection.mode1217 {1218 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1219 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1220 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1221 _ => fail!(Error::<T>::UnexpectedCollectionType)1222 };12231224 Ok(())1225 }1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 #[weight = <T as Config>::WeightInfo::set_schema_version()]1242 pub fn set_schema_version(1243 origin,1244 collection_id: CollectionId,1245 version: SchemaVersion1246 ) -> DispatchResult {1247 let sender = ensure_signed(origin)?;1248 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1249 let mut target_collection = <Collection<T>>::get(collection_id);1250 target_collection.schema_version = version;1251 <Collection<T>>::insert(collection_id, target_collection);12521253 Ok(())1254 }12551256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1269 pub fn set_offchain_schema(1270 origin,1271 collection_id: CollectionId,1272 schema: Vec<u8>1273 ) -> DispatchResult {1274 let sender = ensure_signed(origin)?;1275 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12761277 1278 ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12791280 let mut target_collection = <Collection<T>>::get(collection_id);1281 target_collection.offchain_schema = schema;1282 <Collection<T>>::insert(collection_id, target_collection);12831284 Ok(())1285 }12861287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1300 pub fn set_const_on_chain_schema (1301 origin,1302 collection_id: CollectionId,1303 schema: Vec<u8>1304 ) -> DispatchResult {1305 let sender = ensure_signed(origin)?;1306 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13071308 1309 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13101311 let mut target_collection = <Collection<T>>::get(collection_id);1312 target_collection.const_on_chain_schema = schema;1313 <Collection<T>>::insert(collection_id, target_collection);13141315 Ok(())1316 }13171318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1331 pub fn set_variable_on_chain_schema (1332 origin,1333 collection_id: CollectionId,1334 schema: Vec<u8>1335 ) -> DispatchResult {1336 let sender = ensure_signed(origin)?;1337 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13381339 1340 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13411342 let mut target_collection = <Collection<T>>::get(collection_id);1343 target_collection.variable_on_chain_schema = schema;1344 <Collection<T>>::insert(collection_id, target_collection);13451346 Ok(())1347 }13481349 1350 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1351 pub fn set_chain_limits(1352 origin,1353 limits: ChainLimits1354 ) -> DispatchResult {13551356 #[cfg(not(feature = "runtime-benchmarks"))]1357 ensure_root(origin)?;13581359 <ChainLimit>::put(limits);1360 Ok(())1361 }13621363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1375 pub fn enable_contract_sponsoring(1376 origin,1377 contract_address: T::AccountId,1378 enable: bool1379 ) -> DispatchResult {13801381 let sender = ensure_signed(origin)?;13821383 #[cfg(feature = "runtime-benchmarks")]1384 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13851386 Self::ensure_contract_owned(sender, &contract_address)?;13871388 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1389 Ok(())1390 }13911392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1410 pub fn set_contract_sponsoring_rate_limit(1411 origin,1412 contract_address: T::AccountId,1413 rate_limit: T::BlockNumber1414 ) -> DispatchResult {1415 let sender = ensure_signed(origin)?;14161417 #[cfg(feature = "runtime-benchmarks")]1418 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14191420 Self::ensure_contract_owned(sender, &contract_address)?;1421 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1422 Ok(())1423 }14241425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1437 pub fn toggle_contract_white_list(1438 origin,1439 contract_address: T::AccountId,1440 enable: bool1441 ) -> DispatchResult {1442 let sender = ensure_signed(origin)?;14431444 #[cfg(feature = "runtime-benchmarks")]1445 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14461447 Self::ensure_contract_owned(sender, &contract_address)?;1448 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1449 Ok(())1450 }1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1464 pub fn add_to_contract_white_list(1465 origin,1466 contract_address: T::AccountId,1467 account_address: T::AccountId1468 ) -> DispatchResult {1469 let sender = ensure_signed(origin)?;14701471 #[cfg(feature = "runtime-benchmarks")]1472 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1473 1474 Self::ensure_contract_owned(sender, &contract_address)?; 1475 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1476 Ok(())1477 }14781479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1491 pub fn remove_from_contract_white_list(1492 origin,1493 contract_address: T::AccountId,1494 account_address: T::AccountId1495 ) -> DispatchResult {1496 let sender = ensure_signed(origin)?;14971498 #[cfg(feature = "runtime-benchmarks")]1499 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15001501 Self::ensure_contract_owned(sender, &contract_address)?;1502 <ContractWhiteList<T>>::remove(contract_address, account_address);1503 Ok(())1504 }15051506 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1507 pub fn set_collection_limits(1508 origin,1509 collection_id: u32,1510 limits: CollectionLimits,1511 ) -> DispatchResult {1512 let sender = ensure_signed(origin)?;1513 Self::check_owner_permissions(collection_id, sender.clone())?;1514 let mut target_collection = <Collection<T>>::get(collection_id);1515 let chain_limits = ChainLimit::get();1516 let climits = target_collection.limits;15171518 1519 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1520 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1521 Error::<T>::CollectionLimitBoundsExceeded);15221523 1524 ensure!(climits.token_limit > limits.token_limit && 1525 limits.token_limit <= chain_limits.account_token_ownership_limit, 1526 Error::<T>::AccountTokenLimitExceeded);15271528 target_collection.limits = limits;1529 <Collection<T>>::insert(collection_id, target_collection);15301531 Ok(())1532 } 1533 }1534}15351536impl<T: Config> Module<T> {15371538 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {15391540 let target_collection = <Collection<T>>::get(collection_id);15411542 1543 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;15441545 1546 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1547 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1548 Error::<T>::NoPermission);15491550 if target_collection.access == AccessMode::WhiteList {1551 Self::check_white_list(collection_id, &sender)?;1552 Self::check_white_list(collection_id, &recipient)?;1553 }15541555 match target_collection.mode1556 {1557 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1558 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1559 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1560 _ => ()1561 };15621563 Ok(())1564 }156515661567 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15681569 1570 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1571 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1572 1573 Ok(())1574 }15751576 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15771578 1579 let total_items: u32 = ItemListIndex::get(collection_id);1580 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1581 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1582 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15831584 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1585 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1586 Self::check_white_list(collection_id, owner)?;1587 Self::check_white_list(collection_id, sender)?;1588 }15891590 Ok(())1591 }15921593 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1594 match target_collection.mode1595 {1596 CollectionMode::NFT => {1597 if let CreateItemData::NFT(data) = data {1598 1599 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1600 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1601 } else {1602 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1603 }1604 },1605 CollectionMode::Fungible(_) => {1606 if let CreateItemData::Fungible(_) = data {1607 } else {1608 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1609 }1610 },1611 CollectionMode::ReFungible(_) => {1612 if let CreateItemData::ReFungible(data) = data {16131614 1615 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1616 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1617 } else {1618 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1619 }1620 },1621 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1622 };16231624 Ok(())1625 }16261627 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1628 match data1629 {1630 CreateItemData::NFT(data) => {1631 let item = NftItemType {1632 owner,1633 const_data: data.const_data,1634 variable_data: data.variable_data1635 };16361637 Self::add_nft_item(collection_id, item)?;1638 },1639 CreateItemData::Fungible(data) => {1640 Self::add_fungible_item(collection_id, &owner, data.value)?;1641 },1642 CreateItemData::ReFungible(data) => {1643 let mut owner_list = Vec::new();1644 let value = (10 as u128).pow(collection.decimal_points as u32);1645 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16461647 let item = ReFungibleItemType {1648 owner: owner_list,1649 const_data: data.const_data,1650 variable_data: data.variable_data1651 };16521653 Self::add_refungible_item(collection_id, item)?;1654 }1655 };16561657 1658 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16591660 Ok(())1661 }16621663 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16641665 1666 let mut balance: u128 = 0;1667 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1668 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1669 } 16701671 1672 let item = FungibleItemType {1673 value: balance + value1674 };1675 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16761677 1678 let new_balance = <Balance<T>>::get(collection_id, owner)1679 .checked_add(value)1680 .ok_or(Error::<T>::NumOverflow)?;1681 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16821683 Ok(())1684 }16851686 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1687 let current_index = <ItemListIndex>::get(collection_id)1688 .checked_add(1)1689 .ok_or(Error::<T>::NumOverflow)?;1690 let itemcopy = item.clone();16911692 let value = item.owner.first().unwrap().fraction;1693 let owner = item.owner.first().unwrap().owner.clone();16941695 Self::add_token_index(collection_id, current_index, &owner)?;16961697 <ItemListIndex>::insert(collection_id, current_index);1698 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16991700 1701 let new_balance = <Balance<T>>::get(collection_id, &owner)1702 .checked_add(value)1703 .ok_or(Error::<T>::NumOverflow)?;1704 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);17051706 Ok(())1707 }17081709 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1710 let current_index = <ItemListIndex>::get(collection_id)1711 .checked_add(1)1712 .ok_or(Error::<T>::NumOverflow)?;17131714 let item_owner = item.owner.clone();1715 Self::add_token_index(collection_id, current_index, &item.owner)?;17161717 <ItemListIndex>::insert(collection_id, current_index);1718 <NftItemList<T>>::insert(collection_id, current_index, item);17191720 1721 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1722 .checked_add(1)1723 .ok_or(Error::<T>::NumOverflow)?;1724 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17251726 Ok(())1727 }17281729 fn burn_refungible_item(1730 collection_id: CollectionId,1731 item_id: TokenId,1732 owner: &T::AccountId,1733 ) -> DispatchResult {1734 ensure!(1735 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1736 Error::<T>::TokenNotFound1737 );1738 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1739 let rft_balance = token1740 .owner1741 .iter()1742 .filter(|&i| i.owner == *owner)1743 .next()1744 .unwrap();1745 Self::remove_token_index(collection_id, item_id, owner)?;17461747 1748 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1749 .checked_sub(rft_balance.fraction)1750 .ok_or(Error::<T>::NumOverflow)?;1751 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17521753 1754 let index = token1755 .owner1756 .iter()1757 .position(|i| i.owner == *owner)1758 .unwrap();1759 token.owner.remove(index);1760 let owner_count = token.owner.len();17611762 1763 if owner_count == 0 {1764 <ReFungibleItemList<T>>::remove(collection_id, item_id);1765 }1766 else {1767 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1768 }17691770 Ok(())1771 }17721773 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1774 ensure!(1775 <NftItemList<T>>::contains_key(collection_id, item_id),1776 Error::<T>::TokenNotFound1777 );1778 let item = <NftItemList<T>>::get(collection_id, item_id);1779 Self::remove_token_index(collection_id, item_id, &item.owner)?;17801781 1782 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1783 .checked_sub(1)1784 .ok_or(Error::<T>::NumOverflow)?;1785 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1786 <NftItemList<T>>::remove(collection_id, item_id);17871788 Ok(())1789 }17901791 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1792 ensure!(1793 <FungibleItemList<T>>::contains_key(collection_id, owner),1794 Error::<T>::TokenNotFound1795 );1796 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1797 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17981799 1800 let new_balance = <Balance<T>>::get(collection_id, owner)1801 .checked_sub(value)1802 .ok_or(Error::<T>::NumOverflow)?;1803 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);18041805 if balance.value - value > 0 {1806 balance.value -= value;1807 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1808 }1809 else {1810 <FungibleItemList<T>>::remove(collection_id, owner);1811 }18121813 Ok(())1814 }18151816 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1817 ensure!(1818 <Collection<T>>::contains_key(collection_id),1819 Error::<T>::CollectionNotFound1820 );1821 Ok(())1822 }18231824 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1825 Self::collection_exists(collection_id)?;18261827 let target_collection = <Collection<T>>::get(collection_id);1828 ensure!(1829 subject == target_collection.owner,1830 Error::<T>::NoPermission1831 );18321833 Ok(())1834 }18351836 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1837 let target_collection = <Collection<T>>::get(collection_id);1838 let mut result: bool = subject == target_collection.owner;1839 let exists = <AdminList<T>>::contains_key(collection_id);18401841 if !result & exists {1842 if <AdminList<T>>::get(collection_id).contains(&subject) {1843 result = true1844 }1845 }18461847 result1848 }18491850 fn check_owner_or_admin_permissions(1851 collection_id: CollectionId,1852 subject: T::AccountId,1853 ) -> DispatchResult {1854 Self::collection_exists(collection_id)?;1855 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18561857 ensure!(1858 result,1859 Error::<T>::NoPermission1860 );1861 Ok(())1862 }18631864 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1865 let target_collection = <Collection<T>>::get(collection_id);18661867 match target_collection.mode {1868 CollectionMode::NFT => {1869 <NftItemList<T>>::get(collection_id, item_id).owner == subject1870 }1871 CollectionMode::Fungible(_) => {1872 <FungibleItemList<T>>::contains_key(collection_id, &subject)1873 }1874 CollectionMode::ReFungible(_) => {1875 <ReFungibleItemList<T>>::get(collection_id, item_id)1876 .owner1877 .iter()1878 .any(|i| i.owner == subject)1879 }1880 CollectionMode::Invalid => false,1881 }1882 }18831884 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1885 let mes = Error::<T>::AddresNotInWhiteList;1886 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18871888 Ok(())1889 }18901891 1892 1893 fn token_exists(1894 collection_id: CollectionId,1895 item_id: TokenId,1896 owner: &T::AccountId1897 ) -> DispatchResult {1898 let target_collection = <Collection<T>>::get(collection_id);1899 let exists = match target_collection.mode1900 {1901 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1902 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),1903 CollectionMode::ReFungible(_) => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1904 _ => false1905 };19061907 ensure!(exists == true, Error::<T>::TokenNotFound);1908 Ok(())1909 }19101911 fn transfer_fungible(1912 collection_id: CollectionId,1913 value: u128,1914 owner: &T::AccountId,1915 recipient: &T::AccountId,1916 ) -> DispatchResult {1917 Self::token_exists(collection_id, 0, owner)?;19181919 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1920 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);19211922 1923 Self::add_fungible_item(collection_id, recipient, value)?;19241925 1926 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);19271928 1929 if balance.value == value {1930 <FungibleItemList<T>>::remove(collection_id, owner);1931 }1932 else {1933 balance.value -= value;1934 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1935 }19361937 Ok(())1938 }19391940 fn transfer_refungible(1941 collection_id: CollectionId,1942 item_id: TokenId,1943 value: u128,1944 owner: T::AccountId,1945 new_owner: T::AccountId,1946 ) -> DispatchResult {1947 Self::token_exists(collection_id, item_id, &owner)?;19481949 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1950 let item = full_item1951 .owner1952 .iter()1953 .filter(|i| i.owner == owner)1954 .next()1955 .ok_or(Error::<T>::NumOverflow)?;1956 let amount = item.fraction;19571958 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19591960 1961 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1962 .checked_sub(value)1963 .ok_or(Error::<T>::NumOverflow)?;1964 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19651966 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1967 .checked_add(value)1968 .ok_or(Error::<T>::NumOverflow)?;1969 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19701971 let old_owner = item.owner.clone();1972 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19731974 1975 if amount == value && !new_owner_has_account {1976 1977 1978 let mut new_full_item = full_item.clone();1979 new_full_item1980 .owner1981 .iter_mut()1982 .find(|i| i.owner == owner)1983 .unwrap()1984 .owner = new_owner.clone();1985 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19861987 1988 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1989 } else {1990 let mut new_full_item = full_item.clone();1991 new_full_item1992 .owner1993 .iter_mut()1994 .find(|i| i.owner == owner)1995 .unwrap()1996 .fraction -= value;19971998 1999 if new_owner_has_account {2000 2001 new_full_item2002 .owner2003 .iter_mut()2004 .find(|i| i.owner == new_owner)2005 .unwrap()2006 .fraction += value;2007 } else {2008 2009 new_full_item.owner.push(Ownership {2010 owner: new_owner.clone(),2011 fraction: value,2012 });2013 Self::add_token_index(collection_id, item_id, &new_owner)?;2014 }20152016 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2017 }20182019 Ok(())2020 }20212022 fn transfer_nft(2023 collection_id: CollectionId,2024 item_id: TokenId,2025 sender: T::AccountId,2026 new_owner: T::AccountId,2027 ) -> DispatchResult {2028 Self::token_exists(collection_id, item_id, &sender)?;20292030 let mut item = <NftItemList<T>>::get(collection_id, item_id);20312032 ensure!(2033 sender == item.owner,2034 Error::<T>::MustBeTokenOwner2035 );20362037 2038 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2039 .checked_sub(1)2040 .ok_or(Error::<T>::NumOverflow)?;2041 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20422043 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2044 .checked_add(1)2045 .ok_or(Error::<T>::NumOverflow)?;2046 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20472048 2049 let old_owner = item.owner.clone();2050 item.owner = new_owner.clone();2051 <NftItemList<T>>::insert(collection_id, item_id, item);20522053 2054 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20552056 Ok(())2057 }2058 2059 fn set_re_fungible_variable_data(2060 collection_id: CollectionId,2061 item_id: TokenId,2062 data: Vec<u8>2063 ) -> DispatchResult {2064 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20652066 item.variable_data = data;20672068 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20692070 Ok(())2071 }20722073 fn set_nft_variable_data(2074 collection_id: CollectionId,2075 item_id: TokenId,2076 data: Vec<u8>2077 ) -> DispatchResult {2078 let mut item = <NftItemList<T>>::get(collection_id, item_id);2079 2080 item.variable_data = data;20812082 <NftItemList<T>>::insert(collection_id, item_id, item);2083 2084 Ok(())2085 }20862087 fn init_collection(item: &CollectionType<T::AccountId>) {2088 2089 assert!(2090 item.decimal_points <= MAX_DECIMAL_POINTS,2091 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2092 );2093 assert!(2094 item.name.len() <= 64,2095 "Collection name can not be longer than 63 char"2096 );2097 assert!(2098 item.name.len() <= 256,2099 "Collection description can not be longer than 255 char"2100 );2101 assert!(2102 item.token_prefix.len() <= 16,2103 "Token prefix can not be longer than 15 char"2104 );21052106 2107 let next_id = CreatedCollectionCount::get()2108 .checked_add(1)2109 .unwrap();21102111 CreatedCollectionCount::put(next_id);2112 }21132114 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2115 let current_index = <ItemListIndex>::get(collection_id)2116 .checked_add(1)2117 .unwrap();21182119 let item_owner = item.owner.clone();2120 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21212122 <ItemListIndex>::insert(collection_id, current_index);21232124 2125 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2126 .checked_add(1)2127 .unwrap();2128 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2129 }21302131 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2132 let current_index = <ItemListIndex>::get(collection_id)2133 .checked_add(1)2134 .unwrap();21352136 Self::add_token_index(collection_id, current_index, owner).unwrap();21372138 <ItemListIndex>::insert(collection_id, current_index);21392140 2141 let new_balance = <Balance<T>>::get(collection_id, owner)2142 .checked_add(item.value)2143 .unwrap();2144 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2145 }21462147 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2148 let current_index = <ItemListIndex>::get(collection_id)2149 .checked_add(1)2150 .unwrap();21512152 let value = item.owner.first().unwrap().fraction;2153 let owner = item.owner.first().unwrap().owner.clone();21542155 Self::add_token_index(collection_id, current_index, &owner).unwrap();21562157 <ItemListIndex>::insert(collection_id, current_index);21582159 2160 let new_balance = <Balance<T>>::get(collection_id, &owner)2161 .checked_add(value)2162 .unwrap();2163 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2164 }21652166 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {21672168 2169 if <AccountItemCount<T>>::contains_key(owner) {21702171 2172 let count = <AccountItemCount<T>>::get(owner);2173 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21742175 <AccountItemCount<T>>::insert(owner.clone(), count2176 .checked_add(1)2177 .ok_or(Error::<T>::NumOverflow)?);2178 }2179 else {2180 <AccountItemCount<T>>::insert(owner.clone(), 1);2181 }21822183 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2184 if list_exists {2185 let mut list = <AddressTokens<T>>::get(collection_id, owner);2186 let item_contains = list.contains(&item_index.clone());21872188 if !item_contains {2189 list.push(item_index.clone());2190 }21912192 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2193 } else {2194 let mut itm = Vec::new();2195 itm.push(item_index.clone());2196 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2197 }21982199 Ok(())2200 }22012202 fn remove_token_index(2203 collection_id: CollectionId,2204 item_index: TokenId,2205 owner: &T::AccountId,2206 ) -> DispatchResult {22072208 2209 <AccountItemCount<T>>::insert(owner.clone(), 2210 <AccountItemCount<T>>::get(owner)2211 .checked_sub(1)2212 .ok_or(Error::<T>::NumOverflow)?);221322142215 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2216 if list_exists {2217 let mut list = <AddressTokens<T>>::get(collection_id, owner);2218 let item_contains = list.contains(&item_index.clone());22192220 if item_contains {2221 list.retain(|&item| item != item_index);2222 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2223 }2224 }22252226 Ok(())2227 }22282229 fn move_token_index(2230 collection_id: CollectionId,2231 item_index: TokenId,2232 old_owner: &T::AccountId,2233 new_owner: &T::AccountId,2234 ) -> DispatchResult {2235 Self::remove_token_index(collection_id, item_index, old_owner)?;2236 Self::add_token_index(collection_id, item_index, new_owner)?;22372238 Ok(())2239 }2240 2241 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2242 if <ContractOwner<T>>::contains_key(contract.clone()) {2243 let owner = <ContractOwner<T>>::get(contract);2244 ensure!(account == owner, Error::<T>::NoPermission);2245 } else {2246 fail!(Error::<T>::NoPermission);2247 }22482249 Ok(())2250 }2251}2252225322542255225622572258pub type Multiplier = FixedU128;22592260type BalanceOf<T> = <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::Balance;2261226222632264#[derive(Encode, Decode, Clone, Eq, PartialEq)]2265pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);22662267impl<T: Config + Send + Sync> sp_std::fmt::Debug 2268 for ChargeTransactionPayment<T>2269{2270 #[cfg(feature = "std")]2271 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2272 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2273 }2274 #[cfg(not(feature = "std"))]2275 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2276 Ok(())2277 }2278}22792280impl<T: Config> ChargeTransactionPayment<T>2281where2282 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2283 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2284 T::AccountId: AsRef<[u8]>,2285 T::AccountId: UncheckedFrom<T::Hash>,2286{2287 fn traditional_fee(2288 len: usize,2289 info: &DispatchInfoOf<T::Call>,2290 tip: BalanceOf<T>,2291 ) -> BalanceOf<T>2292 where2293 T::Call: Dispatchable<Info = DispatchInfo>,2294 {2295 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2296 }22972298 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2299 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2300 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2301 let len_saturation = max_block_length as u64 / (len as u64).max(1);2302 let coefficient: BalanceOf<T> = weight_saturation2303 .min(len_saturation)2304 .saturated_into::<BalanceOf<T>>();2305 final_fee2306 .saturating_mul(coefficient)2307 .saturated_into::<TransactionPriority>()2308 }23092310 fn withdraw_fee(2311 &self,2312 who: &T::AccountId,2313 call: &T::Call,2314 info: &DispatchInfoOf<T::Call>,2315 len: usize,2316 ) -> Result<2317 (2318 BalanceOf<T>,2319 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2320 ),2321 TransactionValidityError,2322 > {2323 let tip = self.0;23242325 2326 2327 2328 2329 2330 2331 2332 let fee = Self::traditional_fee(len, info, tip);23332334 2335 if fee.is_zero() {2336 return <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2337 .map(|i| (fee, i));2338 }23392340 2341 2342 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2343 Some(Call::create_item(collection_id, _owner, _properties)) => {23442345 2346 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23472348 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2349 let mut sponsored = true;2350 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2351 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2352 let limit_time = last_tx_block + limit.into();2353 if block_number <= limit_time {2354 sponsored = false;2355 }2356 }2357 if sponsored {2358 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2359 }23602361 2362 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2363 (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2364 (sponsored)2365 {2366 <Collection<T>>::get(collection_id).sponsor2367 } else {2368 T::AccountId::default()2369 }2370 }2371 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2372 2373 let mut sponsor_transfer = false;2374 if <Collection<T>>::get(collection_id).sponsor_confirmed {23752376 let collection_limits = <Collection<T>>::get(collection_id).limits;2377 let collection_mode = <Collection<T>>::get(collection_id).mode;2378 2379 2380 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2381 sponsor_transfer = match collection_mode {2382 CollectionMode::NFT => {2383 2384 2385 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2386 collection_limits.sponsor_transfer_timeout2387 } else {2388 ChainLimit::get().nft_sponsor_transfer_timeout2389 };2390 2391 let mut sponsored = true;2392 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2393 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2394 let limit_time = last_tx_block + limit.into();2395 if block_number <= limit_time {2396 sponsored = false;2397 }2398 }2399 if sponsored {2400 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2401 }24022403 sponsored2404 }2405 CollectionMode::Fungible(_) => {2406 2407 2408 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2409 collection_limits.sponsor_transfer_timeout2410 } else {2411 ChainLimit::get().fungible_sponsor_transfer_timeout2412 };2413 2414 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2415 let mut sponsored = true;2416 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2417 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2418 let limit_time = last_tx_block + limit.into();2419 if block_number <= limit_time {2420 sponsored = false;2421 }2422 }2423 if sponsored {2424 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2425 }24262427 sponsored2428 }2429 CollectionMode::ReFungible(_) => {2430 2431 2432 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2433 collection_limits.sponsor_transfer_timeout2434 } else {2435 ChainLimit::get().refungible_sponsor_transfer_timeout2436 };2437 2438 let mut sponsored = true;2439 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2440 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2441 let limit_time = last_tx_block + limit.into();2442 if block_number <= limit_time {2443 sponsored = false;2444 }2445 }2446 if sponsored {2447 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2448 }24492450 sponsored2451 }2452 _ => {2453 false2454 },2455 };2456 }24572458 if !sponsor_transfer {2459 T::AccountId::default()2460 } else {2461 <Collection<T>>::get(collection_id).sponsor2462 }2463 }24642465 _ => T::AccountId::default(),2466 };24672468 2469 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24702471 2472 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {24732474 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2475 &who,2476 code_hash,2477 salt,2478 );2479 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24802481 T::AccountId::default()2482 },24832484 2485 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24862487 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24882489 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2490 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2491 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2492 2493 if !owned_contract && white_list_enabled {2494 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2495 return Err(InvalidTransaction::Call.into());2496 }2497 }24982499 let mut sponsor_transfer = false;2500 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2501 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2502 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2503 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2504 let limit_time = last_tx_block + rate_limit;25052506 if block_number >= limit_time {2507 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2508 sponsor_transfer = true;2509 }2510 } else {2511 sponsor_transfer = false;2512 }2513 2514 2515 let mut sp = T::AccountId::default();2516 if sponsor_transfer {2517 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2518 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2519 sp = called_contract;2520 }2521 }2522 }25232524 sp2525 },25262527 _ => sponsor,2528 };25292530 let mut who_pays_fee: T::AccountId = sponsor.clone();2531 if sponsor == T::AccountId::default() {2532 who_pays_fee = who.clone();2533 }25342535 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2536 .map(|i| (fee, i))2537 }2538}253925402541impl<T: Config + Send + Sync> SignedExtension2542 for ChargeTransactionPayment<T>2543where2544 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2545 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2546 T::AccountId: AsRef<[u8]>,2547 T::AccountId: UncheckedFrom<T::Hash>,2548{2549 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2550 type AccountId = T::AccountId;2551 type Call = T::Call;2552 type AdditionalSigned = ();2553 type Pre = (2554 2555 BalanceOf<T>,2556 2557 Self::AccountId,2558 2559 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2560 );2561 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2562 Ok(())2563 }25642565 fn validate(2566 &self,2567 who: &Self::AccountId,2568 call: &Self::Call,2569 info: &DispatchInfoOf<Self::Call>,2570 len: usize,2571 ) -> TransactionValidity {2572 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2573 Ok(ValidTransaction {2574 priority: Self::get_priority(len, info, fee),2575 ..Default::default()2576 })2577 }25782579 fn pre_dispatch(2580 self,2581 who: &Self::AccountId,2582 call: &Self::Call,2583 info: &DispatchInfoOf<Self::Call>,2584 len: usize,2585 ) -> Result<Self::Pre, TransactionValidityError> {2586 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2587 Ok((self.0, who.clone(), imbalance))2588 }25892590 fn post_dispatch(2591 pre: Self::Pre,2592 info: &DispatchInfoOf<Self::Call>,2593 post_info: &PostDispatchInfoOf<Self::Call>,2594 len: usize,2595 _result: &DispatchResult,2596 ) -> Result<(), TransactionValidityError> {2597 let (tip, who, imbalance) = pre;2598 let actual_fee = transaction_payment::Module::<T>::compute_actual_fee(2599 len as u32,2600 info,2601 post_info,2602 tip,2603 );2604 <T as transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2605 Ok(())2606 }2607}26082609