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 {10501051 let sender = ensure_signed(origin)?;1052 let target_collection = <Collection<T>>::get(collection_id);10531054 1055 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10561057 1058 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1059 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1060 Error::<T>::NoPermission);10611062 if target_collection.access == AccessMode::WhiteList {1063 Self::check_white_list(collection_id, &sender)?;1064 Self::check_white_list(collection_id, &recipient)?;1065 }10661067 match target_collection.mode1068 {1069 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1070 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1071 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1072 _ => ()1073 };10741075 Ok(())1076 }10771078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 #[weight = <T as Config>::WeightInfo::approve()]1094 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10951096 let sender = ensure_signed(origin)?;10971098 Self::collection_exists(collection_id)?;1099 Self::token_exists(collection_id, item_id, &sender)?;11001101 1102 let target_collection = <Collection<T>>::get(collection_id);1103 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1104 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1105 Error::<T>::NoPermission);11061107 if target_collection.access == AccessMode::WhiteList {1108 Self::check_white_list(collection_id, &sender)?;1109 Self::check_white_list(collection_id, &spender)?;1110 }11111112 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1113 let mut allowance: u128 = amount;1114 if allowance_exists {1115 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1116 }1117 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11181119 Ok(())1120 }1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 #[weight = <T as Config>::WeightInfo::transfer_from()]1142 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11431144 let sender = ensure_signed(origin)?;1145 let mut appoved_transfer = false;11461147 1148 let mut approval: u128 = 0;1149 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1150 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1151 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1152 appoved_transfer = true;1153 }11541155 let target_collection = <Collection<T>>::get(collection_id);11561157 1158 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11591160 1161 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1162 Error::<T>::NoPermission);11631164 if target_collection.access == AccessMode::WhiteList {1165 Self::check_white_list(collection_id, &sender)?;1166 Self::check_white_list(collection_id, &recipient)?;1167 }11681169 1170 if approval.checked_sub(value).unwrap_or(0) > 0 {1171 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1172 }1173 else {1174 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1175 }11761177 match target_collection.mode1178 {1179 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1180 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1181 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1182 _ => ()1183 };11841185 Ok(())1186 }11871188 1189 11901191 1192 1193 1194 11951196 11971198 11991200 1201 12021203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 #[weight = <T as Config>::WeightInfo::set_variable_meta_data()]1216 pub fn set_variable_meta_data (1217 origin,1218 collection_id: CollectionId,1219 item_id: TokenId,1220 data: Vec<u8>1221 ) -> DispatchResult {1222 let sender = ensure_signed(origin)?;1223 1224 Self::collection_exists(collection_id)?;1225 Self::token_exists(collection_id, item_id, &sender)?;12261227 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12281229 1230 let target_collection = <Collection<T>>::get(collection_id);1231 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1232 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1233 Error::<T>::NoPermission);12341235 match target_collection.mode1236 {1237 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1238 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1239 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1240 _ => fail!(Error::<T>::UnexpectedCollectionType)1241 };12421243 Ok(())1244 }1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 #[weight = <T as Config>::WeightInfo::set_schema_version()]1261 pub fn set_schema_version(1262 origin,1263 collection_id: CollectionId,1264 version: SchemaVersion1265 ) -> DispatchResult {1266 let sender = ensure_signed(origin)?;1267 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1268 let mut target_collection = <Collection<T>>::get(collection_id);1269 target_collection.schema_version = version;1270 <Collection<T>>::insert(collection_id, target_collection);12711272 Ok(())1273 }12741275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 #[weight = <T as Config>::WeightInfo::set_offchain_schema()]1288 pub fn set_offchain_schema(1289 origin,1290 collection_id: CollectionId,1291 schema: Vec<u8>1292 ) -> DispatchResult {1293 let sender = ensure_signed(origin)?;1294 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12951296 1297 ensure!(schema.len() as u32 > ChainLimit::get().offchain_schema_limit, "");12981299 let mut target_collection = <Collection<T>>::get(collection_id);1300 target_collection.offchain_schema = schema;1301 <Collection<T>>::insert(collection_id, target_collection);13021303 Ok(())1304 }13051306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1319 pub fn set_const_on_chain_schema (1320 origin,1321 collection_id: CollectionId,1322 schema: Vec<u8>1323 ) -> DispatchResult {1324 let sender = ensure_signed(origin)?;1325 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13261327 1328 ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, "");13291330 let mut target_collection = <Collection<T>>::get(collection_id);1331 target_collection.const_on_chain_schema = schema;1332 <Collection<T>>::insert(collection_id, target_collection);13331334 Ok(())1335 }13361337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 #[weight = <T as Config>::WeightInfo::set_const_on_chain_schema()]1350 pub fn set_variable_on_chain_schema (1351 origin,1352 collection_id: CollectionId,1353 schema: Vec<u8>1354 ) -> DispatchResult {1355 let sender = ensure_signed(origin)?;1356 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13571358 1359 ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, "");13601361 let mut target_collection = <Collection<T>>::get(collection_id);1362 target_collection.variable_on_chain_schema = schema;1363 <Collection<T>>::insert(collection_id, target_collection);13641365 Ok(())1366 }13671368 1369 #[weight = <T as Config>::WeightInfo::set_chain_limits()]1370 pub fn set_chain_limits(1371 origin,1372 limits: ChainLimits1373 ) -> DispatchResult {13741375 #[cfg(not(feature = "runtime-benchmarks"))]1376 ensure_root(origin)?;13771378 <ChainLimit>::put(limits);1379 Ok(())1380 }13811382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 #[weight = <T as Config>::WeightInfo::enable_contract_sponsoring()]1394 pub fn enable_contract_sponsoring(1395 origin,1396 contract_address: T::AccountId,1397 enable: bool1398 ) -> DispatchResult {13991400 let sender = ensure_signed(origin)?;14011402 #[cfg(feature = "runtime-benchmarks")]1403 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14041405 Self::ensure_contract_owned(sender, &contract_address)?;14061407 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1408 Ok(())1409 }14101411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 #[weight = <T as Config>::WeightInfo::set_contract_sponsoring_rate_limit()]1429 pub fn set_contract_sponsoring_rate_limit(1430 origin,1431 contract_address: T::AccountId,1432 rate_limit: T::BlockNumber1433 ) -> DispatchResult {1434 let sender = ensure_signed(origin)?;14351436 #[cfg(feature = "runtime-benchmarks")]1437 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14381439 Self::ensure_contract_owned(sender, &contract_address)?;1440 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1441 Ok(())1442 }14431444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 #[weight = <T as Config>::WeightInfo::toggle_contract_white_list()]1456 pub fn toggle_contract_white_list(1457 origin,1458 contract_address: T::AccountId,1459 enable: bool1460 ) -> DispatchResult {1461 let sender = ensure_signed(origin)?;14621463 #[cfg(feature = "runtime-benchmarks")]1464 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14651466 Self::ensure_contract_owned(sender, &contract_address)?;1467 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1468 Ok(())1469 }1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 #[weight = <T as Config>::WeightInfo::add_to_contract_white_list()]1483 pub fn add_to_contract_white_list(1484 origin,1485 contract_address: T::AccountId,1486 account_address: T::AccountId1487 ) -> DispatchResult {1488 let sender = ensure_signed(origin)?;14891490 #[cfg(feature = "runtime-benchmarks")]1491 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1492 1493 Self::ensure_contract_owned(sender, &contract_address)?; 1494 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1495 Ok(())1496 }14971498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 #[weight = <T as Config>::WeightInfo::remove_from_contract_white_list()]1510 pub fn remove_from_contract_white_list(1511 origin,1512 contract_address: T::AccountId,1513 account_address: T::AccountId1514 ) -> DispatchResult {1515 let sender = ensure_signed(origin)?;15161517 #[cfg(feature = "runtime-benchmarks")]1518 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15191520 Self::ensure_contract_owned(sender, &contract_address)?;1521 <ContractWhiteList<T>>::remove(contract_address, account_address);1522 Ok(())1523 }15241525 #[weight = <T as Config>::WeightInfo::set_collection_limits()]1526 pub fn set_collection_limits(1527 origin,1528 collection_id: u32,1529 limits: CollectionLimits,1530 ) -> DispatchResult {1531 let sender = ensure_signed(origin)?;1532 Self::check_owner_permissions(collection_id, sender.clone())?;1533 let mut target_collection = <Collection<T>>::get(collection_id);1534 let chain_limits = ChainLimit::get();1535 let climits = target_collection.limits;15361537 1538 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1539 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1540 Error::<T>::CollectionLimitBoundsExceeded);15411542 1543 ensure!(climits.token_limit > limits.token_limit && 1544 limits.token_limit <= chain_limits.account_token_ownership_limit, 1545 Error::<T>::AccountTokenLimitExceeded);15461547 target_collection.limits = limits;1548 <Collection<T>>::insert(collection_id, target_collection);15491550 Ok(())1551 } 1552 }1553}15541555impl<T: Config> Module<T> {15561557 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15581559 1560 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1561 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1562 1563 Ok(())1564 }15651566 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15671568 1569 let total_items: u32 = ItemListIndex::get(collection_id);1570 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1571 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1572 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15731574 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1575 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1576 Self::check_white_list(collection_id, owner)?;1577 Self::check_white_list(collection_id, sender)?;1578 }15791580 Ok(())1581 }15821583 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1584 match target_collection.mode1585 {1586 CollectionMode::NFT => {1587 if let CreateItemData::NFT(data) = data {1588 1589 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1590 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1591 } else {1592 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1593 }1594 },1595 CollectionMode::Fungible(_) => {1596 if let CreateItemData::Fungible(_) = data {1597 } else {1598 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1599 }1600 },1601 CollectionMode::ReFungible(_) => {1602 if let CreateItemData::ReFungible(data) = data {16031604 1605 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1606 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1607 } else {1608 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1609 }1610 },1611 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1612 };16131614 Ok(())1615 }16161617 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1618 match data1619 {1620 CreateItemData::NFT(data) => {1621 let item = NftItemType {1622 owner,1623 const_data: data.const_data,1624 variable_data: data.variable_data1625 };16261627 Self::add_nft_item(collection_id, item)?;1628 },1629 CreateItemData::Fungible(data) => {1630 Self::add_fungible_item(collection_id, &owner, data.value)?;1631 },1632 CreateItemData::ReFungible(data) => {1633 let mut owner_list = Vec::new();1634 let value = (10 as u128).pow(collection.decimal_points as u32);1635 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16361637 let item = ReFungibleItemType {1638 owner: owner_list,1639 const_data: data.const_data,1640 variable_data: data.variable_data1641 };16421643 Self::add_refungible_item(collection_id, item)?;1644 }1645 };16461647 1648 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16491650 Ok(())1651 }16521653 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16541655 1656 let mut balance: u128 = 0;1657 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1658 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1659 } 16601661 1662 let item = FungibleItemType {1663 value: balance + value1664 };1665 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16661667 1668 let new_balance = <Balance<T>>::get(collection_id, owner)1669 .checked_add(value)1670 .ok_or(Error::<T>::NumOverflow)?;1671 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16721673 Ok(())1674 }16751676 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1677 let current_index = <ItemListIndex>::get(collection_id)1678 .checked_add(1)1679 .ok_or(Error::<T>::NumOverflow)?;1680 let itemcopy = item.clone();16811682 let value = item.owner.first().unwrap().fraction;1683 let owner = item.owner.first().unwrap().owner.clone();16841685 Self::add_token_index(collection_id, current_index, &owner)?;16861687 <ItemListIndex>::insert(collection_id, current_index);1688 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16891690 1691 let new_balance = <Balance<T>>::get(collection_id, &owner)1692 .checked_add(value)1693 .ok_or(Error::<T>::NumOverflow)?;1694 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16951696 Ok(())1697 }16981699 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1700 let current_index = <ItemListIndex>::get(collection_id)1701 .checked_add(1)1702 .ok_or(Error::<T>::NumOverflow)?;17031704 let item_owner = item.owner.clone();1705 Self::add_token_index(collection_id, current_index, &item.owner)?;17061707 <ItemListIndex>::insert(collection_id, current_index);1708 <NftItemList<T>>::insert(collection_id, current_index, item);17091710 1711 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1712 .checked_add(1)1713 .ok_or(Error::<T>::NumOverflow)?;1714 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17151716 Ok(())1717 }17181719 fn burn_refungible_item(1720 collection_id: CollectionId,1721 item_id: TokenId,1722 owner: &T::AccountId,1723 ) -> DispatchResult {1724 ensure!(1725 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1726 Error::<T>::TokenNotFound1727 );1728 let mut token = <ReFungibleItemList<T>>::get(collection_id, item_id);1729 let rft_balance = token1730 .owner1731 .iter()1732 .filter(|&i| i.owner == *owner)1733 .next()1734 .unwrap();1735 Self::remove_token_index(collection_id, item_id, owner)?;17361737 1738 let new_balance = <Balance<T>>::get(collection_id, rft_balance.owner.clone())1739 .checked_sub(rft_balance.fraction)1740 .ok_or(Error::<T>::NumOverflow)?;1741 <Balance<T>>::insert(collection_id, rft_balance.owner.clone(), new_balance);17421743 1744 let index = token1745 .owner1746 .iter()1747 .position(|i| i.owner == *owner)1748 .unwrap();1749 token.owner.remove(index);1750 let owner_count = token.owner.len();17511752 1753 if owner_count == 0 {1754 <ReFungibleItemList<T>>::remove(collection_id, item_id);1755 }1756 else {1757 <ReFungibleItemList<T>>::insert(collection_id, item_id, token);1758 }17591760 Ok(())1761 }17621763 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1764 ensure!(1765 <NftItemList<T>>::contains_key(collection_id, item_id),1766 Error::<T>::TokenNotFound1767 );1768 let item = <NftItemList<T>>::get(collection_id, item_id);1769 Self::remove_token_index(collection_id, item_id, &item.owner)?;17701771 1772 let new_balance = <Balance<T>>::get(collection_id, &item.owner)1773 .checked_sub(1)1774 .ok_or(Error::<T>::NumOverflow)?;1775 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1776 <NftItemList<T>>::remove(collection_id, item_id);17771778 Ok(())1779 }17801781 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1782 ensure!(1783 <FungibleItemList<T>>::contains_key(collection_id, owner),1784 Error::<T>::TokenNotFound1785 );1786 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1787 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17881789 1790 let new_balance = <Balance<T>>::get(collection_id, owner)1791 .checked_sub(value)1792 .ok_or(Error::<T>::NumOverflow)?;1793 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17941795 if balance.value - value > 0 {1796 balance.value -= value;1797 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1798 }1799 else {1800 <FungibleItemList<T>>::remove(collection_id, owner);1801 }18021803 Ok(())1804 }18051806 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1807 ensure!(1808 <Collection<T>>::contains_key(collection_id),1809 Error::<T>::CollectionNotFound1810 );1811 Ok(())1812 }18131814 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1815 Self::collection_exists(collection_id)?;18161817 let target_collection = <Collection<T>>::get(collection_id);1818 ensure!(1819 subject == target_collection.owner,1820 Error::<T>::NoPermission1821 );18221823 Ok(())1824 }18251826 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1827 let target_collection = <Collection<T>>::get(collection_id);1828 let mut result: bool = subject == target_collection.owner;1829 let exists = <AdminList<T>>::contains_key(collection_id);18301831 if !result & exists {1832 if <AdminList<T>>::get(collection_id).contains(&subject) {1833 result = true1834 }1835 }18361837 result1838 }18391840 fn check_owner_or_admin_permissions(1841 collection_id: CollectionId,1842 subject: T::AccountId,1843 ) -> DispatchResult {1844 Self::collection_exists(collection_id)?;1845 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18461847 ensure!(1848 result,1849 Error::<T>::NoPermission1850 );1851 Ok(())1852 }18531854 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1855 let target_collection = <Collection<T>>::get(collection_id);18561857 match target_collection.mode {1858 CollectionMode::NFT => {1859 <NftItemList<T>>::get(collection_id, item_id).owner == subject1860 }1861 CollectionMode::Fungible(_) => {1862 <FungibleItemList<T>>::contains_key(collection_id, &subject)1863 }1864 CollectionMode::ReFungible(_) => {1865 <ReFungibleItemList<T>>::get(collection_id, item_id)1866 .owner1867 .iter()1868 .any(|i| i.owner == subject)1869 }1870 CollectionMode::Invalid => false,1871 }1872 }18731874 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1875 let mes = Error::<T>::AddresNotInWhiteList;1876 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18771878 Ok(())1879 }18801881 1882 1883 fn token_exists(1884 collection_id: CollectionId,1885 item_id: TokenId,1886 owner: &T::AccountId1887 ) -> DispatchResult {1888 let target_collection = <Collection<T>>::get(collection_id);1889 let exists = match target_collection.mode1890 {1891 CollectionMode::NFT => <NftItemList<T>>::contains_key(collection_id, item_id),1892 CollectionMode::Fungible(_) => <FungibleItemList<T>>::contains_key(collection_id, owner),1893 CollectionMode::ReFungible(_) => <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1894 _ => false1895 };18961897 ensure!(exists == true, Error::<T>::TokenNotFound);1898 Ok(())1899 }19001901 fn transfer_fungible(1902 collection_id: CollectionId,1903 value: u128,1904 owner: &T::AccountId,1905 recipient: &T::AccountId,1906 ) -> DispatchResult {1907 Self::token_exists(collection_id, 0, owner)?;19081909 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1910 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);19111912 1913 Self::add_fungible_item(collection_id, recipient, value)?;19141915 1916 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);19171918 1919 if balance.value == value {1920 <FungibleItemList<T>>::remove(collection_id, owner);1921 }1922 else {1923 balance.value -= value;1924 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1925 }19261927 Ok(())1928 }19291930 fn transfer_refungible(1931 collection_id: CollectionId,1932 item_id: TokenId,1933 value: u128,1934 owner: T::AccountId,1935 new_owner: T::AccountId,1936 ) -> DispatchResult {1937 Self::token_exists(collection_id, item_id, &owner)?;19381939 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1940 let item = full_item1941 .owner1942 .iter()1943 .filter(|i| i.owner == owner)1944 .next()1945 .ok_or(Error::<T>::NumOverflow)?;1946 let amount = item.fraction;19471948 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19491950 1951 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1952 .checked_sub(value)1953 .ok_or(Error::<T>::NumOverflow)?;1954 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19551956 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1957 .checked_add(value)1958 .ok_or(Error::<T>::NumOverflow)?;1959 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19601961 let old_owner = item.owner.clone();1962 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19631964 1965 if amount == value && !new_owner_has_account {1966 1967 1968 let mut new_full_item = full_item.clone();1969 new_full_item1970 .owner1971 .iter_mut()1972 .find(|i| i.owner == owner)1973 .unwrap()1974 .owner = new_owner.clone();1975 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19761977 1978 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;1979 } else {1980 let mut new_full_item = full_item.clone();1981 new_full_item1982 .owner1983 .iter_mut()1984 .find(|i| i.owner == owner)1985 .unwrap()1986 .fraction -= value;19871988 1989 if new_owner_has_account {1990 1991 new_full_item1992 .owner1993 .iter_mut()1994 .find(|i| i.owner == new_owner)1995 .unwrap()1996 .fraction += value;1997 } else {1998 1999 new_full_item.owner.push(Ownership {2000 owner: new_owner.clone(),2001 fraction: value,2002 });2003 Self::add_token_index(collection_id, item_id, &new_owner)?;2004 }20052006 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2007 }20082009 Ok(())2010 }20112012 fn transfer_nft(2013 collection_id: CollectionId,2014 item_id: TokenId,2015 sender: T::AccountId,2016 new_owner: T::AccountId,2017 ) -> DispatchResult {2018 Self::token_exists(collection_id, item_id, &sender)?;20192020 let mut item = <NftItemList<T>>::get(collection_id, item_id);20212022 ensure!(2023 sender == item.owner,2024 Error::<T>::MustBeTokenOwner2025 );20262027 2028 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2029 .checked_sub(1)2030 .ok_or(Error::<T>::NumOverflow)?;2031 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20322033 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())2034 .checked_add(1)2035 .ok_or(Error::<T>::NumOverflow)?;2036 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);20372038 2039 let old_owner = item.owner.clone();2040 item.owner = new_owner.clone();2041 <NftItemList<T>>::insert(collection_id, item_id, item);20422043 2044 Self::move_token_index(collection_id, item_id, &old_owner, &new_owner)?;20452046 Ok(())2047 }2048 2049 fn set_re_fungible_variable_data(2050 collection_id: CollectionId,2051 item_id: TokenId,2052 data: Vec<u8>2053 ) -> DispatchResult {2054 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20552056 item.variable_data = data;20572058 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20592060 Ok(())2061 }20622063 fn set_nft_variable_data(2064 collection_id: CollectionId,2065 item_id: TokenId,2066 data: Vec<u8>2067 ) -> DispatchResult {2068 let mut item = <NftItemList<T>>::get(collection_id, item_id);2069 2070 item.variable_data = data;20712072 <NftItemList<T>>::insert(collection_id, item_id, item);2073 2074 Ok(())2075 }20762077 fn init_collection(item: &CollectionType<T::AccountId>) {2078 2079 assert!(2080 item.decimal_points <= MAX_DECIMAL_POINTS,2081 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2082 );2083 assert!(2084 item.name.len() <= 64,2085 "Collection name can not be longer than 63 char"2086 );2087 assert!(2088 item.name.len() <= 256,2089 "Collection description can not be longer than 255 char"2090 );2091 assert!(2092 item.token_prefix.len() <= 16,2093 "Token prefix can not be longer than 15 char"2094 );20952096 2097 let next_id = CreatedCollectionCount::get()2098 .checked_add(1)2099 .unwrap();21002101 CreatedCollectionCount::put(next_id);2102 }21032104 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2105 let current_index = <ItemListIndex>::get(collection_id)2106 .checked_add(1)2107 .unwrap();21082109 let item_owner = item.owner.clone();2110 Self::add_token_index(collection_id, current_index, &item.owner).unwrap();21112112 <ItemListIndex>::insert(collection_id, current_index);21132114 2115 let new_balance = <Balance<T>>::get(collection_id, &item_owner)2116 .checked_add(1)2117 .unwrap();2118 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2119 }21202121 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2122 let current_index = <ItemListIndex>::get(collection_id)2123 .checked_add(1)2124 .unwrap();21252126 Self::add_token_index(collection_id, current_index, owner).unwrap();21272128 <ItemListIndex>::insert(collection_id, current_index);21292130 2131 let new_balance = <Balance<T>>::get(collection_id, owner)2132 .checked_add(item.value)2133 .unwrap();2134 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2135 }21362137 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2138 let current_index = <ItemListIndex>::get(collection_id)2139 .checked_add(1)2140 .unwrap();21412142 let value = item.owner.first().unwrap().fraction;2143 let owner = item.owner.first().unwrap().owner.clone();21442145 Self::add_token_index(collection_id, current_index, &owner).unwrap();21462147 <ItemListIndex>::insert(collection_id, current_index);21482149 2150 let new_balance = <Balance<T>>::get(collection_id, &owner)2151 .checked_add(value)2152 .unwrap();2153 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2154 }21552156 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: &T::AccountId) -> DispatchResult {21572158 2159 if <AccountItemCount<T>>::contains_key(owner) {21602161 2162 let count = <AccountItemCount<T>>::get(owner);2163 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21642165 <AccountItemCount<T>>::insert(owner.clone(), count2166 .checked_add(1)2167 .ok_or(Error::<T>::NumOverflow)?);2168 }2169 else {2170 <AccountItemCount<T>>::insert(owner.clone(), 1);2171 }21722173 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2174 if list_exists {2175 let mut list = <AddressTokens<T>>::get(collection_id, owner);2176 let item_contains = list.contains(&item_index.clone());21772178 if !item_contains {2179 list.push(item_index.clone());2180 }21812182 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2183 } else {2184 let mut itm = Vec::new();2185 itm.push(item_index.clone());2186 <AddressTokens<T>>::insert(collection_id, owner.clone(), itm);2187 }21882189 Ok(())2190 }21912192 fn remove_token_index(2193 collection_id: CollectionId,2194 item_index: TokenId,2195 owner: &T::AccountId,2196 ) -> DispatchResult {21972198 2199 <AccountItemCount<T>>::insert(owner.clone(), 2200 <AccountItemCount<T>>::get(owner)2201 .checked_sub(1)2202 .ok_or(Error::<T>::NumOverflow)?);220322042205 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner);2206 if list_exists {2207 let mut list = <AddressTokens<T>>::get(collection_id, owner);2208 let item_contains = list.contains(&item_index.clone());22092210 if item_contains {2211 list.retain(|&item| item != item_index);2212 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2213 }2214 }22152216 Ok(())2217 }22182219 fn move_token_index(2220 collection_id: CollectionId,2221 item_index: TokenId,2222 old_owner: &T::AccountId,2223 new_owner: &T::AccountId,2224 ) -> DispatchResult {2225 Self::remove_token_index(collection_id, item_index, old_owner)?;2226 Self::add_token_index(collection_id, item_index, new_owner)?;22272228 Ok(())2229 }2230 2231 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2232 if <ContractOwner<T>>::contains_key(contract.clone()) {2233 let owner = <ContractOwner<T>>::get(contract);2234 ensure!(account == owner, Error::<T>::NoPermission);2235 } else {2236 fail!(Error::<T>::NoPermission);2237 }22382239 Ok(())2240 }2241}2242224322442245224622472248pub type Multiplier = FixedU128;22492250type BalanceOf<T> = <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::Balance;2251225222532254#[derive(Encode, Decode, Clone, Eq, PartialEq)]2255pub struct ChargeTransactionPayment<T: Config>(#[codec(compact)] BalanceOf<T>);22562257impl<T: Config + Send + Sync> sp_std::fmt::Debug 2258 for ChargeTransactionPayment<T>2259{2260 #[cfg(feature = "std")]2261 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2262 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2263 }2264 #[cfg(not(feature = "std"))]2265 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2266 Ok(())2267 }2268}22692270impl<T: Config> ChargeTransactionPayment<T>2271where2272 T::Call: Dispatchable<Info=DispatchInfo, PostInfo=PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2273 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2274 T::AccountId: AsRef<[u8]>,2275 T::AccountId: UncheckedFrom<T::Hash>,2276{2277 fn traditional_fee(2278 len: usize,2279 info: &DispatchInfoOf<T::Call>,2280 tip: BalanceOf<T>,2281 ) -> BalanceOf<T>2282 where2283 T::Call: Dispatchable<Info = DispatchInfo>,2284 {2285 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2286 }22872288 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2289 let weight_saturation = T::BlockWeights::get().max_block / info.weight.max(1);2290 let max_block_length = *T::BlockLength::get().max.get(DispatchClass::Normal);2291 let len_saturation = max_block_length as u64 / (len as u64).max(1);2292 let coefficient: BalanceOf<T> = weight_saturation2293 .min(len_saturation)2294 .saturated_into::<BalanceOf<T>>();2295 final_fee2296 .saturating_mul(coefficient)2297 .saturated_into::<TransactionPriority>()2298 }22992300 fn withdraw_fee(2301 &self,2302 who: &T::AccountId,2303 call: &T::Call,2304 info: &DispatchInfoOf<T::Call>,2305 len: usize,2306 ) -> Result<2307 (2308 BalanceOf<T>,2309 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2310 ),2311 TransactionValidityError,2312 > {2313 let tip = self.0;23142315 2316 2317 2318 2319 2320 2321 2322 let fee = Self::traditional_fee(len, info, tip);23232324 2325 if fee.is_zero() {2326 return <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(who, call, info, fee, tip)2327 .map(|i| (fee, i));2328 }23292330 2331 2332 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2333 Some(Call::create_item(collection_id, _owner, _properties)) => {23342335 2336 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23372338 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2339 let mut sponsored = true;2340 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2341 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2342 let limit_time = last_tx_block + limit.into();2343 if block_number <= limit_time {2344 sponsored = false;2345 }2346 }2347 if sponsored {2348 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2349 }23502351 2352 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2353 (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2354 (sponsored)2355 {2356 <Collection<T>>::get(collection_id).sponsor2357 } else {2358 T::AccountId::default()2359 }2360 }2361 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2362 2363 let mut sponsor_transfer = false;2364 if <Collection<T>>::get(collection_id).sponsor_confirmed {23652366 let collection_limits = <Collection<T>>::get(collection_id).limits;2367 let collection_mode = <Collection<T>>::get(collection_id).mode;2368 2369 2370 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2371 sponsor_transfer = match collection_mode {2372 CollectionMode::NFT => {2373 2374 2375 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2376 collection_limits.sponsor_transfer_timeout2377 } else {2378 ChainLimit::get().nft_sponsor_transfer_timeout2379 };2380 2381 let mut sponsored = true;2382 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2383 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2384 let limit_time = last_tx_block + limit.into();2385 if block_number <= limit_time {2386 sponsored = false;2387 }2388 }2389 if sponsored {2390 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2391 }23922393 sponsored2394 }2395 CollectionMode::Fungible(_) => {2396 2397 2398 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2399 collection_limits.sponsor_transfer_timeout2400 } else {2401 ChainLimit::get().fungible_sponsor_transfer_timeout2402 };2403 2404 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2405 let mut sponsored = true;2406 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2407 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2408 let limit_time = last_tx_block + limit.into();2409 if block_number <= limit_time {2410 sponsored = false;2411 }2412 }2413 if sponsored {2414 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2415 }24162417 sponsored2418 }2419 CollectionMode::ReFungible(_) => {2420 2421 2422 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2423 collection_limits.sponsor_transfer_timeout2424 } else {2425 ChainLimit::get().refungible_sponsor_transfer_timeout2426 };2427 2428 let mut sponsored = true;2429 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2430 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2431 let limit_time = last_tx_block + limit.into();2432 if block_number <= limit_time {2433 sponsored = false;2434 }2435 }2436 if sponsored {2437 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2438 }24392440 sponsored2441 }2442 _ => {2443 false2444 },2445 };2446 }24472448 if !sponsor_transfer {2449 T::AccountId::default()2450 } else {2451 <Collection<T>>::get(collection_id).sponsor2452 }2453 }24542455 _ => T::AccountId::default(),2456 };24572458 2459 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24602461 2462 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, _data, salt)) => {24632464 let new_contract_address = <pallet_contracts::Module<T>>::contract_address(2465 &who,2466 code_hash,2467 salt,2468 );2469 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24702471 T::AccountId::default()2472 },24732474 2475 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24762477 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24782479 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2480 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2481 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2482 2483 if !owned_contract && white_list_enabled {2484 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2485 return Err(InvalidTransaction::Call.into());2486 }2487 }24882489 let mut sponsor_transfer = false;2490 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2491 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2492 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2493 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2494 let limit_time = last_tx_block + rate_limit;24952496 if block_number >= limit_time {2497 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2498 sponsor_transfer = true;2499 }2500 } else {2501 sponsor_transfer = false;2502 }2503 2504 2505 let mut sp = T::AccountId::default();2506 if sponsor_transfer {2507 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2508 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2509 sp = called_contract;2510 }2511 }2512 }25132514 sp2515 },25162517 _ => sponsor,2518 };25192520 let mut who_pays_fee: T::AccountId = sponsor.clone();2521 if sponsor == T::AccountId::default() {2522 who_pays_fee = who.clone();2523 }25242525 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::withdraw_fee(&who_pays_fee, call, info, fee, tip)2526 .map(|i| (fee, i))2527 }2528}252925302531impl<T: Config + Send + Sync> SignedExtension2532 for ChargeTransactionPayment<T>2533where2534 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2535 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2536 T::AccountId: AsRef<[u8]>,2537 T::AccountId: UncheckedFrom<T::Hash>,2538{2539 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2540 type AccountId = T::AccountId;2541 type Call = T::Call;2542 type AdditionalSigned = ();2543 type Pre = (2544 2545 BalanceOf<T>,2546 2547 Self::AccountId,2548 2549 <<T as transaction_payment::Config>::OnChargeTransaction as transaction_payment::OnChargeTransaction<T>>::LiquidityInfo,2550 );2551 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2552 Ok(())2553 }25542555 fn validate(2556 &self,2557 who: &Self::AccountId,2558 call: &Self::Call,2559 info: &DispatchInfoOf<Self::Call>,2560 len: usize,2561 ) -> TransactionValidity {2562 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2563 Ok(ValidTransaction {2564 priority: Self::get_priority(len, info, fee),2565 ..Default::default()2566 })2567 }25682569 fn pre_dispatch(2570 self,2571 who: &Self::AccountId,2572 call: &Self::Call,2573 info: &DispatchInfoOf<Self::Call>,2574 len: usize,2575 ) -> Result<Self::Pre, TransactionValidityError> {2576 let (_fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2577 Ok((self.0, who.clone(), imbalance))2578 }25792580 fn post_dispatch(2581 pre: Self::Pre,2582 info: &DispatchInfoOf<Self::Call>,2583 post_info: &PostDispatchInfoOf<Self::Call>,2584 len: usize,2585 _result: &DispatchResult,2586 ) -> Result<(), TransactionValidityError> {2587 let (tip, who, imbalance) = pre;2588 let actual_fee = transaction_payment::Module::<T>::compute_actual_fee(2589 len as u32,2590 info,2591 post_info,2592 tip,2593 );2594 <T as transaction_payment::Config>::OnChargeTransaction::correct_and_deposit_fee(&who, info, post_info, actual_fee, tip, imbalance)?;2595 Ok(())2596 }2597}25982599