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 sponsor_confirmed: bool, 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): map hasher(identity) CollectionId => Vec<T::AccountId>;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 }442 add_extra_genesis {443 build(|config: &GenesisConfig<T>| {444 445 for (_num, _c) in &config.collection {446 <Module<T>>::init_collection(_c);447 }448449 for (_num, _q, _i) in &config.nft_item_id {450 <Module<T>>::init_nft_token(_i);451 }452453 for (_num, _q, _i) in &config.fungible_item_id {454 <Module<T>>::init_fungible_token(_i);455 }456457 for (_num, _q, _i) in &config.refungible_item_id {458 <Module<T>>::init_refungible_token(_i);459 }460 })461 }462}463464decl_event!(465 pub enum Event<T>466 where467 AccountId = <T as system::Trait>::AccountId,468 {469 470 471 472 473 474 475 476 477 478 Created(CollectionId, u8, AccountId),479480 481 482 483 484 485 486 487 ItemCreated(CollectionId, TokenId),488489 490 491 492 493 494 495 496 ItemDestroyed(CollectionId, TokenId),497 }498);499500decl_module! {501 pub struct Module<T: Trait> for enum Call where origin: T::Origin {502503 fn deposit_event() = default;504 type Error = Error<T>;505506 fn on_initialize(now: T::BlockNumber) -> Weight {507508 if ChainVersion::get() < 2509 {510 let value = NextCollectionID::get();511 CreatedCollectionCount::put(value);512 ChainVersion::put(2);513 }514515 0516 }517518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 #[weight = T::WeightInfo::create_collection()]535 pub fn create_collection(origin,536 collection_name: Vec<u16>,537 collection_description: Vec<u16>,538 token_prefix: Vec<u8>,539 mode: CollectionMode) -> DispatchResult {540541 542 let who = ensure_signed(origin)?;543544 let decimal_points = match mode {545 CollectionMode::Fungible(points) => points,546 CollectionMode::ReFungible(points) => points,547 _ => 0548 };549550 551 ensure!(CollectionCount::get() < ChainLimit::get().collection_numbers_limit, Error::<T>::TotalCollectionsLimitExceeded);552553 554 ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::<T>::CollectionDecimalPointLimitExceeded);555556 let mut name = collection_name.to_vec();557 name.push(0);558 ensure!(name.len() <= 64, Error::<T>::CollectionNameLimitExceeded);559560 let mut description = collection_description.to_vec();561 description.push(0);562 ensure!(name.len() <= 256, Error::<T>::CollectionDescriptionLimitExceeded);563564 let mut prefix = token_prefix.to_vec();565 prefix.push(0);566 ensure!(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: name,585 mode: mode.clone(),586 mint_mode: false,587 access: AccessMode::Normal,588 description: description,589 decimal_points: decimal_points,590 token_prefix: prefix,591 offchain_schema: Vec::new(),592 schema_version: SchemaVersion::ImageURL,593 sponsor: T::AccountId::default(),594 sponsor_confirmed: false,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(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 let mut white_list_collection: Vec<T::AccountId>;672 if <WhiteList<T>>::contains_key(collection_id) {673 white_list_collection = <WhiteList<T>>::get(collection_id);674 if !white_list_collection.contains(&address.clone())675 {676 white_list_collection.push(address.clone());677 }678 }679 else {680 white_list_collection = Vec::new();681 white_list_collection.push(address.clone());682 }683684 <WhiteList<T>>::insert(collection_id, white_list_collection);685 Ok(())686 }687688 689 690 691 692 693 694 695 696 697 698 699 700 #[weight = T::WeightInfo::remove_from_white_list()]701 pub fn remove_from_white_list(origin, collection_id: CollectionId, address: T::AccountId) -> DispatchResult{702703 let sender = ensure_signed(origin)?;704 Self::check_owner_or_admin_permissions(collection_id, sender)?;705706 if <WhiteList<T>>::contains_key(collection_id) {707 let mut white_list_collection = <WhiteList<T>>::get(collection_id);708 if white_list_collection.contains(&address.clone())709 {710 white_list_collection.retain(|i| *i != address.clone());711 <WhiteList<T>>::insert(collection_id, white_list_collection);712 }713 }714715 Ok(())716 }717718 719 720 721 722 723 724 725 726 727 728 729 #[weight = T::WeightInfo::set_public_access_mode()]730 pub fn set_public_access_mode(origin, collection_id: CollectionId, mode: AccessMode) -> DispatchResult731 {732 let sender = ensure_signed(origin)?;733734 Self::check_owner_permissions(collection_id, sender)?;735 let mut target_collection = <Collection<T>>::get(collection_id);736 target_collection.access = mode;737 <Collection<T>>::insert(collection_id, target_collection);738739 Ok(())740 }741742 743 744 745 746 747 748 749 750 751 752 753 754 755 #[weight = T::WeightInfo::set_mint_permission()]756 pub fn set_mint_permission(origin, collection_id: CollectionId, mint_permission: bool) -> DispatchResult757 {758 let sender = ensure_signed(origin)?;759760 Self::check_owner_permissions(collection_id, sender)?;761 let mut target_collection = <Collection<T>>::get(collection_id);762 target_collection.mint_mode = mint_permission;763 <Collection<T>>::insert(collection_id, target_collection);764765 Ok(())766 }767768 769 770 771 772 773 774 775 776 777 778 779 #[weight = T::WeightInfo::change_collection_owner()]780 pub fn change_collection_owner(origin, collection_id: CollectionId, new_owner: T::AccountId) -> DispatchResult {781782 let sender = ensure_signed(origin)?;783 Self::check_owner_permissions(collection_id, sender)?;784 let mut target_collection = <Collection<T>>::get(collection_id);785 target_collection.owner = new_owner;786 <Collection<T>>::insert(collection_id, target_collection);787788 Ok(())789 }790791 792 793 794 795 796 797 798 799 800 801 802 803 804 #[weight = T::WeightInfo::add_collection_admin()]805 pub fn add_collection_admin(origin, collection_id: CollectionId, new_admin_id: T::AccountId) -> DispatchResult {806807 let sender = ensure_signed(origin)?;808 Self::check_owner_or_admin_permissions(collection_id, sender)?;809 let mut admin_arr: Vec<T::AccountId> = Vec::new();810811 if <AdminList<T>>::contains_key(collection_id)812 {813 admin_arr = <AdminList<T>>::get(collection_id);814 ensure!(!admin_arr.contains(&new_admin_id), Error::<T>::AlreadyAdmin);815 }816817 818 ensure!((admin_arr.len() as u64) < ChainLimit::get().collections_admins_limit, Error::<T>::CollectionAdminsLimitExceeded);819820 admin_arr.push(new_admin_id);821 <AdminList<T>>::insert(collection_id, admin_arr);822823 Ok(())824 }825826 827 828 829 830 831 832 833 834 835 836 837 838 #[weight = T::WeightInfo::remove_collection_admin()]839 pub fn remove_collection_admin(origin, collection_id: CollectionId, account_id: T::AccountId) -> DispatchResult {840841 let sender = ensure_signed(origin)?;842 Self::check_owner_or_admin_permissions(collection_id, sender)?;843844 if <AdminList<T>>::contains_key(collection_id)845 {846 let mut admin_arr = <AdminList<T>>::get(collection_id);847 admin_arr.retain(|i| *i != account_id);848 <AdminList<T>>::insert(collection_id, admin_arr);849 }850851 Ok(())852 }853854 855 856 857 858 859 860 861 862 863 #[weight = T::WeightInfo::set_collection_sponsor()]864 pub fn set_collection_sponsor(origin, collection_id: CollectionId, new_sponsor: T::AccountId) -> DispatchResult {865866 let sender = ensure_signed(origin)?;867 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);868869 let mut target_collection = <Collection<T>>::get(collection_id);870 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);871872 target_collection.sponsor = new_sponsor;873 target_collection.sponsor_confirmed = false;874 <Collection<T>>::insert(collection_id, target_collection);875876 Ok(())877 }878879 880 881 882 883 884 885 886 #[weight = T::WeightInfo::confirm_sponsorship()]887 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {888889 let sender = ensure_signed(origin)?;890 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);891892 let mut target_collection = <Collection<T>>::get(collection_id);893 ensure!(sender == target_collection.sponsor, Error::<T>::ConfirmUnsetSponsorFail);894895 target_collection.sponsor_confirmed = true;896 <Collection<T>>::insert(collection_id, target_collection);897898 Ok(())899 }900901 902 903 904 905 906 907 908 909 910 #[weight = T::WeightInfo::remove_collection_sponsor()]911 pub fn remove_collection_sponsor(origin, collection_id: CollectionId) -> DispatchResult {912913 let sender = ensure_signed(origin)?;914 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);915916 let mut target_collection = <Collection<T>>::get(collection_id);917 ensure!(sender == target_collection.owner, Error::<T>::NoPermission);918919 target_collection.sponsor = T::AccountId::default();920 target_collection.sponsor_confirmed = false;921 <Collection<T>>::insert(collection_id, target_collection);922923 Ok(())924 }925926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949950 #[weight = T::WeightInfo::create_item(data.len())]951 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {952953 let sender = ensure_signed(origin)?;954955 Self::collection_exists(collection_id)?;956957 let target_collection = <Collection<T>>::get(collection_id);958959 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;960 Self::validate_create_item_args(&target_collection, &data)?;961 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;962963 Ok(())964 }965966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 #[weight = T::WeightInfo::create_item(items_data.into_iter()985 .map(|data| { data.len() })986 .sum())]987 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {988989 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);990 let sender = ensure_signed(origin)?;991992 Self::collection_exists(collection_id)?;993 let target_collection = <Collection<T>>::get(collection_id);994995 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;996997 for data in &items_data {998 Self::validate_create_item_args(&target_collection, data)?;999 }1000 for data in &items_data {1001 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;1002 }10031004 Ok(())1005 }10061007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 #[weight = T::WeightInfo::burn_item()]1021 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10221023 let sender = ensure_signed(origin)?;1024 Self::collection_exists(collection_id)?;10251026 1027 let target_collection = <Collection<T>>::get(collection_id);1028 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1029 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1030 Error::<T>::NoPermission);10311032 if target_collection.access == AccessMode::WhiteList {1033 Self::check_white_list(collection_id, &sender)?;1034 }10351036 match target_collection.mode1037 {1038 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1039 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1040 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1041 _ => ()1042 };10431044 1045 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10461047 Ok(())1048 }10491050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 #[weight = T::WeightInfo::transfer()]1074 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10751076 let sender = ensure_signed(origin)?;1077 let target_collection = <Collection<T>>::get(collection_id);10781079 1080 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10811082 1083 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1084 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1085 Error::<T>::NoPermission);10861087 if target_collection.access == AccessMode::WhiteList {1088 Self::check_white_list(collection_id, &sender)?;1089 Self::check_white_list(collection_id, &recipient)?;1090 }10911092 match target_collection.mode1093 {1094 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1095 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1096 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1097 _ => ()1098 };10991100 Ok(())1101 }11021103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 #[weight = T::WeightInfo::approve()]1119 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11201121 let sender = ensure_signed(origin)?;11221123 1124 let target_collection = <Collection<T>>::get(collection_id);1125 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1126 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1127 Error::<T>::NoPermission);11281129 if target_collection.access == AccessMode::WhiteList {1130 Self::check_white_list(collection_id, &sender)?;1131 Self::check_white_list(collection_id, &approved)?;1132 }11331134 1135 let amount = 100000000;11361137 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1138 if list_exists {11391140 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1141 let item_contains = list.iter().any(|i| i.approved == approved);11421143 if !item_contains {1144 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1145 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1146 }1147 } else {11481149 let mut list = Vec::new();1150 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1151 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1152 }11531154 Ok(())1155 }1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 #[weight = T::WeightInfo::transfer_from()]1177 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11781179 let sender = ensure_signed(origin)?;1180 let mut appoved_transfer = false;11811182 1183 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1184 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1185 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1186 if opt_item.is_some()1187 {1188 appoved_transfer = true;1189 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1190 }1191 }11921193 let target_collection = <Collection<T>>::get(collection_id);11941195 1196 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11971198 1199 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1200 Error::<T>::NoPermission);12011202 if target_collection.access == AccessMode::WhiteList {1203 Self::check_white_list(collection_id, &sender)?;1204 Self::check_white_list(collection_id, &recipient)?;1205 }12061207 1208 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1209 .into_iter().filter(|i| i.approved != sender.clone()).collect();1210 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);121112121213 match target_collection.mode1214 {1215 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1216 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1217 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1218 _ => ()1219 };12201221 Ok(())1222 }12231224 #[weight = 0]1225 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12261227 1228 1229 1230 12311232 12331234 12351236 Ok(())1237 }12381239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 #[weight = T::WeightInfo::set_variable_meta_data()]1252 pub fn set_variable_meta_data (1253 origin,1254 collection_id: CollectionId,1255 item_id: TokenId,1256 data: Vec<u8>1257 ) -> DispatchResult {1258 let sender = ensure_signed(origin)?;1259 1260 Self::collection_exists(collection_id)?;1261 1262 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12631264 1265 let target_collection = <Collection<T>>::get(collection_id);1266 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1267 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1268 Error::<T>::NoPermission);12691270 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12711272 match target_collection.mode1273 {1274 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1275 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1276 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1277 _ => fail!(Error::<T>::UnexpectedCollectionType)1278 };12791280 Ok(())1281 }1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 #[weight = 0]1298 pub fn set_schema_version(1299 origin,1300 collection_id: CollectionId,1301 version: SchemaVersion1302 ) -> DispatchResult {1303 let sender = ensure_signed(origin)?;1304 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1305 let mut target_collection = <Collection<T>>::get(collection_id);1306 target_collection.schema_version = version;1307 <Collection<T>>::insert(collection_id, target_collection);13081309 Ok(())1310 }13111312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 #[weight = T::WeightInfo::set_offchain_schema()]1325 pub fn set_offchain_schema(1326 origin,1327 collection_id: CollectionId,1328 schema: Vec<u8>1329 ) -> DispatchResult {1330 let sender = ensure_signed(origin)?;1331 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13321333 let mut target_collection = <Collection<T>>::get(collection_id);1334 target_collection.offchain_schema = schema;1335 <Collection<T>>::insert(collection_id, target_collection);13361337 Ok(())1338 }13391340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 #[weight = T::WeightInfo::set_const_on_chain_schema()]1353 pub fn set_const_on_chain_schema (1354 origin,1355 collection_id: CollectionId,1356 schema: Vec<u8>1357 ) -> DispatchResult {1358 let sender = ensure_signed(origin)?;1359 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13601361 let mut target_collection = <Collection<T>>::get(collection_id);1362 target_collection.const_on_chain_schema = schema;1363 <Collection<T>>::insert(collection_id, target_collection);13641365 Ok(())1366 }13671368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 #[weight = T::WeightInfo::set_const_on_chain_schema()]1381 pub fn set_variable_on_chain_schema (1382 origin,1383 collection_id: CollectionId,1384 schema: Vec<u8>1385 ) -> DispatchResult {1386 let sender = ensure_signed(origin)?;1387 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13881389 let mut target_collection = <Collection<T>>::get(collection_id);1390 target_collection.variable_on_chain_schema = schema;1391 <Collection<T>>::insert(collection_id, target_collection);13921393 Ok(())1394 }13951396 1397 #[weight = 0]1398 pub fn set_chain_limits(1399 origin,1400 limits: ChainLimits1401 ) -> DispatchResult {1402 ensure_root(origin)?;1403 <ChainLimit>::put(limits);1404 Ok(())1405 }14061407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 #[weight = T::WeightInfo::enable_contract_sponsoring()]1419 pub fn enable_contract_sponsoring(1420 origin,1421 contract_address: T::AccountId,1422 enable: bool1423 ) -> DispatchResult {14241425 let sender = ensure_signed(origin)?;14261427 #[cfg(feature = "runtime-benchmarks")]1428 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14291430 let mut is_owner = false;1431 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1432 let owner = <ContractOwner<T>>::get(&contract_address);1433 is_owner = sender == owner;1434 }1435 ensure!(is_owner, Error::<T>::NoPermission);14361437 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1438 Ok(())1439 }14401441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 #[weight = 0]1459 pub fn set_contract_sponsoring_rate_limit(1460 origin,1461 contract_address: T::AccountId,1462 rate_limit: T::BlockNumber1463 ) -> DispatchResult {1464 let sender = ensure_signed(origin)?;1465 let mut is_owner = false;1466 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1467 let owner = <ContractOwner<T>>::get(&contract_address);1468 is_owner = sender == owner;1469 }1470 ensure!(is_owner, Error::<T>::NoPermission);14711472 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1473 Ok(())1474 }14751476 #[weight = 0]1477 pub fn set_collection_limits(1478 origin,1479 collection_id: u32,1480 limits: CollectionLimits,1481 ) -> DispatchResult {1482 let sender = ensure_signed(origin)?;1483 Self::check_owner_permissions(collection_id, sender.clone())?;1484 let mut target_collection = <Collection<T>>::get(collection_id);1485 let chain_limits = ChainLimit::get();1486 let climits = target_collection.limits;14871488 1489 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1490 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1491 Error::<T>::CollectionLimitBoundsExceeded);14921493 1494 ensure!(climits.token_limit > limits.token_limit && 1495 limits.token_limit <= chain_limits.account_token_ownership_limit, 1496 Error::<T>::AccountTokenLimitExceeded);14971498 target_collection.limits = limits;1499 <Collection<T>>::insert(collection_id, target_collection);15001501 Ok(())1502 } 1503 }1504}15051506impl<T: Trait> Module<T> {15071508 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15091510 1511 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1512 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1513 1514 Ok(())1515 }15161517 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15181519 1520 let total_items: u32 = ItemListIndex::get(collection_id);1521 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1522 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1523 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15241525 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1526 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1527 Self::check_white_list(collection_id, owner)?;1528 Self::check_white_list(collection_id, sender)?;1529 }15301531 Ok(())1532 }15331534 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1535 match target_collection.mode1536 {1537 CollectionMode::NFT => {1538 if let CreateItemData::NFT(data) = data {1539 1540 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1541 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1542 } else {1543 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1544 }1545 },1546 CollectionMode::Fungible(_) => {1547 if let CreateItemData::Fungible(_) = data {1548 } else {1549 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1550 }1551 },1552 CollectionMode::ReFungible(_) => {1553 if let CreateItemData::ReFungible(data) = data {15541555 1556 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1557 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1558 } else {1559 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1560 }1561 },1562 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1563 };15641565 Ok(())1566 }15671568 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1569 match data1570 {1571 CreateItemData::NFT(data) => {1572 let item = NftItemType {1573 collection: collection_id,1574 owner,1575 const_data: data.const_data,1576 variable_data: data.variable_data1577 };15781579 Self::add_nft_item(item)?;1580 },1581 CreateItemData::Fungible(_) => {1582 let item = FungibleItemType {1583 collection: collection_id,1584 owner,1585 value: (10 as u128).pow(collection.decimal_points as u32)1586 };15871588 Self::add_fungible_item(item)?;1589 },1590 CreateItemData::ReFungible(data) => {1591 let mut owner_list = Vec::new();1592 let value = (10 as u128).pow(collection.decimal_points as u32);1593 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15941595 let item = ReFungibleItemType {1596 collection: collection_id,1597 owner: owner_list,1598 const_data: data.const_data,1599 variable_data: data.variable_data1600 };16011602 Self::add_refungible_item(item)?;1603 }1604 };16051606 1607 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16081609 Ok(())1610 }16111612 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1613 let current_index = <ItemListIndex>::get(item.collection)1614 .checked_add(1)1615 .ok_or(Error::<T>::NumOverflow)?;1616 let itemcopy = item.clone();1617 let owner = item.owner.clone();16181619 Self::add_token_index(item.collection, current_index, owner.clone())?;16201621 <ItemListIndex>::insert(item.collection, current_index);1622 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16231624 1625 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1626 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1627 1628 1629 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1630 .checked_add(item.value)1631 .ok_or(Error::<T>::NumOverflow)?;1632 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16331634 Ok(())1635 }16361637 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1638 let current_index = <ItemListIndex>::get(item.collection)1639 .checked_add(1)1640 .ok_or(Error::<T>::NumOverflow)?;1641 let itemcopy = item.clone();16421643 let value = item.owner.first().unwrap().fraction;1644 let owner = item.owner.first().unwrap().owner.clone();16451646 Self::add_token_index(item.collection, current_index, owner.clone())?;16471648 <ItemListIndex>::insert(item.collection, current_index);1649 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16501651 1652 let block_number: T::BlockNumber = 0.into();1653 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16541655 1656 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1657 .checked_add(value)1658 .ok_or(Error::<T>::NumOverflow)?;1659 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16601661 Ok(())1662 }16631664 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1665 let current_index = <ItemListIndex>::get(item.collection)1666 .checked_add(1)1667 .ok_or(Error::<T>::NumOverflow)?;16681669 let item_owner = item.owner.clone();1670 let collection_id = item.collection.clone();1671 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16721673 <ItemListIndex>::insert(collection_id, current_index);1674 <NftItemList<T>>::insert(collection_id, current_index, item);16751676 1677 let block_number: T::BlockNumber = 0.into();1678 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16791680 1681 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1682 .checked_add(1)1683 .ok_or(Error::<T>::NumOverflow)?;1684 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16851686 Ok(())1687 }16881689 fn burn_refungible_item(1690 collection_id: CollectionId,1691 item_id: TokenId,1692 owner: T::AccountId,1693 ) -> DispatchResult {1694 ensure!(1695 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1696 Error::<T>::TokenNotFound1697 );1698 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1699 let item = collection1700 .owner1701 .iter()1702 .filter(|&i| i.owner == owner)1703 .next()1704 .unwrap();1705 Self::remove_token_index(collection_id, item_id, owner.clone())?;17061707 1708 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17091710 1711 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1712 .checked_sub(item.fraction)1713 .ok_or(Error::<T>::NumOverflow)?;1714 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17151716 <ReFungibleItemList<T>>::remove(collection_id, item_id);17171718 Ok(())1719 }17201721 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1722 ensure!(1723 <NftItemList<T>>::contains_key(collection_id, item_id),1724 Error::<T>::TokenNotFound1725 );1726 let item = <NftItemList<T>>::get(collection_id, item_id);1727 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17281729 1730 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17311732 1733 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1734 .checked_sub(1)1735 .ok_or(Error::<T>::NumOverflow)?;1736 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1737 <NftItemList<T>>::remove(collection_id, item_id);17381739 Ok(())1740 }17411742 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1743 ensure!(1744 <FungibleItemList<T>>::contains_key(collection_id, item_id),1745 Error::<T>::TokenNotFound1746 );1747 let item = <FungibleItemList<T>>::get(collection_id, item_id);1748 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17491750 1751 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17521753 1754 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1755 .checked_sub(item.value)1756 .ok_or(Error::<T>::NumOverflow)?;1757 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17581759 <FungibleItemList<T>>::remove(collection_id, item_id);17601761 Ok(())1762 }17631764 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1765 ensure!(1766 <Collection<T>>::contains_key(collection_id),1767 Error::<T>::CollectionNotFound1768 );1769 Ok(())1770 }17711772 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1773 Self::collection_exists(collection_id)?;17741775 let target_collection = <Collection<T>>::get(collection_id);1776 ensure!(1777 subject == target_collection.owner,1778 Error::<T>::NoPermission1779 );17801781 Ok(())1782 }17831784 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1785 let target_collection = <Collection<T>>::get(collection_id);1786 let mut result: bool = subject == target_collection.owner;1787 let exists = <AdminList<T>>::contains_key(collection_id);17881789 if !result & exists {1790 if <AdminList<T>>::get(collection_id).contains(&subject) {1791 result = true1792 }1793 }17941795 result1796 }17971798 fn check_owner_or_admin_permissions(1799 collection_id: CollectionId,1800 subject: T::AccountId,1801 ) -> DispatchResult {1802 Self::collection_exists(collection_id)?;1803 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18041805 ensure!(1806 result,1807 Error::<T>::NoPermission1808 );1809 Ok(())1810 }18111812 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1813 let target_collection = <Collection<T>>::get(collection_id);18141815 match target_collection.mode {1816 CollectionMode::NFT => {1817 <NftItemList<T>>::get(collection_id, item_id).owner == subject1818 }1819 CollectionMode::Fungible(_) => {1820 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1821 }1822 CollectionMode::ReFungible(_) => {1823 <ReFungibleItemList<T>>::get(collection_id, item_id)1824 .owner1825 .iter()1826 .any(|i| i.owner == subject)1827 }1828 CollectionMode::Invalid => false,1829 }1830 }18311832 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1833 let mes = Error::<T>::AddresNotInWhiteList;1834 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1835 let wl = <WhiteList<T>>::get(collection_id);1836 ensure!(wl.contains(address), mes);18371838 Ok(())1839 }18401841 fn transfer_fungible(1842 collection_id: CollectionId,1843 item_id: TokenId,1844 value: u128,1845 owner: T::AccountId,1846 new_owner: T::AccountId,1847 ) -> DispatchResult {1848 ensure!(1849 <FungibleItemList<T>>::contains_key(collection_id, item_id),1850 Error::<T>::TokenNotFound1851 );18521853 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1854 let amount = full_item.value;18551856 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18571858 1859 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1860 .checked_sub(value)1861 .ok_or(Error::<T>::NumOverflow)?;1862 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18631864 let mut new_owner_account_id = 0;1865 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1866 if new_owner_items.len() > 0 {1867 new_owner_account_id = new_owner_items[0];1868 }18691870 1871 if amount == value && new_owner_account_id == 0 {1872 1873 1874 let mut new_full_item = full_item.clone();1875 new_full_item.owner = new_owner.clone();1876 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18771878 1879 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1880 .checked_add(value)1881 .ok_or(Error::<T>::NumOverflow)?;1882 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18831884 1885 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1886 } else {1887 let mut new_full_item = full_item.clone();1888 new_full_item.value -= value;18891890 1891 if new_owner_account_id > 0 {1892 1893 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1894 item.value += value;18951896 1897 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1898 .checked_add(value)1899 .ok_or(Error::<T>::NumOverflow)?;1900 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19011902 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1903 } else {1904 1905 let item = FungibleItemType {1906 collection: collection_id,1907 owner: new_owner.clone(),1908 value1909 };19101911 Self::add_fungible_item(item)?;1912 }19131914 if amount == value {1915 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19161917 1918 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1919 <FungibleItemList<T>>::remove(collection_id, item_id);1920 }19211922 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1923 }19241925 Ok(())1926 }19271928 fn transfer_refungible(1929 collection_id: CollectionId,1930 item_id: TokenId,1931 value: u128,1932 owner: T::AccountId,1933 new_owner: T::AccountId,1934 ) -> DispatchResult {1935 ensure!(1936 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1937 Error::<T>::TokenNotFound1938 );19391940 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1941 let item = full_item1942 .owner1943 .iter()1944 .filter(|i| i.owner == owner)1945 .next()1946 .ok_or(Error::<T>::NumOverflow)?;1947 let amount = item.fraction;19481949 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19501951 1952 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1953 .checked_sub(value)1954 .ok_or(Error::<T>::NumOverflow)?;1955 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19561957 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1958 .checked_add(value)1959 .ok_or(Error::<T>::NumOverflow)?;1960 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19611962 let old_owner = item.owner.clone();1963 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19641965 1966 if amount == value && !new_owner_has_account {1967 1968 1969 let mut new_full_item = full_item.clone();1970 new_full_item1971 .owner1972 .iter_mut()1973 .find(|i| i.owner == owner)1974 .unwrap()1975 .owner = new_owner.clone();1976 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19771978 1979 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1980 } else {1981 let mut new_full_item = full_item.clone();1982 new_full_item1983 .owner1984 .iter_mut()1985 .find(|i| i.owner == owner)1986 .unwrap()1987 .fraction -= value;19881989 1990 if new_owner_has_account {1991 1992 new_full_item1993 .owner1994 .iter_mut()1995 .find(|i| i.owner == new_owner)1996 .unwrap()1997 .fraction += value;1998 } else {1999 2000 new_full_item.owner.push(Ownership {2001 owner: new_owner.clone(),2002 fraction: value,2003 });2004 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2005 }20062007 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2008 }20092010 Ok(())2011 }20122013 fn transfer_nft(2014 collection_id: CollectionId,2015 item_id: TokenId,2016 sender: T::AccountId,2017 new_owner: T::AccountId,2018 ) -> DispatchResult {2019 ensure!(2020 <NftItemList<T>>::contains_key(collection_id, item_id),2021 Error::<T>::TokenNotFound2022 );20232024 let mut item = <NftItemList<T>>::get(collection_id, item_id);20252026 ensure!(2027 sender == item.owner,2028 Error::<T>::MustBeTokenOwner2029 );20302031 2032 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2033 .checked_sub(1)2034 .ok_or(Error::<T>::NumOverflow)?;2035 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20362037 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2038 .checked_add(1)2039 .ok_or(Error::<T>::NumOverflow)?;2040 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20412042 2043 let old_owner = item.owner.clone();2044 item.owner = new_owner.clone();2045 <NftItemList<T>>::insert(collection_id, item_id, item);20462047 2048 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20492050 2051 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2052 Ok(())2053 }2054 2055 fn item_exists(2056 collection_id: CollectionId,2057 item_id: TokenId,2058 mode: &CollectionMode2059 ) -> DispatchResult {2060 match mode {2061 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2062 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2063 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2064 _ => ()2065 };2066 2067 Ok(())2068 }20692070 fn set_re_fungible_variable_data(2071 collection_id: CollectionId,2072 item_id: TokenId,2073 data: Vec<u8>2074 ) -> DispatchResult {2075 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20762077 item.variable_data = data;20782079 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20802081 Ok(())2082 }20832084 fn set_nft_variable_data(2085 collection_id: CollectionId,2086 item_id: TokenId,2087 data: Vec<u8>2088 ) -> DispatchResult {2089 let mut item = <NftItemList<T>>::get(collection_id, item_id);2090 2091 item.variable_data = data;20922093 <NftItemList<T>>::insert(collection_id, item_id, item);2094 2095 Ok(())2096 }20972098 fn init_collection(item: &CollectionType<T::AccountId>) {2099 2100 assert!(2101 item.decimal_points <= MAX_DECIMAL_POINTS,2102 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2103 );2104 assert!(2105 item.name.len() <= 64,2106 "Collection name can not be longer than 63 char"2107 );2108 assert!(2109 item.name.len() <= 256,2110 "Collection description can not be longer than 255 char"2111 );2112 assert!(2113 item.token_prefix.len() <= 16,2114 "Token prefix can not be longer than 15 char"2115 );21162117 2118 let next_id = CreatedCollectionCount::get()2119 .checked_add(1)2120 .unwrap();21212122 CreatedCollectionCount::put(next_id);2123 }21242125 fn init_nft_token(item: &NftItemType<T::AccountId>) {2126 let current_index = <ItemListIndex>::get(item.collection)2127 .checked_add(1)2128 .unwrap();21292130 let item_owner = item.owner.clone();2131 let collection_id = item.collection.clone();2132 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21332134 <ItemListIndex>::insert(collection_id, current_index);21352136 2137 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2138 .checked_add(1)2139 .unwrap();2140 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2141 }21422143 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2144 let current_index = <ItemListIndex>::get(item.collection)2145 .checked_add(1)2146 .unwrap();2147 let owner = item.owner.clone();21482149 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21502151 <ItemListIndex>::insert(item.collection, current_index);21522153 2154 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2155 .checked_add(item.value)2156 .unwrap();2157 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2158 }21592160 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2161 let current_index = <ItemListIndex>::get(item.collection)2162 .checked_add(1)2163 .unwrap();21642165 let value = item.owner.first().unwrap().fraction;2166 let owner = item.owner.first().unwrap().owner.clone();21672168 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21692170 <ItemListIndex>::insert(item.collection, current_index);21712172 2173 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2174 .checked_add(value)2175 .unwrap();2176 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2177 }21782179 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21802181 2182 if <AccountItemCount<T>>::contains_key(owner.clone()) {21832184 2185 let count = <AccountItemCount<T>>::get(owner.clone());2186 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21872188 <AccountItemCount<T>>::insert(owner.clone(), count2189 .checked_add(1)2190 .ok_or(Error::<T>::NumOverflow)?);2191 }2192 else {2193 <AccountItemCount<T>>::insert(owner.clone(), 1);2194 }21952196 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2197 if list_exists {2198 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2199 let item_contains = list.contains(&item_index.clone());22002201 if !item_contains {2202 list.push(item_index.clone());2203 }22042205 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2206 } else {2207 let mut itm = Vec::new();2208 itm.push(item_index.clone());2209 <AddressTokens<T>>::insert(collection_id, owner, itm);2210 2211 }22122213 Ok(())2214 }22152216 fn remove_token_index(2217 collection_id: CollectionId,2218 item_index: TokenId,2219 owner: T::AccountId,2220 ) -> DispatchResult {22212222 2223 <AccountItemCount<T>>::insert(owner.clone(), 2224 <AccountItemCount<T>>::get(owner.clone())2225 .checked_sub(1)2226 .ok_or(Error::<T>::NumOverflow)?);222722282229 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2230 if list_exists {2231 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2232 let item_contains = list.contains(&item_index.clone());22332234 if item_contains {2235 list.retain(|&item| item != item_index);2236 <AddressTokens<T>>::insert(collection_id, owner, list);2237 }2238 }22392240 Ok(())2241 }22422243 fn move_token_index(2244 collection_id: CollectionId,2245 item_index: TokenId,2246 old_owner: T::AccountId,2247 new_owner: T::AccountId,2248 ) -> DispatchResult {2249 Self::remove_token_index(collection_id, item_index, old_owner)?;2250 Self::add_token_index(collection_id, item_index, new_owner)?;22512252 Ok(())2253 }2254}2255225622572258225922602261pub type Multiplier = FixedU128;22622263type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2264 <T as system::Trait>::AccountId,2265>>::Balance;2266type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2267 <T as system::Trait>::AccountId,2268>>::NegativeImbalance;2269227022712272#[derive(Encode, Decode, Clone, Eq, PartialEq)]2273pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2274 #[codec(compact)] BalanceOf<T>2275);22762277impl<T: Trait + Send + Sync> sp_std::fmt::Debug2278 for ChargeTransactionPayment<T>2279{2280 #[cfg(feature = "std")]2281 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2282 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2283 }2284 #[cfg(not(feature = "std"))]2285 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2286 Ok(())2287 }2288}22892290impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2291where2292 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2293 BalanceOf<T>: Send + Sync + FixedPointOperand,2294{2295 2296 pub fn from(fee: BalanceOf<T>) -> Self {2297 Self(fee)2298 }22992300 pub fn traditional_fee(2301 len: usize,2302 info: &DispatchInfoOf<T::Call>,2303 tip: BalanceOf<T>,2304 ) -> BalanceOf<T>2305 where2306 T::Call: Dispatchable<Info = DispatchInfo>,2307 {2308 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2309 }23102311 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2312 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2313 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2314 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2315 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2316 }23172318 fn withdraw_fee(2319 &self,2320 who: &T::AccountId,2321 call: &T::Call,2322 info: &DispatchInfoOf<T::Call>,2323 len: usize,2324 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2325 let tip = self.0;23262327 2328 2329 2330 2331 2332 2333 2334 let fee = Self::traditional_fee(len, info, tip);23352336 2337 2338 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2339 Some(Call::create_item(collection_id, _owner, _properties)) => {23402341 2342 if (<Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)) &&2343 (<Collection<T>>::get(collection_id).sponsor_confirmed)2344 {2345 <Collection<T>>::get(collection_id).sponsor2346 } else {2347 T::AccountId::default()2348 }2349 }2350 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2351 2352 let mut sponsor_transfer = false;2353 if <Collection<T>>::get(collection_id).sponsor_confirmed {2354 let _collection_limits = <Collection<T>>::get(collection_id).limits;2355 let _collection_mode = <Collection<T>>::get(collection_id).mode;2356 2357 2358 sponsor_transfer = match _collection_mode {2359 CollectionMode::NFT => {2360 2361 2362 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2363 _collection_limits.sponsor_transfer_timeout2364 } else {2365 ChainLimit::get().nft_sponsor_transfer_timeout2366 };2367 2368 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2369 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2370 let limit_time = basket + limit.into();2371 if block_number >= limit_time {2372 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2373 true2374 }2375 else {2376 false2377 }2378 }2379 CollectionMode::Fungible(_) => {2380 2381 2382 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2383 _collection_limits.sponsor_transfer_timeout2384 } else {2385 ChainLimit::get().fungible_sponsor_transfer_timeout2386 };2387 2388 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2389 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2390 if basket.iter().any(|i| i.address == _new_owner.clone())2391 {2392 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2393 let limit_time = item.start_block + limit.into();2394 if block_number >= limit_time {2395 basket.retain(|x| x.address == item.address);2396 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2397 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2398 true2399 }2400 else {2401 false2402 }2403 }2404 else {2405 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2406 true2407 }2408 }2409 CollectionMode::ReFungible(_) => {2410 2411 2412 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2413 _collection_limits.sponsor_transfer_timeout2414 } else {2415 ChainLimit::get().refungible_sponsor_transfer_timeout2416 };2417 2418 let basket = <ReFungibleTransferBasket<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 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2423 true2424 } else {2425 false2426 }2427 }2428 _ => {2429 false2430 },2431 };2432 }24332434 if !sponsor_transfer {2435 T::AccountId::default()2436 } else {2437 <Collection<T>>::get(collection_id).sponsor2438 }2439 }24402441 _ => T::AccountId::default(),2442 };24432444 2445 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24462447 2448 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24492450 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2451 code_hash,2452 &data,2453 &who,2454 );2455 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24562457 T::AccountId::default()2458 },24592460 2461 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24622463 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24642465 let mut sponsor_transfer = false;2466 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2467 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2468 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2469 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2470 let limit_time = last_tx_block + rate_limit;24712472 if block_number >= limit_time {2473 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2474 sponsor_transfer = true;2475 }2476 } else {2477 sponsor_transfer = false;2478 }2479 2480 2481 let mut sp = T::AccountId::default();2482 if sponsor_transfer {2483 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2484 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2485 sp = called_contract;2486 }2487 }2488 }24892490 sp2491 },24922493 _ => sponsor,2494 };24952496 let mut who_pays_fee: T::AccountId = sponsor.clone();2497 if sponsor == T::AccountId::default() {2498 who_pays_fee = who.clone();2499 }25002501 2502 if fee.is_zero() {2503 return Ok((fee, None));2504 }25052506 match <T as transaction_payment::Trait>::Currency::withdraw(2507 &who_pays_fee,2508 fee,2509 if tip.is_zero() {2510 WithdrawReason::TransactionPayment.into()2511 } else {2512 WithdrawReason::TransactionPayment | WithdrawReason::Tip2513 },2514 ExistenceRequirement::KeepAlive,2515 ) {2516 Ok(imbalance) => Ok((fee, Some(imbalance))),2517 Err(_) => Err(InvalidTransaction::Payment.into()),2518 }2519 }2520}252125222523impl<T: Trait + Send + Sync> SignedExtension2524 for ChargeTransactionPayment<T>2525where2526 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2527 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2528{2529 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2530 type AccountId = T::AccountId;2531 type Call = T::Call;2532 type AdditionalSigned = ();2533 type Pre = (2534 BalanceOf<T>,2535 Self::AccountId,2536 Option<NegativeImbalanceOf<T>>,2537 BalanceOf<T>,2538 );2539 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2540 Ok(())2541 }25422543 fn validate(2544 &self,2545 who: &Self::AccountId,2546 call: &Self::Call,2547 info: &DispatchInfoOf<Self::Call>,2548 len: usize,2549 ) -> TransactionValidity {2550 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2551 Ok(ValidTransaction {2552 priority: Self::get_priority(len, info, fee),2553 ..Default::default()2554 })2555 }25562557 fn pre_dispatch(2558 self,2559 who: &Self::AccountId,2560 call: &Self::Call,2561 info: &DispatchInfoOf<Self::Call>,2562 len: usize,2563 ) -> Result<Self::Pre, TransactionValidityError> {2564 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2565 Ok((self.0, who.clone(), imbalance, fee))2566 }25672568 fn post_dispatch(2569 pre: Self::Pre,2570 info: &DispatchInfoOf<Self::Call>,2571 post_info: &PostDispatchInfoOf<Self::Call>,2572 len: usize,2573 _result: &DispatchResult,2574 ) -> Result<(), TransactionValidityError> {2575 let (tip, who, imbalance, fee) = pre;2576 if let Some(payed) = imbalance {2577 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2578 len as u32, info, post_info, tip,2579 );2580 let refund = fee.saturating_sub(actual_fee);2581 let actual_payment =2582 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2583 &who, refund,2584 ) {2585 Ok(refund_imbalance) => {2586 2587 2588 match payed.offset(refund_imbalance) {2589 Ok(actual_payment) => actual_payment,2590 Err(_) => return Err(InvalidTransaction::Payment.into()),2591 }2592 }2593 2594 2595 Err(_) => payed,2596 };2597 let imbalances = actual_payment.split(tip);2598 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2599 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2600 );2601 }2602 Ok(())2603 }2604}26052606