From 98013fc81aa8c5657a954dc1956796f2a3947ca6 Mon Sep 17 00:00:00 2001 From: Yaroslav Bolyukin Date: Thu, 07 Apr 2022 10:14:54 +0000 Subject: [PATCH] feat: check nesting rule --- --- a/pallets/common/src/eth.rs +++ b/pallets/common/src/eth.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Unique Network. If not, see . -use up_data_structs::{CollectionId, TokenId}; +use up_data_structs::CollectionId; use sp_core::H160; // 0x17c4e6453Cc49AAAaEACA894e6D9683e00000001 - collection 1 --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -345,6 +345,13 @@ /// Not sufficient founds to perform action NotSufficientFounds, + + /// Collection has nesting disabled + NestingIsDisabled, + /// Only owner may nest tokens under this collection + OnlyOwnerAllowedToNest, + /// Only tokens from specific collections may nest tokens under this + SourceCollectionIsNotAllowedToNest, } #[pallet::storage] @@ -400,8 +407,6 @@ #[pallet::hooks] impl Hooks> for Pallet { fn on_runtime_upgrade() -> Weight { - let mut weight = 0; - if StorageVersion::get::>() < StorageVersion::new(1) { use up_data_structs::{CollectionVersion1, CollectionVersion2}; >::translate_values::, _>(|v| { @@ -409,7 +414,7 @@ }); } - weight + 0 } } } @@ -774,6 +779,13 @@ data: BoundedVec, ) -> DispatchResultWithPostInfo; + fn nest_token( + &self, + sender: T::CrossAccountId, + from: (CollectionId, TokenId), + under: TokenId, + ) -> DispatchResult; + fn account_tokens(&self, account: T::CrossAccountId) -> Vec; fn token_exists(&self, token: TokenId) -> bool; fn last_token_id(&self) -> TokenId; --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -228,6 +228,15 @@ fail!(>::FungibleItemsDontHaveData) } + fn nest_token( + &self, + _sender: ::CrossAccountId, + _from: (up_data_structs::CollectionId, TokenId), + _under: TokenId, + ) -> sp_runtime::DispatchResult { + fail!(>::FungibleDisallowsNesting) + } + fn account_tokens(&self, account: T::CrossAccountId) -> Vec { if >::get((self.id, account)) != 0 { vec![TokenId::default()] --- a/pallets/fungible/src/lib.rs +++ b/pallets/fungible/src/lib.rs @@ -18,9 +18,14 @@ use core::ops::Deref; use frame_support::{ensure}; -use up_data_structs::{AccessMode, CollectionId, TokenId, CreateCollectionData}; -use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon}; use pallet_evm::account::CrossAccountId; +use up_data_structs::{ + AccessMode, CollectionId, TokenId, CreateCollectionData, mapping::TokenAddressMapping, +}; +use pallet_common::{ + Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, + CollectionHandle, dispatch::CollectionDispatch, +}; use pallet_evm_coder_substrate::WithRecorder; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; @@ -52,6 +57,8 @@ FungibleItemsHaveNoId, /// Tried to set data for fungible item FungibleItemsDontHaveData, + /// Fungible token does not support nested + FungibleDisallowsNesting, } #[pallet::config] @@ -207,7 +214,15 @@ None }; - // ========= + if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) { + let handle = >::try_get(target.0)?; + let dispatch = T::CollectionDispatch::dispatch(handle); + let dispatch = dispatch.as_dyn(); + + // ========= + + dispatch.nest_token(from.clone(), (collection.id, TokenId::default()), target.1)?; + } if let Some(balance_to) = balance_to { // from != to --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -17,7 +17,7 @@ use core::marker::PhantomData; use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight, BoundedVec}; -use up_data_structs::{TokenId, CustomDataLimit, CreateItemExData}; +use up_data_structs::{TokenId, CustomDataLimit, CreateItemExData, CollectionId}; use pallet_common::{CommonCollectionOperations, CommonWeightInfo, with_weight}; use sp_runtime::DispatchError; use sp_std::vec::Vec; @@ -237,6 +237,15 @@ ) } + fn nest_token( + &self, + sender: T::CrossAccountId, + (from, _): (CollectionId, TokenId), + under: TokenId, + ) -> sp_runtime::DispatchResult { + >::nest_token(self, sender, from, under) + } + fn account_tokens(&self, account: T::CrossAccountId) -> Vec { >::iter_prefix((self.id, account)) .map(|(id, _)| id) --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -17,12 +17,16 @@ #![cfg_attr(not(feature = "std"), no_std)] use erc::ERC721Events; -use frame_support::{BoundedVec, ensure}; +use frame_support::{BoundedVec, ensure, fail}; use up_data_structs::{ AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData, + mapping::TokenAddressMapping, NestingRule, }; -use pallet_common::{Error as CommonError, Pallet as PalletCommon, Event as CommonEvent}; use pallet_evm::account::CrossAccountId; +use pallet_common::{ + Error as CommonError, Pallet as PalletCommon, Event as CommonEvent, + CollectionHandle, dispatch::CollectionDispatch, +}; use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; use sp_core::H160; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; @@ -282,8 +286,16 @@ None }; - // ========= + if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) { + let handle = >::try_get(target.0)?; + let dispatch = T::CollectionDispatch::dispatch(handle); + let dispatch = dispatch.as_dyn(); + + // ========= + dispatch.nest_token(from.clone(), (collection.id, token), target.1)?; + } + >::insert( (collection.id, token), ItemData { @@ -567,6 +579,40 @@ Ok(()) } + pub fn nest_token( + handle: &NonfungibleHandle, + sender: T::CrossAccountId, + from: CollectionId, + under: TokenId, + ) -> DispatchResult { + fn ensure_sender_allowed( + collection: CollectionId, + token: TokenId, + sender: T::CrossAccountId, + ) -> DispatchResult { + ensure!( + >::get((collection, token)) + .ok_or(>::TokenNotFound)? + .owner + .conv_eq(&sender), + >::OnlyOwnerAllowedToNest, + ); + Ok(()) + } + match handle.limits.nesting_rule() { + NestingRule::Disabled => fail!(>::NestingIsDisabled), + NestingRule::Owner => ensure_sender_allowed::(from, under, sender)?, + NestingRule::OwnerRestricted(whitelist) => { + ensure!( + whitelist.contains(&from), + >::SourceCollectionIsNotAllowedToNest + ); + ensure_sender_allowed::(from, under, sender)? + } + } + Ok(()) + } + /// Delegated to `create_multiple_items` pub fn create_item( collection: &NonfungibleHandle, --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -243,6 +243,15 @@ ) } + fn nest_token( + &self, + _sender: ::CrossAccountId, + _from: (up_data_structs::CollectionId, TokenId), + _under: TokenId, + ) -> sp_runtime::DispatchResult { + fail!(>::RefungibleDisallowsNesting) + } + fn account_tokens(&self, account: T::CrossAccountId) -> Vec { >::iter_prefix((self.id, account)) .map(|(id, _)| id) --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -19,10 +19,13 @@ use frame_support::{ensure, BoundedVec}; use up_data_structs::{ AccessMode, CollectionId, CustomDataLimit, MAX_REFUNGIBLE_PIECES, TokenId, - CreateCollectionData, CreateRefungibleExData, + CreateCollectionData, CreateRefungibleExData, mapping::TokenAddressMapping, }; -use pallet_common::{Error as CommonError, Event as CommonEvent, Pallet as PalletCommon}; use pallet_evm::account::CrossAccountId; +use pallet_common::{ + Error as CommonError, Event as CommonEvent, Pallet as PalletCommon, + CollectionHandle, dispatch::CollectionDispatch, +}; use sp_runtime::{ArithmeticError, DispatchError, DispatchResult}; use sp_std::{vec::Vec, vec, collections::btree_map::BTreeMap}; use core::ops::Deref; @@ -56,6 +59,8 @@ NotRefungibleDataUsedToMintFungibleCollectionToken, /// Maximum refungibility exceeded WrongRefungiblePieces, + /// Refungible token can't nest other tokens + RefungibleDisallowsNesting, } #[pallet::config] @@ -338,7 +343,15 @@ None }; - // ========= + if let Some(target) = T::CrossTokenAddressMapping::address_to_token(to) { + let handle = >::try_get(target.0)?; + let dispatch = T::CollectionDispatch::dispatch(handle); + let dispatch = dispatch.as_dyn(); + + // ========= + + dispatch.nest_token(from.clone(), (collection.id, token), target.1)?; + } if let Some(balance_to) = balance_to { // from != to --- /dev/null +++ b/primitives/data-structs/src/bounded.rs @@ -0,0 +1,138 @@ +use core::fmt; +use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; +use sp_std::vec::Vec; + +use frame_support::{ + BoundedVec, + storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet}, +}; + +/// BoundedVec doesn't supports serde +#[cfg(feature = "serde1")] +pub mod vec_serde { + use core::convert::TryFrom; + use frame_support::{BoundedVec, traits::Get}; + use serde::{ + ser::{self, Serialize}, + de::{self, Deserialize, Error}, + }; + use sp_std::vec::Vec; + + pub fn serialize(value: &BoundedVec, serializer: D) -> Result + where + D: ser::Serializer, + V: Serialize, + { + (value as &Vec<_>).serialize(serializer) + } + + pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + V: de::Deserialize<'de>, + S: Get, + { + // TODO: Implement custom visitor, which will limit vec size at parse time? Will serde only be used by chainspec? + let vec = >::deserialize(deserializer)?; + let len = vec.len(); + TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size")) + } +} + +pub fn vec_debug(v: &BoundedVec, f: &mut fmt::Formatter) -> Result<(), fmt::Error> +where + V: fmt::Debug, +{ + use core::fmt::Debug; + (&v as &Vec).fmt(f) +} + +#[cfg(feature = "serde1")] +#[allow(dead_code)] +pub mod map_serde { + use core::convert::TryFrom; + use sp_std::collections::btree_map::BTreeMap; + use frame_support::{traits::Get, storage::bounded_btree_map::BoundedBTreeMap}; + use serde::{ + ser::{self, Serialize}, + de::{self, Deserialize, Error}, + }; + pub fn serialize( + value: &BoundedBTreeMap, + serializer: D, + ) -> Result + where + D: ser::Serializer, + K: Serialize + Ord, + V: Serialize, + { + (value as &BTreeMap<_, _>).serialize(serializer) + } + + pub fn deserialize<'de, D, K, V, S>( + deserializer: D, + ) -> Result, D::Error> + where + D: de::Deserializer<'de>, + K: de::Deserialize<'de> + Ord, + V: de::Deserialize<'de>, + S: Get, + { + let map = >::deserialize(deserializer)?; + let len = map.len(); + TryFrom::try_from(map).map_err(|_| D::Error::invalid_length(len, &"lesser size")) + } +} + +pub fn map_debug( + v: &BoundedBTreeMap, + f: &mut fmt::Formatter, +) -> Result<(), fmt::Error> +where + K: fmt::Debug + Ord, + V: fmt::Debug, +{ + use core::fmt::Debug; + (&v as &BTreeMap).fmt(f) +} + +#[cfg(feature = "serde1")] +#[allow(dead_code)] +pub mod set_serde { + use core::convert::TryFrom; + use sp_std::collections::btree_set::BTreeSet; + use frame_support::{traits::Get, storage::bounded_btree_set::BoundedBTreeSet}; + use serde::{ + ser::{self, Serialize}, + de::{self, Deserialize, Error}, + }; + pub fn serialize( + value: &BoundedBTreeSet, + serializer: D, + ) -> Result + where + D: ser::Serializer, + K: Serialize + Ord, + { + (value as &BTreeSet<_>).serialize(serializer) + } + + pub fn deserialize<'de, D, K, S>(deserializer: D) -> Result, D::Error> + where + D: de::Deserializer<'de>, + K: de::Deserialize<'de> + Ord, + S: Get, + { + let map = >::deserialize(deserializer)?; + let len = map.len(); + TryFrom::try_from(map).map_err(|_| D::Error::invalid_length(len, &"lesser size")) + } +} + +pub fn set_debug(v: &BoundedBTreeSet, f: &mut fmt::Formatter) -> Result<(), fmt::Error> +where + K: fmt::Debug + Ord, +{ + use core::fmt::Debug; + (&v as &BTreeSet).fmt(f) +} --- a/primitives/data-structs/src/lib.rs +++ b/primitives/data-structs/src/lib.rs @@ -22,9 +22,7 @@ }; use frame_support::{ storage::{bounded_btree_map::BoundedBTreeMap, bounded_btree_set::BoundedBTreeSet}, - traits::ConstU16, }; -use sp_std::collections::{btree_map::BTreeMap, btree_set::BTreeSet}; #[cfg(feature = "serde")] use serde::{Serialize, Deserialize}; @@ -36,6 +34,7 @@ use derivative::Derivative; use scale_info::TypeInfo; +mod bounded; pub mod mapping; mod migration; @@ -255,14 +254,14 @@ pub owner: AccountId, pub mode: CollectionMode, pub access: AccessMode, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub name: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub description: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub token_prefix: BoundedVec>, pub mint_mode: bool, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub offchain_schema: BoundedVec>, pub schema_version: SchemaVersion, pub sponsorship: SponsorshipState, @@ -272,9 +271,9 @@ #[version(2.., upper(limits.into()))] pub limits: CollectionLimitsVersion2, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub variable_on_chain_schema: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub const_on_chain_schema: BoundedVec>, pub meta_update_permission: MetaUpdatePermission, } @@ -286,20 +285,20 @@ #[derivative(Default(value = "CollectionMode::NFT"))] pub mode: CollectionMode, pub access: Option, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub name: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub description: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub token_prefix: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub offchain_schema: BoundedVec>, pub schema_version: Option, pub pending_sponsor: Option, pub limits: Option, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub variable_on_chain_schema: BoundedVec>, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] pub const_on_chain_schema: BoundedVec>, pub meta_update_permission: Option, } @@ -410,8 +409,8 @@ Owner, /// Owner can nest tokens from specified collections OwnerRestricted( - #[cfg_attr(feature = "serde1", serde(with = "bounded_set_serde"))] - #[derivative(Debug(format_with = "bounded_set_debug"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::set_serde"))] + #[derivative(Debug(format_with = "bounded::set_debug"))] BoundedBTreeSet>, ), } @@ -421,150 +420,17 @@ pub enum SponsoringRateLimit { SponsoringDisabled, Blocks(u32), -} - -/// BoundedVec doesn't supports serde -#[cfg(feature = "serde1")] -mod bounded_serde { - use core::convert::TryFrom; - use frame_support::{BoundedVec, traits::Get}; - use serde::{ - ser::{self, Serialize}, - de::{self, Deserialize, Error}, - }; - use sp_std::vec::Vec; - - pub fn serialize(value: &BoundedVec, serializer: D) -> Result - where - D: ser::Serializer, - V: Serialize, - { - (value as &Vec<_>).serialize(serializer) - } - - pub fn deserialize<'de, D, V, S>(deserializer: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - V: de::Deserialize<'de>, - S: Get, - { - // TODO: Implement custom visitor, which will limit vec size at parse time? Will serde only be used by chainspec? - let vec = >::deserialize(deserializer)?; - let len = vec.len(); - TryFrom::try_from(vec).map_err(|_| D::Error::invalid_length(len, &"lesser size")) - } -} - -fn bounded_debug(v: &BoundedVec, f: &mut fmt::Formatter) -> Result<(), fmt::Error> -where - V: fmt::Debug, -{ - use core::fmt::Debug; - (&v as &Vec).fmt(f) -} - -#[cfg(feature = "serde1")] -#[allow(dead_code)] -mod bounded_map_serde { - use core::convert::TryFrom; - use sp_std::collections::btree_map::BTreeMap; - use frame_support::{traits::Get, storage::bounded_btree_map::BoundedBTreeMap}; - use serde::{ - ser::{self, Serialize}, - de::{self, Deserialize, Error}, - }; - pub fn serialize( - value: &BoundedBTreeMap, - serializer: D, - ) -> Result - where - D: ser::Serializer, - K: Serialize + Ord, - V: Serialize, - { - (value as &BTreeMap<_, _>).serialize(serializer) - } - - pub fn deserialize<'de, D, K, V, S>( - deserializer: D, - ) -> Result, D::Error> - where - D: de::Deserializer<'de>, - K: de::Deserialize<'de> + Ord, - V: de::Deserialize<'de>, - S: Get, - { - let map = >::deserialize(deserializer)?; - let len = map.len(); - TryFrom::try_from(map).map_err(|_| D::Error::invalid_length(len, &"lesser size")) - } -} - -fn bounded_map_debug( - v: &BoundedBTreeMap, - f: &mut fmt::Formatter, -) -> Result<(), fmt::Error> -where - K: fmt::Debug + Ord, - V: fmt::Debug, -{ - use core::fmt::Debug; - (&v as &BTreeMap).fmt(f) -} - -#[cfg(feature = "serde1")] -#[allow(dead_code)] -mod bounded_set_serde { - use core::convert::TryFrom; - use sp_std::collections::btree_set::BTreeSet; - use frame_support::{traits::Get, storage::bounded_btree_set::BoundedBTreeSet}; - use serde::{ - ser::{self, Serialize}, - de::{self, Deserialize, Error}, - }; - pub fn serialize( - value: &BoundedBTreeSet, - serializer: D, - ) -> Result - where - D: ser::Serializer, - K: Serialize + Ord, - { - (value as &BTreeSet<_>).serialize(serializer) - } - - pub fn deserialize<'de, D, K, S>(deserializer: D) -> Result, D::Error> - where - D: de::Deserializer<'de>, - K: de::Deserialize<'de> + Ord, - S: Get, - { - let map = >::deserialize(deserializer)?; - let len = map.len(); - TryFrom::try_from(map).map_err(|_| D::Error::invalid_length(len, &"lesser size")) - } } -fn bounded_set_debug( - v: &BoundedBTreeSet, - f: &mut fmt::Formatter, -) -> Result<(), fmt::Error> -where - K: fmt::Debug + Ord, -{ - use core::fmt::Debug; - (&v as &BTreeSet).fmt(f) -} - #[derive(Encode, Decode, MaxEncodedLen, Default, PartialEq, Clone, Derivative, TypeInfo)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[derivative(Debug)] pub struct CreateNftData { - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] - #[derivative(Debug(format_with = "bounded_debug"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub const_data: BoundedVec, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] - #[derivative(Debug(format_with = "bounded_debug"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub variable_data: BoundedVec, } @@ -578,11 +444,11 @@ #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] #[derivative(Debug)] pub struct CreateReFungibleData { - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] - #[derivative(Debug(format_with = "bounded_debug"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub const_data: BoundedVec, - #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] - #[derivative(Debug(format_with = "bounded_debug"))] + #[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub variable_data: BoundedVec, pub pieces: u128, } @@ -612,9 +478,9 @@ #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)] #[derivative(Debug)] pub struct CreateNftExData { - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub const_data: BoundedVec, - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub variable_data: BoundedVec, pub owner: CrossAccountId, } @@ -622,11 +488,11 @@ #[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, TypeInfo, Derivative)] #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))] pub struct CreateRefungibleExData { - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub const_data: BoundedVec, - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] pub variable_data: BoundedVec, - #[derivative(Debug(format_with = "bounded_map_debug"))] + #[derivative(Debug(format_with = "bounded::map_debug"))] pub users: BoundedBTreeMap>, } @@ -634,16 +500,16 @@ #[derivative(Debug(bound = "CrossAccountId: fmt::Debug + Ord"))] pub enum CreateItemExData { NFT( - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] BoundedVec, ConstU32>, ), Fungible( - #[derivative(Debug(format_with = "bounded_map_debug"))] + #[derivative(Debug(format_with = "bounded::map_debug"))] BoundedBTreeMap>, ), /// Many tokens, each may have only one owner RefungibleMultipleItems( - #[derivative(Debug(format_with = "bounded_debug"))] + #[derivative(Debug(format_with = "bounded::vec_debug"))] BoundedVec, ConstU32>, ), /// Single token, which may have many owners -- gitstuff