1use crate::{2 Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket,3 ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, CreateItemData,4 CollectionMode,5};6use core::marker::PhantomData;7use up_sponsorship::SponsorshipHandler;8use frame_support::{9 traits::{IsSubType},10 storage::{StorageMap, StorageDoubleMap},11};12use nft_data_structs::{13 TokenId, CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,14 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,15};1617pub struct NftSponsorshipHandler<T>(PhantomData<T>);18impl<T: Config> NftSponsorshipHandler<T> {19 pub fn withdraw_create_item(20 who: &T::AccountId,21 collection_id: &CollectionId,22 _properties: &CreateItemData,23 ) -> Option<T::AccountId> {24 let collection = CollectionById::<T>::get(collection_id)?;2526 27 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;2829 let limit = collection.limits.sponsor_transfer_timeout;30 if CreateItemBasket::<T>::contains_key((collection_id, &who)) {31 let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));32 let limit_time = last_tx_block + limit.into();33 if block_number <= limit_time {34 return None;35 }36 }37 CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);3839 40 if collection.limits.sponsored_data_size >= (_properties.data_size() as u32) {41 collection.sponsorship.sponsor().cloned()42 } else {43 None44 }45 }4647 pub fn withdraw_transfer(48 who: &T::AccountId,49 collection_id: &CollectionId,50 item_id: &TokenId,51 ) -> Option<T::AccountId> {52 let collection = CollectionById::<T>::get(collection_id)?;5354 let mut sponsor_transfer = false;55 if collection.sponsorship.confirmed() {56 let collection_limits = collection.limits.clone();57 let collection_mode = collection.mode.clone();5859 60 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;61 sponsor_transfer = match collection_mode {62 CollectionMode::NFT => {63 64 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {65 if collection_limits.sponsor_transfer_timeout > NFT_SPONSOR_TRANSFER_TIMEOUT66 {67 collection_limits.sponsor_transfer_timeout68 } else {69 NFT_SPONSOR_TRANSFER_TIMEOUT70 }71 } else {72 073 };7475 let mut sponsored = true;76 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {77 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);78 let limit_time = last_tx_block + limit.into();79 if block_number <= limit_time {80 sponsored = false;81 }82 }83 if sponsored {84 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);85 }8687 sponsored88 }89 CollectionMode::Fungible(_) => {90 91 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {92 if collection_limits.sponsor_transfer_timeout93 > FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT94 {95 collection_limits.sponsor_transfer_timeout96 } else {97 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT98 }99 } else {100 0101 };102103 let mut sponsored = true;104 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {105 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);106 let limit_time = last_tx_block + limit.into();107 if block_number <= limit_time {108 sponsored = false;109 }110 }111 if sponsored {112 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);113 }114115 sponsored116 }117 CollectionMode::ReFungible => {118 119 let limit: u32 = if collection_limits.sponsor_transfer_timeout != 0 {120 if collection_limits.sponsor_transfer_timeout121 > REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT122 {123 collection_limits.sponsor_transfer_timeout124 } else {125 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT126 }127 } else {128 0129 };130131 let mut sponsored = true;132 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {133 let last_tx_block =134 ReFungibleTransferBasket::<T>::get(collection_id, item_id);135 let limit_time = last_tx_block + limit.into();136 if block_number <= limit_time {137 sponsored = false;138 }139 }140 if sponsored {141 ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);142 }143144 sponsored145 }146 };147 }148149 if !sponsor_transfer {150 None151 } else {152 collection.sponsorship.sponsor().cloned()153 }154 }155156 pub fn withdraw_set_variable_meta_data(157 collection_id: &CollectionId,158 item_id: &TokenId,159 data: &[u8],160 ) -> Option<T::AccountId> {161 let mut sponsor_metadata_changes = false;162163 let collection = CollectionById::<T>::get(collection_id)?;164165 if collection.sponsorship.confirmed() &&166 167 168 !matches!(collection.mode, CollectionMode::Fungible(_)) &&169 data.len() <= collection.limits.sponsored_data_size as usize170 {171 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {172 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;173174 if VariableMetaDataBasket::<T>::get(collection_id, item_id)175 .map(|last_block| block_number - last_block > rate_limit)176 .unwrap_or(true)177 {178 sponsor_metadata_changes = true;179 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);180 }181 }182 }183184 if !sponsor_metadata_changes {185 None186 } else {187 collection.sponsorship.sponsor().cloned()188 }189 }190}191192impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>193where194 T: Config,195 C: IsSubType<Call<T>>,196{197 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {198 match IsSubType::<Call<T>>::is_sub_type(call)? {199 Call::create_item(collection_id, _owner, properties) => {200 Self::withdraw_create_item(who, collection_id, properties)201 }202 Call::transfer(_new_owner, collection_id, item_id, _value) => {203 Self::withdraw_transfer(who, collection_id, item_id)204 }205 Call::set_variable_meta_data(collection_id, item_id, data) => {206 Self::withdraw_set_variable_meta_data(collection_id, item_id, data)207 }208 _ => None,209 }210 }211}