git.delta.rocks / unique-network / refs/commits / 35937ed58884

difftreelog

refactor share unq sponsoring code with evm

Yaroslav Bolyukin2021-11-18parent: #7e74e9a.patch.diff
in: master

4 files changed

modifiedpallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth
1//! Implements EVM sponsoring logic via OnChargeEVMTransaction1//! Implements EVM sponsoring logic via OnChargeEVMTransaction
22
3use crate::{Collection, Config, FungibleTransferBasket, NftTransferBasket};3use crate::{Config, sponsorship::*};
4use evm_coder::{Call, abi::AbiReader};4use evm_coder::{Call, abi::AbiReader};
5use frame_support::{
6 storage::{StorageDoubleMap},
7};
8use pallet_common::eth::map_eth_to_id;5use pallet_common::{CollectionHandle, eth::map_eth_to_id};
9use sp_core::H160;6use sp_core::H160;
10use sp_std::prelude::*;7use sp_std::prelude::*;
11use up_sponsorship::SponsorshipHandler;8use up_sponsorship::SponsorshipHandler;
12use core::marker::PhantomData;9use core::marker::PhantomData;
13use core::convert::TryInto;10use core::convert::TryInto;
14use nft_data_structs::{CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT};11use nft_data_structs::TokenId;
15use pallet_common::{12use up_evm_mapping::EvmBackwardsAddressMapping;
16 CollectionById,13use pallet_evm::AddressMapping;
17 account::{CrossAccountId, EvmBackwardsAddressMapping},
18};
1914
20use pallet_nonfungible::erc::{UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721Call};15use pallet_nonfungible::erc::{UniqueNFTCall, ERC721UniqueExtensionsCall, ERC721Call};
21use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};16use pallet_fungible::erc::{UniqueFungibleCall, ERC20Call};
22
23struct AnyError;
24
25fn try_sponsor<T: Config>(
26 caller: &H160,
27 collection_id: CollectionId,
28 collection: &Collection<T>,
29 call: &[u8],
30) -> Result<(), AnyError> {
31 let (method_id, mut reader) = AbiReader::new_call(call).map_err(|_| AnyError)?;
32 match &collection.mode {
33 crate::CollectionMode::NFT => {
34 let call: UniqueNFTCall = UniqueNFTCall::parse(method_id, &mut reader)
35 .map_err(|_| AnyError)?
36 .ok_or(AnyError)?;
37 match call {
38 UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer {
39 token_id,
40 ..
41 })
42 | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {
43 let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;
44 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
45 let collection_limits = &collection.limits;
46 let limit =
47 collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);
48
49 let mut sponsor = true;
50 if <NftTransferBasket<T>>::contains_key(collection_id, token_id) {
51 let last_tx_block = <NftTransferBasket<T>>::get(collection_id, token_id);
52 let limit_time = last_tx_block + limit.into();
53 if block_number <= limit_time {
54 sponsor = false;
55 }
56 }
57 if sponsor {
58 <NftTransferBasket<T>>::insert(collection_id, token_id, block_number);
59 return Ok(());
60 }
61 }
62 _ => {}
63 }
64 }
65 crate::CollectionMode::Fungible(_) => {
66 let call: UniqueFungibleCall = UniqueFungibleCall::parse(method_id, &mut reader)
67 .map_err(|_| AnyError)?
68 .ok_or(AnyError)?;
69 #[allow(clippy::single_match)]
70 match call {
71 UniqueFungibleCall::ERC20(ERC20Call::Transfer { .. }) => {
72 let who = T::CrossAccountId::from_eth(*caller);
73 let collection_limits = &collection.limits;
74 let limit = collection_limits
75 .sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);
76
77 let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
78 let mut sponsored = true;
79 if <FungibleTransferBasket<T>>::contains_key(collection_id, who.as_sub()) {
80 let last_tx_block =
81 <FungibleTransferBasket<T>>::get(collection_id, who.as_sub());
82 let limit_time = last_tx_block + limit.into();
83 if block_number <= limit_time {
84 sponsored = false;
85 }
86 }
87 if sponsored {
88 <FungibleTransferBasket<T>>::insert(
89 collection_id,
90 who.as_sub(),
91 block_number,
92 );
93 return Ok(());
94 }
95 }
96 _ => {}
97 }
98 }
99 _ => {}
100 }
101 Err(AnyError)
102}
10317
104pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);18pub struct NftEthSponsorshipHandler<T: Config>(PhantomData<*const T>);
105impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {19impl<T: Config> SponsorshipHandler<H160, (H160, Vec<u8>)> for NftEthSponsorshipHandler<T> {
106 fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {20 fn get_sponsor(who: &H160, call: &(H160, Vec<u8>)) -> Option<H160> {
107 if let Some(collection_id) = map_eth_to_id(&call.0) {21 let collection_id = map_eth_to_id(&call.0)?;
108 if let Some(collection) = <CollectionById<T>>::get(collection_id) {22 let collection = <CollectionHandle<T>>::new(collection_id)?;
109 if !collection.sponsorship.confirmed() {23 let sponsor = collection.sponsorship.sponsor()?.clone();
110 return None;24 let sponsor =
111 }25 <T as pallet_common::Config>::EvmBackwardsAddressMapping::from_account_id(sponsor);
26 let who = <T as pallet_common::Config>::EvmAddressMapping::into_account_id(*who);
27 let (method_id, mut reader) = AbiReader::new_call(&call.1).ok()?;
28 match &collection.mode {
29 crate::CollectionMode::NFT => {
30 let call = UniqueNFTCall::parse(method_id, &mut reader).ok()??;
31 match call {
32 UniqueNFTCall::ERC721UniqueExtensions(
33 ERC721UniqueExtensionsCall::Transfer { token_id, .. },
34 )
35 | UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {
36 let token_id: TokenId = token_id.try_into().ok()?;
112 if try_sponsor(who, collection_id, &collection, &call.1).is_ok() {37 withdraw_transfer::<T>(&collection, &who, &token_id).map(|()| sponsor)
113 return collection38 }
114 .sponsorship39 UniqueNFTCall::ERC721(ERC721Call::Approve { token_id, .. }) => {
115 .sponsor()40 let token_id: TokenId = token_id.try_into().ok()?;
116 .cloned()41 withdraw_approve::<T>(&collection, &who, &token_id).map(|()| sponsor)
117 .map(T::EvmBackwardsAddressMapping::from_account_id);42 }
118 }43 _ => None,
119 }44 }
120 }45 }
46 crate::CollectionMode::Fungible(_) => {
47 let call = UniqueFungibleCall::parse(method_id, &mut reader).ok()??;
48 #[allow(clippy::single_match)]
49 match call {
50 UniqueFungibleCall::ERC20(
51 ERC20Call::Transfer { .. } | ERC20Call::TransferFrom { .. },
52 ) => withdraw_transfer::<T>(&collection, &who, &TokenId::default())
53 .map(|()| sponsor),
54 UniqueFungibleCall::ERC20(ERC20Call::Approve { .. }) => {
55 withdraw_approve::<T>(&collection, &who, &TokenId::default())
56 .map(|()| sponsor)
57 }
58 _ => None,
59 }
60 }
121 None61 _ => None,
62 }
122 }63 }
123}64}
12465
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -136,13 +136,13 @@
 		//#region Tokens transfer rate limit baskets
 		/// (Collection id (controlled?2), who created (real))
 		/// TODO: Off chain worker should remove from this map when collection gets removed
-		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => T::BlockNumber;
+		pub CreateItemBasket get(fn create_item_basket): map hasher(blake2_128_concat) (CollectionId, T::AccountId) => Option<T::BlockNumber>;
 		/// Collection id (controlled?2), token id (controlled?2)
-		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;
+		pub NftTransferBasket get(fn nft_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => Option<T::BlockNumber>;
 		/// Collection id (controlled?2), owning user (real)
-		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => T::BlockNumber;
+		pub FungibleTransferBasket get(fn fungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
 		/// Collection id (controlled?2), token id (controlled?2)
-		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): double_map hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId => T::BlockNumber;
+		pub ReFungibleTransferBasket get(fn refungible_transfer_basket): nmap hasher(blake2_128_concat) CollectionId, hasher(blake2_128_concat) TokenId, hasher(twox_64_concat) T::AccountId => Option<T::BlockNumber>;
 		//#endregion
 
 		/// Variable metadata sponsoring
@@ -253,7 +253,7 @@
 
 			<NftTransferBasket<T>>::remove_prefix(collection_id, None);
 			<FungibleTransferBasket<T>>::remove_prefix(collection_id, None);
-			<ReFungibleTransferBasket<T>>::remove_prefix(collection_id, None);
+			<ReFungibleTransferBasket<T>>::remove_prefix((collection_id,), None);
 
 			<VariableMetaDataBasket<T>>::remove_prefix(collection_id, None);
 			<NftApproveBasket<T>>::remove_prefix(collection_id, None);
modifiedpallets/nft/src/sponsorship.rsdiffbeforeafterboth
--- a/pallets/nft/src/sponsorship.rs
+++ b/pallets/nft/src/sponsorship.rs
@@ -1,175 +1,167 @@
 use crate::{
 	Config, Call, CreateItemBasket, VariableMetaDataBasket, ReFungibleTransferBasket,
-	FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode,
+	FungibleTransferBasket, NftTransferBasket, CreateItemData, CollectionMode, NftApproveBasket,
+	FungibleApproveBasket, RefungibleApproveBasket,
 };
 use core::marker::PhantomData;
 use up_sponsorship::SponsorshipHandler;
 use frame_support::{
 	traits::{IsSubType},
-	storage::{StorageMap, StorageDoubleMap},
+	storage::{StorageMap, StorageDoubleMap, StorageNMap},
 };
 use nft_data_structs::{
-	TokenId, CollectionId, NFT_SPONSOR_TRANSFER_TIMEOUT, REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-	FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+	CollectionId, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, NFT_SPONSOR_TRANSFER_TIMEOUT,
+	REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, TokenId,
 };
-use pallet_common::{CollectionById};
+use pallet_common::{CollectionHandle};
 
-pub struct NftSponsorshipHandler<T>(PhantomData<T>);
-impl<T: Config> NftSponsorshipHandler<T> {
-	pub fn withdraw_create_item(
-		who: &T::AccountId,
-		collection_id: &CollectionId,
-		_properties: &CreateItemData,
-	) -> Option<T::AccountId> {
-		let collection = CollectionById::<T>::get(collection_id)?;
+pub fn withdraw_transfer<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::AccountId,
+	item_id: &TokenId,
+) -> Option<()> {
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection
+		.limits
+		.sponsor_transfer_timeout(match collection.mode {
+			CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,
+			CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+			CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+		});
 
-		// sponsor timeout
-		let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-
-		let limit = collection
-			.limits
-			.sponsor_transfer_timeout(match _properties {
-				CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
-				CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-				CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
-			});
-		if CreateItemBasket::<T>::contains_key((collection_id, &who)) {
-			let last_tx_block = CreateItemBasket::<T>::get((collection_id, &who));
-			let limit_time = last_tx_block + limit.into();
-			if block_number <= limit_time {
-				return None;
-			}
+	let last_tx_block = match collection.mode {
+		CollectionMode::NFT => <NftTransferBasket<T>>::get(collection.id, item_id),
+		CollectionMode::Fungible(_) => <FungibleTransferBasket<T>>::get(collection.id, who),
+		CollectionMode::ReFungible => {
+			<ReFungibleTransferBasket<T>>::get((collection.id, item_id, who))
 		}
-		CreateItemBasket::<T>::insert((collection_id, who.clone()), block_number);
+	};
 
-		// check free create limit
-		if collection.limits.sponsored_data_size() >= (_properties.data_size() as u32) {
-			collection.sponsorship.sponsor().cloned()
-		} else {
-			None
+	if let Some(last_tx_block) = last_tx_block {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
 		}
 	}
 
-	pub fn withdraw_transfer(
-		who: &T::AccountId,
-		collection_id: &CollectionId,
-		item_id: &TokenId,
-	) -> Option<T::AccountId> {
-		let collection = CollectionById::<T>::get(collection_id)?;
+	match collection.mode {
+		CollectionMode::NFT => <NftTransferBasket<T>>::insert(collection.id, item_id, block_number),
+		CollectionMode::Fungible(_) => {
+			<FungibleTransferBasket<T>>::insert(collection.id, who, block_number)
+		}
+		CollectionMode::ReFungible => {
+			<ReFungibleTransferBasket<T>>::insert((collection.id, item_id, who), block_number)
+		}
+	};
 
-		let mut sponsor_transfer = false;
-		if collection.sponsorship.confirmed() {
-			let collection_limits = collection.limits.clone();
-			let collection_mode = collection.mode.clone();
+	Some(())
+}
 
-			// sponsor timeout
-			let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-			sponsor_transfer = match collection_mode {
-				CollectionMode::NFT => {
-					// get correct limit
-					let limit =
-						collection_limits.sponsor_transfer_timeout(NFT_SPONSOR_TRANSFER_TIMEOUT);
+pub fn withdraw_create_item<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::AccountId,
+	_properties: &CreateItemData,
+) -> Option<()> {
+	if _properties.data_size() as u32 > collection.limits.sponsored_data_size() {
+		return None;
+	}
 
-					let mut sponsored = true;
-					if NftTransferBasket::<T>::contains_key(collection_id, item_id) {
-						let last_tx_block = NftTransferBasket::<T>::get(collection_id, item_id);
-						let limit_time = last_tx_block + limit.into();
-						if block_number <= limit_time {
-							sponsored = false;
-						}
-					}
-					if sponsored {
-						NftTransferBasket::<T>::insert(collection_id, item_id, block_number);
-					}
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection
+		.limits
+		.sponsor_transfer_timeout(match _properties {
+			CreateItemData::NFT(_) => NFT_SPONSOR_TRANSFER_TIMEOUT,
+			CreateItemData::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+			CreateItemData::ReFungible(_) => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
+		});
 
-					sponsored
-				}
-				CollectionMode::Fungible(_) => {
-					// get correct limit
-					let limit = collection_limits
-						.sponsor_transfer_timeout(FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);
+	if let Some(last_tx_block) = <CreateItemBasket<T>>::get((collection.id, &who)) {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
+		}
+	}
 
-					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
-					let mut sponsored = true;
-					if FungibleTransferBasket::<T>::contains_key(collection_id, who) {
-						let last_tx_block = FungibleTransferBasket::<T>::get(collection_id, who);
-						let limit_time = last_tx_block + limit.into();
-						if block_number <= limit_time {
-							sponsored = false;
-						}
-					}
-					if sponsored {
-						FungibleTransferBasket::<T>::insert(collection_id, who, block_number);
-					}
+	CreateItemBasket::<T>::insert((collection.id, who.clone()), block_number);
 
-					sponsored
-				}
-				CollectionMode::ReFungible => {
-					// get correct limit
-					let limit = collection_limits
-						.sponsor_transfer_timeout(REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT);
+	Some(())
+}
 
-					let mut sponsored = true;
-					if ReFungibleTransferBasket::<T>::contains_key(collection_id, item_id) {
-						let last_tx_block =
-							ReFungibleTransferBasket::<T>::get(collection_id, item_id);
-						let limit_time = last_tx_block + limit.into();
-						if block_number <= limit_time {
-							sponsored = false;
-						}
-					}
-					if sponsored {
-						ReFungibleTransferBasket::<T>::insert(collection_id, item_id, block_number);
-					}
+pub fn withdraw_set_variable_meta_data<T: Config>(
+	collection: &CollectionHandle<T>,
+	item_id: &TokenId,
+	data: &[u8],
+) -> Option<()> {
+	// Can't sponsor fungible collection, this tx will be rejected
+	// as invalid
+	if matches!(collection.mode, CollectionMode::Fungible(_)) {
+		return None;
+	}
+	if data.len() > collection.limits.sponsored_data_size() as usize {
+		return None;
+	}
 
-					sponsored
-				}
-			};
-		}
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection.limits.sponsored_data_rate_limit()?;
 
-		if !sponsor_transfer {
-			None
-		} else {
-			collection.sponsorship.sponsor().cloned()
+	if let Some(last_tx_block) = VariableMetaDataBasket::<T>::get(collection.id, item_id) {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
 		}
 	}
 
-	pub fn withdraw_set_variable_meta_data(
-		collection_id: &CollectionId,
-		item_id: &TokenId,
-		data: &[u8],
-	) -> Option<T::AccountId> {
-		let mut sponsor_metadata_changes = false;
+	<VariableMetaDataBasket<T>>::insert(collection.id, item_id, block_number);
 
-		let collection = CollectionById::<T>::get(collection_id)?;
+	Some(())
+}
 
-		if collection.sponsorship.confirmed() &&
-			// Can't sponsor fungible collection, this tx will be rejected
-			// as invalid
-			!matches!(collection.mode, CollectionMode::Fungible(_)) &&
-			data.len() <= collection.limits.sponsored_data_size() as usize
-		{
-			if let Some(rate_limit) = collection.limits.sponsored_data_rate_limit() {
-				let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+pub fn withdraw_approve<T: Config>(
+	collection: &CollectionHandle<T>,
+	who: &T::AccountId,
+	item_id: &TokenId,
+) -> Option<()> {
+	// sponsor timeout
+	let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
+	let limit = collection.limits.sponsor_approve_timeout();
 
-				if VariableMetaDataBasket::<T>::get(collection_id, item_id)
-					.map(|last_block| block_number - last_block > rate_limit.into())
-					.unwrap_or(true)
-				{
-					sponsor_metadata_changes = true;
-					VariableMetaDataBasket::<T>::insert(collection_id, item_id, block_number);
-				}
-			}
+	let last_tx_block = match collection.mode {
+		CollectionMode::NFT => <NftApproveBasket<T>>::get(collection.id, item_id),
+		CollectionMode::Fungible(_) => <FungibleApproveBasket<T>>::get(collection.id, who),
+		CollectionMode::ReFungible => {
+			<RefungibleApproveBasket<T>>::get((collection.id, item_id, who))
 		}
+	};
 
-		if !sponsor_metadata_changes {
-			None
-		} else {
-			collection.sponsorship.sponsor().cloned()
+	if let Some(last_tx_block) = last_tx_block {
+		let timeout = last_tx_block + limit.into();
+		if block_number < timeout {
+			return None;
 		}
 	}
+
+	match collection.mode {
+		CollectionMode::NFT => <NftApproveBasket<T>>::insert(collection.id, item_id, block_number),
+		CollectionMode::Fungible(_) => {
+			<FungibleApproveBasket<T>>::insert(collection.id, who, block_number)
+		}
+		CollectionMode::ReFungible => {
+			<RefungibleApproveBasket<T>>::insert((collection.id, item_id, who), block_number)
+		}
+	};
+
+	Some(())
 }
 
+fn load<T: Config>(id: CollectionId) -> Option<(T::AccountId, CollectionHandle<T>)> {
+	let collection = CollectionHandle::new(id)?;
+	let sponsor = collection.sponsorship.sponsor().cloned()?;
+	Some((sponsor, collection))
+}
+
+pub struct NftSponsorshipHandler<T>(PhantomData<T>);
 impl<T, C> SponsorshipHandler<T::AccountId, C> for NftSponsorshipHandler<T>
 where
 	T: Config,
@@ -181,17 +173,39 @@
 				collection_id,
 				data,
 				..
-			} => Self::withdraw_create_item(who, collection_id, data),
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_create_item::<T>(&collection, who, data).map(|()| sponsor)
+			}
 			Call::transfer {
 				collection_id,
 				item_id,
 				..
-			} => Self::withdraw_transfer(who, collection_id, item_id),
+			}
+			| Call::transfer_from {
+				collection_id,
+				item_id,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_transfer::<T>(&collection, who, item_id).map(|()| sponsor)
+			}
+			Call::approve {
+				collection_id,
+				item_id,
+				..
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_approve::<T>(&collection, who, item_id).map(|()| sponsor)
+			}
 			Call::set_variable_meta_data {
 				collection_id,
 				item_id,
 				data,
-			} => Self::withdraw_set_variable_meta_data(collection_id, item_id, data),
+			} => {
+				let (sponsor, collection) = load(*collection_id)?;
+				withdraw_set_variable_meta_data::<T>(&collection, item_id, data).map(|()| sponsor)
+			}
 			_ => None,
 		}
 	}
modifiedprimitives/evm-mapping/src/lib.rsdiffbeforeafterboth
--- a/primitives/evm-mapping/src/lib.rs
+++ b/primitives/evm-mapping/src/lib.rs
@@ -4,9 +4,9 @@
 use sp_core::H160;
 
 /// Transforms substrate addresses to ethereum (Reverse of `EvmAddressMapping`)
-/// pallet_evm doesn't have this, as it only checks if eth address 
+/// pallet_evm doesn't have this, as it only checks if eth address
 /// is owned by substrate via `EnsureAddressOrigin` trait
-/// 
+///
 /// This trait implementations shouldn't conflict with used `EnsureAddressOrigin`
 pub trait EvmBackwardsAddressMapping<AccountId> {
 	fn from_account_id(account_id: AccountId) -> H160;