123456#![recursion_limit = "1024"]78#![cfg_attr(not(feature = "std"), no_std)]910#[cfg(feature = "std")]11pub use std::*;1213#[cfg(feature = "std")]14pub use serde::*;1516use codec::{Decode, Encode};17pub use frame_support::{18 construct_runtime, decl_event, decl_module, decl_storage, decl_error,19 dispatch::DispatchResult,20 ensure, fail, parameter_types,21 traits::{22 Currency, ExistenceRequirement, Get, Imbalance, KeyOwnerProofSystem, OnUnbalanced,23 Randomness, WithdrawReason,24 },25 weights::{26 constants::{BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight, WEIGHT_PER_SECOND},27 DispatchInfo, GetDispatchInfo, IdentityFee, Pays, PostDispatchInfo, Weight,28 WeightToFeePolynomial,29 },30 IsSubType, StorageValue,31};3233use frame_system::{self as system, ensure_signed, ensure_root};34use sp_runtime::sp_std::prelude::Vec;35use sp_runtime::{36 traits::{37 DispatchInfoOf, Dispatchable, PostDispatchInfoOf, Saturating, SaturatedConversion, SignedExtension, Zero,38 },39 transaction_validity::{40 TransactionPriority, InvalidTransaction, TransactionValidity, TransactionValidityError, ValidTransaction,41 },42 FixedPointOperand, FixedU128,43};44use pallet_contracts::ContractAddressFor;45use sp_runtime::traits::StaticLookup;4647#[cfg(test)]48mod mock;4950#[cfg(test)]51mod tests;5253mod default_weights;5455pub const MAX_DECIMAL_POINTS: DecimalPoints = 30;56pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000;57pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000;5859606162pub type CollectionId = u32;63pub type TokenId = u32;64pub type DecimalPoints = u8;6566#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]67#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]68pub enum CollectionMode {69 Invalid,70 NFT,71 72 Fungible(DecimalPoints),73 74 ReFungible(DecimalPoints),75}7677impl Into<u8> for CollectionMode {78 fn into(self) -> u8 {79 match self {80 CollectionMode::Invalid => 0,81 CollectionMode::NFT => 1,82 CollectionMode::Fungible(_) => 2,83 CollectionMode::ReFungible(_) => 3,84 }85 }86}8788#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]89#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]90pub enum AccessMode {91 Normal,92 WhiteList,93}94impl Default for AccessMode {95 fn default() -> Self {96 Self::Normal97 }98}99100impl Default for CollectionMode {101 fn default() -> Self {102 Self::Invalid103 }104}105106#[derive(Encode, Decode, Eq, Debug, Clone, PartialEq)]107#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]108pub enum SchemaVersion {109 ImageURL,110 Unique,111}112impl Default for SchemaVersion {113 fn default() -> Self {114 Self::ImageURL115 }116}117118#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]119#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]120pub struct Ownership<AccountId> {121 pub owner: AccountId,122 pub fraction: u128,123}124125#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]126#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]127pub struct CollectionType<AccountId> {128 pub owner: AccountId,129 pub mode: CollectionMode,130 pub access: AccessMode,131 pub decimal_points: DecimalPoints,132 pub name: Vec<u16>, 133 pub description: Vec<u16>, 134 pub token_prefix: Vec<u8>, 135 pub mint_mode: bool,136 pub offchain_schema: Vec<u8>,137 pub schema_version: SchemaVersion,138 pub sponsor: AccountId, 139 pub unconfirmed_sponsor: AccountId, 140 pub limits: CollectionLimits, 141 pub variable_on_chain_schema: Vec<u8>, 142 pub const_on_chain_schema: Vec<u8>, 143}144145#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]146#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]147pub struct NftItemType<AccountId> {148 pub collection: CollectionId,149 pub owner: AccountId,150 pub const_data: Vec<u8>,151 pub variable_data: Vec<u8>,152}153154#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]155#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]156pub struct FungibleItemType<AccountId> {157 pub collection: CollectionId,158 pub owner: AccountId,159 pub value: u128,160}161162#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]163#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]164pub struct ReFungibleItemType<AccountId> {165 pub collection: CollectionId,166 pub owner: Vec<Ownership<AccountId>>,167 pub const_data: Vec<u8>,168 pub variable_data: Vec<u8>,169}170171#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]172#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]173pub struct ApprovePermissions<AccountId> {174 pub approved: AccountId,175 pub amount: u128,176}177178#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]179#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]180pub struct VestingItem<AccountId, Moment> {181 pub sender: AccountId,182 pub recipient: AccountId,183 pub collection_id: CollectionId,184 pub item_id: TokenId,185 pub amount: u64,186 pub vesting_date: Moment,187}188189#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]190#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]191pub struct BasketItem<AccountId, BlockNumber> {192 pub address: AccountId,193 pub start_block: BlockNumber,194}195196#[derive(Encode, Decode, Debug, Clone, PartialEq)]197#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]198pub struct CollectionLimits {199 pub account_token_ownership_limit: u32,200 pub sponsored_data_size: u32,201 pub token_limit: u32,202203 204 pub sponsor_transfer_timeout: u32,205}206207impl Default for CollectionLimits {208 fn default() -> CollectionLimits {209 CollectionLimits { 210 account_token_ownership_limit: 10_000_000, 211 token_limit: u32::max_value(),212 sponsored_data_size: u32::max_value(), 213 sponsor_transfer_timeout: 14400 }214 }215}216217#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]218#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]219pub struct ChainLimits {220 pub collection_numbers_limit: u32,221 pub account_token_ownership_limit: u32,222 pub collections_admins_limit: u64,223 pub custom_data_limit: u32,224225 226 pub nft_sponsor_transfer_timeout: u32,227 pub fungible_sponsor_transfer_timeout: u32,228 pub refungible_sponsor_transfer_timeout: u32,229}230231pub trait WeightInfo {232 fn create_collection() -> Weight;233 fn destroy_collection() -> Weight;234 fn add_to_white_list() -> Weight;235 fn remove_from_white_list() -> Weight;236 fn set_public_access_mode() -> Weight;237 fn set_mint_permission() -> Weight;238 fn change_collection_owner() -> Weight;239 fn add_collection_admin() -> Weight;240 fn remove_collection_admin() -> Weight;241 fn set_collection_sponsor() -> Weight;242 fn confirm_sponsorship() -> Weight;243 fn remove_collection_sponsor() -> Weight;244 fn create_item(s: usize) -> Weight;245 fn burn_item() -> Weight;246 fn transfer() -> Weight;247 fn approve() -> Weight;248 fn transfer_from() -> Weight;249 fn set_offchain_schema() -> Weight;250 fn set_const_on_chain_schema() -> Weight;251 fn set_variable_on_chain_schema() -> Weight;252 fn set_variable_meta_data() -> Weight;253 fn enable_contract_sponsoring() -> Weight;254}255256#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]257#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]258pub struct CreateNftData {259 pub const_data: Vec<u8>,260 pub variable_data: Vec<u8>,261}262263#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]265pub struct CreateFungibleData {266}267268#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)]269#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]270pub struct CreateReFungibleData {271 pub const_data: Vec<u8>,272 pub variable_data: Vec<u8>,273}274275#[derive(Encode, Decode, Debug, Clone, PartialEq)]276#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]277pub enum CreateItemData {278 NFT(CreateNftData),279 Fungible(CreateFungibleData),280 ReFungible(CreateReFungibleData),281}282283impl CreateItemData {284 pub fn len(&self) -> usize {285 let len = match self {286 CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(),287 CreateItemData::ReFungible(data) => data.variable_data.len() + data.const_data.len(),288 _ => 0289 };290 291 return len;292 }293}294295impl From<CreateNftData> for CreateItemData {296 fn from(item: CreateNftData) -> Self {297 CreateItemData::NFT(item)298 }299}300301impl From<CreateReFungibleData> for CreateItemData {302 fn from(item: CreateReFungibleData) -> Self {303 CreateItemData::ReFungible(item)304 }305}306307impl From<CreateFungibleData> for CreateItemData {308 fn from(item: CreateFungibleData) -> Self {309 CreateItemData::Fungible(item)310 }311}312313314decl_error! {315 316 pub enum Error for Module<T: Trait> {317 318 TotalCollectionsLimitExceeded,319 320 CollectionDecimalPointLimitExceeded, 321 322 CollectionNameLimitExceeded, 323 324 CollectionDescriptionLimitExceeded, 325 326 CollectionTokenPrefixLimitExceeded,327 328 CollectionNotFound,329 330 TokenNotFound,331 332 NumOverflow, 333 334 AlreadyAdmin, 335 336 NoPermission,337 338 ConfirmUnsetSponsorFail,339 340 PublicMintingNotAllowed,341 342 MustBeTokenOwner,343 344 TokenValueTooLow,345 346 NftSizeLimitExceeded,347 348 ApproveNotFound,349 350 TokenValueNotEnough,351 352 ApproveRequired,353 354 AddresNotInWhiteList,355 356 CollectionAdminsLimitExceeded,357 358 AddressOwnershipLimitExceeded,359 360 EmptyArgument,361 362 TokenConstDataLimitExceeded,363 364 TokenVariableDataLimitExceeded,365 366 NotNftDataUsedToMintNftCollectionToken,367 368 NotFungibleDataUsedToMintFungibleCollectionToken,369 370 NotReFungibleDataUsedToMintReFungibleCollectionToken,371 372 UnexpectedCollectionType,373 374 CantStoreMetadataInFungibleTokens,375 376 CollectionTokenLimitExceeded,377 378 AccountTokenLimitExceeded,379 380 CollectionLimitBoundsExceeded381 }382}383384pub trait Trait: system::Trait + Sized + transaction_payment::Trait + pallet_contracts::Trait {385 type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;386387 388 type WeightInfo: WeightInfo;389}390391#[cfg(feature = "runtime-benchmarks")]392mod benchmarking;393394395396decl_storage! {397 trait Store for Module<T: Trait> as Nft {398399 400 NextCollectionID: CollectionId;401 CreatedCollectionCount: u32;402 ChainVersion: u64;403 ItemListIndex: map hasher(identity) CollectionId => TokenId;404405 406 pub ChainLimit get(fn chain_limit) config(): ChainLimits;407408 409 CollectionCount: u32;410 pub AccountItemCount get(fn account_item_count): map hasher(twox_64_concat) T::AccountId => u32;411412 413 pub Collection get(fn collection) config(): map hasher(identity) CollectionId => CollectionType<T::AccountId>;414 pub AdminList get(fn admin_list_collection): map hasher(identity) CollectionId => Vec<T::AccountId>;415 pub WhiteList get(fn white_list): 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 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(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.unconfirmed_sponsor = new_sponsor;873 <Collection<T>>::insert(collection_id, target_collection);874875 Ok(())876 }877878 879 880 881 882 883 884 885 #[weight = T::WeightInfo::confirm_sponsorship()]886 pub fn confirm_sponsorship(origin, collection_id: CollectionId) -> DispatchResult {887888 let sender = ensure_signed(origin)?;889 ensure!(<Collection<T>>::contains_key(collection_id), Error::<T>::CollectionNotFound);890891 let mut target_collection = <Collection<T>>::get(collection_id);892 ensure!(sender == target_collection.unconfirmed_sponsor, Error::<T>::ConfirmUnsetSponsorFail);893894 target_collection.sponsor = target_collection.unconfirmed_sponsor;895 target_collection.unconfirmed_sponsor = T::AccountId::default();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 <Collection<T>>::insert(collection_id, target_collection);921922 Ok(())923 }924925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948949 #[weight = T::WeightInfo::create_item(data.len())]950 pub fn create_item(origin, collection_id: CollectionId, owner: T::AccountId, data: CreateItemData) -> DispatchResult {951952 let sender = ensure_signed(origin)?;953954 Self::collection_exists(collection_id)?;955956 let target_collection = <Collection<T>>::get(collection_id);957958 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;959 Self::validate_create_item_args(&target_collection, &data)?;960 Self::create_item_no_validation(collection_id, &target_collection, owner, data)?;961962 Ok(())963 }964965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 #[weight = T::WeightInfo::create_item(items_data.into_iter()984 .map(|data| { data.len() })985 .sum())]986 pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::AccountId, items_data: Vec<CreateItemData>) -> DispatchResult {987988 ensure!(items_data.len() > 0, Error::<T>::EmptyArgument);989 let sender = ensure_signed(origin)?;990991 Self::collection_exists(collection_id)?;992 let target_collection = <Collection<T>>::get(collection_id);993994 Self::can_create_items_in_collection(collection_id, &target_collection, &sender, &owner)?;995996 for data in &items_data {997 Self::validate_create_item_args(&target_collection, data)?;998 }999 for data in &items_data {1000 Self::create_item_no_validation(collection_id, &target_collection, owner.clone(), data.clone())?;1001 }10021003 Ok(())1004 }10051006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 #[weight = T::WeightInfo::burn_item()]1020 pub fn burn_item(origin, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {10211022 let sender = ensure_signed(origin)?;1023 Self::collection_exists(collection_id)?;10241025 1026 let target_collection = <Collection<T>>::get(collection_id);1027 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1028 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1029 Error::<T>::NoPermission);10301031 if target_collection.access == AccessMode::WhiteList {1032 Self::check_white_list(collection_id, &sender)?;1033 }10341035 match target_collection.mode1036 {1037 CollectionMode::NFT => Self::burn_nft_item(collection_id, item_id)?,1038 CollectionMode::Fungible(_) => Self::burn_fungible_item(collection_id, item_id)?,1039 CollectionMode::ReFungible(_) => Self::burn_refungible_item(collection_id, item_id, sender.clone())?,1040 _ => ()1041 };10421043 1044 Self::deposit_event(RawEvent::ItemDestroyed(collection_id, item_id));10451046 Ok(())1047 }10481049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 #[weight = T::WeightInfo::transfer()]1073 pub fn transfer(origin, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128) -> DispatchResult {10741075 let sender = ensure_signed(origin)?;1076 let target_collection = <Collection<T>>::get(collection_id);10771078 1079 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;10801081 1082 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1083 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1084 Error::<T>::NoPermission);10851086 if target_collection.access == AccessMode::WhiteList {1087 Self::check_white_list(collection_id, &sender)?;1088 Self::check_white_list(collection_id, &recipient)?;1089 }10901091 match target_collection.mode1092 {1093 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, sender.clone(), recipient)?,1094 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, sender.clone(), recipient)?,1095 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, sender.clone(), recipient)?,1096 _ => ()1097 };10981099 Ok(())1100 }11011102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 #[weight = T::WeightInfo::approve()]1118 pub fn approve(origin, approved: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> DispatchResult {11191120 let sender = ensure_signed(origin)?;11211122 1123 let target_collection = <Collection<T>>::get(collection_id);1124 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1125 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1126 Error::<T>::NoPermission);11271128 if target_collection.access == AccessMode::WhiteList {1129 Self::check_white_list(collection_id, &sender)?;1130 Self::check_white_list(collection_id, &approved)?;1131 }11321133 1134 let amount = 100000000;11351136 let list_exists = <ApprovedList<T>>::contains_key(collection_id, (item_id, sender.clone()));1137 if list_exists {11381139 let mut list = <ApprovedList<T>>::get(collection_id, (item_id, sender.clone()));1140 let item_contains = list.iter().any(|i| i.approved == approved);11411142 if !item_contains {1143 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1144 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1145 }1146 } else {11471148 let mut list = Vec::new();1149 list.push(ApprovePermissions { approved: approved.clone(), amount: amount });1150 <ApprovedList<T>>::insert(collection_id, (item_id, sender.clone()), list);1151 }11521153 Ok(())1154 }1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 #[weight = T::WeightInfo::transfer_from()]1176 pub fn transfer_from(origin, from: T::AccountId, recipient: T::AccountId, collection_id: CollectionId, item_id: TokenId, value: u128 ) -> DispatchResult {11771178 let sender = ensure_signed(origin)?;1179 let mut appoved_transfer = false;11801181 1182 if <ApprovedList<T>>::contains_key(collection_id, (item_id, from.clone())) {1183 let list_itm = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()));1184 let opt_item = list_itm.iter().find(|i| i.approved == sender.clone());1185 if opt_item.is_some()1186 {1187 appoved_transfer = true;1188 ensure!(opt_item.unwrap().amount >= value, Error::<T>::TokenValueNotEnough);1189 }1190 }11911192 let target_collection = <Collection<T>>::get(collection_id);11931194 1195 Self::is_correct_transfer(collection_id, &target_collection, &recipient)?;11961197 1198 ensure!(appoved_transfer || Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1199 Error::<T>::NoPermission);12001201 if target_collection.access == AccessMode::WhiteList {1202 Self::check_white_list(collection_id, &sender)?;1203 Self::check_white_list(collection_id, &recipient)?;1204 }12051206 1207 let approve_list: Vec<ApprovePermissions<T::AccountId>> = <ApprovedList<T>>::get(collection_id, (item_id, from.clone()))1208 .into_iter().filter(|i| i.approved != sender.clone()).collect();1209 <ApprovedList<T>>::insert(collection_id, (item_id, from.clone()), approve_list);121012111212 match target_collection.mode1213 {1214 CollectionMode::NFT => Self::transfer_nft(collection_id, item_id, from, recipient)?,1215 CollectionMode::Fungible(_) => Self::transfer_fungible(collection_id, item_id, value, from.clone(), recipient)?,1216 CollectionMode::ReFungible(_) => Self::transfer_refungible(collection_id, item_id, value, from.clone(), recipient)?,1217 _ => ()1218 };12191220 Ok(())1221 }12221223 #[weight = 0]1224 pub fn safe_transfer_from(origin, collection_id: CollectionId, item_id: TokenId, new_owner: T::AccountId) -> DispatchResult {12251226 1227 1228 1229 12301231 12321233 12341235 Ok(())1236 }12371238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 #[weight = T::WeightInfo::set_variable_meta_data()]1251 pub fn set_variable_meta_data (1252 origin,1253 collection_id: CollectionId,1254 item_id: TokenId,1255 data: Vec<u8>1256 ) -> DispatchResult {1257 let sender = ensure_signed(origin)?;1258 1259 Self::collection_exists(collection_id)?;1260 1261 ensure!(ChainLimit::get().custom_data_limit >= data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);12621263 1264 let target_collection = <Collection<T>>::get(collection_id);1265 ensure!(Self::is_item_owner(sender.clone(), collection_id, item_id) ||1266 Self::is_owner_or_admin_permissions(collection_id, sender.clone()),1267 Error::<T>::NoPermission);12681269 Self::item_exists(collection_id, item_id, &target_collection.mode)?;12701271 match target_collection.mode1272 {1273 CollectionMode::NFT => Self::set_nft_variable_data(collection_id, item_id, data)?,1274 CollectionMode::ReFungible(_) => Self::set_re_fungible_variable_data(collection_id, item_id, data)?,1275 CollectionMode::Fungible(_) => fail!(Error::<T>::CantStoreMetadataInFungibleTokens),1276 _ => fail!(Error::<T>::UnexpectedCollectionType)1277 };12781279 Ok(())1280 }1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 #[weight = 0]1297 pub fn set_schema_version(1298 origin,1299 collection_id: CollectionId,1300 version: SchemaVersion1301 ) -> DispatchResult {1302 let sender = ensure_signed(origin)?;1303 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;1304 let mut target_collection = <Collection<T>>::get(collection_id);1305 target_collection.schema_version = version;1306 <Collection<T>>::insert(collection_id, target_collection);13071308 Ok(())1309 }13101311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 #[weight = T::WeightInfo::set_offchain_schema()]1324 pub fn set_offchain_schema(1325 origin,1326 collection_id: CollectionId,1327 schema: Vec<u8>1328 ) -> DispatchResult {1329 let sender = ensure_signed(origin)?;1330 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13311332 let mut target_collection = <Collection<T>>::get(collection_id);1333 target_collection.offchain_schema = schema;1334 <Collection<T>>::insert(collection_id, target_collection);13351336 Ok(())1337 }13381339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 #[weight = T::WeightInfo::set_const_on_chain_schema()]1352 pub fn set_const_on_chain_schema (1353 origin,1354 collection_id: CollectionId,1355 schema: Vec<u8>1356 ) -> DispatchResult {1357 let sender = ensure_signed(origin)?;1358 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13591360 let mut target_collection = <Collection<T>>::get(collection_id);1361 target_collection.const_on_chain_schema = schema;1362 <Collection<T>>::insert(collection_id, target_collection);13631364 Ok(())1365 }13661367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 #[weight = T::WeightInfo::set_const_on_chain_schema()]1380 pub fn set_variable_on_chain_schema (1381 origin,1382 collection_id: CollectionId,1383 schema: Vec<u8>1384 ) -> DispatchResult {1385 let sender = ensure_signed(origin)?;1386 Self::check_owner_or_admin_permissions(collection_id, sender.clone())?;13871388 let mut target_collection = <Collection<T>>::get(collection_id);1389 target_collection.variable_on_chain_schema = schema;1390 <Collection<T>>::insert(collection_id, target_collection);13911392 Ok(())1393 }13941395 1396 #[weight = 0]1397 pub fn set_chain_limits(1398 origin,1399 limits: ChainLimits1400 ) -> DispatchResult {1401 ensure_root(origin)?;1402 <ChainLimit>::put(limits);1403 Ok(())1404 }14051406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 #[weight = T::WeightInfo::enable_contract_sponsoring()]1418 pub fn enable_contract_sponsoring(1419 origin,1420 contract_address: T::AccountId,1421 enable: bool1422 ) -> DispatchResult {14231424 let sender = ensure_signed(origin)?;14251426 #[cfg(feature = "runtime-benchmarks")]1427 <ContractOwner<T>>::insert(contract_address.clone(), sender.clone());14281429 let mut is_owner = false;1430 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1431 let owner = <ContractOwner<T>>::get(&contract_address);1432 is_owner = sender == owner;1433 }1434 ensure!(is_owner, Error::<T>::NoPermission);14351436 <ContractSelfSponsoring<T>>::insert(contract_address, enable);1437 Ok(())1438 }14391440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 #[weight = 0]1458 pub fn set_contract_sponsoring_rate_limit(1459 origin,1460 contract_address: T::AccountId,1461 rate_limit: T::BlockNumber1462 ) -> DispatchResult {1463 let sender = ensure_signed(origin)?;1464 let mut is_owner = false;1465 if <ContractOwner<T>>::contains_key(contract_address.clone()) {1466 let owner = <ContractOwner<T>>::get(&contract_address);1467 is_owner = sender == owner;1468 }1469 ensure!(is_owner, Error::<T>::NoPermission);14701471 <ContractSponsoringRateLimit<T>>::insert(contract_address, rate_limit);1472 Ok(())1473 }14741475 #[weight = 0]1476 pub fn set_collection_limits(1477 origin,1478 collection_id: u32,1479 limits: CollectionLimits,1480 ) -> DispatchResult {1481 let sender = ensure_signed(origin)?;1482 Self::check_owner_permissions(collection_id, sender.clone())?;1483 let mut target_collection = <Collection<T>>::get(collection_id);1484 let chain_limits = ChainLimit::get();1485 let climits = target_collection.limits;14861487 1488 ensure!(limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT &&1489 limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP, 1490 Error::<T>::CollectionLimitBoundsExceeded);14911492 1493 ensure!(climits.token_limit > limits.token_limit && 1494 limits.token_limit <= chain_limits.account_token_ownership_limit, 1495 Error::<T>::AccountTokenLimitExceeded);14961497 target_collection.limits = limits;1498 <Collection<T>>::insert(collection_id, target_collection);14991500 Ok(())1501 } 1502 }1503}15041505impl<T: Trait> Module<T> {15061507 fn is_correct_transfer(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, recipient: &T::AccountId) -> DispatchResult {15081509 1510 let account_items: u32 = <AddressTokens<T>>::get(collection_id, recipient).len() as u32;1511 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);1512 1513 Ok(())1514 }15151516 fn can_create_items_in_collection(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, sender: &T::AccountId, owner: &T::AccountId) -> DispatchResult {15171518 1519 let total_items: u32 = ItemListIndex::get(collection_id);1520 let account_items: u32 = <AddressTokens<T>>::get(collection_id, owner).len() as u32;1521 ensure!(collection.limits.token_limit > total_items, Error::<T>::CollectionTokenLimitExceeded);1522 ensure!(collection.limits.account_token_ownership_limit > account_items, Error::<T>::AccountTokenLimitExceeded);15231524 if !Self::is_owner_or_admin_permissions(collection_id, sender.clone()) {1525 ensure!(collection.mint_mode == true, Error::<T>::PublicMintingNotAllowed);1526 Self::check_white_list(collection_id, owner)?;1527 Self::check_white_list(collection_id, sender)?;1528 }15291530 Ok(())1531 }15321533 fn validate_create_item_args(target_collection: &CollectionType<T::AccountId>, data: &CreateItemData) -> DispatchResult {1534 match target_collection.mode1535 {1536 CollectionMode::NFT => {1537 if let CreateItemData::NFT(data) = data {1538 1539 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1540 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1541 } else {1542 fail!(Error::<T>::NotNftDataUsedToMintNftCollectionToken);1543 }1544 },1545 CollectionMode::Fungible(_) => {1546 if let CreateItemData::Fungible(_) = data {1547 } else {1548 fail!(Error::<T>::NotFungibleDataUsedToMintFungibleCollectionToken);1549 }1550 },1551 CollectionMode::ReFungible(_) => {1552 if let CreateItemData::ReFungible(data) = data {15531554 1555 ensure!(ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, Error::<T>::TokenConstDataLimitExceeded);1556 ensure!(ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, Error::<T>::TokenVariableDataLimitExceeded);1557 } else {1558 fail!(Error::<T>::NotReFungibleDataUsedToMintReFungibleCollectionToken);1559 }1560 },1561 _ => { fail!(Error::<T>::UnexpectedCollectionType); }1562 };15631564 Ok(())1565 }15661567 fn create_item_no_validation(collection_id: CollectionId, collection: &CollectionType<T::AccountId>, owner: T::AccountId, data: CreateItemData) -> DispatchResult {1568 match data1569 {1570 CreateItemData::NFT(data) => {1571 let item = NftItemType {1572 collection: collection_id,1573 owner,1574 const_data: data.const_data,1575 variable_data: data.variable_data1576 };15771578 Self::add_nft_item(item)?;1579 },1580 CreateItemData::Fungible(_) => {1581 let item = FungibleItemType {1582 collection: collection_id,1583 owner,1584 value: (10 as u128).pow(collection.decimal_points as u32)1585 };15861587 Self::add_fungible_item(item)?;1588 },1589 CreateItemData::ReFungible(data) => {1590 let mut owner_list = Vec::new();1591 let value = (10 as u128).pow(collection.decimal_points as u32);1592 owner_list.push(Ownership {owner: owner.clone(), fraction: value});15931594 let item = ReFungibleItemType {1595 collection: collection_id,1596 owner: owner_list,1597 const_data: data.const_data,1598 variable_data: data.variable_data1599 };16001601 Self::add_refungible_item(item)?;1602 }1603 };16041605 1606 Self::deposit_event(RawEvent::ItemCreated(collection_id, <ItemListIndex>::get(collection_id)));16071608 Ok(())1609 }16101611 fn add_fungible_item(item: FungibleItemType<T::AccountId>) -> DispatchResult {1612 let current_index = <ItemListIndex>::get(item.collection)1613 .checked_add(1)1614 .ok_or(Error::<T>::NumOverflow)?;1615 let itemcopy = item.clone();1616 let owner = item.owner.clone();16171618 Self::add_token_index(item.collection, current_index, owner.clone())?;16191620 <ItemListIndex>::insert(item.collection, current_index);1621 <FungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16221623 1624 let v: Vec<BasketItem<T::AccountId, T::BlockNumber>> = Vec::new();1625 <FungibleTransferBasket<T>>::insert(item.collection, current_index, v);1626 1627 1628 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1629 .checked_add(item.value)1630 .ok_or(Error::<T>::NumOverflow)?;1631 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16321633 Ok(())1634 }16351636 fn add_refungible_item(item: ReFungibleItemType<T::AccountId>) -> DispatchResult {1637 let current_index = <ItemListIndex>::get(item.collection)1638 .checked_add(1)1639 .ok_or(Error::<T>::NumOverflow)?;1640 let itemcopy = item.clone();16411642 let value = item.owner.first().unwrap().fraction;1643 let owner = item.owner.first().unwrap().owner.clone();16441645 Self::add_token_index(item.collection, current_index, owner.clone())?;16461647 <ItemListIndex>::insert(item.collection, current_index);1648 <ReFungibleItemList<T>>::insert(item.collection, current_index, itemcopy);16491650 1651 let block_number: T::BlockNumber = 0.into();1652 <ReFungibleTransferBasket<T>>::insert(item.collection, current_index, block_number);16531654 1655 let new_balance = <Balance<T>>::get(item.collection, owner.clone())1656 .checked_add(value)1657 .ok_or(Error::<T>::NumOverflow)?;1658 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);16591660 Ok(())1661 }16621663 fn add_nft_item(item: NftItemType<T::AccountId>) -> DispatchResult {1664 let current_index = <ItemListIndex>::get(item.collection)1665 .checked_add(1)1666 .ok_or(Error::<T>::NumOverflow)?;16671668 let item_owner = item.owner.clone();1669 let collection_id = item.collection.clone();1670 Self::add_token_index(collection_id, current_index, item.owner.clone())?;16711672 <ItemListIndex>::insert(collection_id, current_index);1673 <NftItemList<T>>::insert(collection_id, current_index, item);16741675 1676 let block_number: T::BlockNumber = 0.into();1677 <NftTransferBasket<T>>::insert(collection_id, current_index, block_number);16781679 1680 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())1681 .checked_add(1)1682 .ok_or(Error::<T>::NumOverflow)?;1683 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);16841685 Ok(())1686 }16871688 fn burn_refungible_item(1689 collection_id: CollectionId,1690 item_id: TokenId,1691 owner: T::AccountId,1692 ) -> DispatchResult {1693 ensure!(1694 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1695 Error::<T>::TokenNotFound1696 );1697 let collection = <ReFungibleItemList<T>>::get(collection_id, item_id);1698 let item = collection1699 .owner1700 .iter()1701 .filter(|&i| i.owner == owner)1702 .next()1703 .unwrap();1704 Self::remove_token_index(collection_id, item_id, owner.clone())?;17051706 1707 <ApprovedList<T>>::remove(collection_id, (item_id, owner.clone()));17081709 1710 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1711 .checked_sub(item.fraction)1712 .ok_or(Error::<T>::NumOverflow)?;1713 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17141715 <ReFungibleItemList<T>>::remove(collection_id, item_id);17161717 Ok(())1718 }17191720 fn burn_nft_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1721 ensure!(1722 <NftItemList<T>>::contains_key(collection_id, item_id),1723 Error::<T>::TokenNotFound1724 );1725 let item = <NftItemList<T>>::get(collection_id, item_id);1726 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17271728 1729 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17301731 1732 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1733 .checked_sub(1)1734 .ok_or(Error::<T>::NumOverflow)?;1735 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);1736 <NftItemList<T>>::remove(collection_id, item_id);17371738 Ok(())1739 }17401741 fn burn_fungible_item(collection_id: CollectionId, item_id: TokenId) -> DispatchResult {1742 ensure!(1743 <FungibleItemList<T>>::contains_key(collection_id, item_id),1744 Error::<T>::TokenNotFound1745 );1746 let item = <FungibleItemList<T>>::get(collection_id, item_id);1747 Self::remove_token_index(collection_id, item_id, item.owner.clone())?;17481749 1750 <ApprovedList<T>>::remove(collection_id, (item_id, item.owner.clone()));17511752 1753 let new_balance = <Balance<T>>::get(collection_id, item.owner.clone())1754 .checked_sub(item.value)1755 .ok_or(Error::<T>::NumOverflow)?;1756 <Balance<T>>::insert(collection_id, item.owner.clone(), new_balance);17571758 <FungibleItemList<T>>::remove(collection_id, item_id);17591760 Ok(())1761 }17621763 fn collection_exists(collection_id: CollectionId) -> DispatchResult {1764 ensure!(1765 <Collection<T>>::contains_key(collection_id),1766 Error::<T>::CollectionNotFound1767 );1768 Ok(())1769 }17701771 fn check_owner_permissions(collection_id: CollectionId, subject: T::AccountId) -> DispatchResult {1772 Self::collection_exists(collection_id)?;17731774 let target_collection = <Collection<T>>::get(collection_id);1775 ensure!(1776 subject == target_collection.owner,1777 Error::<T>::NoPermission1778 );17791780 Ok(())1781 }17821783 fn is_owner_or_admin_permissions(collection_id: CollectionId, subject: T::AccountId) -> bool {1784 let target_collection = <Collection<T>>::get(collection_id);1785 let mut result: bool = subject == target_collection.owner;1786 let exists = <AdminList<T>>::contains_key(collection_id);17871788 if !result & exists {1789 if <AdminList<T>>::get(collection_id).contains(&subject) {1790 result = true1791 }1792 }17931794 result1795 }17961797 fn check_owner_or_admin_permissions(1798 collection_id: CollectionId,1799 subject: T::AccountId,1800 ) -> DispatchResult {1801 Self::collection_exists(collection_id)?;1802 let result = Self::is_owner_or_admin_permissions(collection_id, subject.clone());18031804 ensure!(1805 result,1806 Error::<T>::NoPermission1807 );1808 Ok(())1809 }18101811 fn is_item_owner(subject: T::AccountId, collection_id: CollectionId, item_id: TokenId) -> bool {1812 let target_collection = <Collection<T>>::get(collection_id);18131814 match target_collection.mode {1815 CollectionMode::NFT => {1816 <NftItemList<T>>::get(collection_id, item_id).owner == subject1817 }1818 CollectionMode::Fungible(_) => {1819 <FungibleItemList<T>>::get(collection_id, item_id).owner == subject1820 }1821 CollectionMode::ReFungible(_) => {1822 <ReFungibleItemList<T>>::get(collection_id, item_id)1823 .owner1824 .iter()1825 .any(|i| i.owner == subject)1826 }1827 CollectionMode::Invalid => false,1828 }1829 }18301831 fn check_white_list(collection_id: CollectionId, address: &T::AccountId) -> DispatchResult {1832 let mes = Error::<T>::AddresNotInWhiteList;1833 ensure!(<WhiteList<T>>::contains_key(collection_id), mes);1834 let wl = <WhiteList<T>>::get(collection_id);1835 ensure!(wl.contains(address), mes);18361837 Ok(())1838 }18391840 fn transfer_fungible(1841 collection_id: CollectionId,1842 item_id: TokenId,1843 value: u128,1844 owner: T::AccountId,1845 new_owner: T::AccountId,1846 ) -> DispatchResult {1847 ensure!(1848 <FungibleItemList<T>>::contains_key(collection_id, item_id),1849 Error::<T>::TokenNotFound1850 );18511852 let full_item = <FungibleItemList<T>>::get(collection_id, item_id);1853 let amount = full_item.value;18541855 ensure!(amount >= value, Error::<T>::TokenValueTooLow);18561857 1858 let balance_old_owner = <Balance<T>>::get(collection_id, owner.clone())1859 .checked_sub(value)1860 .ok_or(Error::<T>::NumOverflow)?;1861 <Balance<T>>::insert(collection_id, owner.clone(), balance_old_owner);18621863 let mut new_owner_account_id = 0;1864 let new_owner_items = <AddressTokens<T>>::get(collection_id, new_owner.clone());1865 if new_owner_items.len() > 0 {1866 new_owner_account_id = new_owner_items[0];1867 }18681869 1870 if amount == value && new_owner_account_id == 0 {1871 1872 1873 let mut new_full_item = full_item.clone();1874 new_full_item.owner = new_owner.clone();1875 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);18761877 1878 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1879 .checked_add(value)1880 .ok_or(Error::<T>::NumOverflow)?;1881 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);18821883 1884 Self::move_token_index(collection_id, item_id, owner.clone(), new_owner.clone())?;1885 } else {1886 let mut new_full_item = full_item.clone();1887 new_full_item.value -= value;18881889 1890 if new_owner_account_id > 0 {1891 1892 let mut item = <FungibleItemList<T>>::get(collection_id, new_owner_account_id);1893 item.value += value;18941895 1896 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1897 .checked_add(value)1898 .ok_or(Error::<T>::NumOverflow)?;1899 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19001901 <FungibleItemList<T>>::insert(collection_id, new_owner_account_id, item);1902 } else {1903 1904 let item = FungibleItemType {1905 collection: collection_id,1906 owner: new_owner.clone(),1907 value1908 };19091910 Self::add_fungible_item(item)?;1911 }19121913 if amount == value {1914 Self::remove_token_index(collection_id, item_id, full_item.owner.clone())?;19151916 1917 <ApprovedList<T>>::remove(collection_id, (item_id, full_item.owner.clone()));1918 <FungibleItemList<T>>::remove(collection_id, item_id);1919 }19201921 <FungibleItemList<T>>::insert(collection_id, item_id, new_full_item);1922 }19231924 Ok(())1925 }19261927 fn transfer_refungible(1928 collection_id: CollectionId,1929 item_id: TokenId,1930 value: u128,1931 owner: T::AccountId,1932 new_owner: T::AccountId,1933 ) -> DispatchResult {1934 ensure!(1935 <ReFungibleItemList<T>>::contains_key(collection_id, item_id),1936 Error::<T>::TokenNotFound1937 );19381939 let full_item = <ReFungibleItemList<T>>::get(collection_id, item_id);1940 let item = full_item1941 .owner1942 .iter()1943 .filter(|i| i.owner == owner)1944 .next()1945 .ok_or(Error::<T>::NumOverflow)?;1946 let amount = item.fraction;19471948 ensure!(amount >= value, Error::<T>::TokenValueTooLow);19491950 1951 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())1952 .checked_sub(value)1953 .ok_or(Error::<T>::NumOverflow)?;1954 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);19551956 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())1957 .checked_add(value)1958 .ok_or(Error::<T>::NumOverflow)?;1959 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);19601961 let old_owner = item.owner.clone();1962 let new_owner_has_account = full_item.owner.iter().any(|i| i.owner == new_owner);19631964 1965 if amount == value && !new_owner_has_account {1966 1967 1968 let mut new_full_item = full_item.clone();1969 new_full_item1970 .owner1971 .iter_mut()1972 .find(|i| i.owner == owner)1973 .unwrap()1974 .owner = new_owner.clone();1975 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);19761977 1978 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;1979 } else {1980 let mut new_full_item = full_item.clone();1981 new_full_item1982 .owner1983 .iter_mut()1984 .find(|i| i.owner == owner)1985 .unwrap()1986 .fraction -= value;19871988 1989 if new_owner_has_account {1990 1991 new_full_item1992 .owner1993 .iter_mut()1994 .find(|i| i.owner == new_owner)1995 .unwrap()1996 .fraction += value;1997 } else {1998 1999 new_full_item.owner.push(Ownership {2000 owner: new_owner.clone(),2001 fraction: value,2002 });2003 Self::add_token_index(collection_id, item_id, new_owner.clone())?;2004 }20052006 <ReFungibleItemList<T>>::insert(collection_id, item_id, new_full_item);2007 }20082009 Ok(())2010 }20112012 fn transfer_nft(2013 collection_id: CollectionId,2014 item_id: TokenId,2015 sender: T::AccountId,2016 new_owner: T::AccountId,2017 ) -> DispatchResult {2018 ensure!(2019 <NftItemList<T>>::contains_key(collection_id, item_id),2020 Error::<T>::TokenNotFound2021 );20222023 let mut item = <NftItemList<T>>::get(collection_id, item_id);20242025 ensure!(2026 sender == item.owner,2027 Error::<T>::MustBeTokenOwner2028 );20292030 2031 let balance_old_owner = <Balance<T>>::get(collection_id, item.owner.clone())2032 .checked_sub(1)2033 .ok_or(Error::<T>::NumOverflow)?;2034 <Balance<T>>::insert(collection_id, item.owner.clone(), balance_old_owner);20352036 let balance_new_owner = <Balance<T>>::get(collection_id, new_owner.clone())2037 .checked_add(1)2038 .ok_or(Error::<T>::NumOverflow)?;2039 <Balance<T>>::insert(collection_id, new_owner.clone(), balance_new_owner);20402041 2042 let old_owner = item.owner.clone();2043 item.owner = new_owner.clone();2044 <NftItemList<T>>::insert(collection_id, item_id, item);20452046 2047 Self::move_token_index(collection_id, item_id, old_owner.clone(), new_owner.clone())?;20482049 2050 <ApprovedList<T>>::remove(collection_id, (item_id, old_owner));2051 Ok(())2052 }2053 2054 fn item_exists(2055 collection_id: CollectionId,2056 item_id: TokenId,2057 mode: &CollectionMode2058 ) -> DispatchResult {2059 match mode {2060 CollectionMode::NFT => ensure!(<NftItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2061 CollectionMode::ReFungible(_) => ensure!(<ReFungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2062 CollectionMode::Fungible(_) => ensure!(<FungibleItemList<T>>::contains_key(collection_id, item_id), Error::<T>::TokenNotFound),2063 _ => ()2064 };2065 2066 Ok(())2067 }20682069 fn set_re_fungible_variable_data(2070 collection_id: CollectionId,2071 item_id: TokenId,2072 data: Vec<u8>2073 ) -> DispatchResult {2074 let mut item = <ReFungibleItemList<T>>::get(collection_id, item_id);20752076 item.variable_data = data;20772078 <ReFungibleItemList<T>>::insert(collection_id, item_id, item);20792080 Ok(())2081 }20822083 fn set_nft_variable_data(2084 collection_id: CollectionId,2085 item_id: TokenId,2086 data: Vec<u8>2087 ) -> DispatchResult {2088 let mut item = <NftItemList<T>>::get(collection_id, item_id);2089 2090 item.variable_data = data;20912092 <NftItemList<T>>::insert(collection_id, item_id, item);2093 2094 Ok(())2095 }20962097 fn init_collection(item: &CollectionType<T::AccountId>) {2098 2099 assert!(2100 item.decimal_points <= MAX_DECIMAL_POINTS,2101 "decimal_points parameter must be lower than MAX_DECIMAL_POINTS"2102 );2103 assert!(2104 item.name.len() <= 64,2105 "Collection name can not be longer than 63 char"2106 );2107 assert!(2108 item.name.len() <= 256,2109 "Collection description can not be longer than 255 char"2110 );2111 assert!(2112 item.token_prefix.len() <= 16,2113 "Token prefix can not be longer than 15 char"2114 );21152116 2117 let next_id = CreatedCollectionCount::get()2118 .checked_add(1)2119 .unwrap();21202121 CreatedCollectionCount::put(next_id);2122 }21232124 fn init_nft_token(item: &NftItemType<T::AccountId>) {2125 let current_index = <ItemListIndex>::get(item.collection)2126 .checked_add(1)2127 .unwrap();21282129 let item_owner = item.owner.clone();2130 let collection_id = item.collection.clone();2131 Self::add_token_index(collection_id, current_index, item.owner.clone()).unwrap();21322133 <ItemListIndex>::insert(collection_id, current_index);21342135 2136 let new_balance = <Balance<T>>::get(collection_id, item_owner.clone())2137 .checked_add(1)2138 .unwrap();2139 <Balance<T>>::insert(collection_id, item_owner.clone(), new_balance);2140 }21412142 fn init_fungible_token(item: &FungibleItemType<T::AccountId>) {2143 let current_index = <ItemListIndex>::get(item.collection)2144 .checked_add(1)2145 .unwrap();2146 let owner = item.owner.clone();21472148 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21492150 <ItemListIndex>::insert(item.collection, current_index);21512152 2153 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2154 .checked_add(item.value)2155 .unwrap();2156 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2157 }21582159 fn init_refungible_token(item: &ReFungibleItemType<T::AccountId>) {2160 let current_index = <ItemListIndex>::get(item.collection)2161 .checked_add(1)2162 .unwrap();21632164 let value = item.owner.first().unwrap().fraction;2165 let owner = item.owner.first().unwrap().owner.clone();21662167 Self::add_token_index(item.collection, current_index, owner.clone()).unwrap();21682169 <ItemListIndex>::insert(item.collection, current_index);21702171 2172 let new_balance = <Balance<T>>::get(item.collection, owner.clone())2173 .checked_add(value)2174 .unwrap();2175 <Balance<T>>::insert(item.collection, owner.clone(), new_balance);2176 }21772178 fn add_token_index(collection_id: CollectionId, item_index: TokenId, owner: T::AccountId) -> DispatchResult {21792180 2181 if <AccountItemCount<T>>::contains_key(owner.clone()) {21822183 2184 let count = <AccountItemCount<T>>::get(owner.clone());2185 ensure!(count < ChainLimit::get().account_token_ownership_limit, Error::<T>::AddressOwnershipLimitExceeded);21862187 <AccountItemCount<T>>::insert(owner.clone(), count2188 .checked_add(1)2189 .ok_or(Error::<T>::NumOverflow)?);2190 }2191 else {2192 <AccountItemCount<T>>::insert(owner.clone(), 1);2193 }21942195 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2196 if list_exists {2197 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2198 let item_contains = list.contains(&item_index.clone());21992200 if !item_contains {2201 list.push(item_index.clone());2202 }22032204 <AddressTokens<T>>::insert(collection_id, owner.clone(), list);2205 } else {2206 let mut itm = Vec::new();2207 itm.push(item_index.clone());2208 <AddressTokens<T>>::insert(collection_id, owner, itm);2209 2210 }22112212 Ok(())2213 }22142215 fn remove_token_index(2216 collection_id: CollectionId,2217 item_index: TokenId,2218 owner: T::AccountId,2219 ) -> DispatchResult {22202221 2222 <AccountItemCount<T>>::insert(owner.clone(), 2223 <AccountItemCount<T>>::get(owner.clone())2224 .checked_sub(1)2225 .ok_or(Error::<T>::NumOverflow)?);222622272228 let list_exists = <AddressTokens<T>>::contains_key(collection_id, owner.clone());2229 if list_exists {2230 let mut list = <AddressTokens<T>>::get(collection_id, owner.clone());2231 let item_contains = list.contains(&item_index.clone());22322233 if item_contains {2234 list.retain(|&item| item != item_index);2235 <AddressTokens<T>>::insert(collection_id, owner, list);2236 }2237 }22382239 Ok(())2240 }22412242 fn move_token_index(2243 collection_id: CollectionId,2244 item_index: TokenId,2245 old_owner: T::AccountId,2246 new_owner: T::AccountId,2247 ) -> DispatchResult {2248 Self::remove_token_index(collection_id, item_index, old_owner)?;2249 Self::add_token_index(collection_id, item_index, new_owner)?;22502251 Ok(())2252 }2253}2254225522562257225822592260pub type Multiplier = FixedU128;22612262type BalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2263 <T as system::Trait>::AccountId,2264>>::Balance;2265type NegativeImbalanceOf<T> = <<T as transaction_payment::Trait>::Currency as Currency<2266 <T as system::Trait>::AccountId,2267>>::NegativeImbalance;2268226922702271#[derive(Encode, Decode, Clone, Eq, PartialEq)]2272pub struct ChargeTransactionPayment<T: Trait + Send + Sync>(2273 #[codec(compact)] BalanceOf<T>2274);22752276impl<T: Trait + Send + Sync> sp_std::fmt::Debug2277 for ChargeTransactionPayment<T>2278{2279 #[cfg(feature = "std")]2280 fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2281 write!(f, "ChargeTransactionPayment<{:?}>", self.0)2282 }2283 #[cfg(not(feature = "std"))]2284 fn fmt(&self, _: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {2285 Ok(())2286 }2287}22882289impl<T: Trait + Send + Sync> ChargeTransactionPayment<T>2290where2291 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2292 BalanceOf<T>: Send + Sync + FixedPointOperand,2293{2294 2295 pub fn from(fee: BalanceOf<T>) -> Self {2296 Self(fee)2297 }22982299 pub fn traditional_fee(2300 len: usize,2301 info: &DispatchInfoOf<T::Call>,2302 tip: BalanceOf<T>,2303 ) -> BalanceOf<T>2304 where2305 T::Call: Dispatchable<Info = DispatchInfo>,2306 {2307 <transaction_payment::Module<T>>::compute_fee(len as u32, info, tip)2308 }23092310 fn get_priority(len: usize, info: &DispatchInfoOf<T::Call>, final_fee: BalanceOf<T>) -> TransactionPriority {2311 let weight_saturation = T::MaximumBlockWeight::get() / info.weight.max(1);2312 let len_saturation = T::MaximumBlockLength::get() as u64 / (len as u64).max(1);2313 let coefficient: BalanceOf<T> = weight_saturation.min(len_saturation).saturated_into::<BalanceOf<T>>();2314 final_fee.saturating_mul(coefficient).saturated_into::<TransactionPriority>()2315 }23162317 fn withdraw_fee(2318 &self,2319 who: &T::AccountId,2320 call: &T::Call,2321 info: &DispatchInfoOf<T::Call>,2322 len: usize,2323 ) -> Result<(BalanceOf<T>, Option<NegativeImbalanceOf<T>>), TransactionValidityError> {2324 let tip = self.0;23252326 2327 2328 2329 2330 2331 2332 2333 let fee = Self::traditional_fee(len, info, tip);23342335 2336 2337 let mut sponsor: T::AccountId = match IsSubType::<Call<T>>::is_sub_type(call) {2338 Some(Call::create_item(collection_id, _owner, _properties)) => {23392340 2341 if <Collection<T>>::get(collection_id).limits.sponsored_data_size >= (_properties.len() as u32)2342 {2343 <Collection<T>>::get(collection_id).sponsor2344 } else {2345 T::AccountId::default()2346 }2347 }2348 Some(Call::transfer(_new_owner, collection_id, _item_id, _value)) => {2349 2350 let _collection_limits = <Collection<T>>::get(collection_id).limits;2351 let _collection_mode = <Collection<T>>::get(collection_id).mode;23522353 2354 let sponsor_transfer = match _collection_mode {2355 CollectionMode::NFT => {23562357 2358 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2359 _collection_limits.sponsor_transfer_timeout2360 } else {2361 ChainLimit::get().nft_sponsor_transfer_timeout2362 };23632364 let basket = <NftTransferBasket<T>>::get(collection_id, _item_id);2365 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2366 let limit_time = basket + limit.into();2367 if block_number >= limit_time {2368 <NftTransferBasket<T>>::insert(collection_id, _item_id, block_number);2369 true2370 }2371 else {2372 false2373 }2374 }2375 CollectionMode::Fungible(_) => {23762377 2378 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2379 _collection_limits.sponsor_transfer_timeout2380 } else {2381 ChainLimit::get().fungible_sponsor_transfer_timeout2382 };23832384 let mut basket = <FungibleTransferBasket<T>>::get(collection_id, _item_id);2385 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2386 if basket.iter().any(|i| i.address == _new_owner.clone())2387 {2388 let item = basket.iter_mut().find(|i| i.address == _new_owner.clone()).unwrap().clone();2389 let limit_time = item.start_block + limit.into();2390 if block_number >= limit_time {2391 basket.retain(|x| x.address == item.address);2392 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone() });2393 <FungibleTransferBasket<T>>::insert(collection_id, _item_id, basket);2394 true2395 }2396 else {2397 false2398 }2399 }2400 else {2401 basket.push(BasketItem { start_block: block_number, address: _new_owner.clone()});2402 true2403 }2404 }2405 CollectionMode::ReFungible(_) => {24062407 2408 let limit: u32 = if _collection_limits.sponsor_transfer_timeout > 0 {2409 _collection_limits.sponsor_transfer_timeout2410 } else {2411 ChainLimit::get().refungible_sponsor_transfer_timeout2412 };24132414 let basket = <ReFungibleTransferBasket<T>>::get(collection_id, _item_id);2415 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2416 let limit_time = basket + limit.into();2417 if block_number >= limit_time {2418 <ReFungibleTransferBasket<T>>::insert(collection_id, _item_id, block_number);2419 true2420 } else {2421 false2422 }2423 }2424 _ => {2425 false2426 },2427 };24282429 if !sponsor_transfer {2430 T::AccountId::default()2431 } else {2432 <Collection<T>>::get(collection_id).sponsor2433 }2434 }24352436 _ => T::AccountId::default(),2437 };24382439 2440 sponsor = match IsSubType::<pallet_contracts::Call<T>>::is_sub_type(call) {24412442 2443 Some(pallet_contracts::Call::instantiate(_endowment, _gas_limit, code_hash, data)) => {24442445 let new_contract_address = <T as pallet_contracts::Trait>::DetermineContractAddress::contract_address_for(2446 code_hash,2447 &data,2448 &who,2449 );2450 <ContractOwner<T>>::insert(new_contract_address.clone(), who.clone());24512452 T::AccountId::default()2453 },24542455 2456 Some(pallet_contracts::Call::call(dest, _value, _gas_limit, _data)) => {24572458 let called_contract: T::AccountId = T::Lookup::lookup((*dest).clone()).unwrap_or(T::AccountId::default());24592460 let mut sponsor_transfer = false;2461 if <ContractSponsoringRateLimit<T>>::contains_key(called_contract.clone()) {2462 let last_tx_block = <ContractSponsorBasket<T>>::get((&called_contract, &who));2463 let block_number = <system::Module<T>>::block_number() as T::BlockNumber;2464 let rate_limit = <ContractSponsoringRateLimit<T>>::get(&called_contract);2465 let limit_time = last_tx_block + rate_limit;24662467 if block_number >= limit_time {2468 <ContractSponsorBasket<T>>::insert((called_contract.clone(), who.clone()), block_number);2469 sponsor_transfer = true;2470 }2471 } else {2472 sponsor_transfer = false;2473 }2474 2475 2476 let mut sp = T::AccountId::default();2477 if sponsor_transfer {2478 if <ContractSelfSponsoring<T>>::contains_key(called_contract.clone()) {2479 if <ContractSelfSponsoring<T>>::get(called_contract.clone()) {2480 sp = called_contract;2481 }2482 }2483 }24842485 sp2486 },24872488 _ => sponsor,2489 };24902491 let mut who_pays_fee: T::AccountId = sponsor.clone();2492 if sponsor == T::AccountId::default() {2493 who_pays_fee = who.clone();2494 }24952496 2497 if fee.is_zero() {2498 return Ok((fee, None));2499 }25002501 match <T as transaction_payment::Trait>::Currency::withdraw(2502 &who_pays_fee,2503 fee,2504 if tip.is_zero() {2505 WithdrawReason::TransactionPayment.into()2506 } else {2507 WithdrawReason::TransactionPayment | WithdrawReason::Tip2508 },2509 ExistenceRequirement::KeepAlive,2510 ) {2511 Ok(imbalance) => Ok((fee, Some(imbalance))),2512 Err(_) => Err(InvalidTransaction::Payment.into()),2513 }2514 }2515}251625172518impl<T: Trait + Send + Sync> SignedExtension2519 for ChargeTransactionPayment<T>2520where2521 BalanceOf<T>: Send + Sync + From<u64> + FixedPointOperand,2522 T::Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo> + IsSubType<Call<T>> + IsSubType<pallet_contracts::Call<T>>,2523{2524 const IDENTIFIER: &'static str = "ChargeTransactionPayment";2525 type AccountId = T::AccountId;2526 type Call = T::Call;2527 type AdditionalSigned = ();2528 type Pre = (2529 BalanceOf<T>,2530 Self::AccountId,2531 Option<NegativeImbalanceOf<T>>,2532 BalanceOf<T>,2533 );2534 fn additional_signed(&self) -> sp_std::result::Result<(), TransactionValidityError> {2535 Ok(())2536 }25372538 fn validate(2539 &self,2540 who: &Self::AccountId,2541 call: &Self::Call,2542 info: &DispatchInfoOf<Self::Call>,2543 len: usize,2544 ) -> TransactionValidity {2545 let (fee, _) = self.withdraw_fee(who, call, info, len)?;2546 Ok(ValidTransaction {2547 priority: Self::get_priority(len, info, fee),2548 ..Default::default()2549 })2550 }25512552 fn pre_dispatch(2553 self,2554 who: &Self::AccountId,2555 call: &Self::Call,2556 info: &DispatchInfoOf<Self::Call>,2557 len: usize,2558 ) -> Result<Self::Pre, TransactionValidityError> {2559 let (fee, imbalance) = self.withdraw_fee(who, call, info, len)?;2560 Ok((self.0, who.clone(), imbalance, fee))2561 }25622563 fn post_dispatch(2564 pre: Self::Pre,2565 info: &DispatchInfoOf<Self::Call>,2566 post_info: &PostDispatchInfoOf<Self::Call>,2567 len: usize,2568 _result: &DispatchResult,2569 ) -> Result<(), TransactionValidityError> {2570 let (tip, who, imbalance, fee) = pre;2571 if let Some(payed) = imbalance {2572 let actual_fee = <transaction_payment::Module<T>>::compute_actual_fee(2573 len as u32, info, post_info, tip,2574 );2575 let refund = fee.saturating_sub(actual_fee);2576 let actual_payment =2577 match <T as transaction_payment::Trait>::Currency::deposit_into_existing(2578 &who, refund,2579 ) {2580 Ok(refund_imbalance) => {2581 2582 2583 match payed.offset(refund_imbalance) {2584 Ok(actual_payment) => actual_payment,2585 Err(_) => return Err(InvalidTransaction::Payment.into()),2586 }2587 }2588 2589 2590 Err(_) => payed,2591 };2592 let imbalances = actual_payment.split(tip);2593 <T as transaction_payment::Trait>::OnTransactionPayment::on_unbalanceds(2594 Some(imbalances.0).into_iter().chain(Some(imbalances.1)),2595 );2596 }2597 Ok(())2598 }2599}26002601