1use crate::{2 Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket,3 ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket,4 CreateItemData, CollectionMode, limit,5};6use core::marker::PhantomData;7use up_sponsorship::SponsorshipHandler;8use frame_support::{9 traits::{IsSubType, Get},10 storage::{StorageMap, StorageDoubleMap},11};12use nft_data_structs::{TokenId, CollectionId};1314pub struct NftSponsorshipHandler<T>(PhantomData<T>);15impl<T: Config> NftSponsorshipHandler<T> {16 pub fn withdraw_create_item(17 who: &T::AccountId,18 collection_id: &CollectionId,19 _properties: &CreateItemData<T::ChainLimits>,20 ) -> Option<T::AccountId> {21 let collection = CollectionById::<T>::get(collection_id)?;2223 24 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;2526 let limit = collection.limits.sponsor_transfer_timeout;27 if CreateItemBasket::<T>::contains_key((collection_id, &who)) {28 let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));29 let limit_time = last_tx_block + limit.into();30 if block_number <= limit_time {31 return None;32 }33 }34 CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);3536 37 if collection.limits.sponsored_data_size >= (_properties.data_size() as u32) {38 collection.sponsorship.sponsor().cloned()39 } else {40 None41 }42 }4344 pub fn withdraw_transfer(45 who: &T::AccountId,46 collection_id: &CollectionId,47 item_id: &TokenId,48 ) -> Option<T::AccountId> {49 let collection = CollectionById::<T>::get(collection_id)?;5051 let mut sponsor_transfer = false;52 if collection.sponsorship.confirmed() {53 let collection_limits = collection.limits.clone();54 let collection_mode = collection.mode.clone();5556 57 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;58 sponsor_transfer = match collection_mode {59 CollectionMode::NFT => {60 61 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {62 collection_limits.sponsor_transfer_timeout63 } else {64 <limit!(T, NftSponsorTransferTimeout)>::get()65 };6667 let mut sponsored = true;68 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {69 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);70 let limit_time = last_tx_block + limit.into();71 if block_number <= limit_time {72 sponsored = false;73 }74 }75 if sponsored {76 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);77 }7879 sponsored80 }81 CollectionMode::Fungible(_) => {82 83 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {84 collection_limits.sponsor_transfer_timeout85 } else {86 <limit!(T, FungibleSponsorTransferTimeout)>::get()87 };8889 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;90 let mut sponsored = true;91 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {92 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);93 let limit_time = last_tx_block + limit.into();94 if block_number <= limit_time {95 sponsored = false;96 }97 }98 if sponsored {99 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);100 }101102 sponsored103 }104 CollectionMode::ReFungible => {105 106 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {107 collection_limits.sponsor_transfer_timeout108 } else {109 <limit!(T, ReFungibleSponsorTransferTimeout)>::get()110 };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 _ => false,128 };129 }130131 if !sponsor_transfer {132 None133 } else {134 collection.sponsorship.sponsor().cloned()135 }136 }137138 pub fn withdraw_set_variable_meta_data(139 collection_id: &CollectionId,140 item_id: &TokenId,141 data: &[u8],142 ) -> Option<T::AccountId> {143 let mut sponsor_metadata_changes = false;144145 let collection = CollectionById::<T>::get(collection_id)?;146147 if collection.sponsorship.confirmed() &&148 149 150 !matches!(collection.mode, CollectionMode::Fungible(_)) &&151 data.len() <= collection.limits.sponsored_data_size as usize152 {153 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {154 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;155156 if VariableMetaDataBasket::<T>::get(collection_id, item_id)157 .map(|last_block| block_number - last_block > rate_limit)158 .unwrap_or(true)159 {160 sponsor_metadata_changes = true;161 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);162 }163 }164 }165166 if !sponsor_metadata_changes {167 None168 } else {169 collection.sponsorship.sponsor().cloned()170 }171 }172}173174impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>175where176 T: Config,177 C: IsSubType<Call<T>>,178{179 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {180 match IsSubType::<Call<T>>::is_sub_type(call)? {181 Call::create_item(collection_id, _owner, properties) => {182 Self::withdraw_create_item(who, collection_id, properties)183 }184 Call::transfer(_new_owner, collection_id, item_id, _value) => {185 Self::withdraw_transfer(who, collection_id, item_id)186 }187 Call::set_variable_meta_data(collection_id, item_id, data) => {188 Self::withdraw_set_variable_meta_data(collection_id, item_id, data)189 }190 _ => None,191 }192 }193}