difftreelog
Merge commit '2074c933e3ff90b7ea5fc778111ead850fd4a5ea' into release-v922000
in: master
20 files changed
client/rpc/src/lib.rsdiffbeforeafterboth--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -25,7 +25,7 @@
use anyhow::anyhow;
use up_data_structs::{
RpcCollection, CollectionId, CollectionStats, CollectionLimits, TokenId, Property,
- PropertyKeyPermission, TokenData,
+ PropertyKeyPermission, TokenData, TokenChild,
};
use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};
use sp_blockchain::HeaderBackend;
@@ -77,6 +77,13 @@
token: TokenId,
at: Option<BlockHash>,
) -> Result<Option<CrossAccountId>>;
+ #[method(name = "unique_tokenChildren")]
+ fn token_children(
+ &self,
+ collection: CollectionId,
+ token: TokenId,
+ at: Option<BlockHash>,
+ ) -> Result<Vec<TokenChild>>;
#[method(name = "unique_collectionProperties")]
fn collection_properties(
@@ -394,6 +401,7 @@
pass_method!(
topmost_token_owner(collection: CollectionId, token: TokenId) -> Option<CrossAccountId>, unique_api
);
+ pass_method!(token_children(collection: CollectionId, token: TokenId) -> Vec<TokenChild>, unique_api);
pass_method!(total_supply(collection: CollectionId) -> u32, unique_api);
pass_method!(account_balance(collection: CollectionId, account: CrossAccountId) -> u32, unique_api);
pass_method!(balance(collection: CollectionId, account: CrossAccountId, token: TokenId) -> String => |v| v.to_string(), unique_api);
pallets/common/src/lib.rsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;2021use core::ops::{Deref, DerefMut};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use sp_std::vec::Vec;24use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};25use evm_coder::ToLog;26use frame_support::{27 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},28 ensure,29 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},30 weights::Pays,31 transactional,32};33use pallet_evm::GasWeightMapping;34use up_data_structs::{35 COLLECTION_NUMBER_LIMIT,36 Collection,37 RpcCollection,38 CollectionId,39 CreateItemData,40 MAX_TOKEN_PREFIX_LENGTH,41 COLLECTION_ADMINS_LIMIT,42 TokenId,43 CollectionStats,44 MAX_TOKEN_OWNERSHIP,45 CollectionMode,46 NFT_SPONSOR_TRANSFER_TIMEOUT,47 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,48 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,49 MAX_SPONSOR_TIMEOUT,50 CUSTOM_DATA_LIMIT,51 CollectionLimits,52 CreateCollectionData,53 SponsorshipState,54 CreateItemExData,55 SponsoringRateLimit,56 budget::Budget,57 PhantomType,58 Property,59 Properties,60 PropertiesPermissionMap,61 PropertyKey,62 PropertyValue,63 PropertyPermission,64 PropertiesError,65 PropertyKeyPermission,66 TokenData,67 TrySetProperty,68 PropertyScope,69 // RMRK70 RmrkCollectionInfo,71 RmrkInstanceInfo,72 RmrkResourceInfo,73 RmrkPropertyInfo,74 RmrkBaseInfo,75 RmrkPartType,76 RmrkTheme,77 RmrkNftChild,78 CollectionPermissions,79 SchemaVersion,80};8182pub use pallet::*;83use sp_core::H160;84use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};85#[cfg(feature = "runtime-benchmarks")]86pub mod benchmarking;87pub mod dispatch;88pub mod erc;89pub mod eth;90pub mod weights;9192pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9394#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]95pub struct CollectionHandle<T: Config> {96 pub id: CollectionId,97 collection: Collection<T::AccountId>,98 pub recorder: SubstrateRecorder<T>,99}100impl<T: Config> WithRecorder<T> for CollectionHandle<T> {101 fn recorder(&self) -> &SubstrateRecorder<T> {102 &self.recorder103 }104 fn into_recorder(self) -> SubstrateRecorder<T> {105 self.recorder106 }107}108impl<T: Config> CollectionHandle<T> {109 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {110 <CollectionById<T>>::get(id).map(|collection| Self {111 id,112 collection,113 recorder: SubstrateRecorder::new(gas_limit),114 })115 }116117 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {118 <CollectionById<T>>::get(id).map(|collection| Self {119 id,120 collection,121 recorder,122 })123 }124125 pub fn new(id: CollectionId) -> Option<Self> {126 Self::new_with_gas_limit(id, u64::MAX)127 }128 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {129 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)130 }131 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {132 self.recorder133 .consume_gas(T::GasWeightMapping::weight_to_gas(134 <T as frame_system::Config>::DbWeight::get()135 .read136 .saturating_mul(reads),137 ))138 }139 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {140 self.recorder141 .consume_gas(T::GasWeightMapping::weight_to_gas(142 <T as frame_system::Config>::DbWeight::get()143 .write144 .saturating_mul(writes),145 ))146 }147 pub fn save(self) -> DispatchResult {148 <CollectionById<T>>::insert(self.id, self.collection);149 Ok(())150 }151152 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {153 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);154 }155156 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {157 if self.collection.sponsorship.pending_sponsor() != Some(sender) {158 return false;159 };160161 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());162 true163 }164}165impl<T: Config> Deref for CollectionHandle<T> {166 type Target = Collection<T::AccountId>;167168 fn deref(&self) -> &Self::Target {169 &self.collection170 }171}172173impl<T: Config> DerefMut for CollectionHandle<T> {174 fn deref_mut(&mut self) -> &mut Self::Target {175 &mut self.collection176 }177}178179impl<T: Config> CollectionHandle<T> {180 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {181 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);182 Ok(())183 }184 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {185 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))186 }187 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {188 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);189 Ok(())190 }191 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {192 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)193 }194 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {195 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)196 }197 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {198 ensure!(199 <Allowlist<T>>::get((self.id, user)),200 <Error<T>>::AddressNotInAllowlist201 );202 Ok(())203 }204}205206#[frame_support::pallet]207pub mod pallet {208 use super::*;209 use pallet_evm::account;210 use dispatch::CollectionDispatch;211 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};212 use frame_system::pallet_prelude::*;213 use frame_support::traits::Currency;214 use up_data_structs::{TokenId, mapping::TokenAddressMapping};215 use scale_info::TypeInfo;216 use weights::WeightInfo;217218 #[pallet::config]219 pub trait Config:220 frame_system::Config221 + pallet_evm_coder_substrate::Config222 + pallet_evm::Config223 + TypeInfo224 + account::Config225 {226 type WeightInfo: WeightInfo;227 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;228229 type Currency: Currency<Self::AccountId>;230231 #[pallet::constant]232 type CollectionCreationPrice: Get<233 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,234 >;235 type CollectionDispatch: CollectionDispatch<Self>;236237 type TreasuryAccountId: Get<Self::AccountId>;238 type ContractAddress: Get<H160>;239240 type EvmTokenAddressMapping: TokenAddressMapping<H160>;241 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;242 }243244 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);245246 #[pallet::pallet]247 #[pallet::storage_version(STORAGE_VERSION)]248 #[pallet::generate_store(pub(super) trait Store)]249 pub struct Pallet<T>(_);250251 #[pallet::extra_constants]252 impl<T: Config> Pallet<T> {253 pub fn collection_admins_limit() -> u32 {254 COLLECTION_ADMINS_LIMIT255 }256 }257258 #[pallet::event]259 #[pallet::generate_deposit(pub fn deposit_event)]260 pub enum Event<T: Config> {261 /// New collection was created262 ///263 /// # Arguments264 ///265 /// * collection_id: Globally unique identifier of newly created collection.266 ///267 /// * mode: [CollectionMode] converted into u8.268 ///269 /// * account_id: Collection owner.270 CollectionCreated(CollectionId, u8, T::AccountId),271272 /// New collection was destroyed273 ///274 /// # Arguments275 ///276 /// * collection_id: Globally unique identifier of collection.277 CollectionDestroyed(CollectionId),278279 /// New item was created.280 ///281 /// # Arguments282 ///283 /// * collection_id: Id of the collection where item was created.284 ///285 /// * item_id: Id of an item. Unique within the collection.286 ///287 /// * recipient: Owner of newly created item288 ///289 /// * amount: Always 1 for NFT290 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),291292 /// Collection item was burned.293 ///294 /// # Arguments295 ///296 /// * collection_id.297 ///298 /// * item_id: Identifier of burned NFT.299 ///300 /// * owner: which user has destroyed its tokens301 ///302 /// * amount: Always 1 for NFT303 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),304305 /// Item was transferred306 ///307 /// * collection_id: Id of collection to which item is belong308 ///309 /// * item_id: Id of an item310 ///311 /// * sender: Original owner of item312 ///313 /// * recipient: New owner of item314 ///315 /// * amount: Always 1 for NFT316 Transfer(317 CollectionId,318 TokenId,319 T::CrossAccountId,320 T::CrossAccountId,321 u128,322 ),323324 /// * collection_id325 ///326 /// * item_id327 ///328 /// * sender329 ///330 /// * spender331 ///332 /// * amount333 Approved(334 CollectionId,335 TokenId,336 T::CrossAccountId,337 T::CrossAccountId,338 u128,339 ),340341 CollectionPropertySet(CollectionId, PropertyKey),342343 CollectionPropertyDeleted(CollectionId, PropertyKey),344345 TokenPropertySet(CollectionId, TokenId, PropertyKey),346347 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),348349 PropertyPermissionSet(CollectionId, PropertyKey),350 }351352 #[pallet::error]353 pub enum Error<T> {354 /// This collection does not exist.355 CollectionNotFound,356 /// Sender parameter and item owner must be equal.357 MustBeTokenOwner,358 /// No permission to perform action359 NoPermission,360 /// Destroying only empty collections is allowed361 CantDestroyNotEmptyCollection,362 /// Collection is not in mint mode.363 PublicMintingNotAllowed,364 /// Address is not in allow list.365 AddressNotInAllowlist,366367 /// Collection name can not be longer than 63 char.368 CollectionNameLimitExceeded,369 /// Collection description can not be longer than 255 char.370 CollectionDescriptionLimitExceeded,371 /// Token prefix can not be longer than 15 char.372 CollectionTokenPrefixLimitExceeded,373 /// Total collections bound exceeded.374 TotalCollectionsLimitExceeded,375 /// Exceeded max admin count376 CollectionAdminCountExceeded,377 /// Collection limit bounds per collection exceeded378 CollectionLimitBoundsExceeded,379 /// Tried to enable permissions which are only permitted to be disabled380 OwnerPermissionsCantBeReverted,381 /// Collection settings not allowing items transferring382 TransferNotAllowed,383 /// Account token limit exceeded per collection384 AccountTokenLimitExceeded,385 /// Collection token limit exceeded386 CollectionTokenLimitExceeded,387 /// Metadata flag frozen388 MetadataFlagFrozen,389390 /// Item not exists.391 TokenNotFound,392 /// Item balance not enough.393 TokenValueTooLow,394 /// Requested value more than approved.395 ApprovedValueTooLow,396 /// Tried to approve more than owned397 CantApproveMoreThanOwned,398399 /// Can't transfer tokens to ethereum zero address400 AddressIsZero,401 /// Target collection doesn't supports this operation402 UnsupportedOperation,403404 /// Not sufficient founds to perform action405 NotSufficientFounds,406407 /// Collection has nesting disabled408 NestingIsDisabled,409 /// Only owner may nest tokens under this collection410 OnlyOwnerAllowedToNest,411 /// Only tokens from specific collections may nest tokens under this412 SourceCollectionIsNotAllowedToNest,413414 /// Tried to store more data than allowed in collection field415 CollectionFieldSizeExceeded,416417 /// Tried to store more property data than allowed418 NoSpaceForProperty,419420 /// Tried to store more property keys than allowed421 PropertyLimitReached,422423 /// Property key is too long424 PropertyKeyIsTooLong,425426 /// Only ASCII letters, digits, and '_', '-' are allowed427 InvalidCharacterInPropertyKey,428429 /// Empty property keys are forbidden430 EmptyPropertyKey,431 }432433 #[pallet::storage]434 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;435 #[pallet::storage]436 pub type DestroyedCollectionCount<T> =437 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;438439 /// Collection info440 #[pallet::storage]441 pub type CollectionById<T> = StorageMap<442 Hasher = Blake2_128Concat,443 Key = CollectionId,444 Value = Collection<<T as frame_system::Config>::AccountId>,445 QueryKind = OptionQuery,446 >;447448 /// Collection properties449 #[pallet::storage]450 #[pallet::getter(fn collection_properties)]451 pub type CollectionProperties<T> = StorageMap<452 Hasher = Blake2_128Concat,453 Key = CollectionId,454 Value = Properties,455 QueryKind = ValueQuery,456 OnEmpty = up_data_structs::CollectionProperties,457 >;458459 #[pallet::storage]460 #[pallet::getter(fn property_permissions)]461 pub type CollectionPropertyPermissions<T> = StorageMap<462 Hasher = Blake2_128Concat,463 Key = CollectionId,464 Value = PropertiesPermissionMap,465 QueryKind = ValueQuery,466 >;467468 #[pallet::storage]469 pub type AdminAmount<T> = StorageMap<470 Hasher = Blake2_128Concat,471 Key = CollectionId,472 Value = u32,473 QueryKind = ValueQuery,474 >;475476 /// List of collection admins477 #[pallet::storage]478 pub type IsAdmin<T: Config> = StorageNMap<479 Key = (480 Key<Blake2_128Concat, CollectionId>,481 Key<Blake2_128Concat, T::CrossAccountId>,482 ),483 Value = bool,484 QueryKind = ValueQuery,485 >;486487 /// Allowlisted collection users488 #[pallet::storage]489 pub type Allowlist<T: Config> = StorageNMap<490 Key = (491 Key<Blake2_128Concat, CollectionId>,492 Key<Blake2_128Concat, T::CrossAccountId>,493 ),494 Value = bool,495 QueryKind = ValueQuery,496 >;497498 /// Not used by code, exists only to provide some types to metadata499 #[pallet::storage]500 pub type DummyStorageValue<T: Config> = StorageValue<501 Value = (502 CollectionStats,503 CollectionId,504 TokenId,505 PhantomType<(506 TokenData<T::CrossAccountId>,507 RpcCollection<T::AccountId>,508 // RMRK509 RmrkCollectionInfo<T::AccountId>,510 RmrkInstanceInfo<T::AccountId>,511 RmrkResourceInfo,512 RmrkPropertyInfo,513 RmrkBaseInfo<T::AccountId>,514 RmrkPartType,515 RmrkTheme,516 RmrkNftChild,517 )>,518 ),519 QueryKind = OptionQuery,520 >;521522 #[pallet::hooks]523 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {524 fn on_runtime_upgrade() -> Weight {525 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {526 use up_data_structs::{CollectionVersion1, CollectionVersion2};527 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {528 let mut props = Vec::new();529 if !v.offchain_schema.is_empty() {530 props.push(Property {531 key: b"_old_offchainSchema".to_vec().try_into().unwrap(),532 value: v533 .offchain_schema534 .clone()535 .into_inner()536 .try_into()537 .expect("offchain schema too big"),538 });539 }540 if !v.variable_on_chain_schema.is_empty() {541 props.push(Property {542 key: b"_old_variableOnChainSchema".to_vec().try_into().unwrap(),543 value: v544 .variable_on_chain_schema545 .clone()546 .into_inner()547 .try_into()548 .expect("offchain schema too big"),549 });550 }551 if !v.const_on_chain_schema.is_empty() {552 props.push(Property {553 key: b"_old_constOnChainSchema".to_vec().try_into().unwrap(),554 value: v555 .const_on_chain_schema556 .clone()557 .into_inner()558 .try_into()559 .expect("offchain schema too big"),560 });561 }562 props.push(Property {563 key: b"_old_schemaVersion".to_vec().try_into().unwrap(),564 value: match v.schema_version {565 SchemaVersion::ImageURL => b"ImageUrl".as_slice(),566 SchemaVersion::Unique => b"Unique".as_slice(),567 }568 .to_vec()569 .try_into()570 .unwrap(),571 });572 Self::set_scoped_collection_properties(573 id,574 PropertyScope::None,575 props.into_iter(),576 )577 .expect("existing data larger than properties");578 let mut new = CollectionVersion2::from(v.clone());579 new.permissions.access = Some(v.access);580 new.permissions.mint_mode = Some(v.mint_mode);581 Some(new)582 });583 }584585 0586 }587 }588}589590impl<T: Config> Pallet<T> {591 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens592 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {593 ensure!(594 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,595 <Error<T>>::AddressIsZero596 );597 Ok(())598 }599 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {600 <IsAdmin<T>>::iter_prefix((collection,))601 .map(|(a, _)| a)602 .collect()603 }604 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {605 <Allowlist<T>>::iter_prefix((collection,))606 .map(|(a, _)| a)607 .collect()608 }609 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {610 <Allowlist<T>>::get((collection, user))611 }612 pub fn collection_stats() -> CollectionStats {613 let created = <CreatedCollectionCount<T>>::get();614 let destroyed = <DestroyedCollectionCount<T>>::get();615 CollectionStats {616 created: created.0,617 destroyed: destroyed.0,618 alive: created.0 - destroyed.0,619 }620 }621622 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {623 let collection = <CollectionById<T>>::get(collection);624 if collection.is_none() {625 return None;626 }627628 let collection = collection.unwrap();629 let limits = collection.limits;630 let effective_limits = CollectionLimits {631 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),632 sponsored_data_size: Some(limits.sponsored_data_size()),633 sponsored_data_rate_limit: Some(634 limits635 .sponsored_data_rate_limit636 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),637 ),638 token_limit: Some(limits.token_limit()),639 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(640 match collection.mode {641 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,642 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,643 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,644 },645 )),646 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),647 owner_can_transfer: Some(limits.owner_can_transfer()),648 owner_can_destroy: Some(limits.owner_can_destroy()),649 transfers_enabled: Some(limits.transfers_enabled()),650 };651652 Some(effective_limits)653 }654655 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {656 let Collection {657 name,658 description,659 owner,660 mode,661 token_prefix,662 sponsorship,663 limits,664 permissions,665 } = <CollectionById<T>>::get(collection)?;666667 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)668 .into_iter()669 .map(|(key, permission)| PropertyKeyPermission { key, permission })670 .collect();671672 let properties = <CollectionProperties<T>>::get(collection)673 .into_iter()674 .map(|(key, value)| Property { key, value })675 .collect();676677 let permissions = CollectionPermissions {678 access: Some(permissions.access()),679 mint_mode: Some(permissions.mint_mode()),680 nesting: Some(permissions.nesting().clone()),681 };682683 Some(RpcCollection {684 name: name.into_inner(),685 description: description.into_inner(),686 owner,687 mode,688 token_prefix: token_prefix.into_inner(),689 sponsorship,690 limits,691 permissions,692 token_property_permissions,693 properties,694 })695 }696}697698macro_rules! limit_default {699 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{700 $(701 if let Some($new) = $new.$field {702 let $old = $old.$field($($arg)?);703 let _ = $new;704 let _ = $old;705 $check706 } else {707 $new.$field = $old.$field708 }709 )*710 }};711}712macro_rules! limit_default_clone {713 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{714 $(715 if let Some($new) = $new.$field.clone() {716 let $old = $old.$field($($arg)?);717 let _ = $new;718 let _ = $old;719 $check720 } else {721 $new.$field = $old.$field.clone()722 }723 )*724 }};725}726727impl<T: Config> Pallet<T> {728 pub fn init_collection(729 owner: T::CrossAccountId,730 data: CreateCollectionData<T::AccountId>,731 ) -> Result<CollectionId, DispatchError> {732 {733 ensure!(734 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,735 Error::<T>::CollectionTokenPrefixLimitExceeded736 );737 }738739 let created_count = <CreatedCollectionCount<T>>::get()740 .0741 .checked_add(1)742 .ok_or(ArithmeticError::Overflow)?;743 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;744 let id = CollectionId(created_count);745746 // bound Total number of collections747 ensure!(748 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,749 <Error<T>>::TotalCollectionsLimitExceeded750 );751752 // =========753754 let collection = Collection {755 owner: owner.as_sub().clone(),756 name: data.name,757 mode: data.mode.clone(),758 description: data.description,759 token_prefix: data.token_prefix,760 sponsorship: data761 .pending_sponsor762 .map(SponsorshipState::Unconfirmed)763 .unwrap_or_default(),764 limits: data765 .limits766 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))767 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,768 permissions: data769 .permissions770 .map(|permissions| {771 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)772 })773 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,774 };775776 let mut collection_properties = up_data_structs::CollectionProperties::get();777 collection_properties778 .try_set_from_iter(data.properties.into_iter())779 .map_err(<Error<T>>::from)?;780781 CollectionProperties::<T>::insert(id, collection_properties);782783 let mut token_props_permissions = PropertiesPermissionMap::new();784 token_props_permissions785 .try_set_from_iter(data.token_property_permissions.into_iter())786 .map_err(<Error<T>>::from)?;787788 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);789790 // Take a (non-refundable) deposit of collection creation791 {792 let mut imbalance =793 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();794 imbalance.subsume(795 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(796 &T::TreasuryAccountId::get(),797 T::CollectionCreationPrice::get(),798 ),799 );800 <T as Config>::Currency::settle(801 &owner.as_sub(),802 imbalance,803 WithdrawReasons::TRANSFER,804 ExistenceRequirement::KeepAlive,805 )806 .map_err(|_| Error::<T>::NotSufficientFounds)?;807 }808809 <CreatedCollectionCount<T>>::put(created_count);810 <Pallet<T>>::deposit_event(Event::CollectionCreated(811 id,812 data.mode.id(),813 owner.as_sub().clone(),814 ));815 <PalletEvm<T>>::deposit_log(816 erc::CollectionHelpersEvents::CollectionCreated {817 owner: *owner.as_eth(),818 collection_id: eth::collection_id_to_address(id),819 }820 .to_log(T::ContractAddress::get()),821 );822 <CollectionById<T>>::insert(id, collection);823 Ok(id)824 }825826 pub fn destroy_collection(827 collection: CollectionHandle<T>,828 sender: &T::CrossAccountId,829 ) -> DispatchResult {830 ensure!(831 collection.limits.owner_can_destroy(),832 <Error<T>>::NoPermission,833 );834 collection.check_is_owner(sender)?;835836 let destroyed_collections = <DestroyedCollectionCount<T>>::get()837 .0838 .checked_add(1)839 .ok_or(ArithmeticError::Overflow)?;840841 // =========842843 <DestroyedCollectionCount<T>>::put(destroyed_collections);844 <CollectionById<T>>::remove(collection.id);845 <AdminAmount<T>>::remove(collection.id);846 <IsAdmin<T>>::remove_prefix((collection.id,), None);847 <Allowlist<T>>::remove_prefix((collection.id,), None);848 <CollectionProperties<T>>::remove(collection.id);849850 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));851 Ok(())852 }853854 pub fn set_collection_property(855 collection: &CollectionHandle<T>,856 sender: &T::CrossAccountId,857 property: Property,858 ) -> DispatchResult {859 collection.check_is_owner_or_admin(sender)?;860861 CollectionProperties::<T>::try_mutate(collection.id, |properties| {862 let property = property.clone();863 properties.try_set(property.key, property.value)864 })865 .map_err(<Error<T>>::from)?;866867 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));868869 Ok(())870 }871872 pub fn set_scoped_collection_property(873 collection_id: CollectionId,874 scope: PropertyScope,875 property: Property,876 ) -> DispatchResult {877 CollectionProperties::<T>::try_mutate(collection_id, |properties| {878 properties.try_scoped_set(scope, property.key, property.value)879 })880 .map_err(<Error<T>>::from)?;881882 Ok(())883 }884885 pub fn set_scoped_collection_properties(886 collection_id: CollectionId,887 scope: PropertyScope,888 properties: impl Iterator<Item = Property>,889 ) -> DispatchResult {890 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {891 stored_properties.try_scoped_set_from_iter(scope, properties)892 })893 .map_err(<Error<T>>::from)?;894895 Ok(())896 }897898 #[transactional]899 pub fn set_collection_properties(900 collection: &CollectionHandle<T>,901 sender: &T::CrossAccountId,902 properties: Vec<Property>,903 ) -> DispatchResult {904 for property in properties {905 Self::set_collection_property(collection, sender, property)?;906 }907908 Ok(())909 }910911 pub fn delete_collection_property(912 collection: &CollectionHandle<T>,913 sender: &T::CrossAccountId,914 property_key: PropertyKey,915 ) -> DispatchResult {916 collection.check_is_owner_or_admin(sender)?;917918 CollectionProperties::<T>::try_mutate(collection.id, |properties| {919 properties.remove(&property_key)920 })921 .map_err(<Error<T>>::from)?;922923 Self::deposit_event(Event::CollectionPropertyDeleted(924 collection.id,925 property_key,926 ));927928 Ok(())929 }930931 #[transactional]932 pub fn delete_collection_properties(933 collection: &CollectionHandle<T>,934 sender: &T::CrossAccountId,935 property_keys: Vec<PropertyKey>,936 ) -> DispatchResult {937 for key in property_keys {938 Self::delete_collection_property(collection, sender, key)?;939 }940941 Ok(())942 }943944 // For migrations945 pub fn set_property_permission_unchecked(946 collection: CollectionId,947 property_permission: PropertyKeyPermission,948 ) -> DispatchResult {949 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {950 permissions.try_set(property_permission.key, property_permission.permission)951 })952 .map_err(<Error<T>>::from)?;953 Ok(())954 }955956 pub fn set_property_permission(957 collection: &CollectionHandle<T>,958 sender: &T::CrossAccountId,959 property_permission: PropertyKeyPermission,960 ) -> DispatchResult {961 collection.check_is_owner_or_admin(sender)?;962963 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);964 let current_permission = all_permissions.get(&property_permission.key);965 if matches![966 current_permission,967 Some(PropertyPermission { mutable: false, .. })968 ] {969 return Err(<Error<T>>::NoPermission.into());970 }971972 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {973 let property_permission = property_permission.clone();974 permissions.try_set(property_permission.key, property_permission.permission)975 })976 .map_err(<Error<T>>::from)?;977978 Self::deposit_event(Event::PropertyPermissionSet(979 collection.id,980 property_permission.key,981 ));982983 Ok(())984 }985986 #[transactional]987 pub fn set_property_permissions(988 collection: &CollectionHandle<T>,989 sender: &T::CrossAccountId,990 property_permissions: Vec<PropertyKeyPermission>,991 ) -> DispatchResult {992 for prop_pemission in property_permissions {993 Self::set_property_permission(collection, sender, prop_pemission)?;994 }995996 Ok(())997 }998999 pub fn get_collection_property(1000 collection_id: CollectionId,1001 key: &PropertyKey,1002 ) -> Option<PropertyValue> {1003 Self::collection_properties(collection_id).get(key).cloned()1004 }10051006 pub fn bytes_keys_to_property_keys(1007 keys: Vec<Vec<u8>>,1008 ) -> Result<Vec<PropertyKey>, DispatchError> {1009 keys.into_iter()1010 .map(|key| -> Result<PropertyKey, DispatchError> {1011 key.try_into()1012 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1013 })1014 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1015 }10161017 pub fn filter_collection_properties(1018 collection_id: CollectionId,1019 keys: Option<Vec<PropertyKey>>,1020 ) -> Result<Vec<Property>, DispatchError> {1021 let properties = Self::collection_properties(collection_id);10221023 let properties = keys1024 .map(|keys| {1025 keys.into_iter()1026 .filter_map(|key| {1027 properties.get(&key).map(|value| Property {1028 key,1029 value: value.clone(),1030 })1031 })1032 .collect()1033 })1034 .unwrap_or_else(|| {1035 properties1036 .into_iter()1037 .map(|(key, value)| Property { key, value })1038 .collect()1039 });10401041 Ok(properties)1042 }10431044 pub fn filter_property_permissions(1045 collection_id: CollectionId,1046 keys: Option<Vec<PropertyKey>>,1047 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1048 let permissions = Self::property_permissions(collection_id);10491050 let key_permissions = keys1051 .map(|keys| {1052 keys.into_iter()1053 .filter_map(|key| {1054 permissions1055 .get(&key)1056 .map(|permission| PropertyKeyPermission {1057 key,1058 permission: permission.clone(),1059 })1060 })1061 .collect()1062 })1063 .unwrap_or_else(|| {1064 permissions1065 .into_iter()1066 .map(|(key, permission)| PropertyKeyPermission { key, permission })1067 .collect()1068 });10691070 Ok(key_permissions)1071 }10721073 pub fn toggle_allowlist(1074 collection: &CollectionHandle<T>,1075 sender: &T::CrossAccountId,1076 user: &T::CrossAccountId,1077 allowed: bool,1078 ) -> DispatchResult {1079 collection.check_is_owner_or_admin(sender)?;10801081 // =========10821083 if allowed {1084 <Allowlist<T>>::insert((collection.id, user), true);1085 } else {1086 <Allowlist<T>>::remove((collection.id, user));1087 }10881089 Ok(())1090 }10911092 pub fn toggle_admin(1093 collection: &CollectionHandle<T>,1094 sender: &T::CrossAccountId,1095 user: &T::CrossAccountId,1096 admin: bool,1097 ) -> DispatchResult {1098 collection.check_is_owner_or_admin(sender)?;10991100 let was_admin = <IsAdmin<T>>::get((collection.id, user));1101 if was_admin == admin {1102 return Ok(());1103 }1104 let amount = <AdminAmount<T>>::get(collection.id);11051106 if admin {1107 let amount = amount1108 .checked_add(1)1109 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1110 ensure!(1111 amount <= Self::collection_admins_limit(),1112 <Error<T>>::CollectionAdminCountExceeded,1113 );11141115 // =========11161117 <AdminAmount<T>>::insert(collection.id, amount);1118 <IsAdmin<T>>::insert((collection.id, user), true);1119 } else {1120 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1121 <IsAdmin<T>>::remove((collection.id, user));1122 }11231124 Ok(())1125 }11261127 pub fn clamp_limits(1128 mode: CollectionMode,1129 old_limit: &CollectionLimits,1130 mut new_limit: CollectionLimits,1131 ) -> Result<CollectionLimits, DispatchError> {1132 limit_default!(old_limit, new_limit,1133 account_token_ownership_limit => ensure!(1134 new_limit <= MAX_TOKEN_OWNERSHIP,1135 <Error<T>>::CollectionLimitBoundsExceeded,1136 ),1137 sponsored_data_size => ensure!(1138 new_limit <= CUSTOM_DATA_LIMIT,1139 <Error<T>>::CollectionLimitBoundsExceeded,1140 ),11411142 sponsored_data_rate_limit => {},1143 token_limit => ensure!(1144 old_limit >= new_limit && new_limit > 0,1145 <Error<T>>::CollectionTokenLimitExceeded1146 ),11471148 sponsor_transfer_timeout(match mode {1149 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1150 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1151 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1152 }) => ensure!(1153 new_limit <= MAX_SPONSOR_TIMEOUT,1154 <Error<T>>::CollectionLimitBoundsExceeded,1155 ),1156 sponsor_approve_timeout => {},1157 owner_can_transfer => ensure!(1158 old_limit || !new_limit,1159 <Error<T>>::OwnerPermissionsCantBeReverted,1160 ),1161 owner_can_destroy => ensure!(1162 old_limit || !new_limit,1163 <Error<T>>::OwnerPermissionsCantBeReverted,1164 ),1165 transfers_enabled => {},1166 );1167 Ok(new_limit)1168 }1169 pub fn clamp_permissions(1170 mode: CollectionMode,1171 old_limit: &CollectionPermissions,1172 mut new_limit: CollectionPermissions,1173 ) -> Result<CollectionPermissions, DispatchError> {1174 limit_default_clone!(old_limit, new_limit,1175 access => {},1176 mint_mode => {},1177 nesting => {},1178 );1179 Ok(new_limit)1180 }1181}11821183#[macro_export]1184macro_rules! unsupported {1185 () => {1186 Err(<Error<T>>::UnsupportedOperation.into())1187 };1188}11891190/// Worst cases1191pub trait CommonWeightInfo<CrossAccountId> {1192 fn create_item() -> Weight;1193 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1194 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1195 fn burn_item() -> Weight;1196 fn set_collection_properties(amount: u32) -> Weight;1197 fn delete_collection_properties(amount: u32) -> Weight;1198 fn set_token_properties(amount: u32) -> Weight;1199 fn delete_token_properties(amount: u32) -> Weight;1200 fn set_property_permissions(amount: u32) -> Weight;1201 fn transfer() -> Weight;1202 fn approve() -> Weight;1203 fn transfer_from() -> Weight;1204 fn burn_from() -> Weight;1205}12061207pub trait CommonCollectionOperations<T: Config> {1208 fn create_item(1209 &self,1210 sender: T::CrossAccountId,1211 to: T::CrossAccountId,1212 data: CreateItemData,1213 nesting_budget: &dyn Budget,1214 ) -> DispatchResultWithPostInfo;1215 fn create_multiple_items(1216 &self,1217 sender: T::CrossAccountId,1218 to: T::CrossAccountId,1219 data: Vec<CreateItemData>,1220 nesting_budget: &dyn Budget,1221 ) -> DispatchResultWithPostInfo;1222 fn create_multiple_items_ex(1223 &self,1224 sender: T::CrossAccountId,1225 data: CreateItemExData<T::CrossAccountId>,1226 nesting_budget: &dyn Budget,1227 ) -> DispatchResultWithPostInfo;1228 fn burn_item(1229 &self,1230 sender: T::CrossAccountId,1231 token: TokenId,1232 amount: u128,1233 ) -> DispatchResultWithPostInfo;1234 fn set_collection_properties(1235 &self,1236 sender: T::CrossAccountId,1237 properties: Vec<Property>,1238 ) -> DispatchResultWithPostInfo;1239 fn delete_collection_properties(1240 &self,1241 sender: &T::CrossAccountId,1242 property_keys: Vec<PropertyKey>,1243 ) -> DispatchResultWithPostInfo;1244 fn set_token_properties(1245 &self,1246 sender: T::CrossAccountId,1247 token_id: TokenId,1248 property: Vec<Property>,1249 ) -> DispatchResultWithPostInfo;1250 fn delete_token_properties(1251 &self,1252 sender: T::CrossAccountId,1253 token_id: TokenId,1254 property_keys: Vec<PropertyKey>,1255 ) -> DispatchResultWithPostInfo;1256 fn set_property_permissions(1257 &self,1258 sender: &T::CrossAccountId,1259 property_permissions: Vec<PropertyKeyPermission>,1260 ) -> DispatchResultWithPostInfo;1261 fn transfer(1262 &self,1263 sender: T::CrossAccountId,1264 to: T::CrossAccountId,1265 token: TokenId,1266 amount: u128,1267 nesting_budget: &dyn Budget,1268 ) -> DispatchResultWithPostInfo;1269 fn approve(1270 &self,1271 sender: T::CrossAccountId,1272 spender: T::CrossAccountId,1273 token: TokenId,1274 amount: u128,1275 ) -> DispatchResultWithPostInfo;1276 fn transfer_from(1277 &self,1278 sender: T::CrossAccountId,1279 from: T::CrossAccountId,1280 to: T::CrossAccountId,1281 token: TokenId,1282 amount: u128,1283 nesting_budget: &dyn Budget,1284 ) -> DispatchResultWithPostInfo;1285 fn burn_from(1286 &self,1287 sender: T::CrossAccountId,1288 from: T::CrossAccountId,1289 token: TokenId,1290 amount: u128,1291 nesting_budget: &dyn Budget,1292 ) -> DispatchResultWithPostInfo;12931294 fn check_nesting(1295 &self,1296 sender: T::CrossAccountId,1297 from: (CollectionId, TokenId),1298 under: TokenId,1299 budget: &dyn Budget,1300 ) -> DispatchResult;13011302 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));13031304 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));13051306 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1307 fn collection_tokens(&self) -> Vec<TokenId>;1308 fn token_exists(&self, token: TokenId) -> bool;1309 fn last_token_id(&self) -> TokenId;13101311 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1312 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1313 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1314 /// Amount of unique collection tokens1315 fn total_supply(&self) -> u32;1316 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1317 fn account_balance(&self, account: T::CrossAccountId) -> u32;1318 /// Amount of specific token account have (Applicable to fungible/refungible)1319 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1320 fn allowance(1321 &self,1322 sender: T::CrossAccountId,1323 spender: T::CrossAccountId,1324 token: TokenId,1325 ) -> u128;1326}13271328// Flexible enough for implementing CommonCollectionOperations1329pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1330 let post_info = PostDispatchInfo {1331 actual_weight: Some(weight),1332 pays_fee: Pays::Yes,1333 };1334 match res {1335 Ok(()) => Ok(post_info),1336 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1337 }1338}13391340impl<T: Config> From<PropertiesError> for Error<T> {1341 fn from(error: PropertiesError) -> Self {1342 match error {1343 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1344 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1345 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1346 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1347 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1348 }1349 }1350}1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617#![cfg_attr(not(feature = "std"), no_std)]1819extern crate alloc;2021use core::ops::{Deref, DerefMut};22use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder};23use sp_std::vec::Vec;24use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};25use evm_coder::ToLog;26use frame_support::{27 dispatch::{DispatchErrorWithPostInfo, DispatchResultWithPostInfo, Weight, PostDispatchInfo},28 ensure,29 traits::{Imbalance, Get, Currency, WithdrawReasons, ExistenceRequirement},30 weights::Pays,31 transactional,32};33use pallet_evm::GasWeightMapping;34use up_data_structs::{35 COLLECTION_NUMBER_LIMIT,36 Collection,37 RpcCollection,38 CollectionId,39 CreateItemData,40 MAX_TOKEN_PREFIX_LENGTH,41 COLLECTION_ADMINS_LIMIT,42 TokenId,43 TokenChild,44 CollectionStats,45 MAX_TOKEN_OWNERSHIP,46 CollectionMode,47 NFT_SPONSOR_TRANSFER_TIMEOUT,48 FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,49 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,50 MAX_SPONSOR_TIMEOUT,51 CUSTOM_DATA_LIMIT,52 CollectionLimits,53 CreateCollectionData,54 SponsorshipState,55 CreateItemExData,56 SponsoringRateLimit,57 budget::Budget,58 PhantomType,59 Property,60 Properties,61 PropertiesPermissionMap,62 PropertyKey,63 PropertyValue,64 PropertyPermission,65 PropertiesError,66 PropertyKeyPermission,67 TokenData,68 TrySetProperty,69 PropertyScope,70 // RMRK71 RmrkCollectionInfo,72 RmrkInstanceInfo,73 RmrkResourceInfo,74 RmrkPropertyInfo,75 RmrkBaseInfo,76 RmrkPartType,77 RmrkTheme,78 RmrkNftChild,79 CollectionPermissions,80 SchemaVersion,81};8283pub use pallet::*;84use sp_core::H160;85use sp_runtime::{ArithmeticError, DispatchError, DispatchResult};86#[cfg(feature = "runtime-benchmarks")]87pub mod benchmarking;88pub mod dispatch;89pub mod erc;90pub mod eth;91pub mod weights;9293pub type SelfWeightOf<T> = <T as Config>::WeightInfo;9495#[must_use = "Should call submit_logs or save, otherwise some data will be lost for evm side"]96pub struct CollectionHandle<T: Config> {97 pub id: CollectionId,98 collection: Collection<T::AccountId>,99 pub recorder: SubstrateRecorder<T>,100}101impl<T: Config> WithRecorder<T> for CollectionHandle<T> {102 fn recorder(&self) -> &SubstrateRecorder<T> {103 &self.recorder104 }105 fn into_recorder(self) -> SubstrateRecorder<T> {106 self.recorder107 }108}109impl<T: Config> CollectionHandle<T> {110 pub fn new_with_gas_limit(id: CollectionId, gas_limit: u64) -> Option<Self> {111 <CollectionById<T>>::get(id).map(|collection| Self {112 id,113 collection,114 recorder: SubstrateRecorder::new(gas_limit),115 })116 }117118 pub fn new_with_recorder(id: CollectionId, recorder: SubstrateRecorder<T>) -> Option<Self> {119 <CollectionById<T>>::get(id).map(|collection| Self {120 id,121 collection,122 recorder,123 })124 }125126 pub fn new(id: CollectionId) -> Option<Self> {127 Self::new_with_gas_limit(id, u64::MAX)128 }129 pub fn try_get(id: CollectionId) -> Result<Self, DispatchError> {130 Ok(Self::new(id).ok_or(<Error<T>>::CollectionNotFound)?)131 }132 pub fn consume_store_reads(&self, reads: u64) -> evm_coder::execution::Result<()> {133 self.recorder134 .consume_gas(T::GasWeightMapping::weight_to_gas(135 <T as frame_system::Config>::DbWeight::get()136 .read137 .saturating_mul(reads),138 ))139 }140 pub fn consume_store_writes(&self, writes: u64) -> evm_coder::execution::Result<()> {141 self.recorder142 .consume_gas(T::GasWeightMapping::weight_to_gas(143 <T as frame_system::Config>::DbWeight::get()144 .write145 .saturating_mul(writes),146 ))147 }148 pub fn save(self) -> DispatchResult {149 <CollectionById<T>>::insert(self.id, self.collection);150 Ok(())151 }152153 pub fn set_sponsor(&mut self, sponsor: T::AccountId) {154 self.collection.sponsorship = SponsorshipState::Unconfirmed(sponsor);155 }156157 pub fn confirm_sponsorship(&mut self, sender: &T::AccountId) -> bool {158 if self.collection.sponsorship.pending_sponsor() != Some(sender) {159 return false;160 };161162 self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());163 true164 }165}166impl<T: Config> Deref for CollectionHandle<T> {167 type Target = Collection<T::AccountId>;168169 fn deref(&self) -> &Self::Target {170 &self.collection171 }172}173174impl<T: Config> DerefMut for CollectionHandle<T> {175 fn deref_mut(&mut self) -> &mut Self::Target {176 &mut self.collection177 }178}179180impl<T: Config> CollectionHandle<T> {181 pub fn check_is_owner(&self, subject: &T::CrossAccountId) -> DispatchResult {182 ensure!(*subject.as_sub() == self.owner, <Error<T>>::NoPermission);183 Ok(())184 }185 pub fn is_owner_or_admin(&self, subject: &T::CrossAccountId) -> bool {186 *subject.as_sub() == self.owner || <IsAdmin<T>>::get((self.id, subject))187 }188 pub fn check_is_owner_or_admin(&self, subject: &T::CrossAccountId) -> DispatchResult {189 ensure!(self.is_owner_or_admin(subject), <Error<T>>::NoPermission);190 Ok(())191 }192 pub fn ignores_allowance(&self, user: &T::CrossAccountId) -> bool {193 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)194 }195 pub fn ignores_owned_amount(&self, user: &T::CrossAccountId) -> bool {196 self.limits.owner_can_transfer() && self.is_owner_or_admin(user)197 }198 pub fn check_allowlist(&self, user: &T::CrossAccountId) -> DispatchResult {199 ensure!(200 <Allowlist<T>>::get((self.id, user)),201 <Error<T>>::AddressNotInAllowlist202 );203 Ok(())204 }205}206207#[frame_support::pallet]208pub mod pallet {209 use super::*;210 use pallet_evm::account;211 use dispatch::CollectionDispatch;212 use frame_support::{Blake2_128Concat, pallet_prelude::*, storage::Key, traits::StorageVersion};213 use frame_system::pallet_prelude::*;214 use frame_support::traits::Currency;215 use up_data_structs::{TokenId, mapping::TokenAddressMapping};216 use scale_info::TypeInfo;217 use weights::WeightInfo;218219 #[pallet::config]220 pub trait Config:221 frame_system::Config222 + pallet_evm_coder_substrate::Config223 + pallet_evm::Config224 + TypeInfo225 + account::Config226 {227 type WeightInfo: WeightInfo;228 type Event: IsType<<Self as frame_system::Config>::Event> + From<Event<Self>>;229230 type Currency: Currency<Self::AccountId>;231232 #[pallet::constant]233 type CollectionCreationPrice: Get<234 <<Self as Config>::Currency as Currency<Self::AccountId>>::Balance,235 >;236 type CollectionDispatch: CollectionDispatch<Self>;237238 type TreasuryAccountId: Get<Self::AccountId>;239 type ContractAddress: Get<H160>;240241 type EvmTokenAddressMapping: TokenAddressMapping<H160>;242 type CrossTokenAddressMapping: TokenAddressMapping<Self::CrossAccountId>;243 }244245 const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);246247 #[pallet::pallet]248 #[pallet::storage_version(STORAGE_VERSION)]249 #[pallet::generate_store(pub(super) trait Store)]250 pub struct Pallet<T>(_);251252 #[pallet::extra_constants]253 impl<T: Config> Pallet<T> {254 pub fn collection_admins_limit() -> u32 {255 COLLECTION_ADMINS_LIMIT256 }257 }258259 #[pallet::event]260 #[pallet::generate_deposit(pub fn deposit_event)]261 pub enum Event<T: Config> {262 /// New collection was created263 ///264 /// # Arguments265 ///266 /// * collection_id: Globally unique identifier of newly created collection.267 ///268 /// * mode: [CollectionMode] converted into u8.269 ///270 /// * account_id: Collection owner.271 CollectionCreated(CollectionId, u8, T::AccountId),272273 /// New collection was destroyed274 ///275 /// # Arguments276 ///277 /// * collection_id: Globally unique identifier of collection.278 CollectionDestroyed(CollectionId),279280 /// New item was created.281 ///282 /// # Arguments283 ///284 /// * collection_id: Id of the collection where item was created.285 ///286 /// * item_id: Id of an item. Unique within the collection.287 ///288 /// * recipient: Owner of newly created item289 ///290 /// * amount: Always 1 for NFT291 ItemCreated(CollectionId, TokenId, T::CrossAccountId, u128),292293 /// Collection item was burned.294 ///295 /// # Arguments296 ///297 /// * collection_id.298 ///299 /// * item_id: Identifier of burned NFT.300 ///301 /// * owner: which user has destroyed its tokens302 ///303 /// * amount: Always 1 for NFT304 ItemDestroyed(CollectionId, TokenId, T::CrossAccountId, u128),305306 /// Item was transferred307 ///308 /// * collection_id: Id of collection to which item is belong309 ///310 /// * item_id: Id of an item311 ///312 /// * sender: Original owner of item313 ///314 /// * recipient: New owner of item315 ///316 /// * amount: Always 1 for NFT317 Transfer(318 CollectionId,319 TokenId,320 T::CrossAccountId,321 T::CrossAccountId,322 u128,323 ),324325 /// * collection_id326 ///327 /// * item_id328 ///329 /// * sender330 ///331 /// * spender332 ///333 /// * amount334 Approved(335 CollectionId,336 TokenId,337 T::CrossAccountId,338 T::CrossAccountId,339 u128,340 ),341342 CollectionPropertySet(CollectionId, PropertyKey),343344 CollectionPropertyDeleted(CollectionId, PropertyKey),345346 TokenPropertySet(CollectionId, TokenId, PropertyKey),347348 TokenPropertyDeleted(CollectionId, TokenId, PropertyKey),349350 PropertyPermissionSet(CollectionId, PropertyKey),351 }352353 #[pallet::error]354 pub enum Error<T> {355 /// This collection does not exist.356 CollectionNotFound,357 /// Sender parameter and item owner must be equal.358 MustBeTokenOwner,359 /// No permission to perform action360 NoPermission,361 /// Destroying only empty collections is allowed362 CantDestroyNotEmptyCollection,363 /// Collection is not in mint mode.364 PublicMintingNotAllowed,365 /// Address is not in allow list.366 AddressNotInAllowlist,367368 /// Collection name can not be longer than 63 char.369 CollectionNameLimitExceeded,370 /// Collection description can not be longer than 255 char.371 CollectionDescriptionLimitExceeded,372 /// Token prefix can not be longer than 15 char.373 CollectionTokenPrefixLimitExceeded,374 /// Total collections bound exceeded.375 TotalCollectionsLimitExceeded,376 /// Exceeded max admin count377 CollectionAdminCountExceeded,378 /// Collection limit bounds per collection exceeded379 CollectionLimitBoundsExceeded,380 /// Tried to enable permissions which are only permitted to be disabled381 OwnerPermissionsCantBeReverted,382 /// Collection settings not allowing items transferring383 TransferNotAllowed,384 /// Account token limit exceeded per collection385 AccountTokenLimitExceeded,386 /// Collection token limit exceeded387 CollectionTokenLimitExceeded,388 /// Metadata flag frozen389 MetadataFlagFrozen,390391 /// Item not exists.392 TokenNotFound,393 /// Item balance not enough.394 TokenValueTooLow,395 /// Requested value more than approved.396 ApprovedValueTooLow,397 /// Tried to approve more than owned398 CantApproveMoreThanOwned,399400 /// Can't transfer tokens to ethereum zero address401 AddressIsZero,402 /// Target collection doesn't supports this operation403 UnsupportedOperation,404405 /// Not sufficient founds to perform action406 NotSufficientFounds,407408 /// Collection has nesting disabled409 NestingIsDisabled,410 /// Only owner may nest tokens under this collection411 OnlyOwnerAllowedToNest,412 /// Only tokens from specific collections may nest tokens under this413 SourceCollectionIsNotAllowedToNest,414415 /// Tried to store more data than allowed in collection field416 CollectionFieldSizeExceeded,417418 /// Tried to store more property data than allowed419 NoSpaceForProperty,420421 /// Tried to store more property keys than allowed422 PropertyLimitReached,423424 /// Property key is too long425 PropertyKeyIsTooLong,426427 /// Only ASCII letters, digits, and '_', '-' are allowed428 InvalidCharacterInPropertyKey,429430 /// Empty property keys are forbidden431 EmptyPropertyKey,432 }433434 #[pallet::storage]435 pub type CreatedCollectionCount<T> = StorageValue<Value = CollectionId, QueryKind = ValueQuery>;436 #[pallet::storage]437 pub type DestroyedCollectionCount<T> =438 StorageValue<Value = CollectionId, QueryKind = ValueQuery>;439440 /// Collection info441 #[pallet::storage]442 pub type CollectionById<T> = StorageMap<443 Hasher = Blake2_128Concat,444 Key = CollectionId,445 Value = Collection<<T as frame_system::Config>::AccountId>,446 QueryKind = OptionQuery,447 >;448449 /// Collection properties450 #[pallet::storage]451 #[pallet::getter(fn collection_properties)]452 pub type CollectionProperties<T> = StorageMap<453 Hasher = Blake2_128Concat,454 Key = CollectionId,455 Value = Properties,456 QueryKind = ValueQuery,457 OnEmpty = up_data_structs::CollectionProperties,458 >;459460 #[pallet::storage]461 #[pallet::getter(fn property_permissions)]462 pub type CollectionPropertyPermissions<T> = StorageMap<463 Hasher = Blake2_128Concat,464 Key = CollectionId,465 Value = PropertiesPermissionMap,466 QueryKind = ValueQuery,467 >;468469 #[pallet::storage]470 pub type AdminAmount<T> = StorageMap<471 Hasher = Blake2_128Concat,472 Key = CollectionId,473 Value = u32,474 QueryKind = ValueQuery,475 >;476477 /// List of collection admins478 #[pallet::storage]479 pub type IsAdmin<T: Config> = StorageNMap<480 Key = (481 Key<Blake2_128Concat, CollectionId>,482 Key<Blake2_128Concat, T::CrossAccountId>,483 ),484 Value = bool,485 QueryKind = ValueQuery,486 >;487488 /// Allowlisted collection users489 #[pallet::storage]490 pub type Allowlist<T: Config> = StorageNMap<491 Key = (492 Key<Blake2_128Concat, CollectionId>,493 Key<Blake2_128Concat, T::CrossAccountId>,494 ),495 Value = bool,496 QueryKind = ValueQuery,497 >;498499 /// Not used by code, exists only to provide some types to metadata500 #[pallet::storage]501 pub type DummyStorageValue<T: Config> = StorageValue<502 Value = (503 CollectionStats,504 CollectionId,505 TokenId,506 TokenChild,507 PhantomType<(508 TokenData<T::CrossAccountId>,509 RpcCollection<T::AccountId>,510 // RMRK511 RmrkCollectionInfo<T::AccountId>,512 RmrkInstanceInfo<T::AccountId>,513 RmrkResourceInfo,514 RmrkPropertyInfo,515 RmrkBaseInfo<T::AccountId>,516 RmrkPartType,517 RmrkTheme,518 RmrkNftChild,519 )>,520 ),521 QueryKind = OptionQuery,522 >;523524 #[pallet::hooks]525 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {526 fn on_runtime_upgrade() -> Weight {527 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {528 use up_data_structs::{CollectionVersion1, CollectionVersion2};529 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {530 let mut props = Vec::new();531 if !v.offchain_schema.is_empty() {532 props.push(Property {533 key: b"_old_offchainSchema".to_vec().try_into().unwrap(),534 value: v535 .offchain_schema536 .clone()537 .into_inner()538 .try_into()539 .expect("offchain schema too big"),540 });541 }542 if !v.variable_on_chain_schema.is_empty() {543 props.push(Property {544 key: b"_old_variableOnChainSchema".to_vec().try_into().unwrap(),545 value: v546 .variable_on_chain_schema547 .clone()548 .into_inner()549 .try_into()550 .expect("offchain schema too big"),551 });552 }553 if !v.const_on_chain_schema.is_empty() {554 props.push(Property {555 key: b"_old_constOnChainSchema".to_vec().try_into().unwrap(),556 value: v557 .const_on_chain_schema558 .clone()559 .into_inner()560 .try_into()561 .expect("offchain schema too big"),562 });563 }564 props.push(Property {565 key: b"_old_schemaVersion".to_vec().try_into().unwrap(),566 value: match v.schema_version {567 SchemaVersion::ImageURL => b"ImageUrl".as_slice(),568 SchemaVersion::Unique => b"Unique".as_slice(),569 }570 .to_vec()571 .try_into()572 .unwrap(),573 });574 Self::set_scoped_collection_properties(575 id,576 PropertyScope::None,577 props.into_iter(),578 )579 .expect("existing data larger than properties");580 let mut new = CollectionVersion2::from(v.clone());581 new.permissions.access = Some(v.access);582 new.permissions.mint_mode = Some(v.mint_mode);583 Some(new)584 });585 }586587 0588 }589 }590}591592impl<T: Config> Pallet<T> {593 /// Ethereum receiver 0x0000000000000000000000000000000000000000 is reserved, and shouldn't own tokens594 pub fn ensure_correct_receiver(receiver: &T::CrossAccountId) -> DispatchResult {595 ensure!(596 &T::CrossAccountId::from_eth(H160([0; 20])) != receiver,597 <Error<T>>::AddressIsZero598 );599 Ok(())600 }601 pub fn adminlist(collection: CollectionId) -> Vec<T::CrossAccountId> {602 <IsAdmin<T>>::iter_prefix((collection,))603 .map(|(a, _)| a)604 .collect()605 }606 pub fn allowlist(collection: CollectionId) -> Vec<T::CrossAccountId> {607 <Allowlist<T>>::iter_prefix((collection,))608 .map(|(a, _)| a)609 .collect()610 }611 pub fn allowed(collection: CollectionId, user: T::CrossAccountId) -> bool {612 <Allowlist<T>>::get((collection, user))613 }614 pub fn collection_stats() -> CollectionStats {615 let created = <CreatedCollectionCount<T>>::get();616 let destroyed = <DestroyedCollectionCount<T>>::get();617 CollectionStats {618 created: created.0,619 destroyed: destroyed.0,620 alive: created.0 - destroyed.0,621 }622 }623624 pub fn effective_collection_limits(collection: CollectionId) -> Option<CollectionLimits> {625 let collection = <CollectionById<T>>::get(collection);626 if collection.is_none() {627 return None;628 }629630 let collection = collection.unwrap();631 let limits = collection.limits;632 let effective_limits = CollectionLimits {633 account_token_ownership_limit: Some(limits.account_token_ownership_limit()),634 sponsored_data_size: Some(limits.sponsored_data_size()),635 sponsored_data_rate_limit: Some(636 limits637 .sponsored_data_rate_limit638 .unwrap_or(SponsoringRateLimit::SponsoringDisabled),639 ),640 token_limit: Some(limits.token_limit()),641 sponsor_transfer_timeout: Some(limits.sponsor_transfer_timeout(642 match collection.mode {643 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,644 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,645 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,646 },647 )),648 sponsor_approve_timeout: Some(limits.sponsor_approve_timeout()),649 owner_can_transfer: Some(limits.owner_can_transfer()),650 owner_can_destroy: Some(limits.owner_can_destroy()),651 transfers_enabled: Some(limits.transfers_enabled()),652 };653654 Some(effective_limits)655 }656657 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {658 let Collection {659 name,660 description,661 owner,662 mode,663 token_prefix,664 sponsorship,665 limits,666 permissions,667 } = <CollectionById<T>>::get(collection)?;668669 let token_property_permissions = <CollectionPropertyPermissions<T>>::get(collection)670 .into_iter()671 .map(|(key, permission)| PropertyKeyPermission { key, permission })672 .collect();673674 let properties = <CollectionProperties<T>>::get(collection)675 .into_iter()676 .map(|(key, value)| Property { key, value })677 .collect();678679 let permissions = CollectionPermissions {680 access: Some(permissions.access()),681 mint_mode: Some(permissions.mint_mode()),682 nesting: Some(permissions.nesting().clone()),683 };684685 Some(RpcCollection {686 name: name.into_inner(),687 description: description.into_inner(),688 owner,689 mode,690 token_prefix: token_prefix.into_inner(),691 sponsorship,692 limits,693 permissions,694 token_property_permissions,695 properties,696 })697 }698}699700macro_rules! limit_default {701 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{702 $(703 if let Some($new) = $new.$field {704 let $old = $old.$field($($arg)?);705 let _ = $new;706 let _ = $old;707 $check708 } else {709 $new.$field = $old.$field710 }711 )*712 }};713}714macro_rules! limit_default_clone {715 ($old:ident, $new:ident, $($field:ident $(($arg:expr))? => $check:expr),* $(,)?) => {{716 $(717 if let Some($new) = $new.$field.clone() {718 let $old = $old.$field($($arg)?);719 let _ = $new;720 let _ = $old;721 $check722 } else {723 $new.$field = $old.$field.clone()724 }725 )*726 }};727}728729impl<T: Config> Pallet<T> {730 pub fn init_collection(731 owner: T::CrossAccountId,732 data: CreateCollectionData<T::AccountId>,733 ) -> Result<CollectionId, DispatchError> {734 {735 ensure!(736 data.token_prefix.len() <= MAX_TOKEN_PREFIX_LENGTH as usize,737 Error::<T>::CollectionTokenPrefixLimitExceeded738 );739 }740741 let created_count = <CreatedCollectionCount<T>>::get()742 .0743 .checked_add(1)744 .ok_or(ArithmeticError::Overflow)?;745 let destroyed_count = <DestroyedCollectionCount<T>>::get().0;746 let id = CollectionId(created_count);747748 // bound Total number of collections749 ensure!(750 created_count - destroyed_count <= COLLECTION_NUMBER_LIMIT,751 <Error<T>>::TotalCollectionsLimitExceeded752 );753754 // =========755756 let collection = Collection {757 owner: owner.as_sub().clone(),758 name: data.name,759 mode: data.mode.clone(),760 description: data.description,761 token_prefix: data.token_prefix,762 sponsorship: data763 .pending_sponsor764 .map(SponsorshipState::Unconfirmed)765 .unwrap_or_default(),766 limits: data767 .limits768 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))769 .unwrap_or_else(|| Ok(CollectionLimits::default()))?,770 permissions: data771 .permissions772 .map(|permissions| {773 Self::clamp_permissions(data.mode.clone(), &Default::default(), permissions)774 })775 .unwrap_or_else(|| Ok(CollectionPermissions::default()))?,776 };777778 let mut collection_properties = up_data_structs::CollectionProperties::get();779 collection_properties780 .try_set_from_iter(data.properties.into_iter())781 .map_err(<Error<T>>::from)?;782783 CollectionProperties::<T>::insert(id, collection_properties);784785 let mut token_props_permissions = PropertiesPermissionMap::new();786 token_props_permissions787 .try_set_from_iter(data.token_property_permissions.into_iter())788 .map_err(<Error<T>>::from)?;789790 CollectionPropertyPermissions::<T>::insert(id, token_props_permissions);791792 // Take a (non-refundable) deposit of collection creation793 {794 let mut imbalance =795 <<<T as Config>::Currency as Currency<T::AccountId>>::PositiveImbalance>::zero();796 imbalance.subsume(797 <<T as Config>::Currency as Currency<T::AccountId>>::deposit_creating(798 &T::TreasuryAccountId::get(),799 T::CollectionCreationPrice::get(),800 ),801 );802 <T as Config>::Currency::settle(803 &owner.as_sub(),804 imbalance,805 WithdrawReasons::TRANSFER,806 ExistenceRequirement::KeepAlive,807 )808 .map_err(|_| Error::<T>::NotSufficientFounds)?;809 }810811 <CreatedCollectionCount<T>>::put(created_count);812 <Pallet<T>>::deposit_event(Event::CollectionCreated(813 id,814 data.mode.id(),815 owner.as_sub().clone(),816 ));817 <PalletEvm<T>>::deposit_log(818 erc::CollectionHelpersEvents::CollectionCreated {819 owner: *owner.as_eth(),820 collection_id: eth::collection_id_to_address(id),821 }822 .to_log(T::ContractAddress::get()),823 );824 <CollectionById<T>>::insert(id, collection);825 Ok(id)826 }827828 pub fn destroy_collection(829 collection: CollectionHandle<T>,830 sender: &T::CrossAccountId,831 ) -> DispatchResult {832 ensure!(833 collection.limits.owner_can_destroy(),834 <Error<T>>::NoPermission,835 );836 collection.check_is_owner(sender)?;837838 let destroyed_collections = <DestroyedCollectionCount<T>>::get()839 .0840 .checked_add(1)841 .ok_or(ArithmeticError::Overflow)?;842843 // =========844845 <DestroyedCollectionCount<T>>::put(destroyed_collections);846 <CollectionById<T>>::remove(collection.id);847 <AdminAmount<T>>::remove(collection.id);848 <IsAdmin<T>>::remove_prefix((collection.id,), None);849 <Allowlist<T>>::remove_prefix((collection.id,), None);850 <CollectionProperties<T>>::remove(collection.id);851852 <Pallet<T>>::deposit_event(Event::CollectionDestroyed(collection.id));853 Ok(())854 }855856 pub fn set_collection_property(857 collection: &CollectionHandle<T>,858 sender: &T::CrossAccountId,859 property: Property,860 ) -> DispatchResult {861 collection.check_is_owner_or_admin(sender)?;862863 CollectionProperties::<T>::try_mutate(collection.id, |properties| {864 let property = property.clone();865 properties.try_set(property.key, property.value)866 })867 .map_err(<Error<T>>::from)?;868869 Self::deposit_event(Event::CollectionPropertySet(collection.id, property.key));870871 Ok(())872 }873874 pub fn set_scoped_collection_property(875 collection_id: CollectionId,876 scope: PropertyScope,877 property: Property,878 ) -> DispatchResult {879 CollectionProperties::<T>::try_mutate(collection_id, |properties| {880 properties.try_scoped_set(scope, property.key, property.value)881 })882 .map_err(<Error<T>>::from)?;883884 Ok(())885 }886887 pub fn set_scoped_collection_properties(888 collection_id: CollectionId,889 scope: PropertyScope,890 properties: impl Iterator<Item = Property>,891 ) -> DispatchResult {892 CollectionProperties::<T>::try_mutate(collection_id, |stored_properties| {893 stored_properties.try_scoped_set_from_iter(scope, properties)894 })895 .map_err(<Error<T>>::from)?;896897 Ok(())898 }899900 #[transactional]901 pub fn set_collection_properties(902 collection: &CollectionHandle<T>,903 sender: &T::CrossAccountId,904 properties: Vec<Property>,905 ) -> DispatchResult {906 for property in properties {907 Self::set_collection_property(collection, sender, property)?;908 }909910 Ok(())911 }912913 pub fn delete_collection_property(914 collection: &CollectionHandle<T>,915 sender: &T::CrossAccountId,916 property_key: PropertyKey,917 ) -> DispatchResult {918 collection.check_is_owner_or_admin(sender)?;919920 CollectionProperties::<T>::try_mutate(collection.id, |properties| {921 properties.remove(&property_key)922 })923 .map_err(<Error<T>>::from)?;924925 Self::deposit_event(Event::CollectionPropertyDeleted(926 collection.id,927 property_key,928 ));929930 Ok(())931 }932933 #[transactional]934 pub fn delete_collection_properties(935 collection: &CollectionHandle<T>,936 sender: &T::CrossAccountId,937 property_keys: Vec<PropertyKey>,938 ) -> DispatchResult {939 for key in property_keys {940 Self::delete_collection_property(collection, sender, key)?;941 }942943 Ok(())944 }945946 // For migrations947 pub fn set_property_permission_unchecked(948 collection: CollectionId,949 property_permission: PropertyKeyPermission,950 ) -> DispatchResult {951 <CollectionPropertyPermissions<T>>::try_mutate(collection, |permissions| {952 permissions.try_set(property_permission.key, property_permission.permission)953 })954 .map_err(<Error<T>>::from)?;955 Ok(())956 }957958 pub fn set_property_permission(959 collection: &CollectionHandle<T>,960 sender: &T::CrossAccountId,961 property_permission: PropertyKeyPermission,962 ) -> DispatchResult {963 collection.check_is_owner_or_admin(sender)?;964965 let all_permissions = CollectionPropertyPermissions::<T>::get(collection.id);966 let current_permission = all_permissions.get(&property_permission.key);967 if matches![968 current_permission,969 Some(PropertyPermission { mutable: false, .. })970 ] {971 return Err(<Error<T>>::NoPermission.into());972 }973974 CollectionPropertyPermissions::<T>::try_mutate(collection.id, |permissions| {975 let property_permission = property_permission.clone();976 permissions.try_set(property_permission.key, property_permission.permission)977 })978 .map_err(<Error<T>>::from)?;979980 Self::deposit_event(Event::PropertyPermissionSet(981 collection.id,982 property_permission.key,983 ));984985 Ok(())986 }987988 #[transactional]989 pub fn set_property_permissions(990 collection: &CollectionHandle<T>,991 sender: &T::CrossAccountId,992 property_permissions: Vec<PropertyKeyPermission>,993 ) -> DispatchResult {994 for prop_pemission in property_permissions {995 Self::set_property_permission(collection, sender, prop_pemission)?;996 }997998 Ok(())999 }10001001 pub fn get_collection_property(1002 collection_id: CollectionId,1003 key: &PropertyKey,1004 ) -> Option<PropertyValue> {1005 Self::collection_properties(collection_id).get(key).cloned()1006 }10071008 pub fn bytes_keys_to_property_keys(1009 keys: Vec<Vec<u8>>,1010 ) -> Result<Vec<PropertyKey>, DispatchError> {1011 keys.into_iter()1012 .map(|key| -> Result<PropertyKey, DispatchError> {1013 key.try_into()1014 .map_err(|_| <Error<T>>::PropertyKeyIsTooLong.into())1015 })1016 .collect::<Result<Vec<PropertyKey>, DispatchError>>()1017 }10181019 pub fn filter_collection_properties(1020 collection_id: CollectionId,1021 keys: Option<Vec<PropertyKey>>,1022 ) -> Result<Vec<Property>, DispatchError> {1023 let properties = Self::collection_properties(collection_id);10241025 let properties = keys1026 .map(|keys| {1027 keys.into_iter()1028 .filter_map(|key| {1029 properties.get(&key).map(|value| Property {1030 key,1031 value: value.clone(),1032 })1033 })1034 .collect()1035 })1036 .unwrap_or_else(|| {1037 properties1038 .into_iter()1039 .map(|(key, value)| Property { key, value })1040 .collect()1041 });10421043 Ok(properties)1044 }10451046 pub fn filter_property_permissions(1047 collection_id: CollectionId,1048 keys: Option<Vec<PropertyKey>>,1049 ) -> Result<Vec<PropertyKeyPermission>, DispatchError> {1050 let permissions = Self::property_permissions(collection_id);10511052 let key_permissions = keys1053 .map(|keys| {1054 keys.into_iter()1055 .filter_map(|key| {1056 permissions1057 .get(&key)1058 .map(|permission| PropertyKeyPermission {1059 key,1060 permission: permission.clone(),1061 })1062 })1063 .collect()1064 })1065 .unwrap_or_else(|| {1066 permissions1067 .into_iter()1068 .map(|(key, permission)| PropertyKeyPermission { key, permission })1069 .collect()1070 });10711072 Ok(key_permissions)1073 }10741075 pub fn toggle_allowlist(1076 collection: &CollectionHandle<T>,1077 sender: &T::CrossAccountId,1078 user: &T::CrossAccountId,1079 allowed: bool,1080 ) -> DispatchResult {1081 collection.check_is_owner_or_admin(sender)?;10821083 // =========10841085 if allowed {1086 <Allowlist<T>>::insert((collection.id, user), true);1087 } else {1088 <Allowlist<T>>::remove((collection.id, user));1089 }10901091 Ok(())1092 }10931094 pub fn toggle_admin(1095 collection: &CollectionHandle<T>,1096 sender: &T::CrossAccountId,1097 user: &T::CrossAccountId,1098 admin: bool,1099 ) -> DispatchResult {1100 collection.check_is_owner_or_admin(sender)?;11011102 let was_admin = <IsAdmin<T>>::get((collection.id, user));1103 if was_admin == admin {1104 return Ok(());1105 }1106 let amount = <AdminAmount<T>>::get(collection.id);11071108 if admin {1109 let amount = amount1110 .checked_add(1)1111 .ok_or(<Error<T>>::CollectionAdminCountExceeded)?;1112 ensure!(1113 amount <= Self::collection_admins_limit(),1114 <Error<T>>::CollectionAdminCountExceeded,1115 );11161117 // =========11181119 <AdminAmount<T>>::insert(collection.id, amount);1120 <IsAdmin<T>>::insert((collection.id, user), true);1121 } else {1122 <AdminAmount<T>>::insert(collection.id, amount.saturating_sub(1));1123 <IsAdmin<T>>::remove((collection.id, user));1124 }11251126 Ok(())1127 }11281129 pub fn clamp_limits(1130 mode: CollectionMode,1131 old_limit: &CollectionLimits,1132 mut new_limit: CollectionLimits,1133 ) -> Result<CollectionLimits, DispatchError> {1134 limit_default!(old_limit, new_limit,1135 account_token_ownership_limit => ensure!(1136 new_limit <= MAX_TOKEN_OWNERSHIP,1137 <Error<T>>::CollectionLimitBoundsExceeded,1138 ),1139 sponsored_data_size => ensure!(1140 new_limit <= CUSTOM_DATA_LIMIT,1141 <Error<T>>::CollectionLimitBoundsExceeded,1142 ),11431144 sponsored_data_rate_limit => {},1145 token_limit => ensure!(1146 old_limit >= new_limit && new_limit > 0,1147 <Error<T>>::CollectionTokenLimitExceeded1148 ),11491150 sponsor_transfer_timeout(match mode {1151 CollectionMode::NFT => NFT_SPONSOR_TRANSFER_TIMEOUT,1152 CollectionMode::Fungible(_) => FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1153 CollectionMode::ReFungible => REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,1154 }) => ensure!(1155 new_limit <= MAX_SPONSOR_TIMEOUT,1156 <Error<T>>::CollectionLimitBoundsExceeded,1157 ),1158 sponsor_approve_timeout => {},1159 owner_can_transfer => ensure!(1160 old_limit || !new_limit,1161 <Error<T>>::OwnerPermissionsCantBeReverted,1162 ),1163 owner_can_destroy => ensure!(1164 old_limit || !new_limit,1165 <Error<T>>::OwnerPermissionsCantBeReverted,1166 ),1167 transfers_enabled => {},1168 );1169 Ok(new_limit)1170 }1171 pub fn clamp_permissions(1172 mode: CollectionMode,1173 old_limit: &CollectionPermissions,1174 mut new_limit: CollectionPermissions,1175 ) -> Result<CollectionPermissions, DispatchError> {1176 limit_default_clone!(old_limit, new_limit,1177 access => {},1178 mint_mode => {},1179 nesting => {},1180 );1181 Ok(new_limit)1182 }1183}11841185#[macro_export]1186macro_rules! unsupported {1187 () => {1188 Err(<Error<T>>::UnsupportedOperation.into())1189 };1190}11911192/// Worst cases1193pub trait CommonWeightInfo<CrossAccountId> {1194 fn create_item() -> Weight;1195 fn create_multiple_items(amount: &[CreateItemData]) -> Weight;1196 fn create_multiple_items_ex(cost: &CreateItemExData<CrossAccountId>) -> Weight;1197 fn burn_item() -> Weight;1198 fn set_collection_properties(amount: u32) -> Weight;1199 fn delete_collection_properties(amount: u32) -> Weight;1200 fn set_token_properties(amount: u32) -> Weight;1201 fn delete_token_properties(amount: u32) -> Weight;1202 fn set_property_permissions(amount: u32) -> Weight;1203 fn transfer() -> Weight;1204 fn approve() -> Weight;1205 fn transfer_from() -> Weight;1206 fn burn_from() -> Weight;1207}12081209pub trait CommonCollectionOperations<T: Config> {1210 fn create_item(1211 &self,1212 sender: T::CrossAccountId,1213 to: T::CrossAccountId,1214 data: CreateItemData,1215 nesting_budget: &dyn Budget,1216 ) -> DispatchResultWithPostInfo;1217 fn create_multiple_items(1218 &self,1219 sender: T::CrossAccountId,1220 to: T::CrossAccountId,1221 data: Vec<CreateItemData>,1222 nesting_budget: &dyn Budget,1223 ) -> DispatchResultWithPostInfo;1224 fn create_multiple_items_ex(1225 &self,1226 sender: T::CrossAccountId,1227 data: CreateItemExData<T::CrossAccountId>,1228 nesting_budget: &dyn Budget,1229 ) -> DispatchResultWithPostInfo;1230 fn burn_item(1231 &self,1232 sender: T::CrossAccountId,1233 token: TokenId,1234 amount: u128,1235 ) -> DispatchResultWithPostInfo;1236 fn set_collection_properties(1237 &self,1238 sender: T::CrossAccountId,1239 properties: Vec<Property>,1240 ) -> DispatchResultWithPostInfo;1241 fn delete_collection_properties(1242 &self,1243 sender: &T::CrossAccountId,1244 property_keys: Vec<PropertyKey>,1245 ) -> DispatchResultWithPostInfo;1246 fn set_token_properties(1247 &self,1248 sender: T::CrossAccountId,1249 token_id: TokenId,1250 property: Vec<Property>,1251 ) -> DispatchResultWithPostInfo;1252 fn delete_token_properties(1253 &self,1254 sender: T::CrossAccountId,1255 token_id: TokenId,1256 property_keys: Vec<PropertyKey>,1257 ) -> DispatchResultWithPostInfo;1258 fn set_property_permissions(1259 &self,1260 sender: &T::CrossAccountId,1261 property_permissions: Vec<PropertyKeyPermission>,1262 ) -> DispatchResultWithPostInfo;1263 fn transfer(1264 &self,1265 sender: T::CrossAccountId,1266 to: T::CrossAccountId,1267 token: TokenId,1268 amount: u128,1269 nesting_budget: &dyn Budget,1270 ) -> DispatchResultWithPostInfo;1271 fn approve(1272 &self,1273 sender: T::CrossAccountId,1274 spender: T::CrossAccountId,1275 token: TokenId,1276 amount: u128,1277 ) -> DispatchResultWithPostInfo;1278 fn transfer_from(1279 &self,1280 sender: T::CrossAccountId,1281 from: T::CrossAccountId,1282 to: T::CrossAccountId,1283 token: TokenId,1284 amount: u128,1285 nesting_budget: &dyn Budget,1286 ) -> DispatchResultWithPostInfo;1287 fn burn_from(1288 &self,1289 sender: T::CrossAccountId,1290 from: T::CrossAccountId,1291 token: TokenId,1292 amount: u128,1293 nesting_budget: &dyn Budget,1294 ) -> DispatchResultWithPostInfo;12951296 fn check_nesting(1297 &self,1298 sender: T::CrossAccountId,1299 from: (CollectionId, TokenId),1300 under: TokenId,1301 budget: &dyn Budget,1302 ) -> DispatchResult;13031304 fn nest(&self, under: TokenId, to_nest: (CollectionId, TokenId));13051306 fn unnest(&self, under: TokenId, to_nest: (CollectionId, TokenId));13071308 fn account_tokens(&self, account: T::CrossAccountId) -> Vec<TokenId>;1309 fn collection_tokens(&self) -> Vec<TokenId>;1310 fn token_exists(&self, token: TokenId) -> bool;1311 fn last_token_id(&self) -> TokenId;13121313 fn token_owner(&self, token: TokenId) -> Option<T::CrossAccountId>;1314 fn token_property(&self, token_id: TokenId, key: &PropertyKey) -> Option<PropertyValue>;1315 fn token_properties(&self, token_id: TokenId, keys: Option<Vec<PropertyKey>>) -> Vec<Property>;1316 /// Amount of unique collection tokens1317 fn total_supply(&self) -> u32;1318 /// Amount of different tokens account has (Applicable to nonfungible/refungible)1319 fn account_balance(&self, account: T::CrossAccountId) -> u32;1320 /// Amount of specific token account have (Applicable to fungible/refungible)1321 fn balance(&self, account: T::CrossAccountId, token: TokenId) -> u128;1322 fn allowance(1323 &self,1324 sender: T::CrossAccountId,1325 spender: T::CrossAccountId,1326 token: TokenId,1327 ) -> u128;1328}13291330// Flexible enough for implementing CommonCollectionOperations1331pub fn with_weight(res: DispatchResult, weight: Weight) -> DispatchResultWithPostInfo {1332 let post_info = PostDispatchInfo {1333 actual_weight: Some(weight),1334 pays_fee: Pays::Yes,1335 };1336 match res {1337 Ok(()) => Ok(post_info),1338 Err(error) => Err(DispatchErrorWithPostInfo { post_info, error }),1339 }1340}13411342impl<T: Config> From<PropertiesError> for Error<T> {1343 fn from(error: PropertiesError) -> Self {1344 match error {1345 PropertiesError::NoSpaceForProperty => Self::NoSpaceForProperty,1346 PropertiesError::PropertyLimitReached => Self::PropertyLimitReached,1347 PropertiesError::InvalidCharacterInPropertyKey => Self::InvalidCharacterInPropertyKey,1348 PropertiesError::PropertyKeyIsTooLong => Self::PropertyKeyIsTooLong,1349 PropertiesError::EmptyPropertyKey => Self::EmptyPropertyKey,1350 }1351 }1352}pallets/nonfungible/src/lib.rsdiffbeforeafterboth--- a/pallets/nonfungible/src/lib.rs
+++ b/pallets/nonfungible/src/lib.rs
@@ -22,7 +22,7 @@
use up_data_structs::{
AccessMode, CollectionId, CustomDataLimit, TokenId, CreateCollectionData, CreateNftExData,
mapping::TokenAddressMapping, NestingRule, budget::Budget, Property, PropertyPermission,
- PropertyKey, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty,
+ PropertyKey, PropertyKeyPermission, Properties, PropertyScope, TrySetProperty, TokenChild,
};
use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm};
use pallet_common::{
@@ -604,7 +604,7 @@
// =========
- <PalletStructure<T>>::unnest_if_nested(from, collection.id, token);
+ <PalletStructure<T>>::unnest_if_nested(&token_data.owner, collection.id, token);
<TokenData<T>>::insert(
(collection.id, token),
@@ -988,6 +988,15 @@
.is_some()
}
+ pub fn token_children_ids(collection_id: CollectionId, token_id: TokenId) -> Vec<TokenChild> {
+ <TokenChildren<T>>::iter_prefix((collection_id, token_id))
+ .map(|((child_collection_id, child_id), _)| TokenChild {
+ collection: child_collection_id,
+ token: child_id,
+ })
+ .collect()
+ }
+
/// Delegated to `create_multiple_items`
pub fn create_item(
collection: &NonfungibleHandle<T>,
pallets/structure/src/lib.rsdiffbeforeafterboth--- a/pallets/structure/src/lib.rs
+++ b/pallets/structure/src/lib.rs
@@ -191,8 +191,8 @@
token_id: TokenId,
nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(under, |d, parent_id| {
- d.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)
+ Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {
+ collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)
})
}
@@ -203,10 +203,10 @@
token_id: TokenId,
nesting_budget: &dyn Budget,
) -> DispatchResult {
- Self::try_exec_if_owner_is_valid_nft(under, |d, parent_id| {
- d.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;
+ Self::try_exec_if_owner_is_valid_nft(under, |collection, parent_id| {
+ collection.check_nesting(from, (collection_id, token_id), parent_id, nesting_budget)?;
- d.nest(parent_id, (collection_id, token_id));
+ collection.nest(parent_id, (collection_id, token_id));
Ok(())
})
@@ -217,8 +217,8 @@
collection_id: CollectionId,
token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(owner, |d, parent_id| {
- d.nest(parent_id, (collection_id, token_id))
+ Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {
+ collection.nest(parent_id, (collection_id, token_id))
});
}
@@ -227,8 +227,8 @@
collection_id: CollectionId,
token_id: TokenId,
) {
- Self::exec_if_owner_is_valid_nft(owner, |d, parent_id| {
- d.unnest(parent_id, (collection_id, token_id))
+ Self::exec_if_owner_is_valid_nft(owner, |collection, parent_id| {
+ collection.unnest(parent_id, (collection_id, token_id))
});
}
@@ -236,8 +236,8 @@
account: &T::CrossAccountId,
action: impl FnOnce(&dyn CommonCollectionOperations<T>, TokenId),
) {
- Self::try_exec_if_owner_is_valid_nft(account, |d, id| {
- action(d, id);
+ Self::try_exec_if_owner_is_valid_nft(account, |collection, id| {
+ action(collection, id);
Ok(())
})
.unwrap();
primitives/data-structs/src/lib.rsdiffbeforeafterboth--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -585,6 +585,14 @@
#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+// todo possibly rename to be used generally as an address pair
+pub struct TokenChild {
+ pub token: TokenId,
+ pub collection: CollectionId,
+}
+
+#[derive(Encode, Decode, MaxEncodedLen, PartialEq, Clone, Debug, TypeInfo)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct CollectionStats {
pub created: u32,
pub destroyed: u32,
primitives/rpc/src/lib.rsdiffbeforeafterboth--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -18,7 +18,7 @@
use up_data_structs::{
CollectionId, TokenId, RpcCollection, CollectionStats, CollectionLimits, Property,
- PropertyKeyPermission, TokenData,
+ PropertyKeyPermission, TokenData, TokenChild,
};
use sp_std::vec::Vec;
use codec::Decode;
@@ -41,6 +41,7 @@
fn token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result<Option<CrossAccountId>>;
+ fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>>;
fn collection_properties(collection: CollectionId, properties: Option<Vec<Vec<u8>>>) -> Result<Vec<Property>>;
runtime/common/src/runtime_apis.rsdiffbeforeafterboth--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -29,7 +29,9 @@
Ok(Some(<pallet_structure::Pallet<Runtime>>::find_topmost_owner(collection, token, &budget)?))
}
-
+ fn token_children(collection: CollectionId, token: TokenId) -> Result<Vec<TokenChild>, DispatchError> {
+ Ok(<pallet_nonfungible::Pallet<Runtime>>::token_children_ids(collection, token))
+ }
fn collection_properties(
collection: CollectionId,
keys: Option<Vec<Vec<u8>>>
runtime/opal/src/lib.rsdiffbeforeafterboth--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -73,6 +73,7 @@
CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
CollectionStats, RpcCollection,
mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
+ TokenChild,
};
// use pallet_contracts::weights::WeightInfo;
runtime/quartz/src/lib.rsdiffbeforeafterboth--- a/runtime/quartz/src/lib.rs
+++ b/runtime/quartz/src/lib.rs
@@ -72,7 +72,8 @@
use up_data_structs::{
CollectionId, TokenId, TokenData, Property, PropertyKeyPermission, CollectionLimits,
CollectionStats, RpcCollection,
- mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping}
+ mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping},
+ TokenChild,
};
// use pallet_contracts::weights::WeightInfo;
runtime/tests/src/tests.rsdiffbeforeafterboth--- a/runtime/tests/src/tests.rs
+++ b/runtime/tests/src/tests.rs
@@ -21,7 +21,7 @@
CreateReFungibleData, MAX_DECIMAL_POINTS, COLLECTION_ADMINS_LIMIT, TokenId,
MAX_TOKEN_OWNERSHIP, CreateCollectionData, CollectionMode, AccessMode, CollectionPermissions,
PropertyKeyPermission, PropertyPermission, Property, CollectionPropertiesVec,
- CollectionPropertiesPermissionsVec,
+ CollectionPropertiesPermissionsVec, TokenChild,
};
use frame_support::{assert_noop, assert_ok, assert_err};
use sp_std::convert::TryInto;
tests/src/interfaces/augment-api-query.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-query.ts
+++ b/tests/src/interfaces/augment-api-query.ts
@@ -5,7 +5,7 @@
import type { BTreeMap, Bytes, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';
import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';
-import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumLog, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsPropertyPermission, UpDataStructsTokenChild } from '@polkadot/types/lookup';
import type { Observable } from '@polkadot/types/types';
declare module '@polkadot/api-base/types/storage' {
@@ -88,7 +88,7 @@
/**
* Not used by code, exists only to provide some types to metadata
**/
- dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
+ dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, UpDataStructsTokenChild, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;
/**
* List of collection admins
**/
tests/src/interfaces/augment-api-rpc.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-api-rpc.ts
+++ b/tests/src/interfaces/augment-api-rpc.ts
@@ -1,7 +1,7 @@
// Auto-generated via `yarn polkadot-types-from-chain`, do not edit
/* eslint-disable */
-import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenData } from './default';
+import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenChild, UpDataStructsTokenData } from './default';
import type { AugmentedRpc } from '@polkadot/rpc-core/types';
import type { Metadata, StorageKey } from '@polkadot/types';
import type { Bytes, HashMap, Json, Null, Option, Text, U256, U64, Vec, bool, u128, u32, u64 } from '@polkadot/types-codec';
@@ -639,6 +639,10 @@
**/
propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
/**
+ * Get tokens nested directly into the token
+ **/
+ tokenChildren: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsTokenChild>>>;
+ /**
* Get token data
**/
tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys?: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
tests/src/interfaces/augment-types.tsdiffbeforeafterboth--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -1,7 +1,7 @@
// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
/* eslint-disable */
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
import type { Data, StorageKey } from '@polkadot/types';
import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, i128, i16, i256, i32, i64, i8, u128, u16, u256, u32, u64, u8, usize } from '@polkadot/types-codec';
import type { AssetApproval, AssetApprovalKey, AssetBalance, AssetDestroyWitness, AssetDetails, AssetMetadata, TAssetBalance, TAssetDepositBalance } from '@polkadot/types/interfaces/assets';
@@ -1210,6 +1210,7 @@
UpDataStructsRpcCollection: UpDataStructsRpcCollection;
UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
+ UpDataStructsTokenChild: UpDataStructsTokenChild;
UpDataStructsTokenData: UpDataStructsTokenData;
UpgradeGoAhead: UpgradeGoAhead;
UpgradeRestriction: UpgradeRestriction;
tests/src/interfaces/default/types.tsdiffbeforeafterboth--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1588,7 +1588,7 @@
}
/** @name PhantomTypeUpDataStructs */
-export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkNftInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkTheme, UpDataStructsRmrkNftChild]>> {}
+export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkNftInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkTheme, UpDataStructsRmrkNftChild]>> {}
/** @name PolkadotCorePrimitivesInboundDownwardMessage */
export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
@@ -1861,7 +1861,6 @@
/** @name UpDataStructsCreateNftData */
export interface UpDataStructsCreateNftData extends Struct {
- readonly constData: Bytes;
readonly properties: Vec<UpDataStructsProperty>;
}
@@ -2101,6 +2100,12 @@
readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
}
+/** @name UpDataStructsTokenChild */
+export interface UpDataStructsTokenChild extends Struct {
+ readonly token: u32;
+ readonly collection: u32;
+}
+
/** @name UpDataStructsTokenData */
export interface UpDataStructsTokenData extends Struct {
readonly properties: Vec<UpDataStructsProperty>;
tests/src/interfaces/lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -1479,17 +1479,16 @@
* Lookup186: up_data_structs::CreateNftData
**/
UpDataStructsCreateNftData: {
- constData: 'Bytes',
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup188: up_data_structs::CreateFungibleData
+ * Lookup187: up_data_structs::CreateFungibleData
**/
UpDataStructsCreateFungibleData: {
value: 'u128'
},
/**
- * Lookup189: up_data_structs::CreateReFungibleData
+ * Lookup188: up_data_structs::CreateReFungibleData
**/
UpDataStructsCreateReFungibleData: {
constData: 'Bytes',
@@ -2282,18 +2281,25 @@
alive: 'u32'
},
/**
- * Lookup323: PhantomType::up_data_structs<T>
+ * Lookup323: up_data_structs::TokenChild
**/
- PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,PalletEvmAccountBasicCrossAccountIdRepr,UpDataStructsRmrkCollectionInfo,UpDataStructsRmrkNftInfo,UpDataStructsRmrkResourceInfo,UpDataStructsRmrkPropertyInfo,UpDataStructsRmrkBaseInfo,UpDataStructsRmrkPartType,UpDataStructsRmrkTheme,UpDataStructsRmrkNftChild);0]',
+ UpDataStructsTokenChild: {
+ token: 'u32',
+ collection: 'u32'
+ },
+ /**
+ * Lookup324: PhantomType::up_data_structs<T>
+ **/
+ PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,UpDataStructsRmrkCollectionInfo,UpDataStructsRmrkNftInfo,UpDataStructsRmrkResourceInfo,UpDataStructsRmrkPropertyInfo,UpDataStructsRmrkBaseInfo,UpDataStructsRmrkPartType,UpDataStructsRmrkTheme,UpDataStructsRmrkNftChild);0]',
/**
- * Lookup325: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup326: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
UpDataStructsTokenData: {
properties: 'Vec<UpDataStructsProperty>',
owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>'
},
/**
- * Lookup327: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+ * Lookup328: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
**/
UpDataStructsRpcCollection: {
owner: 'AccountId32',
@@ -2308,7 +2314,7 @@
properties: 'Vec<UpDataStructsProperty>'
},
/**
- * Lookup328: up_data_structs::rmrk::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
+ * Lookup329: up_data_structs::rmrk::CollectionInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
**/
UpDataStructsRmrkCollectionInfo: {
issuer: 'AccountId32',
@@ -2318,7 +2324,7 @@
nftsCount: 'u32'
},
/**
- * Lookup331: up_data_structs::rmrk::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup332: up_data_structs::rmrk::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkNftInfo: {
owner: 'UpDataStructsRmrkAccountIdOrCollectionNftTuple',
@@ -2328,7 +2334,7 @@
pending: 'bool'
},
/**
- * Lookup332: up_data_structs::rmrk::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
+ * Lookup333: up_data_structs::rmrk::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
**/
UpDataStructsRmrkAccountIdOrCollectionNftTuple: {
_enum: {
@@ -2337,14 +2343,14 @@
}
},
/**
- * Lookup334: up_data_structs::rmrk::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
+ * Lookup335: up_data_structs::rmrk::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
**/
UpDataStructsRmrkRoyaltyInfo: {
recipient: 'AccountId32',
amount: 'Permill'
},
/**
- * Lookup335: up_data_structs::rmrk::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup336: up_data_structs::rmrk::ResourceInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkResourceInfo: {
id: 'Bytes',
@@ -2353,7 +2359,7 @@
pendingRemoval: 'bool'
},
/**
- * Lookup338: up_data_structs::rmrk::ResourceTypes<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup339: up_data_structs::rmrk::ResourceTypes<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkResourceTypes: {
_enum: {
@@ -2363,7 +2369,7 @@
}
},
/**
- * Lookup339: up_data_structs::rmrk::BasicResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup340: up_data_structs::rmrk::BasicResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkBasicResource: {
src: 'Option<Bytes>',
@@ -2372,7 +2378,7 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup341: up_data_structs::rmrk::ComposableResource<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup342: up_data_structs::rmrk::ComposableResource<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkComposableResource: {
parts: 'Vec<u32>',
@@ -2383,7 +2389,7 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup342: up_data_structs::rmrk::SlotResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup343: up_data_structs::rmrk::SlotResource<frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkSlotResource: {
base: 'u32',
@@ -2394,14 +2400,14 @@
thumb: 'Option<Bytes>'
},
/**
- * Lookup343: up_data_structs::rmrk::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup344: up_data_structs::rmrk::PropertyInfo<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkPropertyInfo: {
key: 'Bytes',
value: 'Bytes'
},
/**
- * Lookup346: up_data_structs::rmrk::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup347: up_data_structs::rmrk::BaseInfo<sp_core::crypto::AccountId32, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkBaseInfo: {
issuer: 'AccountId32',
@@ -2409,7 +2415,7 @@
symbol: 'Bytes'
},
/**
- * Lookup347: up_data_structs::rmrk::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup348: up_data_structs::rmrk::PartType<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkPartType: {
_enum: {
@@ -2418,7 +2424,7 @@
}
},
/**
- * Lookup349: up_data_structs::rmrk::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup350: up_data_structs::rmrk::FixedPart<frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkFixedPart: {
id: 'u32',
@@ -2426,7 +2432,7 @@
src: 'Bytes'
},
/**
- * Lookup350: up_data_structs::rmrk::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup351: up_data_structs::rmrk::SlotPart<frame_support::storage::bounded_vec::BoundedVec<T, S>, frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkSlotPart: {
id: 'u32',
@@ -2435,7 +2441,7 @@
z: 'u32'
},
/**
- * Lookup351: up_data_structs::rmrk::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup352: up_data_structs::rmrk::EquippableList<frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkEquippableList: {
_enum: {
@@ -2445,7 +2451,7 @@
}
},
/**
- * Lookup352: up_data_structs::rmrk::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, PropertyList>
+ * Lookup353: up_data_structs::rmrk::Theme<frame_support::storage::bounded_vec::BoundedVec<T, S>, PropertyList>
**/
UpDataStructsRmrkTheme: {
name: 'Bytes',
@@ -2453,69 +2459,69 @@
inherit: 'bool'
},
/**
- * Lookup354: up_data_structs::rmrk::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>
+ * Lookup355: up_data_structs::rmrk::ThemeProperty<frame_support::storage::bounded_vec::BoundedVec<T, S>>
**/
UpDataStructsRmrkThemeProperty: {
key: 'Bytes',
value: 'Bytes'
},
/**
- * Lookup355: up_data_structs::rmrk::NftChild
+ * Lookup356: up_data_structs::rmrk::NftChild
**/
UpDataStructsRmrkNftChild: {
collectionId: 'u32',
nftId: 'u32'
},
/**
- * Lookup357: pallet_common::pallet::Error<T>
+ * Lookup358: pallet_common::pallet::Error<T>
**/
PalletCommonError: {
_enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'NestingIsDisabled', 'OnlyOwnerAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey']
},
/**
- * Lookup359: pallet_fungible::pallet::Error<T>
+ * Lookup360: pallet_fungible::pallet::Error<T>
**/
PalletFungibleError: {
_enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
},
/**
- * Lookup360: pallet_refungible::ItemData
+ * Lookup361: pallet_refungible::ItemData
**/
PalletRefungibleItemData: {
constData: 'Bytes'
},
/**
- * Lookup364: pallet_refungible::pallet::Error<T>
+ * Lookup365: pallet_refungible::pallet::Error<T>
**/
PalletRefungibleError: {
_enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
},
/**
- * Lookup365: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+ * Lookup366: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
**/
PalletNonfungibleItemData: {
owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
},
/**
- * Lookup367: pallet_nonfungible::pallet::Error<T>
+ * Lookup368: pallet_nonfungible::pallet::Error<T>
**/
PalletNonfungibleError: {
_enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
},
/**
- * Lookup368: pallet_structure::pallet::Error<T>
+ * Lookup369: pallet_structure::pallet::Error<T>
**/
PalletStructureError: {
_enum: ['OuroborosDetected', 'DepthLimit', 'TokenNotFound']
},
/**
- * Lookup371: pallet_evm::pallet::Error<T>
+ * Lookup372: pallet_evm::pallet::Error<T>
**/
PalletEvmError: {
_enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']
},
/**
- * Lookup374: fp_rpc::TransactionStatus
+ * Lookup375: fp_rpc::TransactionStatus
**/
FpRpcTransactionStatus: {
transactionHash: 'H256',
@@ -2527,11 +2533,11 @@
logsBloom: 'EthbloomBloom'
},
/**
- * Lookup376: ethbloom::Bloom
+ * Lookup377: ethbloom::Bloom
**/
EthbloomBloom: '[u8;256]',
/**
- * Lookup378: ethereum::receipt::ReceiptV3
+ * Lookup379: ethereum::receipt::ReceiptV3
**/
EthereumReceiptReceiptV3: {
_enum: {
@@ -2541,7 +2547,7 @@
}
},
/**
- * Lookup379: ethereum::receipt::EIP658ReceiptData
+ * Lookup380: ethereum::receipt::EIP658ReceiptData
**/
EthereumReceiptEip658ReceiptData: {
statusCode: 'u8',
@@ -2550,7 +2556,7 @@
logs: 'Vec<EthereumLog>'
},
/**
- * Lookup380: ethereum::block::Block<ethereum::transaction::TransactionV2>
+ * Lookup381: ethereum::block::Block<ethereum::transaction::TransactionV2>
**/
EthereumBlock: {
header: 'EthereumHeader',
@@ -2558,7 +2564,7 @@
ommers: 'Vec<EthereumHeader>'
},
/**
- * Lookup381: ethereum::header::Header
+ * Lookup382: ethereum::header::Header
**/
EthereumHeader: {
parentHash: 'H256',
@@ -2578,41 +2584,41 @@
nonce: 'EthereumTypesHashH64'
},
/**
- * Lookup382: ethereum_types::hash::H64
+ * Lookup383: ethereum_types::hash::H64
**/
EthereumTypesHashH64: '[u8;8]',
/**
- * Lookup387: pallet_ethereum::pallet::Error<T>
+ * Lookup388: pallet_ethereum::pallet::Error<T>
**/
PalletEthereumError: {
_enum: ['InvalidSignature', 'PreLogExists']
},
/**
- * Lookup388: pallet_evm_coder_substrate::pallet::Error<T>
+ * Lookup389: pallet_evm_coder_substrate::pallet::Error<T>
**/
PalletEvmCoderSubstrateError: {
_enum: ['OutOfGas', 'OutOfFund']
},
/**
- * Lookup389: pallet_evm_contract_helpers::SponsoringModeT
+ * Lookup390: pallet_evm_contract_helpers::SponsoringModeT
**/
PalletEvmContractHelpersSponsoringModeT: {
_enum: ['Disabled', 'Allowlisted', 'Generous']
},
/**
- * Lookup391: pallet_evm_contract_helpers::pallet::Error<T>
+ * Lookup392: pallet_evm_contract_helpers::pallet::Error<T>
**/
PalletEvmContractHelpersError: {
_enum: ['NoPermission']
},
/**
- * Lookup392: pallet_evm_migration::pallet::Error<T>
+ * Lookup393: pallet_evm_migration::pallet::Error<T>
**/
PalletEvmMigrationError: {
_enum: ['AccountNotEmpty', 'AccountIsNotMigrating']
},
/**
- * Lookup394: sp_runtime::MultiSignature
+ * Lookup395: sp_runtime::MultiSignature
**/
SpRuntimeMultiSignature: {
_enum: {
@@ -2622,43 +2628,43 @@
}
},
/**
- * Lookup395: sp_core::ed25519::Signature
+ * Lookup396: sp_core::ed25519::Signature
**/
SpCoreEd25519Signature: '[u8;64]',
/**
- * Lookup397: sp_core::sr25519::Signature
+ * Lookup398: sp_core::sr25519::Signature
**/
SpCoreSr25519Signature: '[u8;64]',
/**
- * Lookup398: sp_core::ecdsa::Signature
+ * Lookup399: sp_core::ecdsa::Signature
**/
SpCoreEcdsaSignature: '[u8;65]',
/**
- * Lookup401: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+ * Lookup402: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
**/
FrameSystemExtensionsCheckSpecVersion: 'Null',
/**
- * Lookup402: frame_system::extensions::check_genesis::CheckGenesis<T>
+ * Lookup403: frame_system::extensions::check_genesis::CheckGenesis<T>
**/
FrameSystemExtensionsCheckGenesis: 'Null',
/**
- * Lookup405: frame_system::extensions::check_nonce::CheckNonce<T>
+ * Lookup406: frame_system::extensions::check_nonce::CheckNonce<T>
**/
FrameSystemExtensionsCheckNonce: 'Compact<u32>',
/**
- * Lookup406: frame_system::extensions::check_weight::CheckWeight<T>
+ * Lookup407: frame_system::extensions::check_weight::CheckWeight<T>
**/
FrameSystemExtensionsCheckWeight: 'Null',
/**
- * Lookup407: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+ * Lookup408: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
**/
PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
/**
- * Lookup408: opal_runtime::Runtime
+ * Lookup409: opal_runtime::Runtime
**/
OpalRuntimeRuntime: 'Null',
/**
- * Lookup409: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+ * Lookup410: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
**/
PalletEthereumFakeTransactionFinalizer: 'Null'
};
tests/src/interfaces/registry.tsdiffbeforeafterboth--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -1,7 +1,7 @@
// Auto-generated via `yarn polkadot-types-from-defs`, do not edit
/* eslint-disable */
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmpQueueCall, CumulusPalletXcmpQueueError, CumulusPalletXcmpQueueEvent, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueInboundState, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueOutboundState, CumulusPalletXcmpQueueQueueConfigData, CumulusPrimitivesParachainInherentParachainInherentData, EthbloomBloom, EthereumBlock, EthereumHeader, EthereumLog, EthereumReceiptEip658ReceiptData, EthereumReceiptReceiptV3, EthereumTransactionAccessListItem, EthereumTransactionEip1559Transaction, EthereumTransactionEip2930Transaction, EthereumTransactionLegacyTransaction, EthereumTransactionTransactionAction, EthereumTransactionTransactionSignature, EthereumTransactionTransactionV2, EthereumTypesHashH64, EvmCoreErrorExitError, EvmCoreErrorExitFatal, EvmCoreErrorExitReason, EvmCoreErrorExitRevert, EvmCoreErrorExitSucceed, FpRpcTransactionStatus, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSupportWeightsDispatchClass, FrameSupportWeightsDispatchInfo, FrameSupportWeightsPays, FrameSupportWeightsPerDispatchClassU32, FrameSupportWeightsPerDispatchClassU64, FrameSupportWeightsPerDispatchClassWeightsPerClass, FrameSupportWeightsRuntimeDbWeight, FrameSupportWeightsWeightToFeeCoefficient, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeRuntime, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletFungibleError, PalletInflationCall, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTimestampCall, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletXcmCall, PalletXcmError, PalletXcmEvent, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRmrkAccountIdOrCollectionNftTuple, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkBasicResource, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkComposableResource, UpDataStructsRmrkEquippableList, UpDataStructsRmrkFixedPart, UpDataStructsRmrkNftChild, UpDataStructsRmrkNftInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkResourceTypes, UpDataStructsRmrkRoyaltyInfo, UpDataStructsRmrkSlotPart, UpDataStructsRmrkSlotResource, UpDataStructsRmrkTheme, UpDataStructsRmrkThemeProperty, UpDataStructsRpcCollection, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
declare module '@polkadot/types/types/registry' {
export interface InterfaceTypes {
@@ -188,6 +188,7 @@
UpDataStructsRpcCollection: UpDataStructsRpcCollection;
UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
+ UpDataStructsTokenChild: UpDataStructsTokenChild;
UpDataStructsTokenData: UpDataStructsTokenData;
XcmDoubleEncoded: XcmDoubleEncoded;
XcmV0Junction: XcmV0Junction;
tests/src/interfaces/types-lookup.tsdiffbeforeafterboth--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1604,16 +1604,15 @@
/** @name UpDataStructsCreateNftData (186) */
export interface UpDataStructsCreateNftData extends Struct {
- readonly constData: Bytes;
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsCreateFungibleData (188) */
+ /** @name UpDataStructsCreateFungibleData (187) */
export interface UpDataStructsCreateFungibleData extends Struct {
readonly value: u128;
}
- /** @name UpDataStructsCreateReFungibleData (189) */
+ /** @name UpDataStructsCreateReFungibleData (188) */
export interface UpDataStructsCreateReFungibleData extends Struct {
readonly constData: Bytes;
readonly pieces: u128;
@@ -2469,16 +2468,22 @@
readonly alive: u32;
}
- /** @name PhantomTypeUpDataStructs (323) */
- export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkNftInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkTheme, UpDataStructsRmrkNftChild]>> {}
+ /** @name UpDataStructsTokenChild (323) */
+ export interface UpDataStructsTokenChild extends Struct {
+ readonly token: u32;
+ readonly collection: u32;
+ }
+
+ /** @name PhantomTypeUpDataStructs (324) */
+ export interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, UpDataStructsRmrkCollectionInfo, UpDataStructsRmrkNftInfo, UpDataStructsRmrkResourceInfo, UpDataStructsRmrkPropertyInfo, UpDataStructsRmrkBaseInfo, UpDataStructsRmrkPartType, UpDataStructsRmrkTheme, UpDataStructsRmrkNftChild]>> {}
- /** @name UpDataStructsTokenData (325) */
+ /** @name UpDataStructsTokenData (326) */
export interface UpDataStructsTokenData extends Struct {
readonly properties: Vec<UpDataStructsProperty>;
readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
}
- /** @name UpDataStructsRpcCollection (327) */
+ /** @name UpDataStructsRpcCollection (328) */
export interface UpDataStructsRpcCollection extends Struct {
readonly owner: AccountId32;
readonly mode: UpDataStructsCollectionMode;
@@ -2492,7 +2497,7 @@
readonly properties: Vec<UpDataStructsProperty>;
}
- /** @name UpDataStructsRmrkCollectionInfo (328) */
+ /** @name UpDataStructsRmrkCollectionInfo (329) */
export interface UpDataStructsRmrkCollectionInfo extends Struct {
readonly issuer: AccountId32;
readonly metadata: Bytes;
@@ -2501,7 +2506,7 @@
readonly nftsCount: u32;
}
- /** @name UpDataStructsRmrkNftInfo (331) */
+ /** @name UpDataStructsRmrkNftInfo (332) */
export interface UpDataStructsRmrkNftInfo extends Struct {
readonly owner: UpDataStructsRmrkAccountIdOrCollectionNftTuple;
readonly royalty: Option<UpDataStructsRmrkRoyaltyInfo>;
@@ -2510,7 +2515,7 @@
readonly pending: bool;
}
- /** @name UpDataStructsRmrkAccountIdOrCollectionNftTuple (332) */
+ /** @name UpDataStructsRmrkAccountIdOrCollectionNftTuple (333) */
export interface UpDataStructsRmrkAccountIdOrCollectionNftTuple extends Enum {
readonly isAccountId: boolean;
readonly asAccountId: AccountId32;
@@ -2519,13 +2524,13 @@
readonly type: 'AccountId' | 'CollectionAndNftTuple';
}
- /** @name UpDataStructsRmrkRoyaltyInfo (334) */
+ /** @name UpDataStructsRmrkRoyaltyInfo (335) */
export interface UpDataStructsRmrkRoyaltyInfo extends Struct {
readonly recipient: AccountId32;
readonly amount: Permill;
}
- /** @name UpDataStructsRmrkResourceInfo (335) */
+ /** @name UpDataStructsRmrkResourceInfo (336) */
export interface UpDataStructsRmrkResourceInfo extends Struct {
readonly id: Bytes;
readonly resource: UpDataStructsRmrkResourceTypes;
@@ -2533,7 +2538,7 @@
readonly pendingRemoval: bool;
}
- /** @name UpDataStructsRmrkResourceTypes (338) */
+ /** @name UpDataStructsRmrkResourceTypes (339) */
export interface UpDataStructsRmrkResourceTypes extends Enum {
readonly isBasic: boolean;
readonly asBasic: UpDataStructsRmrkBasicResource;
@@ -2544,7 +2549,7 @@
readonly type: 'Basic' | 'Composable' | 'Slot';
}
- /** @name UpDataStructsRmrkBasicResource (339) */
+ /** @name UpDataStructsRmrkBasicResource (340) */
export interface UpDataStructsRmrkBasicResource extends Struct {
readonly src: Option<Bytes>;
readonly metadata: Option<Bytes>;
@@ -2552,7 +2557,7 @@
readonly thumb: Option<Bytes>;
}
- /** @name UpDataStructsRmrkComposableResource (341) */
+ /** @name UpDataStructsRmrkComposableResource (342) */
export interface UpDataStructsRmrkComposableResource extends Struct {
readonly parts: Vec<u32>;
readonly base: u32;
@@ -2562,7 +2567,7 @@
readonly thumb: Option<Bytes>;
}
- /** @name UpDataStructsRmrkSlotResource (342) */
+ /** @name UpDataStructsRmrkSlotResource (343) */
export interface UpDataStructsRmrkSlotResource extends Struct {
readonly base: u32;
readonly src: Option<Bytes>;
@@ -2572,20 +2577,20 @@
readonly thumb: Option<Bytes>;
}
- /** @name UpDataStructsRmrkPropertyInfo (343) */
+ /** @name UpDataStructsRmrkPropertyInfo (344) */
export interface UpDataStructsRmrkPropertyInfo extends Struct {
readonly key: Bytes;
readonly value: Bytes;
}
- /** @name UpDataStructsRmrkBaseInfo (346) */
+ /** @name UpDataStructsRmrkBaseInfo (347) */
export interface UpDataStructsRmrkBaseInfo extends Struct {
readonly issuer: AccountId32;
readonly baseType: Bytes;
readonly symbol: Bytes;
}
- /** @name UpDataStructsRmrkPartType (347) */
+ /** @name UpDataStructsRmrkPartType (348) */
export interface UpDataStructsRmrkPartType extends Enum {
readonly isFixedPart: boolean;
readonly asFixedPart: UpDataStructsRmrkFixedPart;
@@ -2594,14 +2599,14 @@
readonly type: 'FixedPart' | 'SlotPart';
}
- /** @name UpDataStructsRmrkFixedPart (349) */
+ /** @name UpDataStructsRmrkFixedPart (350) */
export interface UpDataStructsRmrkFixedPart extends Struct {
readonly id: u32;
readonly z: u32;
readonly src: Bytes;
}
- /** @name UpDataStructsRmrkSlotPart (350) */
+ /** @name UpDataStructsRmrkSlotPart (351) */
export interface UpDataStructsRmrkSlotPart extends Struct {
readonly id: u32;
readonly equippable: UpDataStructsRmrkEquippableList;
@@ -2609,7 +2614,7 @@
readonly z: u32;
}
- /** @name UpDataStructsRmrkEquippableList (351) */
+ /** @name UpDataStructsRmrkEquippableList (352) */
export interface UpDataStructsRmrkEquippableList extends Enum {
readonly isAll: boolean;
readonly isEmpty: boolean;
@@ -2618,26 +2623,26 @@
readonly type: 'All' | 'Empty' | 'Custom';
}
- /** @name UpDataStructsRmrkTheme (352) */
+ /** @name UpDataStructsRmrkTheme (353) */
export interface UpDataStructsRmrkTheme extends Struct {
readonly name: Bytes;
readonly properties: Vec<UpDataStructsRmrkThemeProperty>;
readonly inherit: bool;
}
- /** @name UpDataStructsRmrkThemeProperty (354) */
+ /** @name UpDataStructsRmrkThemeProperty (355) */
export interface UpDataStructsRmrkThemeProperty extends Struct {
readonly key: Bytes;
readonly value: Bytes;
}
- /** @name UpDataStructsRmrkNftChild (355) */
+ /** @name UpDataStructsRmrkNftChild (356) */
export interface UpDataStructsRmrkNftChild extends Struct {
readonly collectionId: u32;
readonly nftId: u32;
}
- /** @name PalletCommonError (357) */
+ /** @name PalletCommonError (358) */
export interface PalletCommonError extends Enum {
readonly isCollectionNotFound: boolean;
readonly isMustBeTokenOwner: boolean;
@@ -2675,7 +2680,7 @@
readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey';
}
- /** @name PalletFungibleError (359) */
+ /** @name PalletFungibleError (360) */
export interface PalletFungibleError extends Enum {
readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isFungibleItemsHaveNoId: boolean;
@@ -2685,12 +2690,12 @@
readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
}
- /** @name PalletRefungibleItemData (360) */
+ /** @name PalletRefungibleItemData (361) */
export interface PalletRefungibleItemData extends Struct {
readonly constData: Bytes;
}
- /** @name PalletRefungibleError (364) */
+ /** @name PalletRefungibleError (365) */
export interface PalletRefungibleError extends Enum {
readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isWrongRefungiblePieces: boolean;
@@ -2699,12 +2704,12 @@
readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
}
- /** @name PalletNonfungibleItemData (365) */
+ /** @name PalletNonfungibleItemData (366) */
export interface PalletNonfungibleItemData extends Struct {
readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
}
- /** @name PalletNonfungibleError (367) */
+ /** @name PalletNonfungibleError (368) */
export interface PalletNonfungibleError extends Enum {
readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
readonly isNonfungibleItemsHaveNoAmount: boolean;
@@ -2712,7 +2717,7 @@
readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
}
- /** @name PalletStructureError (368) */
+ /** @name PalletStructureError (369) */
export interface PalletStructureError extends Enum {
readonly isOuroborosDetected: boolean;
readonly isDepthLimit: boolean;
@@ -2720,7 +2725,7 @@
readonly type: 'OuroborosDetected' | 'DepthLimit' | 'TokenNotFound';
}
- /** @name PalletEvmError (371) */
+ /** @name PalletEvmError (372) */
export interface PalletEvmError extends Enum {
readonly isBalanceLow: boolean;
readonly isFeeOverflow: boolean;
@@ -2731,7 +2736,7 @@
readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
}
- /** @name FpRpcTransactionStatus (374) */
+ /** @name FpRpcTransactionStatus (375) */
export interface FpRpcTransactionStatus extends Struct {
readonly transactionHash: H256;
readonly transactionIndex: u32;
@@ -2742,10 +2747,10 @@
readonly logsBloom: EthbloomBloom;
}
- /** @name EthbloomBloom (376) */
+ /** @name EthbloomBloom (377) */
export interface EthbloomBloom extends U8aFixed {}
- /** @name EthereumReceiptReceiptV3 (378) */
+ /** @name EthereumReceiptReceiptV3 (379) */
export interface EthereumReceiptReceiptV3 extends Enum {
readonly isLegacy: boolean;
readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -2756,7 +2761,7 @@
readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
}
- /** @name EthereumReceiptEip658ReceiptData (379) */
+ /** @name EthereumReceiptEip658ReceiptData (380) */
export interface EthereumReceiptEip658ReceiptData extends Struct {
readonly statusCode: u8;
readonly usedGas: U256;
@@ -2764,14 +2769,14 @@
readonly logs: Vec<EthereumLog>;
}
- /** @name EthereumBlock (380) */
+ /** @name EthereumBlock (381) */
export interface EthereumBlock extends Struct {
readonly header: EthereumHeader;
readonly transactions: Vec<EthereumTransactionTransactionV2>;
readonly ommers: Vec<EthereumHeader>;
}
- /** @name EthereumHeader (381) */
+ /** @name EthereumHeader (382) */
export interface EthereumHeader extends Struct {
readonly parentHash: H256;
readonly ommersHash: H256;
@@ -2790,24 +2795,24 @@
readonly nonce: EthereumTypesHashH64;
}
- /** @name EthereumTypesHashH64 (382) */
+ /** @name EthereumTypesHashH64 (383) */
export interface EthereumTypesHashH64 extends U8aFixed {}
- /** @name PalletEthereumError (387) */
+ /** @name PalletEthereumError (388) */
export interface PalletEthereumError extends Enum {
readonly isInvalidSignature: boolean;
readonly isPreLogExists: boolean;
readonly type: 'InvalidSignature' | 'PreLogExists';
}
- /** @name PalletEvmCoderSubstrateError (388) */
+ /** @name PalletEvmCoderSubstrateError (389) */
export interface PalletEvmCoderSubstrateError extends Enum {
readonly isOutOfGas: boolean;
readonly isOutOfFund: boolean;
readonly type: 'OutOfGas' | 'OutOfFund';
}
- /** @name PalletEvmContractHelpersSponsoringModeT (389) */
+ /** @name PalletEvmContractHelpersSponsoringModeT (390) */
export interface PalletEvmContractHelpersSponsoringModeT extends Enum {
readonly isDisabled: boolean;
readonly isAllowlisted: boolean;
@@ -2815,20 +2820,20 @@
readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
}
- /** @name PalletEvmContractHelpersError (391) */
+ /** @name PalletEvmContractHelpersError (392) */
export interface PalletEvmContractHelpersError extends Enum {
readonly isNoPermission: boolean;
readonly type: 'NoPermission';
}
- /** @name PalletEvmMigrationError (392) */
+ /** @name PalletEvmMigrationError (393) */
export interface PalletEvmMigrationError extends Enum {
readonly isAccountNotEmpty: boolean;
readonly isAccountIsNotMigrating: boolean;
readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
}
- /** @name SpRuntimeMultiSignature (394) */
+ /** @name SpRuntimeMultiSignature (395) */
export interface SpRuntimeMultiSignature extends Enum {
readonly isEd25519: boolean;
readonly asEd25519: SpCoreEd25519Signature;
@@ -2839,34 +2844,34 @@
readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
}
- /** @name SpCoreEd25519Signature (395) */
+ /** @name SpCoreEd25519Signature (396) */
export interface SpCoreEd25519Signature extends U8aFixed {}
- /** @name SpCoreSr25519Signature (397) */
+ /** @name SpCoreSr25519Signature (398) */
export interface SpCoreSr25519Signature extends U8aFixed {}
- /** @name SpCoreEcdsaSignature (398) */
+ /** @name SpCoreEcdsaSignature (399) */
export interface SpCoreEcdsaSignature extends U8aFixed {}
- /** @name FrameSystemExtensionsCheckSpecVersion (401) */
+ /** @name FrameSystemExtensionsCheckSpecVersion (402) */
export type FrameSystemExtensionsCheckSpecVersion = Null;
- /** @name FrameSystemExtensionsCheckGenesis (402) */
+ /** @name FrameSystemExtensionsCheckGenesis (403) */
export type FrameSystemExtensionsCheckGenesis = Null;
- /** @name FrameSystemExtensionsCheckNonce (405) */
+ /** @name FrameSystemExtensionsCheckNonce (406) */
export interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
- /** @name FrameSystemExtensionsCheckWeight (406) */
+ /** @name FrameSystemExtensionsCheckWeight (407) */
export type FrameSystemExtensionsCheckWeight = Null;
- /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (407) */
+ /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (408) */
export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
- /** @name OpalRuntimeRuntime (408) */
+ /** @name OpalRuntimeRuntime (409) */
export type OpalRuntimeRuntime = Null;
- /** @name PalletEthereumFakeTransactionFinalizer (409) */
+ /** @name PalletEthereumFakeTransactionFinalizer (410) */
export type PalletEthereumFakeTransactionFinalizer = Null;
} // declare module
tests/src/interfaces/unique/definitions.tsdiffbeforeafterboth--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -50,6 +50,7 @@
allowance: fun('Get allowed amount', [collectionParam, crossAccountParam('sender'), crossAccountParam('spender'), tokenParam], 'u128'),
tokenOwner: fun('Get token owner', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
topmostTokenOwner: fun('Get token owner, in case of nested token - find parent recursive', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
+ tokenChildren: fun('Get tokens nested directly into the token', [collectionParam, tokenParam], 'Vec<UpDataStructsTokenChild>'),
constMetadata: fun('Get token constant metadata', [collectionParam, tokenParam], 'Vec<u8>'),
variableMetadata: fun('Get token variable metadata', [collectionParam, tokenParam], 'Vec<u8>'),
collectionProperties: fun(
tests/src/nesting/nest.test.tsdiffbeforeafterboth--- a/tests/src/nesting/nest.test.ts
+++ b/tests/src/nesting/nest.test.ts
@@ -7,6 +7,7 @@
createItemExpectSuccess,
enableAllowListExpectSuccess,
enablePublicMintingExpectSuccess,
+ getTokenChildren,
getTokenOwner,
getTopmostTokenOwner,
normalizeAccountId,
@@ -76,8 +77,8 @@
api,
alice,
api.tx.unique.transferFrom(
- normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),
- normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),
+ normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenA)}),
+ normalizeAccountId({Ethereum: tokenIdToAddress(collection, tokenB)}),
collection,
tokenC,
1,
@@ -88,6 +89,63 @@
});
});
+ it('Checks token children', async () => {
+ await usingApi(async api => {
+ const collectionA = await createCollectionExpectSuccess({mode: {type: 'NFT'}});
+ await setCollectionPermissionsExpectSuccess(alice, collectionA, {nesting: 'Owner'});
+ const collectionB = await createCollectionExpectSuccess({mode: {type: 'Fungible', decimalPoints: 0}});
+
+ const targetToken = await createItemExpectSuccess(alice, collectionA, 'NFT');
+ const targetAddress = {Ethereum: tokenIdToAddress(collectionA, targetToken)};
+ let children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(0, 'Children length check at creation');
+
+ // Create a nested NFT token
+ const tokenA = await createItemExpectSuccess(alice, collectionA, 'NFT', targetAddress);
+ children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(1, 'Children length check at nesting #1');
+ expect(children).to.have.deep.members([
+ {token: tokenA, collection: collectionA},
+ ], 'Children contents check at nesting #1');
+
+ // Create then nest
+ const tokenB = await createItemExpectSuccess(alice, collectionA, 'NFT');
+ await transferExpectSuccess(collectionA, tokenB, alice, targetAddress);
+ children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(2, 'Children length check at nesting #2');
+ expect(children).to.have.deep.members([
+ {token: tokenA, collection: collectionA},
+ {token: tokenB, collection: collectionA},
+ ], 'Children contents check at nesting #2');
+
+ // Move token B to a different user outside the nesting tree
+ await transferExpectSuccess(collectionA, tokenB, alice, bob);
+ children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(1, 'Children length check at unnesting');
+ expect(children).to.be.have.deep.members([
+ {token: tokenA, collection: collectionA},
+ ], 'Children contents check at unnesting');
+
+ // Create a fungible token in another collection and then nest
+ const tokenC = await createItemExpectSuccess(alice, collectionB, 'Fungible');
+ await transferExpectSuccess(collectionB, tokenC, alice, targetAddress, 1, 'Fungible');
+ children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(2, 'Children length check at nesting #3 (from another collection)');
+ expect(children).to.be.have.deep.members([
+ {token: tokenA, collection: collectionA},
+ {token: tokenC, collection: collectionB},
+ ], 'Children contents check at nesting #3 (from another collection)');
+
+ // Move the fungible token inside token A deeper in the nesting tree
+ await transferFromExpectSuccess(collectionB, tokenC, alice, targetAddress, {Ethereum: tokenIdToAddress(collectionA, tokenA)}, 1, 'Fungible');
+ children = await getTokenChildren(api, collectionA, targetToken);
+ expect(children.length).to.be.equal(1, 'Children length check at deeper nesting');
+ expect(children).to.be.have.deep.members([
+ {token: tokenA, collection: collectionA},
+ ], 'Children contents check at deeper nesting');
+ });
+ });
+
// ---------- Non-Fungible ----------
it('NFT: allows an Owner to nest/unnest their token', async () => {
tests/src/util/helpers.tsdiffbeforeafterboth--- a/tests/src/util/helpers.ts
+++ b/tests/src/util/helpers.ts
@@ -27,6 +27,7 @@
import {default as usingApi, executeTransaction, submitTransactionAsync, submitTransactionExpectFailAsync} from '../substrate/substrate-api';
import {hexToStr, strToUTF16, utf16ToStr} from './util';
import {UpDataStructsRpcCollection, UpDataStructsCreateItemData, UpDataStructsProperty} from '@polkadot/types/lookup';
+import {UpDataStructsTokenChild} from '../interfaces';
chai.use(chaiAsPromised);
const expect = chai.expect;
@@ -1165,6 +1166,13 @@
if (owner == null) throw new Error('owner == null');
return normalizeAccountId(owner);
}
+export async function getTokenChildren(
+ api: ApiPromise,
+ collectionId: number,
+ tokenId: number,
+): Promise<UpDataStructsTokenChild[]> {
+ return (await api.rpc.unique.tokenChildren(collectionId, tokenId)).toJSON() as any;
+}
export async function isTokenExists(
api: ApiPromise,
collectionId: number,