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 CreateItemBasket get(fn create_item_basket): map hasher(twox_64_concat) (CollectionId, T::AccountId) => T::BlockNumber;423 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;424 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;425 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;426427 428 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;429 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;430 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;431 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;432 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 433 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 434 }435 add_extra_genesis {436 build(|config: &GenesisConfig<T>| {437 438 for (_num, _c) in &config.collection {439 <Module<T>>::init_collection(_c);440 }441442 for (_num, _c, _i) in &config.nft_item_id {443 <Module<T>>::init_nft_token(*_c, _i);444 }445446 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {447 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);448 }449450 for (_num, _c, _i) in &config.refungible_item_id {451 <Module<T>>::init_refungible_token(*_c, _i);452 }453 })454 }455}456457decl_event!(458 pub enum Event<T>459 where460 AccountId = <T as system::Trait>::AccountId,461 {462 463 464 465 466 467 468 469 470 471 Created(CollectionId, u8, AccountId),472473 474 475 476 477 478 479 480 ItemCreated(CollectionId, TokenId),481482 483 484 485 486 487 488 489 ItemDestroyed(CollectionId, TokenId),490 }491);492493decl_module! {494 pub struct Module<T: Trait> for enum Call where origin: T::Origin {495496 fn deposit_event() = default;497 type Error = Error<T>;498499 fn on_initialize(now: T::BlockNumber) -> Weight {500501 if ChainVersion::get() < 2502 {503 let value = NextCollectionID::get();504 CreatedCollectionCount::put(value);505 ChainVersion::put(2);506 }507508 0509 }510511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 #[weight = T::WeightInfo::create_collection()]528 pub fn create_collection(origin,529 collection_name: Vec<u16>,530 collection_description: Vec<u16>,531 token_prefix: Vec<u8>,532 mode: CollectionMode) -> DispatchResult {533534 535 let who = ensure_signed(origin)?;536537 let decimal_points = match mode {538 CollectionMode::Fungible(points) => points,539 CollectionMode::ReFungible(points) => points,540 _ => 0541 };542543 544 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);545546 547 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);548 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);549 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);550 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);551552 553 let next_id = CreatedCollectionCount::get()554 .checked_add(1)555 .ok_or(Error::<T>::NumOverflow)?;556557 558 let total = CollectionCount::get()559 .checked_add(1)560 .ok_or(Error::<T>::NumOverflow)?;561562 CreatedCollectionCount::put(next_id);563 CollectionCount::put(total);564565 566 let new_collection = CollectionType {567 owner: who.clone(),568 name: collection_name,569 mode: mode.clone(),570 mint_mode: false,571 access: AccessMode::Normal,572 description: collection_description,573 decimal_points: decimal_points,574 token_prefix: token_prefix,575 offchain_schema: Vec::new(),576 schema_version: SchemaVersion::ImageURL,577 sponsor: T::AccountId::default(),578 sponsor_confirmed: false,579 variable_on_chain_schema: Vec::new(),580 const_on_chain_schema: Vec::new(),581 limits: CollectionLimits::default(),582 };583584 585 <Collection<T>>::insert(next_id, new_collection);586587 588 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));589590 Ok(())591 }592593 594 595 596 597 598 599 600 601 602 #[weight = T::WeightInfo::destroy_collection()]603 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {604605 let sender = ensure_signed(origin)?;606 Self::check_owner_permissions(collection_id, sender)?;607608 <AddressTokens<T>>::remove_prefix(collection_id);609 <Allowances<T>>::remove_prefix(collection_id);610 <Balance<T>>::remove_prefix(collection_id);611 <ItemListIndex>::remove(collection_id);612 <AdminList<T>>::remove(collection_id);613 <Collection<T>>::remove(collection_id);614 <WhiteList<T>>::remove_prefix(collection_id);615616 <NftItemList<T>>::remove_prefix(collection_id);617 <FungibleItemList<T>>::remove_prefix(collection_id);618 <ReFungibleItemList<T>>::remove_prefix(collection_id);619620 <NftTransferBasket<T>>::remove_prefix(collection_id);621 <FungibleTransferBasket<T>>::remove_prefix(collection_id);622 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);623624 if CollectionCount::get() > 0625 {626 627 let total = CollectionCount::get()628 .checked_sub(1)629 .ok_or(Error::<T>::NumOverflow)?;630631 CollectionCount::put(total);632 }633634 Ok(())635 }636637 638 639 640 641 642 643 644 645 646 647 648 649 #[weight = T::WeightInfo::add_to_white_list()]650 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{651652 let sender = ensure_signed(origin)?;653 Self::check_owner_or_admin_permissions(collection_id, sender)?;654655 <WhiteList<T>>::insert(collection_id, address, true);656 657 Ok(())658 }659660 661 662 663 664 665 666 667 668 669 670 671 672 #[weight = T::WeightInfo::remove_from_white_list()]673 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{674675 let sender = ensure_signed(origin)?;676 Self::check_owner_or_admin_permissions(collection_id, sender)?;677678 <WhiteList<T>>::remove(collection_id, address);679680 Ok(())681 }682683 684 685 686 687 688 689 690 691 692 693 694 #[weight = T::WeightInfo::set_public_access_mode()]695 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult696 {697 let sender = ensure_signed(origin)?;698699 Self::check_owner_permissions(collection_id, sender)?;700 let mut target_collection = <Collection<T>>::get(collection_id);701 target_collection.access = mode;702 <Collection<T>>::insert(collection_id, target_collection);703704 Ok(())705 }706707 708 709 710 711 712 713 714 715 716 717 718 719 720 #[weight = T::WeightInfo::set_mint_permission()]721 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult722 {723 let sender = ensure_signed(origin)?;724725 Self::check_owner_permissions(collection_id, sender)?;726 let mut target_collection = <Collection<T>>::get(collection_id);727 target_collection.mint_mode = mint_permission;728 <Collection<T>>::insert(collection_id, target_collection);729730 Ok(())731 }732733 734 735 736 737 738 739 740 741 742 743 744 #[weight = T::WeightInfo::change_collection_owner()]745 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {746747 let sender = ensure_signed(origin)?;748 Self::check_owner_permissions(collection_id, sender)?;749 let mut target_collection = <Collection<T>>::get(collection_id);750 target_collection.owner = new_owner;751 <Collection<T>>::insert(collection_id, target_collection);752753 Ok(())754 }755756 757 758 759 760 761 762 763 764 765 766 767 768 769 #[weight = T::WeightInfo::add_collection_admin()]770 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {771772 let sender = ensure_signed(origin)?;773 Self::check_owner_or_admin_permissions(collection_id, sender)?;774 let mut admin_arr: Vec<T::AccountId> = Vec::new();775776 if <AdminList<T>>::contains_key(collection_id)777 {778 admin_arr = <AdminList<T>>::get(collection_id);779 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);780 }781782 783 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);784785 admin_arr.push(new_admin_id);786 <AdminList<T>>::insert(collection_id, admin_arr);787788 Ok(())789 }790791 792 793 794 795 796 797 798 799 800 801 802 803 #[weight = T::WeightInfo::remove_collection_admin()]804 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {805806 let sender = ensure_signed(origin)?;807 Self::check_owner_or_admin_permissions(collection_id, sender)?;808809 if <AdminList<T>>::contains_key(collection_id)810 {811 let mut admin_arr = <AdminList<T>>::get(collection_id);812 admin_arr.retain(|i| *i != account_id);813 <AdminList<T>>::insert(collection_id, admin_arr);814 }815816 Ok(())817 }818819 820 821 822 823 824 825 826 827 828 #[weight = T::WeightInfo::set_collection_sponsor()]829 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {830831 let sender = ensure_signed(origin)?;832 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);833834 let mut target_collection = <Collection<T>>::get(collection_id);835 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);836837 target_collection.sponsor = new_sponsor;838 target_collection.sponsor_confirmed = false;839 <Collection<T>>::insert(collection_id, target_collection);840841 Ok(())842 }843844 845 846 847 848 849 850 851 #[weight = T::WeightInfo::confirm_sponsorship()]852 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {853854 let sender = ensure_signed(origin)?;855 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);856857 let mut target_collection = <Collection<T>>::get(collection_id);858 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);859860 target_collection.sponsor_confirmed = true;861 <Collection<T>>::insert(collection_id, target_collection);862863 Ok(())864 }865866 867 868 869 870 871 872 873 874 875 #[weight = T::WeightInfo::remove_collection_sponsor()]876 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {877878 let sender = ensure_signed(origin)?;879 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);880881 let mut target_collection = <Collection<T>>::get(collection_id);882 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);883884 target_collection.sponsor = T::AccountId::default();885 target_collection.sponsor_confirmed = false;886 <Collection<T>>::insert(collection_id, target_collection);887888 Ok(())889 }890891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914915 #[weight = T::WeightInfo::create_item(data.len())]916 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {917918 let sender = ensure_signed(origin)?;919920 Self::collection_exists(collection_id)?;921922 let target_collection = <Collection<T>>::get(collection_id);923924 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;925 Self::validate_create_item_args(&target_collection, &data)?;926 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;927928 Ok(())929 }930931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 #[weight = T::WeightInfo::create_item(items_data.into_iter()950 .map(|data| { data.len() })951 .sum())]952 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {953954 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);955 let sender = ensure_signed(origin)?;956957 Self::collection_exists(collection_id)?;958 let target_collection = <Collection<T>>::get(collection_id);959960 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;961962 for data in &items_data {963 Self::validate_create_item_args(&target_collection, data)?;964 }965 for data in &items_data {966 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;967 }968969 Ok(())970 }971972 973 974 975 976 977 978 979 980 981 982 983 984 985 #[weight = T::WeightInfo::burn_item()]986 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {987988 let sender = ensure_signed(origin)?;989 Self::collection_exists(collection_id)?;990991 992 let target_collection = <Collection<T>>::get(collection_id);993 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||994 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),995 Error::<T>::NoPermission);996997 if target_collection.access == AccessMode::WhiteList {998 Self::check_white_list(collection_id, &sender)?;999 }10001001 match target_collection.mode1002 {1003 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1004 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1005 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1006 _ => ()1007 };10081009 1010 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10111012 Ok(())1013 }10141015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 #[weight = T::WeightInfo::transfer()]1039 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10401041 let sender = ensure_signed(origin)?;1042 let target_collection = <Collection<T>>::get(collection_id);10431044 1045 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10461047 1048 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1049 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1050 Error::<T>::NoPermission);10511052 if target_collection.access == AccessMode::WhiteList {1053 Self::check_white_list(collection_id, &sender)?;1054 Self::check_white_list(collection_id, &recipient)?;1055 }10561057 match target_collection.mode1058 {1059 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1060 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1061 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1062 _ => ()1063 };10641065 Ok(())1066 }10671068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 #[weight = T::WeightInfo::approve()]1084 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {10851086 let sender = ensure_signed(origin)?;10871088 1089 let target_collection = <Collection<T>>::get(collection_id);1090 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1091 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1092 Error::<T>::NoPermission);10931094 if target_collection.access == AccessMode::WhiteList {1095 Self::check_white_list(collection_id, &sender)?;1096 Self::check_white_list(collection_id, &spender)?;1097 }10981099 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1100 let mut allowance: u128 = amount;1101 if allowance_exists {1102 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1103 }1104 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11051106 Ok(())1107 }1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 #[weight = T::WeightInfo::transfer_from()]1129 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11301131 let sender = ensure_signed(origin)?;1132 let mut appoved_transfer = false;11331134 1135 let mut approval: u128 = 0;1136 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1137 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1138 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1139 appoved_transfer = true;1140 }11411142 let target_collection = <Collection<T>>::get(collection_id);11431144 1145 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11461147 1148 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1149 Error::<T>::NoPermission);11501151 if target_collection.access == AccessMode::WhiteList {1152 Self::check_white_list(collection_id, &sender)?;1153 Self::check_white_list(collection_id, &recipient)?;1154 }11551156 1157 if approval.checked_sub(value).unwrap_or(0) > 0 {1158 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1159 }1160 else {1161 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1162 }11631164 match target_collection.mode1165 {1166 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1167 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1168 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1169 _ => ()1170 };11711172 Ok(())1173 }11741175 #[weight = 0]1176 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11771178 1179 1180 1181 11821183 11841185 11861187 Ok(())1188 }11891190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 #[weight = T::WeightInfo::set_variable_meta_data()]1203 pub fn set_variable_meta_data (1204 origin,1205 collection_id: CollectionId,1206 item_id: TokenId,1207 data: Vec<u8>1208 ) -> DispatchResult {1209 let sender = ensure_signed(origin)?;1210 1211 Self::collection_exists(collection_id)?;1212 1213 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12141215 1216 let target_collection = <Collection<T>>::get(collection_id);1217 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1218 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1219 Error::<T>::NoPermission);12201221 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12221223 match target_collection.mode1224 {1225 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1226 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1227 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1228 _ => fail!(Error::<T>::UnexpectedCollectionType)1229 };12301231 Ok(())1232 }1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 #[weight = T::WeightInfo::set_schema_version()]1249 pub fn set_schema_version(1250 origin,1251 collection_id: CollectionId,1252 version: SchemaVersion1253 ) -> DispatchResult {1254 let sender = ensure_signed(origin)?;1255 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1256 let mut target_collection = <Collection<T>>::get(collection_id);1257 target_collection.schema_version = version;1258 <Collection<T>>::insert(collection_id, target_collection);12591260 Ok(())1261 }12621263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 #[weight = T::WeightInfo::set_offchain_schema()]1276 pub fn set_offchain_schema(1277 origin,1278 collection_id: CollectionId,1279 schema: Vec<u8>1280 ) -> DispatchResult {1281 let sender = ensure_signed(origin)?;1282 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12831284 let mut target_collection = <Collection<T>>::get(collection_id);1285 target_collection.offchain_schema = schema;1286 <Collection<T>>::insert(collection_id, target_collection);12871288 Ok(())1289 }12901291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 #[weight = T::WeightInfo::set_const_on_chain_schema()]1304 pub fn set_const_on_chain_schema (1305 origin,1306 collection_id: CollectionId,1307 schema: Vec<u8>1308 ) -> DispatchResult {1309 let sender = ensure_signed(origin)?;1310 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13111312 let mut target_collection = <Collection<T>>::get(collection_id);1313 target_collection.const_on_chain_schema = schema;1314 <Collection<T>>::insert(collection_id, target_collection);13151316 Ok(())1317 }13181319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 #[weight = T::WeightInfo::set_const_on_chain_schema()]1332 pub fn set_variable_on_chain_schema (1333 origin,1334 collection_id: CollectionId,1335 schema: Vec<u8>1336 ) -> DispatchResult {1337 let sender = ensure_signed(origin)?;1338 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13391340 let mut target_collection = <Collection<T>>::get(collection_id);1341 target_collection.variable_on_chain_schema = schema;1342 <Collection<T>>::insert(collection_id, target_collection);13431344 Ok(())1345 }13461347 1348 #[weight = T::WeightInfo::set_chain_limits()]1349 pub fn set_chain_limits(1350 origin,1351 limits: ChainLimits1352 ) -> DispatchResult {13531354 #[cfg(not(feature = "runtime-benchmarks"))]1355 ensure_root(origin)?;13561357 <ChainLimit>::put(limits);1358 Ok(())1359 }13601361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 #[weight = T::WeightInfo::enable_contract_sponsoring()]1373 pub fn enable_contract_sponsoring(1374 origin,1375 contract_address: T::AccountId,1376 enable: bool1377 ) -> DispatchResult {13781379 let sender = ensure_signed(origin)?;13801381 #[cfg(feature = "runtime-benchmarks")]1382 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13831384 Self::ensure_contract_owned(sender, &contract_address)?;13851386 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1387 Ok(())1388 }13891390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1408 pub fn set_contract_sponsoring_rate_limit(1409 origin,1410 contract_address: T::AccountId,1411 rate_limit: T::BlockNumber1412 ) -> DispatchResult {1413 let sender = ensure_signed(origin)?;14141415 #[cfg(feature = "runtime-benchmarks")]1416 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14171418 Self::ensure_contract_owned(sender, &contract_address)?;1419 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1420 Ok(())1421 }14221423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 #[weight = T::WeightInfo::toggle_contract_white_list()]1435 pub fn toggle_contract_white_list(1436 origin,1437 contract_address: T::AccountId,1438 enable: bool1439 ) -> DispatchResult {1440 let sender = ensure_signed(origin)?;14411442 #[cfg(feature = "runtime-benchmarks")]1443 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14441445 Self::ensure_contract_owned(sender, &contract_address)?;1446 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1447 Ok(())1448 }1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 #[weight = T::WeightInfo::add_to_contract_white_list()]1462 pub fn add_to_contract_white_list(1463 origin,1464 contract_address: T::AccountId,1465 account_address: T::AccountId1466 ) -> DispatchResult {1467 let sender = ensure_signed(origin)?;14681469 #[cfg(feature = "runtime-benchmarks")]1470 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1471 1472 Self::ensure_contract_owned(sender, &contract_address)?; 1473 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1474 Ok(())1475 }14761477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 #[weight = T::WeightInfo::remove_from_contract_white_list()]1489 pub fn remove_from_contract_white_list(1490 origin,1491 contract_address: T::AccountId,1492 account_address: T::AccountId1493 ) -> DispatchResult {1494 let sender = ensure_signed(origin)?;14951496 #[cfg(feature = "runtime-benchmarks")]1497 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14981499 Self::ensure_contract_owned(sender, &contract_address)?;1500 <ContractWhiteList<T>>::remove(contract_address, account_address);1501 Ok(())1502 }15031504 #[weight = T::WeightInfo::set_collection_limits()]1505 pub fn set_collection_limits(1506 origin,1507 collection_id: u32,1508 limits: CollectionLimits,1509 ) -> DispatchResult {1510 let sender = ensure_signed(origin)?;1511 Self::check_owner_permissions(collection_id, sender.clone())?;1512 let mut target_collection = <Collection<T>>::get(collection_id);1513 let chain_limits = ChainLimit::get();1514 let climits = target_collection.limits;15151516 1517 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1518 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1519 Error::<T>::CollectionLimitBoundsExceeded);15201521 1522 ensure!(climits.token_limit > limits.token_limit && 1523 limits.token_limit <= chain_limits.account_token_ownership_limit, 1524 Error::<T>::AccountTokenLimitExceeded);15251526 target_collection.limits = limits;1527 <Collection<T>>::insert(collection_id, target_collection);15281529 Ok(())1530 } 1531 }1532}15331534impl<T: Trait> Module<T> {15351536 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15371538 1539 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1540 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1541 1542 Ok(())1543 }15441545 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15461547 1548 let total_items: u32 = ItemListIndex::get(collection_id);1549 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1550 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1551 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15521553 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1554 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1555 Self::check_white_list(collection_id, owner)?;1556 Self::check_white_list(collection_id, sender)?;1557 }15581559 Ok(())1560 }15611562 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1563 match target_collection.mode1564 {1565 CollectionMode::NFT => {1566 if let CreateItemData::NFT(data) = data {1567 1568 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1569 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1570 } else {1571 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1572 }1573 },1574 CollectionMode::Fungible(_) => {1575 if let CreateItemData::Fungible(_) = data {1576 } else {1577 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1578 }1579 },1580 CollectionMode::ReFungible(_) => {1581 if let CreateItemData::ReFungible(data) = data {15821583 1584 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1585 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1586 } else {1587 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1588 }1589 },1590 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1591 };15921593 Ok(())1594 }15951596 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1597 match data1598 {1599 CreateItemData::NFT(data) => {1600 let item = NftItemType {1601 owner,1602 const_data: data.const_data,1603 variable_data: data.variable_data1604 };16051606 Self::add_nft_item(collection_id, item)?;1607 },1608 CreateItemData::Fungible(data) => {1609 Self::add_fungible_item(collection_id, &owner, data.value)?;1610 },1611 CreateItemData::ReFungible(data) => {1612 let mut owner_list = Vec::new();1613 let value = (10 as u128).pow(collection.decimal_points as u32);1614 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16151616 let item = ReFungibleItemType {1617 owner: owner_list,1618 const_data: data.const_data,1619 variable_data: data.variable_data1620 };16211622 Self::add_refungible_item(collection_id, item)?;1623 }1624 };16251626 1627 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16281629 Ok(())1630 }16311632 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {16331634 1635 let mut balance: u128 = 0;1636 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1637 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1638 } 16391640 1641 let item = FungibleItemType {1642 value: balance + value1643 };1644 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);16451646 1647 let new_balance = <Balance<T>>::get(collection_id, owner)1648 .checked_add(value)1649 .ok_or(Error::<T>::NumOverflow)?;1650 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16511652 Ok(())1653 }16541655 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1656 let current_index = <ItemListIndex>::get(collection_id)1657 .checked_add(1)1658 .ok_or(Error::<T>::NumOverflow)?;1659 let itemcopy = item.clone();16601661 let value = item.owner.first().unwrap().fraction;1662 let owner = item.owner.first().unwrap().owner.clone();16631664 Self::add_token_index(collection_id, current_index, owner.clone())?;16651666 <ItemListIndex>::insert(collection_id, current_index);1667 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16681669 1670 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1671 .checked_add(value)1672 .ok_or(Error::<T>::NumOverflow)?;1673 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16741675 Ok(())1676 }16771678 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1679 let current_index = <ItemListIndex>::get(collection_id)1680 .checked_add(1)1681 .ok_or(Error::<T>::NumOverflow)?;16821683 let item_owner = item.owner.clone();1684 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16851686 <ItemListIndex>::insert(collection_id, current_index);1687 <NftItemList<T>>::insert(collection_id, current_index, item);16881689 1690 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1691 .checked_add(1)1692 .ok_or(Error::<T>::NumOverflow)?;1693 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16941695 Ok(())1696 }16971698 fn burn_refungible_item(1699 collection_id: CollectionId,1700 item_id: TokenId,1701 owner: T::AccountId,1702 ) -> DispatchResult {1703 ensure!(1704 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1705 Error::<T>::TokenNotFound1706 );1707 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1708 let item = collection1709 .owner1710 .iter()1711 .filter(|&i| i.owner == owner)1712 .next()1713 .unwrap();1714 Self::remove_token_index(collection_id, item_id, owner.clone())?;17151716 1717 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1718 .checked_sub(item.fraction)1719 .ok_or(Error::<T>::NumOverflow)?;1720 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17211722 <ReFungibleItemList<T>>::remove(collection_id, item_id);17231724 Ok(())1725 }17261727 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1728 ensure!(1729 <NftItemList<T>>::contains_key(collection_id, item_id),1730 Error::<T>::TokenNotFound1731 );1732 let item = <NftItemList<T>>::get(collection_id, item_id);1733 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17341735 1736 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1737 .checked_sub(1)1738 .ok_or(Error::<T>::NumOverflow)?;1739 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1740 <NftItemList<T>>::remove(collection_id, item_id);17411742 Ok(())1743 }17441745 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1746 ensure!(1747 <FungibleItemList<T>>::contains_key(collection_id, owner),1748 Error::<T>::TokenNotFound1749 );1750 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1751 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);17521753 1754 let new_balance = <Balance<T>>::get(collection_id, owner)1755 .checked_sub(value)1756 .ok_or(Error::<T>::NumOverflow)?;1757 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);17581759 if balance.value - value > 0 {1760 balance.value -= value;1761 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1762 }1763 else {1764 <FungibleItemList<T>>::remove(collection_id, owner);1765 }17661767 Ok(())1768 }17691770 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1771 ensure!(1772 <Collection<T>>::contains_key(collection_id),1773 Error::<T>::CollectionNotFound1774 );1775 Ok(())1776 }17771778 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1779 Self::collection_exists(collection_id)?;17801781 let target_collection = <Collection<T>>::get(collection_id);1782 ensure!(1783 subject == target_collection.owner,1784 Error::<T>::NoPermission1785 );17861787 Ok(())1788 }17891790 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1791 let target_collection = <Collection<T>>::get(collection_id);1792 let mut result: bool = subject == target_collection.owner;1793 let exists = <AdminList<T>>::contains_key(collection_id);17941795 if !result & exists {1796 if <AdminList<T>>::get(collection_id).contains(&subject) {1797 result = true1798 }1799 }18001801 result1802 }18031804 fn check_owner_or_admin_permissions(1805 collection_id: CollectionId,1806 subject: T::AccountId,1807 ) -> DispatchResult {1808 Self::collection_exists(collection_id)?;1809 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18101811 ensure!(1812 result,1813 Error::<T>::NoPermission1814 );1815 Ok(())1816 }18171818 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1819 let target_collection = <Collection<T>>::get(collection_id);18201821 match target_collection.mode {1822 CollectionMode::NFT => {1823 <NftItemList<T>>::get(collection_id, item_id).owner == subject1824 }1825 CollectionMode::Fungible(_) => {1826 <FungibleItemList<T>>::contains_key(collection_id, &subject)1827 }1828 CollectionMode::ReFungible(_) => {1829 <ReFungibleItemList<T>>::get(collection_id, item_id)1830 .owner1831 .iter()1832 .any(|i| i.owner == subject)1833 }1834 CollectionMode::Invalid => false,1835 }1836 }18371838 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1839 let mes = Error::<T>::AddresNotInWhiteList;1840 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18411842 Ok(())1843 }18441845 fn transfer_fungible(1846 collection_id: CollectionId,1847 value: u128,1848 owner: &T::AccountId,1849 recipient: &T::AccountId,1850 ) -> DispatchResult {1851 ensure!(1852 <FungibleItemList<T>>::contains_key(collection_id, owner),1853 Error::<T>::TokenNotFound1854 );18551856 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1857 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18581859 1860 Self::add_fungible_item(collection_id, recipient, value)?;18611862 1863 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18641865 1866 if balance.value == value {1867 <FungibleItemList<T>>::remove(collection_id, owner);1868 }1869 else {1870 balance.value -= value;1871 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1872 }18731874 Ok(())1875 }18761877 fn transfer_refungible(1878 collection_id: CollectionId,1879 item_id: TokenId,1880 value: u128,1881 owner: T::AccountId,1882 new_owner: T::AccountId,1883 ) -> DispatchResult {1884 ensure!(1885 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1886 Error::<T>::TokenNotFound1887 );18881889 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1890 let item = full_item1891 .owner1892 .iter()1893 .filter(|i| i.owner == owner)1894 .next()1895 .ok_or(Error::<T>::NumOverflow)?;1896 let amount = item.fraction;18971898 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18991900 1901 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1902 .checked_sub(value)1903 .ok_or(Error::<T>::NumOverflow)?;1904 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19051906 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1907 .checked_add(value)1908 .ok_or(Error::<T>::NumOverflow)?;1909 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19101911 let old_owner = item.owner.clone();1912 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19131914 1915 if amount == value && !new_owner_has_account {1916 1917 1918 let mut new_full_item = full_item.clone();1919 new_full_item1920 .owner1921 .iter_mut()1922 .find(|i| i.owner == owner)1923 .unwrap()1924 .owner = new_owner.clone();1925 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19261927 1928 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1929 } else {1930 let mut new_full_item = full_item.clone();1931 new_full_item1932 .owner1933 .iter_mut()1934 .find(|i| i.owner == owner)1935 .unwrap()1936 .fraction -= value;19371938 1939 if new_owner_has_account {1940 1941 new_full_item1942 .owner1943 .iter_mut()1944 .find(|i| i.owner == new_owner)1945 .unwrap()1946 .fraction += value;1947 } else {1948 1949 new_full_item.owner.push(Ownership {1950 owner: new_owner.clone(),1951 fraction: value,1952 });1953 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1954 }19551956 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1957 }19581959 Ok(())1960 }19611962 fn transfer_nft(1963 collection_id: CollectionId,1964 item_id: TokenId,1965 sender: T::AccountId,1966 new_owner: T::AccountId,1967 ) -> DispatchResult {1968 ensure!(1969 <NftItemList<T>>::contains_key(collection_id, item_id),1970 Error::<T>::TokenNotFound1971 );19721973 let mut item = <NftItemList<T>>::get(collection_id, item_id);19741975 ensure!(1976 sender == item.owner,1977 Error::<T>::MustBeTokenOwner1978 );19791980 1981 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1982 .checked_sub(1)1983 .ok_or(Error::<T>::NumOverflow)?;1984 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19851986 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1987 .checked_add(1)1988 .ok_or(Error::<T>::NumOverflow)?;1989 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19901991 1992 let old_owner = item.owner.clone();1993 item.owner = new_owner.clone();1994 <NftItemList<T>>::insert(collection_id, item_id, item);19951996 1997 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19981999 Ok(())2000 }2001 2002 fn item_exists(2003 collection_id: CollectionId,2004 item_id: TokenId,2005 mode: &CollectionMode2006 ) -> DispatchResult {2007 match mode {2008 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2009 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2010 _ => ()2011 };2012 2013 Ok(())2014 }20152016 fn set_re_fungible_variable_data(2017 collection_id: CollectionId,2018 item_id: TokenId,2019 data: Vec<u8>2020 ) -> DispatchResult {2021 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20222023 item.variable_data = data;20242025 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20262027 Ok(())2028 }20292030 fn set_nft_variable_data(2031 collection_id: CollectionId,2032 item_id: TokenId,2033 data: Vec<u8>2034 ) -> DispatchResult {2035 let mut item = <NftItemList<T>>::get(collection_id, item_id);2036 2037 item.variable_data = data;20382039 <NftItemList<T>>::insert(collection_id, item_id, item);2040 2041 Ok(())2042 }20432044 fn init_collection(item: &CollectionType<T::AccountId>) {2045 2046 assert!(2047 item.decimal_points <= MAX_DECIMAL_POINTS,2048 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2049 );2050 assert!(2051 item.name.len() <= 64,2052 "Collection name can not be longer than 63 char"2053 );2054 assert!(2055 item.name.len() <= 256,2056 "Collection description can not be longer than 255 char"2057 );2058 assert!(2059 item.token_prefix.len() <= 16,2060 "Token prefix can not be longer than 15 char"2061 );20622063 2064 let next_id = CreatedCollectionCount::get()2065 .checked_add(1)2066 .unwrap();20672068 CreatedCollectionCount::put(next_id);2069 }20702071 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2072 let current_index = <ItemListIndex>::get(collection_id)2073 .checked_add(1)2074 .unwrap();20752076 let item_owner = item.owner.clone();2077 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20782079 <ItemListIndex>::insert(collection_id, current_index);20802081 2082 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2083 .checked_add(1)2084 .unwrap();2085 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2086 }20872088 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2089 let current_index = <ItemListIndex>::get(collection_id)2090 .checked_add(1)2091 .unwrap();20922093 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();20942095 <ItemListIndex>::insert(collection_id, current_index);20962097 2098 let new_balance = <Balance<T>>::get(collection_id, owner)2099 .checked_add(item.value)2100 .unwrap();2101 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2102 }21032104 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2105 let current_index = <ItemListIndex>::get(collection_id)2106 .checked_add(1)2107 .unwrap();21082109 let value = item.owner.first().unwrap().fraction;2110 let owner = item.owner.first().unwrap().owner.clone();21112112 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();21132114 <ItemListIndex>::insert(collection_id, current_index);21152116 2117 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2118 .checked_add(value)2119 .unwrap();2120 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2121 }21222123 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21242125 2126 if <AccountItemCount<T>>::contains_key(owner.clone()) {21272128 2129 let count = <AccountItemCount<T>>::get(owner.clone());2130 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21312132 <AccountItemCount<T>>::insert(owner.clone(), count2133 .checked_add(1)2134 .ok_or(Error::<T>::NumOverflow)?);2135 }2136 else {2137 <AccountItemCount<T>>::insert(owner.clone(), 1);2138 }21392140 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2141 if list_exists {2142 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2143 let item_contains = list.contains(&item_index.clone());21442145 if !item_contains {2146 list.push(item_index.clone());2147 }21482149 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2150 } else {2151 let mut itm = Vec::new();2152 itm.push(item_index.clone());2153 <AddressTokens<T>>::insert(collection_id, owner, itm);2154 2155 }21562157 Ok(())2158 }21592160 fn remove_token_index(2161 collection_id: CollectionId,2162 item_index: TokenId,2163 owner: T::AccountId,2164 ) -> DispatchResult {21652166 2167 <AccountItemCount<T>>::insert(owner.clone(), 2168 <AccountItemCount<T>>::get(owner.clone())2169 .checked_sub(1)2170 .ok_or(Error::<T>::NumOverflow)?);217121722173 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2174 if list_exists {2175 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2176 let item_contains = list.contains(&item_index.clone());21772178 if item_contains {2179 list.retain(|&item| item != item_index);2180 <AddressTokens<T>>::insert(collection_id, owner, list);2181 }2182 }21832184 Ok(())2185 }21862187 fn move_token_index(2188 collection_id: CollectionId,2189 item_index: TokenId,2190 old_owner: T::AccountId,2191 new_owner: T::AccountId,2192 ) -> DispatchResult {2193 Self::remove_token_index(collection_id, item_index, old_owner)?;2194 Self::add_token_index(collection_id, item_index, new_owner)?;21952196 Ok(())2197 }2198 2199 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2200 if <ContractOwner<T>>::contains_key(contract.clone()) {2201 let owner = <ContractOwner<T>>::get(contract);2202 ensure!(account == owner, Error::<T>::NoPermission);2203 } else {2204 fail!(Error::<T>::NoPermission);2205 }22062207 Ok(())2208 }2209}2210221122122213221422152216pub type Multiplier = FixedU128;22172218type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2219 <T as system::Trait>::AccountId,2220>>::Balance;2221type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2222 <T as system::Trait>::AccountId,2223>>::NegativeImbalance;2224222522262227#[derive(Encode, Decode, Clone, Eq, PartialEq)]2228pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2229 #[codec(compact)] BalanceOf<T>2230);22312232impl<T: Trait + Send + Sync> sp_std::fmt::Debug2233 for ChargeTransactionPayment<T>2234{2235 #[cfg(feature = "std")]2236 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2237 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2238 }2239 #[cfg(not(feature = "std"))]2240 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2241 Ok(())2242 }2243}22442245impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2246where2247 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2248 BalanceOf<T>: Send + Sync + FixedPointOperand,2249{2250 2251 pub fn from(fee: BalanceOf<T>) -> Self {2252 Self(fee)2253 }22542255 pub fn traditional_fee(2256 len: usize,2257 info: &DispatchInfoOf<T::Call>,2258 tip: BalanceOf<T>,2259 ) -> BalanceOf<T>2260 where2261 T::Call: Dispatchable<Info = DispatchInfo>,2262 {2263 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2264 }22652266 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2267 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2268 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2269 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2270 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2271 }22722273 fn withdraw_fee(2274 &self,2275 who: &T::AccountId,2276 call: &T::Call,2277 info: &DispatchInfoOf<T::Call>,2278 len: usize,2279 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2280 let tip = self.0;22812282 2283 2284 2285 2286 2287 2288 2289 let fee = Self::traditional_fee(len, info, tip);22902291 2292 if fee.is_zero() {2293 return Ok((fee, None));2294 }22952296 2297 2298 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2299 Some(Call::create_item(collection_id, _owner, _properties)) => {23002301 2302 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;23032304 let limit = <Collection<T>>::get(collection_id).limits.sponsor_transfer_timeout;2305 let mut sponsored = true;2306 if <CreateItemBasket<T>>::contains_key((collection_id, &who)) {2307 let last_tx_block = <CreateItemBasket<T>>::get((collection_id, &who));2308 let limit_time = last_tx_block + limit.into();2309 if block_number <= limit_time {2310 sponsored = false;2311 }2312 }2313 if sponsored {2314 <CreateItemBasket<T>>::insert((collection_id, who.clone()), block_number);2315 }23162317 2318 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2319 (<Collection<T>>::get(collection_id).sponsor_confirmed) &&2320 (sponsored)2321 {2322 <Collection<T>>::get(collection_id).sponsor2323 } else {2324 T::AccountId::default()2325 }2326 }2327 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2328 2329 let mut sponsor_transfer = false;2330 if <Collection<T>>::get(collection_id).sponsor_confirmed {23312332 let collection_limits = <Collection<T>>::get(collection_id).limits;2333 let collection_mode = <Collection<T>>::get(collection_id).mode;2334 2335 2336 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2337 sponsor_transfer = match collection_mode {2338 CollectionMode::NFT => {2339 2340 2341 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2342 collection_limits.sponsor_transfer_timeout2343 } else {2344 ChainLimit::get().nft_sponsor_transfer_timeout2345 };2346 2347 let mut sponsored = true;2348 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2349 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2350 let limit_time = last_tx_block + limit.into();2351 if block_number <= limit_time {2352 sponsored = false;2353 }2354 }2355 if sponsored {2356 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2357 }23582359 sponsored2360 }2361 CollectionMode::Fungible(_) => {2362 2363 2364 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2365 collection_limits.sponsor_transfer_timeout2366 } else {2367 ChainLimit::get().fungible_sponsor_transfer_timeout2368 };2369 2370 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2371 let mut sponsored = true;2372 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2373 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2374 let limit_time = last_tx_block + limit.into();2375 if block_number <= limit_time {2376 sponsored = false;2377 }2378 }2379 if sponsored {2380 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2381 }23822383 sponsored2384 }2385 CollectionMode::ReFungible(_) => {2386 2387 2388 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2389 collection_limits.sponsor_transfer_timeout2390 } else {2391 ChainLimit::get().refungible_sponsor_transfer_timeout2392 };2393 2394 let mut sponsored = true;2395 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2396 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2397 let limit_time = last_tx_block + limit.into();2398 if block_number <= limit_time {2399 sponsored = false;2400 }2401 }2402 if sponsored {2403 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2404 }24052406 sponsored2407 }2408 _ => {2409 false2410 },2411 };2412 }24132414 if !sponsor_transfer {2415 T::AccountId::default()2416 } else {2417 <Collection<T>>::get(collection_id).sponsor2418 }2419 }24202421 _ => T::AccountId::default(),2422 };24232424 2425 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24262427 2428 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24292430 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2431 code_hash,2432 &data,2433 &who,2434 );2435 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24362437 T::AccountId::default()2438 },24392440 2441 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24422443 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24442445 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2446 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2447 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2448 2449 if !owned_contract && white_list_enabled {2450 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2451 return Err(InvalidTransaction::Call.into());2452 }2453 }24542455 let mut sponsor_transfer = false;2456 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2457 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2458 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2459 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2460 let limit_time = last_tx_block + rate_limit;24612462 if block_number >= limit_time {2463 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2464 sponsor_transfer = true;2465 }2466 } else {2467 sponsor_transfer = false;2468 }2469 2470 2471 let mut sp = T::AccountId::default();2472 if sponsor_transfer {2473 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2474 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2475 sp = called_contract;2476 }2477 }2478 }24792480 sp2481 },24822483 _ => sponsor,2484 };24852486 let mut who_pays_fee: T::AccountId = sponsor.clone();2487 if sponsor == T::AccountId::default() {2488 who_pays_fee = who.clone();2489 }24902491 match <T as transaction_payment::Trait>::Currency::withdraw(2492 &who_pays_fee,2493 fee,2494 if tip.is_zero() {2495 WithdrawReason::TransactionPayment.into()2496 } else {2497 WithdrawReason::TransactionPayment | WithdrawReason::Tip2498 },2499 ExistenceRequirement::KeepAlive,2500 ) {2501 Ok(imbalance) => Ok((fee, Some(imbalance))),2502 Err(_) => Err(InvalidTransaction::Payment.into()),2503 }2504 }2505}250625072508impl<T: Trait + Send + Sync> SignedExtension2509 for ChargeTransactionPayment<T>2510where2511 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2512 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2513{2514 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2515 type AccountId = T::AccountId;2516 type Call = T::Call;2517 type AdditionalSigned = ();2518 type Pre = (2519 BalanceOf<T>,2520 Self::AccountId,2521 Option<NegativeImbalanceOf<T>>,2522 BalanceOf<T>,2523 );2524 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2525 Ok(())2526 }25272528 fn validate(2529 &self,2530 who: &Self::AccountId,2531 call: &Self::Call,2532 info: &DispatchInfoOf<Self::Call>,2533 len: usize,2534 ) -> TransactionValidity {2535 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2536 Ok(ValidTransaction {2537 priority: Self::get_priority(len, info, fee),2538 ..Default::default()2539 })2540 }25412542 fn pre_dispatch(2543 self,2544 who: &Self::AccountId,2545 call: &Self::Call,2546 info: &DispatchInfoOf<Self::Call>,2547 len: usize,2548 ) -> Result<Self::Pre, TransactionValidityError> {2549 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2550 Ok((self.0, who.clone(), imbalance, fee))2551 }25522553 fn post_dispatch(2554 pre: Self::Pre,2555 info: &DispatchInfoOf<Self::Call>,2556 post_info: &PostDispatchInfoOf<Self::Call>,2557 len: usize,2558 _result: &DispatchResult,2559 ) -> Result<(), TransactionValidityError> {2560 let (tip, who, imbalance, fee) = pre;2561 if let Some(payed) = imbalance {2562 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2563 len as u32, info, post_info, tip,2564 );2565 let refund = fee.saturating_sub(actual_fee);2566 let actual_payment =2567 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2568 &who, refund,2569 ) {2570 Ok(refund_imbalance) => {2571 2572 2573 match payed.offset(refund_imbalance) {2574 Ok(actual_payment) => actual_payment,2575 Err(_) => return Err(InvalidTransaction::Payment.into()),2576 }2577 }2578 2579 2580 Err(_) => payed,2581 };2582 let imbalances = actual_payment.split(tip);2583 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2584 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2585 );2586 }2587 Ok(())2588 }2589}25902591