git.delta.rocks / unique-network / refs/commits / 44992fca8f8c

difftreelog

feat burn_from

Yaroslav Bolyukin2021-11-02parent: #283713e.patch.diff
in: master

12 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -459,6 +459,7 @@
 	fn transfer() -> Weight;
 	fn approve() -> Weight;
 	fn transfer_from() -> Weight;
+	fn burn_from() -> Weight;
 	fn set_variable_metadata(bytes: u32) -> Weight;
 }
 
@@ -504,6 +505,13 @@
 		token: TokenId,
 		amount: u128,
 	) -> DispatchResultWithPostInfo;
+	fn burn_from(
+		&self,
+		sender: T::CrossAccountId,
+		from: T::CrossAccountId,
+		token: TokenId,
+		amount: u128,
+	) -> DispatchResultWithPostInfo;
 
 	fn set_variable_metadata(
 		&self,
modifiedpallets/fungible/src/common.rsdiffbeforeafterboth
before · pallets/fungible/src/common.rs
1use core::marker::PhantomData;23use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};4use nft_data_structs::TokenId;5use pallet_common::{6	CommonCollectionOperations, CommonWeightInfo, account::CrossAccountId, with_weight,7};8use sp_runtime::ArithmeticError;9use sp_std::{vec::Vec, vec};1011use crate::{12	Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,13};1415pub struct CommonWeights<T: Config>(PhantomData<T>);16impl<T: Config> CommonWeightInfo for CommonWeights<T> {17	fn create_item() -> Weight {18		<SelfWeightOf<T>>::create_item()19	}2021	fn create_multiple_items(_amount: u32) -> Weight {22		Self::create_item()23	}2425	fn burn_item() -> Weight {26		<SelfWeightOf<T>>::burn_item()27	}2829	fn transfer() -> Weight {30		<SelfWeightOf<T>>::transfer()31	}3233	fn approve() -> Weight {34		<SelfWeightOf<T>>::approve()35	}3637	fn transfer_from() -> Weight {38		<SelfWeightOf<T>>::transfer_from()39	}4041	fn set_variable_metadata(_bytes: u32) -> Weight {42		// Error43		044	}45}4647impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {48	fn create_item(49		&self,50		sender: T::CrossAccountId,51		to: T::CrossAccountId,52		data: nft_data_structs::CreateItemData,53	) -> DispatchResultWithPostInfo {54		match data {55			nft_data_structs::CreateItemData::Fungible(data) => with_weight(56				<Pallet<T>>::create_item(self, &sender, (to, data.value)),57				<CommonWeights<T>>::create_item(),58			),59			_ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),60		}61	}6263	fn create_multiple_items(64		&self,65		sender: T::CrossAccountId,66		to: T::CrossAccountId,67		data: Vec<nft_data_structs::CreateItemData>,68	) -> DispatchResultWithPostInfo {69		let mut sum: u128 = 0;70		for data in data {71			match data {72				nft_data_structs::CreateItemData::Fungible(data) => {73					sum = sum74						.checked_add(data.value)75						.ok_or(ArithmeticError::Overflow)?;76				}77				_ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),78			}79		}8081		with_weight(82			<Pallet<T>>::create_item(self, &sender, (to, sum)),83			<CommonWeights<T>>::create_item(),84		)85	}8687	fn burn_item(88		&self,89		sender: T::CrossAccountId,90		token: TokenId,91		amount: u128,92	) -> DispatchResultWithPostInfo {93		ensure!(94			token == TokenId::default(),95			<Error<T>>::FungibleItemsHaveNoId96		);9798		with_weight(99			<Pallet<T>>::burn(self, &sender, amount),100			<CommonWeights<T>>::burn_item(),101		)102	}103104	fn transfer(105		&self,106		from: T::CrossAccountId,107		to: T::CrossAccountId,108		token: TokenId,109		amount: u128,110	) -> DispatchResultWithPostInfo {111		ensure!(112			token == TokenId::default(),113			<Error<T>>::FungibleItemsHaveNoId114		);115116		with_weight(117			<Pallet<T>>::transfer(&self, &from, &to, amount),118			<CommonWeights<T>>::transfer(),119		)120	}121122	fn approve(123		&self,124		sender: T::CrossAccountId,125		spender: T::CrossAccountId,126		token: TokenId,127		amount: u128,128	) -> DispatchResultWithPostInfo {129		ensure!(130			token == TokenId::default(),131			<Error<T>>::FungibleItemsHaveNoId132		);133134		with_weight(135			<Pallet<T>>::set_allowance(&self, &sender, &spender, amount),136			<CommonWeights<T>>::approve(),137		)138	}139140	fn transfer_from(141		&self,142		sender: T::CrossAccountId,143		from: T::CrossAccountId,144		to: T::CrossAccountId,145		token: TokenId,146		amount: u128,147	) -> DispatchResultWithPostInfo {148		ensure!(149			token == TokenId::default(),150			<Error<T>>::FungibleItemsHaveNoId151		);152153		with_weight(154			<Pallet<T>>::transfer_from(&self, &sender, &from, &to, amount),155			<CommonWeights<T>>::transfer_from(),156		)157	}158159	fn set_variable_metadata(160		&self,161		_sender: T::CrossAccountId,162		_token: TokenId,163		_data: Vec<u8>,164	) -> DispatchResultWithPostInfo {165		fail!(<Error<T>>::FungibleItemsHaveData)166	}167168	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {169		if <Balance<T>>::get((self.id, account.as_sub())) != 0 {170			vec![TokenId::default()]171		} else {172			vec![]173		}174	}175176	fn token_exists(&self, token: TokenId) -> bool {177		token == TokenId::default()178	}179180	fn last_token_id(&self) -> TokenId {181		TokenId::default()182	}183184	fn token_owner(&self, _token: TokenId) -> T::CrossAccountId {185		T::CrossAccountId::default()186	}187	fn const_metadata(&self, _token: TokenId) -> Vec<u8> {188		Vec::new()189	}190	fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {191		Vec::new()192	}193194	fn collection_tokens(&self) -> u32 {195		1196	}197198	fn account_balance(&self, account: T::CrossAccountId) -> u32 {199		if <Balance<T>>::get((self.id, account.as_sub())) != 0 {200			1201		} else {202			0203		}204	}205206	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {207		if token != TokenId::default() {208			return 0;209		}210		<Balance<T>>::get((self.id, account.as_sub()))211	}212213	fn allowance(214		&self,215		sender: T::CrossAccountId,216		spender: T::CrossAccountId,217		token: TokenId,218	) -> u128 {219		if token != TokenId::default() {220			return 0;221		}222		<Allowance<T>>::get((self.id, sender.as_sub(), spender.as_sub()))223	}224}
after · pallets/fungible/src/common.rs
1use core::marker::PhantomData;23use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight};4use nft_data_structs::TokenId;5use pallet_common::{6	CommonCollectionOperations, CommonWeightInfo, account::CrossAccountId, with_weight,7};8use sp_runtime::ArithmeticError;9use sp_std::{vec::Vec, vec};1011use crate::{12	Allowance, Balance, Config, Error, FungibleHandle, Pallet, SelfWeightOf, weights::WeightInfo,13};1415pub struct CommonWeights<T: Config>(PhantomData<T>);16impl<T: Config> CommonWeightInfo for CommonWeights<T> {17	fn create_item() -> Weight {18		<SelfWeightOf<T>>::create_item()19	}2021	fn create_multiple_items(_amount: u32) -> Weight {22		Self::create_item()23	}2425	fn burn_item() -> Weight {26		<SelfWeightOf<T>>::burn_item()27	}2829	fn transfer() -> Weight {30		<SelfWeightOf<T>>::transfer()31	}3233	fn approve() -> Weight {34		<SelfWeightOf<T>>::approve()35	}3637	fn transfer_from() -> Weight {38		<SelfWeightOf<T>>::transfer_from()39	}4041	fn burn_from() -> Weight {42		043	}4445	fn set_variable_metadata(_bytes: u32) -> Weight {46		// Error47		048	}49}5051impl<T: Config> CommonCollectionOperations<T> for FungibleHandle<T> {52	fn create_item(53		&self,54		sender: T::CrossAccountId,55		to: T::CrossAccountId,56		data: nft_data_structs::CreateItemData,57	) -> DispatchResultWithPostInfo {58		match data {59			nft_data_structs::CreateItemData::Fungible(data) => with_weight(60				<Pallet<T>>::create_item(self, &sender, (to, data.value)),61				<CommonWeights<T>>::create_item(),62			),63			_ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),64		}65	}6667	fn create_multiple_items(68		&self,69		sender: T::CrossAccountId,70		to: T::CrossAccountId,71		data: Vec<nft_data_structs::CreateItemData>,72	) -> DispatchResultWithPostInfo {73		let mut sum: u128 = 0;74		for data in data {75			match data {76				nft_data_structs::CreateItemData::Fungible(data) => {77					sum = sum78						.checked_add(data.value)79						.ok_or(ArithmeticError::Overflow)?;80				}81				_ => fail!(<Error<T>>::NotFungibleDataUsedToMintFungibleCollectionToken),82			}83		}8485		with_weight(86			<Pallet<T>>::create_item(self, &sender, (to, sum)),87			<CommonWeights<T>>::create_item(),88		)89	}9091	fn burn_item(92		&self,93		sender: T::CrossAccountId,94		token: TokenId,95		amount: u128,96	) -> DispatchResultWithPostInfo {97		ensure!(98			token == TokenId::default(),99			<Error<T>>::FungibleItemsHaveNoId100		);101102		with_weight(103			<Pallet<T>>::burn(self, &sender, amount),104			<CommonWeights<T>>::burn_item(),105		)106	}107108	fn transfer(109		&self,110		from: T::CrossAccountId,111		to: T::CrossAccountId,112		token: TokenId,113		amount: u128,114	) -> DispatchResultWithPostInfo {115		ensure!(116			token == TokenId::default(),117			<Error<T>>::FungibleItemsHaveNoId118		);119120		with_weight(121			<Pallet<T>>::transfer(&self, &from, &to, amount),122			<CommonWeights<T>>::transfer(),123		)124	}125126	fn approve(127		&self,128		sender: T::CrossAccountId,129		spender: T::CrossAccountId,130		token: TokenId,131		amount: u128,132	) -> DispatchResultWithPostInfo {133		ensure!(134			token == TokenId::default(),135			<Error<T>>::FungibleItemsHaveNoId136		);137138		with_weight(139			<Pallet<T>>::set_allowance(&self, &sender, &spender, amount),140			<CommonWeights<T>>::approve(),141		)142	}143144	fn transfer_from(145		&self,146		sender: T::CrossAccountId,147		from: T::CrossAccountId,148		to: T::CrossAccountId,149		token: TokenId,150		amount: u128,151	) -> DispatchResultWithPostInfo {152		ensure!(153			token == TokenId::default(),154			<Error<T>>::FungibleItemsHaveNoId155		);156157		with_weight(158			<Pallet<T>>::transfer_from(&self, &sender, &from, &to, amount),159			<CommonWeights<T>>::transfer_from(),160		)161	}162163	fn burn_from(164		&self,165		sender: T::CrossAccountId,166		from: T::CrossAccountId,167		token: TokenId,168		amount: u128,169	) -> DispatchResultWithPostInfo {170		ensure!(171			token == TokenId::default(),172			<Error<T>>::FungibleItemsHaveNoId173		);174175		with_weight(176			<Pallet<T>>::burn_from(&self, &sender, &from, amount),177			<CommonWeights<T>>::burn_from(),178		)179	}180181	fn set_variable_metadata(182		&self,183		_sender: T::CrossAccountId,184		_token: TokenId,185		_data: Vec<u8>,186	) -> DispatchResultWithPostInfo {187		fail!(<Error<T>>::FungibleItemsHaveData)188	}189190	fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId> {191		if <Balance<T>>::get((self.id, account.as_sub())) != 0 {192			vec![TokenId::default()]193		} else {194			vec![]195		}196	}197198	fn token_exists(&self, token: TokenId) -> bool {199		token == TokenId::default()200	}201202	fn last_token_id(&self) -> TokenId {203		TokenId::default()204	}205206	fn token_owner(&self, _token: TokenId) -> T::CrossAccountId {207		T::CrossAccountId::default()208	}209	fn const_metadata(&self, _token: TokenId) -> Vec<u8> {210		Vec::new()211	}212	fn variable_metadata(&self, _token: TokenId) -> Vec<u8> {213		Vec::new()214	}215216	fn collection_tokens(&self) -> u32 {217		1218	}219220	fn account_balance(&self, account: T::CrossAccountId) -> u32 {221		if <Balance<T>>::get((self.id, account.as_sub())) != 0 {222			1223		} else {224			0225		}226	}227228	fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128 {229		if token != TokenId::default() {230			return 0;231		}232		<Balance<T>>::get((self.id, account.as_sub()))233	}234235	fn allowance(236		&self,237		sender: T::CrossAccountId,238		spender: T::CrossAccountId,239		token: TokenId,240	) -> u128 {241		if token != TokenId::default() {242			return 0;243		}244		<Allowance<T>>::get((self.id, sender.as_sub(), spender.as_sub()))245	}246}
modifiedpallets/fungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/fungible/src/erc.rs
+++ b/pallets/fungible/src/erc.rs
@@ -96,6 +96,18 @@
 	}
 }
 
+#[solidity_interface(name = "ERC20UniqueExtensions")]
+impl<T: Config> FungibleHandle<T> {
+	fn burn_from(&mut self, caller: caller, from: address, amount: uint256) -> Result<bool> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let amount = amount.try_into().map_err(|_| "amount overflow")?;
+
+		<Pallet<T>>::burn_from(self, &caller, &from, amount).map_err(dispatch_to_evm::<T>)?;
+		Ok(true)
+	}
+}
+
 #[solidity_interface(name = "UniqueFungible", is(ERC20))]
 impl<T: Config> FungibleHandle<T> {}
 
modifiedpallets/fungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -356,6 +356,38 @@
 		Ok(())
 	}
 
+	pub fn burn_from(
+		collection: &FungibleHandle<T>,
+		spender: &T::CrossAccountId,
+		from: &T::CrossAccountId,
+		amount: u128,
+	) -> DispatchResult {
+		if spender == from {
+			return Self::burn(collection, from, amount);
+		}
+		if collection.access == AccessMode::WhiteList {
+			// `from` checked in [`burn`]
+			collection.check_allowlist(spender)?;
+		}
+
+		let allowance = <Allowance<T>>::get((collection.id, from.as_sub(), spender.as_sub()))
+			.checked_sub(amount);
+		if allowance.is_none() {
+			ensure!(
+				collection.ignores_allowance(spender)?,
+				<CommonError<T>>::TokenValueNotEnough
+			);
+		}
+
+		// =========
+
+		Self::burn(collection, from, amount)?;
+		if let Some(allowance) = allowance {
+			Self::set_allowance_unchecked(collection, from, spender, allowance);
+		}
+		Ok(())
+	}
+
 	/// Delegated to `create_multiple_items`
 	pub fn create_item(
 		collection: &FungibleHandle<T>,
modifiedpallets/nft/src/common.rsdiffbeforeafterboth
--- a/pallets/nft/src/common.rs
+++ b/pallets/nft/src/common.rs
@@ -45,4 +45,8 @@
 	fn set_variable_metadata(bytes: u32) -> nft_data_structs::Weight {
 		dispatch_weight::<T>() + max_weight_of!(set_variable_metadata(bytes))
 	}
+
+	fn burn_from() -> Weight {
+		dispatch_weight::<T>() + max_weight_of!(burn_from())
+	}
 }
modifiedpallets/nft/src/eth/sponsoring.rsdiffbeforeafterboth
--- a/pallets/nft/src/eth/sponsoring.rs
+++ b/pallets/nft/src/eth/sponsoring.rs
@@ -35,9 +35,10 @@
 				.map_err(|_| AnyError)?
 				.ok_or(AnyError)?;
 			match call {
-				UniqueNFTCall::ERC721UniqueExtensions(
-					ERC721UniqueExtensionsCall::TransferNft { token_id, .. },
-				)
+				UniqueNFTCall::ERC721UniqueExtensions(ERC721UniqueExtensionsCall::Transfer {
+					token_id,
+					..
+				})
 				| UniqueNFTCall::ERC721(ERC721Call::TransferFrom { token_id, .. }) => {
 					let token_id: u32 = token_id.try_into().map_err(|_| AnyError)?;
 					let block_number = <frame_system::Pallet<T>>::block_number() as T::BlockNumber;
modifiedpallets/nft/src/lib.rsdiffbeforeafterboth
--- a/pallets/nft/src/lib.rs
+++ b/pallets/nft/src/lib.rs
@@ -623,14 +623,13 @@
 		/// * item_id: ID of NFT to burn.
 		///
 		/// * from: owner of item
-		// #[weight = 0]
-		// #[transactional]
-		// pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> PostDispatchInfo {
-		// 	let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
+		#[weight = <CommonWeights<T>>::burn_from()]
+		#[transactional]
+		pub fn burn_from(origin, collection_id: CollectionId, from: T::CrossAccountId, item_id: TokenId, value: u128) -> DispatchResultWithPostInfo {
+			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
 
-		// 	// dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))
-		// 	todo!()
-		// }
+			dispatch_call::<T, _>(collection_id, |d| d.burn_from(sender, from, item_id, value))
+		}
 
 		/// Change ownership of the token.
 		///
modifiedpallets/nonfungible/src/common.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/common.rs
+++ b/pallets/nonfungible/src/common.rs
@@ -39,6 +39,10 @@
 		<SelfWeightOf<T>>::transfer_from()
 	}
 
+	fn burn_from() -> Weight {
+		0
+	}
+
 	fn set_variable_metadata(bytes: u32) -> Weight {
 		<SelfWeightOf<T>>::set_variable_metadata(bytes)
 	}
@@ -163,6 +167,25 @@
 		}
 	}
 
+	fn burn_from(
+		&self,
+		sender: T::CrossAccountId,
+		from: T::CrossAccountId,
+		token: TokenId,
+		amount: u128,
+	) -> DispatchResultWithPostInfo {
+		ensure!(amount <= 1, <Error<T>>::NonfungibleItemsHaveNoAmount);
+
+		if amount == 1 {
+			with_weight(
+				<Pallet<T>>::burn_from(&self, &sender, &from, token),
+				<CommonWeights<T>>::burn_from(),
+			)
+		} else {
+			Ok(().into())
+		}
+	}
+
 	fn set_variable_metadata(
 		&self,
 		sender: T::CrossAccountId,
modifiedpallets/nonfungible/src/erc.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/erc.rs
+++ b/pallets/nonfungible/src/erc.rs
@@ -264,8 +264,7 @@
 
 #[solidity_interface(name = "ERC721UniqueExtensions")]
 impl<T: Config> NonfungibleHandle<T> {
-	#[solidity(rename_selector = "transfer")]
-	fn transfer_nft(
+	fn transfer(
 		&mut self,
 		caller: caller,
 		to: address,
@@ -280,6 +279,21 @@
 		Ok(())
 	}
 
+	fn burn_from(
+		&mut self,
+		caller: caller,
+		from: address,
+		token_id: uint256,
+		_value: value,
+	) -> Result<void> {
+		let caller = T::CrossAccountId::from_eth(caller);
+		let from = T::CrossAccountId::from_eth(from);
+		let token = token_id.try_into()?;
+
+		<Pallet<T>>::burn_from(self, &caller, &from, token).map_err(dispatch_to_evm::<T>)?;
+		Ok(())
+	}
+
 	fn next_token_id(&self) -> Result<uint256> {
 		Ok(<TokensMinted<T>>::get(self.id)
 			.checked_add(1)
modifiedpallets/nonfungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -499,6 +499,32 @@
 		Ok(())
 	}
 
+	pub fn burn_from(
+		collection: &NonfungibleHandle<T>,
+		spender: &T::CrossAccountId,
+		from: &T::CrossAccountId,
+		token: TokenId,
+	) -> DispatchResult {
+		if spender == from {
+			return Self::burn(collection, from, token);
+		}
+		if collection.access == AccessMode::WhiteList {
+			// `from` checked in [`burn`]
+			collection.check_allowlist(spender)?;
+		}
+
+		if <Allowance<T>>::get((collection.id, token)).as_ref() != Some(spender) {
+			ensure!(
+				collection.ignores_allowance(spender)?,
+				<CommonError<T>>::TokenValueNotEnough
+			);
+		}
+
+		// =========
+
+		Self::burn(collection, &from, token)
+	}
+
 	pub fn set_variable_metadata(
 		collection: &NonfungibleHandle<T>,
 		sender: &T::CrossAccountId,
modifiedpallets/refungible/src/common.rsdiffbeforeafterboth
--- a/pallets/refungible/src/common.rs
+++ b/pallets/refungible/src/common.rs
@@ -59,6 +59,10 @@
 		)
 	}
 
+	fn burn_from() -> Weight {
+		0
+	}
+
 	fn set_variable_metadata(bytes: u32) -> Weight {
 		<SelfWeightOf<T>>::set_variable_metadata(bytes)
 	}
@@ -161,7 +165,20 @@
 	) -> DispatchResultWithPostInfo {
 		with_weight(
 			<Pallet<T>>::transfer_from(&self, &sender, &from, &to, token, amount),
-			<CommonWeights<T>>::approve(),
+			<CommonWeights<T>>::transfer_from(),
+		)
+	}
+
+	fn burn_from(
+		&self,
+		sender: T::CrossAccountId,
+		from: T::CrossAccountId,
+		token: TokenId,
+		amount: u128,
+	) -> DispatchResultWithPostInfo {
+		with_weight(
+			<Pallet<T>>::burn_from(&self, &sender, &from, token, amount),
+			<CommonWeights<T>>::burn_from(),
 		)
 	}
 
modifiedpallets/refungible/src/lib.rsdiffbeforeafterboth
--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -537,6 +537,39 @@
 		Ok(())
 	}
 
+	pub fn burn_from(
+		collection: &RefungibleHandle<T>,
+		spender: &T::CrossAccountId,
+		from: &T::CrossAccountId,
+		token: TokenId,
+		amount: u128,
+	) -> DispatchResult {
+		if spender == from {
+			return Self::burn(collection, from, token, amount);
+		}
+		if collection.access == AccessMode::WhiteList {
+			// `from` checked in [`burn`]
+			collection.check_allowlist(spender)?;
+		}
+
+		let allowance = <Allowance<T>>::get((collection.id, token, from.as_sub(), &spender))
+			.checked_sub(amount);
+		if allowance.is_none() {
+			ensure!(
+				collection.ignores_allowance(spender)?,
+				<CommonError<T>>::TokenValueNotEnough
+			);
+		}
+
+		// =========
+
+		Self::burn(collection, from, token, amount)?;
+		if let Some(allowance) = allowance {
+			Self::set_allowance_unchecked(collection, from, spender, token, allowance);
+		}
+		Ok(())
+	}
+
 	pub fn set_variable_metadata(
 		collection: &RefungibleHandle<T>,
 		sender: &T::CrossAccountId,