difftreelog
feat sponsor token property modifications
in: master
3 files changed
pallets/unique/src/lib.rsdiffbeforeafterboth--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -242,6 +242,7 @@
/// Collection id (controlled?2), token id (controlled?2)
#[deprecated]
pub VariableMetaDataBasket get(fn variable_meta_data_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
+ pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
/// Approval sponsoring
pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
runtime/common/src/eth_sponsoring.rsdiffbeforeafterboth--- a/runtime/common/src/eth_sponsoring.rs
+++ b/runtime/common/src/eth_sponsoring.rs
@@ -30,7 +30,7 @@
use crate::sponsoring::*;
use pallet_nonfungible::erc::{
- UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call,
+ UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721MintableCall, ERC721Call, TokenPropertiesCall,
};
use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
use pallet_fungible::Config as FungibleConfig;
@@ -50,6 +50,17 @@
CollectionMode::NFT => {
let call = <UniqueNFTCall<T>>::parse(method_id, &mut reader).ok()??;
match call {
+ UniqueNFTCall::TokenProperties(
+ TokenPropertiesCall::SetProperty { token_id, key, value, .. },
+ ) => {
+ let token_id: TokenId = token_id.try_into().ok()?;
+ withdraw_set_token_property::<T>(
+ &collection,
+ &who,
+ &token_id,
+ key.len() + value.len(),
+ ).map(|()| sponsor)
+ }
UniqueNFTCall::ERC721UniqueExtensions(
ERC721UniqueExtensionsCall::Transfer { token_id, .. },
) => {
runtime/common/src/sponsoring.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617use core::marker::PhantomData;18use up_sponsorship::SponsorshipHandler;19use frame_support::{20 traits::{IsSubType},21 storage::{StorageMap, StorageDoubleMap, StorageNMap},22};23use up_data_structs::{24 CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,25 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId, CollectionMode, CreateItemData,26};27use sp_runtime::traits::Saturating;28use pallet_common::{CollectionHandle};29use pallet_evm::account::CrossAccountId;30use pallet_unique::{31 Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket,32 NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket,33 NftTransferBasket,34};35use pallet_fungible::Config as FungibleConfig;36use pallet_nonfungible::Config as NonfungibleConfig;37use pallet_refungible::Config as RefungibleConfig;3839pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}40impl<T> Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {}4142pub fn withdraw_transfer<T: Config>(43 collection: &CollectionHandle<T>,44 who: &T::CrossAccountId,45 item_id: &TokenId,46) -> Option<()> {47 // preliminary sponsoring correctness check48 match collection.mode {49 CollectionMode::NFT => {50 let owner = pallet_nonfungible::TokenData::<T>::get((collection.id, item_id))?.owner;51 if !owner.conv_eq(who) {52 return None;53 }54 }55 CollectionMode::Fungible(_) => {56 if item_id != &TokenId::default() {57 return None;58 }59 if <pallet_fungible::Balance<T>>::get((collection.id, who)) == 0 {60 return None;61 }62 }63 CollectionMode::ReFungible => {64 if !<pallet_refungible::Owned<T>>::get((collection.id, who, item_id)) {65 return None;66 }67 }68 }6970 // sponsor timeout71 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;72 let limit = collection73 .limits74 .sponsor_transfer_timeout(match collection.mode {75 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,76 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,77 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,78 });7980 let last_tx_block = match collection.mode {81 CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),82 CollectionMode::Fungible(_) => {83 <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())84 }85 CollectionMode::ReFungible => {86 <ReFungibleTransferBasket<T>>::get((collection.id, item_id, who.as_sub()))87 }88 };8990 if let Some(last_tx_block) = last_tx_block {91 let timeout = last_tx_block + limit.into();92 if block_number < timeout {93 return None;94 }95 }9697 match collection.mode {98 CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),99 CollectionMode::Fungible(_) => {100 <FungibleTransferBasket<T>>::insert(collection.id, who.as_sub(), block_number)101 }102 CollectionMode::ReFungible => <ReFungibleTransferBasket<T>>::insert(103 (collection.id, item_id, who.as_sub()),104 block_number,105 ),106 };107108 Some(())109}110111pub fn withdraw_create_item<T: Config>(112 collection: &CollectionHandle<T>,113 who: &T::CrossAccountId,114 _properties: &CreateItemData,115) -> Option<()> {116 if _properties.data_size() as u32 > collection.limits.sponsored_data_size() {117 return None;118 }119120 // sponsor timeout121 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;122 let limit = collection123 .limits124 .sponsor_transfer_timeout(match _properties {125 CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,126 CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,127 CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,128 });129130 if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, who.as_sub())) {131 let timeout = last_tx_block + limit.into();132 if block_number < timeout {133 return None;134 }135 }136137 CreateItemBasket::<T>::insert((collection.id, who.as_sub()), block_number);138139 Some(())140}141142pub fn withdraw_approve<T: Config>(143 collection: &CollectionHandle<T>,144 who: &T::AccountId,145 item_id: &TokenId,146) -> Option<()> {147 // sponsor timeout148 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;149 let limit = collection.limits.sponsor_approve_timeout();150151 let last_tx_block = match collection.mode {152 CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),153 CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),154 CollectionMode::ReFungible => {155 <RefungibleApproveBasket<T>>::get((collection.id, item_id, who))156 }157 };158159 if let Some(last_tx_block) = last_tx_block {160 let timeout = last_tx_block + limit.into();161 if block_number < timeout {162 return None;163 }164 }165166 match collection.mode {167 CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),168 CollectionMode::Fungible(_) => {169 <FungibleApproveBasket<T>>::insert(collection.id, who, block_number)170 }171 CollectionMode::ReFungible => {172 <RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)173 }174 };175176 Some(())177}178179fn load<T: UniqueConfig>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {180 let collection = CollectionHandle::new(id)?;181 let sponsor = collection.sponsorship.sponsor().cloned()?;182 Some((sponsor, collection))183}184185pub struct UniqueSponsorshipHandler<T>(PhantomData<T>);186impl<T, C> SponsorshipHandler<T::AccountId, C> for UniqueSponsorshipHandler<T>187where188 T: Config,189 C: IsSubType<UniqueCall<T>>,190{191 fn get_sponsor(who: &T::AccountId, call: &C) -> Option<T::AccountId> {192 match IsSubType::<UniqueCall<T>>::is_sub_type(call)? {193 UniqueCall::create_item {194 collection_id,195 data,196 ..197 } => {198 let (sponsor, collection) = load(*collection_id)?;199 withdraw_create_item::<T>(200 &collection,201 &T::CrossAccountId::from_sub(who.clone()),202 data,203 )204 .map(|()| sponsor)205 }206 UniqueCall::transfer {207 collection_id,208 item_id,209 ..210 } => {211 let (sponsor, collection) = load(*collection_id)?;212 withdraw_transfer::<T>(213 &collection,214 &T::CrossAccountId::from_sub(who.clone()),215 item_id,216 )217 .map(|()| sponsor)218 }219 UniqueCall::transfer_from {220 collection_id,221 item_id,222 from,223 ..224 } => {225 let (sponsor, collection) = load(*collection_id)?;226 withdraw_transfer::<T>(&collection, from, item_id).map(|()| sponsor)227 }228 UniqueCall::approve {229 collection_id,230 item_id,231 ..232 } => {233 let (sponsor, collection) = load(*collection_id)?;234 withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)235 }236 _ => None,237 }238 }239}240241pub trait SponsorshipPredict<T: Config> {242 fn predict(collection: CollectionId, account: T::CrossAccountId, token: TokenId) -> Option<u64>243 where244 u64: From<<T as frame_system::Config>::BlockNumber>;245}246247pub struct UniqueSponsorshipPredict<T>(PhantomData<T>);248249impl<T: Config> SponsorshipPredict<T> for UniqueSponsorshipPredict<T> {250 fn predict(collection_id: CollectionId, who: T::CrossAccountId, token: TokenId) -> Option<u64>251 where252 u64: From<<T as frame_system::Config>::BlockNumber>,253 {254 let collection = <CollectionHandle<T>>::try_get(collection_id).ok()?;255 let _ = collection.sponsorship.sponsor()?;256257 // sponsor timeout258 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;259 let limit = collection260 .limits261 .sponsor_transfer_timeout(match collection.mode {262 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,263 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,264 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,265 });266267 let last_tx_block = match collection.mode {268 CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, token),269 CollectionMode::Fungible(_) => {270 <FungibleTransferBasket<T>>::get(collection.id, who.as_sub())271 }272 CollectionMode::ReFungible => {273 <ReFungibleTransferBasket<T>>::get((collection.id, token, who.as_sub()))274 }275 };276277 if let Some(last_tx_block) = last_tx_block {278 return Some(279 last_tx_block280 .saturating_add(limit.into())281 .saturating_sub(block_number)282 .into(),283 );284 }285286 let token_exists = match collection.mode {287 CollectionMode::NFT => {288 <pallet_nonfungible::TokenData<T>>::contains_key((collection.id, token))289 }290 CollectionMode::Fungible(_) => token == TokenId::default(),291 CollectionMode::ReFungible => {292 <pallet_refungible::TotalSupply<T>>::contains_key((collection.id, token))293 }294 };295296 if token_exists {297 Some(0)298 } else {299 None300 }301 }302}