From fbd9bd539b893a5f067c5d6d9dc1f18867225648 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Fri, 20 May 2022 14:56:22 +0000 Subject: [PATCH] feat: sponsor token property modifications --- --- 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; + pub TokenPropertyBasket get(fn token_property_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option; /// Approval sponsoring pub NftApproveBasket get(fn nft_approve_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option; --- 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 = >::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::( + &collection, + &who, + &token_id, + key.len() + value.len(), + ).map(|()| sponsor) + } UniqueNFTCall::ERC721UniqueExtensions( ERC721UniqueExtensionsCall::Transfer { token_id, .. }, ) => { --- a/runtime/common/src/sponsoring.rs +++ b/runtime/common/src/sponsoring.rs @@ -29,8 +29,8 @@ use pallet_evm::account::CrossAccountId; use pallet_unique::{ Call as UniqueCall, Config as UniqueConfig, FungibleApproveBasket, RefungibleApproveBasket, - NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, FungibleTransferBasket, - NftTransferBasket, + NftApproveBasket, CreateItemBasket, ReFungibleTransferBasket, + FungibleTransferBasket, NftTransferBasket, TokenPropertyBasket, }; use pallet_fungible::Config as FungibleConfig; use pallet_nonfungible::Config as NonfungibleConfig; @@ -39,6 +39,51 @@ pub trait Config: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {} impl Config for T where T: UniqueConfig + FungibleConfig + NonfungibleConfig + RefungibleConfig {} +// TODO: permission check? +pub fn withdraw_set_token_property( + collection: &CollectionHandle, + who: &T::CrossAccountId, + item_id: &TokenId, + data_size: usize, +) -> Option<()> { + // preliminary sponsoring correctness check + match collection.mode { + CollectionMode::NFT => { + let owner = pallet_nonfungible::TokenData::::get((collection.id, item_id))?.owner; + if !owner.conv_eq(who) { + return None; + } + } + CollectionMode::Fungible(_) => { + // Fungible tokens have no properties + return None; + } + CollectionMode::ReFungible => { + if !>::get((collection.id, who, item_id)) { + return None; + } + } + } + + if data_size > collection.limits.sponsored_data_size() as usize { + return None; + } + + let block_number = >::block_number() as T::BlockNumber; + let limit = collection.limits.sponsored_data_rate_limit()?; + + if let Some(last_tx_block) = TokenPropertyBasket::::get(collection.id, item_id) { + let timeout = last_tx_block + limit.into(); + if block_number < timeout { + return None; + } + } + + >::insert(collection.id, item_id, block_number); + + Some(()) +} + pub fn withdraw_transfer( collection: &CollectionHandle, who: &T::CrossAccountId, @@ -190,6 +235,22 @@ { fn get_sponsor(who: &T::AccountId, call: &C) -> Option { match IsSubType::>::is_sub_type(call)? { + UniqueCall::set_token_properties { + collection_id, + token_id, + properties, + .. + } => { + let (sponsor, collection) = load::(*collection_id)?; + withdraw_set_token_property( + &collection, + &T::CrossAccountId::from_sub(who.clone()), + &token_id, + // No overflow may happen, as data larger than usize can't reach here + properties.iter().map(|p| p.key.len() + p.value.len()).sum() + ) + .map(|()| sponsor) + } UniqueCall::create_item { collection_id, data, -- gitstuff