From 017086424d43bcc9e6f9f8b9aa952ea448f21afc Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Mon, 16 Jan 2023 11:15:43 +0000 Subject: [PATCH] fix: owner/admin ignores token restrictions --- --- 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) } --- 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!( >::check_indirectly_owned( spender.clone(), @@ -690,18 +696,25 @@ >::ApprovedValueTooLow, ); return Ok(None); - } - let allowance = >::get((collection.id, from, spender)).checked_sub(amount); - if allowance.is_none() { - ensure!( - collection.ignores_allowance(spender), - >::ApprovedValueTooLow - ); } + let allowance = Self::compute_allowance_decrease(collection, from, spender, amount); + ensure!(allowance.is_some(), >::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, + from: &T::CrossAccountId, + spender: &T::CrossAccountId, + amount: u128, + ) -> Option { + >::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. --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -1246,7 +1246,7 @@ collection.check_allowlist(spender)?; } - if collection.limits.owner_can_transfer() && collection.is_owner_or_admin(spender) { + if collection.ignores_token_restrictions(spender) { return Ok(()); } @@ -1269,11 +1269,8 @@ if >::get((collection.id, from, spender)) { return Ok(()); } - ensure!( - collection.ignores_allowance(spender), - >::ApprovedValueTooLow - ); - Ok(()) + + Err(>::ApprovedValueTooLow.into()) } /// Transfer NFT token from one account to another. --- 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 = - >::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 >::get((collection.id, from, spender)) { return Ok(allowance); } - if allowance.is_none() { - ensure!( - collection.ignores_allowance(spender), - >::ApprovedValueTooLow - ); - } - Ok(allowance) + Err(>::ApprovedValueTooLow.into()) + } + + /// Returns `Some(amount)` if the `spender` have allowance to spend this amount. + /// Otherwise, it returns `None`. + fn compute_allowance_decrease( + collection: &RefungibleHandle, + token: TokenId, + from: &T::CrossAccountId, + spender: &T::CrossAccountId, + amount: u128, + ) -> Option { + >::get((collection.id, token, from, spender)).checked_sub(amount) } /// Transfer RFT token pieces from one account to another. -- gitstuff