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.tomldiffbeforeafterboth17] }17] }18up-data-structs = { path = "../../primitives/data-structs", default-features = false }18up-data-structs = { path = "../../primitives/data-structs", default-features = false }19pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }19pallet-evm = { default-features = false, git = "https://github.com/uniquenetwork/frontier", branch = "unique-polkadot-v0.9.36" }20log = { version = "0.4.17", default-features = false }202121[features]22[features]22default = ["std"]23default = ["std"]pallets/structure/src/lib.rsdiffbeforeafterboth54#![cfg_attr(not(feature = "std"), no_std)]54#![cfg_attr(not(feature = "std"), no_std)]555556use pallet_common::CommonCollectionOperations;56use pallet_common::CommonCollectionOperations;57use pallet_common::{erc::CrossAccountId, eth::is_collection};57use sp_std::collections::btree_set::BTreeSet;58use sp_std::collections::btree_set::BTreeSet;585959use frame_support::dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo};60use frame_support::dispatch::{DispatchError, DispatchResult, DispatchResultWithPostInfo};86 BreadthLimit,87 BreadthLimit,87 /// Couldn't find the token owner that is itself a token.88 /// Couldn't find the token owner that is itself a token.88 TokenNotFound,89 TokenNotFound,90 /// Tried to nest token under collection contract address, instead of token address91 CantNestTokenUnderCollection,89 }92 }909391 #[pallet::event]94 #[pallet::event]302 token_id: TokenId,305 token_id: TokenId,303 nesting_budget: &dyn Budget,306 nesting_budget: &dyn Budget,304 ) -> DispatchResult {307 ) -> DispatchResult {305 Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {308 Self::try_exec_if_token(under, |collection, parent_id| {306 collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)309 collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)307 })310 })308 }311 }319 token_id: TokenId,322 token_id: TokenId,320 nesting_budget: &dyn Budget,323 nesting_budget: &dyn Budget,321 ) -> DispatchResult {324 ) -> DispatchResult {322 Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {325 Self::try_exec_if_token(under, |collection, parent_id| {323 collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;326 collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;324327325 collection.nest(parent_id, (collection_id, token_id));328 collection.nest(parent_id, (collection_id, token_id));336 collection_id: CollectionId,339 collection_id: CollectionId,337 token_id: TokenId,340 token_id: TokenId,338 ) {341 ) {339 Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {342 Self::exec_if_token(owner, |collection, parent_id| {340 collection.nest(parent_id, (collection_id, token_id))343 collection.nest(parent_id, (collection_id, token_id))341 });344 });342 }345 }347 collection_id: CollectionId,350 collection_id: CollectionId,348 token_id: TokenId,351 token_id: TokenId,349 ) {352 ) {350 Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {353 if let Err(e) = Self::try_exec_if_token(owner, |collection, parent_id| {351 collection.unnest(parent_id, (collection_id, token_id))354 collection.unnest(parent_id, (collection_id, token_id));355 Ok(())352 });356 }) {357 log::warn!("unnest precondition failed: {e:?}")358 }353 }359 }354360361 /// # Panics362 /// If [`Self::try_exec_if_token`] fails355 fn exec_if_owner_is_valid_nft(363 fn exec_if_token(356 account: &T::CrossAccountId,364 account: &T::CrossAccountId,357 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId),365 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId),358 ) {366 ) {359 Self::try_exec_if_owner_is_valid_nft(account, |collection, id| {367 Self::try_exec_if_token(account, |collection, id| {360 action(collection, id);368 action(collection, id);361 Ok(())369 Ok(())362 })370 })363 .unwrap();371 .unwrap();364 }372 }365373374 /// If `account` is a token address, execute `action` providing found collection as an argument375 /// Token may not exist, it is expected it will be checked in the callback.366 fn try_exec_if_owner_is_valid_nft(376 fn try_exec_if_token(367 account: &T::CrossAccountId,377 account: &T::CrossAccountId,368 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult,378 action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId) -> DispatchResult,369 ) -> DispatchResult {379 ) -> DispatchResult {380 if is_collection(&account.as_eth()) {381 fail!(<Error<T>>::CantNestTokenUnderCollection);382 }370 let account = T::CrossTokenAddressMapping::address_to_token(account);383 let Some((collection, token)) = T::CrossTokenAddressMapping::address_to_token(account) else {371372 if account.is_none() {373 return Ok(());384 return Ok(())374 }385 };375376 let account = account.unwrap();377386378 let handle = <CollectionHandle<T>>::try_get(account.0);387 let handle = <CollectionHandle<T>>::try_get(collection)?;379380 if handle.is_err() {381 return Ok(());382 }383384 let handle = handle.unwrap();385388386 let dispatch = T::CollectionDispatch::dispatch(handle);389 let dispatch = T::CollectionDispatch::dispatch(handle);387 let dispatch = dispatch.as_dyn();390 let dispatch = dispatch.as_dyn();388391389 action(dispatch, account.1)392 action(dispatch, token)390 }393 }391}394}392395