1use crate::{2 Config, Call, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket,3 FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode,4};5use core::marker::PhantomData;6use up_sponsorship::SponsorshipHandler;7use frame_support::{8 traits::{IsSubType},9 storage::{StorageMap, StorageDoubleMap},10};11use nft_data_structs::{12 TokenId, CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,13 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,14};15use pallet_common::{CollectionById};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 = collection30 .limits31 .sponsor_transfer_timeout(match _properties {32 CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,33 CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,34 CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,35 });36 if CreateItemBasket::<T>::contains_key((collection_id, &who)) {37 let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));38 let limit_time = last_tx_block + limit.into();39 if block_number <= limit_time {40 return None;41 }42 }43 CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);4445 46 if collection.limits.sponsored_data_size() >= (_properties.data_size() as u32) {47 collection.sponsorship.sponsor().cloned()48 } else {49 None50 }51 }5253 pub fn withdraw_transfer(54 who: &T::AccountId,55 collection_id: &CollectionId,56 item_id: &TokenId,57 ) -> Option<T::AccountId> {58 let collection = CollectionById::<T>::get(collection_id)?;5960 let mut sponsor_transfer = false;61 if collection.sponsorship.confirmed() {62 let collection_limits = collection.limits.clone();63 let collection_mode = collection.mode.clone();6465 66 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;67 sponsor_transfer = match collection_mode {68 CollectionMode::NFT => {69 70 let limit =71 collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);7273 let mut sponsored = true;74 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {75 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);76 let limit_time = last_tx_block + limit.into();77 if block_number <= limit_time {78 sponsored = false;79 }80 }81 if sponsored {82 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);83 }8485 sponsored86 }87 CollectionMode::Fungible(_) => {88 89 let limit = collection_limits90 .sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);9192 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;93 let mut sponsored = true;94 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {95 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);96 let limit_time = last_tx_block + limit.into();97 if block_number <= limit_time {98 sponsored = false;99 }100 }101 if sponsored {102 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);103 }104105 sponsored106 }107 CollectionMode::ReFungible => {108 109 let limit = collection_limits110 .sponsor_transfer_timeout(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);111112 let mut sponsored = true;113 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {114 let last_tx_block =115 ReFungibleTransferBasket::<T>::get(collection_id, item_id);116 let limit_time = last_tx_block + limit.into();117 if block_number <= limit_time {118 sponsored = false;119 }120 }121 if sponsored {122 ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);123 }124125 sponsored126 }127 };128 }129130 if !sponsor_transfer {131 None132 } else {133 collection.sponsorship.sponsor().cloned()134 }135 }136137 pub fn withdraw_set_variable_meta_data(138 collection_id: &CollectionId,139 item_id: &TokenId,140 data: &[u8],141 ) -> Option<T::AccountId> {142 let mut sponsor_metadata_changes = false;143144 let collection = CollectionById::<T>::get(collection_id)?;145146 if collection.sponsorship.confirmed() &&147 148 149 !matches!(collection.mode, CollectionMode::Fungible(_)) &&150 data.len() <= collection.limits.sponsored_data_size() as usize151 {152 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit() {153 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;154155 if VariableMetaDataBasket::<T>::get(collection_id, item_id)156 .map(|last_block| block_number - last_block > rate_limit.into())157 .unwrap_or(true)158 {159 sponsor_metadata_changes = true;160 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);161 }162 }163 }164165 if !sponsor_metadata_changes {166 None167 } else {168 collection.sponsorship.sponsor().cloned()169 }170 }171}172173impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>174where175 T: Config,176 C: IsSubType<Call<T>>,177{178 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {179 match IsSubType::<Call<T>>::is_sub_type(call)? {180 Call::create_item {181 collection_id,182 data,183 ..184 } => Self::withdraw_create_item(who, collection_id, data),185 Call::transfer {186 collection_id,187 item_id,188 ..189 } => Self::withdraw_transfer(who, collection_id, item_id),190 Call::set_variable_meta_data {191 collection_id,192 item_id,193 data,194 } => Self::withdraw_set_variable_meta_data(collection_id, item_id, data),195 _ => None,196 }197 }198}