difftreelog
fix disallow nesting under non-existing tokens
in: master
3 files changed
pallets/nonfungible/src/lib.rsdiffbeforeafterboth1332 let permissive = nesting.permissive;1332 let permissive = nesting.permissive;133313331334 if permissive {1334 if permissive {1335 // Pass1335 ensure!(1336 <TokenData<T>>::contains_key((handle.id, under)),1337 <CommonError<T>>::TokenNotFound1338 );1336 } else if nesting.token_owner1339 } else if nesting.token_owner1337 && <PalletStructure<T>>::check_indirectly_owned(1340 && <PalletStructure<T>>::check_indirectly_owned(1338 sender.clone(),1341 sender.clone(),1341 Some(from),1344 Some(from),1342 nesting_budget,1345 nesting_budget,1343 )? {1346 )? {1344 // Pass1347 // Pass, token existence is checked in `check_indirectly_owned`1345 } else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {1348 } else if nesting.collection_admin && handle.is_owner_or_admin(&sender) {1346 // Pass1349 ensure!(1350 <TokenData<T>>::contains_key((handle.id, under)),1351 <CommonError<T>>::TokenNotFound1352 );1347 } else {1353 } else {1348 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1354 fail!(<CommonError<T>>::UserIsNotAllowedToNest);1349 }1355 }pallets/structure/Cargo.tomldiffbeforeafterboth--- a/pallets/structure/Cargo.toml
+++ b/pallets/structure/Cargo.toml
@@ -17,19 +17,10 @@
] }
up-data-structs = { path = "../../primitives/data-structs", default-features = false }
pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }
+log = { version = "0.4.17", default-features = false }
[features]
default = ["std"]
-std = [
- "frame-support/std",
- "frame-system/std",
- "frame-benchmarking/std",
- "sp-std/std",
- "pallet-common/std",
- "scale-info/std",
- "parity-scale-codec/std",
- "up-data-structs/std",
- "pallet-evm/std",
-]
+std = ["frame-support/std", "frame-system/std", "frame-benchmarking/std", "sp-std/std", "pallet-common/std", "scale-info/std", "parity-scale-codec/std", "up-data-structs/std", "pallet-evm/std"]
runtime-benchmarks = ['frame-benchmarking', 'pallet-common/runtime-benchmarks']
try-runtime = ["frame-support/try-runtime"]
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -54,6 +54,7 @@
#![cfg_attr(not(feature = "std"), no_std)]
use pallet_common::CommonCollectionOperations;
+use pallet_common::{erc::CrossAccountId, eth::is_collection};
use sp_std::collections::btree_set::BTreeSet;
use frame_support::dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo};
@@ -86,6 +87,8 @@
BreadthLimit,
/// Couldn't find the token owner that is itself a token.
TokenNotFound,
+ /// Tried to nest token under collection contract address, instead of token address
+ CantNestTokenUnderCollection,
}
#[pallet::event]
@@ -302,7 +305,7 @@
token_id: TokenId,
nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {
+ Self::try_exec_if_token(under, |collection, parent_id| {
collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)
})
}
@@ -319,7 +322,7 @@
token_id: TokenId,
nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {
+ Self::try_exec_if_token(under, |collection, parent_id| {
collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;
collection.nest(parent_id, (collection_id, token_id));
@@ -336,7 +339,7 @@
collection_id: CollectionId,
token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {
+ Self::exec_if_token(owner, |collection, parent_id| {
collection.nest(parent_id, (collection_id, token_id))
});
}
@@ -347,45 +350,45 @@
collection_id: CollectionId,
token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {
- collection.unnest(parent_id, (collection_id, token_id))
- });
+ if let Err(e) = Self::try_exec_if_token(owner, |collection, parent_id| {
+ collection.unnest(parent_id, (collection_id, token_id));
+ Ok(())
+ }) {
+ log::warn!("unnest precondition failed: {e:?}")
+ }
}
- fn exec_if_owner_is_valid_nft(
+ /// # Panics
+ /// If [`Self::try_exec_if_token`] fails
+ fn exec_if_token(
account: &T::CrossAccountId,
action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId),
) {
- Self::try_exec_if_owner_is_valid_nft(account, |collection, id| {
+ Self::try_exec_if_token(account, |collection, id| {
action(collection, id);
Ok(())
})
.unwrap();
}
- fn try_exec_if_owner_is_valid_nft(
+ /// If `account` is a token address, execute `action` providing found collection as an argument
+ /// Token may not exist, it is expected it will be checked in the callback.
+ fn try_exec_if_token(
account: &T::CrossAccountId,
action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult,
) -> DispatchResult {
- let account = T::CrossTokenAddressMapping::address_to_token(account);
-
- if account.is_none() {
- return Ok(());
+ if is_collection(&account.as_eth()) {
+ fail!(<Error<T>>::CantNestTokenUnderCollection);
}
+ let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account) else {
+ return Ok(())
+ };
- let account = account.unwrap();
-
- let handle = <CollectionHandle<T>>::try_get(account.0);
-
- if handle.is_err() {
- return Ok(());
- }
-
- let handle = handle.unwrap();
+ let handle = <CollectionHandle<T>>::try_get(collection)?;
let dispatch = T::CollectionDispatch::dispatch(handle);
let dispatch = dispatch.as_dyn();
- action(dispatch, account.1)
+ action(dispatch, token)
}
}