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);564 ensure!(collection_name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);565 ensure!(collection_description.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);566 ensure!(token_prefix.len() <= 16, Error::<T>::CollectionTokenPrefixLimitExceeded);567568 569 let next_id = CreatedCollectionCount::get()570 .checked_add(1)571 .ok_or(Error::<T>::NumOverflow)?;572573 574 let total = CollectionCount::get()575 .checked_add(1)576 .ok_or(Error::<T>::NumOverflow)?;577578 CreatedCollectionCount::put(next_id);579 CollectionCount::put(total);580581 582 let new_collection = CollectionType {583 owner: who.clone(),584 name: collection_name,585 mode: mode.clone(),586 mint_mode: false,587 access: AccessMode::Normal,588 description: collection_description,589 decimal_points: decimal_points,590 token_prefix: token_prefix,591 offchain_schema: Vec::new(),592 schema_version: SchemaVersion::ImageURL,593 sponsor: T::AccountId::default(),594 unconfirmed_sponsor: T::AccountId::default(),595 variable_on_chain_schema: Vec::new(),596 const_on_chain_schema: Vec::new(),597 limits: CollectionLimits::default(),598 };599600 601 <Collection<T>>::insert(next_id, new_collection);602603 604 Self::deposit_event(RawEvent::Created(next_id, mode.into(), who.clone()));605606 Ok(())607 }608609 610 611 612 613 614 615 616 617 618 #[weight = T::WeightInfo::destroy_collection()]619 pub fn destroy_collection(origin, collection_id: CollectionId) -> DispatchResult {620621 let sender = ensure_signed(origin)?;622 Self::check_owner_permissions(collection_id, sender)?;623624 <AddressTokens<T>>::remove_prefix(collection_id);625 <ApprovedList<T>>::remove_prefix(collection_id);626 <Balance<T>>::remove_prefix(collection_id);627 <ItemListIndex>::remove(collection_id);628 <AdminList<T>>::remove(collection_id);629 <Collection<T>>::remove(collection_id);630 <WhiteList<T>>::remove_prefix(collection_id);631632 <NftItemList<T>>::remove_prefix(collection_id);633 <FungibleItemList<T>>::remove_prefix(collection_id);634 <ReFungibleItemList<T>>::remove_prefix(collection_id);635636 <NftTransferBasket<T>>::remove_prefix(collection_id);637 <FungibleTransferBasket<T>>::remove_prefix(collection_id);638 <ReFungibleTransferBasket<T>>::remove_prefix(collection_id);639640 if CollectionCount::get() > 0641 {642 643 let total = CollectionCount::get()644 .checked_sub(1)645 .ok_or(Error::<T>::NumOverflow)?;646647 CollectionCount::put(total);648 }649650 Ok(())651 }652653 654 655 656 657 658 659 660 661 662 663 664 665 #[weight = T::WeightInfo::add_to_white_list()]666 pub fn add_to_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{667668 let sender = ensure_signed(origin)?;669 Self::check_owner_or_admin_permissions(collection_id, sender)?;670671 <WhiteList<T>>::insert(collection_id, address, true);672 673 Ok(())674 }675676 677 678 679 680 681 682 683 684 685 686 687 688 #[weight = T::WeightInfo::remove_from_white_list()]689 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{690691 let sender = ensure_signed(origin)?;692 Self::check_owner_or_admin_permissions(collection_id, sender)?;693694 <WhiteList<T>>::remove(collection_id, address);695696 Ok(())697 }698699 700 701 702 703 704 705 706 707 708 709 710 #[weight = T::WeightInfo::set_public_access_mode()]711 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult712 {713 let sender = ensure_signed(origin)?;714715 Self::check_owner_permissions(collection_id, sender)?;716 let mut target_collection = <Collection<T>>::get(collection_id);717 target_collection.access = mode;718 <Collection<T>>::insert(collection_id, target_collection);719720 Ok(())721 }722723 724 725 726 727 728 729 730 731 732 733 734 735 736 #[weight = T::WeightInfo::set_mint_permission()]737 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult738 {739 let sender = ensure_signed(origin)?;740741 Self::check_owner_permissions(collection_id, sender)?;742 let mut target_collection = <Collection<T>>::get(collection_id);743 target_collection.mint_mode = mint_permission;744 <Collection<T>>::insert(collection_id, target_collection);745746 Ok(())747 }748749 750 751 752 753 754 755 756 757 758 759 760 #[weight = T::WeightInfo::change_collection_owner()]761 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {762763 let sender = ensure_signed(origin)?;764 Self::check_owner_permissions(collection_id, sender)?;765 let mut target_collection = <Collection<T>>::get(collection_id);766 target_collection.owner = new_owner;767 <Collection<T>>::insert(collection_id, target_collection);768769 Ok(())770 }771772 773 774 775 776 777 778 779 780 781 782 783 784 785 #[weight = T::WeightInfo::add_collection_admin()]786 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {787788 let sender = ensure_signed(origin)?;789 Self::check_owner_or_admin_permissions(collection_id, sender)?;790 let mut admin_arr: Vec<T::AccountId> = Vec::new();791792 if <AdminList<T>>::contains_key(collection_id)793 {794 admin_arr = <AdminList<T>>::get(collection_id);795 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);796 }797798 799 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);800801 admin_arr.push(new_admin_id);802 <AdminList<T>>::insert(collection_id, admin_arr);803804 Ok(())805 }806807 808 809 810 811 812 813 814 815 816 817 818 819 #[weight = T::WeightInfo::remove_collection_admin()]820 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {821822 let sender = ensure_signed(origin)?;823 Self::check_owner_or_admin_permissions(collection_id, sender)?;824825 if <AdminList<T>>::contains_key(collection_id)826 {827 let mut admin_arr = <AdminList<T>>::get(collection_id);828 admin_arr.retain(|i| *i != account_id);829 <AdminList<T>>::insert(collection_id, admin_arr);830 }831832 Ok(())833 }834835 836 837 838 839 840 841 842 843 844 #[weight = T::WeightInfo::set_collection_sponsor()]845 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {846847 let sender = ensure_signed(origin)?;848 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);849850 let mut target_collection = <Collection<T>>::get(collection_id);851 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);852853 target_collection.unconfirmed_sponsor = new_sponsor;854 <Collection<T>>::insert(collection_id, target_collection);855856 Ok(())857 }858859 860 861 862 863 864 865 866 #[weight = T::WeightInfo::confirm_sponsorship()]867 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {868869 let sender = ensure_signed(origin)?;870 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);871872 let mut target_collection = <Collection<T>>::get(collection_id);873 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);874875 target_collection.sponsor = target_collection.unconfirmed_sponsor;876 target_collection.unconfirmed_sponsor = T::AccountId::default();877 <Collection<T>>::insert(collection_id, target_collection);878879 Ok(())880 }881882 883 884 885 886 887 888 889 890 891 #[weight = T::WeightInfo::remove_collection_sponsor()]892 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {893894 let sender = ensure_signed(origin)?;895 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);896897 let mut target_collection = <Collection<T>>::get(collection_id);898 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);899900 target_collection.sponsor = T::AccountId::default();901 <Collection<T>>::insert(collection_id, target_collection);902903 Ok(())904 }905906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929930 #[weight = T::WeightInfo::create_item(data.len())]931 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {932933 let sender = ensure_signed(origin)?;934935 Self::collection_exists(collection_id)?;936937 let target_collection = <Collection<T>>::get(collection_id);938939 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;940 Self::validate_create_item_args(&target_collection, &data)?;941 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;942943 Ok(())944 }945946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 #[weight = T::WeightInfo::create_item(items_data.into_iter()965 .map(|data| { data.len() })966 .sum())]967 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {968969 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);970 let sender = ensure_signed(origin)?;971972 Self::collection_exists(collection_id)?;973 let target_collection = <Collection<T>>::get(collection_id);974975 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;976977 for data in &items_data {978 Self::validate_create_item_args(&target_collection, data)?;979 }980 for data in &items_data {981 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;982 }983984 Ok(())985 }986987 988 989 990 991 992 993 994 995 996 997 998 999 1000 #[weight = T::WeightInfo::burn_item()]1001 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10021003 let sender = ensure_signed(origin)?;1004 Self::collection_exists(collection_id)?;10051006 1007 let target_collection = <Collection<T>>::get(collection_id);1008 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1009 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1010 Error::<T>::NoPermission);10111012 if target_collection.access == AccessMode::WhiteList {1013 Self::check_white_list(collection_id, &sender)?;1014 }10151016 match target_collection.mode1017 {1018 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1019 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1020 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1021 _ => ()1022 };10231024 1025 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10261027 Ok(())1028 }10291030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 #[weight = T::WeightInfo::transfer()]1054 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10551056 let sender = ensure_signed(origin)?;1057 let target_collection = <Collection<T>>::get(collection_id);10581059 1060 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10611062 1063 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1064 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1065 Error::<T>::NoPermission);10661067 if target_collection.access == AccessMode::WhiteList {1068 Self::check_white_list(collection_id, &sender)?;1069 Self::check_white_list(collection_id, &recipient)?;1070 }10711072 match target_collection.mode1073 {1074 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1075 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1076 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1077 _ => ()1078 };10791080 Ok(())1081 }10821083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 #[weight = T::WeightInfo::approve()]1099 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11001101 let sender = ensure_signed(origin)?;11021103 1104 let target_collection = <Collection<T>>::get(collection_id);1105 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1106 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1107 Error::<T>::NoPermission);11081109 if target_collection.access == AccessMode::WhiteList {1110 Self::check_white_list(collection_id, &sender)?;1111 Self::check_white_list(collection_id, &approved)?;1112 }11131114 1115 let amount = 100000000;11161117 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1118 if list_exists {11191120 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1121 let item_contains = list.iter().any(|i| i.approved == approved);11221123 if !item_contains {1124 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1125 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1126 }1127 } else {11281129 let mut list = Vec::new();1130 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1131 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1132 }11331134 Ok(())1135 }1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 #[weight = T::WeightInfo::transfer_from()]1157 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11581159 let sender = ensure_signed(origin)?;1160 let mut appoved_transfer = false;11611162 1163 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1164 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1165 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1166 if opt_item.is_some()1167 {1168 appoved_transfer = true;1169 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1170 }1171 }11721173 let target_collection = <Collection<T>>::get(collection_id);11741175 1176 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11771178 1179 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1180 Error::<T>::NoPermission);11811182 if target_collection.access == AccessMode::WhiteList {1183 Self::check_white_list(collection_id, &sender)?;1184 Self::check_white_list(collection_id, &recipient)?;1185 }11861187 1188 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1189 .into_iter().filter(|i| i.approved != sender.clone()).collect();1190 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);119111921193 match target_collection.mode1194 {1195 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1196 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1197 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1198 _ => ()1199 };12001201 Ok(())1202 }12031204 #[weight = 0]1205 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12061207 1208 1209 1210 12111212 12131214 12151216 Ok(())1217 }12181219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 #[weight = T::WeightInfo::set_variable_meta_data()]1232 pub fn set_variable_meta_data (1233 origin,1234 collection_id: CollectionId,1235 item_id: TokenId,1236 data: Vec<u8>1237 ) -> DispatchResult {1238 let sender = ensure_signed(origin)?;1239 1240 Self::collection_exists(collection_id)?;1241 1242 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12431244 1245 let target_collection = <Collection<T>>::get(collection_id);1246 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1247 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1248 Error::<T>::NoPermission);12491250 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12511252 match target_collection.mode1253 {1254 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1255 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1256 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1257 _ => fail!(Error::<T>::UnexpectedCollectionType)1258 };12591260 Ok(())1261 }1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 #[weight = T::WeightInfo::set_schema_version()]1278 pub fn set_schema_version(1279 origin,1280 collection_id: CollectionId,1281 version: SchemaVersion1282 ) -> DispatchResult {1283 let sender = ensure_signed(origin)?;1284 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1285 let mut target_collection = <Collection<T>>::get(collection_id);1286 target_collection.schema_version = version;1287 <Collection<T>>::insert(collection_id, target_collection);12881289 Ok(())1290 }12911292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 #[weight = T::WeightInfo::set_offchain_schema()]1305 pub fn set_offchain_schema(1306 origin,1307 collection_id: CollectionId,1308 schema: Vec<u8>1309 ) -> DispatchResult {1310 let sender = ensure_signed(origin)?;1311 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13121313 let mut target_collection = <Collection<T>>::get(collection_id);1314 target_collection.offchain_schema = schema;1315 <Collection<T>>::insert(collection_id, target_collection);13161317 Ok(())1318 }13191320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 #[weight = T::WeightInfo::set_const_on_chain_schema()]1333 pub fn set_const_on_chain_schema (1334 origin,1335 collection_id: CollectionId,1336 schema: Vec<u8>1337 ) -> DispatchResult {1338 let sender = ensure_signed(origin)?;1339 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13401341 let mut target_collection = <Collection<T>>::get(collection_id);1342 target_collection.const_on_chain_schema = schema;1343 <Collection<T>>::insert(collection_id, target_collection);13441345 Ok(())1346 }13471348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 #[weight = T::WeightInfo::set_const_on_chain_schema()]1361 pub fn set_variable_on_chain_schema (1362 origin,1363 collection_id: CollectionId,1364 schema: Vec<u8>1365 ) -> DispatchResult {1366 let sender = ensure_signed(origin)?;1367 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13681369 let mut target_collection = <Collection<T>>::get(collection_id);1370 target_collection.variable_on_chain_schema = schema;1371 <Collection<T>>::insert(collection_id, target_collection);13721373 Ok(())1374 }13751376 1377 #[weight = T::WeightInfo::set_chain_limits()]1378 pub fn set_chain_limits(1379 origin,1380 limits: ChainLimits1381 ) -> DispatchResult {13821383 #[cfg(not(feature = "runtime-benchmarks"))]1384 ensure_root(origin)?;13851386 <ChainLimit>::put(limits);1387 Ok(())1388 }13891390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 #[weight = T::WeightInfo::enable_contract_sponsoring()]1402 pub fn enable_contract_sponsoring(1403 origin,1404 contract_address: T::AccountId,1405 enable: bool1406 ) -> DispatchResult {14071408 let sender = ensure_signed(origin)?;14091410 #[cfg(feature = "runtime-benchmarks")]1411 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14121413 Self::ensure_contract_owned(sender, &contract_address)?;14141415 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1416 Ok(())1417 }14181419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 #[weight = T::WeightInfo::set_contract_sponsoring_rate_limit()]1437 pub fn set_contract_sponsoring_rate_limit(1438 origin,1439 contract_address: T::AccountId,1440 rate_limit: T::BlockNumber1441 ) -> DispatchResult {1442 let sender = ensure_signed(origin)?;14431444 #[cfg(feature = "runtime-benchmarks")]1445 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14461447 Self::ensure_contract_owned(sender, &contract_address)?;1448 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1449 Ok(())1450 }14511452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 #[weight = T::WeightInfo::toggle_contract_white_list()]1464 pub fn toggle_contract_white_list(1465 origin,1466 contract_address: T::AccountId,1467 enable: bool1468 ) -> DispatchResult {1469 let sender = ensure_signed(origin)?;14701471 #[cfg(feature = "runtime-benchmarks")]1472 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14731474 Self::ensure_contract_owned(sender, &contract_address)?;1475 <ContractWhiteListEnabled<T>>::insert(contract_address, enable);1476 Ok(())1477 }1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 #[weight = T::WeightInfo::add_to_contract_white_list()]1491 pub fn add_to_contract_white_list(1492 origin,1493 contract_address: T::AccountId,1494 account_address: T::AccountId1495 ) -> DispatchResult {1496 let sender = ensure_signed(origin)?;14971498 #[cfg(feature = "runtime-benchmarks")]1499 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());1500 1501 Self::ensure_contract_owned(sender, &contract_address)?; 1502 <ContractWhiteList<T>>::insert(contract_address, account_address, true);1503 Ok(())1504 }15051506 #[weight = T::WeightInfo::add_to_contract_white_list()]1507 pub fn wasm_dummy_method(1508 origin1509 ) -> DispatchResult {1510 let sender = ensure_signed(origin)?;1511 Ok(())1512 }15131514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 #[weight = T::WeightInfo::remove_from_contract_white_list()]1526 pub fn remove_from_contract_white_list(1527 origin,1528 contract_address: T::AccountId,1529 account_address: T::AccountId1530 ) -> DispatchResult {1531 let sender = ensure_signed(origin)?;15321533 #[cfg(feature = "runtime-benchmarks")]1534 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());15351536 Self::ensure_contract_owned(sender, &contract_address)?;1537 <ContractWhiteList<T>>::remove(contract_address, account_address);1538 Ok(())1539 }15401541 #[weight = T::WeightInfo::set_collection_limits()]1542 pub fn set_collection_limits(1543 origin,1544 collection_id: u32,1545 limits: CollectionLimits,1546 ) -> DispatchResult {1547 let sender = ensure_signed(origin)?;1548 Self::check_owner_permissions(collection_id, sender.clone())?;1549 let mut target_collection = <Collection<T>>::get(collection_id);1550 let chain_limits = ChainLimit::get();1551 let climits = target_collection.limits;15521553 1554 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1555 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1556 Error::<T>::CollectionLimitBoundsExceeded);15571558 1559 ensure!(climits.token_limit > limits.token_limit && 1560 limits.token_limit <= chain_limits.account_token_ownership_limit, 1561 Error::<T>::AccountTokenLimitExceeded);15621563 target_collection.limits = limits;1564 <Collection<T>>::insert(collection_id, target_collection);15651566 Ok(())1567 } 1568 }1569}15701571impl<T: Trait> Module<T> {15721573 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15741575 1576 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1577 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1578 1579 Ok(())1580 }15811582 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15831584 1585 let total_items: u32 = ItemListIndex::get(collection_id);1586 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1587 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1588 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15891590 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1591 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1592 Self::check_white_list(collection_id, owner)?;1593 Self::check_white_list(collection_id, sender)?;1594 }15951596 Ok(())1597 }15981599 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1600 match target_collection.mode1601 {1602 CollectionMode::NFT => {1603 if let CreateItemData::NFT(data) = data {1604 1605 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1606 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1607 } else {1608 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1609 }1610 },1611 CollectionMode::Fungible(_) => {1612 if let CreateItemData::Fungible(_) = data {1613 } else {1614 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1615 }1616 },1617 CollectionMode::ReFungible(_) => {1618 if let CreateItemData::ReFungible(data) = data {16191620 1621 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1622 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1623 } else {1624 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1625 }1626 },1627 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1628 };16291630 Ok(())1631 }16321633 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1634 match data1635 {1636 CreateItemData::NFT(data) => {1637 let item = NftItemType {1638 collection: collection_id,1639 owner,1640 const_data: data.const_data,1641 variable_data: data.variable_data1642 };16431644 Self::add_nft_item(item)?;1645 },1646 CreateItemData::Fungible(_) => {1647 let item = FungibleItemType {1648 collection: collection_id,1649 owner,1650 value: (10 as u128).pow(collection.decimal_points as u32)1651 };16521653 Self::add_fungible_item(item)?;1654 },1655 CreateItemData::ReFungible(data) => {1656 let mut owner_list = Vec::new();1657 let value = (10 as u128).pow(collection.decimal_points as u32);1658 owner_list.push(Ownership {owner: owner.clone(), fraction: value});16591660 let item = ReFungibleItemType {1661 collection: collection_id,1662 owner: owner_list,1663 const_data: data.const_data,1664 variable_data: data.variable_data1665 };16661667 Self::add_refungible_item(item)?;1668 }1669 };16701671 1672 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16731674 Ok(())1675 }16761677 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1678 let current_index = <ItemListIndex>::get(item.collection)1679 .checked_add(1)1680 .ok_or(Error::<T>::NumOverflow)?;1681 let itemcopy = item.clone();1682 let owner = item.owner.clone();16831684 Self::add_token_index(item.collection, current_index, owner.clone())?;16851686 <ItemListIndex>::insert(item.collection, current_index);1687 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16881689 1690 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1691 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1692 1693 1694 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1695 .checked_add(item.value)1696 .ok_or(Error::<T>::NumOverflow)?;1697 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16981699 Ok(())1700 }17011702 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1703 let current_index = <ItemListIndex>::get(item.collection)1704 .checked_add(1)1705 .ok_or(Error::<T>::NumOverflow)?;1706 let itemcopy = item.clone();17071708 let value = item.owner.first().unwrap().fraction;1709 let owner = item.owner.first().unwrap().owner.clone();17101711 Self::add_token_index(item.collection, current_index, owner.clone())?;17121713 <ItemListIndex>::insert(item.collection, current_index);1714 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);17151716 1717 let block_number: T::BlockNumber = 0.into();1718 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);17191720 1721 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1722 .checked_add(value)1723 .ok_or(Error::<T>::NumOverflow)?;1724 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);17251726 Ok(())1727 }17281729 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1730 let current_index = <ItemListIndex>::get(item.collection)1731 .checked_add(1)1732 .ok_or(Error::<T>::NumOverflow)?;17331734 let item_owner = item.owner.clone();1735 let collection_id = item.collection.clone();1736 Self::add_token_index(collection_id, current_index, item.owner.clone())?;17371738 <ItemListIndex>::insert(collection_id, current_index);1739 <NftItemList<T>>::insert(collection_id, current_index, item);17401741 1742 let block_number: T::BlockNumber = 0.into();1743 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);17441745 1746 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1747 .checked_add(1)1748 .ok_or(Error::<T>::NumOverflow)?;1749 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);17501751 Ok(())1752 }17531754 fn burn_refungible_item(1755 collection_id: CollectionId,1756 item_id: TokenId,1757 owner: T::AccountId,1758 ) -> DispatchResult {1759 ensure!(1760 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1761 Error::<T>::TokenNotFound1762 );1763 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1764 let item = collection1765 .owner1766 .iter()1767 .filter(|&i| i.owner == owner)1768 .next()1769 .unwrap();1770 Self::remove_token_index(collection_id, item_id, owner.clone())?;17711772 1773 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17741775 1776 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1777 .checked_sub(item.fraction)1778 .ok_or(Error::<T>::NumOverflow)?;1779 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17801781 <ReFungibleItemList<T>>::remove(collection_id, item_id);17821783 Ok(())1784 }17851786 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1787 ensure!(1788 <NftItemList<T>>::contains_key(collection_id, item_id),1789 Error::<T>::TokenNotFound1790 );1791 let item = <NftItemList<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(1)1800 .ok_or(Error::<T>::NumOverflow)?;1801 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1802 <NftItemList<T>>::remove(collection_id, item_id);18031804 Ok(())1805 }18061807 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1808 ensure!(1809 <FungibleItemList<T>>::contains_key(collection_id, item_id),1810 Error::<T>::TokenNotFound1811 );1812 let item = <FungibleItemList<T>>::get(collection_id, item_id);1813 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;18141815 1816 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));18171818 1819 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1820 .checked_sub(item.value)1821 .ok_or(Error::<T>::NumOverflow)?;1822 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);18231824 <FungibleItemList<T>>::remove(collection_id, item_id);18251826 Ok(())1827 }18281829 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1830 ensure!(1831 <Collection<T>>::contains_key(collection_id),1832 Error::<T>::CollectionNotFound1833 );1834 Ok(())1835 }18361837 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1838 Self::collection_exists(collection_id)?;18391840 let target_collection = <Collection<T>>::get(collection_id);1841 ensure!(1842 subject == target_collection.owner,1843 Error::<T>::NoPermission1844 );18451846 Ok(())1847 }18481849 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1850 let target_collection = <Collection<T>>::get(collection_id);1851 let mut result: bool = subject == target_collection.owner;1852 let exists = <AdminList<T>>::contains_key(collection_id);18531854 if !result & exists {1855 if <AdminList<T>>::get(collection_id).contains(&subject) {1856 result = true1857 }1858 }18591860 result1861 }18621863 fn check_owner_or_admin_permissions(1864 collection_id: CollectionId,1865 subject: T::AccountId,1866 ) -> DispatchResult {1867 Self::collection_exists(collection_id)?;1868 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18691870 ensure!(1871 result,1872 Error::<T>::NoPermission1873 );1874 Ok(())1875 }18761877 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1878 let target_collection = <Collection<T>>::get(collection_id);18791880 match target_collection.mode {1881 CollectionMode::NFT => {1882 <NftItemList<T>>::get(collection_id, item_id).owner == subject1883 }1884 CollectionMode::Fungible(_) => {1885 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1886 }1887 CollectionMode::ReFungible(_) => {1888 <ReFungibleItemList<T>>::get(collection_id, item_id)1889 .owner1890 .iter()1891 .any(|i| i.owner == subject)1892 }1893 CollectionMode::Invalid => false,1894 }1895 }18961897 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1898 let mes = Error::<T>::AddresNotInWhiteList;1899 ensure!(<WhiteList<T>>::contains_key(collection_id, address), mes);19001901 Ok(())1902 }19031904 fn transfer_fungible(1905 collection_id: CollectionId,1906 item_id: TokenId,1907 value: u128,1908 owner: T::AccountId,1909 new_owner: T::AccountId,1910 ) -> DispatchResult {1911 ensure!(1912 <FungibleItemList<T>>::contains_key(collection_id, item_id),1913 Error::<T>::TokenNotFound1914 );19151916 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1917 let amount = full_item.value;19181919 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19201921 1922 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1923 .checked_sub(value)1924 .ok_or(Error::<T>::NumOverflow)?;1925 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);19261927 let mut new_owner_account_id = 0;1928 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1929 if new_owner_items.len() > 0 {1930 new_owner_account_id = new_owner_items[0];1931 }19321933 1934 if amount == value && new_owner_account_id == 0 {1935 1936 1937 let mut new_full_item = full_item.clone();1938 new_full_item.owner = new_owner.clone();1939 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19401941 1942 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1943 .checked_add(value)1944 .ok_or(Error::<T>::NumOverflow)?;1945 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19461947 1948 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1949 } else {1950 let mut new_full_item = full_item.clone();1951 new_full_item.value -= value;19521953 1954 if new_owner_account_id > 0 {1955 1956 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1957 item.value += value;19581959 1960 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1961 .checked_add(value)1962 .ok_or(Error::<T>::NumOverflow)?;1963 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19641965 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1966 } else {1967 1968 let item = FungibleItemType {1969 collection: collection_id,1970 owner: new_owner.clone(),1971 value1972 };19731974 Self::add_fungible_item(item)?;1975 }19761977 if amount == value {1978 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19791980 1981 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1982 <FungibleItemList<T>>::remove(collection_id, item_id);1983 }19841985 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1986 }19871988 Ok(())1989 }19901991 fn transfer_refungible(1992 collection_id: CollectionId,1993 item_id: TokenId,1994 value: u128,1995 owner: T::AccountId,1996 new_owner: T::AccountId,1997 ) -> DispatchResult {1998 ensure!(1999 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),2000 Error::<T>::TokenNotFound2001 );20022003 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);2004 let item = full_item2005 .owner2006 .iter()2007 .filter(|i| i.owner == owner)2008 .next()2009 .ok_or(Error::<T>::NumOverflow)?;2010 let amount = item.fraction;20112012 ensure!(amount >= value, Error::<T>::TokenValueTooLow);20132014 2015 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2016 .checked_sub(value)2017 .ok_or(Error::<T>::NumOverflow)?;2018 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20192020 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2021 .checked_add(value)2022 .ok_or(Error::<T>::NumOverflow)?;2023 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20242025 let old_owner = item.owner.clone();2026 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);20272028 2029 if amount == value && !new_owner_has_account {2030 2031 2032 let mut new_full_item = full_item.clone();2033 new_full_item2034 .owner2035 .iter_mut()2036 .find(|i| i.owner == owner)2037 .unwrap()2038 .owner = new_owner.clone();2039 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);20402041 2042 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;2043 } else {2044 let mut new_full_item = full_item.clone();2045 new_full_item2046 .owner2047 .iter_mut()2048 .find(|i| i.owner == owner)2049 .unwrap()2050 .fraction -= value;20512052 2053 if new_owner_has_account {2054 2055 new_full_item2056 .owner2057 .iter_mut()2058 .find(|i| i.owner == new_owner)2059 .unwrap()2060 .fraction += value;2061 } else {2062 2063 new_full_item.owner.push(Ownership {2064 owner: new_owner.clone(),2065 fraction: value,2066 });2067 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2068 }20692070 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2071 }20722073 Ok(())2074 }20752076 fn transfer_nft(2077 collection_id: CollectionId,2078 item_id: TokenId,2079 sender: T::AccountId,2080 new_owner: T::AccountId,2081 ) -> DispatchResult {2082 ensure!(2083 <NftItemList<T>>::contains_key(collection_id, item_id),2084 Error::<T>::TokenNotFound2085 );20862087 let mut item = <NftItemList<T>>::get(collection_id, item_id);20882089 ensure!(2090 sender == item.owner,2091 Error::<T>::MustBeTokenOwner2092 );20932094 2095 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2096 .checked_sub(1)2097 .ok_or(Error::<T>::NumOverflow)?;2098 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20992100 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2101 .checked_add(1)2102 .ok_or(Error::<T>::NumOverflow)?;2103 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);21042105 2106 let old_owner = item.owner.clone();2107 item.owner = new_owner.clone();2108 <NftItemList<T>>::insert(collection_id, item_id, item);21092110 2111 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;21122113 2114 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2115 Ok(())2116 }2117 2118 fn item_exists(2119 collection_id: CollectionId,2120 item_id: TokenId,2121 mode: &CollectionMode2122 ) -> DispatchResult {2123 match mode {2124 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2125 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2126 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2127 _ => ()2128 };2129 2130 Ok(())2131 }21322133 fn set_re_fungible_variable_data(2134 collection_id: CollectionId,2135 item_id: TokenId,2136 data: Vec<u8>2137 ) -> DispatchResult {2138 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);21392140 item.variable_data = data;21412142 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);21432144 Ok(())2145 }21462147 fn set_nft_variable_data(2148 collection_id: CollectionId,2149 item_id: TokenId,2150 data: Vec<u8>2151 ) -> DispatchResult {2152 let mut item = <NftItemList<T>>::get(collection_id, item_id);2153 2154 item.variable_data = data;21552156 <NftItemList<T>>::insert(collection_id, item_id, item);2157 2158 Ok(())2159 }21602161 fn init_collection(item: &CollectionType<T::AccountId>) {2162 2163 assert!(2164 item.decimal_points <= MAX_DECIMAL_POINTS,2165 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2166 );2167 assert!(2168 item.name.len() <= 64,2169 "Collection name can not be longer than 63 char"2170 );2171 assert!(2172 item.name.len() <= 256,2173 "Collection description can not be longer than 255 char"2174 );2175 assert!(2176 item.token_prefix.len() <= 16,2177 "Token prefix can not be longer than 15 char"2178 );21792180 2181 let next_id = CreatedCollectionCount::get()2182 .checked_add(1)2183 .unwrap();21842185 CreatedCollectionCount::put(next_id);2186 }21872188 fn init_nft_token(item: &NftItemType<T::AccountId>) {2189 let current_index = <ItemListIndex>::get(item.collection)2190 .checked_add(1)2191 .unwrap();21922193 let item_owner = item.owner.clone();2194 let collection_id = item.collection.clone();2195 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21962197 <ItemListIndex>::insert(collection_id, current_index);21982199 2200 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2201 .checked_add(1)2202 .unwrap();2203 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2204 }22052206 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2207 let current_index = <ItemListIndex>::get(item.collection)2208 .checked_add(1)2209 .unwrap();2210 let owner = item.owner.clone();22112212 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();22132214 <ItemListIndex>::insert(item.collection, current_index);22152216 2217 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2218 .checked_add(item.value)2219 .unwrap();2220 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2221 }22222223 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2224 let current_index = <ItemListIndex>::get(item.collection)2225 .checked_add(1)2226 .unwrap();22272228 let value = item.owner.first().unwrap().fraction;2229 let owner = item.owner.first().unwrap().owner.clone();22302231 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();22322233 <ItemListIndex>::insert(item.collection, current_index);22342235 2236 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2237 .checked_add(value)2238 .unwrap();2239 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2240 }22412242 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {22432244 2245 if <AccountItemCount<T>>::contains_key(owner.clone()) {22462247 2248 let count = <AccountItemCount<T>>::get(owner.clone());2249 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);22502251 <AccountItemCount<T>>::insert(owner.clone(), count2252 .checked_add(1)2253 .ok_or(Error::<T>::NumOverflow)?);2254 }2255 else {2256 <AccountItemCount<T>>::insert(owner.clone(), 1);2257 }22582259 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2260 if list_exists {2261 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2262 let item_contains = list.contains(&item_index.clone());22632264 if !item_contains {2265 list.push(item_index.clone());2266 }22672268 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2269 } else {2270 let mut itm = Vec::new();2271 itm.push(item_index.clone());2272 <AddressTokens<T>>::insert(collection_id, owner, itm);2273 2274 }22752276 Ok(())2277 }22782279 fn remove_token_index(2280 collection_id: CollectionId,2281 item_index: TokenId,2282 owner: T::AccountId,2283 ) -> DispatchResult {22842285 2286 <AccountItemCount<T>>::insert(owner.clone(), 2287 <AccountItemCount<T>>::get(owner.clone())2288 .checked_sub(1)2289 .ok_or(Error::<T>::NumOverflow)?);229022912292 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2293 if list_exists {2294 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2295 let item_contains = list.contains(&item_index.clone());22962297 if item_contains {2298 list.retain(|&item| item != item_index);2299 <AddressTokens<T>>::insert(collection_id, owner, list);2300 }2301 }23022303 Ok(())2304 }23052306 fn move_token_index(2307 collection_id: CollectionId,2308 item_index: TokenId,2309 old_owner: T::AccountId,2310 new_owner: T::AccountId,2311 ) -> DispatchResult {2312 Self::remove_token_index(collection_id, item_index, old_owner)?;2313 Self::add_token_index(collection_id, item_index, new_owner)?;23142315 Ok(())2316 }2317 2318 fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {2319 if <ContractOwner<T>>::contains_key(contract.clone()) {2320 let owner = <ContractOwner<T>>::get(contract);2321 ensure!(account == owner, Error::<T>::NoPermission);2322 } else {2323 fail!(Error::<T>::NoPermission);2324 }23252326 Ok(())2327 }2328}2329233023312332233323342335pub type Multiplier = FixedU128;23362337type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2338 <T as system::Trait>::AccountId,2339>>::Balance;2340type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2341 <T as system::Trait>::AccountId,2342>>::NegativeImbalance;2343234423452346#[derive(Encode, Decode, Clone, Eq, PartialEq)]2347pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2348 #[codec(compact)] BalanceOf<T>2349);23502351impl<T: Trait + Send + Sync> sp_std::fmt::Debug2352 for ChargeTransactionPayment<T>2353{2354 #[cfg(feature = "std")]2355 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2356 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2357 }2358 #[cfg(not(feature = "std"))]2359 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2360 Ok(())2361 }2362}23632364impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2365where2366 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2367 BalanceOf<T>: Send + Sync + FixedPointOperand,2368{2369 2370 pub fn from(fee: BalanceOf<T>) -> Self {2371 Self(fee)2372 }23732374 pub fn traditional_fee(2375 len: usize,2376 info: &DispatchInfoOf<T::Call>,2377 tip: BalanceOf<T>,2378 ) -> BalanceOf<T>2379 where2380 T::Call: Dispatchable<Info = DispatchInfo>,2381 {2382 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2383 }23842385 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2386 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2387 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2388 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2389 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2390 }23912392 fn withdraw_fee(2393 &self,2394 who: &T::AccountId,2395 call: &T::Call,2396 info: &DispatchInfoOf<T::Call>,2397 len: usize,2398 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2399 let tip = self.0;24002401 2402 2403 2404 2405 2406 2407 2408 let fee = Self::traditional_fee(len, info, tip);24092410 2411 2412 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2413 Some(Call::create_item(collection_id, _owner, _properties)) => {24142415 2416 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2417 {2418 <Collection<T>>::get(collection_id).sponsor2419 } else {2420 T::AccountId::default()2421 }2422 }2423 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2424 2425 let _collection_limits = <Collection<T>>::get(collection_id).limits;2426 let _collection_mode = <Collection<T>>::get(collection_id).mode;24272428 2429 let sponsor_transfer = match _collection_mode {2430 CollectionMode::NFT => {24312432 2433 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2434 _collection_limits.sponsor_transfer_timeout2435 } else {2436 ChainLimit::get().nft_sponsor_transfer_timeout2437 };24382439 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2440 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2441 let limit_time = basket + limit.into();2442 if block_number >= limit_time {2443 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2444 true2445 }2446 else {2447 false2448 }2449 }2450 CollectionMode::Fungible(_) => {24512452 2453 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2454 _collection_limits.sponsor_transfer_timeout2455 } else {2456 ChainLimit::get().fungible_sponsor_transfer_timeout2457 };24582459 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2460 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2461 if basket.iter().any(|i| i.address == _new_owner.clone())2462 {2463 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2464 let limit_time = item.start_block + limit.into();2465 if block_number >= limit_time {2466 basket.retain(|x| x.address == item.address);2467 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2468 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2469 true2470 }2471 else {2472 false2473 }2474 }2475 else {2476 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2477 true2478 }2479 }2480 CollectionMode::ReFungible(_) => {24812482 2483 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2484 _collection_limits.sponsor_transfer_timeout2485 } else {2486 ChainLimit::get().refungible_sponsor_transfer_timeout2487 };24882489 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2490 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2491 let limit_time = basket + limit.into();2492 if block_number >= limit_time {2493 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2494 true2495 } else {2496 false2497 }2498 }2499 _ => {2500 false2501 },2502 };25032504 if !sponsor_transfer {2505 T::AccountId::default()2506 } else {2507 <Collection<T>>::get(collection_id).sponsor2508 }2509 }25102511 _ => T::AccountId::default(),2512 };25132514 2515 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {25162517 2518 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {25192520 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2521 code_hash,2522 &data,2523 &who,2524 );2525 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());25262527 T::AccountId::default()2528 },25292530 2531 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {25322533 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());25342535 let owned_contract = <ContractOwner<T>>::contains_key(called_contract.clone())2536 && <ContractOwner<T>>::get(called_contract.clone()) == *who;2537 let white_list_enabled = <ContractWhiteListEnabled<T>>::contains_key(called_contract.clone()) && <ContractWhiteListEnabled<T>>::get(called_contract.clone());2538 2539 if !owned_contract && white_list_enabled {2540 if !<ContractWhiteList<T>>::contains_key(called_contract.clone(), who) {2541 return Err(InvalidTransaction::Call.into());2542 }2543 }25442545 let mut sponsor_transfer = false;2546 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2547 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2548 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2549 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2550 let limit_time = last_tx_block + rate_limit;25512552 if block_number >= limit_time {2553 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2554 sponsor_transfer = true;2555 }2556 } else {2557 sponsor_transfer = false;2558 }2559 2560 2561 let mut sp = T::AccountId::default();2562 if sponsor_transfer {2563 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2564 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2565 sp = called_contract;2566 }2567 }2568 }25692570 sp2571 },25722573 _ => sponsor,2574 };25752576 let mut who_pays_fee: T::AccountId = sponsor.clone();2577 if sponsor == T::AccountId::default() {2578 who_pays_fee = who.clone();2579 }25802581 2582 if fee.is_zero() {2583 return Ok((fee, None));2584 }25852586 match <T as transaction_payment::Trait>::Currency::withdraw(2587 &who_pays_fee,2588 fee,2589 if tip.is_zero() {2590 WithdrawReason::TransactionPayment.into()2591 } else {2592 WithdrawReason::TransactionPayment | WithdrawReason::Tip2593 },2594 ExistenceRequirement::KeepAlive,2595 ) {2596 Ok(imbalance) => Ok((fee, Some(imbalance))),2597 Err(_) => Err(InvalidTransaction::Payment.into()),2598 }2599 }2600}260126022603impl<T: Trait + Send + Sync> SignedExtension2604 for ChargeTransactionPayment<T>2605where2606 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2607 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2608{2609 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2610 type AccountId = T::AccountId;2611 type Call = T::Call;2612 type AdditionalSigned = ();2613 type Pre = (2614 BalanceOf<T>,2615 Self::AccountId,2616 Option<NegativeImbalanceOf<T>>,2617 BalanceOf<T>,2618 );2619 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2620 Ok(())2621 }26222623 fn validate(2624 &self,2625 who: &Self::AccountId,2626 call: &Self::Call,2627 info: &DispatchInfoOf<Self::Call>,2628 len: usize,2629 ) -> TransactionValidity {2630 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2631 Ok(ValidTransaction {2632 priority: Self::get_priority(len, info, fee),2633 ..Default::default()2634 })2635 }26362637 fn pre_dispatch(2638 self,2639 who: &Self::AccountId,2640 call: &Self::Call,2641 info: &DispatchInfoOf<Self::Call>,2642 len: usize,2643 ) -> Result<Self::Pre, TransactionValidityError> {2644 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2645 Ok((self.0, who.clone(), imbalance, fee))2646 }26472648 fn post_dispatch(2649 pre: Self::Pre,2650 info: &DispatchInfoOf<Self::Call>,2651 post_info: &PostDispatchInfoOf<Self::Call>,2652 len: usize,2653 _result: &DispatchResult,2654 ) -> Result<(), TransactionValidityError> {2655 let (tip, who, imbalance, fee) = pre;2656 if let Some(payed) = imbalance {2657 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2658 len as u32, info, post_info, tip,2659 );2660 let refund = fee.saturating_sub(actual_fee);2661 let actual_payment =2662 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2663 &who, refund,2664 ) {2665 Ok(refund_imbalance) => {2666 2667 2668 match payed.offset(refund_imbalance) {2669 Ok(actual_payment) => actual_payment,2670 Err(_) => return Err(InvalidTransaction::Payment.into()),2671 }2672 }2673 2674 2675 Err(_) => payed,2676 };2677 let imbalances = actual_payment.split(tip);2678 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2679 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2680 );2681 }2682 Ok(())2683 }2684}26852686