difftreelog
feat implement sponsoring primitive for nft
in: master
3 files changed
pallets/nft/Cargo.tomldiffbeforeafterboth--- a/pallets/nft/Cargo.toml
+++ b/pallets/nft/Cargo.toml
@@ -30,6 +30,7 @@
'pallet-transaction-payment/std',
'fp-evm/std',
'nft-data-structs/std',
+ 'up-sponsorship/std',
'sp-std/std',
'sp-api/std',
'sp-runtime/std',
@@ -135,9 +136,14 @@
[dependencies.nft-data-structs]
default-features = false
-path = '../../primitives'
+path = '../../primitives/nft'
version = '0.9.0'
+[dependencies.up-sponsorship]
+default-features = false
+path = '../../primitives/sponsorship'
+version = '0.1.0'
+
[dependencies]
ethereum-tx-sign = { version = "3.0.4", optional = true }
pallets/nft/src/lib.rsdiffbeforeafterboth--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -50,6 +50,8 @@
mod default_weights;
mod eth;
+mod sponsorship;
+pub use sponsorship::NftSponsorshipHandler;
pub use eth::NftErcSupport;
pub use eth::account::*;
@@ -2232,12 +2234,6 @@
) -> DispatchResult {
Self::remove_token_index(collection_id, item_index, old_owner)?;
Self::add_token_index(collection_id, item_index, new_owner)?;
-
- Ok(())
- }
-
- fn ensure_contract_owned(account: T::AccountId, contract: &T::AccountId) -> DispatchResult {
- ensure!(<ContractOwner<T>>::get(contract) == Some(account), Error::<T>::NoPermission);
Ok(())
}
pallets/nft/src/sponsorship.rsdiffbeforeafterboth1use crate::{Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, ChainLimit, CreateItemData, CollectionMode};2use core::marker::PhantomData;3use up_sponsorship::SponsorshipHandler;4use frame_support::{5 traits::IsSubType,6 storage::{StorageMap, StorageDoubleMap, StorageValue},7};8use nft_data_structs::{TokenId, CollectionId};9use alloc::vec::Vec;1011pub struct NftSponsorshipHandler<T>(PhantomData<T>);12impl<T: Config> NftSponsorshipHandler<T> {13 pub fn withdraw_create_item(14 who: &T::AccountId,15 collection_id: &CollectionId,16 _properties: &CreateItemData,17 ) -> Option<T::AccountId> {18 19 let collection = CollectionById::<T>::get(collection_id)?;2021 // sponsor timeout22 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;2324 let limit = collection.limits.sponsor_transfer_timeout;25 if CreateItemBasket::<T>::contains_key((collection_id, &who)) {26 let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));27 let limit_time = last_tx_block + limit.into();28 if block_number <= limit_time {29 return None;30 }31 }32 CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);3334 // check free create limit35 if collection.limits.sponsored_data_size >= (_properties.len() as u32) {36 collection.sponsorship.sponsor()37 .cloned()38 } else {39 None40 }41 }4243 pub fn withdraw_transfer(44 who: &T::AccountId,45 collection_id: &CollectionId,46 item_id: &TokenId,47 ) -> Option<T::AccountId> {4849 let collection = CollectionById::<T>::get(collection_id)?;50 let limits = ChainLimit::get();5152 let mut sponsor_transfer = false;53 if collection.sponsorship.confirmed() {5455 let collection_limits = collection.limits.clone();56 let collection_mode = collection.mode.clone();5758 // sponsor timeout59 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;60 sponsor_transfer = match collection_mode {61 CollectionMode::NFT => {6263 // get correct limit64 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {65 collection_limits.sponsor_transfer_timeout66 } else {67 limits.nft_sponsor_transfer_timeout68 };6970 let mut sponsored = true;71 if NftTransferBasket::<T>::contains_key(collection_id, item_id) {72 let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);73 let limit_time = last_tx_block + limit.into();74 if block_number <= limit_time {75 sponsored = false;76 }77 }78 if sponsored {79 NftTransferBasket::<T>::insert(collection_id, item_id, block_number);80 }8182 sponsored83 }84 CollectionMode::Fungible(_) => {8586 // get correct limit87 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {88 collection_limits.sponsor_transfer_timeout89 } else {90 limits.fungible_sponsor_transfer_timeout91 };9293 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;94 let mut sponsored = true;95 if FungibleTransferBasket::<T>::contains_key(collection_id, who) {96 let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);97 let limit_time = last_tx_block + limit.into();98 if block_number <= limit_time {99 sponsored = false;100 }101 }102 if sponsored {103 FungibleTransferBasket::<T>::insert(collection_id, who, block_number);104 }105106 sponsored107 }108 CollectionMode::ReFungible => {109110 // get correct limit111 let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 {112 collection_limits.sponsor_transfer_timeout113 } else {114 limits.refungible_sponsor_transfer_timeout115 };116117 let mut sponsored = true;118 if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {119 let last_tx_block = ReFungibleTransferBasket::<T>::get(collection_id, item_id);120 let limit_time = last_tx_block + limit.into();121 if block_number <= limit_time {122 sponsored = false;123 }124 }125 if sponsored {126 ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);127 }128129 sponsored130 }131 _ => {132 false133 },134 };135 }136137 if !sponsor_transfer {138 None139 } else {140 collection.sponsorship.sponsor()141 .cloned()142 }143 }144 145 pub fn withdraw_set_variable_meta_data(146 collection_id: &CollectionId,147 item_id: &TokenId,148 data: &Vec<u8>,149 ) -> Option<T::AccountId> {150151 let mut sponsor_metadata_changes = false;152153 let collection = CollectionById::<T>::get(collection_id)?;154155 if156 collection.sponsorship.confirmed() &&157 // Can't sponsor fungible collection, this tx will be rejected158 // as invalid159 !matches!(collection.mode, CollectionMode::Fungible(_)) &&160 data.len() <= collection.limits.sponsored_data_size as usize161 {162 if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit {163 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;164165 if VariableMetaDataBasket::<T>::get(collection_id, item_id)166 .map(|last_block| block_number - last_block > rate_limit)167 .unwrap_or(true) 168 {169 sponsor_metadata_changes = true;170 VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);171 }172 }173 }174175 if !sponsor_metadata_changes {176 None177 } else {178 collection.sponsorship.sponsor().cloned()179 }180181 }182}183184impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>185where 186 T: Config,187 C: IsSubType<Call<T>>188{189 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {190 match IsSubType::<Call<T>>::is_sub_type(call)? {191 Call::create_item(collection_id, _owner, _properties) => {192 Self::withdraw_create_item(who, collection_id, &_properties)193 },194 Call::transfer(_new_owner, collection_id, item_id, _value) => {195 Self::withdraw_transfer(who, collection_id, item_id)196 },197 Call::set_variable_meta_data(collection_id, item_id, data) => {198 Self::withdraw_set_variable_meta_data(collection_id, item_id, &data)199 },200 _ => None,201 }202 }203}