1#![recursion_limit = "1024"]23#![cfg_attr(not(feature = "std"), no_std)]45#[cfg(feature = "std")]6pub use std::*;78#[cfg(feature = "std")]9pub use serde::*;1011use codec::{Decode, Encode};12pub use frame_support::{13 construct_runtime, decl_event, decl_module, decl_storage, decl_error,14 dispatch::DispatchResult,15 ensure, fail, parameter_types,16 traits::{17 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,18 Randomness, WithdrawReason,19 },20 weights::{21 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},22 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,23 WeightToFeePolynomial,24 },25 IsSubType, StorageValue,26};2728use frame_system::{self as system, ensure_signed, ensure_root};29use sp_runtime::sp_std::prelude::Vec;30use sp_runtime::{31 traits::{32 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,33 },34 transaction_validity::{35 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,36 },37 FixedPointOperand, FixedU128,38};39use pallet_contracts::ContractAddressFor;40use sp_runtime::traits::StaticLookup;4142#[cfg(test)]43mod mock;4445#[cfg(test)]46mod tests;4748mod default_weights;4950pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;51pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;52pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5354555657pub type CollectionId = u32;58pub type TokenId = u32;59pub type DecimalPoints = u8;6061#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]62#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]63pub enum CollectionMode {64 Invalid,65 NFT,66 67 Fungible(DecimalPoints),68 69 ReFungible(DecimalPoints),70}7172impl Into<u8> for CollectionMode {73 fn into(self) -> u8 {74 match self {75 CollectionMode::Invalid => 0,76 CollectionMode::NFT => 1,77 CollectionMode::Fungible(_) => 2,78 CollectionMode::ReFungible(_) => 3,79 }80 }81}8283#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]84#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]85pub enum AccessMode {86 Normal,87 WhiteList,88}89impl Default for AccessMode {90 fn default() -> Self {91 Self::Normal92 }93}9495impl Default for CollectionMode {96 fn default() -> Self {97 Self::Invalid98 }99}100101#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]102#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]103pub enum SchemaVersion {104 ImageURL,105 Unique,106}107impl Default for SchemaVersion {108 fn default() -> Self {109 Self::ImageURL110 }111}112113#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]114#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]115pub struct Ownership<AccountId> {116 pub owner: AccountId,117 pub fraction: u128,118}119120#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]121#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]122pub struct CollectionType<AccountId> {123 pub owner: AccountId,124 pub mode: CollectionMode,125 pub access: AccessMode,126 pub decimal_points: DecimalPoints,127 pub name: Vec<u16>, 128 pub description: Vec<u16>, 129 pub token_prefix: Vec<u8>, 130 pub mint_mode: bool,131 pub offchain_schema: Vec<u8>,132 pub schema_version: SchemaVersion,133 pub sponsor: AccountId, 134 pub unconfirmed_sponsor: AccountId, 135 pub limits: CollectionLimits, 136 pub variable_on_chain_schema: Vec<u8>, 137 pub const_on_chain_schema: Vec<u8>, 138}139140#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]141#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]142pub struct NftItemType<AccountId> {143 pub collection: CollectionId,144 pub owner: 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 FungibleItemType<AccountId> {152 pub collection: CollectionId,153 pub owner: AccountId,154 pub value: u128,155}156157#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]158#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]159pub struct ReFungibleItemType<AccountId> {160 pub collection: CollectionId,161 pub owner: Vec<Ownership<AccountId>>,162 pub const_data: Vec<u8>,163 pub variable_data: Vec<u8>,164}165166#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]167#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]168pub struct ApprovePermissions<AccountId> {169 pub approved: AccountId,170 pub amount: u128,171}172173#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]174#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]175pub struct VestingItem<AccountId, Moment> {176 pub sender: AccountId,177 pub recipient: AccountId,178 pub collection_id: CollectionId,179 pub item_id: TokenId,180 pub amount: u64,181 pub vesting_date: Moment,182}183184#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]185#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]186pub struct BasketItem<AccountId, BlockNumber> {187 pub address: AccountId,188 pub start_block: BlockNumber,189}190191#[derive(Encode, Decode, Debug, Clone, PartialEq)]192#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]193pub struct CollectionLimits {194 pub account_token_ownership_limit: u32,195 pub sponsored_data_size: u32,196 pub token_limit: u32,197198 199 pub sponsor_transfer_timeout: u32,200}201202impl Default for CollectionLimits {203 fn default() -> CollectionLimits {204 CollectionLimits { 205 account_token_ownership_limit: 10_000_000, 206 token_limit: u32::max_value(),207 sponsored_data_size: u32::max_value(), 208 sponsor_transfer_timeout: 14400 }209 }210}211212#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]213#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]214pub struct ChainLimits {215 pub collection_numbers_limit: u32,216 pub account_token_ownership_limit: u32,217 pub collections_admins_limit: u64,218 pub custom_data_limit: u32,219220 221 pub nft_sponsor_transfer_timeout: u32,222 pub fungible_sponsor_transfer_timeout: u32,223 pub refungible_sponsor_transfer_timeout: u32,224}225226pub trait WeightInfo {227 fn create_collection() -> Weight;228 fn destroy_collection() -> Weight;229 fn add_to_white_list() -> Weight;230 fn remove_from_white_list() -> Weight;231 fn set_public_access_mode() -> Weight;232 fn set_mint_permission() -> Weight;233 fn change_collection_owner() -> Weight;234 fn add_collection_admin() -> Weight;235 fn remove_collection_admin() -> Weight;236 fn set_collection_sponsor() -> Weight;237 fn confirm_sponsorship() -> Weight;238 fn remove_collection_sponsor() -> Weight;239 fn create_item(s: usize) -> Weight;240 fn burn_item() -> Weight;241 fn transfer() -> Weight;242 fn approve() -> Weight;243 fn transfer_from() -> Weight;244 fn set_offchain_schema() -> Weight;245 fn set_const_on_chain_schema() -> Weight;246 fn set_variable_on_chain_schema() -> Weight;247 fn set_variable_meta_data() -> Weight;248 fn enable_contract_sponsoring() -> Weight;249}250251#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]252#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]253pub struct CreateNftData {254 pub const_data: Vec<u8>,255 pub variable_data: Vec<u8>,256}257258#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]259#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]260pub struct CreateFungibleData {261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateReFungibleData {266 pub const_data: Vec<u8>,267 pub variable_data: Vec<u8>,268}269270#[derive(Encode, Decode, Debug, Clone, PartialEq)]271#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]272pub enum CreateItemData {273 NFT(CreateNftData),274 Fungible(CreateFungibleData),275 ReFungible(CreateReFungibleData),276}277278impl CreateItemData {279 pub fn len(&self) -> usize {280 let len = match self {281 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),282 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),283 _ => 0284 };285 286 return len;287 }288}289290impl From<CreateNftData> for CreateItemData {291 fn from(item: CreateNftData) -> Self {292 CreateItemData::NFT(item)293 }294}295296impl From<CreateReFungibleData> for CreateItemData {297 fn from(item: CreateReFungibleData) -> Self {298 CreateItemData::ReFungible(item)299 }300}301302impl From<CreateFungibleData> for CreateItemData {303 fn from(item: CreateFungibleData) -> Self {304 CreateItemData::Fungible(item)305 }306}307308309decl_error! {310 311 pub enum Error for Module<T: Trait> {312 313 TotalCollectionsLimitExceeded,314 315 CollectionDecimalPointLimitExceeded, 316 317 CollectionNameLimitExceeded, 318 319 CollectionDescriptionLimitExceeded, 320 321 CollectionTokenPrefixLimitExceeded,322 323 CollectionNotFound,324 325 TokenNotFound,326 327 NumOverflow, 328 329 AlreadyAdmin, 330 331 NoPermission,332 333 ConfirmUnsetSponsorFail,334 335 PublicMintingNotAllowed,336 337 MustBeTokenOwner,338 339 TokenValueTooLow,340 341 NftSizeLimitExceeded,342 343 ApproveNotFound,344 345 TokenValueNotEnough,346 347 ApproveRequired,348 349 AddresNotInWhiteList,350 351 CollectionAdminsLimitExceeded,352 353 AddressOwnershipLimitExceeded,354 355 EmptyArgument,356 357 TokenConstDataLimitExceeded,358 359 TokenVariableDataLimitExceeded,360 361 NotNftDataUsedToMintNftCollectionToken,362 363 NotFungibleDataUsedToMintFungibleCollectionToken,364 365 NotReFungibleDataUsedToMintReFungibleCollectionToken,366 367 UnexpectedCollectionType,368 369 CantStoreMetadataInFungibleTokens,370 371 CollectionTokenLimitExceeded,372 373 AccountTokenLimitExceeded,374 375 CollectionLimitBoundsExceeded376 }377}378379pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {380 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;381382 383 type WeightInfo: WeightInfo;384}385386#[cfg(feature = "runtime-benchmarks")]387mod benchmarking;388389390391decl_storage! {392 trait Store for Module<T: Trait> as Nft {393394 395 NextCollectionID: CollectionId;396 CreatedCollectionCount: u32;397 ChainVersion: u64;398 ItemListIndex: map hasher(identity) CollectionId => TokenId;399400 401 pub ChainLimit get(fn chain_limit) config(): ChainLimits;402403 404 CollectionCount: u32;405 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;406407 408 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;409 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;410 pub WhiteList get(fn white_list): map hasher(identity) CollectionId => Vec<T::AccountId>;411412 413 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;414415 416 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;417418 419 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;420 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;421 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;422423 424 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;425426 427 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;428 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;429 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;430431 432 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;433 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;434 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;435 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;436 }437 add_extra_genesis {438 build(|config: &GenesisConfig<T>| {439 440 for (_num, _c) in &config.collection {441 <Module<T>>::init_collection(_c);442 }443444 for (_num, _q, _i) in &config.nft_item_id {445 <Module<T>>::init_nft_token(_i);446 }447448 for (_num, _q, _i) in &config.fungible_item_id {449 <Module<T>>::init_fungible_token(_i);450 }451452 for (_num, _q, _i) in &config.refungible_item_id {453 <Module<T>>::init_refungible_token(_i);454 }455 })456 }457}458459decl_event!(460 pub enum Event<T>461 where462 AccountId = <T as system::Trait>::AccountId,463 {464 465 466 467 468 469 470 471 472 473 Created(CollectionId, u8, AccountId),474475 476 477 478 479 480 481 482 ItemCreated(CollectionId, TokenId),483484 485 486 487 488 489 490 491 ItemDestroyed(CollectionId, TokenId),492 }493);494495decl_module! {496 pub struct Module<T: Trait> for enum Call where origin: T::Origin {497498 fn deposit_event() = default;499 type Error = Error<T>;500501 fn on_initialize(now: T::BlockNumber) -> Weight {502503 if ChainVersion::get() < 2504 {505 let value = NextCollectionID::get();506 CreatedCollectionCount::put(value);507 ChainVersion::put(2);508 }509510 0511 }512513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 #[weight = T::WeightInfo::create_collection()]530 pub fn create_collection(origin,531 collection_name: Vec<u16>,532 collection_description: Vec<u16>,533 token_prefix: Vec<u8>,534 mode: CollectionMode) -> DispatchResult {535536 537 let who = ensure_signed(origin)?;538539 let decimal_points = match mode {540 CollectionMode::Fungible(points) => points,541 CollectionMode::ReFungible(points) => points,542 _ => 0543 };544545 546 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);547548 549 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);550551 let mut name = collection_name.to_vec();552 name.push(0);553 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);554555 let mut description = collection_description.to_vec();556 description.push(0);557 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);558559 let mut prefix = token_prefix.to_vec();560 prefix.push(0);561 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);562563 564 let next_id = CreatedCollectionCount::get()565 .checked_add(1)566 .ok_or(Error::<T>::NumOverflow)?;567568 569 let total = CollectionCount::get()570 .checked_add(1)571 .ok_or(Error::<T>::NumOverflow)?;572573 CreatedCollectionCount::put(next_id);574 CollectionCount::put(total);575576 577 let new_collection = CollectionType {578 owner: who.clone(),579 name: name,580 mode: mode.clone(),581 mint_mode: false,582 access: AccessMode::Normal,583 description: description,584 decimal_points: decimal_points,585 token_prefix: prefix,586 offchain_schema: Vec::new(),587 schema_version: SchemaVersion::ImageURL,588 sponsor: T::AccountId::default(),589 unconfirmed_sponsor: T::AccountId::default(),590 variable_on_chain_schema: Vec::new(),591 const_on_chain_schema: Vec::new(),592 limits: CollectionLimits::default(),593 };594595 596 <Collection<T>>::insert(next_id, new_collection);597598 599 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));600601 Ok(())602 }603604 605 606 607 608 609 610 611 612 613 #[weight = T::WeightInfo::destroy_collection()]614 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {615616 let sender = ensure_signed(origin)?;617 Self::check_owner_permissions(collection_id, sender)?;618619 <AddressTokens<T>>::remove_prefix(collection_id);620 <ApprovedList<T>>::remove_prefix(collection_id);621 <Balance<T>>::remove_prefix(collection_id);622 <ItemListIndex>::remove(collection_id);623 <AdminList<T>>::remove(collection_id);624 <Collection<T>>::remove(collection_id);625 <WhiteList<T>>::remove(collection_id);626627 <NftItemList<T>>::remove_prefix(collection_id);628 <FungibleItemList<T>>::remove_prefix(collection_id);629 <ReFungibleItemList<T>>::remove_prefix(collection_id);630631 <NftTransferBasket<T>>::remove_prefix(collection_id);632 <FungibleTransferBasket<T>>::remove_prefix(collection_id);633 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);634635 if CollectionCount::get() > 0636 {637 638 let total = CollectionCount::get()639 .checked_sub(1)640 .ok_or(Error::<T>::NumOverflow)?;641642 CollectionCount::put(total);643 }644645 Ok(())646 }647648 649 650 651 652 653 654 655 656 657 658 659 660 #[weight = T::WeightInfo::add_to_white_list()]661 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{662663 let sender = ensure_signed(origin)?;664 Self::check_owner_or_admin_permissions(collection_id, sender)?;665666 let mut white_list_collection: Vec<T::AccountId>;667 if <WhiteList<T>>::contains_key(collection_id) {668 white_list_collection = <WhiteList<T>>::get(collection_id);669 if !white_list_collection.contains(&address.clone())670 {671 white_list_collection.push(address.clone());672 }673 }674 else {675 white_list_collection = Vec::new();676 white_list_collection.push(address.clone());677 }678679 <WhiteList<T>>::insert(collection_id, white_list_collection);680 Ok(())681 }682683 684 685 686 687 688 689 690 691 692 693 694 695 #[weight = T::WeightInfo::remove_from_white_list()]696 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{697698 let sender = ensure_signed(origin)?;699 Self::check_owner_or_admin_permissions(collection_id, sender)?;700701 if <WhiteList<T>>::contains_key(collection_id) {702 let mut white_list_collection = <WhiteList<T>>::get(collection_id);703 if white_list_collection.contains(&address.clone())704 {705 white_list_collection.retain(|i| *i != address.clone());706 <WhiteList<T>>::insert(collection_id, white_list_collection);707 }708 }709710 Ok(())711 }712713 714 715 716 717 718 719 720 721 722 723 724 #[weight = T::WeightInfo::set_public_access_mode()]725 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> 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.access = mode;732 <Collection<T>>::insert(collection_id, target_collection);733734 Ok(())735 }736737 738 739 740 741 742 743 744 745 746 747 748 749 750 #[weight = T::WeightInfo::set_mint_permission()]751 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult752 {753 let sender = ensure_signed(origin)?;754755 Self::check_owner_permissions(collection_id, sender)?;756 let mut target_collection = <Collection<T>>::get(collection_id);757 target_collection.mint_mode = mint_permission;758 <Collection<T>>::insert(collection_id, target_collection);759760 Ok(())761 }762763 764 765 766 767 768 769 770 771 772 773 774 #[weight = T::WeightInfo::change_collection_owner()]775 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {776777 let sender = ensure_signed(origin)?;778 Self::check_owner_permissions(collection_id, sender)?;779 let mut target_collection = <Collection<T>>::get(collection_id);780 target_collection.owner = new_owner;781 <Collection<T>>::insert(collection_id, target_collection);782783 Ok(())784 }785786 787 788 789 790 791 792 793 794 795 796 797 798 799 #[weight = T::WeightInfo::add_collection_admin()]800 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {801802 let sender = ensure_signed(origin)?;803 Self::check_owner_or_admin_permissions(collection_id, sender)?;804 let mut admin_arr: Vec<T::AccountId> = Vec::new();805806 if <AdminList<T>>::contains_key(collection_id)807 {808 admin_arr = <AdminList<T>>::get(collection_id);809 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);810 }811812 813 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);814815 admin_arr.push(new_admin_id);816 <AdminList<T>>::insert(collection_id, admin_arr);817818 Ok(())819 }820821 822 823 824 825 826 827 828 829 830 831 832 833 #[weight = T::WeightInfo::remove_collection_admin()]834 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {835836 let sender = ensure_signed(origin)?;837 Self::check_owner_or_admin_permissions(collection_id, sender)?;838839 if <AdminList<T>>::contains_key(collection_id)840 {841 let mut admin_arr = <AdminList<T>>::get(collection_id);842 admin_arr.retain(|i| *i != account_id);843 <AdminList<T>>::insert(collection_id, admin_arr);844 }845846 Ok(())847 }848849 850 851 852 853 854 855 856 857 858 #[weight = T::WeightInfo::set_collection_sponsor()]859 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {860861 let sender = ensure_signed(origin)?;862 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);863864 let mut target_collection = <Collection<T>>::get(collection_id);865 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);866867 target_collection.unconfirmed_sponsor = new_sponsor;868 <Collection<T>>::insert(collection_id, target_collection);869870 Ok(())871 }872873 874 875 876 877 878 879 880 #[weight = T::WeightInfo::confirm_sponsorship()]881 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {882883 let sender = ensure_signed(origin)?;884 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);885886 let mut target_collection = <Collection<T>>::get(collection_id);887 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);888889 target_collection.sponsor = target_collection.unconfirmed_sponsor;890 target_collection.unconfirmed_sponsor = T::AccountId::default();891 <Collection<T>>::insert(collection_id, target_collection);892893 Ok(())894 }895896 897 898 899 900 901 902 903 904 905 #[weight = T::WeightInfo::remove_collection_sponsor()]906 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {907908 let sender = ensure_signed(origin)?;909 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);910911 let mut target_collection = <Collection<T>>::get(collection_id);912 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);913914 target_collection.sponsor = T::AccountId::default();915 <Collection<T>>::insert(collection_id, target_collection);916917 Ok(())918 }919920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943944 #[weight = T::WeightInfo::create_item(data.len())]945 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {946947 let sender = ensure_signed(origin)?;948949 Self::collection_exists(collection_id)?;950951 let target_collection = <Collection<T>>::get(collection_id);952953 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;954 Self::validate_create_item_args(&target_collection, &data)?;955 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;956957 Ok(())958 }959960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 #[weight = T::WeightInfo::create_item(items_data.into_iter()979 .map(|data| { data.len() })980 .sum())]981 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {982983 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);984 let sender = ensure_signed(origin)?;985986 Self::collection_exists(collection_id)?;987 let target_collection = <Collection<T>>::get(collection_id);988989 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;990991 for data in &items_data {992 Self::validate_create_item_args(&target_collection, data)?;993 }994 for data in &items_data {995 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;996 }997998 Ok(())999 }10001001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 #[weight = T::WeightInfo::burn_item()]1015 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10161017 let sender = ensure_signed(origin)?;1018 Self::collection_exists(collection_id)?;10191020 1021 let target_collection = <Collection<T>>::get(collection_id);1022 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1023 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1024 Error::<T>::NoPermission);10251026 if target_collection.access == AccessMode::WhiteList {1027 Self::check_white_list(collection_id, &sender)?;1028 }10291030 match target_collection.mode1031 {1032 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1033 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1034 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1035 _ => ()1036 };10371038 1039 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10401041 Ok(())1042 }10431044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 #[weight = T::WeightInfo::transfer()]1068 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10691070 let sender = ensure_signed(origin)?;1071 let target_collection = <Collection<T>>::get(collection_id);10721073 1074 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10751076 1077 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1078 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1079 Error::<T>::NoPermission);10801081 if target_collection.access == AccessMode::WhiteList {1082 Self::check_white_list(collection_id, &sender)?;1083 Self::check_white_list(collection_id, &recipient)?;1084 }10851086 match target_collection.mode1087 {1088 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1089 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1090 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1091 _ => ()1092 };10931094 Ok(())1095 }10961097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 #[weight = T::WeightInfo::approve()]1113 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11141115 let sender = ensure_signed(origin)?;11161117 1118 let target_collection = <Collection<T>>::get(collection_id);1119 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1120 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1121 Error::<T>::NoPermission);11221123 if target_collection.access == AccessMode::WhiteList {1124 Self::check_white_list(collection_id, &sender)?;1125 Self::check_white_list(collection_id, &approved)?;1126 }11271128 1129 let amount = 100000000;11301131 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1132 if list_exists {11331134 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1135 let item_contains = list.iter().any(|i| i.approved == approved);11361137 if !item_contains {1138 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1139 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1140 }1141 } else {11421143 let mut list = Vec::new();1144 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1145 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1146 }11471148 Ok(())1149 }1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 #[weight = T::WeightInfo::transfer_from()]1171 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11721173 let sender = ensure_signed(origin)?;1174 let mut appoved_transfer = false;11751176 1177 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1178 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1179 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1180 if opt_item.is_some()1181 {1182 appoved_transfer = true;1183 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1184 }1185 }11861187 let target_collection = <Collection<T>>::get(collection_id);11881189 1190 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11911192 1193 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1194 Error::<T>::NoPermission);11951196 if target_collection.access == AccessMode::WhiteList {1197 Self::check_white_list(collection_id, &sender)?;1198 Self::check_white_list(collection_id, &recipient)?;1199 }12001201 1202 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1203 .into_iter().filter(|i| i.approved != sender.clone()).collect();1204 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);120512061207 match target_collection.mode1208 {1209 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1210 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1211 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1212 _ => ()1213 };12141215 Ok(())1216 }12171218 #[weight = 0]1219 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12201221 1222 1223 1224 12251226 12271228 12291230 Ok(())1231 }12321233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 #[weight = T::WeightInfo::set_variable_meta_data()]1246 pub fn set_variable_meta_data (1247 origin,1248 collection_id: CollectionId,1249 item_id: TokenId,1250 data: Vec<u8>1251 ) -> DispatchResult {1252 let sender = ensure_signed(origin)?;1253 1254 Self::collection_exists(collection_id)?;1255 1256 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12571258 1259 let target_collection = <Collection<T>>::get(collection_id);1260 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1261 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1262 Error::<T>::NoPermission);12631264 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12651266 match target_collection.mode1267 {1268 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1269 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1270 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1271 _ => fail!(Error::<T>::UnexpectedCollectionType)1272 };12731274 Ok(())1275 }1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 #[weight = 0]1292 pub fn set_schema_version(1293 origin,1294 collection_id: CollectionId,1295 version: SchemaVersion1296 ) -> DispatchResult {1297 let sender = ensure_signed(origin)?;1298 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1299 let mut target_collection = <Collection<T>>::get(collection_id);1300 target_collection.schema_version = version;1301 <Collection<T>>::insert(collection_id, target_collection);13021303 Ok(())1304 }13051306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 #[weight = T::WeightInfo::set_offchain_schema()]1319 pub fn set_offchain_schema(1320 origin,1321 collection_id: CollectionId,1322 schema: Vec<u8>1323 ) -> DispatchResult {1324 let sender = ensure_signed(origin)?;1325 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13261327 let mut target_collection = <Collection<T>>::get(collection_id);1328 target_collection.offchain_schema = schema;1329 <Collection<T>>::insert(collection_id, target_collection);13301331 Ok(())1332 }13331334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 #[weight = T::WeightInfo::set_const_on_chain_schema()]1347 pub fn set_const_on_chain_schema (1348 origin,1349 collection_id: CollectionId,1350 schema: Vec<u8>1351 ) -> DispatchResult {1352 let sender = ensure_signed(origin)?;1353 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13541355 let mut target_collection = <Collection<T>>::get(collection_id);1356 target_collection.const_on_chain_schema = schema;1357 <Collection<T>>::insert(collection_id, target_collection);13581359 Ok(())1360 }13611362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 #[weight = T::WeightInfo::set_const_on_chain_schema()]1375 pub fn set_variable_on_chain_schema (1376 origin,1377 collection_id: CollectionId,1378 schema: Vec<u8>1379 ) -> DispatchResult {1380 let sender = ensure_signed(origin)?;1381 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13821383 let mut target_collection = <Collection<T>>::get(collection_id);1384 target_collection.variable_on_chain_schema = schema;1385 <Collection<T>>::insert(collection_id, target_collection);13861387 Ok(())1388 }13891390 1391 #[weight = 0]1392 pub fn set_chain_limits(1393 origin,1394 limits: ChainLimits1395 ) -> DispatchResult {1396 ensure_root(origin)?;1397 <ChainLimit>::put(limits);1398 Ok(())1399 }14001401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 #[weight = T::WeightInfo::enable_contract_sponsoring()]1413 pub fn enable_contract_sponsoring(1414 origin,1415 contract_address: T::AccountId,1416 enable: bool1417 ) -> DispatchResult {14181419 let sender = ensure_signed(origin)?;14201421 #[cfg(feature = "runtime-benchmarks")]1422 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14231424 let mut is_owner = false;1425 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1426 let owner = <ContractOwner<T>>::get(&contract_address);1427 is_owner = sender == owner;1428 }1429 ensure!(is_owner, Error::<T>::NoPermission);14301431 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1432 Ok(())1433 }14341435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 #[weight = 0]1453 pub fn set_contract_sponsoring_rate_limit(1454 origin,1455 contract_address: T::AccountId,1456 rate_limit: T::BlockNumber1457 ) -> DispatchResult {1458 let sender = ensure_signed(origin)?;1459 let mut is_owner = false;1460 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1461 let owner = <ContractOwner<T>>::get(&contract_address);1462 is_owner = sender == owner;1463 }1464 ensure!(is_owner, Error::<T>::NoPermission);14651466 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1467 Ok(())1468 }14691470 #[weight = 0]1471 pub fn set_collection_limits(1472 origin,1473 collection_id: u32,1474 limits: CollectionLimits,1475 ) -> DispatchResult {1476 let sender = ensure_signed(origin)?;1477 Self::check_owner_permissions(collection_id, sender.clone())?;1478 let mut target_collection = <Collection<T>>::get(collection_id);1479 let chain_limits = ChainLimit::get();1480 let climits = target_collection.limits;14811482 1483 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1484 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1485 Error::<T>::CollectionLimitBoundsExceeded);14861487 1488 ensure!(climits.token_limit > limits.token_limit && 1489 limits.token_limit <= chain_limits.account_token_ownership_limit, 1490 Error::<T>::AccountTokenLimitExceeded);14911492 target_collection.limits = limits;1493 <Collection<T>>::insert(collection_id, target_collection);14941495 Ok(())1496 } 1497 }1498}14991500impl<T: Trait> Module<T> {15011502 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15031504 1505 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1506 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1507 1508 Ok(())1509 }15101511 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15121513 1514 let total_items: u32 = ItemListIndex::get(collection_id);1515 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1516 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1517 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15181519 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1520 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1521 Self::check_white_list(collection_id, owner)?;1522 Self::check_white_list(collection_id, sender)?;1523 }15241525 Ok(())1526 }15271528 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1529 match target_collection.mode1530 {1531 CollectionMode::NFT => {1532 if let CreateItemData::NFT(data) = data {1533 1534 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1535 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1536 } else {1537 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1538 }1539 },1540 CollectionMode::Fungible(_) => {1541 if let CreateItemData::Fungible(_) = data {1542 } else {1543 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1544 }1545 },1546 CollectionMode::ReFungible(_) => {1547 if let CreateItemData::ReFungible(data) = data {15481549 1550 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1551 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1552 } else {1553 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1554 }1555 },1556 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1557 };15581559 Ok(())1560 }15611562 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1563 match data1564 {1565 CreateItemData::NFT(data) => {1566 let item = NftItemType {1567 collection: collection_id,1568 owner,1569 const_data: data.const_data,1570 variable_data: data.variable_data1571 };15721573 Self::add_nft_item(item)?;1574 },1575 CreateItemData::Fungible(_) => {1576 let item = FungibleItemType {1577 collection: collection_id,1578 owner,1579 value: (10 as u128).pow(collection.decimal_points as u32)1580 };15811582 Self::add_fungible_item(item)?;1583 },1584 CreateItemData::ReFungible(data) => {1585 let mut owner_list = Vec::new();1586 let value = (10 as u128).pow(collection.decimal_points as u32);1587 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15881589 let item = ReFungibleItemType {1590 collection: collection_id,1591 owner: owner_list,1592 const_data: data.const_data,1593 variable_data: data.variable_data1594 };15951596 Self::add_refungible_item(item)?;1597 }1598 };15991600 1601 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16021603 Ok(())1604 }16051606 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1607 let current_index = <ItemListIndex>::get(item.collection)1608 .checked_add(1)1609 .ok_or(Error::<T>::NumOverflow)?;1610 let itemcopy = item.clone();1611 let owner = item.owner.clone();16121613 Self::add_token_index(item.collection, current_index, owner.clone())?;16141615 <ItemListIndex>::insert(item.collection, current_index);1616 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16171618 1619 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1620 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1621 1622 1623 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1624 .checked_add(item.value)1625 .ok_or(Error::<T>::NumOverflow)?;1626 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16271628 Ok(())1629 }16301631 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1632 let current_index = <ItemListIndex>::get(item.collection)1633 .checked_add(1)1634 .ok_or(Error::<T>::NumOverflow)?;1635 let itemcopy = item.clone();16361637 let value = item.owner.first().unwrap().fraction;1638 let owner = item.owner.first().unwrap().owner.clone();16391640 Self::add_token_index(item.collection, current_index, owner.clone())?;16411642 <ItemListIndex>::insert(item.collection, current_index);1643 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16441645 1646 let block_number: T::BlockNumber = 0.into();1647 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16481649 1650 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1651 .checked_add(value)1652 .ok_or(Error::<T>::NumOverflow)?;1653 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16541655 Ok(())1656 }16571658 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1659 let current_index = <ItemListIndex>::get(item.collection)1660 .checked_add(1)1661 .ok_or(Error::<T>::NumOverflow)?;16621663 let item_owner = item.owner.clone();1664 let collection_id = item.collection.clone();1665 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16661667 <ItemListIndex>::insert(collection_id, current_index);1668 <NftItemList<T>>::insert(collection_id, current_index, item);16691670 1671 let block_number: T::BlockNumber = 0.into();1672 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16731674 1675 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1676 .checked_add(1)1677 .ok_or(Error::<T>::NumOverflow)?;1678 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16791680 Ok(())1681 }16821683 fn burn_refungible_item(1684 collection_id: CollectionId,1685 item_id: TokenId,1686 owner: T::AccountId,1687 ) -> DispatchResult {1688 ensure!(1689 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1690 Error::<T>::TokenNotFound1691 );1692 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1693 let item = collection1694 .owner1695 .iter()1696 .filter(|&i| i.owner == owner)1697 .next()1698 .unwrap();1699 Self::remove_token_index(collection_id, item_id, owner.clone())?;17001701 1702 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17031704 1705 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1706 .checked_sub(item.fraction)1707 .ok_or(Error::<T>::NumOverflow)?;1708 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17091710 <ReFungibleItemList<T>>::remove(collection_id, item_id);17111712 Ok(())1713 }17141715 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1716 ensure!(1717 <NftItemList<T>>::contains_key(collection_id, item_id),1718 Error::<T>::TokenNotFound1719 );1720 let item = <NftItemList<T>>::get(collection_id, item_id);1721 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17221723 1724 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17251726 1727 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1728 .checked_sub(1)1729 .ok_or(Error::<T>::NumOverflow)?;1730 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1731 <NftItemList<T>>::remove(collection_id, item_id);17321733 Ok(())1734 }17351736 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1737 ensure!(1738 <FungibleItemList<T>>::contains_key(collection_id, item_id),1739 Error::<T>::TokenNotFound1740 );1741 let item = <FungibleItemList<T>>::get(collection_id, item_id);1742 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17431744 1745 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17461747 1748 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1749 .checked_sub(item.value)1750 .ok_or(Error::<T>::NumOverflow)?;1751 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17521753 <FungibleItemList<T>>::remove(collection_id, item_id);17541755 Ok(())1756 }17571758 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1759 ensure!(1760 <Collection<T>>::contains_key(collection_id),1761 Error::<T>::CollectionNotFound1762 );1763 Ok(())1764 }17651766 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1767 Self::collection_exists(collection_id)?;17681769 let target_collection = <Collection<T>>::get(collection_id);1770 ensure!(1771 subject == target_collection.owner,1772 Error::<T>::NoPermission1773 );17741775 Ok(())1776 }17771778 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1779 let target_collection = <Collection<T>>::get(collection_id);1780 let mut result: bool = subject == target_collection.owner;1781 let exists = <AdminList<T>>::contains_key(collection_id);17821783 if !result & exists {1784 if <AdminList<T>>::get(collection_id).contains(&subject) {1785 result = true1786 }1787 }17881789 result1790 }17911792 fn check_owner_or_admin_permissions(1793 collection_id: CollectionId,1794 subject: T::AccountId,1795 ) -> DispatchResult {1796 Self::collection_exists(collection_id)?;1797 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());17981799 ensure!(1800 result,1801 Error::<T>::NoPermission1802 );1803 Ok(())1804 }18051806 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1807 let target_collection = <Collection<T>>::get(collection_id);18081809 match target_collection.mode {1810 CollectionMode::NFT => {1811 <NftItemList<T>>::get(collection_id, item_id).owner == subject1812 }1813 CollectionMode::Fungible(_) => {1814 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1815 }1816 CollectionMode::ReFungible(_) => {1817 <ReFungibleItemList<T>>::get(collection_id, item_id)1818 .owner1819 .iter()1820 .any(|i| i.owner == subject)1821 }1822 CollectionMode::Invalid => false,1823 }1824 }18251826 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1827 let mes = Error::<T>::AddresNotInWhiteList;1828 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1829 let wl = <WhiteList<T>>::get(collection_id);1830 ensure!(wl.contains(address), mes);18311832 Ok(())1833 }18341835 fn transfer_fungible(1836 collection_id: CollectionId,1837 item_id: TokenId,1838 value: u128,1839 owner: T::AccountId,1840 new_owner: T::AccountId,1841 ) -> DispatchResult {1842 ensure!(1843 <FungibleItemList<T>>::contains_key(collection_id, item_id),1844 Error::<T>::TokenNotFound1845 );18461847 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1848 let amount = full_item.value;18491850 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18511852 1853 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1854 .checked_sub(value)1855 .ok_or(Error::<T>::NumOverflow)?;1856 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18571858 let mut new_owner_account_id = 0;1859 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1860 if new_owner_items.len() > 0 {1861 new_owner_account_id = new_owner_items[0];1862 }18631864 1865 if amount == value && new_owner_account_id == 0 {1866 1867 1868 let mut new_full_item = full_item.clone();1869 new_full_item.owner = new_owner.clone();1870 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18711872 1873 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 1879 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1880 } else {1881 let mut new_full_item = full_item.clone();1882 new_full_item.value -= value;18831884 1885 if new_owner_account_id > 0 {1886 1887 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1888 item.value += value;18891890 1891 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1892 .checked_add(value)1893 .ok_or(Error::<T>::NumOverflow)?;1894 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18951896 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1897 } else {1898 1899 let item = FungibleItemType {1900 collection: collection_id,1901 owner: new_owner.clone(),1902 value1903 };19041905 Self::add_fungible_item(item)?;1906 }19071908 if amount == value {1909 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19101911 1912 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1913 <FungibleItemList<T>>::remove(collection_id, item_id);1914 }19151916 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1917 }19181919 Ok(())1920 }19211922 fn transfer_refungible(1923 collection_id: CollectionId,1924 item_id: TokenId,1925 value: u128,1926 owner: T::AccountId,1927 new_owner: T::AccountId,1928 ) -> DispatchResult {1929 ensure!(1930 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1931 Error::<T>::TokenNotFound1932 );19331934 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1935 let item = full_item1936 .owner1937 .iter()1938 .filter(|i| i.owner == owner)1939 .next()1940 .ok_or(Error::<T>::NumOverflow)?;1941 let amount = item.fraction;19421943 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19441945 1946 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1947 .checked_sub(value)1948 .ok_or(Error::<T>::NumOverflow)?;1949 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19501951 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1952 .checked_add(value)1953 .ok_or(Error::<T>::NumOverflow)?;1954 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19551956 let old_owner = item.owner.clone();1957 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19581959 1960 if amount == value && !new_owner_has_account {1961 1962 1963 let mut new_full_item = full_item.clone();1964 new_full_item1965 .owner1966 .iter_mut()1967 .find(|i| i.owner == owner)1968 .unwrap()1969 .owner = new_owner.clone();1970 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19711972 1973 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1974 } else {1975 let mut new_full_item = full_item.clone();1976 new_full_item1977 .owner1978 .iter_mut()1979 .find(|i| i.owner == owner)1980 .unwrap()1981 .fraction -= value;19821983 1984 if new_owner_has_account {1985 1986 new_full_item1987 .owner1988 .iter_mut()1989 .find(|i| i.owner == new_owner)1990 .unwrap()1991 .fraction += value;1992 } else {1993 1994 new_full_item.owner.push(Ownership {1995 owner: new_owner.clone(),1996 fraction: value,1997 });1998 Self::add_token_index(collection_id, item_id, new_owner.clone())?;1999 }20002001 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2002 }20032004 Ok(())2005 }20062007 fn transfer_nft(2008 collection_id: CollectionId,2009 item_id: TokenId,2010 sender: T::AccountId,2011 new_owner: T::AccountId,2012 ) -> DispatchResult {2013 ensure!(2014 <NftItemList<T>>::contains_key(collection_id, item_id),2015 Error::<T>::TokenNotFound2016 );20172018 let mut item = <NftItemList<T>>::get(collection_id, item_id);20192020 ensure!(2021 sender == item.owner,2022 Error::<T>::MustBeTokenOwner2023 );20242025 2026 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2027 .checked_sub(1)2028 .ok_or(Error::<T>::NumOverflow)?;2029 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20302031 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2032 .checked_add(1)2033 .ok_or(Error::<T>::NumOverflow)?;2034 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20352036 2037 let old_owner = item.owner.clone();2038 item.owner = new_owner.clone();2039 <NftItemList<T>>::insert(collection_id, item_id, item);20402041 2042 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20432044 2045 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2046 Ok(())2047 }2048 2049 fn item_exists(2050 collection_id: CollectionId,2051 item_id: TokenId,2052 mode: &CollectionMode2053 ) -> DispatchResult {2054 match mode {2055 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2056 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2057 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2058 _ => ()2059 };2060 2061 Ok(())2062 }20632064 fn set_re_fungible_variable_data(2065 collection_id: CollectionId,2066 item_id: TokenId,2067 data: Vec<u8>2068 ) -> DispatchResult {2069 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20702071 item.variable_data = data;20722073 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20742075 Ok(())2076 }20772078 fn set_nft_variable_data(2079 collection_id: CollectionId,2080 item_id: TokenId,2081 data: Vec<u8>2082 ) -> DispatchResult {2083 let mut item = <NftItemList<T>>::get(collection_id, item_id);2084 2085 item.variable_data = data;20862087 <NftItemList<T>>::insert(collection_id, item_id, item);2088 2089 Ok(())2090 }20912092 fn init_collection(item: &CollectionType<T::AccountId>) {2093 2094 assert!(2095 item.decimal_points <= MAX_DECIMAL_POINTS,2096 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2097 );2098 assert!(2099 item.name.len() <= 64,2100 "Collection name can not be longer than 63 char"2101 );2102 assert!(2103 item.name.len() <= 256,2104 "Collection description can not be longer than 255 char"2105 );2106 assert!(2107 item.token_prefix.len() <= 16,2108 "Token prefix can not be longer than 15 char"2109 );21102111 2112 let next_id = CreatedCollectionCount::get()2113 .checked_add(1)2114 .unwrap();21152116 CreatedCollectionCount::put(next_id);2117 }21182119 fn init_nft_token(item: &NftItemType<T::AccountId>) {2120 let current_index = <ItemListIndex>::get(item.collection)2121 .checked_add(1)2122 .unwrap();21232124 let item_owner = item.owner.clone();2125 let collection_id = item.collection.clone();2126 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21272128 <ItemListIndex>::insert(collection_id, current_index);21292130 2131 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2132 .checked_add(1)2133 .unwrap();2134 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2135 }21362137 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2138 let current_index = <ItemListIndex>::get(item.collection)2139 .checked_add(1)2140 .unwrap();2141 let owner = item.owner.clone();21422143 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21442145 <ItemListIndex>::insert(item.collection, current_index);21462147 2148 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2149 .checked_add(item.value)2150 .unwrap();2151 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2152 }21532154 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2155 let current_index = <ItemListIndex>::get(item.collection)2156 .checked_add(1)2157 .unwrap();21582159 let value = item.owner.first().unwrap().fraction;2160 let owner = item.owner.first().unwrap().owner.clone();21612162 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21632164 <ItemListIndex>::insert(item.collection, current_index);21652166 2167 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2168 .checked_add(value)2169 .unwrap();2170 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2171 }21722173 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21742175 2176 if <AccountItemCount<T>>::contains_key(owner.clone()) {21772178 2179 let count = <AccountItemCount<T>>::get(owner.clone());2180 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21812182 <AccountItemCount<T>>::insert(owner.clone(), count2183 .checked_add(1)2184 .ok_or(Error::<T>::NumOverflow)?);2185 }2186 else {2187 <AccountItemCount<T>>::insert(owner.clone(), 1);2188 }21892190 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2191 if list_exists {2192 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2193 let item_contains = list.contains(&item_index.clone());21942195 if !item_contains {2196 list.push(item_index.clone());2197 }21982199 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2200 } else {2201 let mut itm = Vec::new();2202 itm.push(item_index.clone());2203 <AddressTokens<T>>::insert(collection_id, owner, itm);2204 2205 }22062207 Ok(())2208 }22092210 fn remove_token_index(2211 collection_id: CollectionId,2212 item_index: TokenId,2213 owner: T::AccountId,2214 ) -> DispatchResult {22152216 2217 <AccountItemCount<T>>::insert(owner.clone(), 2218 <AccountItemCount<T>>::get(owner.clone())2219 .checked_sub(1)2220 .ok_or(Error::<T>::NumOverflow)?);222122222223 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2224 if list_exists {2225 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2226 let item_contains = list.contains(&item_index.clone());22272228 if item_contains {2229 list.retain(|&item| item != item_index);2230 <AddressTokens<T>>::insert(collection_id, owner, list);2231 }2232 }22332234 Ok(())2235 }22362237 fn move_token_index(2238 collection_id: CollectionId,2239 item_index: TokenId,2240 old_owner: T::AccountId,2241 new_owner: T::AccountId,2242 ) -> DispatchResult {2243 Self::remove_token_index(collection_id, item_index, old_owner)?;2244 Self::add_token_index(collection_id, item_index, new_owner)?;22452246 Ok(())2247 }2248}2249225022512252225322542255pub type Multiplier = FixedU128;22562257type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2258 <T as system::Trait>::AccountId,2259>>::Balance;2260type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2261 <T as system::Trait>::AccountId,2262>>::NegativeImbalance;2263226422652266#[derive(Encode, Decode, Clone, Eq, PartialEq)]2267pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2268 #[codec(compact)] BalanceOf<T>2269);22702271impl<T: Trait + Send + Sync> sp_std::fmt::Debug2272 for ChargeTransactionPayment<T>2273{2274 #[cfg(feature = "std")]2275 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2276 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2277 }2278 #[cfg(not(feature = "std"))]2279 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2280 Ok(())2281 }2282}22832284impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2285where2286 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2287 BalanceOf<T>: Send + Sync + FixedPointOperand,2288{2289 2290 pub fn from(fee: BalanceOf<T>) -> Self {2291 Self(fee)2292 }22932294 pub fn traditional_fee(2295 len: usize,2296 info: &DispatchInfoOf<T::Call>,2297 tip: BalanceOf<T>,2298 ) -> BalanceOf<T>2299 where2300 T::Call: Dispatchable<Info = DispatchInfo>,2301 {2302 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2303 }23042305 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2306 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2307 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2308 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2309 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2310 }23112312 fn withdraw_fee(2313 &self,2314 who: &T::AccountId,2315 call: &T::Call,2316 info: &DispatchInfoOf<T::Call>,2317 len: usize,2318 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2319 let tip = self.0;23202321 2322 2323 2324 2325 2326 2327 2328 let fee = Self::traditional_fee(len, info, tip);23292330 2331 2332 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2333 Some(Call::create_item(collection_id, _owner, _properties)) => {23342335 2336 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2337 {2338 <Collection<T>>::get(collection_id).sponsor2339 } else {2340 T::AccountId::default()2341 }2342 }2343 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2344 2345 let _collection_limits = <Collection<T>>::get(collection_id).limits;2346 let _collection_mode = <Collection<T>>::get(collection_id).mode;23472348 2349 let sponsor_transfer = match _collection_mode {2350 CollectionMode::NFT => {23512352 2353 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2354 _collection_limits.sponsor_transfer_timeout2355 } else {2356 ChainLimit::get().nft_sponsor_transfer_timeout2357 };23582359 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2360 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2361 let limit_time = basket + limit.into();2362 if block_number >= limit_time {2363 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2364 true2365 }2366 else {2367 false2368 }2369 }2370 CollectionMode::Fungible(_) => {23712372 2373 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2374 _collection_limits.sponsor_transfer_timeout2375 } else {2376 ChainLimit::get().fungible_sponsor_transfer_timeout2377 };23782379 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2380 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2381 if basket.iter().any(|i| i.address == _new_owner.clone())2382 {2383 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2384 let limit_time = item.start_block + limit.into();2385 if block_number >= limit_time {2386 basket.retain(|x| x.address == item.address);2387 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2388 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2389 true2390 }2391 else {2392 false2393 }2394 }2395 else {2396 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2397 true2398 }2399 }2400 CollectionMode::ReFungible(_) => {24012402 2403 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2404 _collection_limits.sponsor_transfer_timeout2405 } else {2406 ChainLimit::get().refungible_sponsor_transfer_timeout2407 };24082409 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2410 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2411 let limit_time = basket + limit.into();2412 if block_number >= limit_time {2413 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2414 true2415 } else {2416 false2417 }2418 }2419 _ => {2420 false2421 },2422 };24232424 if !sponsor_transfer {2425 T::AccountId::default()2426 } else {2427 <Collection<T>>::get(collection_id).sponsor2428 }2429 }24302431 _ => T::AccountId::default(),2432 };24332434 2435 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24362437 2438 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24392440 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2441 code_hash,2442 &data,2443 &who,2444 );2445 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24462447 T::AccountId::default()2448 },24492450 2451 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24522453 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24542455 let mut sponsor_transfer = false;2456 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2457 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2458 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2459 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2460 let limit_time = last_tx_block + rate_limit;24612462 if block_number >= limit_time {2463 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2464 sponsor_transfer = true;2465 }2466 } else {2467 sponsor_transfer = false;2468 }2469 2470 2471 let mut sp = T::AccountId::default();2472 if sponsor_transfer {2473 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2474 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2475 sp = called_contract;2476 }2477 }2478 }24792480 sp2481 },24822483 _ => sponsor,2484 };24852486 let mut who_pays_fee: T::AccountId = sponsor.clone();2487 if sponsor == T::AccountId::default() {2488 who_pays_fee = who.clone();2489 }24902491 2492 if fee.is_zero() {2493 return Ok((fee, None));2494 }24952496 match <T as transaction_payment::Trait>::Currency::withdraw(2497 &who_pays_fee,2498 fee,2499 if tip.is_zero() {2500 WithdrawReason::TransactionPayment.into()2501 } else {2502 WithdrawReason::TransactionPayment | WithdrawReason::Tip2503 },2504 ExistenceRequirement::KeepAlive,2505 ) {2506 Ok(imbalance) => Ok((fee, Some(imbalance))),2507 Err(_) => Err(InvalidTransaction::Payment.into()),2508 }2509 }2510}251125122513impl<T: Trait + Send + Sync> SignedExtension2514 for ChargeTransactionPayment<T>2515where2516 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2517 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2518{2519 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2520 type AccountId = T::AccountId;2521 type Call = T::Call;2522 type AdditionalSigned = ();2523 type Pre = (2524 BalanceOf<T>,2525 Self::AccountId,2526 Option<NegativeImbalanceOf<T>>,2527 BalanceOf<T>,2528 );2529 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2530 Ok(())2531 }25322533 fn validate(2534 &self,2535 who: &Self::AccountId,2536 call: &Self::Call,2537 info: &DispatchInfoOf<Self::Call>,2538 len: usize,2539 ) -> TransactionValidity {2540 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2541 Ok(ValidTransaction {2542 priority: Self::get_priority(len, info, fee),2543 ..Default::default()2544 })2545 }25462547 fn pre_dispatch(2548 self,2549 who: &Self::AccountId,2550 call: &Self::Call,2551 info: &DispatchInfoOf<Self::Call>,2552 len: usize,2553 ) -> Result<Self::Pre, TransactionValidityError> {2554 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2555 Ok((self.0, who.clone(), imbalance, fee))2556 }25572558 fn post_dispatch(2559 pre: Self::Pre,2560 info: &DispatchInfoOf<Self::Call>,2561 post_info: &PostDispatchInfoOf<Self::Call>,2562 len: usize,2563 _result: &DispatchResult,2564 ) -> Result<(), TransactionValidityError> {2565 let (tip, who, imbalance, fee) = pre;2566 if let Some(payed) = imbalance {2567 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2568 len as u32, info, post_info, tip,2569 );2570 let refund = fee.saturating_sub(actual_fee);2571 let actual_payment =2572 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2573 &who, refund,2574 ) {2575 Ok(refund_imbalance) => {2576 2577 2578 match payed.offset(refund_imbalance) {2579 Ok(actual_payment) => actual_payment,2580 Err(_) => return Err(InvalidTransaction::Payment.into()),2581 }2582 }2583 2584 2585 Err(_) => payed,2586 };2587 let imbalances = actual_payment.split(tip);2588 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2589 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2590 );2591 }2592 Ok(())2593 }2594}25952596