123456#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, WithdrawReason,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial,29 },30 IsSubType, StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36 traits::{37 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38 },39 transaction_validity::{40 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41 },42 FixedPointOperand, FixedU128,43};44use pallet_contracts::ContractAddressFor;45use sp_runtime::traits::StaticLookup;4647#[cfg(test)]48mod mock;4950#[cfg(test)]51mod tests;5253mod default_weights;5455pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;56pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;57pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5859606162pub type CollectionId = u32;63pub type TokenId = u32;64pub type DecimalPoints = u8;6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum CollectionMode {69 Invalid,70 NFT,71 72 Fungible(DecimalPoints),73 74 ReFungible(DecimalPoints),75}7677impl Into<u8> for CollectionMode {78 fn into(self) -> u8 {79 match self {80 CollectionMode::Invalid => 0,81 CollectionMode::NFT => 1,82 CollectionMode::Fungible(_) => 2,83 CollectionMode::ReFungible(_) => 3,84 }85 }86}8788#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]89#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]90pub enum AccessMode {91 Normal,92 WhiteList,93}94impl Default for AccessMode {95 fn default() -> Self {96 Self::Normal97 }98}99100impl Default for CollectionMode {101 fn default() -> Self {102 Self::Invalid103 }104}105106#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]107#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]108pub enum SchemaVersion {109 ImageURL,110 Unique,111}112impl Default for SchemaVersion {113 fn default() -> Self {114 Self::ImageURL115 }116}117118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]120pub struct Ownership<AccountId> {121 pub owner: AccountId,122 pub fraction: u128,123}124125#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]126#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]127pub struct CollectionType<AccountId> {128 pub owner: AccountId,129 pub mode: CollectionMode,130 pub access: AccessMode,131 pub decimal_points: DecimalPoints,132 pub name: Vec<u16>, 133 pub description: Vec<u16>, 134 pub token_prefix: Vec<u8>, 135 pub mint_mode: bool,136 pub offchain_schema: Vec<u8>,137 pub schema_version: SchemaVersion,138 pub sponsor: AccountId, 139 pub unconfirmed_sponsor: AccountId, 140 pub limits: CollectionLimits, 141 pub variable_on_chain_schema: Vec<u8>, 142 pub const_on_chain_schema: Vec<u8>, 143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct NftItemType<AccountId> {148 pub collection: CollectionId,149 pub owner: AccountId,150 pub const_data: Vec<u8>,151 pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType<AccountId> {157 pub collection: CollectionId,158 pub owner: AccountId,159 pub value: u128,160}161162#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]163#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]164pub struct ReFungibleItemType<AccountId> {165 pub collection: CollectionId,166 pub owner: Vec<Ownership<AccountId>>,167 pub const_data: Vec<u8>,168 pub variable_data: Vec<u8>,169}170171#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]172#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]173pub struct ApprovePermissions<AccountId> {174 pub approved: AccountId,175 pub amount: u128,176}177178#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]179#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]180pub struct VestingItem<AccountId, Moment> {181 pub sender: AccountId,182 pub recipient: AccountId,183 pub collection_id: CollectionId,184 pub item_id: TokenId,185 pub amount: u64,186 pub vesting_date: Moment,187}188189#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]190#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]191pub struct BasketItem<AccountId, BlockNumber> {192 pub address: AccountId,193 pub start_block: BlockNumber,194}195196#[derive(Encode, Decode, Debug, Clone, PartialEq)]197#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]198pub struct CollectionLimits {199 pub account_token_ownership_limit: u32,200 pub sponsored_data_size: u32,201 pub token_limit: u32,202203 204 pub sponsor_transfer_timeout: u32,205}206207impl Default for CollectionLimits {208 fn default() -> CollectionLimits {209 CollectionLimits { 210 account_token_ownership_limit: 10_000_000, 211 token_limit: u32::max_value(),212 sponsored_data_size: u32::max_value(), 213 sponsor_transfer_timeout: 14400 }214 }215}216217#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]218#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]219pub struct ChainLimits {220 pub collection_numbers_limit: u32,221 pub account_token_ownership_limit: u32,222 pub collections_admins_limit: u64,223 pub custom_data_limit: u32,224225 226 pub nft_sponsor_transfer_timeout: u32,227 pub fungible_sponsor_transfer_timeout: u32,228 pub refungible_sponsor_transfer_timeout: u32,229}230231pub trait WeightInfo {232 fn create_collection() -> Weight;233 fn destroy_collection() -> Weight;234 fn add_to_white_list() -> Weight;235 fn remove_from_white_list() -> Weight;236 fn set_public_access_mode() -> Weight;237 fn set_mint_permission() -> Weight;238 fn change_collection_owner() -> Weight;239 fn add_collection_admin() -> Weight;240 fn remove_collection_admin() -> Weight;241 fn set_collection_sponsor() -> Weight;242 fn confirm_sponsorship() -> Weight;243 fn remove_collection_sponsor() -> Weight;244 fn create_item(s: usize) -> Weight;245 fn burn_item() -> Weight;246 fn transfer() -> Weight;247 fn approve() -> Weight;248 fn transfer_from() -> Weight;249 fn set_offchain_schema() -> Weight;250 fn set_const_on_chain_schema() -> Weight;251 fn set_variable_on_chain_schema() -> Weight;252 fn set_variable_meta_data() -> Weight;253 fn enable_contract_sponsoring() -> Weight;254 fn set_schema_version() -> Weight;255 fn set_chain_limits() -> Weight;256 fn set_contract_sponsoring_rate_limit() -> Weight;257 fn toggle_contract_white_list() -> Weight;258 fn add_to_contract_white_list() -> Weight;259 fn remove_from_contract_white_list() -> Weight;260 fn set_collection_limits() -> Weight;261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateNftData {266 pub const_data: Vec<u8>,267 pub variable_data: Vec<u8>,268}269270#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]271#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]272pub struct CreateFungibleData {273}274275#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]276#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]277pub struct CreateReFungibleData {278 pub const_data: Vec<u8>,279 pub variable_data: Vec<u8>,280}281282#[derive(Encode, Decode, Debug, Clone, PartialEq)]283#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]284pub enum CreateItemData {285 NFT(CreateNftData),286 Fungible(CreateFungibleData),287 ReFungible(CreateReFungibleData),288}289290impl CreateItemData {291 pub fn len(&self) -> usize {292 let len = match self {293 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),294 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),295 _ => 0296 };297 298 return len;299 }300}301302impl From<CreateNftData> for CreateItemData {303 fn from(item: CreateNftData) -> Self {304 CreateItemData::NFT(item)305 }306}307308impl From<CreateReFungibleData> for CreateItemData {309 fn from(item: CreateReFungibleData) -> Self {310 CreateItemData::ReFungible(item)311 }312}313314impl From<CreateFungibleData> for CreateItemData {315 fn from(item: CreateFungibleData) -> Self {316 CreateItemData::Fungible(item)317 }318}319320321decl_error! {322 323 pub enum Error for Module<T: Trait> {324 325 TotalCollectionsLimitExceeded,326 327 CollectionDecimalPointLimitExceeded, 328 329 CollectionNameLimitExceeded, 330 331 CollectionDescriptionLimitExceeded, 332 333 CollectionTokenPrefixLimitExceeded,334 335 CollectionNotFound,336 337 TokenNotFound,338 339 NumOverflow, 340 341 AlreadyAdmin, 342 343 NoPermission,344 345 ConfirmUnsetSponsorFail,346 347 PublicMintingNotAllowed,348 349 MustBeTokenOwner,350 351 TokenValueTooLow,352 353 NftSizeLimitExceeded,354 355 ApproveNotFound,356 357 TokenValueNotEnough,358 359 ApproveRequired,360 361 AddresNotInWhiteList,362 363 CollectionAdminsLimitExceeded,364 365 AddressOwnershipLimitExceeded,366 367 EmptyArgument,368 369 TokenConstDataLimitExceeded,370 371 TokenVariableDataLimitExceeded,372 373 NotNftDataUsedToMintNftCollectionToken,374 375 NotFungibleDataUsedToMintFungibleCollectionToken,376 377 NotReFungibleDataUsedToMintReFungibleCollectionToken,378 379 UnexpectedCollectionType,380 381 CantStoreMetadataInFungibleTokens,382 383 CollectionTokenLimitExceeded,384 385 AccountTokenLimitExceeded,386 387 CollectionLimitBoundsExceeded388 }389}390391pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {392 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;393394 395 type WeightInfo: WeightInfo;396}397398#[cfg(feature = "runtime-benchmarks")]399mod benchmarking;400401402403decl_storage! {404 trait Store for Module<T: Trait> as Nft {405406 407 NextCollectionID: CollectionId;408 CreatedCollectionCount: u32;409 ChainVersion: u64;410 ItemListIndex: map hasher(identity) CollectionId => TokenId;411412 413 pub ChainLimit get(fn chain_limit) config(): ChainLimits;414415 416 CollectionCount: u32;417 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;418419 420 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;421 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;422 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;423424 425 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;426427 428 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;429430 431 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;432 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;433 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;434435 436 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;437438 439 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;440 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;441 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;442443 444 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;445 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;446 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;447 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;448 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 449 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 450 }451 add_extra_genesis {452 build(|config: &GenesisConfig<T>| {453 454 for (_num, _c) in &config.collection {455 <Module<T>>::init_collection(_c);456 }457458 for (_num, _q, _i) in &config.nft_item_id {459 <Module<T>>::init_nft_token(_i);460 }461462 for (_num, _q, _i) in &config.fungible_item_id {463 <Module<T>>::init_fungible_token(_i);464 }465466 for (_num, _q, _i) in &config.refungible_item_id {467 <Module<T>>::init_refungible_token(_i);468 }469 })470 }471}472473decl_event!(474 pub enum Event<T>475 where476 AccountId = <T as system::Trait>::AccountId,477 {478 479 480 481 482 483 484 485 486 487 Created(CollectionId, u8, AccountId),488489 490 491 492 493 494 495 496 ItemCreated(CollectionId, TokenId),497498 499 500 501 502 503 504 505 ItemDestroyed(CollectionId, TokenId),506 }507);508509decl_module! {510 pub struct Module<T: Trait> for enum Call where origin: T::Origin {511512 fn deposit_event() = default;513 type Error = Error<T>;514515 fn on_initialize(now: T::BlockNumber) -> Weight {516517 if ChainVersion::get() < 2518 {519 let value = NextCollectionID::get();520 CreatedCollectionCount::put(value);521 ChainVersion::put(2);522 }523524 0525 }526527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 #[weight = T::WeightInfo::create_collection()]544 pub fn create_collection(origin,545 collection_name: Vec<u16>,546 collection_description: Vec<u16>,547 token_prefix: Vec<u8>,548 mode: CollectionMode) -> DispatchResult {549550 551 let who = ensure_signed(origin)?;552553 let decimal_points = match mode {554 CollectionMode::Fungible(points) => points,555 CollectionMode::ReFungible(points) => points,556 _ => 0557 };558559 560 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);561562 563 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);564565 let mut name = collection_name.to_vec();566 name.push(0);567 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);568569 let mut description = collection_description.to_vec();570 description.push(0);571 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);572573 let mut prefix = token_prefix.to_vec();574 prefix.push(0);575 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);576577 578 let next_id = CreatedCollectionCount::get()579 .checked_add(1)580 .ok_or(Error::<T>::NumOverflow)?;581582 583 let total = CollectionCount::get()584 .checked_add(1)585 .ok_or(Error::<T>::NumOverflow)?;586587 CreatedCollectionCount::put(next_id);588 CollectionCount::put(total);589590 591 let new_collection = CollectionType {592 owner: who.clone(),593 name: name,594 mode: mode.clone(),595 mint_mode: false,596 access: AccessMode::Normal,597 description: description,598 decimal_points: decimal_points,599 token_prefix: prefix,600 offchain_schema: Vec::new(),601 schema_version: SchemaVersion::ImageURL,602 sponsor: T::AccountId::default(),603 unconfirmed_sponsor: T::AccountId::default(),604 variable_on_chain_schema: Vec::new(),605 const_on_chain_schema: Vec::new(),606 limits: CollectionLimits::default(),607 };608609 610 <Collection<T>>::insert(next_id, new_collection);611612 613 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));614615 Ok(())616 }617618 619 620 621 622 623 624 625 626 627 #[weight = T::WeightInfo::destroy_collection()]628 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {629630 let sender = ensure_signed(origin)?;631 Self::check_owner_permissions(collection_id, sender)?;632633 <AddressTokens<T>>::remove_prefix(collection_id);634 <ApprovedList<T>>::remove_prefix(collection_id);635 <Balance<T>>::remove_prefix(collection_id);636 <ItemListIndex>::remove(collection_id);637 <AdminList<T>>::remove(collection_id);638 <Collection<T>>::remove(collection_id);639 <WhiteList<T>>::remove_prefix(collection_id);640641 <NftItemList<T>>::remove_prefix(collection_id);642 <FungibleItemList<T>>::remove_prefix(collection_id);643 <ReFungibleItemList<T>>::remove_prefix(collection_id);644645 <NftTransferBasket<T>>::remove_prefix(collection_id);646 <FungibleTransferBasket<T>>::remove_prefix(collection_id);647 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);648649 if CollectionCount::get() > 0650 {651 652 let total = CollectionCount::get()653 .checked_sub(1)654 .ok_or(Error::<T>::NumOverflow)?;655656 CollectionCount::put(total);657 }658659 Ok(())660 }661662 663 664 665 666 667 668 669 670 671 672 673 674 #[weight = T::WeightInfo::add_to_white_list()]675 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{676677 let sender = ensure_signed(origin)?;678 Self::check_owner_or_admin_permissions(collection_id, sender)?;679680 <WhiteList<T>>::insert(collection_id, address, true);681 682 Ok(())683 }684685 686 687 688 689 690 691 692 693 694 695 696 697 #[weight = T::WeightInfo::remove_from_white_list()]698 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{699700 let sender = ensure_signed(origin)?;701 Self::check_owner_or_admin_permissions(collection_id, sender)?;702703 <WhiteList<T>>::remove(collection_id, address);704705 Ok(())706 }707708 709 710 711 712 713 714 715 716 717 718 719 #[weight = T::WeightInfo::set_public_access_mode()]720 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult721 {722 let sender = ensure_signed(origin)?;723724 Self::check_owner_permissions(collection_id, sender)?;725 let mut target_collection = <Collection<T>>::get(collection_id);726 target_collection.access = mode;727 <Collection<T>>::insert(collection_id, target_collection);728729 Ok(())730 }731732 733 734 735 736 737 738 739 740 741 742 743 744 745 #[weight = T::WeightInfo::set_mint_permission()]746 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult747 {748 let sender = ensure_signed(origin)?;749750 Self::check_owner_permissions(collection_id, sender)?;751 let mut target_collection = <Collection<T>>::get(collection_id);752 target_collection.mint_mode = mint_permission;753 <Collection<T>>::insert(collection_id, target_collection);754755 Ok(())756 }757758 759 760 761 762 763 764 765 766 767 768 769 #[weight = T::WeightInfo::change_collection_owner()]770 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {771772 let sender = ensure_signed(origin)?;773 Self::check_owner_permissions(collection_id, sender)?;774 let mut target_collection = <Collection<T>>::get(collection_id);775 target_collection.owner = new_owner;776 <Collection<T>>::insert(collection_id, target_collection);777778 Ok(())779 }780781 782 783 784 785 786 787 788 789 790 791 792 793 794 #[weight = T::WeightInfo::add_collection_admin()]795 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {796797 let sender = ensure_signed(origin)?;798 Self::check_owner_or_admin_permissions(collection_id, sender)?;799 let mut admin_arr: Vec<T::AccountId> = Vec::new();800801 if <AdminList<T>>::contains_key(collection_id)802 {803 admin_arr = <AdminList<T>>::get(collection_id);804 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);805 }806807 808 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);809810 admin_arr.push(new_admin_id);811 <AdminList<T>>::insert(collection_id, admin_arr);812813 Ok(())814 }815816 817 818 819 820 821 822 823 824 825 826 827 828 #[weight = T::WeightInfo::remove_collection_admin()]829 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {830831 let sender = ensure_signed(origin)?;832 Self::check_owner_or_admin_permissions(collection_id, sender)?;833834 if <AdminList<T>>::contains_key(collection_id)835 {836 let mut admin_arr = <AdminList<T>>::get(collection_id);837 admin_arr.retain(|i| *i != account_id);838 <AdminList<T>>::insert(collection_id, admin_arr);839 }840841 Ok(())842 }843844 845 846 847 848 849 850 851 852 853 #[weight = T::WeightInfo::set_collection_sponsor()]854 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {855856 let sender = ensure_signed(origin)?;857 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);858859 let mut target_collection = <Collection<T>>::get(collection_id);860 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);861862 target_collection.unconfirmed_sponsor = new_sponsor;863 <Collection<T>>::insert(collection_id, target_collection);864865 Ok(())866 }867868 869 870 871 872 873 874 875 #[weight = T::WeightInfo::confirm_sponsorship()]876 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {877878 let sender = ensure_signed(origin)?;879 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);880881 let mut target_collection = <Collection<T>>::get(collection_id);882 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);883884 target_collection.sponsor = target_collection.unconfirmed_sponsor;885 target_collection.unconfirmed_sponsor = T::AccountId::default();886 <Collection<T>>::insert(collection_id, target_collection);887888 Ok(())889 }890891 892 893 894 895 896 897 898 899 900 #[weight = T::WeightInfo::remove_collection_sponsor()]901 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {902903 let sender = ensure_signed(origin)?;904 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);905906 let mut target_collection = <Collection<T>>::get(collection_id);907 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);908909 target_collection.sponsor = T::AccountId::default();910 <Collection<T>>::insert(collection_id, target_collection);911912 Ok(())913 }914915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938939 #[weight = T::WeightInfo::create_item(data.len())]940 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {941942 let sender = ensure_signed(origin)?;943944 Self::collection_exists(collection_id)?;945946 let target_collection = <Collection<T>>::get(collection_id);947948 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;949 Self::validate_create_item_args(&target_collection, &data)?;950 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;951952 Ok(())953 }954955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 #[weight = T::WeightInfo::create_item(items_data.into_iter()974 .map(|data| { data.len() })975 .sum())]976 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {977978 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);979 let sender = ensure_signed(origin)?;980981 Self::collection_exists(collection_id)?;982 let target_collection = <Collection<T>>::get(collection_id);983984 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;985986 for data in &items_data {987 Self::validate_create_item_args(&target_collection, data)?;988 }989 for data in &items_data {990 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;991 }992993 Ok(())994 }995996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 #[weight = T::WeightInfo::burn_item()]1010 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10111012 let sender = ensure_signed(origin)?;1013 Self::collection_exists(collection_id)?;10141015 1016 let target_collection = <Collection<T>>::get(collection_id);1017 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1018 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1019 Error::<T>::NoPermission);10201021 if target_collection.access == AccessMode::WhiteList {1022 Self::check_white_list(collection_id, &sender)?;1023 }10241025 match target_collection.mode1026 {1027 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1028 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1029 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1030 _ => ()1031 };10321033 1034 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10351036 Ok(())1037 }10381039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 #[weight = T::WeightInfo::transfer()]1063 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10641065 let sender = ensure_signed(origin)?;1066 let target_collection = <Collection<T>>::get(collection_id);10671068 1069 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10701071 1072 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1073 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1074 Error::<T>::NoPermission);10751076 if target_collection.access == AccessMode::WhiteList {1077 Self::check_white_list(collection_id, &sender)?;1078 Self::check_white_list(collection_id, &recipient)?;1079 }10801081 match target_collection.mode1082 {1083 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1084 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1085 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1086 _ => ()1087 };10881089 Ok(())1090 }10911092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 #[weight = T::WeightInfo::approve()]1108 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11091110 let sender = ensure_signed(origin)?;11111112 1113 let target_collection = <Collection<T>>::get(collection_id);1114 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1115 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1116 Error::<T>::NoPermission);11171118 if target_collection.access == AccessMode::WhiteList {1119 Self::check_white_list(collection_id, &sender)?;1120 Self::check_white_list(collection_id, &approved)?;1121 }11221123 1124 let amount = 100000000;11251126 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1127 if list_exists {11281129 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1130 let item_contains = list.iter().any(|i| i.approved == approved);11311132 if !item_contains {1133 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1134 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1135 }1136 } else {11371138 let mut list = Vec::new();1139 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1140 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1141 }11421143 Ok(())1144 }1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 #[weight = T::WeightInfo::transfer_from()]1166 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11671168 let sender = ensure_signed(origin)?;1169 let mut appoved_transfer = false;11701171 1172 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1173 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1174 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1175 if opt_item.is_some()1176 {1177 appoved_transfer = true;1178 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1179 }1180 }11811182 let target_collection = <Collection<T>>::get(collection_id);11831184 1185 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11861187 1188 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1189 Error::<T>::NoPermission);11901191 if target_collection.access == AccessMode::WhiteList {1192 Self::check_white_list(collection_id, &sender)?;1193 Self::check_white_list(collection_id, &recipient)?;1194 }11951196 1197 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1198 .into_iter().filter(|i| i.approved != sender.clone()).collect();1199 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);120012011202 match target_collection.mode1203 {1204 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1205 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1206 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1207 _ => ()1208 };12091210 Ok(())1211 }12121213 #[weight = 0]1214 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12151216 1217 1218 1219 12201221 12221223 12241225 Ok(())1226 }12271228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 #[weight = T::WeightInfo::set_variable_meta_data()]1241 pub fn set_variable_meta_data (1242 origin,1243 collection_id: CollectionId,1244 item_id: TokenId,1245 data: Vec<u8>1246 ) -> DispatchResult {1247 let sender = ensure_signed(origin)?;1248 1249 Self::collection_exists(collection_id)?;1250 1251 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12521253 1254 let target_collection = <Collection<T>>::get(collection_id);1255 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1256 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1257 Error::<T>::NoPermission);12581259 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12601261 match target_collection.mode1262 {1263 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1264 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1265 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1266 _ => fail!(Error::<T>::UnexpectedCollectionType)1267 };12681269 Ok(())1270 }1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 #[weight = T::WeightInfo::set_schema_version()]1287 pub fn set_schema_version(1288 origin,1289 collection_id: CollectionId,1290 version: SchemaVersion1291 ) -> DispatchResult {1292 let sender = ensure_signed(origin)?;1293 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1294 let mut target_collection = <Collection<T>>::get(collection_id);1295 target_collection.schema_version = version;1296 <Collection<T>>::insert(collection_id, target_collection);12971298 Ok(())1299 }13001301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 #[weight = T::WeightInfo::set_offchain_schema()]1314 pub fn set_offchain_schema(1315 origin,1316 collection_id: CollectionId,1317 schema: Vec<u8>1318 ) -> DispatchResult {1319 let sender = ensure_signed(origin)?;1320 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13211322 let mut target_collection = <Collection<T>>::get(collection_id);1323 target_collection.offchain_schema = schema;1324 <Collection<T>>::insert(collection_id, target_collection);13251326 Ok(())1327 }13281329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 #[weight = T::WeightInfo::set_const_on_chain_schema()]1342 pub fn set_const_on_chain_schema (1343 origin,1344 collection_id: CollectionId,1345 schema: Vec<u8>1346 ) -> DispatchResult {1347 let sender = ensure_signed(origin)?;1348 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13491350 let mut target_collection = <Collection<T>>::get(collection_id);1351 target_collection.const_on_chain_schema = schema;1352 <Collection<T>>::insert(collection_id, target_collection);13531354 Ok(())1355 }13561357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 #[weight = T::WeightInfo::set_const_on_chain_schema()]1370 pub fn set_variable_on_chain_schema (1371 origin,1372 collection_id: CollectionId,1373 schema: Vec<u8>1374 ) -> DispatchResult {1375 let sender = ensure_signed(origin)?;1376 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13771378 let mut target_collection = <Collection<T>>::get(collection_id);1379 target_collection.variable_on_chain_schema = schema;1380 <Collection<T>>::insert(collection_id, target_collection);13811382 Ok(())1383 }13841385 1386 #[weight = T::WeightInfo::set_chain_limits()]1387 pub fn set_chain_limits(1388 origin,1389 limits: ChainLimits1390 ) -> DispatchResult {13911392 #[cfg(not(feature = "runtime-benchmarks"))]1393 ensure_root(origin)?;13941395 <ChainLimit>::put(limits);1396 Ok(())1397 }13981399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 #[weight = T::WeightInfo::enable_contract_sponsoring()]1411 pub fn enable_contract_sponsoring(1412 origin,1413 contract_address: T::AccountId,1414 enable: bool1415 ) -> DispatchResult {14161417 let sender = ensure_signed(origin)?;14181419 #[cfg(feature = "runtime-benchmarks")]1420 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14211422 Self::ensure_contract_owned(sender, &contract_address)?;14231424 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1425 Ok(())1426 }14271428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1446 pub fn set_contract_sponsoring_rate_limit(1447 origin,1448 contract_address: T::AccountId,1449 rate_limit: T::BlockNumber1450 ) -> DispatchResult {1451 let sender = ensure_signed(origin)?;14521453 #[cfg(feature = "runtime-benchmarks")]1454 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14551456 Self::ensure_contract_owned(sender, &contract_address)?;1457 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1458 Ok(())1459 }14601461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 #[weight = T::WeightInfo::toggle_contract_white_list()]1473 pub fn toggle_contract_white_list(1474 origin,1475 contract_address: T::AccountId,1476 enable: bool1477 ) -> DispatchResult {1478 let sender = ensure_signed(origin)?;14791480 #[cfg(feature = "runtime-benchmarks")]1481 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14821483 Self::ensure_contract_owned(sender, &contract_address)?;1484 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1485 Ok(())1486 }1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 #[weight = T::WeightInfo::add_to_contract_white_list()]1500 pub fn add_to_contract_white_list(1501 origin,1502 contract_address: T::AccountId,1503 account_address: T::AccountId1504 ) -> DispatchResult {1505 let sender = ensure_signed(origin)?;15061507 #[cfg(feature = "runtime-benchmarks")]1508 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1509 1510 Self::ensure_contract_owned(sender, &contract_address)?; 1511 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1512 Ok(())1513 }15141515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 #[weight = T::WeightInfo::remove_from_contract_white_list()]1527 pub fn remove_from_contract_white_list(1528 origin,1529 contract_address: T::AccountId,1530 account_address: T::AccountId1531 ) -> DispatchResult {1532 let sender = ensure_signed(origin)?;15331534 #[cfg(feature = "runtime-benchmarks")]1535 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15361537 Self::ensure_contract_owned(sender, &contract_address)?;1538 <ContractWhiteList<T>>::remove(contract_address, account_address);1539 Ok(())1540 }15411542 #[weight = T::WeightInfo::set_collection_limits()]1543 pub fn set_collection_limits(1544 origin,1545 collection_id: u32,1546 limits: CollectionLimits,1547 ) -> DispatchResult {1548 let sender = ensure_signed(origin)?;1549 Self::check_owner_permissions(collection_id, sender.clone())?;1550 let mut target_collection = <Collection<T>>::get(collection_id);1551 let chain_limits = ChainLimit::get();1552 let climits = target_collection.limits;15531554 1555 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1556 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1557 Error::<T>::CollectionLimitBoundsExceeded);15581559 1560 ensure!(climits.token_limit > limits.token_limit && 1561 limits.token_limit <= chain_limits.account_token_ownership_limit, 1562 Error::<T>::AccountTokenLimitExceeded);15631564 target_collection.limits = limits;1565 <Collection<T>>::insert(collection_id, target_collection);15661567 Ok(())1568 } 1569 }1570}15711572impl<T: Trait> Module<T> {15731574 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15751576 1577 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1578 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1579 1580 Ok(())1581 }15821583 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15841585 1586 let total_items: u32 = ItemListIndex::get(collection_id);1587 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1588 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1589 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15901591 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1592 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1593 Self::check_white_list(collection_id, owner)?;1594 Self::check_white_list(collection_id, sender)?;1595 }15961597 Ok(())1598 }15991600 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1601 match target_collection.mode1602 {1603 CollectionMode::NFT => {1604 if let CreateItemData::NFT(data) = data {1605 1606 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1607 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1608 } else {1609 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1610 }1611 },1612 CollectionMode::Fungible(_) => {1613 if let CreateItemData::Fungible(_) = data {1614 } else {1615 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1616 }1617 },1618 CollectionMode::ReFungible(_) => {1619 if let CreateItemData::ReFungible(data) = data {16201621 1622 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1623 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1624 } else {1625 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1626 }1627 },1628 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1629 };16301631 Ok(())1632 }16331634 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1635 match data1636 {1637 CreateItemData::NFT(data) => {1638 let item = NftItemType {1639 collection: collection_id,1640 owner,1641 const_data: data.const_data,1642 variable_data: data.variable_data1643 };16441645 Self::add_nft_item(item)?;1646 },1647 CreateItemData::Fungible(_) => {1648 let item = FungibleItemType {1649 collection: collection_id,1650 owner,1651 value: (10 as u128).pow(collection.decimal_points as u32)1652 };16531654 Self::add_fungible_item(item)?;1655 },1656 CreateItemData::ReFungible(data) => {1657 let mut owner_list = Vec::new();1658 let value = (10 as u128).pow(collection.decimal_points as u32);1659 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16601661 let item = ReFungibleItemType {1662 collection: collection_id,1663 owner: owner_list,1664 const_data: data.const_data,1665 variable_data: data.variable_data1666 };16671668 Self::add_refungible_item(item)?;1669 }1670 };16711672 1673 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16741675 Ok(())1676 }16771678 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1679 let current_index = <ItemListIndex>::get(item.collection)1680 .checked_add(1)1681 .ok_or(Error::<T>::NumOverflow)?;1682 let itemcopy = item.clone();1683 let owner = item.owner.clone();16841685 Self::add_token_index(item.collection, current_index, owner.clone())?;16861687 <ItemListIndex>::insert(item.collection, current_index);1688 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16891690 1691 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1692 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1693 1694 1695 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1696 .checked_add(item.value)1697 .ok_or(Error::<T>::NumOverflow)?;1698 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16991700 Ok(())1701 }17021703 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1704 let current_index = <ItemListIndex>::get(item.collection)1705 .checked_add(1)1706 .ok_or(Error::<T>::NumOverflow)?;1707 let itemcopy = item.clone();17081709 let value = item.owner.first().unwrap().fraction;1710 let owner = item.owner.first().unwrap().owner.clone();17111712 Self::add_token_index(item.collection, current_index, owner.clone())?;17131714 <ItemListIndex>::insert(item.collection, current_index);1715 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);17161717 1718 let block_number: T::BlockNumber = 0.into();1719 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);17201721 1722 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1723 .checked_add(value)1724 .ok_or(Error::<T>::NumOverflow)?;1725 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);17261727 Ok(())1728 }17291730 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1731 let current_index = <ItemListIndex>::get(item.collection)1732 .checked_add(1)1733 .ok_or(Error::<T>::NumOverflow)?;17341735 let item_owner = item.owner.clone();1736 let collection_id = item.collection.clone();1737 Self::add_token_index(collection_id, current_index, item.owner.clone())?;17381739 <ItemListIndex>::insert(collection_id, current_index);1740 <NftItemList<T>>::insert(collection_id, current_index, item);17411742 1743 let block_number: T::BlockNumber = 0.into();1744 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);17451746 1747 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1748 .checked_add(1)1749 .ok_or(Error::<T>::NumOverflow)?;1750 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17511752 Ok(())1753 }17541755 fn burn_refungible_item(1756 collection_id: CollectionId,1757 item_id: TokenId,1758 owner: T::AccountId,1759 ) -> DispatchResult {1760 ensure!(1761 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1762 Error::<T>::TokenNotFound1763 );1764 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1765 let item = collection1766 .owner1767 .iter()1768 .filter(|&i| i.owner == owner)1769 .next()1770 .unwrap();1771 Self::remove_token_index(collection_id, item_id, owner.clone())?;17721773 1774 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17751776 1777 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1778 .checked_sub(item.fraction)1779 .ok_or(Error::<T>::NumOverflow)?;1780 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17811782 <ReFungibleItemList<T>>::remove(collection_id, item_id);17831784 Ok(())1785 }17861787 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1788 ensure!(1789 <NftItemList<T>>::contains_key(collection_id, item_id),1790 Error::<T>::TokenNotFound1791 );1792 let item = <NftItemList<T>>::get(collection_id, item_id);1793 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17941795 1796 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17971798 1799 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1800 .checked_sub(1)1801 .ok_or(Error::<T>::NumOverflow)?;1802 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1803 <NftItemList<T>>::remove(collection_id, item_id);18041805 Ok(())1806 }18071808 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1809 ensure!(1810 <FungibleItemList<T>>::contains_key(collection_id, item_id),1811 Error::<T>::TokenNotFound1812 );1813 let item = <FungibleItemList<T>>::get(collection_id, item_id);1814 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;18151816 1817 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));18181819 1820 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1821 .checked_sub(item.value)1822 .ok_or(Error::<T>::NumOverflow)?;1823 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);18241825 <FungibleItemList<T>>::remove(collection_id, item_id);18261827 Ok(())1828 }18291830 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1831 ensure!(1832 <Collection<T>>::contains_key(collection_id),1833 Error::<T>::CollectionNotFound1834 );1835 Ok(())1836 }18371838 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1839 Self::collection_exists(collection_id)?;18401841 let target_collection = <Collection<T>>::get(collection_id);1842 ensure!(1843 subject == target_collection.owner,1844 Error::<T>::NoPermission1845 );18461847 Ok(())1848 }18491850 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1851 let target_collection = <Collection<T>>::get(collection_id);1852 let mut result: bool = subject == target_collection.owner;1853 let exists = <AdminList<T>>::contains_key(collection_id);18541855 if !result & exists {1856 if <AdminList<T>>::get(collection_id).contains(&subject) {1857 result = true1858 }1859 }18601861 result1862 }18631864 fn check_owner_or_admin_permissions(1865 collection_id: CollectionId,1866 subject: T::AccountId,1867 ) -> DispatchResult {1868 Self::collection_exists(collection_id)?;1869 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18701871 ensure!(1872 result,1873 Error::<T>::NoPermission1874 );1875 Ok(())1876 }18771878 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1879 let target_collection = <Collection<T>>::get(collection_id);18801881 match target_collection.mode {1882 CollectionMode::NFT => {1883 <NftItemList<T>>::get(collection_id, item_id).owner == subject1884 }1885 CollectionMode::Fungible(_) => {1886 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1887 }1888 CollectionMode::ReFungible(_) => {1889 <ReFungibleItemList<T>>::get(collection_id, item_id)1890 .owner1891 .iter()1892 .any(|i| i.owner == subject)1893 }1894 CollectionMode::Invalid => false,1895 }1896 }18971898 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1899 let mes = Error::<T>::AddresNotInWhiteList;1900 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);19011902 Ok(())1903 }19041905 fn transfer_fungible(1906 collection_id: CollectionId,1907 item_id: TokenId,1908 value: u128,1909 owner: T::AccountId,1910 new_owner: T::AccountId,1911 ) -> DispatchResult {1912 ensure!(1913 <FungibleItemList<T>>::contains_key(collection_id, item_id),1914 Error::<T>::TokenNotFound1915 );19161917 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1918 let amount = full_item.value;19191920 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19211922 1923 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1924 .checked_sub(value)1925 .ok_or(Error::<T>::NumOverflow)?;1926 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);19271928 let mut new_owner_account_id = 0;1929 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1930 if new_owner_items.len() > 0 {1931 new_owner_account_id = new_owner_items[0];1932 }19331934 1935 if amount == value && new_owner_account_id == 0 {1936 1937 1938 let mut new_full_item = full_item.clone();1939 new_full_item.owner = new_owner.clone();1940 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19411942 1943 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1944 .checked_add(value)1945 .ok_or(Error::<T>::NumOverflow)?;1946 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19471948 1949 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1950 } else {1951 let mut new_full_item = full_item.clone();1952 new_full_item.value -= value;19531954 1955 if new_owner_account_id > 0 {1956 1957 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1958 item.value += value;19591960 1961 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1962 .checked_add(value)1963 .ok_or(Error::<T>::NumOverflow)?;1964 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19651966 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1967 } else {1968 1969 let item = FungibleItemType {1970 collection: collection_id,1971 owner: new_owner.clone(),1972 value1973 };19741975 Self::add_fungible_item(item)?;1976 }19771978 if amount == value {1979 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19801981 1982 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1983 <FungibleItemList<T>>::remove(collection_id, item_id);1984 }19851986 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1987 }19881989 Ok(())1990 }19911992 fn transfer_refungible(1993 collection_id: CollectionId,1994 item_id: TokenId,1995 value: u128,1996 owner: T::AccountId,1997 new_owner: T::AccountId,1998 ) -> DispatchResult {1999 ensure!(2000 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2001 Error::<T>::TokenNotFound2002 );20032004 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2005 let item = full_item2006 .owner2007 .iter()2008 .filter(|i| i.owner == owner)2009 .next()2010 .ok_or(Error::<T>::NumOverflow)?;2011 let amount = item.fraction;20122013 ensure!(amount >= value, Error::<T>::TokenValueTooLow);20142015 2016 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2017 .checked_sub(value)2018 .ok_or(Error::<T>::NumOverflow)?;2019 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20202021 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2022 .checked_add(value)2023 .ok_or(Error::<T>::NumOverflow)?;2024 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20252026 let old_owner = item.owner.clone();2027 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);20282029 2030 if amount == value && !new_owner_has_account {2031 2032 2033 let mut new_full_item = full_item.clone();2034 new_full_item2035 .owner2036 .iter_mut()2037 .find(|i| i.owner == owner)2038 .unwrap()2039 .owner = new_owner.clone();2040 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);20412042 2043 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;2044 } else {2045 let mut new_full_item = full_item.clone();2046 new_full_item2047 .owner2048 .iter_mut()2049 .find(|i| i.owner == owner)2050 .unwrap()2051 .fraction -= value;20522053 2054 if new_owner_has_account {2055 2056 new_full_item2057 .owner2058 .iter_mut()2059 .find(|i| i.owner == new_owner)2060 .unwrap()2061 .fraction += value;2062 } else {2063 2064 new_full_item.owner.push(Ownership {2065 owner: new_owner.clone(),2066 fraction: value,2067 });2068 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2069 }20702071 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2072 }20732074 Ok(())2075 }20762077 fn transfer_nft(2078 collection_id: CollectionId,2079 item_id: TokenId,2080 sender: T::AccountId,2081 new_owner: T::AccountId,2082 ) -> DispatchResult {2083 ensure!(2084 <NftItemList<T>>::contains_key(collection_id, item_id),2085 Error::<T>::TokenNotFound2086 );20872088 let mut item = <NftItemList<T>>::get(collection_id, item_id);20892090 ensure!(2091 sender == item.owner,2092 Error::<T>::MustBeTokenOwner2093 );20942095 2096 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2097 .checked_sub(1)2098 .ok_or(Error::<T>::NumOverflow)?;2099 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);21002101 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2102 .checked_add(1)2103 .ok_or(Error::<T>::NumOverflow)?;2104 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);21052106 2107 let old_owner = item.owner.clone();2108 item.owner = new_owner.clone();2109 <NftItemList<T>>::insert(collection_id, item_id, item);21102111 2112 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;21132114 2115 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2116 Ok(())2117 }2118 2119 fn item_exists(2120 collection_id: CollectionId,2121 item_id: TokenId,2122 mode: &CollectionMode2123 ) -> DispatchResult {2124 match mode {2125 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2126 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2127 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2128 _ => ()2129 };2130 2131 Ok(())2132 }21332134 fn set_re_fungible_variable_data(2135 collection_id: CollectionId,2136 item_id: TokenId,2137 data: Vec<u8>2138 ) -> DispatchResult {2139 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);21402141 item.variable_data = data;21422143 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);21442145 Ok(())2146 }21472148 fn set_nft_variable_data(2149 collection_id: CollectionId,2150 item_id: TokenId,2151 data: Vec<u8>2152 ) -> DispatchResult {2153 let mut item = <NftItemList<T>>::get(collection_id, item_id);2154 2155 item.variable_data = data;21562157 <NftItemList<T>>::insert(collection_id, item_id, item);2158 2159 Ok(())2160 }21612162 fn init_collection(item: &CollectionType<T::AccountId>) {2163 2164 assert!(2165 item.decimal_points <= MAX_DECIMAL_POINTS,2166 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2167 );2168 assert!(2169 item.name.len() <= 64,2170 "Collection name can not be longer than 63 char"2171 );2172 assert!(2173 item.name.len() <= 256,2174 "Collection description can not be longer than 255 char"2175 );2176 assert!(2177 item.token_prefix.len() <= 16,2178 "Token prefix can not be longer than 15 char"2179 );21802181 2182 let next_id = CreatedCollectionCount::get()2183 .checked_add(1)2184 .unwrap();21852186 CreatedCollectionCount::put(next_id);2187 }21882189 fn init_nft_token(item: &NftItemType<T::AccountId>) {2190 let current_index = <ItemListIndex>::get(item.collection)2191 .checked_add(1)2192 .unwrap();21932194 let item_owner = item.owner.clone();2195 let collection_id = item.collection.clone();2196 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21972198 <ItemListIndex>::insert(collection_id, current_index);21992200 2201 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2202 .checked_add(1)2203 .unwrap();2204 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2205 }22062207 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2208 let current_index = <ItemListIndex>::get(item.collection)2209 .checked_add(1)2210 .unwrap();2211 let owner = item.owner.clone();22122213 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();22142215 <ItemListIndex>::insert(item.collection, current_index);22162217 2218 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2219 .checked_add(item.value)2220 .unwrap();2221 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2222 }22232224 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2225 let current_index = <ItemListIndex>::get(item.collection)2226 .checked_add(1)2227 .unwrap();22282229 let value = item.owner.first().unwrap().fraction;2230 let owner = item.owner.first().unwrap().owner.clone();22312232 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();22332234 <ItemListIndex>::insert(item.collection, current_index);22352236 2237 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2238 .checked_add(value)2239 .unwrap();2240 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2241 }22422243 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {22442245 2246 if <AccountItemCount<T>>::contains_key(owner.clone()) {22472248 2249 let count = <AccountItemCount<T>>::get(owner.clone());2250 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);22512252 <AccountItemCount<T>>::insert(owner.clone(), count2253 .checked_add(1)2254 .ok_or(Error::<T>::NumOverflow)?);2255 }2256 else {2257 <AccountItemCount<T>>::insert(owner.clone(), 1);2258 }22592260 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2261 if list_exists {2262 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2263 let item_contains = list.contains(&item_index.clone());22642265 if !item_contains {2266 list.push(item_index.clone());2267 }22682269 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2270 } else {2271 let mut itm = Vec::new();2272 itm.push(item_index.clone());2273 <AddressTokens<T>>::insert(collection_id, owner, itm);2274 2275 }22762277 Ok(())2278 }22792280 fn remove_token_index(2281 collection_id: CollectionId,2282 item_index: TokenId,2283 owner: T::AccountId,2284 ) -> DispatchResult {22852286 2287 <AccountItemCount<T>>::insert(owner.clone(), 2288 <AccountItemCount<T>>::get(owner.clone())2289 .checked_sub(1)2290 .ok_or(Error::<T>::NumOverflow)?);229122922293 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2294 if list_exists {2295 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2296 let item_contains = list.contains(&item_index.clone());22972298 if item_contains {2299 list.retain(|&item| item != item_index);2300 <AddressTokens<T>>::insert(collection_id, owner, list);2301 }2302 }23032304 Ok(())2305 }23062307 fn move_token_index(2308 collection_id: CollectionId,2309 item_index: TokenId,2310 old_owner: T::AccountId,2311 new_owner: T::AccountId,2312 ) -> DispatchResult {2313 Self::remove_token_index(collection_id, item_index, old_owner)?;2314 Self::add_token_index(collection_id, item_index, new_owner)?;23152316 Ok(())2317 }2318 2319 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2320 if <ContractOwner<T>>::contains_key(contract.clone()) {2321 let owner = <ContractOwner<T>>::get(contract);2322 ensure!(account == owner, Error::<T>::NoPermission);2323 } else {2324 fail!(Error::<T>::NoPermission);2325 }23262327 Ok(())2328 }2329}2330233123322333233423352336pub type Multiplier = FixedU128;23372338type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2339 <T as system::Trait>::AccountId,2340>>::Balance;2341type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2342 <T as system::Trait>::AccountId,2343>>::NegativeImbalance;2344234523462347#[derive(Encode, Decode, Clone, Eq, PartialEq)]2348pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2349 #[codec(compact)] BalanceOf<T>2350);23512352impl<T: Trait + Send + Sync> sp_std::fmt::Debug2353 for ChargeTransactionPayment<T>2354{2355 #[cfg(feature = "std")]2356 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2357 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2358 }2359 #[cfg(not(feature = "std"))]2360 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2361 Ok(())2362 }2363}23642365impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2366where2367 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2368 BalanceOf<T>: Send + Sync + FixedPointOperand,2369{2370 2371 pub fn from(fee: BalanceOf<T>) -> Self {2372 Self(fee)2373 }23742375 pub fn traditional_fee(2376 len: usize,2377 info: &DispatchInfoOf<T::Call>,2378 tip: BalanceOf<T>,2379 ) -> BalanceOf<T>2380 where2381 T::Call: Dispatchable<Info = DispatchInfo>,2382 {2383 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2384 }23852386 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2387 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2388 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2389 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2390 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2391 }23922393 fn withdraw_fee(2394 &self,2395 who: &T::AccountId,2396 call: &T::Call,2397 info: &DispatchInfoOf<T::Call>,2398 len: usize,2399 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2400 let tip = self.0;24012402 2403 2404 2405 2406 2407 2408 2409 let fee = Self::traditional_fee(len, info, tip);24102411 2412 2413 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2414 Some(Call::create_item(collection_id, _owner, _properties)) => {24152416 2417 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2418 {2419 <Collection<T>>::get(collection_id).sponsor2420 } else {2421 T::AccountId::default()2422 }2423 }2424 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2425 2426 let _collection_limits = <Collection<T>>::get(collection_id).limits;2427 let _collection_mode = <Collection<T>>::get(collection_id).mode;24282429 2430 let sponsor_transfer = match _collection_mode {2431 CollectionMode::NFT => {24322433 2434 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2435 _collection_limits.sponsor_transfer_timeout2436 } else {2437 ChainLimit::get().nft_sponsor_transfer_timeout2438 };24392440 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2441 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2442 let limit_time = basket + limit.into();2443 if block_number >= limit_time {2444 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2445 true2446 }2447 else {2448 false2449 }2450 }2451 CollectionMode::Fungible(_) => {24522453 2454 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2455 _collection_limits.sponsor_transfer_timeout2456 } else {2457 ChainLimit::get().fungible_sponsor_transfer_timeout2458 };24592460 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2461 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2462 if basket.iter().any(|i| i.address == _new_owner.clone())2463 {2464 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2465 let limit_time = item.start_block + limit.into();2466 if block_number >= limit_time {2467 basket.retain(|x| x.address == item.address);2468 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2469 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2470 true2471 }2472 else {2473 false2474 }2475 }2476 else {2477 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2478 true2479 }2480 }2481 CollectionMode::ReFungible(_) => {24822483 2484 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2485 _collection_limits.sponsor_transfer_timeout2486 } else {2487 ChainLimit::get().refungible_sponsor_transfer_timeout2488 };24892490 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2491 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2492 let limit_time = basket + limit.into();2493 if block_number >= limit_time {2494 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2495 true2496 } else {2497 false2498 }2499 }2500 _ => {2501 false2502 },2503 };25042505 if !sponsor_transfer {2506 T::AccountId::default()2507 } else {2508 <Collection<T>>::get(collection_id).sponsor2509 }2510 }25112512 _ => T::AccountId::default(),2513 };25142515 2516 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {25172518 2519 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {25202521 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2522 code_hash,2523 &data,2524 &who,2525 );2526 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25272528 T::AccountId::default()2529 },25302531 2532 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {25332534 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());25352536 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2537 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2538 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2539 2540 if !owned_contract && white_list_enabled {2541 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2542 return Err(InvalidTransaction::Call.into());2543 }2544 }25452546 let mut sponsor_transfer = false;2547 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2548 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2549 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2550 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2551 let limit_time = last_tx_block + rate_limit;25522553 if block_number >= limit_time {2554 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2555 sponsor_transfer = true;2556 }2557 } else {2558 sponsor_transfer = false;2559 }2560 2561 2562 let mut sp = T::AccountId::default();2563 if sponsor_transfer {2564 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2565 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2566 sp = called_contract;2567 }2568 }2569 }25702571 sp2572 },25732574 _ => sponsor,2575 };25762577 let mut who_pays_fee: T::AccountId = sponsor.clone();2578 if sponsor == T::AccountId::default() {2579 who_pays_fee = who.clone();2580 }25812582 2583 if fee.is_zero() {2584 return Ok((fee, None));2585 }25862587 match <T as transaction_payment::Trait>::Currency::withdraw(2588 &who_pays_fee,2589 fee,2590 if tip.is_zero() {2591 WithdrawReason::TransactionPayment.into()2592 } else {2593 WithdrawReason::TransactionPayment | WithdrawReason::Tip2594 },2595 ExistenceRequirement::KeepAlive,2596 ) {2597 Ok(imbalance) => Ok((fee, Some(imbalance))),2598 Err(_) => Err(InvalidTransaction::Payment.into()),2599 }2600 }2601}260226032604impl<T: Trait + Send + Sync> SignedExtension2605 for ChargeTransactionPayment<T>2606where2607 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2608 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2609{2610 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2611 type AccountId = T::AccountId;2612 type Call = T::Call;2613 type AdditionalSigned = ();2614 type Pre = (2615 BalanceOf<T>,2616 Self::AccountId,2617 Option<NegativeImbalanceOf<T>>,2618 BalanceOf<T>,2619 );2620 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2621 Ok(())2622 }26232624 fn validate(2625 &self,2626 who: &Self::AccountId,2627 call: &Self::Call,2628 info: &DispatchInfoOf<Self::Call>,2629 len: usize,2630 ) -> TransactionValidity {2631 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2632 Ok(ValidTransaction {2633 priority: Self::get_priority(len, info, fee),2634 ..Default::default()2635 })2636 }26372638 fn pre_dispatch(2639 self,2640 who: &Self::AccountId,2641 call: &Self::Call,2642 info: &DispatchInfoOf<Self::Call>,2643 len: usize,2644 ) -> Result<Self::Pre, TransactionValidityError> {2645 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2646 Ok((self.0, who.clone(), imbalance, fee))2647 }26482649 fn post_dispatch(2650 pre: Self::Pre,2651 info: &DispatchInfoOf<Self::Call>,2652 post_info: &PostDispatchInfoOf<Self::Call>,2653 len: usize,2654 _result: &DispatchResult,2655 ) -> Result<(), TransactionValidityError> {2656 let (tip, who, imbalance, fee) = pre;2657 if let Some(payed) = imbalance {2658 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2659 len as u32, info, post_info, tip,2660 );2661 let refund = fee.saturating_sub(actual_fee);2662 let actual_payment =2663 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2664 &who, refund,2665 ) {2666 Ok(refund_imbalance) => {2667 2668 2669 match payed.offset(refund_imbalance) {2670 Ok(actual_payment) => actual_payment,2671 Err(_) => return Err(InvalidTransaction::Payment.into()),2672 }2673 }2674 2675 2676 Err(_) => payed,2677 };2678 let imbalances = actual_payment.split(tip);2679 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2680 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2681 );2682 }2683 Ok(())2684 }2685}26862687