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;4748pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;4950515253pub type CollectionId = u32;54pub type TokenId = u32;5556pub type DecimalPoints = u8;5758#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]59#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]60pub enum CollectionMode {61 Invalid,62 NFT,63 64 Fungible(DecimalPoints),65 66 ReFungible(DecimalPoints),67}6869impl Into<u8> for CollectionMode {70 fn into(self) -> u8 {71 match self {72 CollectionMode::Invalid => 0,73 CollectionMode::NFT => 1,74 CollectionMode::Fungible(_) => 2,75 CollectionMode::ReFungible(_) => 3,76 }77 }78}7980#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]81#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]82pub enum AccessMode {83 Normal,84 WhiteList,85}86impl Default for AccessMode {87 fn default() -> Self {88 Self::Normal89 }90}9192impl Default for CollectionMode {93 fn default() -> Self {94 Self::Invalid95 }96}9798#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]99#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]100pub struct Ownership<AccountId> {101 pub owner: AccountId,102 pub fraction: u128,103}104105#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]106#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]107pub struct CollectionType<AccountId> {108 pub owner: AccountId,109 pub mode: CollectionMode,110 pub access: AccessMode,111 pub decimal_points: DecimalPoints,112 pub name: Vec<u16>, 113 pub description: Vec<u16>, 114 pub token_prefix: Vec<u8>, 115 pub mint_mode: bool,116 pub offchain_schema: Vec<u8>,117 pub sponsor: AccountId, 118 pub unconfirmed_sponsor: AccountId, 119 pub variable_on_chain_schema: Vec<u8>, 120 pub const_on_chain_schema: Vec<u8>, 121}122123#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]124#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]125pub struct NftItemType<AccountId> {126 pub collection: CollectionId,127 pub owner: AccountId,128 pub const_data: Vec<u8>,129 pub variable_data: Vec<u8>,130}131132#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]133#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]134pub struct FungibleItemType<AccountId> {135 pub collection: CollectionId,136 pub owner: AccountId,137 pub value: u128,138}139140#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]141#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]142pub struct ReFungibleItemType<AccountId> {143 pub collection: CollectionId,144 pub owner: Vec<Ownership<AccountId>>,145 pub const_data: Vec<u8>,146 pub variable_data: Vec<u8>,147}148149#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]150#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]151pub struct ApprovePermissions<AccountId> {152 pub approved: AccountId,153 pub amount: u64,154}155156#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]157#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]158pub struct VestingItem<AccountId, Moment> {159 pub sender: AccountId,160 pub recipient: AccountId,161 pub collection_id: CollectionId,162 pub item_id: TokenId,163 pub amount: u64,164 pub vesting_date: Moment,165}166167#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]168#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]169pub struct BasketItem<AccountId, BlockNumber> {170 pub address: AccountId,171 pub start_block: BlockNumber,172}173174#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]175#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]176pub struct ChainLimits {177 pub collection_numbers_limit: u32,178 pub account_token_ownership_limit: u32,179 pub collections_admins_limit: u64,180 pub custom_data_limit: u32,181182 183 pub nft_sponsor_transfer_timeout: u32,184 pub fungible_sponsor_transfer_timeout: u32,185 pub refungible_sponsor_transfer_timeout: u32,186}187188pub trait WeightInfo {189 fn create_collection() -> Weight;190 fn destroy_collection() -> Weight;191 fn add_to_white_list() -> Weight;192 fn remove_from_white_list() -> Weight;193 fn set_public_access_mode() -> Weight;194 fn set_mint_permission() -> Weight;195 fn change_collection_owner() -> Weight;196 fn add_collection_admin() -> Weight;197 fn remove_collection_admin() -> Weight;198 fn set_collection_sponsor() -> Weight;199 fn confirm_sponsorship() -> Weight;200 fn remove_collection_sponsor() -> Weight;201 fn create_item(s: usize) -> Weight;202 fn burn_item() -> Weight;203 fn transfer() -> Weight;204 fn approve() -> Weight;205 fn transfer_from() -> Weight;206 fn set_offchain_schema() -> Weight;207 fn set_const_on_chain_schema() -> Weight;208 fn set_variable_on_chain_schema() -> Weight;209 fn set_variable_meta_data() -> Weight;210 fn enable_contract_sponsoring() -> Weight;211}212213#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]214#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]215pub struct CreateNftData {216 pub const_data: Vec<u8>,217 pub variable_data: Vec<u8>,218}219220#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]221#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]222pub struct CreateFungibleData {223}224225#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]226#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]227pub struct CreateReFungibleData {228 pub const_data: Vec<u8>,229 pub variable_data: Vec<u8>,230}231232#[derive(Encode, Decode, Debug, Clone, PartialEq)]233#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]234pub enum CreateItemData {235 NFT(CreateNftData),236 Fungible(CreateFungibleData),237 ReFungible(CreateReFungibleData)238}239240impl CreateItemData {241 pub fn len(&self) -> usize {242 let len = match self {243 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),244 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),245 _ => 0246 };247 248 return len;249 }250}251252impl From<CreateNftData> for CreateItemData {253 fn from(item: CreateNftData) -> Self {254 CreateItemData::NFT(item)255 }256}257258impl From<CreateReFungibleData> for CreateItemData {259 fn from(item: CreateReFungibleData) -> Self {260 CreateItemData::ReFungible(item)261 }262}263264impl From<CreateFungibleData> for CreateItemData {265 fn from(item: CreateFungibleData) -> Self {266 CreateItemData::Fungible(item)267 }268}269270271decl_error! {272 273 pub enum Error for Module<T: Trait> {274 275 TotalCollectionsLimitExceeded,276 277 CollectionDecimalPointLimitExceeded, 278 279 CollectionNameLimitExceeded, 280 281 CollectionDescriptionLimitExceeded, 282 283 CollectionTokenPrefixLimitExceeded,284 285 CollectionNotFound,286 287 TokenNotFound,288 289 NumOverflow, 290 291 AlreadyAdmin, 292 293 NoPermission,294 295 ConfirmUnsetSponsorFail,296 297 PublicMintingNotAllowed,298 299 MustBeTokenOwner,300 301 TokenValueTooLow,302 303 NftSizeLimitExceeded,304 305 ApproveNotFound,306 307 TokenValueNotEnough,308 309 ApproveRequired,310 311 AddresNotInWhiteList,312 313 CollectionAdminsLimitExceeded,314 315 AddressOwnershipLimitExceeded,316 317 EmptyArgument,318 319 TokenConstDataLimitExceeded,320 321 TokenVariableDataLimitExceeded,322 323 NotNftDataUsedToMintNftCollectionToken,324 325 NotFungibleDataUsedToMintFungibleCollectionToken,326 327 NotReFungibleDataUsedToMintReFungibleCollectionToken,328 329 UnexpectedCollectionType,330 331 CantStoreMetadataInFungibleTokens332 }333}334335pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {336 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;337338 339 type WeightInfo: WeightInfo;340}341342#[cfg(feature = "runtime-benchmarks")]343mod benchmarking;344345346347decl_storage! {348 trait Store for Module<T: Trait> as Nft {349350 351 NextCollectionID: CollectionId;352 CreatedCollectionCount: u32;353 ChainVersion: u64;354 ItemListIndex: map hasher(identity) CollectionId => TokenId;355356 357 pub ChainLimit get(fn chain_limit) config(): ChainLimits;358359 360 CollectionCount: u32;361 pub AccountItemCount get(fn account_item_count): map hasher(identity) T::AccountId => u32;362363 364 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;365 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;366 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;367368 369 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u64;370371 372 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(blake2_128_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;373374 375 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;376 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;377 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;378379 380 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;381382 383 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;384 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;385 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;386387 388 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;389 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;390 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;391 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;392 }393 add_extra_genesis {394 build(|config: &GenesisConfig<T>| {395 396 for (_num, _c) in &config.collection {397 <Module<T>>::init_collection(_c);398 }399400 for (_num, _q, _i) in &config.nft_item_id {401 <Module<T>>::init_nft_token(_i);402 }403404 for (_num, _q, _i) in &config.fungible_item_id {405 <Module<T>>::init_fungible_token(_i);406 }407408 for (_num, _q, _i) in &config.refungible_item_id {409 <Module<T>>::init_refungible_token(_i);410 }411 })412 }413}414415decl_event!(416 pub enum Event<T>417 where418 AccountId = <T as system::Trait>::AccountId,419 {420 421 422 423 424 425 426 427 428 429 Created(CollectionId, u8, AccountId),430431 432 433 434 435 436 437 438 ItemCreated(CollectionId, TokenId),439440 441 442 443 444 445 446 447 ItemDestroyed(CollectionId, TokenId),448 }449);450451decl_module! {452 pub struct Module<T: Trait> for enum Call where origin: T::Origin {453454 fn deposit_event() = default;455 type Error = Error<T>;456457 fn on_initialize(now: T::BlockNumber) -> Weight {458459 if ChainVersion::get() < 2460 {461 let value = NextCollectionID::get();462 CreatedCollectionCount::put(value);463 ChainVersion::put(2);464 }465466 0467 }468469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 #[weight = T::WeightInfo::create_collection()]486 pub fn create_collection(origin,487 collection_name: Vec<u16>,488 collection_description: Vec<u16>,489 token_prefix: Vec<u8>,490 mode: CollectionMode) -> DispatchResult {491492 493 let who = ensure_signed(origin)?;494495 let decimal_points = match mode {496 CollectionMode::Fungible(points) => points,497 CollectionMode::ReFungible(points) => points,498 _ => 0499 };500501 502 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);503504 505 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);506507 let mut name = collection_name.to_vec();508 name.push(0);509 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);510511 let mut description = collection_description.to_vec();512 description.push(0);513 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);514515 let mut prefix = token_prefix.to_vec();516 prefix.push(0);517 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);518519 520 let next_id = CreatedCollectionCount::get()521 .checked_add(1)522 .ok_or(Error::<T>::NumOverflow)?;523524 525 let total = CollectionCount::get()526 .checked_add(1)527 .ok_or(Error::<T>::NumOverflow)?;528529 CreatedCollectionCount::put(next_id);530 CollectionCount::put(total);531532 533 let new_collection = CollectionType {534 owner: who.clone(),535 name: name,536 mode: mode.clone(),537 mint_mode: false,538 access: AccessMode::Normal,539 description: description,540 decimal_points: decimal_points,541 token_prefix: prefix,542 offchain_schema: Vec::new(),543 sponsor: T::AccountId::default(),544 unconfirmed_sponsor: T::AccountId::default(),545 variable_on_chain_schema: Vec::new(),546 const_on_chain_schema: Vec::new(),547 };548549 550 <Collection<T>>::insert(next_id, new_collection);551552 553 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));554555 Ok(())556 }557558 559 560 561 562 563 564 565 566 567 #[weight = T::WeightInfo::destroy_collection()]568 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {569570 let sender = ensure_signed(origin)?;571 Self::check_owner_permissions(collection_id, sender)?;572573 <AddressTokens<T>>::remove_prefix(collection_id);574 <ApprovedList<T>>::remove_prefix(collection_id);575 <Balance<T>>::remove_prefix(collection_id);576 <ItemListIndex>::remove(collection_id);577 <AdminList<T>>::remove(collection_id);578 <Collection<T>>::remove(collection_id);579 <WhiteList<T>>::remove(collection_id);580581 <NftItemList<T>>::remove_prefix(collection_id);582 <FungibleItemList<T>>::remove_prefix(collection_id);583 <ReFungibleItemList<T>>::remove_prefix(collection_id);584585 <NftTransferBasket<T>>::remove_prefix(collection_id);586 <FungibleTransferBasket<T>>::remove_prefix(collection_id);587 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);588589 if CollectionCount::get() > 0590 {591 592 let total = CollectionCount::get()593 .checked_sub(1)594 .ok_or(Error::<T>::NumOverflow)?;595596 CollectionCount::put(total);597 }598599 Ok(())600 }601602 603 604 605 606 607 608 609 610 611 612 613 614 #[weight = T::WeightInfo::add_to_white_list()]615 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{616617 let sender = ensure_signed(origin)?;618 Self::check_owner_or_admin_permissions(collection_id, sender)?;619620 let mut white_list_collection: Vec<T::AccountId>;621 if <WhiteList<T>>::contains_key(collection_id) {622 white_list_collection = <WhiteList<T>>::get(collection_id);623 if !white_list_collection.contains(&address.clone())624 {625 white_list_collection.push(address.clone());626 }627 }628 else {629 white_list_collection = Vec::new();630 white_list_collection.push(address.clone());631 }632633 <WhiteList<T>>::insert(collection_id, white_list_collection);634 Ok(())635 }636637 638 639 640 641 642 643 644 645 646 647 648 649 #[weight = T::WeightInfo::remove_from_white_list()]650 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{651652 let sender = ensure_signed(origin)?;653 Self::check_owner_or_admin_permissions(collection_id, sender)?;654655 if <WhiteList<T>>::contains_key(collection_id) {656 let mut white_list_collection = <WhiteList<T>>::get(collection_id);657 if white_list_collection.contains(&address.clone())658 {659 white_list_collection.retain(|i| *i != address.clone());660 <WhiteList<T>>::insert(collection_id, white_list_collection);661 }662 }663664 Ok(())665 }666667 668 669 670 671 672 673 674 675 676 677 678 #[weight = T::WeightInfo::set_public_access_mode()]679 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult680 {681 let sender = ensure_signed(origin)?;682683 Self::check_owner_permissions(collection_id, sender)?;684 let mut target_collection = <Collection<T>>::get(collection_id);685 target_collection.access = mode;686 <Collection<T>>::insert(collection_id, target_collection);687688 Ok(())689 }690691 692 693 694 695 696 697 698 699 700 701 702 703 704 #[weight = T::WeightInfo::set_mint_permission()]705 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult706 {707 let sender = ensure_signed(origin)?;708709 Self::check_owner_permissions(collection_id, sender)?;710 let mut target_collection = <Collection<T>>::get(collection_id);711 target_collection.mint_mode = mint_permission;712 <Collection<T>>::insert(collection_id, target_collection);713714 Ok(())715 }716717 718 719 720 721 722 723 724 725 726 727 728 #[weight = T::WeightInfo::change_collection_owner()]729 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {730731 let sender = ensure_signed(origin)?;732 Self::check_owner_permissions(collection_id, sender)?;733 let mut target_collection = <Collection<T>>::get(collection_id);734 target_collection.owner = new_owner;735 <Collection<T>>::insert(collection_id, target_collection);736737 Ok(())738 }739740 741 742 743 744 745 746 747 748 749 750 751 752 753 #[weight = T::WeightInfo::add_collection_admin()]754 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {755756 let sender = ensure_signed(origin)?;757 Self::check_owner_or_admin_permissions(collection_id, sender)?;758 let mut admin_arr: Vec<T::AccountId> = Vec::new();759760 if <AdminList<T>>::contains_key(collection_id)761 {762 admin_arr = <AdminList<T>>::get(collection_id);763 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);764 }765766 767 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);768769 admin_arr.push(new_admin_id);770 <AdminList<T>>::insert(collection_id, admin_arr);771772 Ok(())773 }774775 776 777 778 779 780 781 782 783 784 785 786 787 #[weight = T::WeightInfo::remove_collection_admin()]788 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {789790 let sender = ensure_signed(origin)?;791 Self::check_owner_or_admin_permissions(collection_id, sender)?;792793 if <AdminList<T>>::contains_key(collection_id)794 {795 let mut admin_arr = <AdminList<T>>::get(collection_id);796 admin_arr.retain(|i| *i != account_id);797 <AdminList<T>>::insert(collection_id, admin_arr);798 }799800 Ok(())801 }802803 804 805 806 807 808 809 810 811 812 #[weight = T::WeightInfo::set_collection_sponsor()]813 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {814815 let sender = ensure_signed(origin)?;816 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);817818 let mut target_collection = <Collection<T>>::get(collection_id);819 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);820821 target_collection.unconfirmed_sponsor = new_sponsor;822 <Collection<T>>::insert(collection_id, target_collection);823824 Ok(())825 }826827 828 829 830 831 832 833 834 #[weight = T::WeightInfo::confirm_sponsorship()]835 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {836837 let sender = ensure_signed(origin)?;838 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);839840 let mut target_collection = <Collection<T>>::get(collection_id);841 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);842843 target_collection.sponsor = target_collection.unconfirmed_sponsor;844 target_collection.unconfirmed_sponsor = T::AccountId::default();845 <Collection<T>>::insert(collection_id, target_collection);846847 Ok(())848 }849850 851 852 853 854 855 856 857 858 859 #[weight = T::WeightInfo::remove_collection_sponsor()]860 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {861862 let sender = ensure_signed(origin)?;863 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);864865 let mut target_collection = <Collection<T>>::get(collection_id);866 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);867868 target_collection.sponsor = T::AccountId::default();869 <Collection<T>>::insert(collection_id, target_collection);870871 Ok(())872 }873874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897898 #[weight = T::WeightInfo::create_item(data.len())]899 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {900901 let sender = ensure_signed(origin)?;902903 Self::collection_exists(collection_id)?;904905 let target_collection = <Collection<T>>::get(collection_id);906907 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;908 Self::validate_create_item_args(&target_collection, &data)?;909 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;910911 Ok(())912 }913914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 #[weight = T::WeightInfo::create_item(items_data.into_iter()933 .map(|data| { data.len() })934 .sum())]935 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {936937 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);938 let sender = ensure_signed(origin)?;939940 Self::collection_exists(collection_id)?;941 let target_collection = <Collection<T>>::get(collection_id);942943 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;944945 for data in &items_data {946 Self::validate_create_item_args(&target_collection, data)?;947 }948 for data in &items_data {949 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;950 }951952 Ok(())953 }954955 956 957 958 959 960 961 962 963 964 965 966 967 968 #[weight = T::WeightInfo::burn_item()]969 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {970971 let sender = ensure_signed(origin)?;972 Self::collection_exists(collection_id)?;973974 975 let target_collection = <Collection<T>>::get(collection_id);976 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||977 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),978 Error::<T>::NoPermission);979980 if target_collection.access == AccessMode::WhiteList {981 Self::check_white_list(collection_id, &sender)?;982 }983984 match target_collection.mode985 {986 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,987 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,988 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,989 _ => ()990 };991992 993 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));994995 Ok(())996 }997998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 #[weight = T::WeightInfo::transfer()]1022 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u64) -> DispatchResult {10231024 let sender = ensure_signed(origin)?;10251026 1027 let target_collection = <Collection<T>>::get(collection_id);1028 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1029 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1030 Error::<T>::NoPermission);10311032 if target_collection.access == AccessMode::WhiteList {1033 Self::check_white_list(collection_id, &sender)?;1034 Self::check_white_list(collection_id, &recipient)?;1035 }10361037 match target_collection.mode1038 {1039 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1040 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1041 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1042 _ => ()1043 };10441045 Ok(())1046 }10471048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 #[weight = T::WeightInfo::approve()]1064 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10651066 let sender = ensure_signed(origin)?;10671068 1069 let target_collection = <Collection<T>>::get(collection_id);1070 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1071 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1072 Error::<T>::NoPermission);10731074 if target_collection.access == AccessMode::WhiteList {1075 Self::check_white_list(collection_id, &sender)?;1076 Self::check_white_list(collection_id, &approved)?;1077 }10781079 1080 let amount = 100000000;10811082 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1083 if list_exists {10841085 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1086 let item_contains = list.iter().any(|i| i.approved == approved);10871088 if !item_contains {1089 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1090 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1091 }1092 } else {10931094 let mut list = Vec::new();1095 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1096 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1097 }10981099 Ok(())1100 }1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 #[weight = T::WeightInfo::transfer_from()]1122 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u64 ) -> DispatchResult {11231124 let sender = ensure_signed(origin)?;1125 let mut appoved_transfer = false;11261127 1128 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1129 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1130 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1131 if opt_item.is_some()1132 {1133 appoved_transfer = true;1134 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1135 }1136 }11371138 1139 let target_collection = <Collection<T>>::get(collection_id);1140 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1141 Error::<T>::NoPermission);11421143 if target_collection.access == AccessMode::WhiteList {1144 Self::check_white_list(collection_id, &sender)?;1145 Self::check_white_list(collection_id, &recipient)?;1146 }11471148 1149 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1150 .into_iter().filter(|i| i.approved != sender.clone()).collect();1151 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);115211531154 match target_collection.mode1155 {1156 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1157 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1158 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1159 _ => ()1160 };11611162 Ok(())1163 }11641165 1166 #[weight = 0]1167 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {11681169 1170 1171 1172 11731174 11751176 11771178 Ok(())1179 }11801181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 #[weight = T::WeightInfo::set_variable_meta_data()]1194 pub fn set_variable_meta_data (1195 origin,1196 collection_id: CollectionId,1197 item_id: TokenId,1198 data: Vec<u8>1199 ) -> DispatchResult {1200 let sender = ensure_signed(origin)?;1201 1202 Self::collection_exists(collection_id)?;1203 1204 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12051206 1207 let target_collection = <Collection<T>>::get(collection_id);1208 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1209 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1210 Error::<T>::NoPermission);12111212 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12131214 match target_collection.mode1215 {1216 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1217 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1218 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1219 _ => fail!(Error::<T>::UnexpectedCollectionType)1220 };12211222 Ok(())1223 }1224 12251226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 #[weight = T::WeightInfo::set_offchain_schema()]1239 pub fn set_offchain_schema(1240 origin,1241 collection_id: CollectionId,1242 schema: Vec<u8>1243 ) -> DispatchResult {1244 let sender = ensure_signed(origin)?;1245 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12461247 let mut target_collection = <Collection<T>>::get(collection_id);1248 target_collection.offchain_schema = schema;1249 <Collection<T>>::insert(collection_id, target_collection);12501251 Ok(())1252 }12531254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 #[weight = T::WeightInfo::set_const_on_chain_schema()]1267 pub fn set_const_on_chain_schema (1268 origin,1269 collection_id: CollectionId,1270 schema: Vec<u8>1271 ) -> DispatchResult {1272 let sender = ensure_signed(origin)?;1273 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;12741275 let mut target_collection = <Collection<T>>::get(collection_id);1276 target_collection.const_on_chain_schema = schema;1277 <Collection<T>>::insert(collection_id, target_collection);12781279 Ok(())1280 }12811282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 #[weight = T::WeightInfo::set_const_on_chain_schema()]1295 pub fn set_variable_on_chain_schema (1296 origin,1297 collection_id: CollectionId,1298 schema: Vec<u8>1299 ) -> DispatchResult {1300 let sender = ensure_signed(origin)?;1301 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13021303 let mut target_collection = <Collection<T>>::get(collection_id);1304 target_collection.variable_on_chain_schema = schema;1305 <Collection<T>>::insert(collection_id, target_collection);13061307 Ok(())1308 }13091310 1311 #[weight = 0]1312 pub fn set_chain_limits(1313 origin,1314 limits: ChainLimits1315 ) -> DispatchResult {1316 ensure_root(origin)?;1317 <ChainLimit>::put(limits);1318 Ok(())1319 }13201321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 #[weight = T::WeightInfo::enable_contract_sponsoring()]1333 pub fn enable_contract_sponsoring(1334 origin,1335 contract_address: T::AccountId,1336 enable: bool1337 ) -> DispatchResult {13381339 let sender = ensure_signed(origin)?;13401341 #[cfg(feature = "runtime-benchmarks")]1342 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());13431344 let mut is_owner = false;1345 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1346 let owner = <ContractOwner<T>>::get(&contract_address);1347 is_owner = sender == owner;1348 }1349 ensure!(is_owner, Error::<T>::NoPermission);13501351 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1352 Ok(())1353 }13541355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 #[weight = 0]1373 pub fn set_contract_sponsoring_rate_limit(1374 origin,1375 contract_address: T::AccountId,1376 rate_limit: T::BlockNumber1377 ) -> DispatchResult {1378 let sender = ensure_signed(origin)?;1379 let mut is_owner = false;1380 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1381 let owner = <ContractOwner<T>>::get(&contract_address);1382 is_owner = sender == owner;1383 }1384 ensure!(is_owner, Error::<T>::NoPermission);13851386 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1387 Ok(())1388 }13891390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 }1402}14031404impl<T: Trait> Module<T> {14051406 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {14071408 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1409 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1410 Self::check_white_list(collection_id, owner)?;1411 Self::check_white_list(collection_id, sender)?;1412 }14131414 Ok(())1415 }14161417 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1418 match target_collection.mode1419 {1420 CollectionMode::NFT => {1421 if let CreateItemData::NFT(data) = data {1422 1423 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1424 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1425 } else {1426 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1427 }1428 },1429 CollectionMode::Fungible(_) => {1430 if let CreateItemData::Fungible(_) = data {1431 } else {1432 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1433 }1434 },1435 CollectionMode::ReFungible(_) => {1436 if let CreateItemData::ReFungible(data) = data {14371438 1439 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1440 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1441 } else {1442 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1443 }1444 },1445 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1446 };14471448 Ok(())1449 }14501451 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1452 match data1453 {1454 CreateItemData::NFT(data) => {1455 let item = NftItemType {1456 collection: collection_id,1457 owner,1458 const_data: data.const_data,1459 variable_data: data.variable_data1460 };14611462 Self::add_nft_item(item)?;1463 },1464 CreateItemData::Fungible(_) => {1465 let item = FungibleItemType {1466 collection: collection_id,1467 owner,1468 value: (10 as u128).pow(collection.decimal_points as u32)1469 };14701471 Self::add_fungible_item(item)?;1472 },1473 CreateItemData::ReFungible(data) => {1474 let mut owner_list = Vec::new();1475 let value = (10 as u128).pow(collection.decimal_points as u32);1476 owner_list.push(Ownership {owner: owner.clone(), fraction: value});14771478 let item = ReFungibleItemType {1479 collection: collection_id,1480 owner: owner_list,1481 const_data: data.const_data,1482 variable_data: data.variable_data1483 };14841485 Self::add_refungible_item(item)?;1486 }1487 };148814891490 1491 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));14921493 Ok(())1494 }14951496 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1497 let current_index = <ItemListIndex>::get(item.collection)1498 .checked_add(1)1499 .ok_or(Error::<T>::NumOverflow)?;1500 let itemcopy = item.clone();1501 let owner = item.owner.clone();1502 let value = item.value as u64;15031504 Self::add_token_index(item.collection, current_index, owner.clone())?;15051506 <ItemListIndex>::insert(item.collection, current_index);1507 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15081509 1510 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1511 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1512 1513 1514 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1515 .checked_add(value)1516 .ok_or(Error::<T>::NumOverflow)?;1517 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15181519 Ok(())1520 }15211522 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1523 let current_index = <ItemListIndex>::get(item.collection)1524 .checked_add(1)1525 .ok_or(Error::<T>::NumOverflow)?;1526 let itemcopy = item.clone();15271528 let value = item.owner.first().unwrap().fraction as u64;1529 let owner = item.owner.first().unwrap().owner.clone();15301531 Self::add_token_index(item.collection, current_index, owner.clone())?;15321533 <ItemListIndex>::insert(item.collection, current_index);1534 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);15351536 1537 let block_number: T::BlockNumber = 0.into();1538 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);15391540 1541 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1542 .checked_add(value)1543 .ok_or(Error::<T>::NumOverflow)?;1544 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);15451546 Ok(())1547 }15481549 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1550 let current_index = <ItemListIndex>::get(item.collection)1551 .checked_add(1)1552 .ok_or(Error::<T>::NumOverflow)?;15531554 let item_owner = item.owner.clone();1555 let collection_id = item.collection.clone();1556 Self::add_token_index(collection_id, current_index, item.owner.clone())?;15571558 <ItemListIndex>::insert(collection_id, current_index);1559 <NftItemList<T>>::insert(collection_id, current_index, item);15601561 1562 let block_number: T::BlockNumber = 0.into();1563 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);15641565 1566 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1567 .checked_add(1)1568 .ok_or(Error::<T>::NumOverflow)?;1569 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);15701571 Ok(())1572 }15731574 fn burn_refungible_item(1575 collection_id: CollectionId,1576 item_id: TokenId,1577 owner: T::AccountId,1578 ) -> DispatchResult {1579 ensure!(1580 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1581 Error::<T>::TokenNotFound1582 );1583 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1584 let item = collection1585 .owner1586 .iter()1587 .filter(|&i| i.owner == owner)1588 .next()1589 .unwrap();1590 Self::remove_token_index(collection_id, item_id, owner.clone())?;15911592 1593 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));15941595 1596 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1597 .checked_sub(item.fraction as u64)1598 .ok_or(Error::<T>::NumOverflow)?;1599 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16001601 <ReFungibleItemList<T>>::remove(collection_id, item_id);16021603 Ok(())1604 }16051606 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1607 ensure!(1608 <NftItemList<T>>::contains_key(collection_id, item_id),1609 Error::<T>::TokenNotFound1610 );1611 let item = <NftItemList<T>>::get(collection_id, item_id);1612 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16131614 1615 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16161617 1618 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1619 .checked_sub(1)1620 .ok_or(Error::<T>::NumOverflow)?;1621 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1622 <NftItemList<T>>::remove(collection_id, item_id);16231624 Ok(())1625 }16261627 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1628 ensure!(1629 <FungibleItemList<T>>::contains_key(collection_id, item_id),1630 Error::<T>::TokenNotFound1631 );1632 let item = <FungibleItemList<T>>::get(collection_id, item_id);1633 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;16341635 1636 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));16371638 1639 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1640 .checked_sub(item.value as u64)1641 .ok_or(Error::<T>::NumOverflow)?;1642 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);16431644 <FungibleItemList<T>>::remove(collection_id, item_id);16451646 Ok(())1647 }16481649 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1650 ensure!(1651 <Collection<T>>::contains_key(collection_id),1652 Error::<T>::CollectionNotFound1653 );1654 Ok(())1655 }16561657 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1658 Self::collection_exists(collection_id)?;16591660 let target_collection = <Collection<T>>::get(collection_id);1661 ensure!(1662 subject == target_collection.owner,1663 Error::<T>::NoPermission1664 );16651666 Ok(())1667 }16681669 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1670 let target_collection = <Collection<T>>::get(collection_id);1671 let mut result: bool = subject == target_collection.owner;1672 let exists = <AdminList<T>>::contains_key(collection_id);16731674 if !result & exists {1675 if <AdminList<T>>::get(collection_id).contains(&subject) {1676 result = true1677 }1678 }16791680 result1681 }16821683 fn check_owner_or_admin_permissions(1684 collection_id: CollectionId,1685 subject: T::AccountId,1686 ) -> DispatchResult {1687 Self::collection_exists(collection_id)?;1688 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());16891690 ensure!(1691 result,1692 Error::<T>::NoPermission1693 );1694 Ok(())1695 }16961697 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1698 let target_collection = <Collection<T>>::get(collection_id);16991700 match target_collection.mode {1701 CollectionMode::NFT => {1702 <NftItemList<T>>::get(collection_id, item_id).owner == subject1703 }1704 CollectionMode::Fungible(_) => {1705 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1706 }1707 CollectionMode::ReFungible(_) => {1708 <ReFungibleItemList<T>>::get(collection_id, item_id)1709 .owner1710 .iter()1711 .any(|i| i.owner == subject)1712 }1713 CollectionMode::Invalid => false,1714 }1715 }17161717 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1718 let mes = Error::<T>::AddresNotInWhiteList;1719 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1720 let wl = <WhiteList<T>>::get(collection_id);1721 ensure!(wl.contains(address), mes);17221723 Ok(())1724 }17251726 fn transfer_fungible(1727 collection_id: CollectionId,1728 item_id: TokenId,1729 value: u64,1730 owner: T::AccountId,1731 new_owner: T::AccountId,1732 ) -> DispatchResult {1733 ensure!(1734 <FungibleItemList<T>>::contains_key(collection_id, item_id),1735 Error::<T>::TokenNotFound1736 );17371738 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1739 let amount = full_item.value;17401741 ensure!(amount >= value.into(), Error::<T>::TokenValueTooLow);17421743 1744 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1745 .checked_sub(value)1746 .ok_or(Error::<T>::NumOverflow)?;1747 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);17481749 let mut new_owner_account_id = 0;1750 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1751 if new_owner_items.len() > 0 {1752 new_owner_account_id = new_owner_items[0];1753 }17541755 let val64 = value.into();17561757 1758 if amount == val64 && new_owner_account_id == 0 {1759 1760 1761 let mut new_full_item = full_item.clone();1762 new_full_item.owner = new_owner.clone();1763 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);17641765 1766 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1767 .checked_add(value)1768 .ok_or(Error::<T>::NumOverflow)?;1769 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);17701771 1772 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1773 } else {1774 let mut new_full_item = full_item.clone();1775 new_full_item.value -= val64;17761777 1778 if new_owner_account_id > 0 {1779 1780 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1781 item.value += val64;17821783 1784 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1785 .checked_add(value)1786 .ok_or(Error::<T>::NumOverflow)?;1787 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);17881789 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1790 } else {1791 1792 let item = FungibleItemType {1793 collection: collection_id,1794 owner: new_owner.clone(),1795 value: val64,1796 };17971798 Self::add_fungible_item(item)?;1799 }18001801 if amount == val64 {1802 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;18031804 1805 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1806 <FungibleItemList<T>>::remove(collection_id, item_id);1807 }18081809 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1810 }18111812 Ok(())1813 }18141815 fn transfer_refungible(1816 collection_id: CollectionId,1817 item_id: TokenId,1818 value: u64,1819 owner: T::AccountId,1820 new_owner: T::AccountId,1821 ) -> DispatchResult {1822 ensure!(1823 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1824 Error::<T>::TokenNotFound1825 );18261827 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1828 let item = full_item1829 .owner1830 .iter()1831 .filter(|i| i.owner == owner)1832 .next()1833 .ok_or(Error::<T>::NumOverflow)?;1834 let amount = item.fraction;18351836 ensure!(amount >= value.into(), Error::<T>::TokenValueTooLow);18371838 1839 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1840 .checked_sub(value)1841 .ok_or(Error::<T>::NumOverflow)?;1842 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);18431844 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1845 .checked_add(value)1846 .ok_or(Error::<T>::NumOverflow)?;1847 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18481849 let old_owner = item.owner.clone();1850 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);1851 let val64 = value.into();18521853 1854 if amount == val64 && !new_owner_has_account {1855 1856 1857 let mut new_full_item = full_item.clone();1858 new_full_item1859 .owner1860 .iter_mut()1861 .find(|i| i.owner == owner)1862 .unwrap()1863 .owner = new_owner.clone();1864 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18651866 1867 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1868 } else {1869 let mut new_full_item = full_item.clone();1870 new_full_item1871 .owner1872 .iter_mut()1873 .find(|i| i.owner == owner)1874 .unwrap()1875 .fraction -= val64;18761877 1878 if new_owner_has_account {1879 1880 new_full_item1881 .owner1882 .iter_mut()1883 .find(|i| i.owner == new_owner)1884 .unwrap()1885 .fraction += val64;1886 } else {1887 1888 new_full_item.owner.push(Ownership {1889 owner: new_owner.clone(),1890 fraction: val64,1891 });1892 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1893 }18941895 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1896 }18971898 Ok(())1899 }19001901 fn transfer_nft(1902 collection_id: CollectionId,1903 item_id: TokenId,1904 sender: T::AccountId,1905 new_owner: T::AccountId,1906 ) -> DispatchResult {1907 ensure!(1908 <NftItemList<T>>::contains_key(collection_id, item_id),1909 Error::<T>::TokenNotFound1910 );19111912 let mut item = <NftItemList<T>>::get(collection_id, item_id);19131914 ensure!(1915 sender == item.owner,1916 Error::<T>::MustBeTokenOwner1917 );19181919 1920 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1921 .checked_sub(1)1922 .ok_or(Error::<T>::NumOverflow)?;1923 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19241925 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1926 .checked_add(1)1927 .ok_or(Error::<T>::NumOverflow)?;1928 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19291930 1931 let old_owner = item.owner.clone();1932 item.owner = new_owner.clone();1933 <NftItemList<T>>::insert(collection_id, item_id, item);19341935 1936 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;19371938 1939 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));1940 Ok(())1941 }1942 1943 fn item_exists(1944 collection_id: CollectionId,1945 item_id: TokenId,1946 mode: &CollectionMode1947 ) -> DispatchResult {1948 match mode {1949 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1950 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1951 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),1952 _ => ()1953 };1954 1955 Ok(())1956 }19571958 fn set_re_fungible_variable_data(1959 collection_id: CollectionId,1960 item_id: TokenId,1961 data: Vec<u8>1962 ) -> DispatchResult {1963 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);19641965 item.variable_data = data;19661967 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);19681969 Ok(())1970 }19711972 fn set_nft_variable_data(1973 collection_id: CollectionId,1974 item_id: TokenId,1975 data: Vec<u8>1976 ) -> DispatchResult {1977 let mut item = <NftItemList<T>>::get(collection_id, item_id);1978 1979 item.variable_data = data;19801981 <NftItemList<T>>::insert(collection_id, item_id, item);1982 1983 Ok(())1984 }19851986 fn init_collection(item: &CollectionType<T::AccountId>) {1987 1988 assert!(1989 item.decimal_points <= MAX_DECIMAL_POINTS,1990 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"1991 );1992 assert!(1993 item.name.len() <= 64,1994 "Collection name can not be longer than 63 char"1995 );1996 assert!(1997 item.name.len() <= 256,1998 "Collection description can not be longer than 255 char"1999 );2000 assert!(2001 item.token_prefix.len() <= 16,2002 "Token prefix can not be longer than 15 char"2003 );20042005 2006 let next_id = CreatedCollectionCount::get()2007 .checked_add(1)2008 .unwrap();20092010 CreatedCollectionCount::put(next_id);2011 }20122013 fn init_nft_token(item: &NftItemType<T::AccountId>) {2014 let current_index = <ItemListIndex>::get(item.collection)2015 .checked_add(1)2016 .unwrap();20172018 let item_owner = item.owner.clone();2019 let collection_id = item.collection.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(item: &FungibleItemType<T::AccountId>) {2032 let current_index = <ItemListIndex>::get(item.collection)2033 .checked_add(1)2034 .unwrap();2035 let owner = item.owner.clone();2036 let value = item.value as u64;20372038 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20392040 <ItemListIndex>::insert(item.collection, current_index);20412042 2043 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2044 .checked_add(value)2045 .unwrap();2046 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2047 }20482049 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2050 let current_index = <ItemListIndex>::get(item.collection)2051 .checked_add(1)2052 .unwrap();20532054 let value = item.owner.first().unwrap().fraction as u64;2055 let owner = item.owner.first().unwrap().owner.clone();20562057 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();20582059 <ItemListIndex>::insert(item.collection, current_index);20602061 2062 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2063 .checked_add(value)2064 .unwrap();2065 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2066 }20672068 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {20692070 2071 if <AccountItemCount<T>>::contains_key(owner.clone()) {20722073 2074 let count = <AccountItemCount<T>>::get(owner.clone());2075 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);20762077 <AccountItemCount<T>>::insert(owner.clone(), count2078 .checked_add(1)2079 .ok_or(Error::<T>::NumOverflow)?);2080 }2081 else {2082 <AccountItemCount<T>>::insert(owner.clone(), 1);2083 }20842085 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2086 if list_exists {2087 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2088 let item_contains = list.contains(&item_index.clone());20892090 if !item_contains {2091 list.push(item_index.clone());2092 }20932094 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2095 } else {2096 let mut itm = Vec::new();2097 itm.push(item_index.clone());2098 <AddressTokens<T>>::insert(collection_id, owner, itm);2099 2100 }21012102 Ok(())2103 }21042105 fn remove_token_index(2106 collection_id: CollectionId,2107 item_index: TokenId,2108 owner: T::AccountId,2109 ) -> DispatchResult {21102111 2112 <AccountItemCount<T>>::insert(owner.clone(), 2113 <AccountItemCount<T>>::get(owner.clone())2114 .checked_sub(1)2115 .ok_or(Error::<T>::NumOverflow)?);211621172118 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2119 if list_exists {2120 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2121 let item_contains = list.contains(&item_index.clone());21222123 if item_contains {2124 list.retain(|&item| item != item_index);2125 <AddressTokens<T>>::insert(collection_id, owner, list);2126 }2127 }21282129 Ok(())2130 }21312132 fn move_token_index(2133 collection_id: CollectionId,2134 item_index: TokenId,2135 old_owner: T::AccountId,2136 new_owner: T::AccountId,2137 ) -> DispatchResult {2138 Self::remove_token_index(collection_id, item_index, old_owner)?;2139 Self::add_token_index(collection_id, item_index, new_owner)?;21402141 Ok(())2142 }2143}2144214521462147214821492150pub type Multiplier = FixedU128;21512152type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2153 <T as system::Trait>::AccountId,2154>>::Balance;2155type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2156 <T as system::Trait>::AccountId,2157>>::NegativeImbalance;2158215921602161#[derive(Encode, Decode, Clone, Eq, PartialEq)]2162pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2163 #[codec(compact)] BalanceOf<T>2164);21652166impl<T: Trait + Send + Sync> sp_std::fmt::Debug2167 for ChargeTransactionPayment<T>2168{2169 #[cfg(feature = "std")]2170 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2171 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2172 }2173 #[cfg(not(feature = "std"))]2174 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2175 Ok(())2176 }2177}21782179impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2180where2181 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2182 BalanceOf<T>: Send + Sync + FixedPointOperand,2183{2184 2185 pub fn from(fee: BalanceOf<T>) -> Self {2186 Self(fee)2187 }21882189 pub fn traditional_fee(2190 len: usize,2191 info: &DispatchInfoOf<T::Call>,2192 tip: BalanceOf<T>,2193 ) -> BalanceOf<T>2194 where2195 T::Call: Dispatchable<Info = DispatchInfo>,2196 {2197 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2198 }21992200 fn withdraw_fee(2201 &self,2202 who: &T::AccountId,2203 call: &T::Call,2204 info: &DispatchInfoOf<T::Call>,2205 len: usize,2206 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2207 let tip = self.0;22082209 2210 2211 2212 2213 2214 2215 2216 let fee = Self::traditional_fee(len, info, tip);22172218 2219 2220 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2221 Some(Call::create_item(collection_id, _properties, _owner)) => {2222 <Collection<T>>::get(collection_id).sponsor2223 }2224 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2225 let _collection_mode = <Collection<T>>::get(collection_id).mode;22262227 2228 let sponsor_transfer = match _collection_mode {2229 CollectionMode::NFT => {2230 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2231 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2232 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2233 if block_number >= limit_time {2234 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2235 true2236 }2237 else {2238 false2239 }2240 }2241 CollectionMode::Fungible(_) => {2242 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2243 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2244 if basket.iter().any(|i| i.address == _new_owner.clone())2245 {2246 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2247 let limit_time = item.start_block + ChainLimit::get().fungible_sponsor_transfer_timeout.into();2248 if block_number >= limit_time {2249 basket.retain(|x| x.address == item.address);2250 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2251 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2252 true2253 }2254 else {2255 false2256 }2257 }2258 else {2259 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2260 true2261 }2262 }2263 CollectionMode::ReFungible(_) => {2264 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2265 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2266 let limit_time = basket + ChainLimit::get().nft_sponsor_transfer_timeout.into();2267 if block_number >= limit_time {2268 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2269 true2270 } else {2271 false2272 }2273 }2274 _ => {2275 false2276 },2277 };22782279 if !sponsor_transfer {2280 T::AccountId::default()2281 } else {2282 <Collection<T>>::get(collection_id).sponsor2283 }2284 }22852286 _ => T::AccountId::default(),2287 };22882289 2290 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {22912292 2293 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {22942295 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2296 code_hash,2297 &data,2298 &who,2299 );2300 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());23012302 T::AccountId::default()2303 },23042305 2306 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {23072308 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());23092310 let mut sponsor_transfer = false;2311 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2312 let last_tx_block = <ContractSponsorBasket<T>>::get(&called_contract);2313 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2314 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2315 let limit_time = last_tx_block + rate_limit;23162317 if block_number >= limit_time {2318 <ContractSponsorBasket<T>>::insert(called_contract.clone(), block_number);2319 sponsor_transfer = true;2320 }2321 } else {2322 sponsor_transfer = false;2323 }2324 2325 2326 let mut sp = T::AccountId::default();2327 if sponsor_transfer {2328 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2329 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2330 sp = called_contract;2331 }2332 }2333 }23342335 sp2336 },23372338 _ => sponsor,2339 };23402341 let mut who_pays_fee: T::AccountId = sponsor.clone();2342 if sponsor == T::AccountId::default() {2343 who_pays_fee = who.clone();2344 }23452346 2347 if fee.is_zero() {2348 return Ok((fee, None));2349 }23502351 match <T as transaction_payment::Trait>::Currency::withdraw(2352 &who_pays_fee,2353 fee,2354 if tip.is_zero() {2355 WithdrawReason::TransactionPayment.into()2356 } else {2357 WithdrawReason::TransactionPayment | WithdrawReason::Tip2358 },2359 ExistenceRequirement::KeepAlive,2360 ) {2361 Ok(imbalance) => Ok((fee, Some(imbalance))),2362 Err(_) => Err(InvalidTransaction::Payment.into()),2363 }2364 }2365}236623672368impl<T: Trait + Send + Sync> SignedExtension2369 for ChargeTransactionPayment<T>2370where2371 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2372 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2373{2374 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2375 type AccountId = T::AccountId;2376 type Call = T::Call;2377 type AdditionalSigned = ();2378 type Pre = (2379 BalanceOf<T>,2380 Self::AccountId,2381 Option<NegativeImbalanceOf<T>>,2382 BalanceOf<T>,2383 );2384 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2385 Ok(())2386 }23872388 fn validate(2389 &self,2390 _who: &Self::AccountId,2391 _call: &Self::Call,2392 _info: &DispatchInfoOf<Self::Call>,2393 _len: usize,2394 ) -> TransactionValidity {2395 Ok(ValidTransaction::default())2396 }23972398 fn pre_dispatch(2399 self,2400 who: &Self::AccountId,2401 call: &Self::Call,2402 info: &DispatchInfoOf<Self::Call>,2403 len: usize,2404 ) -> Result<Self::Pre, TransactionValidityError> {2405 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2406 Ok((self.0, who.clone(), imbalance, fee))2407 }24082409 fn post_dispatch(2410 pre: Self::Pre,2411 info: &DispatchInfoOf<Self::Call>,2412 post_info: &PostDispatchInfoOf<Self::Call>,2413 len: usize,2414 _result: &DispatchResult,2415 ) -> Result<(), TransactionValidityError> {2416 let (tip, who, imbalance, fee) = pre;2417 if let Some(payed) = imbalance {2418 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2419 len as u32, info, post_info, tip,2420 );2421 let refund = fee.saturating_sub(actual_fee);2422 let actual_payment =2423 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2424 &who, refund,2425 ) {2426 Ok(refund_imbalance) => {2427 2428 2429 match payed.offset(refund_imbalance) {2430 Ok(actual_payment) => actual_payment,2431 Err(_) => return Err(InvalidTransaction::Payment.into()),2432 }2433 }2434 2435 2436 Err(_) => payed,2437 };2438 let imbalances = actual_payment.split(tip);2439 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2440 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2441 );2442 }2443 Ok(())2444 }2445}24462447