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, WithdrawReason,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial,29 },30 IsSubType, 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 pallet_contracts::ContractAddressFor;45use sp_runtime::traits::StaticLookup;4647#[cfg(test)]48mod mock;4950#[cfg(test)]51mod tests;5253mod default_weights;5455pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;56pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;57pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5859606162pub type CollectionId = u32;63pub type TokenId = u32;64pub type DecimalPoints = u8;6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum CollectionMode {69 Invalid,70 NFT,71 72 Fungible(DecimalPoints),73 74 ReFungible(DecimalPoints),75}7677impl Into<u8> for CollectionMode {78 fn into(self) -> u8 {79 match self {80 CollectionMode::Invalid => 0,81 CollectionMode::NFT => 1,82 CollectionMode::Fungible(_) => 2,83 CollectionMode::ReFungible(_) => 3,84 }85 }86}8788#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]89#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]90pub enum AccessMode {91 Normal,92 WhiteList,93}94impl Default for AccessMode {95 fn default() -> Self {96 Self::Normal97 }98}99100impl Default for CollectionMode {101 fn default() -> Self {102 Self::Invalid103 }104}105106#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]107#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]108pub enum SchemaVersion {109 ImageURL,110 Unique,111}112impl Default for SchemaVersion {113 fn default() -> Self {114 Self::ImageURL115 }116}117118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]120pub struct Ownership<AccountId> {121 pub owner: AccountId,122 pub fraction: u128,123}124125#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]126#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]127pub struct CollectionType<AccountId> {128 pub owner: AccountId,129 pub mode: CollectionMode,130 pub access: AccessMode,131 pub decimal_points: DecimalPoints,132 pub name: Vec<u16>, 133 pub description: Vec<u16>, 134 pub token_prefix: Vec<u8>, 135 pub mint_mode: bool,136 pub offchain_schema: Vec<u8>,137 pub schema_version: SchemaVersion,138 pub sponsor: AccountId, 139 pub sponsor_confirmed: bool, 140 pub limits: CollectionLimits, 141 pub variable_on_chain_schema: Vec<u8>, 142 pub const_on_chain_schema: Vec<u8>, 143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct NftItemType<AccountId> {148 pub owner: AccountId,149 pub const_data: Vec<u8>,150 pub variable_data: Vec<u8>,151}152153#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]154#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]155pub struct FungibleItemType {156 pub value: u128,157}158159#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]160#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]161pub struct ReFungibleItemType<AccountId> {162 pub owner: Vec<Ownership<AccountId>>,163 pub const_data: Vec<u8>,164 pub variable_data: Vec<u8>,165}166167168169170171172173174175176177178#[derive(Encode, Decode, Debug, Clone, PartialEq)]179#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]180pub struct CollectionLimits {181 pub account_token_ownership_limit: u32,182 pub sponsored_data_size: u32,183 pub token_limit: u32,184185 186 pub sponsor_transfer_timeout: u32,187}188189impl Default for CollectionLimits {190 fn default() -> CollectionLimits {191 CollectionLimits { 192 account_token_ownership_limit: 10_000_000, 193 token_limit: u32::max_value(),194 sponsored_data_size: u32::max_value(), 195 sponsor_transfer_timeout: 14400 }196 }197}198199#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]200#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]201pub struct ChainLimits {202 pub collection_numbers_limit: u32,203 pub account_token_ownership_limit: u32,204 pub collections_admins_limit: u64,205 pub custom_data_limit: u32,206207 208 pub nft_sponsor_transfer_timeout: u32,209 pub fungible_sponsor_transfer_timeout: u32,210 pub refungible_sponsor_transfer_timeout: u32,211}212213pub trait WeightInfo {214 fn create_collection() -> Weight;215 fn destroy_collection() -> Weight;216 fn add_to_white_list() -> Weight;217 fn remove_from_white_list() -> Weight;218 fn set_public_access_mode() -> Weight;219 fn set_mint_permission() -> Weight;220 fn change_collection_owner() -> Weight;221 fn add_collection_admin() -> Weight;222 fn remove_collection_admin() -> Weight;223 fn set_collection_sponsor() -> Weight;224 fn confirm_sponsorship() -> Weight;225 fn remove_collection_sponsor() -> Weight;226 fn create_item(s: usize) -> Weight;227 fn burn_item() -> Weight;228 fn transfer() -> Weight;229 fn approve() -> Weight;230 fn transfer_from() -> Weight;231 fn set_offchain_schema() -> Weight;232 fn set_const_on_chain_schema() -> Weight;233 fn set_variable_on_chain_schema() -> Weight;234 fn set_variable_meta_data() -> Weight;235 fn enable_contract_sponsoring() -> Weight;236 fn set_schema_version() -> Weight;237 fn set_chain_limits() -> Weight;238 fn set_contract_sponsoring_rate_limit() -> Weight;239 fn toggle_contract_white_list() -> Weight;240 fn add_to_contract_white_list() -> Weight;241 fn remove_from_contract_white_list() -> Weight;242 fn set_collection_limits() -> Weight;243}244245#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]246#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]247pub struct CreateNftData {248 pub const_data: Vec<u8>,249 pub variable_data: Vec<u8>,250}251252#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]253#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]254pub struct CreateFungibleData {255 pub value: u128,256}257258#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]259#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]260pub struct CreateReFungibleData {261 pub const_data: Vec<u8>,262 pub variable_data: Vec<u8>,263}264265#[derive(Encode, Decode, Debug, Clone, PartialEq)]266#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]267pub enum CreateItemData {268 NFT(CreateNftData),269 Fungible(CreateFungibleData),270 ReFungible(CreateReFungibleData),271}272273impl CreateItemData {274 pub fn len(&self) -> usize {275 let len = match self {276 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),277 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),278 _ => 0279 };280 281 return len;282 }283}284285impl From<CreateNftData> for CreateItemData {286 fn from(item: CreateNftData) -> Self {287 CreateItemData::NFT(item)288 }289}290291impl From<CreateReFungibleData> for CreateItemData {292 fn from(item: CreateReFungibleData) -> Self {293 CreateItemData::ReFungible(item)294 }295}296297impl From<CreateFungibleData> for CreateItemData {298 fn from(item: CreateFungibleData) -> Self {299 CreateItemData::Fungible(item)300 }301}302303304decl_error! {305 306 pub enum Error for Module<T: Trait> {307 308 TotalCollectionsLimitExceeded,309 310 CollectionDecimalPointLimitExceeded, 311 312 CollectionNameLimitExceeded, 313 314 CollectionDescriptionLimitExceeded, 315 316 CollectionTokenPrefixLimitExceeded,317 318 CollectionNotFound,319 320 TokenNotFound,321 322 NumOverflow, 323 324 AlreadyAdmin, 325 326 NoPermission,327 328 ConfirmUnsetSponsorFail,329 330 PublicMintingNotAllowed,331 332 MustBeTokenOwner,333 334 TokenValueTooLow,335 336 NftSizeLimitExceeded,337 338 ApproveNotFound,339 340 TokenValueNotEnough,341 342 ApproveRequired,343 344 AddresNotInWhiteList,345 346 CollectionAdminsLimitExceeded,347 348 AddressOwnershipLimitExceeded,349 350 EmptyArgument,351 352 TokenConstDataLimitExceeded,353 354 TokenVariableDataLimitExceeded,355 356 NotNftDataUsedToMintNftCollectionToken,357 358 NotFungibleDataUsedToMintFungibleCollectionToken,359 360 NotReFungibleDataUsedToMintReFungibleCollectionToken,361 362 UnexpectedCollectionType,363 364 CantStoreMetadataInFungibleTokens,365 366 CollectionTokenLimitExceeded,367 368 AccountTokenLimitExceeded,369 370 CollectionLimitBoundsExceeded371 }372}373374pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {375 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;376377 378 type WeightInfo: WeightInfo;379}380381#[cfg(feature = "runtime-benchmarks")]382mod benchmarking;383384385386decl_storage! {387 trait Store for Module<T: Trait> as Nft {388389 390 NextCollectionID: CollectionId;391 CreatedCollectionCount: u32;392 ChainVersion: u64;393 ItemListIndex: map hasher(identity) CollectionId => TokenId;394395 396 pub ChainLimit get(fn chain_limit) config(): ChainLimits;397398 399 CollectionCount: u32;400 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;401402 403 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;404 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;405 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;406407 408 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;409410 411 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;412413 414 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;415 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;416 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;417418 419 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;420421 422 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;423 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;424 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;425426 427 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;428 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;429 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;430 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;431 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 432 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 433 }434 add_extra_genesis {435 build(|config: &GenesisConfig<T>| {436 437 for (_num, _c) in &config.collection {438 <Module<T>>::init_collection(_c);439 }440441 for (_num, _c, _i) in &config.nft_item_id {442 <Module<T>>::init_nft_token(*_c, _i);443 }444445 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {446 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);447 }448449 for (_num, _c, _i) in &config.refungible_item_id {450 <Module<T>>::init_refungible_token(*_c, _i);451 }452 })453 }454}455456decl_event!(457 pub enum Event<T>458 where459 AccountId = <T as system::Trait>::AccountId,460 {461 462 463 464 465 466 467 468 469 470 Created(CollectionId, u8, AccountId),471472 473 474 475 476 477 478 479 ItemCreated(CollectionId, TokenId),480481 482 483 484 485 486 487 488 ItemDestroyed(CollectionId, TokenId),489 }490);491492decl_module! {493 pub struct Module<T: Trait> for enum Call where origin: T::Origin {494495 fn deposit_event() = default;496 type Error = Error<T>;497498 fn on_initialize(now: T::BlockNumber) -> Weight {499500 if ChainVersion::get() < 2501 {502 let value = NextCollectionID::get();503 CreatedCollectionCount::put(value);504 ChainVersion::put(2);505 }506507 0508 }509510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 #[weight = T::WeightInfo::create_collection()]527 pub fn create_collection(origin,528 collection_name: Vec<u16>,529 collection_description: Vec<u16>,530 token_prefix: Vec<u8>,531 mode: CollectionMode) -> DispatchResult {532533 534 let who = ensure_signed(origin)?;535536 let decimal_points = match mode {537 CollectionMode::Fungible(points) => points,538 CollectionMode::ReFungible(points) => points,539 _ => 0540 };541542 543 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);544545 546 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);547548 let mut name = collection_name.to_vec();549 name.push(0);550 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);551552 let mut description = collection_description.to_vec();553 description.push(0);554 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);555556 let mut prefix = token_prefix.to_vec();557 prefix.push(0);558 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);559560 561 let next_id = CreatedCollectionCount::get()562 .checked_add(1)563 .ok_or(Error::<T>::NumOverflow)?;564565 566 let total = CollectionCount::get()567 .checked_add(1)568 .ok_or(Error::<T>::NumOverflow)?;569570 CreatedCollectionCount::put(next_id);571 CollectionCount::put(total);572573 574 let new_collection = CollectionType {575 owner: who.clone(),576 name: name,577 mode: mode.clone(),578 mint_mode: false,579 access: AccessMode::Normal,580 description: description,581 decimal_points: decimal_points,582 token_prefix: prefix,583 offchain_schema: Vec::new(),584 schema_version: SchemaVersion::ImageURL,585 sponsor: T::AccountId::default(),586 sponsor_confirmed: false,587 variable_on_chain_schema: Vec::new(),588 const_on_chain_schema: Vec::new(),589 limits: CollectionLimits::default(),590 };591592 593 <Collection<T>>::insert(next_id, new_collection);594595 596 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));597598 Ok(())599 }600601 602 603 604 605 606 607 608 609 610 #[weight = T::WeightInfo::destroy_collection()]611 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {612613 let sender = ensure_signed(origin)?;614 Self::check_owner_permissions(collection_id, sender)?;615616 <AddressTokens<T>>::remove_prefix(collection_id);617 <Allowances<T>>::remove_prefix(collection_id);618 <Balance<T>>::remove_prefix(collection_id);619 <ItemListIndex>::remove(collection_id);620 <AdminList<T>>::remove(collection_id);621 <Collection<T>>::remove(collection_id);622 <WhiteList<T>>::remove_prefix(collection_id);623624 <NftItemList<T>>::remove_prefix(collection_id);625 <FungibleItemList<T>>::remove_prefix(collection_id);626 <ReFungibleItemList<T>>::remove_prefix(collection_id);627628 <NftTransferBasket<T>>::remove_prefix(collection_id);629 <FungibleTransferBasket<T>>::remove_prefix(collection_id);630 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);631632 if CollectionCount::get() > 0633 {634 635 let total = CollectionCount::get()636 .checked_sub(1)637 .ok_or(Error::<T>::NumOverflow)?;638639 CollectionCount::put(total);640 }641642 Ok(())643 }644645 646 647 648 649 650 651 652 653 654 655 656 657 #[weight = T::WeightInfo::add_to_white_list()]658 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{659660 let sender = ensure_signed(origin)?;661 Self::check_owner_or_admin_permissions(collection_id, sender)?;662663 <WhiteList<T>>::insert(collection_id, address, true);664 665 Ok(())666 }667668 669 670 671 672 673 674 675 676 677 678 679 680 #[weight = T::WeightInfo::remove_from_white_list()]681 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{682683 let sender = ensure_signed(origin)?;684 Self::check_owner_or_admin_permissions(collection_id, sender)?;685686 <WhiteList<T>>::remove(collection_id, address);687688 Ok(())689 }690691 692 693 694 695 696 697 698 699 700 701 702 #[weight = T::WeightInfo::set_public_access_mode()]703 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult704 {705 let sender = ensure_signed(origin)?;706707 Self::check_owner_permissions(collection_id, sender)?;708 let mut target_collection = <Collection<T>>::get(collection_id);709 target_collection.access = mode;710 <Collection<T>>::insert(collection_id, target_collection);711712 Ok(())713 }714715 716 717 718 719 720 721 722 723 724 725 726 727 728 #[weight = T::WeightInfo::set_mint_permission()]729 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult730 {731 let sender = ensure_signed(origin)?;732733 Self::check_owner_permissions(collection_id, sender)?;734 let mut target_collection = <Collection<T>>::get(collection_id);735 target_collection.mint_mode = mint_permission;736 <Collection<T>>::insert(collection_id, target_collection);737738 Ok(())739 }740741 742 743 744 745 746 747 748 749 750 751 752 #[weight = T::WeightInfo::change_collection_owner()]753 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {754755 let sender = ensure_signed(origin)?;756 Self::check_owner_permissions(collection_id, sender)?;757 let mut target_collection = <Collection<T>>::get(collection_id);758 target_collection.owner = new_owner;759 <Collection<T>>::insert(collection_id, target_collection);760761 Ok(())762 }763764 765 766 767 768 769 770 771 772 773 774 775 776 777 #[weight = T::WeightInfo::add_collection_admin()]778 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {779780 let sender = ensure_signed(origin)?;781 Self::check_owner_or_admin_permissions(collection_id, sender)?;782 let mut admin_arr: Vec<T::AccountId> = Vec::new();783784 if <AdminList<T>>::contains_key(collection_id)785 {786 admin_arr = <AdminList<T>>::get(collection_id);787 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);788 }789790 791 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);792793 admin_arr.push(new_admin_id);794 <AdminList<T>>::insert(collection_id, admin_arr);795796 Ok(())797 }798799 800 801 802 803 804 805 806 807 808 809 810 811 #[weight = T::WeightInfo::remove_collection_admin()]812 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {813814 let sender = ensure_signed(origin)?;815 Self::check_owner_or_admin_permissions(collection_id, sender)?;816817 if <AdminList<T>>::contains_key(collection_id)818 {819 let mut admin_arr = <AdminList<T>>::get(collection_id);820 admin_arr.retain(|i| *i != account_id);821 <AdminList<T>>::insert(collection_id, admin_arr);822 }823824 Ok(())825 }826827 828 829 830 831 832 833 834 835 836 #[weight = T::WeightInfo::set_collection_sponsor()]837 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {838839 let sender = ensure_signed(origin)?;840 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);841842 let mut target_collection = <Collection<T>>::get(collection_id);843 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);844845 target_collection.sponsor = new_sponsor;846 target_collection.sponsor_confirmed = false;847 <Collection<T>>::insert(collection_id, target_collection);848849 Ok(())850 }851852 853 854 855 856 857 858 859 #[weight = T::WeightInfo::confirm_sponsorship()]860 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {861862 let sender = ensure_signed(origin)?;863 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);864865 let mut target_collection = <Collection<T>>::get(collection_id);866 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);867868 target_collection.sponsor_confirmed = true;869 <Collection<T>>::insert(collection_id, target_collection);870871 Ok(())872 }873874 875 876 877 878 879 880 881 882 883 #[weight = T::WeightInfo::remove_collection_sponsor()]884 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {885886 let sender = ensure_signed(origin)?;887 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);888889 let mut target_collection = <Collection<T>>::get(collection_id);890 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);891892 target_collection.sponsor = T::AccountId::default();893 target_collection.sponsor_confirmed = false;894 <Collection<T>>::insert(collection_id, target_collection);895896 Ok(())897 }898899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922923 #[weight = T::WeightInfo::create_item(data.len())]924 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {925926 let sender = ensure_signed(origin)?;927928 Self::collection_exists(collection_id)?;929930 let target_collection = <Collection<T>>::get(collection_id);931932 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;933 Self::validate_create_item_args(&target_collection, &data)?;934 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;935936 Ok(())937 }938939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 #[weight = T::WeightInfo::create_item(items_data.into_iter()958 .map(|data| { data.len() })959 .sum())]960 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {961962 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);963 let sender = ensure_signed(origin)?;964965 Self::collection_exists(collection_id)?;966 let target_collection = <Collection<T>>::get(collection_id);967968 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;969970 for data in &items_data {971 Self::validate_create_item_args(&target_collection, data)?;972 }973 for data in &items_data {974 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;975 }976977 Ok(())978 }979980 981 982 983 984 985 986 987 988 989 990 991 992 993 #[weight = T::WeightInfo::burn_item()]994 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {995996 let sender = ensure_signed(origin)?;997 Self::collection_exists(collection_id)?;998999 1000 let target_collection = <Collection<T>>::get(collection_id);1001 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1002 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1003 Error::<T>::NoPermission);10041005 if target_collection.access == AccessMode::WhiteList {1006 Self::check_white_list(collection_id, &sender)?;1007 }10081009 match target_collection.mode1010 {1011 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1012 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1013 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1014 _ => ()1015 };10161017 1018 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10191020 Ok(())1021 }10221023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 #[weight = T::WeightInfo::transfer()]1047 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10481049 let sender = ensure_signed(origin)?;1050 let target_collection = <Collection<T>>::get(collection_id);10511052 1053 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10541055 1056 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1057 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1058 Error::<T>::NoPermission);10591060 if target_collection.access == AccessMode::WhiteList {1061 Self::check_white_list(collection_id, &sender)?;1062 Self::check_white_list(collection_id, &recipient)?;1063 }10641065 match target_collection.mode1066 {1067 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1068 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1069 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1070 _ => ()1071 };10721073 Ok(())1074 }10751076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 #[weight = T::WeightInfo::approve()]1092 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10931094 let sender = ensure_signed(origin)?;10951096 1097 let target_collection = <Collection<T>>::get(collection_id);1098 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1099 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1100 Error::<T>::NoPermission);11011102 if target_collection.access == AccessMode::WhiteList {1103 Self::check_white_list(collection_id, &sender)?;1104 Self::check_white_list(collection_id, &spender)?;1105 }11061107 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1108 let mut allowance: u128 = amount;1109 if allowance_exists {1110 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1111 }1112 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11131114 Ok(())1115 }1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 #[weight = T::WeightInfo::transfer_from()]1137 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11381139 let sender = ensure_signed(origin)?;1140 let mut appoved_transfer = false;11411142 1143 let mut approval: u128 = 0;1144 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1145 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1146 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1147 appoved_transfer = true;1148 }11491150 let target_collection = <Collection<T>>::get(collection_id);11511152 1153 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11541155 1156 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1157 Error::<T>::NoPermission);11581159 if target_collection.access == AccessMode::WhiteList {1160 Self::check_white_list(collection_id, &sender)?;1161 Self::check_white_list(collection_id, &recipient)?;1162 }11631164 1165 if approval - value > 0 {1166 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1167 }1168 else {1169 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1170 }11711172 match target_collection.mode1173 {1174 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1175 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1176 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1177 _ => ()1178 };11791180 Ok(())1181 }11821183 #[weight = 0]1184 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11851186 1187 1188 1189 11901191 11921193 11941195 Ok(())1196 }11971198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 #[weight = T::WeightInfo::set_variable_meta_data()]1211 pub fn set_variable_meta_data (1212 origin,1213 collection_id: CollectionId,1214 item_id: TokenId,1215 data: Vec<u8>1216 ) -> DispatchResult {1217 let sender = ensure_signed(origin)?;1218 1219 Self::collection_exists(collection_id)?;1220 1221 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12221223 1224 let target_collection = <Collection<T>>::get(collection_id);1225 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1226 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1227 Error::<T>::NoPermission);12281229 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12301231 match target_collection.mode1232 {1233 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1234 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1235 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1236 _ => fail!(Error::<T>::UnexpectedCollectionType)1237 };12381239 Ok(())1240 }1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 #[weight = T::WeightInfo::set_schema_version()]1257 pub fn set_schema_version(1258 origin,1259 collection_id: CollectionId,1260 version: SchemaVersion1261 ) -> DispatchResult {1262 let sender = ensure_signed(origin)?;1263 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1264 let mut target_collection = <Collection<T>>::get(collection_id);1265 target_collection.schema_version = version;1266 <Collection<T>>::insert(collection_id, target_collection);12671268 Ok(())1269 }12701271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 #[weight = T::WeightInfo::set_offchain_schema()]1284 pub fn set_offchain_schema(1285 origin,1286 collection_id: CollectionId,1287 schema: Vec<u8>1288 ) -> DispatchResult {1289 let sender = ensure_signed(origin)?;1290 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12911292 let mut target_collection = <Collection<T>>::get(collection_id);1293 target_collection.offchain_schema = schema;1294 <Collection<T>>::insert(collection_id, target_collection);12951296 Ok(())1297 }12981299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 #[weight = T::WeightInfo::set_const_on_chain_schema()]1312 pub fn set_const_on_chain_schema (1313 origin,1314 collection_id: CollectionId,1315 schema: Vec<u8>1316 ) -> DispatchResult {1317 let sender = ensure_signed(origin)?;1318 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13191320 let mut target_collection = <Collection<T>>::get(collection_id);1321 target_collection.const_on_chain_schema = schema;1322 <Collection<T>>::insert(collection_id, target_collection);13231324 Ok(())1325 }13261327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 #[weight = T::WeightInfo::set_const_on_chain_schema()]1340 pub fn set_variable_on_chain_schema (1341 origin,1342 collection_id: CollectionId,1343 schema: Vec<u8>1344 ) -> DispatchResult {1345 let sender = ensure_signed(origin)?;1346 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13471348 let mut target_collection = <Collection<T>>::get(collection_id);1349 target_collection.variable_on_chain_schema = schema;1350 <Collection<T>>::insert(collection_id, target_collection);13511352 Ok(())1353 }13541355 1356 #[weight = T::WeightInfo::set_chain_limits()]1357 pub fn set_chain_limits(1358 origin,1359 limits: ChainLimits1360 ) -> DispatchResult {13611362 #[cfg(not(feature = "runtime-benchmarks"))]1363 ensure_root(origin)?;13641365 <ChainLimit>::put(limits);1366 Ok(())1367 }13681369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 #[weight = T::WeightInfo::enable_contract_sponsoring()]1381 pub fn enable_contract_sponsoring(1382 origin,1383 contract_address: T::AccountId,1384 enable: bool1385 ) -> DispatchResult {13861387 let sender = ensure_signed(origin)?;13881389 #[cfg(feature = "runtime-benchmarks")]1390 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13911392 Self::ensure_contract_owned(sender, &contract_address)?;13931394 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1395 Ok(())1396 }13971398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1416 pub fn set_contract_sponsoring_rate_limit(1417 origin,1418 contract_address: T::AccountId,1419 rate_limit: T::BlockNumber1420 ) -> DispatchResult {1421 let sender = ensure_signed(origin)?;14221423 #[cfg(feature = "runtime-benchmarks")]1424 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14251426 Self::ensure_contract_owned(sender, &contract_address)?;1427 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1428 Ok(())1429 }14301431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 #[weight = T::WeightInfo::toggle_contract_white_list()]1443 pub fn toggle_contract_white_list(1444 origin,1445 contract_address: T::AccountId,1446 enable: bool1447 ) -> DispatchResult {1448 let sender = ensure_signed(origin)?;14491450 #[cfg(feature = "runtime-benchmarks")]1451 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14521453 Self::ensure_contract_owned(sender, &contract_address)?;1454 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1455 Ok(())1456 }1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 #[weight = T::WeightInfo::add_to_contract_white_list()]1470 pub fn add_to_contract_white_list(1471 origin,1472 contract_address: T::AccountId,1473 account_address: T::AccountId1474 ) -> DispatchResult {1475 let sender = ensure_signed(origin)?;14761477 #[cfg(feature = "runtime-benchmarks")]1478 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1479 1480 Self::ensure_contract_owned(sender, &contract_address)?; 1481 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1482 Ok(())1483 }14841485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 #[weight = T::WeightInfo::remove_from_contract_white_list()]1497 pub fn remove_from_contract_white_list(1498 origin,1499 contract_address: T::AccountId,1500 account_address: T::AccountId1501 ) -> DispatchResult {1502 let sender = ensure_signed(origin)?;15031504 #[cfg(feature = "runtime-benchmarks")]1505 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15061507 Self::ensure_contract_owned(sender, &contract_address)?;1508 <ContractWhiteList<T>>::remove(contract_address, account_address);1509 Ok(())1510 }15111512 #[weight = T::WeightInfo::set_collection_limits()]1513 pub fn set_collection_limits(1514 origin,1515 collection_id: u32,1516 limits: CollectionLimits,1517 ) -> DispatchResult {1518 let sender = ensure_signed(origin)?;1519 Self::check_owner_permissions(collection_id, sender.clone())?;1520 let mut target_collection = <Collection<T>>::get(collection_id);1521 let chain_limits = ChainLimit::get();1522 let climits = target_collection.limits;15231524 1525 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1526 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1527 Error::<T>::CollectionLimitBoundsExceeded);15281529 1530 ensure!(climits.token_limit > limits.token_limit && 1531 limits.token_limit <= chain_limits.account_token_ownership_limit, 1532 Error::<T>::AccountTokenLimitExceeded);15331534 target_collection.limits = limits;1535 <Collection<T>>::insert(collection_id, target_collection);15361537 Ok(())1538 } 1539 }1540}15411542impl<T: Trait> Module<T> {15431544 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15451546 1547 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1548 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1549 1550 Ok(())1551 }15521553 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15541555 1556 let total_items: u32 = ItemListIndex::get(collection_id);1557 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1558 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1559 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15601561 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1562 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1563 Self::check_white_list(collection_id, owner)?;1564 Self::check_white_list(collection_id, sender)?;1565 }15661567 Ok(())1568 }15691570 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1571 match target_collection.mode1572 {1573 CollectionMode::NFT => {1574 if let CreateItemData::NFT(data) = data {1575 1576 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1577 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1578 } else {1579 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1580 }1581 },1582 CollectionMode::Fungible(_) => {1583 if let CreateItemData::Fungible(_) = data {1584 } else {1585 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1586 }1587 },1588 CollectionMode::ReFungible(_) => {1589 if let CreateItemData::ReFungible(data) = data {15901591 1592 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1593 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1594 } else {1595 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1596 }1597 },1598 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1599 };16001601 Ok(())1602 }16031604 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1605 match data1606 {1607 CreateItemData::NFT(data) => {1608 let item = NftItemType {1609 owner,1610 const_data: data.const_data,1611 variable_data: data.variable_data1612 };16131614 Self::add_nft_item(collection_id, item)?;1615 },1616 CreateItemData::Fungible(data) => {1617 Self::add_fungible_item(collection_id, &owner, data.value)?;1618 },1619 CreateItemData::ReFungible(data) => {1620 let mut owner_list = Vec::new();1621 let value = (10 as u128).pow(collection.decimal_points as u32);1622 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16231624 let item = ReFungibleItemType {1625 owner: owner_list,1626 const_data: data.const_data,1627 variable_data: data.variable_data1628 };16291630 Self::add_refungible_item(collection_id, item)?;1631 }1632 };16331634 1635 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16361637 Ok(())1638 }16391640 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16411642 1643 let mut balance: u128 = 0;1644 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1645 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1646 } 16471648 1649 let item = FungibleItemType {1650 value: balance + value1651 };1652 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16531654 1655 let new_balance = <Balance<T>>::get(collection_id, owner)1656 .checked_add(value)1657 .ok_or(Error::<T>::NumOverflow)?;1658 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16591660 Ok(())1661 }16621663 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1664 let current_index = <ItemListIndex>::get(collection_id)1665 .checked_add(1)1666 .ok_or(Error::<T>::NumOverflow)?;1667 let itemcopy = item.clone();16681669 let value = item.owner.first().unwrap().fraction;1670 let owner = item.owner.first().unwrap().owner.clone();16711672 Self::add_token_index(collection_id, current_index, owner.clone())?;16731674 <ItemListIndex>::insert(collection_id, current_index);1675 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16761677 1678 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1679 .checked_add(value)1680 .ok_or(Error::<T>::NumOverflow)?;1681 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16821683 Ok(())1684 }16851686 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1687 let current_index = <ItemListIndex>::get(collection_id)1688 .checked_add(1)1689 .ok_or(Error::<T>::NumOverflow)?;16901691 let item_owner = item.owner.clone();1692 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16931694 <ItemListIndex>::insert(collection_id, current_index);1695 <NftItemList<T>>::insert(collection_id, current_index, item);16961697 1698 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1699 .checked_add(1)1700 .ok_or(Error::<T>::NumOverflow)?;1701 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17021703 Ok(())1704 }17051706 fn burn_refungible_item(1707 collection_id: CollectionId,1708 item_id: TokenId,1709 owner: T::AccountId,1710 ) -> DispatchResult {1711 ensure!(1712 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1713 Error::<T>::TokenNotFound1714 );1715 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1716 let item = collection1717 .owner1718 .iter()1719 .filter(|&i| i.owner == owner)1720 .next()1721 .unwrap();1722 Self::remove_token_index(collection_id, item_id, owner.clone())?;17231724 1725 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1726 .checked_sub(item.fraction)1727 .ok_or(Error::<T>::NumOverflow)?;1728 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17291730 <ReFungibleItemList<T>>::remove(collection_id, item_id);17311732 Ok(())1733 }17341735 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1736 ensure!(1737 <NftItemList<T>>::contains_key(collection_id, item_id),1738 Error::<T>::TokenNotFound1739 );1740 let item = <NftItemList<T>>::get(collection_id, item_id);1741 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17421743 1744 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1745 .checked_sub(1)1746 .ok_or(Error::<T>::NumOverflow)?;1747 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1748 <NftItemList<T>>::remove(collection_id, item_id);17491750 Ok(())1751 }17521753 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1754 ensure!(1755 <FungibleItemList<T>>::contains_key(collection_id, owner),1756 Error::<T>::TokenNotFound1757 );1758 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1759 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17601761 1762 let new_balance = <Balance<T>>::get(collection_id, owner)1763 .checked_sub(value)1764 .ok_or(Error::<T>::NumOverflow)?;1765 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17661767 if balance.value - value > 0 {1768 balance.value -= value;1769 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1770 }1771 else {1772 <FungibleItemList<T>>::remove(collection_id, owner);1773 }17741775 Ok(())1776 }17771778 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1779 ensure!(1780 <Collection<T>>::contains_key(collection_id),1781 Error::<T>::CollectionNotFound1782 );1783 Ok(())1784 }17851786 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1787 Self::collection_exists(collection_id)?;17881789 let target_collection = <Collection<T>>::get(collection_id);1790 ensure!(1791 subject == target_collection.owner,1792 Error::<T>::NoPermission1793 );17941795 Ok(())1796 }17971798 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1799 let target_collection = <Collection<T>>::get(collection_id);1800 let mut result: bool = subject == target_collection.owner;1801 let exists = <AdminList<T>>::contains_key(collection_id);18021803 if !result & exists {1804 if <AdminList<T>>::get(collection_id).contains(&subject) {1805 result = true1806 }1807 }18081809 result1810 }18111812 fn check_owner_or_admin_permissions(1813 collection_id: CollectionId,1814 subject: T::AccountId,1815 ) -> DispatchResult {1816 Self::collection_exists(collection_id)?;1817 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18181819 ensure!(1820 result,1821 Error::<T>::NoPermission1822 );1823 Ok(())1824 }18251826 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1827 let target_collection = <Collection<T>>::get(collection_id);18281829 match target_collection.mode {1830 CollectionMode::NFT => {1831 <NftItemList<T>>::get(collection_id, item_id).owner == subject1832 }1833 CollectionMode::Fungible(_) => {1834 <FungibleItemList<T>>::contains_key(collection_id, &subject)1835 }1836 CollectionMode::ReFungible(_) => {1837 <ReFungibleItemList<T>>::get(collection_id, item_id)1838 .owner1839 .iter()1840 .any(|i| i.owner == subject)1841 }1842 CollectionMode::Invalid => false,1843 }1844 }18451846 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1847 let mes = Error::<T>::AddresNotInWhiteList;1848 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18491850 Ok(())1851 }18521853 fn transfer_fungible(1854 collection_id: CollectionId,1855 value: u128,1856 owner: &T::AccountId,1857 recipient: &T::AccountId,1858 ) -> DispatchResult {1859 ensure!(1860 <FungibleItemList<T>>::contains_key(collection_id, owner),1861 Error::<T>::TokenNotFound1862 );18631864 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1865 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18661867 1868 Self::add_fungible_item(collection_id, recipient, value)?;18691870 1871 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18721873 1874 if balance.value == value {1875 <FungibleItemList<T>>::remove(collection_id, owner);1876 }1877 else {1878 balance.value -= value;1879 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1880 }18811882 Ok(())1883 }18841885 fn transfer_refungible(1886 collection_id: CollectionId,1887 item_id: TokenId,1888 value: u128,1889 owner: T::AccountId,1890 new_owner: T::AccountId,1891 ) -> DispatchResult {1892 ensure!(1893 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1894 Error::<T>::TokenNotFound1895 );18961897 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1898 let item = full_item1899 .owner1900 .iter()1901 .filter(|i| i.owner == owner)1902 .next()1903 .ok_or(Error::<T>::NumOverflow)?;1904 let amount = item.fraction;19051906 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19071908 1909 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1910 .checked_sub(value)1911 .ok_or(Error::<T>::NumOverflow)?;1912 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19131914 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1915 .checked_add(value)1916 .ok_or(Error::<T>::NumOverflow)?;1917 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19181919 let old_owner = item.owner.clone();1920 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19211922 1923 if amount == value && !new_owner_has_account {1924 1925 1926 let mut new_full_item = full_item.clone();1927 new_full_item1928 .owner1929 .iter_mut()1930 .find(|i| i.owner == owner)1931 .unwrap()1932 .owner = new_owner.clone();1933 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19341935 1936 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1937 } else {1938 let mut new_full_item = full_item.clone();1939 new_full_item1940 .owner1941 .iter_mut()1942 .find(|i| i.owner == owner)1943 .unwrap()1944 .fraction -= value;19451946 1947 if new_owner_has_account {1948 1949 new_full_item1950 .owner1951 .iter_mut()1952 .find(|i| i.owner == new_owner)1953 .unwrap()1954 .fraction += value;1955 } else {1956 1957 new_full_item.owner.push(Ownership {1958 owner: new_owner.clone(),1959 fraction: value,1960 });1961 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1962 }19631964 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1965 }19661967 Ok(())1968 }19691970 fn transfer_nft(1971 collection_id: CollectionId,1972 item_id: TokenId,1973 sender: T::AccountId,1974 new_owner: T::AccountId,1975 ) -> DispatchResult {1976 ensure!(1977 <NftItemList<T>>::contains_key(collection_id, item_id),1978 Error::<T>::TokenNotFound1979 );19801981 let mut item = <NftItemList<T>>::get(collection_id, item_id);19821983 ensure!(1984 sender == item.owner,1985 Error::<T>::MustBeTokenOwner1986 );19871988 1989 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1990 .checked_sub(1)1991 .ok_or(Error::<T>::NumOverflow)?;1992 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19931994 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1995 .checked_add(1)1996 .ok_or(Error::<T>::NumOverflow)?;1997 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19981999 2000 let old_owner = item.owner.clone();2001 item.owner = new_owner.clone();2002 <NftItemList<T>>::insert(collection_id, item_id, item);20032004 2005 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20062007 Ok(())2008 }2009 2010 fn item_exists(2011 collection_id: CollectionId,2012 item_id: TokenId,2013 mode: &CollectionMode2014 ) -> DispatchResult {2015 match mode {2016 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2017 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2018 _ => ()2019 };2020 2021 Ok(())2022 }20232024 fn set_re_fungible_variable_data(2025 collection_id: CollectionId,2026 item_id: TokenId,2027 data: Vec<u8>2028 ) -> DispatchResult {2029 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20302031 item.variable_data = data;20322033 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20342035 Ok(())2036 }20372038 fn set_nft_variable_data(2039 collection_id: CollectionId,2040 item_id: TokenId,2041 data: Vec<u8>2042 ) -> DispatchResult {2043 let mut item = <NftItemList<T>>::get(collection_id, item_id);2044 2045 item.variable_data = data;20462047 <NftItemList<T>>::insert(collection_id, item_id, item);2048 2049 Ok(())2050 }20512052 fn init_collection(item: &CollectionType<T::AccountId>) {2053 2054 assert!(2055 item.decimal_points <= MAX_DECIMAL_POINTS,2056 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2057 );2058 assert!(2059 item.name.len() <= 64,2060 "Collection name can not be longer than 63 char"2061 );2062 assert!(2063 item.name.len() <= 256,2064 "Collection description can not be longer than 255 char"2065 );2066 assert!(2067 item.token_prefix.len() <= 16,2068 "Token prefix can not be longer than 15 char"2069 );20702071 2072 let next_id = CreatedCollectionCount::get()2073 .checked_add(1)2074 .unwrap();20752076 CreatedCollectionCount::put(next_id);2077 }20782079 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2080 let current_index = <ItemListIndex>::get(collection_id)2081 .checked_add(1)2082 .unwrap();20832084 let item_owner = item.owner.clone();2085 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20862087 <ItemListIndex>::insert(collection_id, current_index);20882089 2090 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2091 .checked_add(1)2092 .unwrap();2093 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2094 }20952096 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2097 let current_index = <ItemListIndex>::get(collection_id)2098 .checked_add(1)2099 .unwrap();21002101 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();21022103 <ItemListIndex>::insert(collection_id, current_index);21042105 2106 let new_balance = <Balance<T>>::get(collection_id, owner)2107 .checked_add(item.value)2108 .unwrap();2109 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2110 }21112112 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2113 let current_index = <ItemListIndex>::get(collection_id)2114 .checked_add(1)2115 .unwrap();21162117 let value = item.owner.first().unwrap().fraction;2118 let owner = item.owner.first().unwrap().owner.clone();21192120 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();21212122 <ItemListIndex>::insert(collection_id, current_index);21232124 2125 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2126 .checked_add(value)2127 .unwrap();2128 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2129 }21302131 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21322133 2134 if <AccountItemCount<T>>::contains_key(owner.clone()) {21352136 2137 let count = <AccountItemCount<T>>::get(owner.clone());2138 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21392140 <AccountItemCount<T>>::insert(owner.clone(), count2141 .checked_add(1)2142 .ok_or(Error::<T>::NumOverflow)?);2143 }2144 else {2145 <AccountItemCount<T>>::insert(owner.clone(), 1);2146 }21472148 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2149 if list_exists {2150 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2151 let item_contains = list.contains(&item_index.clone());21522153 if !item_contains {2154 list.push(item_index.clone());2155 }21562157 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2158 } else {2159 let mut itm = Vec::new();2160 itm.push(item_index.clone());2161 <AddressTokens<T>>::insert(collection_id, owner, itm);2162 2163 }21642165 Ok(())2166 }21672168 fn remove_token_index(2169 collection_id: CollectionId,2170 item_index: TokenId,2171 owner: T::AccountId,2172 ) -> DispatchResult {21732174 2175 <AccountItemCount<T>>::insert(owner.clone(), 2176 <AccountItemCount<T>>::get(owner.clone())2177 .checked_sub(1)2178 .ok_or(Error::<T>::NumOverflow)?);217921802181 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2182 if list_exists {2183 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2184 let item_contains = list.contains(&item_index.clone());21852186 if item_contains {2187 list.retain(|&item| item != item_index);2188 <AddressTokens<T>>::insert(collection_id, owner, list);2189 }2190 }21912192 Ok(())2193 }21942195 fn move_token_index(2196 collection_id: CollectionId,2197 item_index: TokenId,2198 old_owner: T::AccountId,2199 new_owner: T::AccountId,2200 ) -> DispatchResult {2201 Self::remove_token_index(collection_id, item_index, old_owner)?;2202 Self::add_token_index(collection_id, item_index, new_owner)?;22032204 Ok(())2205 }2206 2207 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2208 if <ContractOwner<T>>::contains_key(contract.clone()) {2209 let owner = <ContractOwner<T>>::get(contract);2210 ensure!(account == owner, Error::<T>::NoPermission);2211 } else {2212 fail!(Error::<T>::NoPermission);2213 }22142215 Ok(())2216 }2217}2218221922202221222222232224pub type Multiplier = FixedU128;22252226type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2227 <T as system::Trait>::AccountId,2228>>::Balance;2229type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2230 <T as system::Trait>::AccountId,2231>>::NegativeImbalance;2232223322342235#[derive(Encode, Decode, Clone, Eq, PartialEq)]2236pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2237 #[codec(compact)] BalanceOf<T>2238);22392240impl<T: Trait + Send + Sync> sp_std::fmt::Debug2241 for ChargeTransactionPayment<T>2242{2243 #[cfg(feature = "std")]2244 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2245 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2246 }2247 #[cfg(not(feature = "std"))]2248 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2249 Ok(())2250 }2251}22522253impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2254where2255 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2256 BalanceOf<T>: Send + Sync + FixedPointOperand,2257{2258 2259 pub fn from(fee: BalanceOf<T>) -> Self {2260 Self(fee)2261 }22622263 pub fn traditional_fee(2264 len: usize,2265 info: &DispatchInfoOf<T::Call>,2266 tip: BalanceOf<T>,2267 ) -> BalanceOf<T>2268 where2269 T::Call: Dispatchable<Info = DispatchInfo>,2270 {2271 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2272 }22732274 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2275 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2276 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2277 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2278 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2279 }22802281 fn withdraw_fee(2282 &self,2283 who: &T::AccountId,2284 call: &T::Call,2285 info: &DispatchInfoOf<T::Call>,2286 len: usize,2287 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2288 let tip = self.0;22892290 2291 2292 2293 2294 2295 2296 2297 let fee = Self::traditional_fee(len, info, tip);22982299 2300 if fee.is_zero() {2301 return Ok((fee, None));2302 }23032304 2305 2306 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2307 Some(Call::create_item(collection_id, _owner, _properties)) => {23082309 2310 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2311 (<Collection<T>>::get(collection_id).sponsor_confirmed)2312 {2313 <Collection<T>>::get(collection_id).sponsor2314 } else {2315 T::AccountId::default()2316 }2317 }2318 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2319 2320 let mut sponsor_transfer = false;2321 if <Collection<T>>::get(collection_id).sponsor_confirmed {23222323 let collection_limits = <Collection<T>>::get(collection_id).limits;2324 let collection_mode = <Collection<T>>::get(collection_id).mode;2325 2326 2327 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2328 sponsor_transfer = match collection_mode {2329 CollectionMode::NFT => {2330 2331 2332 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2333 collection_limits.sponsor_transfer_timeout2334 } else {2335 ChainLimit::get().nft_sponsor_transfer_timeout2336 };2337 2338 let mut sponsored = true;2339 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2340 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2341 let limit_time = last_tx_block + limit.into();2342 if block_number <= limit_time {2343 sponsored = false;2344 }2345 }2346 if sponsored {2347 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2348 }23492350 sponsored2351 }2352 CollectionMode::Fungible(_) => {2353 2354 2355 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2356 collection_limits.sponsor_transfer_timeout2357 } else {2358 ChainLimit::get().fungible_sponsor_transfer_timeout2359 };2360 2361 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2362 let mut sponsored = true;2363 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2364 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2365 let limit_time = last_tx_block + limit.into();2366 if block_number <= limit_time {2367 sponsored = false;2368 }2369 }2370 if sponsored {2371 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2372 }23732374 sponsored2375 }2376 CollectionMode::ReFungible(_) => {2377 2378 2379 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2380 collection_limits.sponsor_transfer_timeout2381 } else {2382 ChainLimit::get().refungible_sponsor_transfer_timeout2383 };2384 2385 let mut sponsored = true;2386 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2387 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2388 let limit_time = last_tx_block + limit.into();2389 if block_number <= limit_time {2390 sponsored = false;2391 }2392 }2393 if sponsored {2394 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2395 }23962397 sponsored2398 }2399 _ => {2400 false2401 },2402 };2403 }24042405 if !sponsor_transfer {2406 T::AccountId::default()2407 } else {2408 <Collection<T>>::get(collection_id).sponsor2409 }2410 }24112412 _ => T::AccountId::default(),2413 };24142415 2416 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24172418 2419 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24202421 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2422 code_hash,2423 &data,2424 &who,2425 );2426 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24272428 T::AccountId::default()2429 },24302431 2432 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24332434 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24352436 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2437 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2438 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2439 2440 if !owned_contract && white_list_enabled {2441 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2442 return Err(InvalidTransaction::Call.into());2443 }2444 }24452446 let mut sponsor_transfer = false;2447 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2448 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2449 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2450 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2451 let limit_time = last_tx_block + rate_limit;24522453 if block_number >= limit_time {2454 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2455 sponsor_transfer = true;2456 }2457 } else {2458 sponsor_transfer = false;2459 }2460 2461 2462 let mut sp = T::AccountId::default();2463 if sponsor_transfer {2464 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2465 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2466 sp = called_contract;2467 }2468 }2469 }24702471 sp2472 },24732474 _ => sponsor,2475 };24762477 let mut who_pays_fee: T::AccountId = sponsor.clone();2478 if sponsor == T::AccountId::default() {2479 who_pays_fee = who.clone();2480 }24812482 match <T as transaction_payment::Trait>::Currency::withdraw(2483 &who_pays_fee,2484 fee,2485 if tip.is_zero() {2486 WithdrawReason::TransactionPayment.into()2487 } else {2488 WithdrawReason::TransactionPayment | WithdrawReason::Tip2489 },2490 ExistenceRequirement::KeepAlive,2491 ) {2492 Ok(imbalance) => Ok((fee, Some(imbalance))),2493 Err(_) => Err(InvalidTransaction::Payment.into()),2494 }2495 }2496}249724982499impl<T: Trait + Send + Sync> SignedExtension2500 for ChargeTransactionPayment<T>2501where2502 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2503 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2504{2505 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2506 type AccountId = T::AccountId;2507 type Call = T::Call;2508 type AdditionalSigned = ();2509 type Pre = (2510 BalanceOf<T>,2511 Self::AccountId,2512 Option<NegativeImbalanceOf<T>>,2513 BalanceOf<T>,2514 );2515 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2516 Ok(())2517 }25182519 fn validate(2520 &self,2521 who: &Self::AccountId,2522 call: &Self::Call,2523 info: &DispatchInfoOf<Self::Call>,2524 len: usize,2525 ) -> TransactionValidity {2526 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2527 Ok(ValidTransaction {2528 priority: Self::get_priority(len, info, fee),2529 ..Default::default()2530 })2531 }25322533 fn pre_dispatch(2534 self,2535 who: &Self::AccountId,2536 call: &Self::Call,2537 info: &DispatchInfoOf<Self::Call>,2538 len: usize,2539 ) -> Result<Self::Pre, TransactionValidityError> {2540 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2541 Ok((self.0, who.clone(), imbalance, fee))2542 }25432544 fn post_dispatch(2545 pre: Self::Pre,2546 info: &DispatchInfoOf<Self::Call>,2547 post_info: &PostDispatchInfoOf<Self::Call>,2548 len: usize,2549 _result: &DispatchResult,2550 ) -> Result<(), TransactionValidityError> {2551 let (tip, who, imbalance, fee) = pre;2552 if let Some(payed) = imbalance {2553 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2554 len as u32, info, post_info, tip,2555 );2556 let refund = fee.saturating_sub(actual_fee);2557 let actual_payment =2558 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2559 &who, refund,2560 ) {2561 Ok(refund_imbalance) => {2562 2563 2564 match payed.offset(refund_imbalance) {2565 Ok(actual_payment) => actual_payment,2566 Err(_) => return Err(InvalidTransaction::Payment.into()),2567 }2568 }2569 2570 2571 Err(_) => payed,2572 };2573 let imbalances = actual_payment.split(tip);2574 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2575 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2576 );2577 }2578 Ok(())2579 }2580}25812582