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);547 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);548 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);549 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);550551 552 let next_id = CreatedCollectionCount::get()553 .checked_add(1)554 .ok_or(Error::<T>::NumOverflow)?;555556 557 let total = CollectionCount::get()558 .checked_add(1)559 .ok_or(Error::<T>::NumOverflow)?;560561 CreatedCollectionCount::put(next_id);562 CollectionCount::put(total);563564 565 let new_collection = CollectionType {566 owner: who.clone(),567 name: collection_name,568 mode: mode.clone(),569 mint_mode: false,570 access: AccessMode::Normal,571 description: collection_description,572 decimal_points: decimal_points,573 token_prefix: token_prefix,574 offchain_schema: Vec::new(),575 schema_version: SchemaVersion::ImageURL,576 sponsor: T::AccountId::default(),577 sponsor_confirmed: false,578 variable_on_chain_schema: Vec::new(),579 const_on_chain_schema: Vec::new(),580 limits: CollectionLimits::default(),581 };582583 584 <Collection<T>>::insert(next_id, new_collection);585586 587 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));588589 Ok(())590 }591592 593 594 595 596 597 598 599 600 601 #[weight = T::WeightInfo::destroy_collection()]602 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {603604 let sender = ensure_signed(origin)?;605 Self::check_owner_permissions(collection_id, sender)?;606607 <AddressTokens<T>>::remove_prefix(collection_id);608 <Allowances<T>>::remove_prefix(collection_id);609 <Balance<T>>::remove_prefix(collection_id);610 <ItemListIndex>::remove(collection_id);611 <AdminList<T>>::remove(collection_id);612 <Collection<T>>::remove(collection_id);613 <WhiteList<T>>::remove_prefix(collection_id);614615 <NftItemList<T>>::remove_prefix(collection_id);616 <FungibleItemList<T>>::remove_prefix(collection_id);617 <ReFungibleItemList<T>>::remove_prefix(collection_id);618619 <NftTransferBasket<T>>::remove_prefix(collection_id);620 <FungibleTransferBasket<T>>::remove_prefix(collection_id);621 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);622623 if CollectionCount::get() > 0624 {625 626 let total = CollectionCount::get()627 .checked_sub(1)628 .ok_or(Error::<T>::NumOverflow)?;629630 CollectionCount::put(total);631 }632633 Ok(())634 }635636 637 638 639 640 641 642 643 644 645 646 647 648 #[weight = T::WeightInfo::add_to_white_list()]649 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{650651 let sender = ensure_signed(origin)?;652 Self::check_owner_or_admin_permissions(collection_id, sender)?;653654 <WhiteList<T>>::insert(collection_id, address, true);655 656 Ok(())657 }658659 660 661 662 663 664 665 666 667 668 669 670 671 #[weight = T::WeightInfo::remove_from_white_list()]672 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{673674 let sender = ensure_signed(origin)?;675 Self::check_owner_or_admin_permissions(collection_id, sender)?;676677 <WhiteList<T>>::remove(collection_id, address);678679 Ok(())680 }681682 683 684 685 686 687 688 689 690 691 692 693 #[weight = T::WeightInfo::set_public_access_mode()]694 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult695 {696 let sender = ensure_signed(origin)?;697698 Self::check_owner_permissions(collection_id, sender)?;699 let mut target_collection = <Collection<T>>::get(collection_id);700 target_collection.access = mode;701 <Collection<T>>::insert(collection_id, target_collection);702703 Ok(())704 }705706 707 708 709 710 711 712 713 714 715 716 717 718 719 #[weight = T::WeightInfo::set_mint_permission()]720 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult721 {722 let sender = ensure_signed(origin)?;723724 Self::check_owner_permissions(collection_id, sender)?;725 let mut target_collection = <Collection<T>>::get(collection_id);726 target_collection.mint_mode = mint_permission;727 <Collection<T>>::insert(collection_id, target_collection);728729 Ok(())730 }731732 733 734 735 736 737 738 739 740 741 742 743 #[weight = T::WeightInfo::change_collection_owner()]744 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {745746 let sender = ensure_signed(origin)?;747 Self::check_owner_permissions(collection_id, sender)?;748 let mut target_collection = <Collection<T>>::get(collection_id);749 target_collection.owner = new_owner;750 <Collection<T>>::insert(collection_id, target_collection);751752 Ok(())753 }754755 756 757 758 759 760 761 762 763 764 765 766 767 768 #[weight = T::WeightInfo::add_collection_admin()]769 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {770771 let sender = ensure_signed(origin)?;772 Self::check_owner_or_admin_permissions(collection_id, sender)?;773 let mut admin_arr: Vec<T::AccountId> = Vec::new();774775 if <AdminList<T>>::contains_key(collection_id)776 {777 admin_arr = <AdminList<T>>::get(collection_id);778 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);779 }780781 782 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);783784 admin_arr.push(new_admin_id);785 <AdminList<T>>::insert(collection_id, admin_arr);786787 Ok(())788 }789790 791 792 793 794 795 796 797 798 799 800 801 802 #[weight = T::WeightInfo::remove_collection_admin()]803 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {804805 let sender = ensure_signed(origin)?;806 Self::check_owner_or_admin_permissions(collection_id, sender)?;807808 if <AdminList<T>>::contains_key(collection_id)809 {810 let mut admin_arr = <AdminList<T>>::get(collection_id);811 admin_arr.retain(|i| *i != account_id);812 <AdminList<T>>::insert(collection_id, admin_arr);813 }814815 Ok(())816 }817818 819 820 821 822 823 824 825 826 827 #[weight = T::WeightInfo::set_collection_sponsor()]828 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {829830 let sender = ensure_signed(origin)?;831 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);832833 let mut target_collection = <Collection<T>>::get(collection_id);834 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);835836 target_collection.sponsor = new_sponsor;837 target_collection.sponsor_confirmed = false;838 <Collection<T>>::insert(collection_id, target_collection);839840 Ok(())841 }842843 844 845 846 847 848 849 850 #[weight = T::WeightInfo::confirm_sponsorship()]851 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {852853 let sender = ensure_signed(origin)?;854 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);855856 let mut target_collection = <Collection<T>>::get(collection_id);857 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);858859 target_collection.sponsor_confirmed = true;860 <Collection<T>>::insert(collection_id, target_collection);861862 Ok(())863 }864865 866 867 868 869 870 871 872 873 874 #[weight = T::WeightInfo::remove_collection_sponsor()]875 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {876877 let sender = ensure_signed(origin)?;878 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);879880 let mut target_collection = <Collection<T>>::get(collection_id);881 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);882883 target_collection.sponsor = T::AccountId::default();884 target_collection.sponsor_confirmed = false;885 <Collection<T>>::insert(collection_id, target_collection);886887 Ok(())888 }889890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913914 #[weight = T::WeightInfo::create_item(data.len())]915 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {916917 let sender = ensure_signed(origin)?;918919 Self::collection_exists(collection_id)?;920921 let target_collection = <Collection<T>>::get(collection_id);922923 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;924 Self::validate_create_item_args(&target_collection, &data)?;925 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;926927 Ok(())928 }929930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 #[weight = T::WeightInfo::create_item(items_data.into_iter()949 .map(|data| { data.len() })950 .sum())]951 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {952953 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);954 let sender = ensure_signed(origin)?;955956 Self::collection_exists(collection_id)?;957 let target_collection = <Collection<T>>::get(collection_id);958959 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;960961 for data in &items_data {962 Self::validate_create_item_args(&target_collection, data)?;963 }964 for data in &items_data {965 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;966 }967968 Ok(())969 }970971 972 973 974 975 976 977 978 979 980 981 982 983 984 #[weight = T::WeightInfo::burn_item()]985 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {986987 let sender = ensure_signed(origin)?;988 Self::collection_exists(collection_id)?;989990 991 let target_collection = <Collection<T>>::get(collection_id);992 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||993 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),994 Error::<T>::NoPermission);995996 if target_collection.access == AccessMode::WhiteList {997 Self::check_white_list(collection_id, &sender)?;998 }9991000 match target_collection.mode1001 {1002 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1003 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1004 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1005 _ => ()1006 };10071008 1009 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10101011 Ok(())1012 }10131014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 #[weight = T::WeightInfo::transfer()]1038 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10391040 let sender = ensure_signed(origin)?;1041 let target_collection = <Collection<T>>::get(collection_id);10421043 1044 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10451046 1047 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1048 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1049 Error::<T>::NoPermission);10501051 if target_collection.access == AccessMode::WhiteList {1052 Self::check_white_list(collection_id, &sender)?;1053 Self::check_white_list(collection_id, &recipient)?;1054 }10551056 match target_collection.mode1057 {1058 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1059 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1060 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1061 _ => ()1062 };10631064 Ok(())1065 }10661067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 #[weight = T::WeightInfo::approve()]1083 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10841085 let sender = ensure_signed(origin)?;10861087 1088 let target_collection = <Collection<T>>::get(collection_id);1089 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1090 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1091 Error::<T>::NoPermission);10921093 if target_collection.access == AccessMode::WhiteList {1094 Self::check_white_list(collection_id, &sender)?;1095 Self::check_white_list(collection_id, &spender)?;1096 }10971098 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1099 let mut allowance: u128 = amount;1100 if allowance_exists {1101 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1102 }1103 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11041105 Ok(())1106 }1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 #[weight = T::WeightInfo::transfer_from()]1128 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11291130 let sender = ensure_signed(origin)?;1131 let mut appoved_transfer = false;11321133 1134 let mut approval: u128 = 0;1135 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1136 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1137 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1138 appoved_transfer = true;1139 }11401141 let target_collection = <Collection<T>>::get(collection_id);11421143 1144 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11451146 1147 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1148 Error::<T>::NoPermission);11491150 if target_collection.access == AccessMode::WhiteList {1151 Self::check_white_list(collection_id, &sender)?;1152 Self::check_white_list(collection_id, &recipient)?;1153 }11541155 1156 if approval - value > 0 {1157 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1158 }1159 else {1160 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1161 }11621163 match target_collection.mode1164 {1165 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1166 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1167 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1168 _ => ()1169 };11701171 Ok(())1172 }11731174 #[weight = 0]1175 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11761177 1178 1179 1180 11811182 11831184 11851186 Ok(())1187 }11881189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 #[weight = T::WeightInfo::set_variable_meta_data()]1202 pub fn set_variable_meta_data (1203 origin,1204 collection_id: CollectionId,1205 item_id: TokenId,1206 data: Vec<u8>1207 ) -> DispatchResult {1208 let sender = ensure_signed(origin)?;1209 1210 Self::collection_exists(collection_id)?;1211 1212 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12131214 1215 let target_collection = <Collection<T>>::get(collection_id);1216 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1217 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1218 Error::<T>::NoPermission);12191220 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12211222 match target_collection.mode1223 {1224 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1225 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1226 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1227 _ => fail!(Error::<T>::UnexpectedCollectionType)1228 };12291230 Ok(())1231 }1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 #[weight = T::WeightInfo::set_schema_version()]1248 pub fn set_schema_version(1249 origin,1250 collection_id: CollectionId,1251 version: SchemaVersion1252 ) -> DispatchResult {1253 let sender = ensure_signed(origin)?;1254 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1255 let mut target_collection = <Collection<T>>::get(collection_id);1256 target_collection.schema_version = version;1257 <Collection<T>>::insert(collection_id, target_collection);12581259 Ok(())1260 }12611262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 #[weight = T::WeightInfo::set_offchain_schema()]1275 pub fn set_offchain_schema(1276 origin,1277 collection_id: CollectionId,1278 schema: Vec<u8>1279 ) -> DispatchResult {1280 let sender = ensure_signed(origin)?;1281 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12821283 let mut target_collection = <Collection<T>>::get(collection_id);1284 target_collection.offchain_schema = schema;1285 <Collection<T>>::insert(collection_id, target_collection);12861287 Ok(())1288 }12891290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 #[weight = T::WeightInfo::set_const_on_chain_schema()]1303 pub fn set_const_on_chain_schema (1304 origin,1305 collection_id: CollectionId,1306 schema: Vec<u8>1307 ) -> DispatchResult {1308 let sender = ensure_signed(origin)?;1309 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13101311 let mut target_collection = <Collection<T>>::get(collection_id);1312 target_collection.const_on_chain_schema = schema;1313 <Collection<T>>::insert(collection_id, target_collection);13141315 Ok(())1316 }13171318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 #[weight = T::WeightInfo::set_const_on_chain_schema()]1331 pub fn set_variable_on_chain_schema (1332 origin,1333 collection_id: CollectionId,1334 schema: Vec<u8>1335 ) -> DispatchResult {1336 let sender = ensure_signed(origin)?;1337 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13381339 let mut target_collection = <Collection<T>>::get(collection_id);1340 target_collection.variable_on_chain_schema = schema;1341 <Collection<T>>::insert(collection_id, target_collection);13421343 Ok(())1344 }13451346 1347 #[weight = T::WeightInfo::set_chain_limits()]1348 pub fn set_chain_limits(1349 origin,1350 limits: ChainLimits1351 ) -> DispatchResult {13521353 #[cfg(not(feature = "runtime-benchmarks"))]1354 ensure_root(origin)?;13551356 <ChainLimit>::put(limits);1357 Ok(())1358 }13591360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 #[weight = T::WeightInfo::enable_contract_sponsoring()]1372 pub fn enable_contract_sponsoring(1373 origin,1374 contract_address: T::AccountId,1375 enable: bool1376 ) -> DispatchResult {13771378 let sender = ensure_signed(origin)?;13791380 #[cfg(feature = "runtime-benchmarks")]1381 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13821383 Self::ensure_contract_owned(sender, &contract_address)?;13841385 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1386 Ok(())1387 }13881389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1407 pub fn set_contract_sponsoring_rate_limit(1408 origin,1409 contract_address: T::AccountId,1410 rate_limit: T::BlockNumber1411 ) -> DispatchResult {1412 let sender = ensure_signed(origin)?;14131414 #[cfg(feature = "runtime-benchmarks")]1415 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14161417 Self::ensure_contract_owned(sender, &contract_address)?;1418 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1419 Ok(())1420 }14211422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 #[weight = T::WeightInfo::toggle_contract_white_list()]1434 pub fn toggle_contract_white_list(1435 origin,1436 contract_address: T::AccountId,1437 enable: bool1438 ) -> DispatchResult {1439 let sender = ensure_signed(origin)?;14401441 #[cfg(feature = "runtime-benchmarks")]1442 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14431444 Self::ensure_contract_owned(sender, &contract_address)?;1445 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1446 Ok(())1447 }1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 #[weight = T::WeightInfo::add_to_contract_white_list()]1461 pub fn add_to_contract_white_list(1462 origin,1463 contract_address: T::AccountId,1464 account_address: T::AccountId1465 ) -> DispatchResult {1466 let sender = ensure_signed(origin)?;14671468 #[cfg(feature = "runtime-benchmarks")]1469 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1470 1471 Self::ensure_contract_owned(sender, &contract_address)?; 1472 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1473 Ok(())1474 }14751476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 #[weight = T::WeightInfo::remove_from_contract_white_list()]1488 pub fn remove_from_contract_white_list(1489 origin,1490 contract_address: T::AccountId,1491 account_address: T::AccountId1492 ) -> DispatchResult {1493 let sender = ensure_signed(origin)?;14941495 #[cfg(feature = "runtime-benchmarks")]1496 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14971498 Self::ensure_contract_owned(sender, &contract_address)?;1499 <ContractWhiteList<T>>::remove(contract_address, account_address);1500 Ok(())1501 }15021503 #[weight = T::WeightInfo::set_collection_limits()]1504 pub fn set_collection_limits(1505 origin,1506 collection_id: u32,1507 limits: CollectionLimits,1508 ) -> DispatchResult {1509 let sender = ensure_signed(origin)?;1510 Self::check_owner_permissions(collection_id, sender.clone())?;1511 let mut target_collection = <Collection<T>>::get(collection_id);1512 let chain_limits = ChainLimit::get();1513 let climits = target_collection.limits;15141515 1516 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1517 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1518 Error::<T>::CollectionLimitBoundsExceeded);15191520 1521 ensure!(climits.token_limit > limits.token_limit && 1522 limits.token_limit <= chain_limits.account_token_ownership_limit, 1523 Error::<T>::AccountTokenLimitExceeded);15241525 target_collection.limits = limits;1526 <Collection<T>>::insert(collection_id, target_collection);15271528 Ok(())1529 } 1530 }1531}15321533impl<T: Trait> Module<T> {15341535 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15361537 1538 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1539 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1540 1541 Ok(())1542 }15431544 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15451546 1547 let total_items: u32 = ItemListIndex::get(collection_id);1548 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1549 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1550 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15511552 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1553 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1554 Self::check_white_list(collection_id, owner)?;1555 Self::check_white_list(collection_id, sender)?;1556 }15571558 Ok(())1559 }15601561 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1562 match target_collection.mode1563 {1564 CollectionMode::NFT => {1565 if let CreateItemData::NFT(data) = data {1566 1567 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1568 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1569 } else {1570 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1571 }1572 },1573 CollectionMode::Fungible(_) => {1574 if let CreateItemData::Fungible(_) = data {1575 } else {1576 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1577 }1578 },1579 CollectionMode::ReFungible(_) => {1580 if let CreateItemData::ReFungible(data) = data {15811582 1583 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1584 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1585 } else {1586 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1587 }1588 },1589 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1590 };15911592 Ok(())1593 }15941595 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1596 match data1597 {1598 CreateItemData::NFT(data) => {1599 let item = NftItemType {1600 owner,1601 const_data: data.const_data,1602 variable_data: data.variable_data1603 };16041605 Self::add_nft_item(collection_id, item)?;1606 },1607 CreateItemData::Fungible(data) => {1608 Self::add_fungible_item(collection_id, &owner, data.value)?;1609 },1610 CreateItemData::ReFungible(data) => {1611 let mut owner_list = Vec::new();1612 let value = (10 as u128).pow(collection.decimal_points as u32);1613 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16141615 let item = ReFungibleItemType {1616 owner: owner_list,1617 const_data: data.const_data,1618 variable_data: data.variable_data1619 };16201621 Self::add_refungible_item(collection_id, item)?;1622 }1623 };16241625 1626 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16271628 Ok(())1629 }16301631 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16321633 1634 let mut balance: u128 = 0;1635 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1636 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1637 } 16381639 1640 let item = FungibleItemType {1641 value: balance + value1642 };1643 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16441645 1646 let new_balance = <Balance<T>>::get(collection_id, owner)1647 .checked_add(value)1648 .ok_or(Error::<T>::NumOverflow)?;1649 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16501651 Ok(())1652 }16531654 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1655 let current_index = <ItemListIndex>::get(collection_id)1656 .checked_add(1)1657 .ok_or(Error::<T>::NumOverflow)?;1658 let itemcopy = item.clone();16591660 let value = item.owner.first().unwrap().fraction;1661 let owner = item.owner.first().unwrap().owner.clone();16621663 Self::add_token_index(collection_id, current_index, owner.clone())?;16641665 <ItemListIndex>::insert(collection_id, current_index);1666 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16671668 1669 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1670 .checked_add(value)1671 .ok_or(Error::<T>::NumOverflow)?;1672 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16731674 Ok(())1675 }16761677 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1678 let current_index = <ItemListIndex>::get(collection_id)1679 .checked_add(1)1680 .ok_or(Error::<T>::NumOverflow)?;16811682 let item_owner = item.owner.clone();1683 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16841685 <ItemListIndex>::insert(collection_id, current_index);1686 <NftItemList<T>>::insert(collection_id, current_index, item);16871688 1689 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1690 .checked_add(1)1691 .ok_or(Error::<T>::NumOverflow)?;1692 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16931694 Ok(())1695 }16961697 fn burn_refungible_item(1698 collection_id: CollectionId,1699 item_id: TokenId,1700 owner: T::AccountId,1701 ) -> DispatchResult {1702 ensure!(1703 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1704 Error::<T>::TokenNotFound1705 );1706 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1707 let item = collection1708 .owner1709 .iter()1710 .filter(|&i| i.owner == owner)1711 .next()1712 .unwrap();1713 Self::remove_token_index(collection_id, item_id, owner.clone())?;17141715 1716 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1717 .checked_sub(item.fraction)1718 .ok_or(Error::<T>::NumOverflow)?;1719 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17201721 <ReFungibleItemList<T>>::remove(collection_id, item_id);17221723 Ok(())1724 }17251726 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1727 ensure!(1728 <NftItemList<T>>::contains_key(collection_id, item_id),1729 Error::<T>::TokenNotFound1730 );1731 let item = <NftItemList<T>>::get(collection_id, item_id);1732 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17331734 1735 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1736 .checked_sub(1)1737 .ok_or(Error::<T>::NumOverflow)?;1738 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1739 <NftItemList<T>>::remove(collection_id, item_id);17401741 Ok(())1742 }17431744 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1745 ensure!(1746 <FungibleItemList<T>>::contains_key(collection_id, owner),1747 Error::<T>::TokenNotFound1748 );1749 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1750 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17511752 1753 let new_balance = <Balance<T>>::get(collection_id, owner)1754 .checked_sub(value)1755 .ok_or(Error::<T>::NumOverflow)?;1756 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17571758 if balance.value - value > 0 {1759 balance.value -= value;1760 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1761 }1762 else {1763 <FungibleItemList<T>>::remove(collection_id, owner);1764 }17651766 Ok(())1767 }17681769 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1770 ensure!(1771 <Collection<T>>::contains_key(collection_id),1772 Error::<T>::CollectionNotFound1773 );1774 Ok(())1775 }17761777 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1778 Self::collection_exists(collection_id)?;17791780 let target_collection = <Collection<T>>::get(collection_id);1781 ensure!(1782 subject == target_collection.owner,1783 Error::<T>::NoPermission1784 );17851786 Ok(())1787 }17881789 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1790 let target_collection = <Collection<T>>::get(collection_id);1791 let mut result: bool = subject == target_collection.owner;1792 let exists = <AdminList<T>>::contains_key(collection_id);17931794 if !result & exists {1795 if <AdminList<T>>::get(collection_id).contains(&subject) {1796 result = true1797 }1798 }17991800 result1801 }18021803 fn check_owner_or_admin_permissions(1804 collection_id: CollectionId,1805 subject: T::AccountId,1806 ) -> DispatchResult {1807 Self::collection_exists(collection_id)?;1808 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18091810 ensure!(1811 result,1812 Error::<T>::NoPermission1813 );1814 Ok(())1815 }18161817 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1818 let target_collection = <Collection<T>>::get(collection_id);18191820 match target_collection.mode {1821 CollectionMode::NFT => {1822 <NftItemList<T>>::get(collection_id, item_id).owner == subject1823 }1824 CollectionMode::Fungible(_) => {1825 <FungibleItemList<T>>::contains_key(collection_id, &subject)1826 }1827 CollectionMode::ReFungible(_) => {1828 <ReFungibleItemList<T>>::get(collection_id, item_id)1829 .owner1830 .iter()1831 .any(|i| i.owner == subject)1832 }1833 CollectionMode::Invalid => false,1834 }1835 }18361837 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1838 let mes = Error::<T>::AddresNotInWhiteList;1839 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18401841 Ok(())1842 }18431844 fn transfer_fungible(1845 collection_id: CollectionId,1846 value: u128,1847 owner: &T::AccountId,1848 recipient: &T::AccountId,1849 ) -> DispatchResult {1850 ensure!(1851 <FungibleItemList<T>>::contains_key(collection_id, owner),1852 Error::<T>::TokenNotFound1853 );18541855 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1856 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18571858 1859 Self::add_fungible_item(collection_id, recipient, value)?;18601861 1862 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18631864 1865 if balance.value == value {1866 <FungibleItemList<T>>::remove(collection_id, owner);1867 }1868 else {1869 balance.value -= value;1870 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1871 }18721873 Ok(())1874 }18751876 fn transfer_refungible(1877 collection_id: CollectionId,1878 item_id: TokenId,1879 value: u128,1880 owner: T::AccountId,1881 new_owner: T::AccountId,1882 ) -> DispatchResult {1883 ensure!(1884 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1885 Error::<T>::TokenNotFound1886 );18871888 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1889 let item = full_item1890 .owner1891 .iter()1892 .filter(|i| i.owner == owner)1893 .next()1894 .ok_or(Error::<T>::NumOverflow)?;1895 let amount = item.fraction;18961897 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18981899 1900 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1901 .checked_sub(value)1902 .ok_or(Error::<T>::NumOverflow)?;1903 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19041905 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1906 .checked_add(value)1907 .ok_or(Error::<T>::NumOverflow)?;1908 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19091910 let old_owner = item.owner.clone();1911 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19121913 1914 if amount == value && !new_owner_has_account {1915 1916 1917 let mut new_full_item = full_item.clone();1918 new_full_item1919 .owner1920 .iter_mut()1921 .find(|i| i.owner == owner)1922 .unwrap()1923 .owner = new_owner.clone();1924 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19251926 1927 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1928 } else {1929 let mut new_full_item = full_item.clone();1930 new_full_item1931 .owner1932 .iter_mut()1933 .find(|i| i.owner == owner)1934 .unwrap()1935 .fraction -= value;19361937 1938 if new_owner_has_account {1939 1940 new_full_item1941 .owner1942 .iter_mut()1943 .find(|i| i.owner == new_owner)1944 .unwrap()1945 .fraction += value;1946 } else {1947 1948 new_full_item.owner.push(Ownership {1949 owner: new_owner.clone(),1950 fraction: value,1951 });1952 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1953 }19541955 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1956 }19571958 Ok(())1959 }19601961 fn transfer_nft(1962 collection_id: CollectionId,1963 item_id: TokenId,1964 sender: T::AccountId,1965 new_owner: T::AccountId,1966 ) -> DispatchResult {1967 ensure!(1968 <NftItemList<T>>::contains_key(collection_id, item_id),1969 Error::<T>::TokenNotFound1970 );19711972 let mut item = <NftItemList<T>>::get(collection_id, item_id);19731974 ensure!(1975 sender == item.owner,1976 Error::<T>::MustBeTokenOwner1977 );19781979 1980 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1981 .checked_sub(1)1982 .ok_or(Error::<T>::NumOverflow)?;1983 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19841985 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1986 .checked_add(1)1987 .ok_or(Error::<T>::NumOverflow)?;1988 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19891990 1991 let old_owner = item.owner.clone();1992 item.owner = new_owner.clone();1993 <NftItemList<T>>::insert(collection_id, item_id, item);19941995 1996 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19971998 Ok(())1999 }2000 2001 fn item_exists(2002 collection_id: CollectionId,2003 item_id: TokenId,2004 mode: &CollectionMode2005 ) -> DispatchResult {2006 match mode {2007 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2008 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2009 _ => ()2010 };2011 2012 Ok(())2013 }20142015 fn set_re_fungible_variable_data(2016 collection_id: CollectionId,2017 item_id: TokenId,2018 data: Vec<u8>2019 ) -> DispatchResult {2020 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20212022 item.variable_data = data;20232024 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20252026 Ok(())2027 }20282029 fn set_nft_variable_data(2030 collection_id: CollectionId,2031 item_id: TokenId,2032 data: Vec<u8>2033 ) -> DispatchResult {2034 let mut item = <NftItemList<T>>::get(collection_id, item_id);2035 2036 item.variable_data = data;20372038 <NftItemList<T>>::insert(collection_id, item_id, item);2039 2040 Ok(())2041 }20422043 fn init_collection(item: &CollectionType<T::AccountId>) {2044 2045 assert!(2046 item.decimal_points <= MAX_DECIMAL_POINTS,2047 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2048 );2049 assert!(2050 item.name.len() <= 64,2051 "Collection name can not be longer than 63 char"2052 );2053 assert!(2054 item.name.len() <= 256,2055 "Collection description can not be longer than 255 char"2056 );2057 assert!(2058 item.token_prefix.len() <= 16,2059 "Token prefix can not be longer than 15 char"2060 );20612062 2063 let next_id = CreatedCollectionCount::get()2064 .checked_add(1)2065 .unwrap();20662067 CreatedCollectionCount::put(next_id);2068 }20692070 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2071 let current_index = <ItemListIndex>::get(collection_id)2072 .checked_add(1)2073 .unwrap();20742075 let item_owner = item.owner.clone();2076 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20772078 <ItemListIndex>::insert(collection_id, current_index);20792080 2081 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2082 .checked_add(1)2083 .unwrap();2084 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2085 }20862087 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2088 let current_index = <ItemListIndex>::get(collection_id)2089 .checked_add(1)2090 .unwrap();20912092 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();20932094 <ItemListIndex>::insert(collection_id, current_index);20952096 2097 let new_balance = <Balance<T>>::get(collection_id, owner)2098 .checked_add(item.value)2099 .unwrap();2100 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2101 }21022103 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2104 let current_index = <ItemListIndex>::get(collection_id)2105 .checked_add(1)2106 .unwrap();21072108 let value = item.owner.first().unwrap().fraction;2109 let owner = item.owner.first().unwrap().owner.clone();21102111 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();21122113 <ItemListIndex>::insert(collection_id, current_index);21142115 2116 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2117 .checked_add(value)2118 .unwrap();2119 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2120 }21212122 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21232124 2125 if <AccountItemCount<T>>::contains_key(owner.clone()) {21262127 2128 let count = <AccountItemCount<T>>::get(owner.clone());2129 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21302131 <AccountItemCount<T>>::insert(owner.clone(), count2132 .checked_add(1)2133 .ok_or(Error::<T>::NumOverflow)?);2134 }2135 else {2136 <AccountItemCount<T>>::insert(owner.clone(), 1);2137 }21382139 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2140 if list_exists {2141 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2142 let item_contains = list.contains(&item_index.clone());21432144 if !item_contains {2145 list.push(item_index.clone());2146 }21472148 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2149 } else {2150 let mut itm = Vec::new();2151 itm.push(item_index.clone());2152 <AddressTokens<T>>::insert(collection_id, owner, itm);2153 2154 }21552156 Ok(())2157 }21582159 fn remove_token_index(2160 collection_id: CollectionId,2161 item_index: TokenId,2162 owner: T::AccountId,2163 ) -> DispatchResult {21642165 2166 <AccountItemCount<T>>::insert(owner.clone(), 2167 <AccountItemCount<T>>::get(owner.clone())2168 .checked_sub(1)2169 .ok_or(Error::<T>::NumOverflow)?);217021712172 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2173 if list_exists {2174 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2175 let item_contains = list.contains(&item_index.clone());21762177 if item_contains {2178 list.retain(|&item| item != item_index);2179 <AddressTokens<T>>::insert(collection_id, owner, list);2180 }2181 }21822183 Ok(())2184 }21852186 fn move_token_index(2187 collection_id: CollectionId,2188 item_index: TokenId,2189 old_owner: T::AccountId,2190 new_owner: T::AccountId,2191 ) -> DispatchResult {2192 Self::remove_token_index(collection_id, item_index, old_owner)?;2193 Self::add_token_index(collection_id, item_index, new_owner)?;21942195 Ok(())2196 }2197 2198 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2199 if <ContractOwner<T>>::contains_key(contract.clone()) {2200 let owner = <ContractOwner<T>>::get(contract);2201 ensure!(account == owner, Error::<T>::NoPermission);2202 } else {2203 fail!(Error::<T>::NoPermission);2204 }22052206 Ok(())2207 }2208}2209221022112212221322142215pub type Multiplier = FixedU128;22162217type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2218 <T as system::Trait>::AccountId,2219>>::Balance;2220type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2221 <T as system::Trait>::AccountId,2222>>::NegativeImbalance;2223222422252226#[derive(Encode, Decode, Clone, Eq, PartialEq)]2227pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2228 #[codec(compact)] BalanceOf<T>2229);22302231impl<T: Trait + Send + Sync> sp_std::fmt::Debug2232 for ChargeTransactionPayment<T>2233{2234 #[cfg(feature = "std")]2235 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2236 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2237 }2238 #[cfg(not(feature = "std"))]2239 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2240 Ok(())2241 }2242}22432244impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2245where2246 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2247 BalanceOf<T>: Send + Sync + FixedPointOperand,2248{2249 2250 pub fn from(fee: BalanceOf<T>) -> Self {2251 Self(fee)2252 }22532254 pub fn traditional_fee(2255 len: usize,2256 info: &DispatchInfoOf<T::Call>,2257 tip: BalanceOf<T>,2258 ) -> BalanceOf<T>2259 where2260 T::Call: Dispatchable<Info = DispatchInfo>,2261 {2262 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2263 }22642265 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2266 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2267 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2268 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2269 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2270 }22712272 fn withdraw_fee(2273 &self,2274 who: &T::AccountId,2275 call: &T::Call,2276 info: &DispatchInfoOf<T::Call>,2277 len: usize,2278 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2279 let tip = self.0;22802281 2282 2283 2284 2285 2286 2287 2288 let fee = Self::traditional_fee(len, info, tip);22892290 2291 if fee.is_zero() {2292 return Ok((fee, None));2293 }22942295 2296 2297 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2298 Some(Call::create_item(collection_id, _owner, _properties)) => {22992300 2301 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2302 (<Collection<T>>::get(collection_id).sponsor_confirmed)2303 {2304 <Collection<T>>::get(collection_id).sponsor2305 } else {2306 T::AccountId::default()2307 }2308 }2309 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2310 2311 let mut sponsor_transfer = false;2312 if <Collection<T>>::get(collection_id).sponsor_confirmed {23132314 let collection_limits = <Collection<T>>::get(collection_id).limits;2315 let collection_mode = <Collection<T>>::get(collection_id).mode;2316 2317 2318 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2319 sponsor_transfer = match collection_mode {2320 CollectionMode::NFT => {2321 2322 2323 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2324 collection_limits.sponsor_transfer_timeout2325 } else {2326 ChainLimit::get().nft_sponsor_transfer_timeout2327 };2328 2329 let mut sponsored = true;2330 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2331 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2332 let limit_time = last_tx_block + limit.into();2333 if block_number <= limit_time {2334 sponsored = false;2335 }2336 }2337 if sponsored {2338 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2339 }23402341 sponsored2342 }2343 CollectionMode::Fungible(_) => {2344 2345 2346 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2347 collection_limits.sponsor_transfer_timeout2348 } else {2349 ChainLimit::get().fungible_sponsor_transfer_timeout2350 };2351 2352 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2353 let mut sponsored = true;2354 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2355 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2356 let limit_time = last_tx_block + limit.into();2357 if block_number <= limit_time {2358 sponsored = false;2359 }2360 }2361 if sponsored {2362 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2363 }23642365 sponsored2366 }2367 CollectionMode::ReFungible(_) => {2368 2369 2370 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2371 collection_limits.sponsor_transfer_timeout2372 } else {2373 ChainLimit::get().refungible_sponsor_transfer_timeout2374 };2375 2376 let mut sponsored = true;2377 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2378 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2379 let limit_time = last_tx_block + limit.into();2380 if block_number <= limit_time {2381 sponsored = false;2382 }2383 }2384 if sponsored {2385 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2386 }23872388 sponsored2389 }2390 _ => {2391 false2392 },2393 };2394 }23952396 if !sponsor_transfer {2397 T::AccountId::default()2398 } else {2399 <Collection<T>>::get(collection_id).sponsor2400 }2401 }24022403 _ => T::AccountId::default(),2404 };24052406 2407 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24082409 2410 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24112412 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2413 code_hash,2414 &data,2415 &who,2416 );2417 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24182419 T::AccountId::default()2420 },24212422 2423 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24242425 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24262427 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2428 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2429 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2430 2431 if !owned_contract && white_list_enabled {2432 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2433 return Err(InvalidTransaction::Call.into());2434 }2435 }24362437 let mut sponsor_transfer = false;2438 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2439 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2440 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2441 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2442 let limit_time = last_tx_block + rate_limit;24432444 if block_number >= limit_time {2445 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2446 sponsor_transfer = true;2447 }2448 } else {2449 sponsor_transfer = false;2450 }2451 2452 2453 let mut sp = T::AccountId::default();2454 if sponsor_transfer {2455 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2456 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2457 sp = called_contract;2458 }2459 }2460 }24612462 sp2463 },24642465 _ => sponsor,2466 };24672468 let mut who_pays_fee: T::AccountId = sponsor.clone();2469 if sponsor == T::AccountId::default() {2470 who_pays_fee = who.clone();2471 }24722473 match <T as transaction_payment::Trait>::Currency::withdraw(2474 &who_pays_fee,2475 fee,2476 if tip.is_zero() {2477 WithdrawReason::TransactionPayment.into()2478 } else {2479 WithdrawReason::TransactionPayment | WithdrawReason::Tip2480 },2481 ExistenceRequirement::KeepAlive,2482 ) {2483 Ok(imbalance) => Ok((fee, Some(imbalance))),2484 Err(_) => Err(InvalidTransaction::Payment.into()),2485 }2486 }2487}248824892490impl<T: Trait + Send + Sync> SignedExtension2491 for ChargeTransactionPayment<T>2492where2493 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2494 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2495{2496 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2497 type AccountId = T::AccountId;2498 type Call = T::Call;2499 type AdditionalSigned = ();2500 type Pre = (2501 BalanceOf<T>,2502 Self::AccountId,2503 Option<NegativeImbalanceOf<T>>,2504 BalanceOf<T>,2505 );2506 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2507 Ok(())2508 }25092510 fn validate(2511 &self,2512 who: &Self::AccountId,2513 call: &Self::Call,2514 info: &DispatchInfoOf<Self::Call>,2515 len: usize,2516 ) -> TransactionValidity {2517 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2518 Ok(ValidTransaction {2519 priority: Self::get_priority(len, info, fee),2520 ..Default::default()2521 })2522 }25232524 fn pre_dispatch(2525 self,2526 who: &Self::AccountId,2527 call: &Self::Call,2528 info: &DispatchInfoOf<Self::Call>,2529 len: usize,2530 ) -> Result<Self::Pre, TransactionValidityError> {2531 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2532 Ok((self.0, who.clone(), imbalance, fee))2533 }25342535 fn post_dispatch(2536 pre: Self::Pre,2537 info: &DispatchInfoOf<Self::Call>,2538 post_info: &PostDispatchInfoOf<Self::Call>,2539 len: usize,2540 _result: &DispatchResult,2541 ) -> Result<(), TransactionValidityError> {2542 let (tip, who, imbalance, fee) = pre;2543 if let Some(payed) = imbalance {2544 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2545 len as u32, info, post_info, tip,2546 );2547 let refund = fee.saturating_sub(actual_fee);2548 let actual_payment =2549 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2550 &who, refund,2551 ) {2552 Ok(refund_imbalance) => {2553 2554 2555 match payed.offset(refund_imbalance) {2556 Ok(actual_payment) => actual_payment,2557 Err(_) => return Err(InvalidTransaction::Payment.into()),2558 }2559 }2560 2561 2562 Err(_) => payed,2563 };2564 let imbalances = actual_payment.split(tip);2565 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2566 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2567 );2568 }2569 Ok(())2570 }2571}25722573