1#![cfg_attr(not(feature = "std"), no_std)]23#[cfg(feature = "std")]4pub use std::*;56#[cfg(feature = "std")]7pub use serde::*;89use codec::{Decode, Encode};10pub use frame_support::{11 construct_runtime, decl_event, decl_module, decl_storage, decl_error,12 dispatch::DispatchResult,13 ensure, fail, parameter_types,14 traits::{15 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,16 Randomness, WithdrawReason,17 },18 weights::{19 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},20 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,21 WeightToFeePolynomial,22 },23 IsSubType, StorageValue,24};2526use frame_system::{self as system, ensure_signed, ensure_root};27use sp_runtime::sp_std::prelude::Vec;28use sp_runtime::{29 traits::{30 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SignedExtension, Zero,31 },32 transaction_validity::{33 InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,34 },35 FixedPointOperand, FixedU128,36};37use pallet_contracts::ContractAddressFor;38use sp_runtime::traits::StaticLookup;3940#[cfg(test)]41mod mock;4243#[cfg(test)]44mod tests;4546mod default_weights;4748495051#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]52#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]53pub enum CollectionMode {54 Invalid,55 NFT,56 57 Fungible(u32),58 59 ReFungible(u32),60}6162impl Into<u8> for CollectionMode {63 fn into(self) -> u8 {64 match self {65 CollectionMode::Invalid => 0,66 CollectionMode::NFT => 1,67 CollectionMode::Fungible(_) => 2,68 CollectionMode::ReFungible(_) => 3,69 }70 }71}7273#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]74#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]75pub enum AccessMode {76 Normal,77 WhiteList,78}79impl Default for AccessMode {80 fn default() -> Self {81 Self::Normal82 }83}8485impl Default for CollectionMode {86 fn default() -> Self {87 Self::Invalid88 }89}9091#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]92#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]93pub struct Ownership<AccountId> {94 pub owner: AccountId,95 pub fraction: u128,96}9798#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]99#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]100pub struct CollectionType<AccountId> {101 pub owner: AccountId,102 pub mode: CollectionMode,103 pub access: AccessMode,104 pub decimal_points: u32,105 pub name: Vec<u16>, 106 pub description: Vec<u16>, 107 pub token_prefix: Vec<u8>, 108 pub mint_mode: bool,109 pub offchain_schema: Vec<u8>,110 pub sponsor: AccountId, 111 pub unconfirmed_sponsor: AccountId, 112 pub limits: CollectionLimits, 113 pub variable_on_chain_schema: Vec<u8>, 114 pub const_on_chain_schema: Vec<u8>, 115}116117#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]118#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]119pub struct NftItemType<AccountId> {120 pub collection: u64,121 pub owner: AccountId,122 pub const_data: Vec<u8>,123 pub variable_data: Vec<u8>,124}125126#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]127#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]128pub struct FungibleItemType<AccountId> {129 pub collection: u64,130 pub owner: AccountId,131 pub value: u128,132}133134#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]135#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]136pub struct ReFungibleItemType<AccountId> {137 pub collection: u64,138 pub owner: Vec<Ownership<AccountId>>,139 pub const_data: Vec<u8>,140 pub variable_data: Vec<u8>,141}142143#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]144#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]145pub struct ApprovePermissions<AccountId> {146 pub approved: AccountId,147 pub amount: u64,148}149150#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]151#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]152pub struct VestingItem<AccountId, Moment> {153 pub sender: AccountId,154 pub recipient: AccountId,155 pub collection_id: u64,156 pub item_id: u64,157 pub amount: u64,158 pub vesting_date: Moment,159}160161#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]162#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]163pub struct BasketItem<AccountId, BlockNumber> {164 pub address: AccountId,165 pub start_block: BlockNumber,166}167168#[derive(Encode, Decode, Debug, Clone, PartialEq)]169#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]170pub struct CollectionLimits {171 pub account_token_ownership_limit: u32,172 pub sponsored_data_size: u32,173 pub token_limit: u32,174175 176 pub sponsor_transfer_timeout: u32,177}178179impl Default for CollectionLimits {180 fn default() -> CollectionLimits {181 CollectionLimits { 182 account_token_ownership_limit: 0, 183 token_limit: 0,184 sponsored_data_size: 0, 185 sponsor_transfer_timeout: 0 }186 }187}188189#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]190#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]191pub struct ChainLimits {192 pub collection_numbers_limit: u64,193 pub account_token_ownership_limit: u64,194 pub collections_admins_limit: u64,195 pub custom_data_limit: u32,196197 198 pub nft_sponsor_transfer_timeout: u32,199 pub fungible_sponsor_transfer_timeout: u32,200 pub refungible_sponsor_transfer_timeout: u32,201}202203pub trait WeightInfo {204 fn create_collection() -> Weight;205 fn destroy_collection() -> Weight;206 fn add_to_white_list() -> Weight;207 fn remove_from_white_list() -> Weight;208 fn set_public_access_mode() -> Weight;209 fn set_mint_permission() -> Weight;210 fn change_collection_owner() -> Weight;211 fn add_collection_admin() -> Weight;212 fn remove_collection_admin() -> Weight;213 fn set_collection_sponsor() -> Weight;214 fn confirm_sponsorship() -> Weight;215 fn remove_collection_sponsor() -> Weight;216 fn create_item(s: usize) -> Weight;217 fn burn_item() -> Weight;218 fn transfer() -> Weight;219 fn approve() -> Weight;220 fn transfer_from() -> Weight;221 fn set_offchain_schema() -> Weight;222 fn set_const_on_chain_schema() -> Weight;223 fn set_variable_on_chain_schema() -> Weight;224 fn set_variable_meta_data() -> Weight;225 fn enable_contract_sponsoring() -> Weight;226}227228#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]229#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]230pub struct CreateNftData {231 pub const_data: Vec<u8>,232 pub variable_data: Vec<u8>,233}234235#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]236#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]237pub struct CreateFungibleData {238}239240#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]241#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]242pub struct CreateReFungibleData {243 pub const_data: Vec<u8>,244 pub variable_data: Vec<u8>,245}246247#[derive(Encode, Decode, Debug, Clone, PartialEq)]248#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]249pub enum CreateItemData {250 NFT(CreateNftData),251 Fungible(CreateFungibleData),252 ReFungible(CreateReFungibleData)253}254255impl CreateItemData {256 pub fn len(&self) -> usize {257 let len = match self {258 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),259 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),260 _ => 0261 };262 263 return len;264 }265}266267impl From<CreateNftData> for CreateItemData {268 fn from(item: CreateNftData) -> Self {269 CreateItemData::NFT(item)270 }271}272273impl From<CreateReFungibleData> for CreateItemData {274 fn from(item: CreateReFungibleData) -> Self {275 CreateItemData::ReFungible(item)276 }277}278279impl From<CreateFungibleData> for CreateItemData {280 fn from(item: CreateFungibleData) -> Self {281 CreateItemData::Fungible(item)282 }283}284285286decl_error! {287 288 pub enum Error for Module<T: Trait> {289 290 TotalCollectionsLimitExceeded,291 292 CollectionDecimalPointLimitExceeded, 293 294 CollectionNameLimitExceeded, 295 296 CollectionDescriptionLimitExceeded, 297 298 CollectionTokenPrefixLimitExceeded,299 300 CollectionNotFound,301 302 TokenNotFound,303 304 NumOverflow, 305 306 AlreadyAdmin, 307 308 NoPermission,309 310 ConfirmUnsetSponsorFail,311 312 PublicMintingNotAllowed,313 314 MustBeTokenOwner,315 316 TokenValueTooLow,317 318 NftSizeLimitExceeded,319 320 ApproveNotFound,321 322 TokenValueNotEnough,323 324 ApproveRequired,325 326 AddresNotInWhiteList,327 328 CollectionAdminsLimitExceeded,329 330 AddressOwnershipLimitExceeded,331 332 EmptyArgument,333 334 TokenConstDataLimitExceeded,335 336 TokenVariableDataLimitExceeded,337 338 NotNftDataUsedToMintNftCollectionToken,339 340 NotFungibleDataUsedToMintFungibleCollectionToken,341 342 NotReFungibleDataUsedToMintReFungibleCollectionToken,343 344 UnexpectedCollectionType,345 346 CantStoreMetadataInFungibleTokens,347 348 CollectionTokenLimitExceeded,349 350 AccountTokenLimitExceeded351 }352}353354pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {355 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;356357 358 type WeightInfo: WeightInfo;359}360361#[cfg(feature = "runtime-benchmarks")]362mod benchmarking;363364365366decl_storage! {367 trait Store for Module<T: Trait> as Nft {368369 370 NextCollectionID: u64;371 CreatedCollectionCount: u64;372 ChainVersion: u64;373 ItemListIndex: map hasher(blake2_128_concat) u64 => u64;374375 376 pub ChainLimit get(fn chain_limit) config(): ChainLimits;377378 379 CollectionCount: u64;380 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u64;381382 383 pub Collection get(fn collection) config(): map hasher(identity) u64 => CollectionType<T::AccountId>;384 pub AdminList get(fn admin_list_collection): map hasher(identity) u64 => Vec<T::AccountId>;385 pub WhiteList get(fn white_list): map hasher(identity) u64 => Vec<T::AccountId>;386387 388 pub Balance get(fn balance_count): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => u64;389390 391 pub ApprovedList get(fn approved): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) (u64, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;392393 394 pub NftItemList get(fn nft_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => NftItemType<T::AccountId>;395 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => FungibleItemType<T::AccountId>;396 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => ReFungibleItemType<T::AccountId>;397398 399 pub AddressTokens get(fn address_tokens): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) T::AccountId => Vec<u64>;400401 402 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;403 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => Vec<BasketItem<T::AccountId, T::BlockNumber>>;404 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) u64, hasher(blake2_128_concat) u64 => T::BlockNumber;405406 407 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;408 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;409 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;410 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;411 }412 add_extra_genesis {413 build(|config: &GenesisConfig<T>| {414 415 for (_num, _c) in &config.collection {416 <Module<T>>::init_collection(_c);417 }418419 for (_num, _q, _i) in &config.nft_item_id {420 <Module<T>>::init_nft_token(_i);421 }422423 for (_num, _q, _i) in &config.fungible_item_id {424 <Module<T>>::init_fungible_token(_i);425 }426427 for (_num, _q, _i) in &config.refungible_item_id {428 <Module<T>>::init_refungible_token(_i);429 }430 })431 }432}433434decl_event!(435 pub enum Event<T>436 where437 AccountId = <T as system::Trait>::AccountId,438 {439 440 441 442 443 444 445 446 447 448 Created(u64, u8, AccountId),449450 451 452 453 454 455 456 457 ItemCreated(u64, u64),458459 460 461 462 463 464 465 466 ItemDestroyed(u64, u64),467 }468);469470decl_module! {471 pub struct Module<T: Trait> for enum Call where origin: T::Origin {472473 fn deposit_event() = default;474 type Error = Error<T>;475476 fn on_initialize(now: T::BlockNumber) -> Weight {477478 if ChainVersion::get() < 2479 {480 let value = NextCollectionID::get();481 CreatedCollectionCount::put(value);482 ChainVersion::put(2);483 }484485 0486 }487488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 #[weight = T::WeightInfo::create_collection()]505 pub fn create_collection(origin,506 collection_name: Vec<u16>,507 collection_description: Vec<u16>,508 token_prefix: Vec<u8>,509 mode: CollectionMode) -> DispatchResult {510511 512 let who = ensure_signed(origin)?;513514 let decimal_points = match mode {515 CollectionMode::Fungible(points) => points,516 CollectionMode::ReFungible(points) => points,517 _ => 0518 };519520 521 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);522523 524 ensure!(decimal_points <= 4, Error::<T>::CollectionDecimalPointLimitExceeded);525526 let mut name = collection_name.to_vec();527 name.push(0);528 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);529530 let mut description = collection_description.to_vec();531 description.push(0);532 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);533534 let mut prefix = token_prefix.to_vec();535 prefix.push(0);536 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);537538 539 let next_id = CreatedCollectionCount::get()540 .checked_add(1)541 .ok_or(Error::<T>::NumOverflow)?;542543 544 let total = CollectionCount::get()545 .checked_add(1)546 .ok_or(Error::<T>::NumOverflow)?;547548 CreatedCollectionCount::put(next_id);549 CollectionCount::put(total);550551 552 let new_collection = CollectionType {553 owner: who.clone(),554 name: name,555 mode: mode.clone(),556 mint_mode: false,557 access: AccessMode::Normal,558 description: description,559 decimal_points: decimal_points,560 token_prefix: prefix,561 offchain_schema: Vec::new(),562 sponsor: T::AccountId::default(),563 unconfirmed_sponsor: T::AccountId::default(),564 variable_on_chain_schema: Vec::new(),565 const_on_chain_schema: Vec::new(),566 limits: CollectionLimits::default(),567 };568569 570 <Collection<T>>::insert(next_id, new_collection);571572 573 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));574575 Ok(())576 }577578 579 580 581 582 583 584 585 586 587 #[weight = T::WeightInfo::destroy_collection()]588 pub fn destroy_collection(origin, collection_id: u64) -> DispatchResult {589590 let sender = ensure_signed(origin)?;591 Self::check_owner_permissions(collection_id, sender)?;592593 <AddressTokens<T>>::remove_prefix(collection_id);594 <ApprovedList<T>>::remove_prefix(collection_id);595 <Balance<T>>::remove_prefix(collection_id);596 <ItemListIndex>::remove(collection_id);597 <AdminList<T>>::remove(collection_id);598 <Collection<T>>::remove(collection_id);599 <WhiteList<T>>::remove(collection_id);600601 <NftItemList<T>>::remove_prefix(collection_id);602 <FungibleItemList<T>>::remove_prefix(collection_id);603 <ReFungibleItemList<T>>::remove_prefix(collection_id);604605 <NftTransferBasket<T>>::remove_prefix(collection_id);606 <FungibleTransferBasket<T>>::remove_prefix(collection_id);607 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);608609 if CollectionCount::get() > 0610 {611 612 let total = CollectionCount::get()613 .checked_sub(1)614 .ok_or(Error::<T>::NumOverflow)?;615616 CollectionCount::put(total);617 }618619 Ok(())620 }621622 623 624 625 626 627 628 629 630 631 632 633 634 #[weight = T::WeightInfo::add_to_white_list()]635 pub fn add_to_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{636637 let sender = ensure_signed(origin)?;638 Self::check_owner_or_admin_permissions(collection_id, sender)?;639640 let mut white_list_collection: Vec<T::AccountId>;641 if <WhiteList<T>>::contains_key(collection_id) {642 white_list_collection = <WhiteList<T>>::get(collection_id);643 if !white_list_collection.contains(&address.clone())644 {645 white_list_collection.push(address.clone());646 }647 }648 else {649 white_list_collection = Vec::new();650 white_list_collection.push(address.clone());651 }652653 <WhiteList<T>>::insert(collection_id, white_list_collection);654 Ok(())655 }656657 658 659 660 661 662 663 664 665 666 667 668 669 #[weight = T::WeightInfo::remove_from_white_list()]670 pub fn remove_from_white_list(origin, collection_id: u64, address: T::AccountId) -> DispatchResult{671672 let sender = ensure_signed(origin)?;673 Self::check_owner_or_admin_permissions(collection_id, sender)?;674675 if <WhiteList<T>>::contains_key(collection_id) {676 let mut white_list_collection = <WhiteList<T>>::get(collection_id);677 if white_list_collection.contains(&address.clone())678 {679 white_list_collection.retain(|i| *i != address.clone());680 <WhiteList<T>>::insert(collection_id, white_list_collection);681 }682 }683684 Ok(())685 }686687 688 689 690 691 692 693 694 695 696 697 698 #[weight = T::WeightInfo::set_public_access_mode()]699 pub fn set_public_access_mode(origin, collection_id: u64, mode: AccessMode) -> DispatchResult700 {701 let sender = ensure_signed(origin)?;702703 Self::check_owner_permissions(collection_id, sender)?;704 let mut target_collection = <Collection<T>>::get(collection_id);705 target_collection.access = mode;706 <Collection<T>>::insert(collection_id, target_collection);707708 Ok(())709 }710711 712 713 714 715 716 717 718 719 720 721 722 723 724 #[weight = T::WeightInfo::set_mint_permission()]725 pub fn set_mint_permission(origin, collection_id: u64, mint_permission: bool) -> DispatchResult726 {727 let sender = ensure_signed(origin)?;728729 Self::check_owner_permissions(collection_id, sender)?;730 let mut target_collection = <Collection<T>>::get(collection_id);731 target_collection.mint_mode = mint_permission;732 <Collection<T>>::insert(collection_id, target_collection);733734 Ok(())735 }736737 738 739 740 741 742 743 744 745 746 747 748 #[weight = T::WeightInfo::change_collection_owner()]749 pub fn change_collection_owner(origin, collection_id: u64, new_owner: T::AccountId) -> DispatchResult {750751 let sender = ensure_signed(origin)?;752 Self::check_owner_permissions(collection_id, sender)?;753 let mut target_collection = <Collection<T>>::get(collection_id);754 target_collection.owner = new_owner;755 <Collection<T>>::insert(collection_id, target_collection);756757 Ok(())758 }759760 761 762 763 764 765 766 767 768 769 770 771 772 773 #[weight = T::WeightInfo::add_collection_admin()]774 pub fn add_collection_admin(origin, collection_id: u64, new_admin_id: T::AccountId) -> DispatchResult {775776 let sender = ensure_signed(origin)?;777 Self::check_owner_or_admin_permissions(collection_id, sender)?;778 let mut admin_arr: Vec<T::AccountId> = Vec::new();779780 if <AdminList<T>>::contains_key(collection_id)781 {782 admin_arr = <AdminList<T>>::get(collection_id);783 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);784 }785786 787 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);788789 admin_arr.push(new_admin_id);790 <AdminList<T>>::insert(collection_id, admin_arr);791792 Ok(())793 }794795 796 797 798 799 800 801 802 803 804 805 806 807 #[weight = T::WeightInfo::remove_collection_admin()]808 pub fn remove_collection_admin(origin, collection_id: u64, account_id: T::AccountId) -> DispatchResult {809810 let sender = ensure_signed(origin)?;811 Self::check_owner_or_admin_permissions(collection_id, sender)?;812813 if <AdminList<T>>::contains_key(collection_id)814 {815 let mut admin_arr = <AdminList<T>>::get(collection_id);816 admin_arr.retain(|i| *i != account_id);817 <AdminList<T>>::insert(collection_id, admin_arr);818 }819820 Ok(())821 }822823 824 825 826 827 828 829 830 831 832 #[weight = T::WeightInfo::set_collection_sponsor()]833 pub fn set_collection_sponsor(origin, collection_id: u64, new_sponsor: T::AccountId) -> DispatchResult {834835 let sender = ensure_signed(origin)?;836 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);837838 let mut target_collection = <Collection<T>>::get(collection_id);839 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);840841 target_collection.unconfirmed_sponsor = new_sponsor;842 <Collection<T>>::insert(collection_id, target_collection);843844 Ok(())845 }846847 848 849 850 851 852 853 854 #[weight = T::WeightInfo::confirm_sponsorship()]855 pub fn confirm_sponsorship(origin, collection_id: u64) -> DispatchResult {856857 let sender = ensure_signed(origin)?;858 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);859860 let mut target_collection = <Collection<T>>::get(collection_id);861 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);862863 target_collection.sponsor = target_collection.unconfirmed_sponsor;864 target_collection.unconfirmed_sponsor = T::AccountId::default();865 <Collection<T>>::insert(collection_id, target_collection);866867 Ok(())868 }869870 871 872 873 874 875 876 877 878 879 #[weight = T::WeightInfo::remove_collection_sponsor()]880 pub fn remove_collection_sponsor(origin, collection_id: u64) -> DispatchResult {881882 let sender = ensure_signed(origin)?;883 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);884885 let mut target_collection = <Collection<T>>::get(collection_id);886 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);887888 target_collection.sponsor = T::AccountId::default();889 <Collection<T>>::insert(collection_id, target_collection);890891 Ok(())892 }893894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917918 #[weight = T::WeightInfo::create_item(data.len())]919 pub fn create_item(origin, collection_id: u64, owner: T::AccountId, data: CreateItemData) -> DispatchResult {920921 let sender = ensure_signed(origin)?;922923 Self::collection_exists(collection_id)?;924925 let target_collection = <Collection<T>>::get(collection_id);926927 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;928 Self::validate_create_item_args(&target_collection, &data)?;929 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;930931 Ok(())932 }933934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 #[weight = T::WeightInfo::create_item(items_data.into_iter()953 .map(|data| { data.len() })954 .sum())]955 pub fn create_multiple_items(origin, collection_id: u64, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {956957 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);958 let sender = ensure_signed(origin)?;959960 Self::collection_exists(collection_id)?;961 let target_collection = <Collection<T>>::get(collection_id);962963 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;964965 for data in &items_data {966 Self::validate_create_item_args(&target_collection, data)?;967 }968 for data in &items_data {969 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;970 }971972 Ok(())973 }974975 976 977 978 979 980 981 982 983 984 985 986 987 988 #[weight = T::WeightInfo::burn_item()]989 pub fn burn_item(origin, collection_id: u64, item_id: u64) -> DispatchResult {990991 let sender = ensure_signed(origin)?;992 Self::collection_exists(collection_id)?;993994 995 let target_collection = <Collection<T>>::get(collection_id);996 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||997 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),998 Error::<T>::NoPermission);9991000 if target_collection.access == AccessMode::WhiteList {1001 Self::check_white_list(collection_id, &sender)?;1002 }10031004 match target_collection.mode1005 {1006 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1007 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1008 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1009 _ => ()1010 };10111012 1013 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10141015 Ok(())1016 }10171018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 #[weight = T::WeightInfo::transfer()]1042 pub fn transfer(origin, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64) -> DispatchResult {10431044 let sender = ensure_signed(origin)?;10451046 1047 let target_collection = <Collection<T>>::get(collection_id);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, item_id, value, sender.clone(), 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, approved: T::AccountId, collection_id: u64, item_id: u64) -> 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, &approved)?;1097 }10981099 1100 let amount = 100000000;11011102 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1103 if list_exists {11041105 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1106 let item_contains = list.iter().any(|i| i.approved == approved);11071108 if !item_contains {1109 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1110 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1111 }1112 } else {11131114 let mut list = Vec::new();1115 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1116 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1117 }11181119 Ok(())1120 }1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 #[weight = T::WeightInfo::transfer_from()]1142 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: u64, item_id: u64, value: u64 ) -> DispatchResult {11431144 let sender = ensure_signed(origin)?;1145 let mut appoved_transfer = false;11461147 1148 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1149 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1150 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1151 if opt_item.is_some()1152 {1153 appoved_transfer = true;1154 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1155 }1156 }11571158 1159 let target_collection = <Collection<T>>::get(collection_id);1160 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1161 Error::<T>::NoPermission);11621163 if target_collection.access == AccessMode::WhiteList {1164 Self::check_white_list(collection_id, &sender)?;1165 Self::check_white_list(collection_id, &recipient)?;1166 }11671168 1169 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1170 .into_iter().filter(|i| i.approved != sender.clone()).collect();1171 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);117211731174 match target_collection.mode1175 {1176 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1177 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1178 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1179 _ => ()1180 };11811182 Ok(())1183 }11841185 1186 #[weight = 0]1187 pub fn safe_transfer_from(origin, collection_id: u64, item_id: u64, new_owner: T::AccountId) -> DispatchResult {11881189 1190 1191 1192 11931194 11951196 11971198 Ok(())1199 }12001201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 #[weight = T::WeightInfo::set_variable_meta_data()]1214 pub fn set_variable_meta_data (1215 origin,1216 collection_id: u64,1217 item_id: u64,1218 data: Vec<u8>1219 ) -> DispatchResult {1220 let sender = ensure_signed(origin)?;1221 1222 Self::collection_exists(collection_id)?;1223 1224 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12251226 1227 let target_collection = <Collection<T>>::get(collection_id);1228 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1229 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1230 Error::<T>::NoPermission);12311232 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12331234 match target_collection.mode1235 {1236 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1237 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1238 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1239 _ => fail!(Error::<T>::UnexpectedCollectionType)1240 };12411242 Ok(())1243 }1244 12451246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 #[weight = T::WeightInfo::set_offchain_schema()]1259 pub fn set_offchain_schema(1260 origin,1261 collection_id: u64,1262 schema: Vec<u8>1263 ) -> DispatchResult {1264 let sender = ensure_signed(origin)?;1265 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12661267 let mut target_collection = <Collection<T>>::get(collection_id);1268 target_collection.offchain_schema = schema;1269 <Collection<T>>::insert(collection_id, target_collection);12701271 Ok(())1272 }12731274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 #[weight = T::WeightInfo::set_const_on_chain_schema()]1287 pub fn set_const_on_chain_schema (1288 origin,1289 collection_id: u64,1290 schema: Vec<u8>1291 ) -> DispatchResult {1292 let sender = ensure_signed(origin)?;1293 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12941295 let mut target_collection = <Collection<T>>::get(collection_id);1296 target_collection.const_on_chain_schema = schema;1297 <Collection<T>>::insert(collection_id, target_collection);12981299 Ok(())1300 }13011302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 #[weight = T::WeightInfo::set_const_on_chain_schema()]1315 pub fn set_variable_on_chain_schema (1316 origin,1317 collection_id: u64,1318 schema: Vec<u8>1319 ) -> DispatchResult {1320 let sender = ensure_signed(origin)?;1321 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13221323 let mut target_collection = <Collection<T>>::get(collection_id);1324 target_collection.variable_on_chain_schema = schema;1325 <Collection<T>>::insert(collection_id, target_collection);13261327 Ok(())1328 }13291330 1331 #[weight = 0]1332 pub fn set_chain_limits(1333 origin,1334 limits: ChainLimits1335 ) -> DispatchResult {1336 ensure_root(origin)?;1337 <ChainLimit>::put(limits);1338 Ok(())1339 }13401341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 #[weight = T::WeightInfo::enable_contract_sponsoring()]1353 pub fn enable_contract_sponsoring(1354 origin,1355 contract_address: T::AccountId,1356 enable: bool1357 ) -> DispatchResult {13581359 let sender = ensure_signed(origin)?;13601361 #[cfg(feature = "runtime-benchmarks")]1362 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13631364 let mut is_owner = false;1365 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1366 let owner = <ContractOwner<T>>::get(&contract_address);1367 is_owner = sender == owner;1368 }1369 ensure!(is_owner, Error::<T>::NoPermission);13701371 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1372 Ok(())1373 }13741375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 #[weight = 0]1393 pub fn set_contract_sponsoring_rate_limit(1394 origin,1395 contract_address: T::AccountId,1396 rate_limit: T::BlockNumber1397 ) -> DispatchResult {1398 let sender = ensure_signed(origin)?;1399 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 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1407 Ok(())1408 }14091410 #[weight = 0]1411 pub fn set_collection_limits(1412 origin,1413 collection_id: u64,1414 limits: CollectionLimits,1415 ) -> DispatchResult {1416 let sender = ensure_signed(origin)?;1417 Self::check_owner_permissions(collection_id, sender.clone())?;14181419 let mut target_collection = <Collection<T>>::get(collection_id);1420 target_collection.limits = limits;1421 <Collection<T>>::insert(collection_id, target_collection);14221423 Ok(())1424 } 1425 }1426}14271428impl<T: Trait> Module<T> {14291430 fn can_create_items_in_collection(collection_id: u64, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14311432 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {14331434 1435 let total_items: u64 = ItemListIndex::get(collection_id);1436 let account_items: u32 = <AddressTokens<T>>::get(collection_id, sender.clone()).len() as u32;1437 ensure!(collection.limits.token_limit as u64 > total_items, Error::<T>::CollectionTokenLimitExceeded);1438 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1439 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1440 Self::check_white_list(collection_id, owner)?;1441 Self::check_white_list(collection_id, sender)?;1442 }14431444 Ok(())1445 }14461447 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1448 match target_collection.mode1449 {1450 CollectionMode::NFT => {1451 if let CreateItemData::NFT(data) = data {1452 1453 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1454 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1455 } else {1456 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1457 }1458 },1459 CollectionMode::Fungible(_) => {1460 if let CreateItemData::Fungible(_) = data {1461 } else {1462 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1463 }1464 },1465 CollectionMode::ReFungible(_) => {1466 if let CreateItemData::ReFungible(data) = data {14671468 1469 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1470 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1471 } else {1472 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1473 }1474 },1475 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1476 };14771478 Ok(())1479 }14801481 fn create_item_no_validation(collection_id: u64, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1482 match data1483 {1484 CreateItemData::NFT(data) => {1485 let item = NftItemType {1486 collection: collection_id,1487 owner,1488 const_data: data.const_data,1489 variable_data: data.variable_data1490 };14911492 Self::add_nft_item(item)?;1493 },1494 CreateItemData::Fungible(_) => {1495 let item = FungibleItemType {1496 collection: collection_id,1497 owner,1498 value: (10 as u128).pow(collection.decimal_points)1499 };15001501 Self::add_fungible_item(item)?;1502 },1503 CreateItemData::ReFungible(data) => {1504 let mut owner_list = Vec::new();1505 let value = (10 as u128).pow(collection.decimal_points);1506 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15071508 let item = ReFungibleItemType {1509 collection: collection_id,1510 owner: owner_list,1511 const_data: data.const_data,1512 variable_data: data.variable_data1513 };15141515 Self::add_refungible_item(item)?;1516 }1517 };15181519 1520 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));15211522 Ok(())1523 }15241525 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1526 let current_index = <ItemListIndex>::get(item.collection)1527 .checked_add(1)1528 .ok_or(Error::<T>::NumOverflow)?;1529 let itemcopy = item.clone();1530 let owner = item.owner.clone();1531 let value = item.value as u64;15321533 Self::add_token_index(item.collection, current_index, owner.clone())?;15341535 <ItemListIndex>::insert(item.collection, current_index);1536 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15371538 1539 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1540 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1541 1542 1543 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1544 .checked_add(value)1545 .ok_or(Error::<T>::NumOverflow)?;1546 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15471548 Ok(())1549 }15501551 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1552 let current_index = <ItemListIndex>::get(item.collection)1553 .checked_add(1)1554 .ok_or(Error::<T>::NumOverflow)?;1555 let itemcopy = item.clone();15561557 let value = item.owner.first().unwrap().fraction as u64;1558 let owner = item.owner.first().unwrap().owner.clone();15591560 Self::add_token_index(item.collection, current_index, owner.clone())?;15611562 <ItemListIndex>::insert(item.collection, current_index);1563 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15641565 1566 let block_number: T::BlockNumber = 0.into();1567 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);15681569 1570 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1571 .checked_add(value)1572 .ok_or(Error::<T>::NumOverflow)?;1573 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15741575 Ok(())1576 }15771578 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1579 let current_index = <ItemListIndex>::get(item.collection)1580 .checked_add(1)1581 .ok_or(Error::<T>::NumOverflow)?;15821583 let item_owner = item.owner.clone();1584 let collection_id = item.collection.clone();1585 Self::add_token_index(collection_id, current_index, item.owner.clone())?;15861587 <ItemListIndex>::insert(collection_id, current_index);1588 <NftItemList<T>>::insert(collection_id, current_index, item);15891590 1591 let block_number: T::BlockNumber = 0.into();1592 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);15931594 1595 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1596 .checked_add(1)1597 .ok_or(Error::<T>::NumOverflow)?;1598 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);15991600 Ok(())1601 }16021603 fn burn_refungible_item(1604 collection_id: u64,1605 item_id: u64,1606 owner: T::AccountId,1607 ) -> DispatchResult {1608 ensure!(1609 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1610 Error::<T>::TokenNotFound1611 );1612 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1613 let item = collection1614 .owner1615 .iter()1616 .filter(|&i| i.owner == owner)1617 .next()1618 .unwrap();1619 Self::remove_token_index(collection_id, item_id, owner.clone())?;16201621 1622 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));16231624 1625 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1626 .checked_sub(item.fraction as u64)1627 .ok_or(Error::<T>::NumOverflow)?;1628 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16291630 <ReFungibleItemList<T>>::remove(collection_id, item_id);16311632 Ok(())1633 }16341635 fn burn_nft_item(collection_id: u64, item_id: u64) -> DispatchResult {1636 ensure!(1637 <NftItemList<T>>::contains_key(collection_id, item_id),1638 Error::<T>::TokenNotFound1639 );1640 let item = <NftItemList<T>>::get(collection_id, item_id);1641 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16421643 1644 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16451646 1647 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1648 .checked_sub(1)1649 .ok_or(Error::<T>::NumOverflow)?;1650 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1651 <NftItemList<T>>::remove(collection_id, item_id);16521653 Ok(())1654 }16551656 fn burn_fungible_item(collection_id: u64, item_id: u64) -> DispatchResult {1657 ensure!(1658 <FungibleItemList<T>>::contains_key(collection_id, item_id),1659 Error::<T>::TokenNotFound1660 );1661 let item = <FungibleItemList<T>>::get(collection_id, item_id);1662 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16631664 1665 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16661667 1668 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1669 .checked_sub(item.value as u64)1670 .ok_or(Error::<T>::NumOverflow)?;1671 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16721673 <FungibleItemList<T>>::remove(collection_id, item_id);16741675 Ok(())1676 }16771678 fn collection_exists(collection_id: u64) -> DispatchResult {1679 ensure!(1680 <Collection<T>>::contains_key(collection_id),1681 Error::<T>::CollectionNotFound1682 );1683 Ok(())1684 }16851686 fn check_owner_permissions(collection_id: u64, subject: T::AccountId) -> DispatchResult {1687 Self::collection_exists(collection_id)?;16881689 let target_collection = <Collection<T>>::get(collection_id);1690 ensure!(1691 subject == target_collection.owner,1692 Error::<T>::NoPermission1693 );16941695 Ok(())1696 }16971698 fn is_owner_or_admin_permissions(collection_id: u64, subject: T::AccountId) -> bool {1699 let target_collection = <Collection<T>>::get(collection_id);1700 let mut result: bool = subject == target_collection.owner;1701 let exists = <AdminList<T>>::contains_key(collection_id);17021703 if !result & exists {1704 if <AdminList<T>>::get(collection_id).contains(&subject) {1705 result = true1706 }1707 }17081709 result1710 }17111712 fn check_owner_or_admin_permissions(1713 collection_id: u64,1714 subject: T::AccountId,1715 ) -> DispatchResult {1716 Self::collection_exists(collection_id)?;1717 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17181719 ensure!(1720 result,1721 Error::<T>::NoPermission1722 );1723 Ok(())1724 }17251726 fn is_item_owner(subject: T::AccountId, collection_id: u64, item_id: u64) -> bool {1727 let target_collection = <Collection<T>>::get(collection_id);17281729 match target_collection.mode {1730 CollectionMode::NFT => {1731 <NftItemList<T>>::get(collection_id, item_id).owner == subject1732 }1733 CollectionMode::Fungible(_) => {1734 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1735 }1736 CollectionMode::ReFungible(_) => {1737 <ReFungibleItemList<T>>::get(collection_id, item_id)1738 .owner1739 .iter()1740 .any(|i| i.owner == subject)1741 }1742 CollectionMode::Invalid => false,1743 }1744 }17451746 fn check_white_list(collection_id: u64, address: &T::AccountId) -> DispatchResult {1747 let mes = Error::<T>::AddresNotInWhiteList;1748 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1749 let wl = <WhiteList<T>>::get(collection_id);1750 ensure!(wl.contains(address), mes);17511752 Ok(())1753 }17541755 fn transfer_fungible(1756 collection_id: u64,1757 item_id: u64,1758 value: u64,1759 owner: T::AccountId,1760 new_owner: T::AccountId,1761 ) -> DispatchResult {1762 ensure!(1763 <FungibleItemList<T>>::contains_key(collection_id, item_id),1764 Error::<T>::TokenNotFound1765 );17661767 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1768 let amount = full_item.value;17691770 ensure!(amount >= value.into(), Error::<T>::TokenValueTooLow);17711772 1773 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1774 .checked_sub(value)1775 .ok_or(Error::<T>::NumOverflow)?;1776 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);17771778 let mut new_owner_account_id = 0;1779 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1780 if new_owner_items.len() > 0 {1781 new_owner_account_id = new_owner_items[0];1782 }17831784 let val64 = value.into();17851786 1787 if amount == val64 && new_owner_account_id == 0 {1788 1789 1790 let mut new_full_item = full_item.clone();1791 new_full_item.owner = new_owner.clone();1792 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);17931794 1795 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1796 .checked_add(value)1797 .ok_or(Error::<T>::NumOverflow)?;1798 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);17991800 1801 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1802 } else {1803 let mut new_full_item = full_item.clone();1804 new_full_item.value -= val64;18051806 1807 if new_owner_account_id > 0 {1808 1809 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1810 item.value += val64;18111812 1813 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1814 .checked_add(value)1815 .ok_or(Error::<T>::NumOverflow)?;1816 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18171818 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1819 } else {1820 1821 let item = FungibleItemType {1822 collection: collection_id,1823 owner: new_owner.clone(),1824 value: val64,1825 };18261827 Self::add_fungible_item(item)?;1828 }18291830 if amount == val64 {1831 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;18321833 1834 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1835 <FungibleItemList<T>>::remove(collection_id, item_id);1836 }18371838 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1839 }18401841 Ok(())1842 }18431844 fn transfer_refungible(1845 collection_id: u64,1846 item_id: u64,1847 value: u64,1848 owner: T::AccountId,1849 new_owner: T::AccountId,1850 ) -> DispatchResult {1851 ensure!(1852 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1853 Error::<T>::TokenNotFound1854 );18551856 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1857 let item = full_item1858 .owner1859 .iter()1860 .filter(|i| i.owner == owner)1861 .next()1862 .ok_or(Error::<T>::NumOverflow)?;1863 let amount = item.fraction;18641865 ensure!(amount >= value.into(), Error::<T>::TokenValueTooLow);18661867 1868 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1869 .checked_sub(value)1870 .ok_or(Error::<T>::NumOverflow)?;1871 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);18721873 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1874 .checked_add(value)1875 .ok_or(Error::<T>::NumOverflow)?;1876 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18771878 let old_owner = item.owner.clone();1879 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1880 let val64 = value.into();18811882 1883 if amount == val64 && !new_owner_has_account {1884 1885 1886 let mut new_full_item = full_item.clone();1887 new_full_item1888 .owner1889 .iter_mut()1890 .find(|i| i.owner == owner)1891 .unwrap()1892 .owner = new_owner.clone();1893 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18941895 1896 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1897 } else {1898 let mut new_full_item = full_item.clone();1899 new_full_item1900 .owner1901 .iter_mut()1902 .find(|i| i.owner == owner)1903 .unwrap()1904 .fraction -= val64;19051906 1907 if new_owner_has_account {1908 1909 new_full_item1910 .owner1911 .iter_mut()1912 .find(|i| i.owner == new_owner)1913 .unwrap()1914 .fraction += val64;1915 } else {1916 1917 new_full_item.owner.push(Ownership {1918 owner: new_owner.clone(),1919 fraction: val64,1920 });1921 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1922 }19231924 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1925 }19261927 Ok(())1928 }19291930 fn transfer_nft(1931 collection_id: u64,1932 item_id: u64,1933 sender: T::AccountId,1934 new_owner: T::AccountId,1935 ) -> DispatchResult {1936 ensure!(1937 <NftItemList<T>>::contains_key(collection_id, item_id),1938 Error::<T>::TokenNotFound1939 );19401941 let mut item = <NftItemList<T>>::get(collection_id, item_id);19421943 ensure!(1944 sender == item.owner,1945 Error::<T>::MustBeTokenOwner1946 );19471948 1949 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1950 .checked_sub(1)1951 .ok_or(Error::<T>::NumOverflow)?;1952 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19531954 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1955 .checked_add(1)1956 .ok_or(Error::<T>::NumOverflow)?;1957 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19581959 1960 let old_owner = item.owner.clone();1961 item.owner = new_owner.clone();1962 <NftItemList<T>>::insert(collection_id, item_id, item);19631964 1965 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19661967 1968 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1969 Ok(())1970 }1971 1972 fn item_exists(1973 collection_id: u64,1974 item_id: u64,1975 mode: &CollectionMode1976 ) -> DispatchResult {1977 match mode {1978 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1979 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1980 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1981 _ => ()1982 };1983 1984 Ok(())1985 }19861987 fn set_re_fungible_variable_data(1988 collection_id: u64,1989 item_id: u64,1990 data: Vec<u8>1991 ) -> DispatchResult {1992 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);19931994 item.variable_data = data;19951996 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);19971998 Ok(())1999 }20002001 fn set_nft_variable_data(2002 collection_id: u64,2003 item_id: u64,2004 data: Vec<u8>2005 ) -> DispatchResult {2006 let mut item = <NftItemList<T>>::get(collection_id, item_id);2007 2008 item.variable_data = data;20092010 <NftItemList<T>>::insert(collection_id, item_id, item);2011 2012 Ok(())2013 }20142015 fn init_collection(item: &CollectionType<T::AccountId>) {2016 2017 assert!(2018 item.decimal_points <= 4,2019 "decimal_points parameter must be lower than 4"2020 );2021 assert!(2022 item.name.len() <= 64,2023 "Collection name can not be longer than 63 char"2024 );2025 assert!(2026 item.name.len() <= 256,2027 "Collection description can not be longer than 255 char"2028 );2029 assert!(2030 item.token_prefix.len() <= 16,2031 "Token prefix can not be longer than 15 char"2032 );20332034 2035 let next_id = CreatedCollectionCount::get()2036 .checked_add(1)2037 .unwrap();20382039 CreatedCollectionCount::put(next_id);2040 }20412042 fn init_nft_token(item: &NftItemType<T::AccountId>) {2043 let current_index = <ItemListIndex>::get(item.collection)2044 .checked_add(1)2045 .unwrap();20462047 let item_owner = item.owner.clone();2048 let collection_id = item.collection.clone();2049 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();20502051 <ItemListIndex>::insert(collection_id, current_index);20522053 2054 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2055 .checked_add(1)2056 .unwrap();2057 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2058 }20592060 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2061 let current_index = <ItemListIndex>::get(item.collection)2062 .checked_add(1)2063 .unwrap();2064 let owner = item.owner.clone();2065 let value = item.value as u64;20662067 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20682069 <ItemListIndex>::insert(item.collection, current_index);20702071 2072 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2073 .checked_add(value)2074 .unwrap();2075 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2076 }20772078 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2079 let current_index = <ItemListIndex>::get(item.collection)2080 .checked_add(1)2081 .unwrap();20822083 let value = item.owner.first().unwrap().fraction as u64;2084 let owner = item.owner.first().unwrap().owner.clone();20852086 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20872088 <ItemListIndex>::insert(item.collection, current_index);20892090 2091 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2092 .checked_add(value)2093 .unwrap();2094 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2095 }20962097 fn add_token_index(collection_id: u64, item_index: u64, owner: T::AccountId) -> DispatchResult {20982099 2100 if <AccountItemCount<T>>::contains_key(owner.clone()) {21012102 2103 let count = <AccountItemCount<T>>::get(owner.clone());2104 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21052106 <AccountItemCount<T>>::insert(owner.clone(), count2107 .checked_add(1)2108 .ok_or(Error::<T>::NumOverflow)?);2109 }2110 else {2111 <AccountItemCount<T>>::insert(owner.clone(), 1);2112 }21132114 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2115 if list_exists {2116 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2117 let item_contains = list.contains(&item_index.clone());21182119 if !item_contains {2120 list.push(item_index.clone());2121 }21222123 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2124 } else {2125 let mut itm = Vec::new();2126 itm.push(item_index.clone());2127 <AddressTokens<T>>::insert(collection_id, owner, itm);2128 2129 }21302131 Ok(())2132 }21332134 fn remove_token_index(2135 collection_id: u64,2136 item_index: u64,2137 owner: T::AccountId,2138 ) -> DispatchResult {21392140 2141 <AccountItemCount<T>>::insert(owner.clone(), 2142 <AccountItemCount<T>>::get(owner.clone())2143 .checked_sub(1)2144 .ok_or(Error::<T>::NumOverflow)?);214521462147 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2148 if list_exists {2149 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2150 let item_contains = list.contains(&item_index.clone());21512152 if item_contains {2153 list.retain(|&item| item != item_index);2154 <AddressTokens<T>>::insert(collection_id, owner, list);2155 }2156 }21572158 Ok(())2159 }21602161 fn move_token_index(2162 collection_id: u64,2163 item_index: u64,2164 old_owner: T::AccountId,2165 new_owner: T::AccountId,2166 ) -> DispatchResult {2167 Self::remove_token_index(collection_id, item_index, old_owner)?;2168 Self::add_token_index(collection_id, item_index, new_owner)?;21692170 Ok(())2171 }2172}2173217421752176217721782179pub type Multiplier = FixedU128;21802181type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2182 <T as system::Trait>::AccountId,2183>>::Balance;2184type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2185 <T as system::Trait>::AccountId,2186>>::NegativeImbalance;2187218821892190#[derive(Encode, Decode, Clone, Eq, PartialEq)]2191pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2192 #[codec(compact)] BalanceOf<T>2193);21942195impl<T: Trait + Send + Sync> sp_std::fmt::Debug2196 for ChargeTransactionPayment<T>2197{2198 #[cfg(feature = "std")]2199 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2200 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2201 }2202 #[cfg(not(feature = "std"))]2203 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2204 Ok(())2205 }2206}22072208impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2209where2210 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2211 BalanceOf<T>: Send + Sync + FixedPointOperand,2212{2213 2214 pub fn from(fee: BalanceOf<T>) -> Self {2215 Self(fee)2216 }22172218 pub fn traditional_fee(2219 len: usize,2220 info: &DispatchInfoOf<T::Call>,2221 tip: BalanceOf<T>,2222 ) -> BalanceOf<T>2223 where2224 T::Call: Dispatchable<Info = DispatchInfo>,2225 {2226 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2227 }22282229 fn withdraw_fee(2230 &self,2231 who: &T::AccountId,2232 call: &T::Call,2233 info: &DispatchInfoOf<T::Call>,2234 len: usize,2235 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2236 let tip = self.0;22372238 2239 2240 2241 2242 2243 2244 2245 let fee = Self::traditional_fee(len, info, tip);22462247 2248 2249 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2250 Some(Call::create_item(collection_id, _owner, _properties)) => {22512252 2253 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2254 {2255 <Collection<T>>::get(collection_id).sponsor2256 } else {2257 T::AccountId::default()2258 }2259 }2260 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2261 2262 let _collection_limits = <Collection<T>>::get(collection_id).limits;2263 let _collection_mode = <Collection<T>>::get(collection_id).mode;22642265 2266 let sponsor_transfer = match _collection_mode {2267 CollectionMode::NFT => {22682269 2270 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2271 _collection_limits.sponsor_transfer_timeout2272 } else {2273 ChainLimit::get().nft_sponsor_transfer_timeout2274 };22752276 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2277 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2278 let limit_time = basket + limit.into();2279 if block_number >= limit_time {2280 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2281 true2282 }2283 else {2284 false2285 }2286 }2287 CollectionMode::Fungible(_) => {22882289 2290 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2291 _collection_limits.sponsor_transfer_timeout2292 } else {2293 ChainLimit::get().fungible_sponsor_transfer_timeout2294 };22952296 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2297 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2298 if basket.iter().any(|i| i.address == _new_owner.clone())2299 {2300 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2301 let limit_time = item.start_block + limit.into();2302 if block_number >= limit_time {2303 basket.retain(|x| x.address == item.address);2304 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2305 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2306 true2307 }2308 else {2309 false2310 }2311 }2312 else {2313 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2314 true2315 }2316 }2317 CollectionMode::ReFungible(_) => {23182319 2320 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2321 _collection_limits.sponsor_transfer_timeout2322 } else {2323 ChainLimit::get().refungible_sponsor_transfer_timeout2324 };23252326 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2327 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2328 let limit_time = basket + limit.into();2329 if block_number >= limit_time {2330 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2331 true2332 } else {2333 false2334 }2335 }2336 _ => {2337 false2338 },2339 };23402341 if !sponsor_transfer {2342 T::AccountId::default()2343 } else {2344 <Collection<T>>::get(collection_id).sponsor2345 }2346 }23472348 _ => T::AccountId::default(),2349 };23502351 2352 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {23532354 2355 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {23562357 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2358 code_hash,2359 &data,2360 &who,2361 );2362 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());23632364 T::AccountId::default()2365 },23662367 2368 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {23692370 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());23712372 let mut sponsor_transfer = false;2373 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2374 let last_tx_block = <ContractSponsorBasket<T>>::get(&called_contract);2375 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2376 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2377 let limit_time = last_tx_block + rate_limit;23782379 if block_number >= limit_time {2380 <ContractSponsorBasket<T>>::insert(called_contract.clone(), block_number);2381 sponsor_transfer = true;2382 }2383 } else {2384 sponsor_transfer = false;2385 }2386 2387 2388 let mut sp = T::AccountId::default();2389 if sponsor_transfer {2390 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2391 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2392 sp = called_contract;2393 }2394 }2395 }23962397 sp2398 },23992400 _ => sponsor,2401 };24022403 let mut who_pays_fee: T::AccountId = sponsor.clone();2404 if sponsor == T::AccountId::default() {2405 who_pays_fee = who.clone();2406 }24072408 2409 if fee.is_zero() {2410 return Ok((fee, None));2411 }24122413 match <T as transaction_payment::Trait>::Currency::withdraw(2414 &who_pays_fee,2415 fee,2416 if tip.is_zero() {2417 WithdrawReason::TransactionPayment.into()2418 } else {2419 WithdrawReason::TransactionPayment | WithdrawReason::Tip2420 },2421 ExistenceRequirement::KeepAlive,2422 ) {2423 Ok(imbalance) => Ok((fee, Some(imbalance))),2424 Err(_) => Err(InvalidTransaction::Payment.into()),2425 }2426 }2427}242824292430impl<T: Trait + Send + Sync> SignedExtension2431 for ChargeTransactionPayment<T>2432where2433 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2434 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2435{2436 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2437 type AccountId = T::AccountId;2438 type Call = T::Call;2439 type AdditionalSigned = ();2440 type Pre = (2441 BalanceOf<T>,2442 Self::AccountId,2443 Option<NegativeImbalanceOf<T>>,2444 BalanceOf<T>,2445 );2446 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2447 Ok(())2448 }24492450 fn validate(2451 &self,2452 _who: &Self::AccountId,2453 _call: &Self::Call,2454 _info: &DispatchInfoOf<Self::Call>,2455 _len: usize,2456 ) -> TransactionValidity {2457 Ok(ValidTransaction::default())2458 }24592460 fn pre_dispatch(2461 self,2462 who: &Self::AccountId,2463 call: &Self::Call,2464 info: &DispatchInfoOf<Self::Call>,2465 len: usize,2466 ) -> Result<Self::Pre, TransactionValidityError> {2467 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2468 Ok((self.0, who.clone(), imbalance, fee))2469 }24702471 fn post_dispatch(2472 pre: Self::Pre,2473 info: &DispatchInfoOf<Self::Call>,2474 post_info: &PostDispatchInfoOf<Self::Call>,2475 len: usize,2476 _result: &DispatchResult,2477 ) -> Result<(), TransactionValidityError> {2478 let (tip, who, imbalance, fee) = pre;2479 if let Some(payed) = imbalance {2480 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2481 len as u32, info, post_info, tip,2482 );2483 let refund = fee.saturating_sub(actual_fee);2484 let actual_payment =2485 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2486 &who, refund,2487 ) {2488 Ok(refund_imbalance) => {2489 2490 2491 match payed.offset(refund_imbalance) {2492 Ok(actual_payment) => actual_payment,2493 Err(_) => return Err(InvalidTransaction::Payment.into()),2494 }2495 }2496 2497 2498 Err(_) => payed,2499 };2500 let imbalances = actual_payment.split(tip);2501 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2502 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2503 );2504 }2505 Ok(())2506 }2507}25082509