difftreelog
fix owner/admin ignores token restrictions
in: master
4 files changed
pallets/common/src/lib.rsdiffbeforeafterboth--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -390,8 +390,10 @@
Ok(())
}
- /// Return **true** if `user` was not allowed to have tokens, and he can ignore such restrictions.
- pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {
+ /// Returns **true** if
+ /// * the `user`is a collection owner or admin
+ /// * the collection limits allow the owner/admins to transfer/burn any collection token
+ pub fn ignores_token_restrictions(&self, user: &T::CrossAccountId) -> bool {
self.limits.owner_can_transfer() && self.is_owner_or_admin(user)
}
pallets/fungible/src/lib.rsdiffbeforeafterboth--- a/pallets/fungible/src/lib.rs
+++ b/pallets/fungible/src/lib.rs
@@ -677,8 +677,14 @@
// `from`, `to` checked in [`transfer`]
collection.check_allowlist(spender)?;
}
+
+ if collection.ignores_token_restrictions(spender) {
+ return Ok(Self::compute_allowance_decrease(
+ collection, from, spender, amount,
+ ));
+ }
+
if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {
- // TODO: should collection owner be allowed to perform this transfer?
ensure!(
<PalletStructure<T>>::check_indirectly_owned(
spender.clone(),
@@ -690,18 +696,25 @@
<CommonError<T>>::ApprovedValueTooLow,
);
return Ok(None);
- }
- let allowance = <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount);
- if allowance.is_none() {
- ensure!(
- collection.ignores_allowance(spender),
- <CommonError<T>>::ApprovedValueTooLow
- );
}
+ let allowance = Self::compute_allowance_decrease(collection, from, spender, amount);
+ ensure!(allowance.is_some(), <CommonError<T>>::ApprovedValueTooLow);
+
Ok(allowance)
}
+ /// Returns `Some(amount)` if the `spender` have allowance to spend this amount.
+ /// Otherwise, it returns `None`.
+ fn compute_allowance_decrease(
+ collection: &FungibleHandle<T>,
+ from: &T::CrossAccountId,
+ spender: &T::CrossAccountId,
+ amount: u128,
+ ) -> Option<u128> {
+ <Allowance<T>>::get((collection.id, from, spender)).checked_sub(amount)
+ }
+
/// Transfer fungible tokens from one account to another.
/// Same as the [`transfer`][`Pallet::transfer`] but spender doesn't needs to be an owner of the token pieces.
/// The owner should set allowance for the spender to transfer pieces.
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1246 collection.check_allowlist(spender)?;1246 collection.check_allowlist(spender)?;1247 }1247 }124812481249 if collection.limits.owner_can_transfer() && collection.is_owner_or_admin(spender) {1249 if collection.ignores_token_restrictions(spender) {1250 return Ok(());1250 return Ok(());1251 }1251 }125212521269 if <CollectionAllowance<T>>::get((collection.id, from, spender)) {1269 if <CollectionAllowance<T>>::get((collection.id, from, spender)) {1270 return Ok(());1270 return Ok(());1271 }1271 }1272 ensure!(12721273 collection.ignores_allowance(spender),1274 <CommonError<T>>::ApprovedValueTooLow1273 Err(<CommonError<T>>::ApprovedValueTooLow.into())1275 );1276 Ok(())1277 }1274 }127812751279 /// Transfer NFT token from one account to another.1276 /// Transfer NFT token from one account to another.pallets/refungible/src/lib.rsdiffbeforeafterboth--- a/pallets/refungible/src/lib.rs
+++ b/pallets/refungible/src/lib.rs
@@ -1178,8 +1178,10 @@
collection.check_allowlist(spender)?;
}
- if collection.limits.owner_can_transfer() && collection.is_owner_or_admin(spender) {
- return Ok(None);
+ if collection.ignores_token_restrictions(spender) {
+ return Ok(Self::compute_allowance_decrease(
+ collection, token, from, &spender, amount,
+ ));
}
if let Some(source) = T::CrossTokenAddressMapping::address_to_token(from) {
@@ -1196,21 +1198,30 @@
);
return Ok(None);
}
- let allowance =
- <Allowance<T>>::get((collection.id, token, from, &spender)).checked_sub(amount);
+ let allowance = Self::compute_allowance_decrease(collection, token, from, &spender, amount);
+ if allowance.is_some() {
+ return Ok(allowance);
+ }
+
// Allowance (if any) would be reduced if spender is also wallet operator
if <CollectionAllowance<T>>::get((collection.id, from, spender)) {
return Ok(allowance);
}
- if allowance.is_none() {
- ensure!(
- collection.ignores_allowance(spender),
- <CommonError<T>>::ApprovedValueTooLow
- );
- }
- Ok(allowance)
+ Err(<CommonError<T>>::ApprovedValueTooLow.into())
+ }
+
+ /// Returns `Some(amount)` if the `spender` have allowance to spend this amount.
+ /// Otherwise, it returns `None`.
+ fn compute_allowance_decrease(
+ collection: &RefungibleHandle<T>,
+ token: TokenId,
+ from: &T::CrossAccountId,
+ spender: &T::CrossAccountId,
+ amount: u128,
+ ) -> Option<u128> {
+ <Allowance<T>>::get((collection.id, token, from, spender)).checked_sub(amount)
}
/// Transfer RFT token pieces from one account to another.