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_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, 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}189190impl Default for CollectionLimits {191 fn default() -> CollectionLimits {192 CollectionLimits { 193 account_token_ownership_limit: 10_000_000, 194 token_limit: u32::max_value(),195 sponsored_data_size: u32::max_value(), 196 sponsor_transfer_timeout: 14400 }197 }198}199200#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]201#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]202pub struct ChainLimits {203 pub collection_numbers_limit: u32,204 pub account_token_ownership_limit: u32,205 pub collections_admins_limit: u64,206 pub custom_data_limit: u32,207208 209 pub nft_sponsor_transfer_timeout: u32,210 pub fungible_sponsor_transfer_timeout: u32,211 pub refungible_sponsor_transfer_timeout: u32,212213 214 pub offchain_schema_limit: u32,215 pub variable_on_chain_schema_limit: u32,216 pub const_on_chain_schema_limit: u32,217}218219pub trait WeightInfo {220 fn create_collection() -> Weight;221 fn destroy_collection() -> Weight;222 fn add_to_white_list() -> Weight;223 fn remove_from_white_list() -> Weight;224 fn set_public_access_mode() -> Weight;225 fn set_mint_permission() -> Weight;226 fn change_collection_owner() -> Weight;227 fn add_collection_admin() -> Weight;228 fn remove_collection_admin() -> Weight;229 fn set_collection_sponsor() -> Weight;230 fn confirm_sponsorship() -> Weight;231 fn remove_collection_sponsor() -> Weight;232 fn create_item(s: usize) -> Weight;233 fn burn_item() -> Weight;234 fn transfer() -> Weight;235 fn approve() -> Weight;236 fn transfer_from() -> Weight;237 fn set_offchain_schema() -> Weight;238 fn set_const_on_chain_schema() -> Weight;239 fn set_variable_on_chain_schema() -> Weight;240 fn set_variable_meta_data() -> Weight;241 fn enable_contract_sponsoring() -> Weight;242 fn set_schema_version() -> Weight;243 fn set_chain_limits() -> Weight;244 fn set_contract_sponsoring_rate_limit() -> Weight;245 fn toggle_contract_white_list() -> Weight;246 fn add_to_contract_white_list() -> Weight;247 fn remove_from_contract_white_list() -> Weight;248 fn set_collection_limits() -> Weight;249}250251#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]252#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]253pub struct CreateNftData {254 pub const_data: Vec<u8>,255 pub variable_data: Vec<u8>,256}257258#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]259#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]260pub struct CreateFungibleData {261 pub value: u128,262}263264#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]265#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]266pub struct CreateReFungibleData {267 pub const_data: Vec<u8>,268 pub variable_data: Vec<u8>,269 pub pieces: u128,270}271272#[derive(Encode, Decode, Debug, Clone, PartialEq)]273#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]274pub enum CreateItemData {275 NFT(CreateNftData),276 Fungible(CreateFungibleData),277 ReFungible(CreateReFungibleData),278}279280impl CreateItemData {281 pub fn len(&self) -> usize {282 let len = match self {283 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),284 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),285 _ => 0286 };287 288 return len;289 }290}291292impl From<CreateNftData> for CreateItemData {293 fn from(item: CreateNftData) -> Self {294 CreateItemData::NFT(item)295 }296}297298impl From<CreateReFungibleData> for CreateItemData {299 fn from(item: CreateReFungibleData) -> Self {300 CreateItemData::ReFungible(item)301 }302}303304impl From<CreateFungibleData> for CreateItemData {305 fn from(item: CreateFungibleData) -> Self {306 CreateItemData::Fungible(item)307 }308}309310311decl_error! {312 313 pub enum Error for Module<T: Config> {314 315 TotalCollectionsLimitExceeded,316 317 CollectionDecimalPointLimitExceeded, 318 319 CollectionNameLimitExceeded, 320 321 CollectionDescriptionLimitExceeded, 322 323 CollectionTokenPrefixLimitExceeded,324 325 CollectionNotFound,326 327 TokenNotFound,328 329 AdminNotFound,330 331 NumOverflow, 332 333 AlreadyAdmin, 334 335 NoPermission,336 337 ConfirmUnsetSponsorFail,338 339 PublicMintingNotAllowed,340 341 MustBeTokenOwner,342 343 TokenValueTooLow,344 345 NftSizeLimitExceeded,346 347 ApproveNotFound,348 349 TokenValueNotEnough,350 351 ApproveRequired,352 353 AddresNotInWhiteList,354 355 CollectionAdminsLimitExceeded,356 357 AddressOwnershipLimitExceeded,358 359 EmptyArgument,360 361 TokenConstDataLimitExceeded,362 363 TokenVariableDataLimitExceeded,364 365 NotNftDataUsedToMintNftCollectionToken,366 367 NotFungibleDataUsedToMintFungibleCollectionToken,368 369 NotReFungibleDataUsedToMintReFungibleCollectionToken,370 371 UnexpectedCollectionType,372 373 CantStoreMetadataInFungibleTokens,374 375 CollectionTokenLimitExceeded,376 377 AccountTokenLimitExceeded,378 379 CollectionLimitBoundsExceeded,380 381 SchemaDataLimitExceeded,382 383 WrongRefungiblePieces384 }385}386387pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config {388 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;389390 391 type WeightInfo: WeightInfo;392}393394#[cfg(feature = "runtime-benchmarks")]395mod benchmarking;396397398399decl_storage! {400 trait Store for Module<T: Config> as Nft {401402 403 NextCollectionID: CollectionId;404 CreatedCollectionCount: u32;405 ChainVersion: u64;406 ItemListIndex: map hasher(identity) CollectionId => TokenId;407408 409 pub ChainLimit get(fn chain_limit) config(): ChainLimits;410411 412 CollectionCount: u32;413 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;414415 416 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;417 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;418 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;419420 421 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;422423 424 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;425426 427 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;428 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;429 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;430431 432 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;433434 435 pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;436 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;437 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;438 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;439440 441 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;442 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;443 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;444 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;445 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 446 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 447 }448 add_extra_genesis {449 build(|config: &GenesisConfig<T>| {450 451 for (_num, _c) in &config.collection {452 <Module<T>>::init_collection(_c);453 }454455 for (_num, _c, _i) in &config.nft_item_id {456 <Module<T>>::init_nft_token(*_c, _i);457 }458459 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {460 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);461 }462463 for (_num, _c, _i) in &config.refungible_item_id {464 <Module<T>>::init_refungible_token(*_c, _i);465 }466 })467 }468}469470decl_event!(471 pub enum Event<T>472 where473 AccountId = <T as system::Config>::AccountId,474 {475 476 477 478 479 480 481 482 483 484 Created(CollectionId, u8, AccountId),485486 487 488 489 490 491 492 493 ItemCreated(CollectionId, TokenId),494495 496 497 498 499 500 501 502 ItemDestroyed(CollectionId, TokenId),503 }504);505506decl_module! {507 pub struct Module<T: Config> for enum Call 508 where 509 origin: T::Origin510 {511 fn deposit_event() = default;512 type Error = Error<T>;513514 fn on_initialize(now: T::BlockNumber) -> Weight {515516 if ChainVersion::get() < 2517 {518 let value = NextCollectionID::get();519 CreatedCollectionCount::put(value);520 ChainVersion::put(2);521 }522523 0524 }525526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 #[weight = <T as Config>::WeightInfo::create_collection()]543 pub fn create_collection(origin,544 collection_name: Vec<u16>,545 collection_description: Vec<u16>,546 token_prefix: Vec<u8>,547 mode: CollectionMode) -> DispatchResult {548549 550 let who = ensure_signed(origin)?;551552 let decimal_points = match mode {553 CollectionMode::Fungible(points) => points,554 _ => 0555 };556557 558 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);559560 561 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);562 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);563 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);564 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);565566 567 let next_id = CreatedCollectionCount::get()568 .checked_add(1)569 .ok_or(Error::<T>::NumOverflow)?;570571 572 let total = CollectionCount::get()573 .checked_add(1)574 .ok_or(Error::<T>::NumOverflow)?;575576 CreatedCollectionCount::put(next_id);577 CollectionCount::put(total);578579 580 let new_collection = CollectionType {581 owner: who.clone(),582 name: collection_name,583 mode: mode.clone(),584 mint_mode: false,585 access: AccessMode::Normal,586 description: collection_description,587 decimal_points: decimal_points,588 token_prefix: token_prefix,589 offchain_schema: Vec::new(),590 schema_version: SchemaVersion::ImageURL,591 sponsor: T::AccountId::default(),592 sponsor_confirmed: false,593 variable_on_chain_schema: Vec::new(),594 const_on_chain_schema: Vec::new(),595 limits: CollectionLimits::default(),596 };597598 599 <Collection<T>>::insert(next_id, new_collection);600601 602 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));603604 Ok(())605 }606607 608 609 610 611 612 613 614 615 616 #[weight = <T as Config>::WeightInfo::destroy_collection()]617 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {618619 let sender = ensure_signed(origin)?;620 Self::check_owner_permissions(collection_id, sender)?;621622 <AddressTokens<T>>::remove_prefix(collection_id);623 <Allowances<T>>::remove_prefix(collection_id);624 <Balance<T>>::remove_prefix(collection_id);625 <ItemListIndex>::remove(collection_id);626 <AdminList<T>>::remove(collection_id);627 <Collection<T>>::remove(collection_id);628 <WhiteList<T>>::remove_prefix(collection_id);629630 <NftItemList<T>>::remove_prefix(collection_id);631 <FungibleItemList<T>>::remove_prefix(collection_id);632 <ReFungibleItemList<T>>::remove_prefix(collection_id);633634 <NftTransferBasket<T>>::remove_prefix(collection_id);635 <FungibleTransferBasket<T>>::remove_prefix(collection_id);636 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);637638 if CollectionCount::get() > 0639 {640 641 let total = CollectionCount::get()642 .checked_sub(1)643 .ok_or(Error::<T>::NumOverflow)?;644645 CollectionCount::put(total);646 }647648 Ok(())649 }650651 652 653 654 655 656 657 658 659 660 661 662 663 #[weight = <T as Config>::WeightInfo::add_to_white_list()]664 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{665666 let sender = ensure_signed(origin)?;667 Self::check_owner_or_admin_permissions(collection_id, sender)?;668669 <WhiteList<T>>::insert(collection_id, address, true);670 671 Ok(())672 }673674 675 676 677 678 679 680 681 682 683 684 685 686 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]687 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{688689 let sender = ensure_signed(origin)?;690 Self::check_owner_or_admin_permissions(collection_id, sender)?;691692 <WhiteList<T>>::remove(collection_id, address);693694 Ok(())695 }696697 698 699 700 701 702 703 704 705 706 707 708 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]709 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult710 {711 let sender = ensure_signed(origin)?;712713 Self::check_owner_permissions(collection_id, sender)?;714 let mut target_collection = <Collection<T>>::get(collection_id);715 target_collection.access = mode;716 <Collection<T>>::insert(collection_id, target_collection);717718 Ok(())719 }720721 722 723 724 725 726 727 728 729 730 731 732 733 734 #[weight = <T as Config>::WeightInfo::set_mint_permission()]735 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult736 {737 let sender = ensure_signed(origin)?;738739 Self::check_owner_permissions(collection_id, sender)?;740 let mut target_collection = <Collection<T>>::get(collection_id);741 target_collection.mint_mode = mint_permission;742 <Collection<T>>::insert(collection_id, target_collection);743744 Ok(())745 }746747 748 749 750 751 752 753 754 755 756 757 758 #[weight = <T as Config>::WeightInfo::change_collection_owner()]759 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {760761 let sender = ensure_signed(origin)?;762 Self::check_owner_permissions(collection_id, sender)?;763 let mut target_collection = <Collection<T>>::get(collection_id);764 target_collection.owner = new_owner;765 <Collection<T>>::insert(collection_id, target_collection);766767 Ok(())768 }769770 771 772 773 774 775 776 777 778 779 780 781 782 783 #[weight = <T as Config>::WeightInfo::add_collection_admin()]784 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {785786 let sender = ensure_signed(origin)?;787 Self::check_owner_or_admin_permissions(collection_id, sender)?;788 let mut admin_arr: Vec<T::AccountId> = Vec::new();789790 if <AdminList<T>>::contains_key(collection_id)791 {792 admin_arr = <AdminList<T>>::get(collection_id);793 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);794 }795796 797 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);798799 admin_arr.push(new_admin_id);800 <AdminList<T>>::insert(collection_id, admin_arr);801802 Ok(())803 }804805 806 807 808 809 810 811 812 813 814 815 816 817 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]818 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {819820 let sender = ensure_signed(origin)?;821 Self::check_owner_or_admin_permissions(collection_id, sender)?;822 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);823824 let mut admin_arr = <AdminList<T>>::get(collection_id);825 admin_arr.retain(|i| *i != account_id);826 <AdminList<T>>::insert(collection_id, admin_arr);827828 Ok(())829 }830831 832 833 834 835 836 837 838 839 840 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]841 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {842843 let sender = ensure_signed(origin)?;844 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);845846 let mut target_collection = <Collection<T>>::get(collection_id);847 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);848849 target_collection.sponsor = new_sponsor;850 target_collection.sponsor_confirmed = false;851 <Collection<T>>::insert(collection_id, target_collection);852853 Ok(())854 }855856 857 858 859 860 861 862 863 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]864 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {865866 let sender = ensure_signed(origin)?;867 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);868869 let mut target_collection = <Collection<T>>::get(collection_id);870 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);871872 target_collection.sponsor_confirmed = true;873 <Collection<T>>::insert(collection_id, target_collection);874875 Ok(())876 }877878 879 880 881 882 883 884 885 886 887 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]888 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {889890 let sender = ensure_signed(origin)?;891 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);892893 let mut target_collection = <Collection<T>>::get(collection_id);894 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);895896 target_collection.sponsor = T::AccountId::default();897 target_collection.sponsor_confirmed = false;898 <Collection<T>>::insert(collection_id, target_collection);899900 Ok(())901 }902903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926927 #[weight = <T as Config>::WeightInfo::create_item(data.len())]928 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {929930 let sender = ensure_signed(origin)?;931932 Self::collection_exists(collection_id)?;933934 let target_collection = <Collection<T>>::get(collection_id);935936 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;937 Self::validate_create_item_args(&target_collection, &data)?;938 Self::create_item_no_validation(collection_id, owner, data)?;939940 Ok(())941 }942943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()962 .map(|data| { data.len() })963 .sum())]964 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {965966 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);967 let sender = ensure_signed(origin)?;968969 Self::collection_exists(collection_id)?;970 let target_collection = <Collection<T>>::get(collection_id);971972 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;973974 for data in &items_data {975 Self::validate_create_item_args(&target_collection, data)?;976 }977 for data in &items_data {978 Self::create_item_no_validation(collection_id, owner.clone(), data.clone())?;979 }980981 Ok(())982 }983984 985 986 987 988 989 990 991 992 993 994 995 996 997 #[weight = <T as Config>::WeightInfo::burn_item()]998 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {9991000 let sender = ensure_signed(origin)?;1001 Self::collection_exists(collection_id)?;10021003 1004 let target_collection = <Collection<T>>::get(collection_id);1005 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1006 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1007 Error::<T>::NoPermission);10081009 if target_collection.access == AccessMode::WhiteList {1010 Self::check_white_list(collection_id, &sender)?;1011 }10121013 match target_collection.mode1014 {1015 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1016 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1017 CollectionMode::ReFungible => Self::burn_refungible_item(collection_id, item_id, &sender)?,1018 _ => ()1019 };10201021 1022 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10231024 Ok(())1025 }10261027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 #[weight = <T as Config>::WeightInfo::transfer()]1051 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1052 let sender = ensure_signed(origin)?;1053 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1054 }10551056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 #[weight = <T as Config>::WeightInfo::approve()]1072 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10731074 let sender = ensure_signed(origin)?;10751076 Self::collection_exists(collection_id)?;1077 Self::token_exists(collection_id, item_id, &sender)?;10781079 1080 let target_collection = <Collection<T>>::get(collection_id);1081 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1082 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1083 Error::<T>::NoPermission);10841085 if target_collection.access == AccessMode::WhiteList {1086 Self::check_white_list(collection_id, &sender)?;1087 Self::check_white_list(collection_id, &spender)?;1088 }10891090 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1091 let mut allowance: u128 = amount;1092 if allowance_exists {1093 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1094 }1095 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);10961097 Ok(())1098 }1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 #[weight = <T as Config>::WeightInfo::transfer_from()]1120 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11211122 let sender = ensure_signed(origin)?;1123 let mut appoved_transfer = false;11241125 1126 let mut approval: u128 = 0;1127 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &sender)) {1128 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &sender));1129 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1130 appoved_transfer = true;1131 }11321133 let target_collection = <Collection<T>>::get(collection_id);11341135 1136 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11371138 1139 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1140 Error::<T>::NoPermission);11411142 if target_collection.access == AccessMode::WhiteList {1143 Self::check_white_list(collection_id, &sender)?;1144 Self::check_white_list(collection_id, &recipient)?;1145 }11461147 1148 if approval.checked_sub(value).unwrap_or(0) > 0 {1149 <Allowances<T>>::insert(collection_id, (item_id, &from, &sender), approval - value);1150 }1151 else {1152 <Allowances<T>>::remove(collection_id, (item_id, &from, &sender));1153 }11541155 match target_collection.mode1156 {1157 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1158 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1159 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1160 _ => ()1161 };11621163 Ok(())1164 }11651166 1167 11681169 1170 1171 1172 11731174 11751176 11771178 1179 11801181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1194 pub fn set_variable_meta_data (1195 origin,1196 collection_id: CollectionId,1197 item_id: TokenId,1198 data: Vec<u8>1199 ) -> DispatchResult {1200 let sender = ensure_signed(origin)?;1201 1202 Self::collection_exists(collection_id)?;1203 Self::token_exists(collection_id, item_id, &sender)?;12041205 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12061207 1208 let target_collection = <Collection<T>>::get(collection_id);1209 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1210 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1211 Error::<T>::NoPermission);12121213 match target_collection.mode1214 {1215 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1216 CollectionMode::ReFungible => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1217 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1218 _ => fail!(Error::<T>::UnexpectedCollectionType)1219 };12201221 Ok(())1222 }1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 #[weight = <T as Config>::WeightInfo::set_schema_version()]1239 pub fn set_schema_version(1240 origin,1241 collection_id: CollectionId,1242 version: SchemaVersion1243 ) -> DispatchResult {1244 let sender = ensure_signed(origin)?;1245 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1246 let mut target_collection = <Collection<T>>::get(collection_id);1247 target_collection.schema_version = version;1248 <Collection<T>>::insert(collection_id, target_collection);12491250 Ok(())1251 }12521253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1266 pub fn set_offchain_schema(1267 origin,1268 collection_id: CollectionId,1269 schema: Vec<u8>1270 ) -> DispatchResult {1271 let sender = ensure_signed(origin)?;1272 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12731274 1275 ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12761277 let mut target_collection = <Collection<T>>::get(collection_id);1278 target_collection.offchain_schema = schema;1279 <Collection<T>>::insert(collection_id, target_collection);12801281 Ok(())1282 }12831284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1297 pub fn set_const_on_chain_schema (1298 origin,1299 collection_id: CollectionId,1300 schema: Vec<u8>1301 ) -> DispatchResult {1302 let sender = ensure_signed(origin)?;1303 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13041305 1306 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13071308 let mut target_collection = <Collection<T>>::get(collection_id);1309 target_collection.const_on_chain_schema = schema;1310 <Collection<T>>::insert(collection_id, target_collection);13111312 Ok(())1313 }13141315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1328 pub fn set_variable_on_chain_schema (1329 origin,1330 collection_id: CollectionId,1331 schema: Vec<u8>1332 ) -> DispatchResult {1333 let sender = ensure_signed(origin)?;1334 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13351336 1337 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13381339 let mut target_collection = <Collection<T>>::get(collection_id);1340 target_collection.variable_on_chain_schema = schema;1341 <Collection<T>>::insert(collection_id, target_collection);13421343 Ok(())1344 }13451346 1347 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1348 pub fn set_chain_limits(1349 origin,1350 limits: ChainLimits1351 ) -> DispatchResult {13521353 #[cfg(not(feature = "runtime-benchmarks"))]1354 ensure_root(origin)?;13551356 <ChainLimit>::put(limits);1357 Ok(())1358 }13591360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1372 pub fn enable_contract_sponsoring(1373 origin,1374 contract_address: T::AccountId,1375 enable: bool1376 ) -> DispatchResult {13771378 let sender = ensure_signed(origin)?;13791380 #[cfg(feature = "runtime-benchmarks")]1381 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13821383 Self::ensure_contract_owned(sender, &contract_address)?;13841385 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1386 Ok(())1387 }13881389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1407 pub fn set_contract_sponsoring_rate_limit(1408 origin,1409 contract_address: T::AccountId,1410 rate_limit: T::BlockNumber1411 ) -> DispatchResult {1412 let sender = ensure_signed(origin)?;14131414 #[cfg(feature = "runtime-benchmarks")]1415 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14161417 Self::ensure_contract_owned(sender, &contract_address)?;1418 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1419 Ok(())1420 }14211422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1434 pub fn toggle_contract_white_list(1435 origin,1436 contract_address: T::AccountId,1437 enable: bool1438 ) -> DispatchResult {1439 let sender = ensure_signed(origin)?;14401441 #[cfg(feature = "runtime-benchmarks")]1442 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14431444 Self::ensure_contract_owned(sender, &contract_address)?;1445 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1446 Ok(())1447 }1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1461 pub fn add_to_contract_white_list(1462 origin,1463 contract_address: T::AccountId,1464 account_address: T::AccountId1465 ) -> DispatchResult {1466 let sender = ensure_signed(origin)?;14671468 #[cfg(feature = "runtime-benchmarks")]1469 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1470 1471 Self::ensure_contract_owned(sender, &contract_address)?; 1472 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1473 Ok(())1474 }14751476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1488 pub fn remove_from_contract_white_list(1489 origin,1490 contract_address: T::AccountId,1491 account_address: T::AccountId1492 ) -> DispatchResult {1493 let sender = ensure_signed(origin)?;14941495 #[cfg(feature = "runtime-benchmarks")]1496 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14971498 Self::ensure_contract_owned(sender, &contract_address)?;1499 <ContractWhiteList<T>>::remove(contract_address, account_address);1500 Ok(())1501 }15021503 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1504 pub fn set_collection_limits(1505 origin,1506 collection_id: u32,1507 limits: CollectionLimits,1508 ) -> DispatchResult {1509 let sender = ensure_signed(origin)?;1510 Self::check_owner_permissions(collection_id, sender.clone())?;1511 let mut target_collection = <Collection<T>>::get(collection_id);1512 let chain_limits = ChainLimit::get();1513 let climits = target_collection.limits;15141515 1516 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1517 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1518 Error::<T>::CollectionLimitBoundsExceeded);15191520 1521 ensure!(climits.token_limit > limits.token_limit && 1522 limits.token_limit <= chain_limits.account_token_ownership_limit, 1523 Error::<T>::AccountTokenLimitExceeded);15241525 target_collection.limits = limits;1526 <Collection<T>>::insert(collection_id, target_collection);15271528 Ok(())1529 } 1530 }1531}15321533impl<T: Config> Module<T> {15341535 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {15361537 let target_collection = <Collection<T>>::get(collection_id);15381539 1540 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;15411542 1543 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1544 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1545 Error::<T>::NoPermission);15461547 if target_collection.access == AccessMode::WhiteList {1548 Self::check_white_list(collection_id, &sender)?;1549 Self::check_white_list(collection_id, &recipient)?;1550 }15511552 match target_collection.mode1553 {1554 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1555 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1556 CollectionMode::ReFungible => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1557 _ => ()1558 };15591560 Ok(())1561 }156215631564 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15651566 1567 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1568 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1569 1570 Ok(())1571 }15721573 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15741575 1576 let total_items: u32 = ItemListIndex::get(collection_id);1577 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1578 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1579 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15801581 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1582 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1583 Self::check_white_list(collection_id, owner)?;1584 Self::check_white_list(collection_id, sender)?;1585 }15861587 Ok(())1588 }15891590 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1591 match target_collection.mode1592 {1593 CollectionMode::NFT => {1594 if let CreateItemData::NFT(data) = data {1595 1596 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1597 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1598 } else {1599 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1600 }1601 },1602 CollectionMode::Fungible(_) => {1603 if let CreateItemData::Fungible(_) = data {1604 } else {1605 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1606 }1607 },1608 CollectionMode::ReFungible => {1609 if let CreateItemData::ReFungible(data) = data {16101611 1612 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1613 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);16141615 1616 ensure!(data.pieces <= MAX_REFUNGIBLE_PIECES, Error::<T>::WrongRefungiblePieces);1617 ensure!(data.pieces > 0, Error::<T>::WrongRefungiblePieces);1618 } else {1619 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1620 }1621 },1622 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1623 };16241625 Ok(())1626 }16271628 fn create_item_no_validation(collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1629 match data1630 {1631 CreateItemData::NFT(data) => {1632 let item = NftItemType {1633 owner,1634 const_data: data.const_data,1635 variable_data: data.variable_data1636 };16371638 Self::add_nft_item(collection_id, item)?;1639 },1640 CreateItemData::Fungible(data) => {1641 Self::add_fungible_item(collection_id, &owner, data.value)?;1642 },1643 CreateItemData::ReFungible(data) => {1644 let mut owner_list = Vec::new();1645 owner_list.push(Ownership {owner: owner.clone(), fraction: data.pieces});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