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}237238#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]239#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]240pub struct CreateNftData {241 pub const_data: Vec<u8>,242 pub variable_data: Vec<u8>,243}244245#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]246#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]247pub struct CreateFungibleData {248 pub value: u128,249}250251#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]252#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]253pub struct CreateReFungibleData {254 pub const_data: Vec<u8>,255 pub variable_data: Vec<u8>,256}257258#[derive(Encode, Decode, Debug, Clone, PartialEq)]259#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]260pub enum CreateItemData {261 NFT(CreateNftData),262 Fungible(CreateFungibleData),263 ReFungible(CreateReFungibleData),264}265266impl CreateItemData {267 pub fn len(&self) -> usize {268 let len = match self {269 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),270 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),271 _ => 0272 };273 274 return len;275 }276}277278impl From<CreateNftData> for CreateItemData {279 fn from(item: CreateNftData) -> Self {280 CreateItemData::NFT(item)281 }282}283284impl From<CreateReFungibleData> for CreateItemData {285 fn from(item: CreateReFungibleData) -> Self {286 CreateItemData::ReFungible(item)287 }288}289290impl From<CreateFungibleData> for CreateItemData {291 fn from(item: CreateFungibleData) -> Self {292 CreateItemData::Fungible(item)293 }294}295296297decl_error! {298 299 pub enum Error for Module<T: Trait> {300 301 TotalCollectionsLimitExceeded,302 303 CollectionDecimalPointLimitExceeded, 304 305 CollectionNameLimitExceeded, 306 307 CollectionDescriptionLimitExceeded, 308 309 CollectionTokenPrefixLimitExceeded,310 311 CollectionNotFound,312 313 TokenNotFound,314 315 NumOverflow, 316 317 AlreadyAdmin, 318 319 NoPermission,320 321 ConfirmUnsetSponsorFail,322 323 PublicMintingNotAllowed,324 325 MustBeTokenOwner,326 327 TokenValueTooLow,328 329 NftSizeLimitExceeded,330 331 ApproveNotFound,332 333 TokenValueNotEnough,334 335 ApproveRequired,336 337 AddresNotInWhiteList,338 339 CollectionAdminsLimitExceeded,340 341 AddressOwnershipLimitExceeded,342 343 EmptyArgument,344 345 TokenConstDataLimitExceeded,346 347 TokenVariableDataLimitExceeded,348 349 NotNftDataUsedToMintNftCollectionToken,350 351 NotFungibleDataUsedToMintFungibleCollectionToken,352 353 NotReFungibleDataUsedToMintReFungibleCollectionToken,354 355 UnexpectedCollectionType,356 357 CantStoreMetadataInFungibleTokens,358 359 CollectionTokenLimitExceeded,360 361 AccountTokenLimitExceeded,362 363 CollectionLimitBoundsExceeded364 }365}366367pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {368 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;369370 371 type WeightInfo: WeightInfo;372}373374#[cfg(feature = "runtime-benchmarks")]375mod benchmarking;376377378379decl_storage! {380 trait Store for Module<T: Trait> as Nft {381382 383 NextCollectionID: CollectionId;384 CreatedCollectionCount: u32;385 ChainVersion: u64;386 ItemListIndex: map hasher(identity) CollectionId => TokenId;387388 389 pub ChainLimit get(fn chain_limit) config(): ChainLimits;390391 392 CollectionCount: u32;393 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;394395 396 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;397 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;398 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;399400 401 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;402403 404 pub Allowances get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId, T::AccountId) => u128;405406 407 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;408 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => FungibleItemType;409 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;410411 412 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;413414 415 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;416 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;417 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;418419 420 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;421 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;422 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;423 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;424 }425 add_extra_genesis {426 build(|config: &GenesisConfig<T>| {427 428 for (_num, _c) in &config.collection {429 <Module<T>>::init_collection(_c);430 }431432 for (_num, _c, _i) in &config.nft_item_id {433 <Module<T>>::init_nft_token(*_c, _i);434 }435436 for (collection_id, account_id, fungible_item) in &config.fungible_item_id {437 <Module<T>>::init_fungible_token(*collection_id, account_id, fungible_item);438 }439440 for (_num, _c, _i) in &config.refungible_item_id {441 <Module<T>>::init_refungible_token(*_c, _i);442 }443 })444 }445}446447decl_event!(448 pub enum Event<T>449 where450 AccountId = <T as system::Trait>::AccountId,451 {452 453 454 455 456 457 458 459 460 461 Created(CollectionId, u8, AccountId),462463 464 465 466 467 468 469 470 ItemCreated(CollectionId, TokenId),471472 473 474 475 476 477 478 479 ItemDestroyed(CollectionId, TokenId),480 }481);482483decl_module! {484 pub struct Module<T: Trait> for enum Call where origin: T::Origin {485486 fn deposit_event() = default;487 type Error = Error<T>;488489 fn on_initialize(now: T::BlockNumber) -> Weight {490491 if ChainVersion::get() < 2492 {493 let value = NextCollectionID::get();494 CreatedCollectionCount::put(value);495 ChainVersion::put(2);496 }497498 0499 }500501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 #[weight = T::WeightInfo::create_collection()]518 pub fn create_collection(origin,519 collection_name: Vec<u16>,520 collection_description: Vec<u16>,521 token_prefix: Vec<u8>,522 mode: CollectionMode) -> DispatchResult {523524 525 let who = ensure_signed(origin)?;526527 let decimal_points = match mode {528 CollectionMode::Fungible(points) => points,529 CollectionMode::ReFungible(points) => points,530 _ => 0531 };532533 534 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);535536 537 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);538539 let mut name = collection_name.to_vec();540 name.push(0);541 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);542543 let mut description = collection_description.to_vec();544 description.push(0);545 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);546547 let mut prefix = token_prefix.to_vec();548 prefix.push(0);549 ensure!(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: name,568 mode: mode.clone(),569 mint_mode: false,570 access: AccessMode::Normal,571 description: description,572 decimal_points: decimal_points,573 token_prefix: 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(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 let mut white_list_collection: Vec<T::AccountId>;655 if <WhiteList<T>>::contains_key(collection_id) {656 white_list_collection = <WhiteList<T>>::get(collection_id);657 if !white_list_collection.contains(&address.clone())658 {659 white_list_collection.push(address.clone());660 }661 }662 else {663 white_list_collection = Vec::new();664 white_list_collection.push(address.clone());665 }666667 <WhiteList<T>>::insert(collection_id, white_list_collection);668 Ok(())669 }670671 672 673 674 675 676 677 678 679 680 681 682 683 #[weight = T::WeightInfo::remove_from_white_list()]684 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{685686 let sender = ensure_signed(origin)?;687 Self::check_owner_or_admin_permissions(collection_id, sender)?;688689 if <WhiteList<T>>::contains_key(collection_id) {690 let mut white_list_collection = <WhiteList<T>>::get(collection_id);691 if white_list_collection.contains(&address.clone())692 {693 white_list_collection.retain(|i| *i != address.clone());694 <WhiteList<T>>::insert(collection_id, white_list_collection);695 }696 }697698 Ok(())699 }700701 702 703 704 705 706 707 708 709 710 711 712 #[weight = T::WeightInfo::set_public_access_mode()]713 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult714 {715 let sender = ensure_signed(origin)?;716717 Self::check_owner_permissions(collection_id, sender)?;718 let mut target_collection = <Collection<T>>::get(collection_id);719 target_collection.access = mode;720 <Collection<T>>::insert(collection_id, target_collection);721722 Ok(())723 }724725 726 727 728 729 730 731 732 733 734 735 736 737 738 #[weight = T::WeightInfo::set_mint_permission()]739 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult740 {741 let sender = ensure_signed(origin)?;742743 Self::check_owner_permissions(collection_id, sender)?;744 let mut target_collection = <Collection<T>>::get(collection_id);745 target_collection.mint_mode = mint_permission;746 <Collection<T>>::insert(collection_id, target_collection);747748 Ok(())749 }750751 752 753 754 755 756 757 758 759 760 761 762 #[weight = T::WeightInfo::change_collection_owner()]763 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {764765 let sender = ensure_signed(origin)?;766 Self::check_owner_permissions(collection_id, sender)?;767 let mut target_collection = <Collection<T>>::get(collection_id);768 target_collection.owner = new_owner;769 <Collection<T>>::insert(collection_id, target_collection);770771 Ok(())772 }773774 775 776 777 778 779 780 781 782 783 784 785 786 787 #[weight = T::WeightInfo::add_collection_admin()]788 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {789790 let sender = ensure_signed(origin)?;791 Self::check_owner_or_admin_permissions(collection_id, sender)?;792 let mut admin_arr: Vec<T::AccountId> = Vec::new();793794 if <AdminList<T>>::contains_key(collection_id)795 {796 admin_arr = <AdminList<T>>::get(collection_id);797 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);798 }799800 801 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);802803 admin_arr.push(new_admin_id);804 <AdminList<T>>::insert(collection_id, admin_arr);805806 Ok(())807 }808809 810 811 812 813 814 815 816 817 818 819 820 821 #[weight = T::WeightInfo::remove_collection_admin()]822 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {823824 let sender = ensure_signed(origin)?;825 Self::check_owner_or_admin_permissions(collection_id, sender)?;826827 if <AdminList<T>>::contains_key(collection_id)828 {829 let mut admin_arr = <AdminList<T>>::get(collection_id);830 admin_arr.retain(|i| *i != account_id);831 <AdminList<T>>::insert(collection_id, admin_arr);832 }833834 Ok(())835 }836837 838 839 840 841 842 843 844 845 846 #[weight = T::WeightInfo::set_collection_sponsor()]847 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {848849 let sender = ensure_signed(origin)?;850 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);851852 let mut target_collection = <Collection<T>>::get(collection_id);853 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);854855 target_collection.sponsor = new_sponsor;856 target_collection.sponsor_confirmed = false;857 <Collection<T>>::insert(collection_id, target_collection);858859 Ok(())860 }861862 863 864 865 866 867 868 869 #[weight = T::WeightInfo::confirm_sponsorship()]870 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {871872 let sender = ensure_signed(origin)?;873 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);874875 let mut target_collection = <Collection<T>>::get(collection_id);876 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);877878 target_collection.sponsor_confirmed = true;879 <Collection<T>>::insert(collection_id, target_collection);880881 Ok(())882 }883884 885 886 887 888 889 890 891 892 893 #[weight = T::WeightInfo::remove_collection_sponsor()]894 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {895896 let sender = ensure_signed(origin)?;897 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);898899 let mut target_collection = <Collection<T>>::get(collection_id);900 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);901902 target_collection.sponsor = T::AccountId::default();903 target_collection.sponsor_confirmed = false;904 <Collection<T>>::insert(collection_id, target_collection);905906 Ok(())907 }908909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932933 #[weight = T::WeightInfo::create_item(data.len())]934 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {935936 let sender = ensure_signed(origin)?;937938 Self::collection_exists(collection_id)?;939940 let target_collection = <Collection<T>>::get(collection_id);941942 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;943 Self::validate_create_item_args(&target_collection, &data)?;944 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;945946 Ok(())947 }948949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 #[weight = T::WeightInfo::create_item(items_data.into_iter()968 .map(|data| { data.len() })969 .sum())]970 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {971972 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);973 let sender = ensure_signed(origin)?;974975 Self::collection_exists(collection_id)?;976 let target_collection = <Collection<T>>::get(collection_id);977978 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;979980 for data in &items_data {981 Self::validate_create_item_args(&target_collection, data)?;982 }983 for data in &items_data {984 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;985 }986987 Ok(())988 }989990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 #[weight = T::WeightInfo::burn_item()]1004 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10051006 let sender = ensure_signed(origin)?;1007 Self::collection_exists(collection_id)?;10081009 1010 let target_collection = <Collection<T>>::get(collection_id);1011 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1012 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1013 Error::<T>::NoPermission);10141015 if target_collection.access == AccessMode::WhiteList {1016 Self::check_white_list(collection_id, &sender)?;1017 }10181019 match target_collection.mode1020 {1021 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1022 CollectionMode::Fungible(_) => Self::burn_fungible_item(&sender, collection_id, value)?,1023 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1024 _ => ()1025 };10261027 1028 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10291030 Ok(())1031 }10321033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 #[weight = T::WeightInfo::transfer()]1057 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10581059 let sender = ensure_signed(origin)?;1060 let target_collection = <Collection<T>>::get(collection_id);10611062 1063 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10641065 1066 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1067 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1068 Error::<T>::NoPermission);10691070 if target_collection.access == AccessMode::WhiteList {1071 Self::check_white_list(collection_id, &sender)?;1072 Self::check_white_list(collection_id, &recipient)?;1073 }10741075 match target_collection.mode1076 {1077 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1078 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &sender, &recipient)?,1079 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1080 _ => ()1081 };10821083 Ok(())1084 }10851086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 #[weight = T::WeightInfo::approve()]1102 pub fn approve(origin, spender: T::AccountId, collection_id: CollectionId, item_id: TokenId, amount: u128) -> DispatchResult {11031104 let sender = ensure_signed(origin)?;11051106 1107 let target_collection = <Collection<T>>::get(collection_id);1108 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1109 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1110 Error::<T>::NoPermission);11111112 if target_collection.access == AccessMode::WhiteList {1113 Self::check_white_list(collection_id, &sender)?;1114 Self::check_white_list(collection_id, &spender)?;1115 }11161117 let allowance_exists = <Allowances<T>>::contains_key(collection_id, (item_id, &sender, &spender));1118 let mut allowance: u128 = amount;1119 if allowance_exists {1120 allowance += <Allowances<T>>::get(collection_id, (item_id, &sender, &spender));1121 }1122 <Allowances<T>>::insert(collection_id, (item_id, sender.clone(), spender.clone()), allowance);11231124 Ok(())1125 }1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 #[weight = T::WeightInfo::transfer_from()]1147 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11481149 let sender = ensure_signed(origin)?;1150 let mut appoved_transfer = false;11511152 1153 let mut approval: u128 = 0;1154 if <Allowances<T>>::contains_key(collection_id, (item_id, &from, &recipient)) {1155 approval = <Allowances<T>>::get(collection_id, (item_id, &from, &recipient));1156 ensure!(approval >= value, Error::<T>::TokenValueNotEnough);1157 appoved_transfer = true;1158 }11591160 let target_collection = <Collection<T>>::get(collection_id);11611162 1163 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11641165 1166 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1167 Error::<T>::NoPermission);11681169 if target_collection.access == AccessMode::WhiteList {1170 Self::check_white_list(collection_id, &sender)?;1171 Self::check_white_list(collection_id, &recipient)?;1172 }11731174 1175 if approval - value > 0 {1176 <Allowances<T>>::insert(collection_id, (item_id, &from, &recipient), approval - value);1177 }1178 else {1179 <Allowances<T>>::remove(collection_id, (item_id, &from, &recipient));1180 }11811182 match target_collection.mode1183 {1184 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1185 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, value, &from, &recipient)?,1186 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1187 _ => ()1188 };11891190 Ok(())1191 }11921193 #[weight = 0]1194 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11951196 1197 1198 1199 12001201 12021203 12041205 Ok(())1206 }12071208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 #[weight = T::WeightInfo::set_variable_meta_data()]1221 pub fn set_variable_meta_data (1222 origin,1223 collection_id: CollectionId,1224 item_id: TokenId,1225 data: Vec<u8>1226 ) -> DispatchResult {1227 let sender = ensure_signed(origin)?;1228 1229 Self::collection_exists(collection_id)?;1230 1231 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12321233 1234 let target_collection = <Collection<T>>::get(collection_id);1235 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1236 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1237 Error::<T>::NoPermission);12381239 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12401241 match target_collection.mode1242 {1243 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1244 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1245 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1246 _ => fail!(Error::<T>::UnexpectedCollectionType)1247 };12481249 Ok(())1250 }1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 #[weight = 0]1267 pub fn set_schema_version(1268 origin,1269 collection_id: CollectionId,1270 version: SchemaVersion1271 ) -> DispatchResult {1272 let sender = ensure_signed(origin)?;1273 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1274 let mut target_collection = <Collection<T>>::get(collection_id);1275 target_collection.schema_version = version;1276 <Collection<T>>::insert(collection_id, target_collection);12771278 Ok(())1279 }12801281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 #[weight = T::WeightInfo::set_offchain_schema()]1294 pub fn set_offchain_schema(1295 origin,1296 collection_id: CollectionId,1297 schema: Vec<u8>1298 ) -> DispatchResult {1299 let sender = ensure_signed(origin)?;1300 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13011302 let mut target_collection = <Collection<T>>::get(collection_id);1303 target_collection.offchain_schema = schema;1304 <Collection<T>>::insert(collection_id, target_collection);13051306 Ok(())1307 }13081309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 #[weight = T::WeightInfo::set_const_on_chain_schema()]1322 pub fn set_const_on_chain_schema (1323 origin,1324 collection_id: CollectionId,1325 schema: Vec<u8>1326 ) -> DispatchResult {1327 let sender = ensure_signed(origin)?;1328 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13291330 let mut target_collection = <Collection<T>>::get(collection_id);1331 target_collection.const_on_chain_schema = schema;1332 <Collection<T>>::insert(collection_id, target_collection);13331334 Ok(())1335 }13361337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 #[weight = T::WeightInfo::set_const_on_chain_schema()]1350 pub fn set_variable_on_chain_schema (1351 origin,1352 collection_id: CollectionId,1353 schema: Vec<u8>1354 ) -> DispatchResult {1355 let sender = ensure_signed(origin)?;1356 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13571358 let mut target_collection = <Collection<T>>::get(collection_id);1359 target_collection.variable_on_chain_schema = schema;1360 <Collection<T>>::insert(collection_id, target_collection);13611362 Ok(())1363 }13641365 1366 #[weight = 0]1367 pub fn set_chain_limits(1368 origin,1369 limits: ChainLimits1370 ) -> DispatchResult {1371 ensure_root(origin)?;1372 <ChainLimit>::put(limits);1373 Ok(())1374 }13751376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 #[weight = T::WeightInfo::enable_contract_sponsoring()]1388 pub fn enable_contract_sponsoring(1389 origin,1390 contract_address: T::AccountId,1391 enable: bool1392 ) -> DispatchResult {13931394 let sender = ensure_signed(origin)?;13951396 #[cfg(feature = "runtime-benchmarks")]1397 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13981399 let mut is_owner = false;1400 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1401 let owner = <ContractOwner<T>>::get(&contract_address);1402 is_owner = sender == owner;1403 }1404 ensure!(is_owner, Error::<T>::NoPermission);14051406 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1407 Ok(())1408 }14091410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 #[weight = 0]1428 pub fn set_contract_sponsoring_rate_limit(1429 origin,1430 contract_address: T::AccountId,1431 rate_limit: T::BlockNumber1432 ) -> DispatchResult {1433 let sender = ensure_signed(origin)?;1434 let mut is_owner = false;1435 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1436 let owner = <ContractOwner<T>>::get(&contract_address);1437 is_owner = sender == owner;1438 }1439 ensure!(is_owner, Error::<T>::NoPermission);14401441 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1442 Ok(())1443 }14441445 #[weight = 0]1446 pub fn set_collection_limits(1447 origin,1448 collection_id: u32,1449 limits: CollectionLimits,1450 ) -> DispatchResult {1451 let sender = ensure_signed(origin)?;1452 Self::check_owner_permissions(collection_id, sender.clone())?;1453 let mut target_collection = <Collection<T>>::get(collection_id);1454 let chain_limits = ChainLimit::get();1455 let climits = target_collection.limits;14561457 1458 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1459 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1460 Error::<T>::CollectionLimitBoundsExceeded);14611462 1463 ensure!(climits.token_limit > limits.token_limit && 1464 limits.token_limit <= chain_limits.account_token_ownership_limit, 1465 Error::<T>::AccountTokenLimitExceeded);14661467 target_collection.limits = limits;1468 <Collection<T>>::insert(collection_id, target_collection);14691470 Ok(())1471 } 1472 }1473}14741475impl<T: Trait> Module<T> {14761477 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {14781479 1480 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1481 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1482 1483 Ok(())1484 }14851486 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14871488 1489 let total_items: u32 = ItemListIndex::get(collection_id);1490 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1491 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1492 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);14931494 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1495 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1496 Self::check_white_list(collection_id, owner)?;1497 Self::check_white_list(collection_id, sender)?;1498 }14991500 Ok(())1501 }15021503 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1504 match target_collection.mode1505 {1506 CollectionMode::NFT => {1507 if let CreateItemData::NFT(data) = data {1508 1509 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1510 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1511 } else {1512 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1513 }1514 },1515 CollectionMode::Fungible(_) => {1516 if let CreateItemData::Fungible(_) = data {1517 } else {1518 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1519 }1520 },1521 CollectionMode::ReFungible(_) => {1522 if let CreateItemData::ReFungible(data) = data {15231524 1525 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1526 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1527 } else {1528 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1529 }1530 },1531 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1532 };15331534 Ok(())1535 }15361537 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1538 match data1539 {1540 CreateItemData::NFT(data) => {1541 let item = NftItemType {1542 owner,1543 const_data: data.const_data,1544 variable_data: data.variable_data1545 };15461547 Self::add_nft_item(collection_id, item)?;1548 },1549 CreateItemData::Fungible(data) => {1550 Self::add_fungible_item(collection_id, &owner, data.value)?;1551 },1552 CreateItemData::ReFungible(data) => {1553 let mut owner_list = Vec::new();1554 let value = (10 as u128).pow(collection.decimal_points as u32);1555 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15561557 let item = ReFungibleItemType {1558 owner: owner_list,1559 const_data: data.const_data,1560 variable_data: data.variable_data1561 };15621563 Self::add_refungible_item(collection_id, item)?;1564 }1565 };15661567 1568 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));15691570 Ok(())1571 }15721573 fn add_fungible_item(collection_id: CollectionId, owner: &T::AccountId, value: u128) -> DispatchResult {15741575 1576 let mut balance: u128 = 0;1577 if <FungibleItemList<T>>::contains_key(collection_id, owner) {1578 balance = <FungibleItemList<T>>::get(collection_id, owner).value;1579 } 15801581 1582 let item = FungibleItemType {1583 value: balance + value1584 };1585 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), item);15861587 1588 let new_balance = <Balance<T>>::get(collection_id, owner)1589 .checked_add(value)1590 .ok_or(Error::<T>::NumOverflow)?;1591 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);15921593 Ok(())1594 }15951596 fn add_refungible_item(collection_id: CollectionId, item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1597 let current_index = <ItemListIndex>::get(collection_id)1598 .checked_add(1)1599 .ok_or(Error::<T>::NumOverflow)?;1600 let itemcopy = item.clone();16011602 let value = item.owner.first().unwrap().fraction;1603 let owner = item.owner.first().unwrap().owner.clone();16041605 Self::add_token_index(collection_id, current_index, owner.clone())?;16061607 <ItemListIndex>::insert(collection_id, current_index);1608 <ReFungibleItemList<T>>::insert(collection_id, current_index, itemcopy);16091610 1611 let new_balance = <Balance<T>>::get(collection_id, owner.clone())1612 .checked_add(value)1613 .ok_or(Error::<T>::NumOverflow)?;1614 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);16151616 Ok(())1617 }16181619 fn add_nft_item(collection_id: CollectionId, item: NftItemType<T::AccountId>) -> DispatchResult {1620 let current_index = <ItemListIndex>::get(collection_id)1621 .checked_add(1)1622 .ok_or(Error::<T>::NumOverflow)?;16231624 let item_owner = item.owner.clone();1625 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16261627 <ItemListIndex>::insert(collection_id, current_index);1628 <NftItemList<T>>::insert(collection_id, current_index, item);16291630 1631 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1632 .checked_add(1)1633 .ok_or(Error::<T>::NumOverflow)?;1634 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16351636 Ok(())1637 }16381639 fn burn_refungible_item(1640 collection_id: CollectionId,1641 item_id: TokenId,1642 owner: T::AccountId,1643 ) -> DispatchResult {1644 ensure!(1645 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1646 Error::<T>::TokenNotFound1647 );1648 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1649 let item = collection1650 .owner1651 .iter()1652 .filter(|&i| i.owner == owner)1653 .next()1654 .unwrap();1655 Self::remove_token_index(collection_id, item_id, owner.clone())?;16561657 1658 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1659 .checked_sub(item.fraction)1660 .ok_or(Error::<T>::NumOverflow)?;1661 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16621663 <ReFungibleItemList<T>>::remove(collection_id, item_id);16641665 Ok(())1666 }16671668 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1669 ensure!(1670 <NftItemList<T>>::contains_key(collection_id, item_id),1671 Error::<T>::TokenNotFound1672 );1673 let item = <NftItemList<T>>::get(collection_id, item_id);1674 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16751676 1677 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1678 .checked_sub(1)1679 .ok_or(Error::<T>::NumOverflow)?;1680 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1681 <NftItemList<T>>::remove(collection_id, item_id);16821683 Ok(())1684 }16851686 fn burn_fungible_item(owner: &T::AccountId, collection_id: CollectionId, value: u128) -> DispatchResult {1687 ensure!(1688 <FungibleItemList<T>>::contains_key(collection_id, owner),1689 Error::<T>::TokenNotFound1690 );1691 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1692 ensure!(balance.value >= value, Error::<T>::TokenValueNotEnough);16931694 1695 let new_balance = <Balance<T>>::get(collection_id, owner)1696 .checked_sub(value)1697 .ok_or(Error::<T>::NumOverflow)?;1698 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);16991700 if balance.value - value > 0 {1701 balance.value -= value;1702 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1703 }1704 else {1705 <FungibleItemList<T>>::remove(collection_id, owner);1706 }17071708 Ok(())1709 }17101711 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1712 ensure!(1713 <Collection<T>>::contains_key(collection_id),1714 Error::<T>::CollectionNotFound1715 );1716 Ok(())1717 }17181719 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1720 Self::collection_exists(collection_id)?;17211722 let target_collection = <Collection<T>>::get(collection_id);1723 ensure!(1724 subject == target_collection.owner,1725 Error::<T>::NoPermission1726 );17271728 Ok(())1729 }17301731 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1732 let target_collection = <Collection<T>>::get(collection_id);1733 let mut result: bool = subject == target_collection.owner;1734 let exists = <AdminList<T>>::contains_key(collection_id);17351736 if !result & exists {1737 if <AdminList<T>>::get(collection_id).contains(&subject) {1738 result = true1739 }1740 }17411742 result1743 }17441745 fn check_owner_or_admin_permissions(1746 collection_id: CollectionId,1747 subject: T::AccountId,1748 ) -> DispatchResult {1749 Self::collection_exists(collection_id)?;1750 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17511752 ensure!(1753 result,1754 Error::<T>::NoPermission1755 );1756 Ok(())1757 }17581759 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1760 let target_collection = <Collection<T>>::get(collection_id);17611762 match target_collection.mode {1763 CollectionMode::NFT => {1764 <NftItemList<T>>::get(collection_id, item_id).owner == subject1765 }1766 CollectionMode::Fungible(_) => {1767 <FungibleItemList<T>>::contains_key(collection_id, &subject)1768 }1769 CollectionMode::ReFungible(_) => {1770 <ReFungibleItemList<T>>::get(collection_id, item_id)1771 .owner1772 .iter()1773 .any(|i| i.owner == subject)1774 }1775 CollectionMode::Invalid => false,1776 }1777 }17781779 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1780 let mes = Error::<T>::AddresNotInWhiteList;1781 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1782 let wl = <WhiteList<T>>::get(collection_id);1783 ensure!(wl.contains(address), mes);17841785 Ok(())1786 }17871788 fn transfer_fungible(1789 collection_id: CollectionId,1790 value: u128,1791 owner: &T::AccountId,1792 recipient: &T::AccountId,1793 ) -> DispatchResult {1794 ensure!(1795 <FungibleItemList<T>>::contains_key(collection_id, owner),1796 Error::<T>::TokenNotFound1797 );17981799 let mut balance = <FungibleItemList<T>>::get(collection_id, owner);1800 ensure!(balance.value >= value, Error::<T>::TokenValueTooLow);18011802 1803 Self::add_fungible_item(collection_id, recipient, value)?;18041805 1806 <Balance<T>>::insert(collection_id, (*owner).clone(), balance.value - value);18071808 1809 if balance.value == value {1810 <FungibleItemList<T>>::remove(collection_id, owner);1811 }1812 else {1813 balance.value -= value;1814 <FungibleItemList<T>>::insert(collection_id, (*owner).clone(), balance);1815 }18161817 Ok(())1818 }18191820 fn transfer_refungible(1821 collection_id: CollectionId,1822 item_id: TokenId,1823 value: u128,1824 owner: T::AccountId,1825 new_owner: T::AccountId,1826 ) -> DispatchResult {1827 ensure!(1828 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1829 Error::<T>::TokenNotFound1830 );18311832 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1833 let item = full_item1834 .owner1835 .iter()1836 .filter(|i| i.owner == owner)1837 .next()1838 .ok_or(Error::<T>::NumOverflow)?;1839 let amount = item.fraction;18401841 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18421843 1844 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1845 .checked_sub(value)1846 .ok_or(Error::<T>::NumOverflow)?;1847 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);18481849 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1850 .checked_add(value)1851 .ok_or(Error::<T>::NumOverflow)?;1852 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);18531854 let old_owner = item.owner.clone();1855 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);18561857 1858 if amount == value && !new_owner_has_account {1859 1860 1861 let mut new_full_item = full_item.clone();1862 new_full_item1863 .owner1864 .iter_mut()1865 .find(|i| i.owner == owner)1866 .unwrap()1867 .owner = new_owner.clone();1868 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18691870 1871 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1872 } else {1873 let mut new_full_item = full_item.clone();1874 new_full_item1875 .owner1876 .iter_mut()1877 .find(|i| i.owner == owner)1878 .unwrap()1879 .fraction -= value;18801881 1882 if new_owner_has_account {1883 1884 new_full_item1885 .owner1886 .iter_mut()1887 .find(|i| i.owner == new_owner)1888 .unwrap()1889 .fraction += value;1890 } else {1891 1892 new_full_item.owner.push(Ownership {1893 owner: new_owner.clone(),1894 fraction: value,1895 });1896 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1897 }18981899 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1900 }19011902 Ok(())1903 }19041905 fn transfer_nft(1906 collection_id: CollectionId,1907 item_id: TokenId,1908 sender: T::AccountId,1909 new_owner: T::AccountId,1910 ) -> DispatchResult {1911 ensure!(1912 <NftItemList<T>>::contains_key(collection_id, item_id),1913 Error::<T>::TokenNotFound1914 );19151916 let mut item = <NftItemList<T>>::get(collection_id, item_id);19171918 ensure!(1919 sender == item.owner,1920 Error::<T>::MustBeTokenOwner1921 );19221923 1924 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1925 .checked_sub(1)1926 .ok_or(Error::<T>::NumOverflow)?;1927 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19281929 let balancenew_owner = <Balance<T>>::get(collection_id, new_owner.clone())1930 .checked_add(1)1931 .ok_or(Error::<T>::NumOverflow)?;1932 <Balance<T>>::insert(collection_id, new_owner.clone(), balancenew_owner);19331934 1935 let old_owner = item.owner.clone();1936 item.owner = new_owner.clone();1937 <NftItemList<T>>::insert(collection_id, item_id, item);19381939 1940 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19411942 Ok(())1943 }1944 1945 fn item_exists(1946 collection_id: CollectionId,1947 item_id: TokenId,1948 mode: &CollectionMode1949 ) -> DispatchResult {1950 match mode {1951 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1952 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1953 _ => ()1954 };1955 1956 Ok(())1957 }19581959 fn set_re_fungible_variable_data(1960 collection_id: CollectionId,1961 item_id: TokenId,1962 data: Vec<u8>1963 ) -> DispatchResult {1964 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);19651966 item.variable_data = data;19671968 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);19691970 Ok(())1971 }19721973 fn set_nft_variable_data(1974 collection_id: CollectionId,1975 item_id: TokenId,1976 data: Vec<u8>1977 ) -> DispatchResult {1978 let mut item = <NftItemList<T>>::get(collection_id, item_id);1979 1980 item.variable_data = data;19811982 <NftItemList<T>>::insert(collection_id, item_id, item);1983 1984 Ok(())1985 }19861987 fn init_collection(item: &CollectionType<T::AccountId>) {1988 1989 assert!(1990 item.decimal_points <= MAX_DECIMAL_POINTS,1991 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"1992 );1993 assert!(1994 item.name.len() <= 64,1995 "Collection name can not be longer than 63 char"1996 );1997 assert!(1998 item.name.len() <= 256,1999 "Collection description can not be longer than 255 char"2000 );2001 assert!(2002 item.token_prefix.len() <= 16,2003 "Token prefix can not be longer than 15 char"2004 );20052006 2007 let next_id = CreatedCollectionCount::get()2008 .checked_add(1)2009 .unwrap();20102011 CreatedCollectionCount::put(next_id);2012 }20132014 fn init_nft_token(collection_id: CollectionId, item: &NftItemType<T::AccountId>) {2015 let current_index = <ItemListIndex>::get(collection_id)2016 .checked_add(1)2017 .unwrap();20182019 let item_owner = item.owner.clone();2020 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20212022 <ItemListIndex>::insert(collection_id, current_index);20232024 2025 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2026 .checked_add(1)2027 .unwrap();2028 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2029 }20302031 fn init_fungible_token(collection_id: CollectionId, owner: &T::AccountId, item: &FungibleItemType) {2032 let current_index = <ItemListIndex>::get(collection_id)2033 .checked_add(1)2034 .unwrap();20352036 Self::add_token_index(collection_id, current_index, (*owner).clone()).unwrap();20372038 <ItemListIndex>::insert(collection_id, current_index);20392040 2041 let new_balance = <Balance<T>>::get(collection_id, owner)2042 .checked_add(item.value)2043 .unwrap();2044 <Balance<T>>::insert(collection_id, (*owner).clone(), new_balance);2045 }20462047 fn init_refungible_token(collection_id: CollectionId, item: &ReFungibleItemType<T::AccountId>) {2048 let current_index = <ItemListIndex>::get(collection_id)2049 .checked_add(1)2050 .unwrap();20512052 let value = item.owner.first().unwrap().fraction;2053 let owner = item.owner.first().unwrap().owner.clone();20542055 Self::add_token_index(collection_id, current_index, owner.clone()).unwrap();20562057 <ItemListIndex>::insert(collection_id, current_index);20582059 2060 let new_balance = <Balance<T>>::get(collection_id, owner.clone())2061 .checked_add(value)2062 .unwrap();2063 <Balance<T>>::insert(collection_id, owner.clone(), new_balance);2064 }20652066 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {20672068 2069 if <AccountItemCount<T>>::contains_key(owner.clone()) {20702071 2072 let count = <AccountItemCount<T>>::get(owner.clone());2073 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);20742075 <AccountItemCount<T>>::insert(owner.clone(), count2076 .checked_add(1)2077 .ok_or(Error::<T>::NumOverflow)?);2078 }2079 else {2080 <AccountItemCount<T>>::insert(owner.clone(), 1);2081 }20822083 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2084 if list_exists {2085 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2086 let item_contains = list.contains(&item_index.clone());20872088 if !item_contains {2089 list.push(item_index.clone());2090 }20912092 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2093 } else {2094 let mut itm = Vec::new();2095 itm.push(item_index.clone());2096 <AddressTokens<T>>::insert(collection_id, owner, itm);2097 2098 }20992100 Ok(())2101 }21022103 fn remove_token_index(2104 collection_id: CollectionId,2105 item_index: TokenId,2106 owner: T::AccountId,2107 ) -> DispatchResult {21082109 2110 <AccountItemCount<T>>::insert(owner.clone(), 2111 <AccountItemCount<T>>::get(owner.clone())2112 .checked_sub(1)2113 .ok_or(Error::<T>::NumOverflow)?);211421152116 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2117 if list_exists {2118 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2119 let item_contains = list.contains(&item_index.clone());21202121 if item_contains {2122 list.retain(|&item| item != item_index);2123 <AddressTokens<T>>::insert(collection_id, owner, list);2124 }2125 }21262127 Ok(())2128 }21292130 fn move_token_index(2131 collection_id: CollectionId,2132 item_index: TokenId,2133 old_owner: T::AccountId,2134 new_owner: T::AccountId,2135 ) -> DispatchResult {2136 Self::remove_token_index(collection_id, item_index, old_owner)?;2137 Self::add_token_index(collection_id, item_index, new_owner)?;21382139 Ok(())2140 }2141}2142214321442145214621472148pub type Multiplier = FixedU128;21492150type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2151 <T as system::Trait>::AccountId,2152>>::Balance;2153type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2154 <T as system::Trait>::AccountId,2155>>::NegativeImbalance;2156215721582159#[derive(Encode, Decode, Clone, Eq, PartialEq)]2160pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2161 #[codec(compact)] BalanceOf<T>2162);21632164impl<T: Trait + Send + Sync> sp_std::fmt::Debug2165 for ChargeTransactionPayment<T>2166{2167 #[cfg(feature = "std")]2168 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2169 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2170 }2171 #[cfg(not(feature = "std"))]2172 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2173 Ok(())2174 }2175}21762177impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2178where2179 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2180 BalanceOf<T>: Send + Sync + FixedPointOperand,2181{2182 2183 pub fn from(fee: BalanceOf<T>) -> Self {2184 Self(fee)2185 }21862187 pub fn traditional_fee(2188 len: usize,2189 info: &DispatchInfoOf<T::Call>,2190 tip: BalanceOf<T>,2191 ) -> BalanceOf<T>2192 where2193 T::Call: Dispatchable<Info = DispatchInfo>,2194 {2195 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2196 }21972198 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2199 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2200 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2201 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2202 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2203 }22042205 fn withdraw_fee(2206 &self,2207 who: &T::AccountId,2208 call: &T::Call,2209 info: &DispatchInfoOf<T::Call>,2210 len: usize,2211 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2212 let tip = self.0;22132214 2215 2216 2217 2218 2219 2220 2221 let fee = Self::traditional_fee(len, info, tip);22222223 2224 if fee.is_zero() {2225 return Ok((fee, None));2226 }22272228 2229 2230 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2231 Some(Call::create_item(collection_id, _owner, _properties)) => {22322233 2234 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2235 (<Collection<T>>::get(collection_id).sponsor_confirmed)2236 {2237 <Collection<T>>::get(collection_id).sponsor2238 } else {2239 T::AccountId::default()2240 }2241 }2242 Some(Call::transfer(_new_owner, collection_id, item_id, _value)) => {2243 2244 let mut sponsor_transfer = false;2245 if <Collection<T>>::get(collection_id).sponsor_confirmed {22462247 let collection_limits = <Collection<T>>::get(collection_id).limits;2248 let collection_mode = <Collection<T>>::get(collection_id).mode;2249 2250 2251 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2252 sponsor_transfer = match collection_mode {2253 CollectionMode::NFT => {2254 2255 2256 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2257 collection_limits.sponsor_transfer_timeout2258 } else {2259 ChainLimit::get().nft_sponsor_transfer_timeout2260 };2261 2262 let mut sponsored = true;2263 if <NftTransferBasket<T>>::contains_key(collection_id, item_id) {2264 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, item_id);2265 let limit_time = last_tx_block + limit.into();2266 if block_number <= limit_time {2267 sponsored = false;2268 }2269 }2270 if sponsored {2271 <NftTransferBasket<T>>::insert(collection_id, item_id, block_number);2272 }22732274 sponsored2275 }2276 CollectionMode::Fungible(_) => {2277 2278 2279 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2280 collection_limits.sponsor_transfer_timeout2281 } else {2282 ChainLimit::get().fungible_sponsor_transfer_timeout2283 };2284 2285 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2286 let mut sponsored = true;2287 if <FungibleTransferBasket<T>>::contains_key(collection_id, who) {2288 let last_tx_block = <FungibleTransferBasket<T>>::get(collection_id, who);2289 let limit_time = last_tx_block + limit.into();2290 if block_number <= limit_time {2291 sponsored = false;2292 }2293 }2294 if sponsored {2295 <FungibleTransferBasket<T>>::insert(collection_id, who, block_number);2296 }22972298 sponsored2299 }2300 CollectionMode::ReFungible(_) => {2301 2302 2303 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {2304 collection_limits.sponsor_transfer_timeout2305 } else {2306 ChainLimit::get().refungible_sponsor_transfer_timeout2307 };2308 2309 let mut sponsored = true;2310 if <ReFungibleTransferBasket<T>>::contains_key(collection_id, item_id) {2311 let last_tx_block = <ReFungibleTransferBasket<T>>::get(collection_id, item_id);2312 let limit_time = last_tx_block + limit.into();2313 if block_number <= limit_time {2314 sponsored = false;2315 }2316 }2317 if sponsored {2318 <ReFungibleTransferBasket<T>>::insert(collection_id, item_id, block_number);2319 }23202321 sponsored2322 }2323 _ => {2324 false2325 },2326 };2327 }23282329 if !sponsor_transfer {2330 T::AccountId::default()2331 } else {2332 <Collection<T>>::get(collection_id).sponsor2333 }2334 }23352336 _ => T::AccountId::default(),2337 };23382339 2340 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23412342 2343 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23442345 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2346 code_hash,2347 &data,2348 &who,2349 );2350 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());23512352 T::AccountId::default()2353 },23542355 2356 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {23572358 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());23592360 let mut sponsor_transfer = false;2361 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2362 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2363 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2364 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2365 let limit_time = last_tx_block + rate_limit;23662367 if block_number >= limit_time {2368 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2369 sponsor_transfer = true;2370 }2371 } else {2372 sponsor_transfer = false;2373 }2374 2375 2376 let mut sp = T::AccountId::default();2377 if sponsor_transfer {2378 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2379 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2380 sp = called_contract;2381 }2382 }2383 }23842385 sp2386 },23872388 _ => sponsor,2389 };23902391 let mut who_pays_fee: T::AccountId = sponsor.clone();2392 if sponsor == T::AccountId::default() {2393 who_pays_fee = who.clone();2394 }23952396 match <T as transaction_payment::Trait>::Currency::withdraw(2397 &who_pays_fee,2398 fee,2399 if tip.is_zero() {2400 WithdrawReason::TransactionPayment.into()2401 } else {2402 WithdrawReason::TransactionPayment | WithdrawReason::Tip2403 },2404 ExistenceRequirement::KeepAlive,2405 ) {2406 Ok(imbalance) => Ok((fee, Some(imbalance))),2407 Err(_) => Err(InvalidTransaction::Payment.into()),2408 }2409 }2410}241124122413impl<T: Trait + Send + Sync> SignedExtension2414 for ChargeTransactionPayment<T>2415where2416 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2417 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2418{2419 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2420 type AccountId = T::AccountId;2421 type Call = T::Call;2422 type AdditionalSigned = ();2423 type Pre = (2424 BalanceOf<T>,2425 Self::AccountId,2426 Option<NegativeImbalanceOf<T>>,2427 BalanceOf<T>,2428 );2429 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2430 Ok(())2431 }24322433 fn validate(2434 &self,2435 who: &Self::AccountId,2436 call: &Self::Call,2437 info: &DispatchInfoOf<Self::Call>,2438 len: usize,2439 ) -> TransactionValidity {2440 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2441 Ok(ValidTransaction {2442 priority: Self::get_priority(len, info, fee),2443 ..Default::default()2444 })2445 }24462447 fn pre_dispatch(2448 self,2449 who: &Self::AccountId,2450 call: &Self::Call,2451 info: &DispatchInfoOf<Self::Call>,2452 len: usize,2453 ) -> Result<Self::Pre, TransactionValidityError> {2454 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2455 Ok((self.0, who.clone(), imbalance, fee))2456 }24572458 fn post_dispatch(2459 pre: Self::Pre,2460 info: &DispatchInfoOf<Self::Call>,2461 post_info: &PostDispatchInfoOf<Self::Call>,2462 len: usize,2463 _result: &DispatchResult,2464 ) -> Result<(), TransactionValidityError> {2465 let (tip, who, imbalance, fee) = pre;2466 if let Some(payed) = imbalance {2467 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2468 len as u32, info, post_info, tip,2469 );2470 let refund = fee.saturating_sub(actual_fee);2471 let actual_payment =2472 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2473 &who, refund,2474 ) {2475 Ok(refund_imbalance) => {2476 2477 2478 match payed.offset(refund_imbalance) {2479 Ok(actual_payment) => actual_payment,2480 Err(_) => return Err(InvalidTransaction::Payment.into()),2481 }2482 }2483 2484 2485 Err(_) => payed,2486 };2487 let imbalances = actual_payment.split(tip);2488 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2489 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2490 );2491 }2492 Ok(())2493 }2494}24952496