1use crate::{2 Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket,3 ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, ChainLimit,4 CreateItemData, CollectionMode,5};6use core::marker::PhantomData;7use up_sponsorship::SponsorshipHandler;8use frame_support::{9 traits::IsSubType,10 storage::{StorageMap, StorageDoubleMap, StorageValue},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,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)?;50 let limits = ChainLimit::get();5152 let mut sponsor_transfer = false;53 if collection.sponsorship.confirmed() {54 let collection_limits = collection.limits.clone();55 let collection_mode = collection.mode.clone();5657 58 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;59 sponsor_transfer = match collection_mode {60 CollectionMode::NFT => {61 62 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {63 collection_limits.sponsor_transfer_timeout64 } else {65 limits.nft_sponsor_transfer_timeout66 };6768 let mut sponsored = true;69 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {70 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);71 let limit_time = last_tx_block + limit.into();72 if block_number <= limit_time {73 sponsored = false;74 }75 }76 if sponsored {77 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);78 }7980 sponsored81 }82 CollectionMode::Fungible(_) => {83 84 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {85 collection_limits.sponsor_transfer_timeout86 } else {87 limits.fungible_sponsor_transfer_timeout88 };8990 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;91 let mut sponsored = true;92 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {93 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);94 let limit_time = last_tx_block + limit.into();95 if block_number <= limit_time {96 sponsored = false;97 }98 }99 if sponsored {100 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);101 }102103 sponsored104 }105 CollectionMode::ReFungible => {106 107 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {108 collection_limits.sponsor_transfer_timeout109 } else {110 limits.refungible_sponsor_transfer_timeout111 };112113 let mut sponsored = true;114 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {115 let last_tx_block =116 ReFungibleTransferBasket::<T>::get(collection_id, item_id);117 let limit_time = last_tx_block + limit.into();118 if block_number <= limit_time {119 sponsored = false;120 }121 }122 if sponsored {123 ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);124 }125126 sponsored127 }128 _ => false,129 };130 }131132 if !sponsor_transfer {133 None134 } else {135 collection.sponsorship.sponsor().cloned()136 }137 }138139 pub fn withdraw_set_variable_meta_data(140 collection_id: &CollectionId,141 item_id: &TokenId,142 data: &[u8],143 ) -> Option<T::AccountId> {144 let mut sponsor_metadata_changes = false;145146 let collection = CollectionById::<T>::get(collection_id)?;147148 if collection.sponsorship.confirmed() &&149 150 151 !matches!(collection.mode, CollectionMode::Fungible(_)) &&152 data.len() <= collection.limits.sponsored_data_size as usize153 {154 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {155 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;156157 if VariableMetaDataBasket::<T>::get(collection_id, item_id)158 .map(|last_block| block_number - last_block > rate_limit)159 .unwrap_or(true)160 {161 sponsor_metadata_changes = true;162 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);163 }164 }165 }166167 if !sponsor_metadata_changes {168 None169 } else {170 collection.sponsorship.sponsor().cloned()171 }172 }173}174175impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>176where177 T: Config,178 C: IsSubType<Call<T>>,179{180 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {181 match IsSubType::<Call<T>>::is_sub_type(call)? {182 Call::create_item(collection_id, _owner, properties) => {183 Self::withdraw_create_item(who, collection_id, properties)184 }185 Call::transfer(_new_owner, collection_id, item_id, _value) => {186 Self::withdraw_transfer(who, collection_id, item_id)187 }188 Call::set_variable_meta_data(collection_id, item_id, data) => {189 Self::withdraw_set_variable_meta_data(collection_id, item_id, data)190 }191 _ => None,192 }193 }194}