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}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}270271#[derive(Encode, Decode, Debug, Clone, PartialEq)]272#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]273pub enum CreateItemData {274 NFT(CreateNftData),275 Fungible(CreateFungibleData),276 ReFungible(CreateReFungibleData),277}278279impl CreateItemData {280 pub fn len(&self) -> usize {281 let len = match self {282 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),283 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),284 _ => 0285 };286 287 return len;288 }289}290291impl From<CreateNftData> for CreateItemData {292 fn from(item: CreateNftData) -> Self {293 CreateItemData::NFT(item)294 }295}296297impl From<CreateReFungibleData> for CreateItemData {298 fn from(item: CreateReFungibleData) -> Self {299 CreateItemData::ReFungible(item)300 }301}302303impl From<CreateFungibleData> for CreateItemData {304 fn from(item: CreateFungibleData) -> Self {305 CreateItemData::Fungible(item)306 }307}308309310decl_error! {311 312 pub enum Error for Module<T: Config> {313 314 TotalCollectionsLimitExceeded,315 316 CollectionDecimalPointLimitExceeded, 317 318 CollectionNameLimitExceeded, 319 320 CollectionDescriptionLimitExceeded, 321 322 CollectionTokenPrefixLimitExceeded,323 324 CollectionNotFound,325 326 TokenNotFound,327 328 AdminNotFound,329 330 NumOverflow, 331 332 AlreadyAdmin, 333 334 NoPermission,335 336 ConfirmUnsetSponsorFail,337 338 PublicMintingNotAllowed,339 340 MustBeTokenOwner,341 342 TokenValueTooLow,343 344 NftSizeLimitExceeded,345 346 ApproveNotFound,347 348 TokenValueNotEnough,349 350 ApproveRequired,351 352 AddresNotInWhiteList,353 354 CollectionAdminsLimitExceeded,355 356 AddressOwnershipLimitExceeded,357 358 EmptyArgument,359 360 TokenConstDataLimitExceeded,361 362 TokenVariableDataLimitExceeded,363 364 NotNftDataUsedToMintNftCollectionToken,365 366 NotFungibleDataUsedToMintFungibleCollectionToken,367 368 NotReFungibleDataUsedToMintReFungibleCollectionToken,369 370 UnexpectedCollectionType,371 372 CantStoreMetadataInFungibleTokens,373 374 CollectionTokenLimitExceeded,375 376 AccountTokenLimitExceeded,377 378 CollectionLimitBoundsExceeded,379 380 SchemaDataLimitExceeded381 }382}383384pub trait Config: system::Config + Sized + transaction_payment::Config + pallet_contracts::Config {385 type Event: From<Event<Self>> + Into<<Self as system::Config>::Event>;386387 388 type WeightInfo: WeightInfo;389}390391#[cfg(feature = "runtime-benchmarks")]392mod benchmarking;393394395396decl_storage! {397 trait Store for Module<T: Config> as Nft {398399 400 NextCollectionID: CollectionId;401 CreatedCollectionCount: u32;402 ChainVersion: u64;403 ItemListIndex: map hasher(identity) CollectionId => TokenId;404405 406 pub ChainLimit get(fn chain_limit) config(): ChainLimits;407408 409 CollectionCount: u32;410 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;411412 413 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;414 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;415 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;416417 418 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;419420 421 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;422423 424 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;425 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;426 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;427428 429 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;430431 432 pub CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;433 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;434 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;435 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;436437 438 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;439 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;440 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;441 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;442 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 443 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 444 }445 add_extra_genesis {446 build(|config: &GenesisConfig<T>| {447 448 for (_num, _c) in &config.collection {449 <Module<T>>::init_collection(_c);450 }451452 for (_num, _c, _i) in &config.nft_item_id {453 <Module<T>>::init_nft_token(*_c, _i);454 }455456 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {457 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);458 }459460 for (_num, _c, _i) in &config.refungible_item_id {461 <Module<T>>::init_refungible_token(*_c, _i);462 }463 })464 }465}466467decl_event!(468 pub enum Event<T>469 where470 AccountId = <T as system::Config>::AccountId,471 {472 473 474 475 476 477 478 479 480 481 Created(CollectionId, u8, AccountId),482483 484 485 486 487 488 489 490 ItemCreated(CollectionId, TokenId),491492 493 494 495 496 497 498 499 ItemDestroyed(CollectionId, TokenId),500 }501);502503decl_module! {504 pub struct Module<T: Config> for enum Call 505 where 506 origin: T::Origin507 {508 fn deposit_event() = default;509 type Error = Error<T>;510511 fn on_initialize(now: T::BlockNumber) -> Weight {512513 if ChainVersion::get() < 2514 {515 let value = NextCollectionID::get();516 CreatedCollectionCount::put(value);517 ChainVersion::put(2);518 }519520 0521 }522523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 #[weight = <T as Config>::WeightInfo::create_collection()]540 pub fn create_collection(origin,541 collection_name: Vec<u16>,542 collection_description: Vec<u16>,543 token_prefix: Vec<u8>,544 mode: CollectionMode) -> DispatchResult {545546 547 let who = ensure_signed(origin)?;548549 let decimal_points = match mode {550 CollectionMode::Fungible(points) => points,551 CollectionMode::ReFungible(points) => points,552 _ => 0553 };554555 556 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);557558 559 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);560 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);561 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);562 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);563564 565 let next_id = CreatedCollectionCount::get()566 .checked_add(1)567 .ok_or(Error::<T>::NumOverflow)?;568569 570 let total = CollectionCount::get()571 .checked_add(1)572 .ok_or(Error::<T>::NumOverflow)?;573574 CreatedCollectionCount::put(next_id);575 CollectionCount::put(total);576577 578 let new_collection = CollectionType {579 owner: who.clone(),580 name: collection_name,581 mode: mode.clone(),582 mint_mode: false,583 access: AccessMode::Normal,584 description: collection_description,585 decimal_points: decimal_points,586 token_prefix: token_prefix,587 offchain_schema: Vec::new(),588 schema_version: SchemaVersion::ImageURL,589 sponsor: T::AccountId::default(),590 sponsor_confirmed: false,591 variable_on_chain_schema: Vec::new(),592 const_on_chain_schema: Vec::new(),593 limits: CollectionLimits::default(),594 };595596 597 <Collection<T>>::insert(next_id, new_collection);598599 600 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));601602 Ok(())603 }604605 606 607 608 609 610 611 612 613 614 #[weight = <T as Config>::WeightInfo::destroy_collection()]615 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {616617 let sender = ensure_signed(origin)?;618 Self::check_owner_permissions(collection_id, sender)?;619620 <AddressTokens<T>>::remove_prefix(collection_id);621 <Allowances<T>>::remove_prefix(collection_id);622 <Balance<T>>::remove_prefix(collection_id);623 <ItemListIndex>::remove(collection_id);624 <AdminList<T>>::remove(collection_id);625 <Collection<T>>::remove(collection_id);626 <WhiteList<T>>::remove_prefix(collection_id);627628 <NftItemList<T>>::remove_prefix(collection_id);629 <FungibleItemList<T>>::remove_prefix(collection_id);630 <ReFungibleItemList<T>>::remove_prefix(collection_id);631632 <NftTransferBasket<T>>::remove_prefix(collection_id);633 <FungibleTransferBasket<T>>::remove_prefix(collection_id);634 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);635636 if CollectionCount::get() > 0637 {638 639 let total = CollectionCount::get()640 .checked_sub(1)641 .ok_or(Error::<T>::NumOverflow)?;642643 CollectionCount::put(total);644 }645646 Ok(())647 }648649 650 651 652 653 654 655 656 657 658 659 660 661 #[weight = <T as Config>::WeightInfo::add_to_white_list()]662 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{663664 let sender = ensure_signed(origin)?;665 Self::check_owner_or_admin_permissions(collection_id, sender)?;666667 <WhiteList<T>>::insert(collection_id, address, true);668 669 Ok(())670 }671672 673 674 675 676 677 678 679 680 681 682 683 684 #[weight = <T as Config>::WeightInfo::remove_from_white_list()]685 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{686687 let sender = ensure_signed(origin)?;688 Self::check_owner_or_admin_permissions(collection_id, sender)?;689690 <WhiteList<T>>::remove(collection_id, address);691692 Ok(())693 }694695 696 697 698 699 700 701 702 703 704 705 706 #[weight = <T as Config>::WeightInfo::set_public_access_mode()]707 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult708 {709 let sender = ensure_signed(origin)?;710711 Self::check_owner_permissions(collection_id, sender)?;712 let mut target_collection = <Collection<T>>::get(collection_id);713 target_collection.access = mode;714 <Collection<T>>::insert(collection_id, target_collection);715716 Ok(())717 }718719 720 721 722 723 724 725 726 727 728 729 730 731 732 #[weight = <T as Config>::WeightInfo::set_mint_permission()]733 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult734 {735 let sender = ensure_signed(origin)?;736737 Self::check_owner_permissions(collection_id, sender)?;738 let mut target_collection = <Collection<T>>::get(collection_id);739 target_collection.mint_mode = mint_permission;740 <Collection<T>>::insert(collection_id, target_collection);741742 Ok(())743 }744745 746 747 748 749 750 751 752 753 754 755 756 #[weight = <T as Config>::WeightInfo::change_collection_owner()]757 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {758759 let sender = ensure_signed(origin)?;760 Self::check_owner_permissions(collection_id, sender)?;761 let mut target_collection = <Collection<T>>::get(collection_id);762 target_collection.owner = new_owner;763 <Collection<T>>::insert(collection_id, target_collection);764765 Ok(())766 }767768 769 770 771 772 773 774 775 776 777 778 779 780 781 #[weight = <T as Config>::WeightInfo::add_collection_admin()]782 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {783784 let sender = ensure_signed(origin)?;785 Self::check_owner_or_admin_permissions(collection_id, sender)?;786 let mut admin_arr: Vec<T::AccountId> = Vec::new();787788 if <AdminList<T>>::contains_key(collection_id)789 {790 admin_arr = <AdminList<T>>::get(collection_id);791 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);792 }793794 795 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);796797 admin_arr.push(new_admin_id);798 <AdminList<T>>::insert(collection_id, admin_arr);799800 Ok(())801 }802803 804 805 806 807 808 809 810 811 812 813 814 815 #[weight = <T as Config>::WeightInfo::remove_collection_admin()]816 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {817818 let sender = ensure_signed(origin)?;819 Self::check_owner_or_admin_permissions(collection_id, sender)?;820 ensure!(<AdminList<T>>::contains_key(collection_id), Error::<T>::AdminNotFound);821822 let mut admin_arr = <AdminList<T>>::get(collection_id);823 admin_arr.retain(|i| *i != account_id);824 <AdminList<T>>::insert(collection_id, admin_arr);825826 Ok(())827 }828829 830 831 832 833 834 835 836 837 838 #[weight = <T as Config>::WeightInfo::set_collection_sponsor()]839 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {840841 let sender = ensure_signed(origin)?;842 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);843844 let mut target_collection = <Collection<T>>::get(collection_id);845 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);846847 target_collection.sponsor = new_sponsor;848 target_collection.sponsor_confirmed = false;849 <Collection<T>>::insert(collection_id, target_collection);850851 Ok(())852 }853854 855 856 857 858 859 860 861 #[weight = <T as Config>::WeightInfo::confirm_sponsorship()]862 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {863864 let sender = ensure_signed(origin)?;865 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);866867 let mut target_collection = <Collection<T>>::get(collection_id);868 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);869870 target_collection.sponsor_confirmed = true;871 <Collection<T>>::insert(collection_id, target_collection);872873 Ok(())874 }875876 877 878 879 880 881 882 883 884 885 #[weight = <T as Config>::WeightInfo::remove_collection_sponsor()]886 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {887888 let sender = ensure_signed(origin)?;889 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);890891 let mut target_collection = <Collection<T>>::get(collection_id);892 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);893894 target_collection.sponsor = T::AccountId::default();895 target_collection.sponsor_confirmed = false;896 <Collection<T>>::insert(collection_id, target_collection);897898 Ok(())899 }900901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924925 #[weight = <T as Config>::WeightInfo::create_item(data.len())]926 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {927928 let sender = ensure_signed(origin)?;929930 Self::collection_exists(collection_id)?;931932 let target_collection = <Collection<T>>::get(collection_id);933934 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;935 Self::validate_create_item_args(&target_collection, &data)?;936 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;937938 Ok(())939 }940941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 #[weight = <T as Config>::WeightInfo::create_item(items_data.into_iter()960 .map(|data| { data.len() })961 .sum())]962 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {963964 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);965 let sender = ensure_signed(origin)?;966967 Self::collection_exists(collection_id)?;968 let target_collection = <Collection<T>>::get(collection_id);969970 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;971972 for data in &items_data {973 Self::validate_create_item_args(&target_collection, data)?;974 }975 for data in &items_data {976 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;977 }978979 Ok(())980 }981982 983 984 985 986 987 988 989 990 991 992 993 994 995 #[weight = <T as Config>::WeightInfo::burn_item()]996 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {997998 let sender = ensure_signed(origin)?;999 Self::collection_exists(collection_id)?;10001001 1002 let target_collection = <Collection<T>>::get(collection_id);1003 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1004 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1005 Error::<T>::NoPermission);10061007 if target_collection.access == AccessMode::WhiteList {1008 Self::check_white_list(collection_id, &sender)?;1009 }10101011 match target_collection.mode1012 {1013 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1014 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1015 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, &sender)?,1016 _ => ()1017 };10181019 1020 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10211022 Ok(())1023 }10241025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 #[weight = <T as Config>::WeightInfo::transfer()]1049 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {1050 let sender = ensure_signed(origin)?;1051 Self::transfer_internal(sender, recipient, collection_id, item_id, value)1052 }10531054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 #[weight = <T as Config>::WeightInfo::approve()]1070 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10711072 let sender = ensure_signed(origin)?;10731074 Self::collection_exists(collection_id)?;1075 Self::token_exists(collection_id, item_id, &sender)?;10761077 1078 let target_collection = <Collection<T>>::get(collection_id);1079 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1080 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1081 Error::<T>::NoPermission);10821083 if target_collection.access == AccessMode::WhiteList {1084 Self::check_white_list(collection_id, &sender)?;1085 Self::check_white_list(collection_id, &spender)?;1086 }10871088 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1089 let mut allowance: u128 = amount;1090 if allowance_exists {1091 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1092 }1093 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);10941095 Ok(())1096 }1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 #[weight = <T as Config>::WeightInfo::transfer_from()]1118 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11191120 let sender = ensure_signed(origin)?;1121 let mut appoved_transfer = false;11221123 1124 let mut approval: u128 = 0;1125 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1126 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1127 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1128 appoved_transfer = true;1129 }11301131 let target_collection = <Collection<T>>::get(collection_id);11321133 1134 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11351136 1137 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1138 Error::<T>::NoPermission);11391140 if target_collection.access == AccessMode::WhiteList {1141 Self::check_white_list(collection_id, &sender)?;1142 Self::check_white_list(collection_id, &recipient)?;1143 }11441145 1146 if approval.checked_sub(value).unwrap_or(0) > 0 {1147 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1148 }1149 else {1150 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1151 }11521153 match target_collection.mode1154 {1155 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1156 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1157 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1158 _ => ()1159 };11601161 Ok(())1162 }11631164 1165 11661167 1168 1169 1170 11711172 11731174 11751176 1177 11781179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1192 pub fn set_variable_meta_data (1193 origin,1194 collection_id: CollectionId,1195 item_id: TokenId,1196 data: Vec<u8>1197 ) -> DispatchResult {1198 let sender = ensure_signed(origin)?;1199 1200 Self::collection_exists(collection_id)?;1201 Self::token_exists(collection_id, item_id, &sender)?;12021203 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12041205 1206 let target_collection = <Collection<T>>::get(collection_id);1207 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1208 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1209 Error::<T>::NoPermission);12101211 match target_collection.mode1212 {1213 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1214 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1215 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1216 _ => fail!(Error::<T>::UnexpectedCollectionType)1217 };12181219 Ok(())1220 }1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 #[weight = <T as Config>::WeightInfo::set_schema_version()]1237 pub fn set_schema_version(1238 origin,1239 collection_id: CollectionId,1240 version: SchemaVersion1241 ) -> DispatchResult {1242 let sender = ensure_signed(origin)?;1243 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1244 let mut target_collection = <Collection<T>>::get(collection_id);1245 target_collection.schema_version = version;1246 <Collection<T>>::insert(collection_id, target_collection);12471248 Ok(())1249 }12501251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1264 pub fn set_offchain_schema(1265 origin,1266 collection_id: CollectionId,1267 schema: Vec<u8>1268 ) -> DispatchResult {1269 let sender = ensure_signed(origin)?;1270 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12711272 1273 ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12741275 let mut target_collection = <Collection<T>>::get(collection_id);1276 target_collection.offchain_schema = schema;1277 <Collection<T>>::insert(collection_id, target_collection);12781279 Ok(())1280 }12811282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1295 pub fn set_const_on_chain_schema (1296 origin,1297 collection_id: CollectionId,1298 schema: Vec<u8>1299 ) -> DispatchResult {1300 let sender = ensure_signed(origin)?;1301 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13021303 1304 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13051306 let mut target_collection = <Collection<T>>::get(collection_id);1307 target_collection.const_on_chain_schema = schema;1308 <Collection<T>>::insert(collection_id, target_collection);13091310 Ok(())1311 }13121313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1326 pub fn set_variable_on_chain_schema (1327 origin,1328 collection_id: CollectionId,1329 schema: Vec<u8>1330 ) -> DispatchResult {1331 let sender = ensure_signed(origin)?;1332 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13331334 1335 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13361337 let mut target_collection = <Collection<T>>::get(collection_id);1338 target_collection.variable_on_chain_schema = schema;1339 <Collection<T>>::insert(collection_id, target_collection);13401341 Ok(())1342 }13431344 1345 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1346 pub fn set_chain_limits(1347 origin,1348 limits: ChainLimits1349 ) -> DispatchResult {13501351 #[cfg(not(feature = "runtime-benchmarks"))]1352 ensure_root(origin)?;13531354 <ChainLimit>::put(limits);1355 Ok(())1356 }13571358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1370 pub fn enable_contract_sponsoring(1371 origin,1372 contract_address: T::AccountId,1373 enable: bool1374 ) -> DispatchResult {13751376 let sender = ensure_signed(origin)?;13771378 #[cfg(feature = "runtime-benchmarks")]1379 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13801381 Self::ensure_contract_owned(sender, &contract_address)?;13821383 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1384 Ok(())1385 }13861387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1405 pub fn set_contract_sponsoring_rate_limit(1406 origin,1407 contract_address: T::AccountId,1408 rate_limit: T::BlockNumber1409 ) -> DispatchResult {1410 let sender = ensure_signed(origin)?;14111412 #[cfg(feature = "runtime-benchmarks")]1413 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14141415 Self::ensure_contract_owned(sender, &contract_address)?;1416 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1417 Ok(())1418 }14191420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1432 pub fn toggle_contract_white_list(1433 origin,1434 contract_address: T::AccountId,1435 enable: bool1436 ) -> DispatchResult {1437 let sender = ensure_signed(origin)?;14381439 #[cfg(feature = "runtime-benchmarks")]1440 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14411442 Self::ensure_contract_owned(sender, &contract_address)?;1443 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1444 Ok(())1445 }1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1459 pub fn add_to_contract_white_list(1460 origin,1461 contract_address: T::AccountId,1462 account_address: T::AccountId1463 ) -> DispatchResult {1464 let sender = ensure_signed(origin)?;14651466 #[cfg(feature = "runtime-benchmarks")]1467 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1468 1469 Self::ensure_contract_owned(sender, &contract_address)?; 1470 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1471 Ok(())1472 }14731474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1486 pub fn remove_from_contract_white_list(1487 origin,1488 contract_address: T::AccountId,1489 account_address: T::AccountId1490 ) -> DispatchResult {1491 let sender = ensure_signed(origin)?;14921493 #[cfg(feature = "runtime-benchmarks")]1494 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14951496 Self::ensure_contract_owned(sender, &contract_address)?;1497 <ContractWhiteList<T>>::remove(contract_address, account_address);1498 Ok(())1499 }15001501 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1502 pub fn set_collection_limits(1503 origin,1504 collection_id: u32,1505 limits: CollectionLimits,1506 ) -> DispatchResult {1507 let sender = ensure_signed(origin)?;1508 Self::check_owner_permissions(collection_id, sender.clone())?;1509 let mut target_collection = <Collection<T>>::get(collection_id);1510 let chain_limits = ChainLimit::get();1511 let climits = target_collection.limits;15121513 1514 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1515 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1516 Error::<T>::CollectionLimitBoundsExceeded);15171518 1519 ensure!(climits.token_limit > limits.token_limit && 1520 limits.token_limit <= chain_limits.account_token_ownership_limit, 1521 Error::<T>::AccountTokenLimitExceeded);15221523 target_collection.limits = limits;1524 <Collection<T>>::insert(collection_id, target_collection);15251526 Ok(())1527 } 1528 }1529}15301531impl<T: Config> Module<T> {15321533 pub fn transfer_internal(sender: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {15341535 let target_collection = <Collection<T>>::get(collection_id);15361537 1538 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;15391540 1541 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1542 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1543 Error::<T>::NoPermission);15441545 if target_collection.access == AccessMode::WhiteList {1546 Self::check_white_list(collection_id, &sender)?;1547 Self::check_white_list(collection_id, &recipient)?;1548 }15491550 match target_collection.mode1551 {1552 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1553 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1554 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1555 _ => ()1556 };15571558 Ok(())1559 }156015611562 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15631564 1565 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1566 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1567 1568 Ok(())1569 }15701571 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15721573 1574 let total_items: u32 = ItemListIndex::get(collection_id);1575 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1576 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1577 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15781579 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1580 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1581 Self::check_white_list(collection_id, owner)?;1582 Self::check_white_list(collection_id, sender)?;1583 }15841585 Ok(())1586 }15871588 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1589 match target_collection.mode1590 {1591 CollectionMode::NFT => {1592 if let CreateItemData::NFT(data) = data {1593 1594 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1595 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1596 } else {1597 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1598 }1599 },1600 CollectionMode::Fungible(_) => {1601 if let CreateItemData::Fungible(_) = data {1602 } else {1603 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1604 }1605 },1606 CollectionMode::ReFungible(_) => {1607 if let CreateItemData::ReFungible(data) = data {16081609 1610 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1611 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1612 } else {1613 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1614 }1615 },1616 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1617 };16181619 Ok(())1620 }16211622 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1623 match data1624 {1625 CreateItemData::NFT(data) => {1626 let item = NftItemType {1627 owner,1628 const_data: data.const_data,1629 variable_data: data.variable_data1630 };16311632 Self::add_nft_item(collection_id, item)?;1633 },1634 CreateItemData::Fungible(data) => {1635 Self::add_fungible_item(collection_id, &owner, data.value)?;1636 },1637 CreateItemData::ReFungible(data) => {1638 let mut owner_list = Vec::new();1639 let value = (10 as u128).pow(collection.decimal_points as u32);1640 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16411642 let item = ReFungibleItemType {1643 owner: owner_list,1644 const_data: data.const_data,1645 variable_data: data.variable_data1646 };16471648 Self::add_refungible_item(collection_id, item)?;1649 }1650 };16511652 1653 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16541655 Ok(())1656 }16571658 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16591660 1661 let mut balance: u128 = 0;1662 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1663 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1664 } 16651666 1667 let item = FungibleItemType {1668 value: balance + value1669 };1670 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16711672 1673 let new_balance = <Balance<T>>::get(collection_id, owner)1674 .checked_add(value)1675 .ok_or(Error::<T>::NumOverflow)?;1676 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16771678 Ok(())1679 }16801681 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1682 let current_index = <ItemListIndex>::get(collection_id)1683 .checked_add(1)1684 .ok_or(Error::<T>::NumOverflow)?;1685 let itemcopy = item.clone();16861687 let value = item.owner.first().unwrap().fraction;1688 let owner = item.owner.first().unwrap().owner.clone();16891690 Self::add_token_index(collection_id, current_index, &owner)?;16911692 <ItemListIndex>::insert(collection_id, current_index);1693 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16941695 1696 let new_balance = <Balance<T>>::get(collection_id, &owner)1697 .checked_add(value)1698 .ok_or(Error::<T>::NumOverflow)?;1699 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);17001701 Ok(())1702 }17031704 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1705 let current_index = <ItemListIndex>::get(collection_id)1706 .checked_add(1)1707 .ok_or(Error::<T>::NumOverflow)?;17081709 let item_owner = item.owner.clone();1710 Self::add_token_index(collection_id, current_index, &item.owner)?;17111712 <ItemListIndex>::insert(collection_id, current_index);1713 <NftItemList<T>>::insert(collection_id, current_index, item);17141715 1716 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1717 .checked_add(1)1718 .ok_or(Error::<T>::NumOverflow)?;1719 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17201721 Ok(())1722 }17231724 fn burn_refungible_item(1725 collection_id: CollectionId,1726 item_id: TokenId,1727 owner: &T::AccountId,1728 ) -> DispatchResult {1729 ensure!(1730 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1731 Error::<T>::TokenNotFound1732 );1733 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1734 let rft_balance = token1735 .owner1736 .iter()1737 .filter(|&i| i.owner == *owner)1738 .next()1739 .unwrap();1740 Self::remove_token_index(collection_id, item_id, owner)?;17411742 1743 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1744 .checked_sub(rft_balance.fraction)1745 .ok_or(Error::<T>::NumOverflow)?;1746 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17471748 1749 let index = token1750 .owner1751 .iter()1752 .position(|i| i.owner == *owner)1753 .unwrap();1754 token.owner.remove(index);1755 let owner_count = token.owner.len();17561757 1758 if owner_count == 0 {1759 <ReFungibleItemList<T>>::remove(collection_id, item_id);1760 }1761 else {1762 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1763 }17641765 Ok(())1766 }17671768 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1769 ensure!(1770 <NftItemList<T>>::contains_key(collection_id, item_id),1771 Error::<T>::TokenNotFound1772 );1773 let item = <NftItemList<T>>::get(collection_id, item_id);1774 Self::remove_token_index(collection_id, item_id, &item.owner)?;17751776 1777 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1778 .checked_sub(1)1779 .ok_or(Error::<T>::NumOverflow)?;1780 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1781 <NftItemList<T>>::remove(collection_id, item_id);17821783 Ok(())1784 }17851786 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1787 ensure!(1788 <FungibleItemList<T>>::contains_key(collection_id, owner),1789 Error::<T>::TokenNotFound1790 );1791 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1792 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17931794 1795 let new_balance = <Balance<T>>::get(collection_id, owner)1796 .checked_sub(value)1797 .ok_or(Error::<T>::NumOverflow)?;1798 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17991800 if balance.value - value > 0 {1801 balance.value -= value;1802 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1803 }1804 else {1805 <FungibleItemList<T>>::remove(collection_id, owner);1806 }18071808 Ok(())1809 }18101811 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1812 ensure!(1813 <Collection<T>>::contains_key(collection_id),1814 Error::<T>::CollectionNotFound1815 );1816 Ok(())1817 }18181819 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1820 Self::collection_exists(collection_id)?;18211822 let target_collection = <Collection<T>>::get(collection_id);1823 ensure!(1824 subject == target_collection.owner,1825 Error::<T>::NoPermission1826 );18271828 Ok(())1829 }18301831 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1832 let target_collection = <Collection<T>>::get(collection_id);1833 let mut result: bool = subject == target_collection.owner;1834 let exists = <AdminList<T>>::contains_key(collection_id);18351836 if !result & exists {1837 if <AdminList<T>>::get(collection_id).contains(&subject) {1838 result = true1839 }1840 }18411842 result1843 }18441845 fn check_owner_or_admin_permissions(1846 collection_id: CollectionId,1847 subject: T::AccountId,1848 ) -> DispatchResult {1849 Self::collection_exists(collection_id)?;1850 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18511852 ensure!(1853 result,1854 Error::<T>::NoPermission1855 );1856 Ok(())1857 }18581859 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1860 let target_collection = <Collection<T>>::get(collection_id);18611862 match target_collection.mode {1863 CollectionMode::NFT => {1864 <NftItemList<T>>::get(collection_id, item_id).owner == subject1865 }1866 CollectionMode::Fungible(_) => {1867 <FungibleItemList<T>>::contains_key(collection_id, &subject)1868 }1869 CollectionMode::ReFungible(_) => {1870 <ReFungibleItemList<T>>::get(collection_id, item_id)1871 .owner1872 .iter()1873 .any(|i| i.owner == subject)1874 }1875 CollectionMode::Invalid => false,1876 }1877 }18781879 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1880 let mes = Error::<T>::AddresNotInWhiteList;1881 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18821883 Ok(())1884 }18851886 1887 1888 fn token_exists(1889 collection_id: CollectionId,1890 item_id: TokenId,1891 owner: &T::AccountId1892 ) -> DispatchResult {1893 let target_collection = <Collection<T>>::get(collection_id);1894 let exists = match target_collection.mode1895 {1896 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1897 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),1898 CollectionMode::ReFungible(_) => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1899 _ => false1900 };19011902 ensure!(exists == true, Error::<T>::TokenNotFound);1903 Ok(())1904 }19051906 fn transfer_fungible(1907 collection_id: CollectionId,1908 value: u128,1909 owner: &T::AccountId,1910 recipient: &T::AccountId,1911 ) -> DispatchResult {1912 Self::token_exists(collection_id, 0, owner)?;19131914 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1915 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);19161917 1918 Self::add_fungible_item(collection_id, recipient, value)?;19191920 1921 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);19221923 1924 if balance.value == value {1925 <FungibleItemList<T>>::remove(collection_id, owner);1926 }1927 else {1928 balance.value -= value;1929 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1930 }19311932 Ok(())1933 }19341935 fn transfer_refungible(1936 collection_id: CollectionId,1937 item_id: TokenId,1938 value: u128,1939 owner: T::AccountId,1940 new_owner: T::AccountId,1941 ) -> DispatchResult {1942 Self::token_exists(collection_id, item_id, &owner)?;19431944 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1945 let item = full_item1946 .owner1947 .iter()1948 .filter(|i| i.owner == owner)1949 .next()1950 .ok_or(Error::<T>::NumOverflow)?;1951 let amount = item.fraction;19521953 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19541955 1956 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1957 .checked_sub(value)1958 .ok_or(Error::<T>::NumOverflow)?;1959 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19601961 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1962 .checked_add(value)1963 .ok_or(Error::<T>::NumOverflow)?;1964 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19651966 let old_owner = item.owner.clone();1967 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19681969 1970 if amount == value && !new_owner_has_account {1971 1972 1973 let mut new_full_item = full_item.clone();1974 new_full_item1975 .owner1976 .iter_mut()1977 .find(|i| i.owner == owner)1978 .unwrap()1979 .owner = new_owner.clone();1980 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19811982 1983 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1984 } else {1985 let mut new_full_item = full_item.clone();1986 new_full_item1987 .owner1988 .iter_mut()1989 .find(|i| i.owner == owner)1990 .unwrap()1991 .fraction -= value;19921993 1994 if new_owner_has_account {1995 1996 new_full_item1997 .owner1998 .iter_mut()1999 .find(|i| i.owner == new_owner)2000 .unwrap()2001 .fraction += value;2002 } else {2003 2004 new_full_item.owner.push(Ownership {2005 owner: new_owner.clone(),2006 fraction: value,2007 });2008 Self::add_token_index(collection_id, item_id, &new_owner)?;2009 }20102011 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2012 }20132014 Ok(())2015 }20162017 fn transfer_nft(2018 collection_id: CollectionId,2019 item_id: TokenId,2020 sender: T::AccountId,2021 new_owner: T::AccountId,2022 ) -> DispatchResult {2023 Self::token_exists(collection_id, item_id, &sender)?;20242025 let mut item = <NftItemList<T>>::get(collection_id, item_id);20262027 ensure!(2028 sender == item.owner,2029 Error::<T>::MustBeTokenOwner2030 );20312032 2033 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2034 .checked_sub(1)2035 .ok_or(Error::<T>::NumOverflow)?;2036 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20372038 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2039 .checked_add(1)2040 .ok_or(Error::<T>::NumOverflow)?;2041 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20422043 2044 let old_owner = item.owner.clone();2045 item.owner = new_owner.clone();2046 <NftItemList<T>>::insert(collection_id, item_id, item);20472048 2049 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20502051 Ok(())2052 }2053 2054 fn set_re_fungible_variable_data(2055 collection_id: CollectionId,2056 item_id: TokenId,2057 data: Vec<u8>2058 ) -> DispatchResult {2059 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20602061 item.variable_data = data;20622063 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20642065 Ok(())2066 }20672068 fn set_nft_variable_data(2069 collection_id: CollectionId,2070 item_id: TokenId,2071 data: Vec<u8>2072 ) -> DispatchResult {2073 let mut item = <NftItemList<T>>::get(collection_id, item_id);2074 2075 item.variable_data = data;20762077 <NftItemList<T>>::insert(collection_id, item_id, item);2078 2079 Ok(())2080 }20812082 fn init_collection(item: &CollectionType<T::AccountId>) {2083 2084 assert!(2085 item.decimal_points <= MAX_DECIMAL_POINTS,2086 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2087 );2088 assert!(2089 item.name.len() <= 64,2090 "Collection name can not be longer than 63 char"2091 );2092 assert!(2093 item.name.len() <= 256,2094 "Collection description can not be longer than 255 char"2095 );2096 assert!(2097 item.token_prefix.len() <= 16,2098 "Token prefix can not be longer than 15 char"2099 );21002101 2102 let next_id = CreatedCollectionCount::get()2103 .checked_add(1)2104 .unwrap();21052106 CreatedCollectionCount::put(next_id);2107 }21082109 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2110 let current_index = <ItemListIndex>::get(collection_id)2111 .checked_add(1)2112 .unwrap();21132114 let item_owner = item.owner.clone();2115 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21162117 <ItemListIndex>::insert(collection_id, current_index);21182119 2120 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2121 .checked_add(1)2122 .unwrap();2123 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2124 }21252126 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2127 let current_index = <ItemListIndex>::get(collection_id)2128 .checked_add(1)2129 .unwrap();21302131 Self::add_token_index(collection_id, current_index, owner).unwrap();21322133 <ItemListIndex>::insert(collection_id, current_index);21342135 2136 let new_balance = <Balance<T>>::get(collection_id, owner)2137 .checked_add(item.value)2138 .unwrap();2139 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2140 }21412142 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2143 let current_index = <ItemListIndex>::get(collection_id)2144 .checked_add(1)2145 .unwrap();21462147 let value = item.owner.first().unwrap().fraction;2148 let owner = item.owner.first().unwrap().owner.clone();21492150 Self::add_token_index(collection_id, current_index, &owner).unwrap();21512152 <ItemListIndex>::insert(collection_id, current_index);21532154 2155 let new_balance = <Balance<T>>::get(collection_id, &owner)2156 .checked_add(value)2157 .unwrap();2158 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2159 }21602161 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {21622163 2164 if <AccountItemCount<T>>::contains_key(owner) {21652166 2167 let count = <AccountItemCount<T>>::get(owner);2168 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21692170 <AccountItemCount<T>>::insert(owner.clone(), count2171 .checked_add(1)2172 .ok_or(Error::<T>::NumOverflow)?);2173 }2174 else {2175 <AccountItemCount<T>>::insert(owner.clone(), 1);2176 }21772178 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2179 if list_exists {2180 let mut list = <AddressTokens<T>>::get(collection_id, owner);2181 let item_contains = list.contains(&item_index.clone());21822183 if !item_contains {2184 list.push(item_index.clone());2185 }21862187 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2188 } else {2189 let mut itm = Vec::new();2190 itm.push(item_index.clone());2191 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2192 }21932194 Ok(())2195 }21962197 fn remove_token_index(2198 collection_id: CollectionId,2199 item_index: TokenId,2200 owner: &T::AccountId,2201 ) -> DispatchResult {22022203 2204 <AccountItemCount<T>>::insert(owner.clone(), 2205 <AccountItemCount<T>>::get(owner)2206 .checked_sub(1)2207 .ok_or(Error::<T>::NumOverflow)?);220822092210 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2211 if list_exists {2212 let mut list = <AddressTokens<T>>::get(collection_id, owner);2213 let item_contains = list.contains(&item_index.clone());22142215 if item_contains {2216 list.retain(|&item| item != item_index);2217 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2218 }2219 }22202221 Ok(())2222 }22232224 fn move_token_index(2225 collection_id: CollectionId,2226 item_index: TokenId,2227 old_owner: &T::AccountId,2228 new_owner: &T::AccountId,2229 ) -> DispatchResult {2230 Self::remove_token_index(collection_id, item_index, old_owner)?;2231 Self::add_token_index(collection_id, item_index, new_owner)?;22322233 Ok(())2234 }2235 2236 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2237 if <ContractOwner<T>>::contains_key(contract.clone()) {2238 let owner = <ContractOwner<T>>::get(contract);2239 ensure!(account == owner, Error::<T>::NoPermission);2240 } else {2241 fail!(Error::<T>::NoPermission);2242 }22432244 Ok(())2245 }2246}2247224822492250225122522253pub type Multiplier = FixedU128;22542255type BalanceOf<T> = <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::Balance;2256225722582259#[derive(Encode, Decode, Clone, Eq, PartialEq)]2260pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);22612262impl<T: Config + Send + Sync> sp_std::fmt::Debug 2263 for ChargeTransactionPayment<T>2264{2265 #[cfg(feature = "std")]2266 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2267 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2268 }2269 #[cfg(not(feature = "std"))]2270 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2271 Ok(())2272 }2273}22742275impl<T: Config> ChargeTransactionPayment<T>2276where2277 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2278 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2279 T::AccountId: AsRef<[u8]>,2280 T::AccountId: UncheckedFrom<T::Hash>,2281{2282 fn traditional_fee(2283 len: usize,2284 info: &DispatchInfoOf<T::Call>,2285 tip: BalanceOf<T>,2286 ) -> BalanceOf<T>2287 where2288 T::Call: Dispatchable<Info = DispatchInfo>,2289 {2290 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2291 }22922293 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2294 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2295 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2296 let len_saturation = max_block_length as u64 / (len as u64).max(1);2297 let coefficient: BalanceOf<T> = weight_saturation2298 .min(len_saturation)2299 .saturated_into::<BalanceOf<T>>();2300 final_fee2301 .saturating_mul(coefficient)2302 .saturated_into::<TransactionPriority>()2303 }23042305 fn withdraw_fee(2306 &self,2307 who: &T::AccountId,2308 call: &T::Call,2309 info: &DispatchInfoOf<T::Call>,2310 len: usize,2311 ) -> Result<2312 (2313 BalanceOf<T>,2314 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2315 ),2316 TransactionValidityError,2317 > {2318 let tip = self.0;23192320 2321 2322 2323 2324 2325 2326 2327 let fee = Self::traditional_fee(len, info, tip);23282329 2330 if fee.is_zero() {2331 return <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2332 .map(|i| (fee, i));2333 }23342335 2336 2337 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2338 Some(Call::create_item(collection_id, _owner, _properties)) => {23392340 2341 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23422343 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2344 let mut sponsored = true;2345 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2346 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2347 let limit_time = last_tx_block + limit.into();2348 if block_number <= limit_time {2349 sponsored = false;2350 }2351 }2352 if sponsored {2353 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2354 }23552356 2357 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2358 (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2359 (sponsored)2360 {2361 <Collection<T>>::get(collection_id).sponsor2362 } else {2363 T::AccountId::default()2364 }2365 }2366 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2367 2368 let mut sponsor_transfer = false;2369 if <Collection<T>>::get(collection_id).sponsor_confirmed {23702371 let collection_limits = <Collection<T>>::get(collection_id).limits;2372 let collection_mode = <Collection<T>>::get(collection_id).mode;2373 2374 2375 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2376 sponsor_transfer = match collection_mode {2377 CollectionMode::NFT => {2378 2379 2380 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2381 collection_limits.sponsor_transfer_timeout2382 } else {2383 ChainLimit::get().nft_sponsor_transfer_timeout2384 };2385 2386 let mut sponsored = true;2387 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2388 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2389 let limit_time = last_tx_block + limit.into();2390 if block_number <= limit_time {2391 sponsored = false;2392 }2393 }2394 if sponsored {2395 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2396 }23972398 sponsored2399 }2400 CollectionMode::Fungible(_) => {2401 2402 2403 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2404 collection_limits.sponsor_transfer_timeout2405 } else {2406 ChainLimit::get().fungible_sponsor_transfer_timeout2407 };2408 2409 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2410 let mut sponsored = true;2411 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2412 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2413 let limit_time = last_tx_block + limit.into();2414 if block_number <= limit_time {2415 sponsored = false;2416 }2417 }2418 if sponsored {2419 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2420 }24212422 sponsored2423 }2424 CollectionMode::ReFungible(_) => {2425 2426 2427 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2428 collection_limits.sponsor_transfer_timeout2429 } else {2430 ChainLimit::get().refungible_sponsor_transfer_timeout2431 };2432 2433 let mut sponsored = true;2434 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2435 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2436 let limit_time = last_tx_block + limit.into();2437 if block_number <= limit_time {2438 sponsored = false;2439 }2440 }2441 if sponsored {2442 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2443 }24442445 sponsored2446 }2447 _ => {2448 false2449 },2450 };2451 }24522453 if !sponsor_transfer {2454 T::AccountId::default()2455 } else {2456 <Collection<T>>::get(collection_id).sponsor2457 }2458 }24592460 _ => T::AccountId::default(),2461 };24622463 2464 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24652466 2467 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {24682469 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2470 &who,2471 code_hash,2472 salt,2473 );2474 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24752476 T::AccountId::default()2477 },24782479 2480 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24812482 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24832484 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2485 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2486 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2487 2488 if !owned_contract && white_list_enabled {2489 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2490 return Err(InvalidTransaction::Call.into());2491 }2492 }24932494 let mut sponsor_transfer = false;2495 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2496 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2497 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2498 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2499 let limit_time = last_tx_block + rate_limit;25002501 if block_number >= limit_time {2502 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2503 sponsor_transfer = true;2504 }2505 } else {2506 sponsor_transfer = false;2507 }2508 2509 2510 let mut sp = T::AccountId::default();2511 if sponsor_transfer {2512 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2513 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2514 sp = called_contract;2515 }2516 }2517 }25182519 sp2520 },25212522 _ => sponsor,2523 };25242525 let mut who_pays_fee: T::AccountId = sponsor.clone();2526 if sponsor == T::AccountId::default() {2527 who_pays_fee = who.clone();2528 }25292530 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2531 .map(|i| (fee, i))2532 }2533}253425352536impl<T: Config + Send + Sync> SignedExtension2537 for ChargeTransactionPayment<T>2538where2539 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2540 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2541 T::AccountId: AsRef<[u8]>,2542 T::AccountId: UncheckedFrom<T::Hash>,2543{2544 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2545 type AccountId = T::AccountId;2546 type Call = T::Call;2547 type AdditionalSigned = ();2548 type Pre = (2549 2550 BalanceOf<T>,2551 2552 Self::AccountId,2553 2554 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2555 );2556 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2557 Ok(())2558 }25592560 fn validate(2561 &self,2562 who: &Self::AccountId,2563 call: &Self::Call,2564 info: &DispatchInfoOf<Self::Call>,2565 len: usize,2566 ) -> TransactionValidity {2567 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2568 Ok(ValidTransaction {2569 priority: Self::get_priority(len, info, fee),2570 ..Default::default()2571 })2572 }25732574 fn pre_dispatch(2575 self,2576 who: &Self::AccountId,2577 call: &Self::Call,2578 info: &DispatchInfoOf<Self::Call>,2579 len: usize,2580 ) -> Result<Self::Pre, TransactionValidityError> {2581 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2582 Ok((self.0, who.clone(), imbalance))2583 }25842585 fn post_dispatch(2586 pre: Self::Pre,2587 info: &DispatchInfoOf<Self::Call>,2588 post_info: &PostDispatchInfoOf<Self::Call>,2589 len: usize,2590 _result: &DispatchResult,2591 ) -> Result<(), TransactionValidityError> {2592 let (tip, who, imbalance) = pre;2593 let actual_fee = transaction_payment::Module::<T>::compute_actual_fee(2594 len as u32,2595 info,2596 post_info,2597 tip,2598 );2599 <T as transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2600 Ok(())2601 }2602}26032604