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}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259 pub const_data: Vec<u8>,260 pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266}267268#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]269#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]270pub struct CreateReFungibleData {271 pub const_data: Vec<u8>,272 pub variable_data: Vec<u8>,273}274275#[derive(Encode, Decode, Debug, Clone, PartialEq)]276#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]277pub enum CreateItemData {278 NFT(CreateNftData),279 Fungible(CreateFungibleData),280 ReFungible(CreateReFungibleData),281}282283impl CreateItemData {284 pub fn len(&self) -> usize {285 let len = match self {286 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),287 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),288 _ => 0289 };290 291 return len;292 }293}294295impl From<CreateNftData> for CreateItemData {296 fn from(item: CreateNftData) -> Self {297 CreateItemData::NFT(item)298 }299}300301impl From<CreateReFungibleData> for CreateItemData {302 fn from(item: CreateReFungibleData) -> Self {303 CreateItemData::ReFungible(item)304 }305}306307impl From<CreateFungibleData> for CreateItemData {308 fn from(item: CreateFungibleData) -> Self {309 CreateItemData::Fungible(item)310 }311}312313314decl_error! {315 316 pub enum Error for Module<T: Trait> {317 318 TotalCollectionsLimitExceeded,319 320 CollectionDecimalPointLimitExceeded, 321 322 CollectionNameLimitExceeded, 323 324 CollectionDescriptionLimitExceeded, 325 326 CollectionTokenPrefixLimitExceeded,327 328 CollectionNotFound,329 330 TokenNotFound,331 332 NumOverflow, 333 334 AlreadyAdmin, 335 336 NoPermission,337 338 ConfirmUnsetSponsorFail,339 340 PublicMintingNotAllowed,341 342 MustBeTokenOwner,343 344 TokenValueTooLow,345 346 NftSizeLimitExceeded,347 348 ApproveNotFound,349 350 TokenValueNotEnough,351 352 ApproveRequired,353 354 AddresNotInWhiteList,355 356 CollectionAdminsLimitExceeded,357 358 AddressOwnershipLimitExceeded,359 360 EmptyArgument,361 362 TokenConstDataLimitExceeded,363 364 TokenVariableDataLimitExceeded,365 366 NotNftDataUsedToMintNftCollectionToken,367 368 NotFungibleDataUsedToMintFungibleCollectionToken,369 370 NotReFungibleDataUsedToMintReFungibleCollectionToken,371 372 UnexpectedCollectionType,373 374 CantStoreMetadataInFungibleTokens,375 376 CollectionTokenLimitExceeded,377 378 AccountTokenLimitExceeded,379 380 CollectionLimitBoundsExceeded381 }382}383384pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {385 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;386387 388 type WeightInfo: WeightInfo;389}390391#[cfg(feature = "runtime-benchmarks")]392mod benchmarking;393394395396decl_storage! {397 trait Store for Module<T: Trait> as Nft {398399 400 NextCollectionID: CollectionId;401 CreatedCollectionCount: u32;402 ChainVersion: u64;403 ItemListIndex: map hasher(identity) CollectionId => TokenId;404405 406 pub ChainLimit get(fn chain_limit) config(): ChainLimits;407408 409 CollectionCount: u32;410 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;411412 413 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;414 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;415 pub WhiteList get(fn white_list): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => bool;416417 418 pub Balance get(fn balance_count): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => u128;419420 421 pub ApprovedList get(fn approved): double_map hasher(identity) CollectionId, hasher(twox_64_concat) (TokenId, T::AccountId) => Vec<ApprovePermissions<T::AccountId>>;422423 424 pub NftItemList get(fn nft_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => NftItemType<T::AccountId>;425 pub FungibleItemList get(fn fungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => FungibleItemType<T::AccountId>;426 pub ReFungibleItemList get(fn refungible_item_id) config(): double_map hasher(identity) CollectionId, hasher(identity) TokenId => ReFungibleItemType<T::AccountId>;427428 429 pub AddressTokens get(fn address_tokens): double_map hasher(identity) CollectionId, hasher(twox_64_concat) T::AccountId => Vec<TokenId>;430431 432 pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;433 pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => Vec<BasketItem<T::AccountId, T::BlockNumber>>;434 pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(identity) CollectionId, hasher(identity) TokenId => T::BlockNumber;435436 437 pub ContractOwner get(fn contract_owner): map hasher(twox_64_concat) T::AccountId => T::AccountId;438 pub ContractSelfSponsoring get(fn contract_self_sponsoring): map hasher(twox_64_concat) T::AccountId => bool;439 pub ContractSponsorBasket get(fn contract_sponsor_basket): map hasher(twox_64_concat) (T::AccountId, T::AccountId) => T::BlockNumber;440 pub ContractSponsoringRateLimit get(fn contract_sponsoring_rate_limit): map hasher(twox_64_concat) T::AccountId => T::BlockNumber;441 pub ContractWhiteListEnabled get(fn contract_white_list_enabled): map hasher(twox_64_concat) T::AccountId => bool; 442 pub ContractWhiteList get(fn contract_white_list): double_map hasher(twox_64_concat) T::AccountId, hasher(twox_64_concat) T::AccountId => bool; 443 }444 add_extra_genesis {445 build(|config: &GenesisConfig<T>| {446 447 for (_num, _c) in &config.collection {448 <Module<T>>::init_collection(_c);449 }450451 for (_num, _q, _i) in &config.nft_item_id {452 <Module<T>>::init_nft_token(_i);453 }454455 for (_num, _q, _i) in &config.fungible_item_id {456 <Module<T>>::init_fungible_token(_i);457 }458459 for (_num, _q, _i) in &config.refungible_item_id {460 <Module<T>>::init_refungible_token(_i);461 }462 })463 }464}465466decl_event!(467 pub enum Event<T>468 where469 AccountId = <T as system::Trait>::AccountId,470 {471 472 473 474 475 476 477 478 479 480 Created(CollectionId, u8, AccountId),481482 483 484 485 486 487 488 489 ItemCreated(CollectionId, TokenId),490491 492 493 494 495 496 497 498 ItemDestroyed(CollectionId, TokenId),499 }500);501502decl_module! {503 pub struct Module<T: Trait> for enum Call where origin: T::Origin {504505 fn deposit_event() = default;506 type Error = Error<T>;507508 fn on_initialize(now: T::BlockNumber) -> Weight {509510 if ChainVersion::get() < 2511 {512 let value = NextCollectionID::get();513 CreatedCollectionCount::put(value);514 ChainVersion::put(2);515 }516517 0518 }519520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 #[weight = T::WeightInfo::create_collection()]537 pub fn create_collection(origin,538 collection_name: Vec<u16>,539 collection_description: Vec<u16>,540 token_prefix: Vec<u8>,541 mode: CollectionMode) -> DispatchResult {542543 544 let who = ensure_signed(origin)?;545546 let decimal_points = match mode {547 CollectionMode::Fungible(points) => points,548 CollectionMode::ReFungible(points) => points,549 _ => 0550 };551552 553 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);554555 556 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);557558 let mut name = collection_name.to_vec();559 name.push(0);560 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);561562 let mut description = collection_description.to_vec();563 description.push(0);564 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);565566 let mut prefix = token_prefix.to_vec();567 prefix.push(0);568 ensure!(prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);569570 571 let next_id = CreatedCollectionCount::get()572 .checked_add(1)573 .ok_or(Error::<T>::NumOverflow)?;574575 576 let total = CollectionCount::get()577 .checked_add(1)578 .ok_or(Error::<T>::NumOverflow)?;579580 CreatedCollectionCount::put(next_id);581 CollectionCount::put(total);582583 584 let new_collection = CollectionType {585 owner: who.clone(),586 name: name,587 mode: mode.clone(),588 mint_mode: false,589 access: AccessMode::Normal,590 description: description,591 decimal_points: decimal_points,592 token_prefix: prefix,593 offchain_schema: Vec::new(),594 schema_version: SchemaVersion::ImageURL,595 sponsor: T::AccountId::default(),596 unconfirmed_sponsor: T::AccountId::default(),597 variable_on_chain_schema: Vec::new(),598 const_on_chain_schema: Vec::new(),599 limits: CollectionLimits::default(),600 };601602 603 <Collection<T>>::insert(next_id, new_collection);604605 606 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));607608 Ok(())609 }610611 612 613 614 615 616 617 618 619 620 #[weight = T::WeightInfo::destroy_collection()]621 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {622623 let sender = ensure_signed(origin)?;624 Self::check_owner_permissions(collection_id, sender)?;625626 <AddressTokens<T>>::remove_prefix(collection_id);627 <ApprovedList<T>>::remove_prefix(collection_id);628 <Balance<T>>::remove_prefix(collection_id);629 <ItemListIndex>::remove(collection_id);630 <AdminList<T>>::remove(collection_id);631 <Collection<T>>::remove(collection_id);632 <WhiteList<T>>::remove_prefix(collection_id);633634 <NftItemList<T>>::remove_prefix(collection_id);635 <FungibleItemList<T>>::remove_prefix(collection_id);636 <ReFungibleItemList<T>>::remove_prefix(collection_id);637638 <NftTransferBasket<T>>::remove_prefix(collection_id);639 <FungibleTransferBasket<T>>::remove_prefix(collection_id);640 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);641642 if CollectionCount::get() > 0643 {644 645 let total = CollectionCount::get()646 .checked_sub(1)647 .ok_or(Error::<T>::NumOverflow)?;648649 CollectionCount::put(total);650 }651652 Ok(())653 }654655 656 657 658 659 660 661 662 663 664 665 666 667 #[weight = T::WeightInfo::add_to_white_list()]668 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{669670 let sender = ensure_signed(origin)?;671 Self::check_owner_or_admin_permissions(collection_id, sender)?;672673 <WhiteList<T>>::insert(collection_id, address, true);674 675 Ok(())676 }677678 679 680 681 682 683 684 685 686 687 688 689 690 #[weight = T::WeightInfo::remove_from_white_list()]691 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{692693 let sender = ensure_signed(origin)?;694 Self::check_owner_or_admin_permissions(collection_id, sender)?;695696 <WhiteList<T>>::remove(collection_id, address);697698 Ok(())699 }700701 702 703 704 705 706 707 708 709 710 711 712 #[weight = T::WeightInfo::set_public_access_mode()]713 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult714 {715 let sender = ensure_signed(origin)?;716717 Self::check_owner_permissions(collection_id, sender)?;718 let mut target_collection = <Collection<T>>::get(collection_id);719 target_collection.access = mode;720 <Collection<T>>::insert(collection_id, target_collection);721722 Ok(())723 }724725 726 727 728 729 730 731 732 733 734 735 736 737 738 #[weight = T::WeightInfo::set_mint_permission()]739 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult740 {741 let sender = ensure_signed(origin)?;742743 Self::check_owner_permissions(collection_id, sender)?;744 let mut target_collection = <Collection<T>>::get(collection_id);745 target_collection.mint_mode = mint_permission;746 <Collection<T>>::insert(collection_id, target_collection);747748 Ok(())749 }750751 752 753 754 755 756 757 758 759 760 761 762 #[weight = T::WeightInfo::change_collection_owner()]763 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {764765 let sender = ensure_signed(origin)?;766 Self::check_owner_permissions(collection_id, sender)?;767 let mut target_collection = <Collection<T>>::get(collection_id);768 target_collection.owner = new_owner;769 <Collection<T>>::insert(collection_id, target_collection);770771 Ok(())772 }773774 775 776 777 778 779 780 781 782 783 784 785 786 787 #[weight = T::WeightInfo::add_collection_admin()]788 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {789790 let sender = ensure_signed(origin)?;791 Self::check_owner_or_admin_permissions(collection_id, sender)?;792 let mut admin_arr: Vec<T::AccountId> = Vec::new();793794 if <AdminList<T>>::contains_key(collection_id)795 {796 admin_arr = <AdminList<T>>::get(collection_id);797 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);798 }799800 801 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);802803 admin_arr.push(new_admin_id);804 <AdminList<T>>::insert(collection_id, admin_arr);805806 Ok(())807 }808809 810 811 812 813 814 815 816 817 818 819 820 821 #[weight = T::WeightInfo::remove_collection_admin()]822 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {823824 let sender = ensure_signed(origin)?;825 Self::check_owner_or_admin_permissions(collection_id, sender)?;826827 if <AdminList<T>>::contains_key(collection_id)828 {829 let mut admin_arr = <AdminList<T>>::get(collection_id);830 admin_arr.retain(|i| *i != account_id);831 <AdminList<T>>::insert(collection_id, admin_arr);832 }833834 Ok(())835 }836837 838 839 840 841 842 843 844 845 846 #[weight = T::WeightInfo::set_collection_sponsor()]847 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {848849 let sender = ensure_signed(origin)?;850 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);851852 let mut target_collection = <Collection<T>>::get(collection_id);853 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);854855 target_collection.unconfirmed_sponsor = new_sponsor;856 <Collection<T>>::insert(collection_id, target_collection);857858 Ok(())859 }860861 862 863 864 865 866 867 868 #[weight = T::WeightInfo::confirm_sponsorship()]869 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {870871 let sender = ensure_signed(origin)?;872 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);873874 let mut target_collection = <Collection<T>>::get(collection_id);875 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);876877 target_collection.sponsor = target_collection.unconfirmed_sponsor;878 target_collection.unconfirmed_sponsor = T::AccountId::default();879 <Collection<T>>::insert(collection_id, target_collection);880881 Ok(())882 }883884 885 886 887 888 889 890 891 892 893 #[weight = T::WeightInfo::remove_collection_sponsor()]894 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {895896 let sender = ensure_signed(origin)?;897 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);898899 let mut target_collection = <Collection<T>>::get(collection_id);900 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);901902 target_collection.sponsor = T::AccountId::default();903 <Collection<T>>::insert(collection_id, target_collection);904905 Ok(())906 }907908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931932 #[weight = T::WeightInfo::create_item(data.len())]933 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {934935 let sender = ensure_signed(origin)?;936937 Self::collection_exists(collection_id)?;938939 let target_collection = <Collection<T>>::get(collection_id);940941 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;942 Self::validate_create_item_args(&target_collection, &data)?;943 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;944945 Ok(())946 }947948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 #[weight = T::WeightInfo::create_item(items_data.into_iter()967 .map(|data| { data.len() })968 .sum())]969 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {970971 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);972 let sender = ensure_signed(origin)?;973974 Self::collection_exists(collection_id)?;975 let target_collection = <Collection<T>>::get(collection_id);976977 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;978979 for data in &items_data {980 Self::validate_create_item_args(&target_collection, data)?;981 }982 for data in &items_data {983 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;984 }985986 Ok(())987 }988989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 #[weight = T::WeightInfo::burn_item()]1003 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10041005 let sender = ensure_signed(origin)?;1006 Self::collection_exists(collection_id)?;10071008 1009 let target_collection = <Collection<T>>::get(collection_id);1010 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1011 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1012 Error::<T>::NoPermission);10131014 if target_collection.access == AccessMode::WhiteList {1015 Self::check_white_list(collection_id, &sender)?;1016 }10171018 match target_collection.mode1019 {1020 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1021 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1022 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1023 _ => ()1024 };10251026 1027 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10281029 Ok(())1030 }10311032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 #[weight = T::WeightInfo::transfer()]1056 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10571058 let sender = ensure_signed(origin)?;1059 let target_collection = <Collection<T>>::get(collection_id);10601061 1062 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10631064 1065 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1066 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1067 Error::<T>::NoPermission);10681069 if target_collection.access == AccessMode::WhiteList {1070 Self::check_white_list(collection_id, &sender)?;1071 Self::check_white_list(collection_id, &recipient)?;1072 }10731074 match target_collection.mode1075 {1076 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1077 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1078 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1079 _ => ()1080 };10811082 Ok(())1083 }10841085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 #[weight = T::WeightInfo::approve()]1101 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11021103 let sender = ensure_signed(origin)?;11041105 1106 let target_collection = <Collection<T>>::get(collection_id);1107 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1108 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1109 Error::<T>::NoPermission);11101111 if target_collection.access == AccessMode::WhiteList {1112 Self::check_white_list(collection_id, &sender)?;1113 Self::check_white_list(collection_id, &approved)?;1114 }11151116 1117 let amount = 100000000;11181119 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1120 if list_exists {11211122 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1123 let item_contains = list.iter().any(|i| i.approved == approved);11241125 if !item_contains {1126 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1127 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1128 }1129 } else {11301131 let mut list = Vec::new();1132 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1133 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1134 }11351136 Ok(())1137 }1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 #[weight = T::WeightInfo::transfer_from()]1159 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11601161 let sender = ensure_signed(origin)?;1162 let mut appoved_transfer = false;11631164 1165 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1166 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1167 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1168 if opt_item.is_some()1169 {1170 appoved_transfer = true;1171 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1172 }1173 }11741175 let target_collection = <Collection<T>>::get(collection_id);11761177 1178 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11791180 1181 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1182 Error::<T>::NoPermission);11831184 if target_collection.access == AccessMode::WhiteList {1185 Self::check_white_list(collection_id, &sender)?;1186 Self::check_white_list(collection_id, &recipient)?;1187 }11881189 1190 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1191 .into_iter().filter(|i| i.approved != sender.clone()).collect();1192 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);119311941195 match target_collection.mode1196 {1197 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1198 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1199 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1200 _ => ()1201 };12021203 Ok(())1204 }12051206 #[weight = 0]1207 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12081209 1210 1211 1212 12131214 12151216 12171218 Ok(())1219 }12201221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 #[weight = T::WeightInfo::set_variable_meta_data()]1234 pub fn set_variable_meta_data (1235 origin,1236 collection_id: CollectionId,1237 item_id: TokenId,1238 data: Vec<u8>1239 ) -> DispatchResult {1240 let sender = ensure_signed(origin)?;1241 1242 Self::collection_exists(collection_id)?;1243 1244 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12451246 1247 let target_collection = <Collection<T>>::get(collection_id);1248 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1249 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1250 Error::<T>::NoPermission);12511252 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12531254 match target_collection.mode1255 {1256 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1257 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1258 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1259 _ => fail!(Error::<T>::UnexpectedCollectionType)1260 };12611262 Ok(())1263 }1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 #[weight = 0]1280 pub fn set_schema_version(1281 origin,1282 collection_id: CollectionId,1283 version: SchemaVersion1284 ) -> DispatchResult {1285 let sender = ensure_signed(origin)?;1286 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1287 let mut target_collection = <Collection<T>>::get(collection_id);1288 target_collection.schema_version = version;1289 <Collection<T>>::insert(collection_id, target_collection);12901291 Ok(())1292 }12931294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 #[weight = T::WeightInfo::set_offchain_schema()]1307 pub fn set_offchain_schema(1308 origin,1309 collection_id: CollectionId,1310 schema: Vec<u8>1311 ) -> DispatchResult {1312 let sender = ensure_signed(origin)?;1313 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13141315 let mut target_collection = <Collection<T>>::get(collection_id);1316 target_collection.offchain_schema = schema;1317 <Collection<T>>::insert(collection_id, target_collection);13181319 Ok(())1320 }13211322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 #[weight = T::WeightInfo::set_const_on_chain_schema()]1335 pub fn set_const_on_chain_schema (1336 origin,1337 collection_id: CollectionId,1338 schema: Vec<u8>1339 ) -> DispatchResult {1340 let sender = ensure_signed(origin)?;1341 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13421343 let mut target_collection = <Collection<T>>::get(collection_id);1344 target_collection.const_on_chain_schema = schema;1345 <Collection<T>>::insert(collection_id, target_collection);13461347 Ok(())1348 }13491350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 #[weight = T::WeightInfo::set_const_on_chain_schema()]1363 pub fn set_variable_on_chain_schema (1364 origin,1365 collection_id: CollectionId,1366 schema: Vec<u8>1367 ) -> DispatchResult {1368 let sender = ensure_signed(origin)?;1369 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13701371 let mut target_collection = <Collection<T>>::get(collection_id);1372 target_collection.variable_on_chain_schema = schema;1373 <Collection<T>>::insert(collection_id, target_collection);13741375 Ok(())1376 }13771378 1379 #[weight = 0]1380 pub fn set_chain_limits(1381 origin,1382 limits: ChainLimits1383 ) -> DispatchResult {1384 ensure_root(origin)?;1385 <ChainLimit>::put(limits);1386 Ok(())1387 }13881389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 #[weight = T::WeightInfo::enable_contract_sponsoring()]1401 pub fn enable_contract_sponsoring(1402 origin,1403 contract_address: T::AccountId,1404 enable: bool1405 ) -> DispatchResult {14061407 let sender = ensure_signed(origin)?;14081409 #[cfg(feature = "runtime-benchmarks")]1410 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14111412 Self::ensure_contract_owned(sender, &contract_address)?;14131414 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1415 Ok(())1416 }14171418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 #[weight = 0]1436 pub fn set_contract_sponsoring_rate_limit(1437 origin,1438 contract_address: T::AccountId,1439 rate_limit: T::BlockNumber1440 ) -> DispatchResult {1441 let sender = ensure_signed(origin)?;1442 Self::ensure_contract_owned(sender, &contract_address)?;14431444 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1445 Ok(())1446 }14471448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 #[weight = 0]1460 pub fn toggle_contract_white_list(1461 origin,1462 contract_address: T::AccountId,1463 enable: bool1464 ) -> DispatchResult {1465 let sender = ensure_signed(origin)?;1466 Self::ensure_contract_owned(sender, &contract_address)?;14671468 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1469 Ok(())1470 }1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 #[weight = 0]1484 pub fn add_to_contract_white_list(1485 origin,1486 contract_address: T::AccountId,1487 account_address: T::AccountId1488 ) -> DispatchResult {1489 let sender = ensure_signed(origin)?;1490 Self::ensure_contract_owned(sender, &contract_address)?;1491 1492 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1493 Ok(())1494 }14951496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 #[weight = 0]1508 pub fn remove_from_contract_white_list(1509 origin,1510 contract_address: T::AccountId,1511 account_address: T::AccountId1512 ) -> DispatchResult {1513 let sender = ensure_signed(origin)?;1514 Self::ensure_contract_owned(sender, &contract_address)?;1515 1516 <ContractWhiteList<T>>::remove(contract_address, account_address);1517 Ok(())1518 }15191520 #[weight = 0]1521 pub fn set_collection_limits(1522 origin,1523 collection_id: u32,1524 limits: CollectionLimits,1525 ) -> DispatchResult {1526 let sender = ensure_signed(origin)?;1527 Self::check_owner_permissions(collection_id, sender.clone())?;1528 let mut target_collection = <Collection<T>>::get(collection_id);1529 let chain_limits = ChainLimit::get();1530 let climits = target_collection.limits;15311532 1533 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1534 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1535 Error::<T>::CollectionLimitBoundsExceeded);15361537 1538 ensure!(climits.token_limit > limits.token_limit && 1539 limits.token_limit <= chain_limits.account_token_ownership_limit, 1540 Error::<T>::AccountTokenLimitExceeded);15411542 target_collection.limits = limits;1543 <Collection<T>>::insert(collection_id, target_collection);15441545 Ok(())1546 } 1547 }1548}15491550impl<T: Trait> Module<T> {15511552 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15531554 1555 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1556 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1557 1558 Ok(())1559 }15601561 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15621563 1564 let total_items: u32 = ItemListIndex::get(collection_id);1565 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1566 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1567 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15681569 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1570 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1571 Self::check_white_list(collection_id, owner)?;1572 Self::check_white_list(collection_id, sender)?;1573 }15741575 Ok(())1576 }15771578 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1579 match target_collection.mode1580 {1581 CollectionMode::NFT => {1582 if let CreateItemData::NFT(data) = data {1583 1584 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1585 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1586 } else {1587 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1588 }1589 },1590 CollectionMode::Fungible(_) => {1591 if let CreateItemData::Fungible(_) = data {1592 } else {1593 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1594 }1595 },1596 CollectionMode::ReFungible(_) => {1597 if let CreateItemData::ReFungible(data) = data {15981599 1600 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1601 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1602 } else {1603 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1604 }1605 },1606 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1607 };16081609 Ok(())1610 }16111612 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1613 match data1614 {1615 CreateItemData::NFT(data) => {1616 let item = NftItemType {1617 collection: collection_id,1618 owner,1619 const_data: data.const_data,1620 variable_data: data.variable_data1621 };16221623 Self::add_nft_item(item)?;1624 },1625 CreateItemData::Fungible(_) => {1626 let item = FungibleItemType {1627 collection: collection_id,1628 owner,1629 value: (10 as u128).pow(collection.decimal_points as u32)1630 };16311632 Self::add_fungible_item(item)?;1633 },1634 CreateItemData::ReFungible(data) => {1635 let mut owner_list = Vec::new();1636 let value = (10 as u128).pow(collection.decimal_points as u32);1637 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16381639 let item = ReFungibleItemType {1640 collection: collection_id,1641 owner: owner_list,1642 const_data: data.const_data,1643 variable_data: data.variable_data1644 };16451646 Self::add_refungible_item(item)?;1647 }1648 };16491650 1651 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16521653 Ok(())1654 }16551656 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1657 let current_index = <ItemListIndex>::get(item.collection)1658 .checked_add(1)1659 .ok_or(Error::<T>::NumOverflow)?;1660 let itemcopy = item.clone();1661 let owner = item.owner.clone();16621663 Self::add_token_index(item.collection, current_index, owner.clone())?;16641665 <ItemListIndex>::insert(item.collection, current_index);1666 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16671668 1669 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1670 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1671 1672 1673 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1674 .checked_add(item.value)1675 .ok_or(Error::<T>::NumOverflow)?;1676 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16771678 Ok(())1679 }16801681 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1682 let current_index = <ItemListIndex>::get(item.collection)1683 .checked_add(1)1684 .ok_or(Error::<T>::NumOverflow)?;1685 let itemcopy = item.clone();16861687 let value = item.owner.first().unwrap().fraction;1688 let owner = item.owner.first().unwrap().owner.clone();16891690 Self::add_token_index(item.collection, current_index, owner.clone())?;16911692 <ItemListIndex>::insert(item.collection, current_index);1693 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16941695 1696 let block_number: T::BlockNumber = 0.into();1697 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16981699 1700 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1701 .checked_add(value)1702 .ok_or(Error::<T>::NumOverflow)?;1703 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);17041705 Ok(())1706 }17071708 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1709 let current_index = <ItemListIndex>::get(item.collection)1710 .checked_add(1)1711 .ok_or(Error::<T>::NumOverflow)?;17121713 let item_owner = item.owner.clone();1714 let collection_id = item.collection.clone();1715 Self::add_token_index(collection_id, current_index, item.owner.clone())?;17161717 <ItemListIndex>::insert(collection_id, current_index);1718 <NftItemList<T>>::insert(collection_id, current_index, item);17191720 1721 let block_number: T::BlockNumber = 0.into();1722 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);17231724 1725 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1726 .checked_add(1)1727 .ok_or(Error::<T>::NumOverflow)?;1728 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17291730 Ok(())1731 }17321733 fn burn_refungible_item(1734 collection_id: CollectionId,1735 item_id: TokenId,1736 owner: T::AccountId,1737 ) -> DispatchResult {1738 ensure!(1739 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1740 Error::<T>::TokenNotFound1741 );1742 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1743 let item = collection1744 .owner1745 .iter()1746 .filter(|&i| i.owner == owner)1747 .next()1748 .unwrap();1749 Self::remove_token_index(collection_id, item_id, owner.clone())?;17501751 1752 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17531754 1755 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1756 .checked_sub(item.fraction)1757 .ok_or(Error::<T>::NumOverflow)?;1758 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17591760 <ReFungibleItemList<T>>::remove(collection_id, item_id);17611762 Ok(())1763 }17641765 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1766 ensure!(1767 <NftItemList<T>>::contains_key(collection_id, item_id),1768 Error::<T>::TokenNotFound1769 );1770 let item = <NftItemList<T>>::get(collection_id, item_id);1771 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17721773 1774 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17751776 1777 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1778 .checked_sub(1)1779 .ok_or(Error::<T>::NumOverflow)?;1780 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1781 <NftItemList<T>>::remove(collection_id, item_id);17821783 Ok(())1784 }17851786 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1787 ensure!(1788 <FungibleItemList<T>>::contains_key(collection_id, item_id),1789 Error::<T>::TokenNotFound1790 );1791 let item = <FungibleItemList<T>>::get(collection_id, item_id);1792 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17931794 1795 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17961797 1798 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1799 .checked_sub(item.value)1800 .ok_or(Error::<T>::NumOverflow)?;1801 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);18021803 <FungibleItemList<T>>::remove(collection_id, item_id);18041805 Ok(())1806 }18071808 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1809 ensure!(1810 <Collection<T>>::contains_key(collection_id),1811 Error::<T>::CollectionNotFound1812 );1813 Ok(())1814 }18151816 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1817 Self::collection_exists(collection_id)?;18181819 let target_collection = <Collection<T>>::get(collection_id);1820 ensure!(1821 subject == target_collection.owner,1822 Error::<T>::NoPermission1823 );18241825 Ok(())1826 }18271828 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1829 let target_collection = <Collection<T>>::get(collection_id);1830 let mut result: bool = subject == target_collection.owner;1831 let exists = <AdminList<T>>::contains_key(collection_id);18321833 if !result & exists {1834 if <AdminList<T>>::get(collection_id).contains(&subject) {1835 result = true1836 }1837 }18381839 result1840 }18411842 fn check_owner_or_admin_permissions(1843 collection_id: CollectionId,1844 subject: T::AccountId,1845 ) -> DispatchResult {1846 Self::collection_exists(collection_id)?;1847 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18481849 ensure!(1850 result,1851 Error::<T>::NoPermission1852 );1853 Ok(())1854 }18551856 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1857 let target_collection = <Collection<T>>::get(collection_id);18581859 match target_collection.mode {1860 CollectionMode::NFT => {1861 <NftItemList<T>>::get(collection_id, item_id).owner == subject1862 }1863 CollectionMode::Fungible(_) => {1864 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1865 }1866 CollectionMode::ReFungible(_) => {1867 <ReFungibleItemList<T>>::get(collection_id, item_id)1868 .owner1869 .iter()1870 .any(|i| i.owner == subject)1871 }1872 CollectionMode::Invalid => false,1873 }1874 }18751876 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1877 let mes = Error::<T>::AddresNotInWhiteList;1878 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);18791880 Ok(())1881 }18821883 fn transfer_fungible(1884 collection_id: CollectionId,1885 item_id: TokenId,1886 value: u128,1887 owner: T::AccountId,1888 new_owner: T::AccountId,1889 ) -> DispatchResult {1890 ensure!(1891 <FungibleItemList<T>>::contains_key(collection_id, item_id),1892 Error::<T>::TokenNotFound1893 );18941895 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1896 let amount = full_item.value;18971898 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18991900 1901 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1902 .checked_sub(value)1903 .ok_or(Error::<T>::NumOverflow)?;1904 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);19051906 let mut new_owner_account_id = 0;1907 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1908 if new_owner_items.len() > 0 {1909 new_owner_account_id = new_owner_items[0];1910 }19111912 1913 if amount == value && new_owner_account_id == 0 {1914 1915 1916 let mut new_full_item = full_item.clone();1917 new_full_item.owner = new_owner.clone();1918 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19191920 1921 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1922 .checked_add(value)1923 .ok_or(Error::<T>::NumOverflow)?;1924 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19251926 1927 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1928 } else {1929 let mut new_full_item = full_item.clone();1930 new_full_item.value -= value;19311932 1933 if new_owner_account_id > 0 {1934 1935 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1936 item.value += value;19371938 1939 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1940 .checked_add(value)1941 .ok_or(Error::<T>::NumOverflow)?;1942 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19431944 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1945 } else {1946 1947 let item = FungibleItemType {1948 collection: collection_id,1949 owner: new_owner.clone(),1950 value1951 };19521953 Self::add_fungible_item(item)?;1954 }19551956 if amount == value {1957 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19581959 1960 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1961 <FungibleItemList<T>>::remove(collection_id, item_id);1962 }19631964 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1965 }19661967 Ok(())1968 }19691970 fn transfer_refungible(1971 collection_id: CollectionId,1972 item_id: TokenId,1973 value: u128,1974 owner: T::AccountId,1975 new_owner: T::AccountId,1976 ) -> DispatchResult {1977 ensure!(1978 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1979 Error::<T>::TokenNotFound1980 );19811982 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1983 let item = full_item1984 .owner1985 .iter()1986 .filter(|i| i.owner == owner)1987 .next()1988 .ok_or(Error::<T>::NumOverflow)?;1989 let amount = item.fraction;19901991 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19921993 1994 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1995 .checked_sub(value)1996 .ok_or(Error::<T>::NumOverflow)?;1997 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19981999 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2000 .checked_add(value)2001 .ok_or(Error::<T>::NumOverflow)?;2002 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20032004 let old_owner = item.owner.clone();2005 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);20062007 2008 if amount == value && !new_owner_has_account {2009 2010 2011 let mut new_full_item = full_item.clone();2012 new_full_item2013 .owner2014 .iter_mut()2015 .find(|i| i.owner == owner)2016 .unwrap()2017 .owner = new_owner.clone();2018 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);20192020 2021 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;2022 } else {2023 let mut new_full_item = full_item.clone();2024 new_full_item2025 .owner2026 .iter_mut()2027 .find(|i| i.owner == owner)2028 .unwrap()2029 .fraction -= value;20302031 2032 if new_owner_has_account {2033 2034 new_full_item2035 .owner2036 .iter_mut()2037 .find(|i| i.owner == new_owner)2038 .unwrap()2039 .fraction += value;2040 } else {2041 2042 new_full_item.owner.push(Ownership {2043 owner: new_owner.clone(),2044 fraction: value,2045 });2046 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2047 }20482049 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2050 }20512052 Ok(())2053 }20542055 fn transfer_nft(2056 collection_id: CollectionId,2057 item_id: TokenId,2058 sender: T::AccountId,2059 new_owner: T::AccountId,2060 ) -> DispatchResult {2061 ensure!(2062 <NftItemList<T>>::contains_key(collection_id, item_id),2063 Error::<T>::TokenNotFound2064 );20652066 let mut item = <NftItemList<T>>::get(collection_id, item_id);20672068 ensure!(2069 sender == item.owner,2070 Error::<T>::MustBeTokenOwner2071 );20722073 2074 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2075 .checked_sub(1)2076 .ok_or(Error::<T>::NumOverflow)?;2077 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20782079 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2080 .checked_add(1)2081 .ok_or(Error::<T>::NumOverflow)?;2082 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20832084 2085 let old_owner = item.owner.clone();2086 item.owner = new_owner.clone();2087 <NftItemList<T>>::insert(collection_id, item_id, item);20882089 2090 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20912092 2093 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2094 Ok(())2095 }2096 2097 fn item_exists(2098 collection_id: CollectionId,2099 item_id: TokenId,2100 mode: &CollectionMode2101 ) -> DispatchResult {2102 match mode {2103 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2104 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2105 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2106 _ => ()2107 };2108 2109 Ok(())2110 }21112112 fn set_re_fungible_variable_data(2113 collection_id: CollectionId,2114 item_id: TokenId,2115 data: Vec<u8>2116 ) -> DispatchResult {2117 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);21182119 item.variable_data = data;21202121 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);21222123 Ok(())2124 }21252126 fn set_nft_variable_data(2127 collection_id: CollectionId,2128 item_id: TokenId,2129 data: Vec<u8>2130 ) -> DispatchResult {2131 let mut item = <NftItemList<T>>::get(collection_id, item_id);2132 2133 item.variable_data = data;21342135 <NftItemList<T>>::insert(collection_id, item_id, item);2136 2137 Ok(())2138 }21392140 fn init_collection(item: &CollectionType<T::AccountId>) {2141 2142 assert!(2143 item.decimal_points <= MAX_DECIMAL_POINTS,2144 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2145 );2146 assert!(2147 item.name.len() <= 64,2148 "Collection name can not be longer than 63 char"2149 );2150 assert!(2151 item.name.len() <= 256,2152 "Collection description can not be longer than 255 char"2153 );2154 assert!(2155 item.token_prefix.len() <= 16,2156 "Token prefix can not be longer than 15 char"2157 );21582159 2160 let next_id = CreatedCollectionCount::get()2161 .checked_add(1)2162 .unwrap();21632164 CreatedCollectionCount::put(next_id);2165 }21662167 fn init_nft_token(item: &NftItemType<T::AccountId>) {2168 let current_index = <ItemListIndex>::get(item.collection)2169 .checked_add(1)2170 .unwrap();21712172 let item_owner = item.owner.clone();2173 let collection_id = item.collection.clone();2174 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21752176 <ItemListIndex>::insert(collection_id, current_index);21772178 2179 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2180 .checked_add(1)2181 .unwrap();2182 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2183 }21842185 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2186 let current_index = <ItemListIndex>::get(item.collection)2187 .checked_add(1)2188 .unwrap();2189 let owner = item.owner.clone();21902191 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21922193 <ItemListIndex>::insert(item.collection, current_index);21942195 2196 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2197 .checked_add(item.value)2198 .unwrap();2199 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2200 }22012202 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2203 let current_index = <ItemListIndex>::get(item.collection)2204 .checked_add(1)2205 .unwrap();22062207 let value = item.owner.first().unwrap().fraction;2208 let owner = item.owner.first().unwrap().owner.clone();22092210 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();22112212 <ItemListIndex>::insert(item.collection, current_index);22132214 2215 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2216 .checked_add(value)2217 .unwrap();2218 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2219 }22202221 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {22222223 2224 if <AccountItemCount<T>>::contains_key(owner.clone()) {22252226 2227 let count = <AccountItemCount<T>>::get(owner.clone());2228 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);22292230 <AccountItemCount<T>>::insert(owner.clone(), count2231 .checked_add(1)2232 .ok_or(Error::<T>::NumOverflow)?);2233 }2234 else {2235 <AccountItemCount<T>>::insert(owner.clone(), 1);2236 }22372238 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2239 if list_exists {2240 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2241 let item_contains = list.contains(&item_index.clone());22422243 if !item_contains {2244 list.push(item_index.clone());2245 }22462247 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2248 } else {2249 let mut itm = Vec::new();2250 itm.push(item_index.clone());2251 <AddressTokens<T>>::insert(collection_id, owner, itm);2252 2253 }22542255 Ok(())2256 }22572258 fn remove_token_index(2259 collection_id: CollectionId,2260 item_index: TokenId,2261 owner: T::AccountId,2262 ) -> DispatchResult {22632264 2265 <AccountItemCount<T>>::insert(owner.clone(), 2266 <AccountItemCount<T>>::get(owner.clone())2267 .checked_sub(1)2268 .ok_or(Error::<T>::NumOverflow)?);226922702271 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2272 if list_exists {2273 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2274 let item_contains = list.contains(&item_index.clone());22752276 if item_contains {2277 list.retain(|&item| item != item_index);2278 <AddressTokens<T>>::insert(collection_id, owner, list);2279 }2280 }22812282 Ok(())2283 }22842285 fn move_token_index(2286 collection_id: CollectionId,2287 item_index: TokenId,2288 old_owner: T::AccountId,2289 new_owner: T::AccountId,2290 ) -> DispatchResult {2291 Self::remove_token_index(collection_id, item_index, old_owner)?;2292 Self::add_token_index(collection_id, item_index, new_owner)?;22932294 Ok(())2295 }2296 2297 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2298 if <ContractOwner<T>>::contains_key(contract.clone()) {2299 let owner = <ContractOwner<T>>::get(contract);2300 ensure!(account == owner, Error::<T>::NoPermission);2301 } else {2302 fail!(Error::<T>::NoPermission);2303 }23042305 Ok(())2306 }2307}2308230923102311231223132314pub type Multiplier = FixedU128;23152316type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2317 <T as system::Trait>::AccountId,2318>>::Balance;2319type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2320 <T as system::Trait>::AccountId,2321>>::NegativeImbalance;2322232323242325#[derive(Encode, Decode, Clone, Eq, PartialEq)]2326pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2327 #[codec(compact)] BalanceOf<T>2328);23292330impl<T: Trait + Send + Sync> sp_std::fmt::Debug2331 for ChargeTransactionPayment<T>2332{2333 #[cfg(feature = "std")]2334 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2335 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2336 }2337 #[cfg(not(feature = "std"))]2338 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2339 Ok(())2340 }2341}23422343impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2344where2345 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2346 BalanceOf<T>: Send + Sync + FixedPointOperand,2347{2348 2349 pub fn from(fee: BalanceOf<T>) -> Self {2350 Self(fee)2351 }23522353 pub fn traditional_fee(2354 len: usize,2355 info: &DispatchInfoOf<T::Call>,2356 tip: BalanceOf<T>,2357 ) -> BalanceOf<T>2358 where2359 T::Call: Dispatchable<Info = DispatchInfo>,2360 {2361 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2362 }23632364 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2365 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2366 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2367 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2368 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2369 }23702371 fn withdraw_fee(2372 &self,2373 who: &T::AccountId,2374 call: &T::Call,2375 info: &DispatchInfoOf<T::Call>,2376 len: usize,2377 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2378 let tip = self.0;23792380 2381 2382 2383 2384 2385 2386 2387 let fee = Self::traditional_fee(len, info, tip);23882389 2390 2391 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2392 Some(Call::create_item(collection_id, _owner, _properties)) => {23932394 2395 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2396 {2397 <Collection<T>>::get(collection_id).sponsor2398 } else {2399 T::AccountId::default()2400 }2401 }2402 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2403 2404 let _collection_limits = <Collection<T>>::get(collection_id).limits;2405 let _collection_mode = <Collection<T>>::get(collection_id).mode;24062407 2408 let sponsor_transfer = match _collection_mode {2409 CollectionMode::NFT => {24102411 2412 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2413 _collection_limits.sponsor_transfer_timeout2414 } else {2415 ChainLimit::get().nft_sponsor_transfer_timeout2416 };24172418 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2419 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2420 let limit_time = basket + limit.into();2421 if block_number >= limit_time {2422 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2423 true2424 }2425 else {2426 false2427 }2428 }2429 CollectionMode::Fungible(_) => {24302431 2432 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2433 _collection_limits.sponsor_transfer_timeout2434 } else {2435 ChainLimit::get().fungible_sponsor_transfer_timeout2436 };24372438 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2439 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2440 if basket.iter().any(|i| i.address == _new_owner.clone())2441 {2442 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2443 let limit_time = item.start_block + limit.into();2444 if block_number >= limit_time {2445 basket.retain(|x| x.address == item.address);2446 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2447 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2448 true2449 }2450 else {2451 false2452 }2453 }2454 else {2455 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2456 true2457 }2458 }2459 CollectionMode::ReFungible(_) => {24602461 2462 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2463 _collection_limits.sponsor_transfer_timeout2464 } else {2465 ChainLimit::get().refungible_sponsor_transfer_timeout2466 };24672468 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2469 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2470 let limit_time = basket + limit.into();2471 if block_number >= limit_time {2472 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2473 true2474 } else {2475 false2476 }2477 }2478 _ => {2479 false2480 },2481 };24822483 if !sponsor_transfer {2484 T::AccountId::default()2485 } else {2486 <Collection<T>>::get(collection_id).sponsor2487 }2488 }24892490 _ => T::AccountId::default(),2491 };24922493 2494 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24952496 2497 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24982499 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2500 code_hash,2501 &data,2502 &who,2503 );2504 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25052506 T::AccountId::default()2507 },25082509 2510 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {25112512 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());25132514 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2515 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2516 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2517 2518 if !owned_contract && white_list_enabled {2519 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2520 return Err(InvalidTransaction::Call.into());2521 }2522 }25232524 let mut sponsor_transfer = false;2525 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2526 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2527 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2528 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2529 let limit_time = last_tx_block + rate_limit;25302531 if block_number >= limit_time {2532 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2533 sponsor_transfer = true;2534 }2535 } else {2536 sponsor_transfer = false;2537 }2538 2539 2540 let mut sp = T::AccountId::default();2541 if sponsor_transfer {2542 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2543 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2544 sp = called_contract;2545 }2546 }2547 }25482549 sp2550 },25512552 _ => sponsor,2553 };25542555 let mut who_pays_fee: T::AccountId = sponsor.clone();2556 if sponsor == T::AccountId::default() {2557 who_pays_fee = who.clone();2558 }25592560 2561 if fee.is_zero() {2562 return Ok((fee, None));2563 }25642565 match <T as transaction_payment::Trait>::Currency::withdraw(2566 &who_pays_fee,2567 fee,2568 if tip.is_zero() {2569 WithdrawReason::TransactionPayment.into()2570 } else {2571 WithdrawReason::TransactionPayment | WithdrawReason::Tip2572 },2573 ExistenceRequirement::KeepAlive,2574 ) {2575 Ok(imbalance) => Ok((fee, Some(imbalance))),2576 Err(_) => Err(InvalidTransaction::Payment.into()),2577 }2578 }2579}258025812582impl<T: Trait + Send + Sync> SignedExtension2583 for ChargeTransactionPayment<T>2584where2585 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2586 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2587{2588 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2589 type AccountId = T::AccountId;2590 type Call = T::Call;2591 type AdditionalSigned = ();2592 type Pre = (2593 BalanceOf<T>,2594 Self::AccountId,2595 Option<NegativeImbalanceOf<T>>,2596 BalanceOf<T>,2597 );2598 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2599 Ok(())2600 }26012602 fn validate(2603 &self,2604 who: &Self::AccountId,2605 call: &Self::Call,2606 info: &DispatchInfoOf<Self::Call>,2607 len: usize,2608 ) -> TransactionValidity {2609 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2610 Ok(ValidTransaction {2611 priority: Self::get_priority(len, info, fee),2612 ..Default::default()2613 })2614 }26152616 fn pre_dispatch(2617 self,2618 who: &Self::AccountId,2619 call: &Self::Call,2620 info: &DispatchInfoOf<Self::Call>,2621 len: usize,2622 ) -> Result<Self::Pre, TransactionValidityError> {2623 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2624 Ok((self.0, who.clone(), imbalance, fee))2625 }26262627 fn post_dispatch(2628 pre: Self::Pre,2629 info: &DispatchInfoOf<Self::Call>,2630 post_info: &PostDispatchInfoOf<Self::Call>,2631 len: usize,2632 _result: &DispatchResult,2633 ) -> Result<(), TransactionValidityError> {2634 let (tip, who, imbalance, fee) = pre;2635 if let Some(payed) = imbalance {2636 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2637 len as u32, info, post_info, tip,2638 );2639 let refund = fee.saturating_sub(actual_fee);2640 let actual_payment =2641 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2642 &who, refund,2643 ) {2644 Ok(refund_imbalance) => {2645 2646 2647 match payed.offset(refund_imbalance) {2648 Ok(actual_payment) => actual_payment,2649 Err(_) => return Err(InvalidTransaction::Payment.into()),2650 }2651 }2652 2653 2654 Err(_) => payed,2655 };2656 let imbalances = actual_payment.split(tip);2657 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2658 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2659 );2660 }2661 Ok(())2662 }2663}26642665