git.delta.rocks / unique-network / refs/commits / b47cba8662c4

difftreelog

test(properties)

Fahrrader2022-05-06parent: #761b2c7.patch.diff
in: master

13 files changed

modifiedtests/package.jsondiffbeforeafterboth
--- a/tests/package.json
+++ b/tests/package.json
@@ -34,6 +34,7 @@
     "testCollision": "mocha --timeout 9999999 -r ts-node/register ./src/collision-tests/*.test.ts",
     "testEvent": "mocha --timeout 9999999 -r ts-node/register ./src/check-event/*.test.ts",
     "testNesting": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/**.test.ts",
+    "testProperties": "mocha --timeout 9999999 -r ts-node/register ./**/properties.test.ts",
     "testMigrationStructure": "mocha --timeout 9999999 -r ts-node/register ./**/nesting/migration-check.test.ts",
     "testAddCollectionAdmin": "mocha --timeout 9999999 -r ts-node/register ./**/addCollectionAdmin.test.ts",
     "testSetSchemaVersion": "mocha --timeout 9999999 -r ts-node/register ./**/setSchemaVersion.test.ts",
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -271,9 +271,9 @@
        **/
       NotFungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
       /**
-       * Item properties are not allowed
+       * Setting item properties is not allowed
        **/
-      PropertiesNotAllowed: AugmentedError<ApiType>;
+      SettingPropertiesNotAllowed: AugmentedError<ApiType>;
       /**
        * Generic error
        **/
@@ -399,13 +399,13 @@
        **/
       NotRefungibleDataUsedToMintFungibleCollectionToken: AugmentedError<ApiType>;
       /**
-       * Item properties are not allowed
+       * Refungible token can't nest other tokens
        **/
-      PropertiesNotAllowed: AugmentedError<ApiType>;
+      RefungibleDisallowsNesting: AugmentedError<ApiType>;
       /**
-       * Refungible token can't nest other tokens
+       * Setting item properties is not allowed
        **/
-      RefungibleDisallowsNesting: AugmentedError<ApiType>;
+      SettingPropertiesNotAllowed: AugmentedError<ApiType>;
       /**
        * Maximum refungibility exceeded
        **/
modifiedtests/src/interfaces/augment-api-query.tsdiffbeforeafterboth
5import type { BTreeMap, Bytes, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';5import type { BTreeMap, Bytes, Option, U256, Vec, bool, u128, u16, u32, u64 } from '@polkadot/types-codec';
6import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';6import type { AnyNumber, ITuple } from '@polkadot/types-codec/types';
7import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';7import type { AccountId32, H160, H256 } from '@polkadot/types/interfaces/runtime';
8import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructs, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertyPermission } from '@polkadot/types/lookup';8import type { CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmpQueueInboundChannelDetails, CumulusPalletXcmpQueueOutboundChannelDetails, CumulusPalletXcmpQueueQueueConfigData, EthereumBlock, EthereumReceiptReceiptV3, EthereumTransactionTransactionV2, FpRpcTransactionStatus, FrameSupportWeightsPerDispatchClassU64, FrameSystemAccountInfo, FrameSystemEventRecord, FrameSystemLastRuntimeUpgradeInfo, FrameSystemPhase, OrmlVestingVestingSchedule, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesReleases, PalletBalancesReserveData, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmContractHelpersSponsoringModeT, PalletNonfungibleItemData, PalletRefungibleItemData, PalletTransactionPaymentReleases, PalletTreasuryProposal, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpRuntimeDigest, SpTrieStorageProof, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionStats, UpDataStructsProperties, UpDataStructsPropertyPermission } from '@polkadot/types/lookup';
9import type { Observable } from '@polkadot/types/types';9import type { Observable } from '@polkadot/types/types';
1010
11declare module '@polkadot/api-base/types/storage' {11declare module '@polkadot/api-base/types/storage' {
92 /**92 /**
93 * Not used by code, exists only to provide some types to metadata93 * Not used by code, exists only to provide some types to metadata
94 **/94 **/
95 dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, PhantomTypeUpDataStructs]>>>, []> & QueryableStorageEntry<ApiType, []>;95 dummyStorageValue: AugmentedQuery<ApiType, () => Observable<Option<ITuple<[UpDataStructsCollectionStats, u32, u32, PhantomTypeUpDataStructsTokenData, PhantomTypeUpDataStructsRpcCollection]>>>, []> & QueryableStorageEntry<ApiType, []>;
96 /**96 /**
97 * List of collection admins97 * List of collection admins
98 **/98 **/
modifiedtests/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, UpDataStructsRpcCollection } from './unique';
+import type { PalletEvmAccountBasicCrossAccountIdRepr, UpDataStructsCollectionLimits, UpDataStructsCollectionStats, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsRpcCollection, UpDataStructsTokenData } from './unique';
 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';
@@ -13,7 +13,6 @@
 import type { PrefixedStorageKey } from '@polkadot/types/interfaces/childstate';
 import type { AuthorityId } from '@polkadot/types/interfaces/consensus';
 import type { CodeUploadRequest, CodeUploadResult, ContractCallRequest, ContractExecResult, ContractInstantiateResult, InstantiateRequest } from '@polkadot/types/interfaces/contracts';
-import type { BlockStats } from '@polkadot/types/interfaces/dev';
 import type { CreatedBlock } from '@polkadot/types/interfaces/engine';
 import type { EthAccount, EthCallRequest, EthFilter, EthFilterChanges, EthLog, EthReceipt, EthRichBlock, EthSubKind, EthSubParams, EthSyncStatus, EthTransaction, EthTransactionRequest, EthWork } from '@polkadot/types/interfaces/eth';
 import type { Extrinsic } from '@polkadot/types/interfaces/extrinsics';
@@ -23,7 +22,7 @@
 import type { FeeDetails, RuntimeDispatchInfo } from '@polkadot/types/interfaces/payment';
 import type { RpcMethods } from '@polkadot/types/interfaces/rpc';
 import type { AccountId, BlockNumber, H160, H256, H64, Hash, Header, Index, Justification, KeyValue, SignedBlock, StorageData } from '@polkadot/types/interfaces/runtime';
-import type { MigrationStatusResult, ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
+import type { ReadProof, RuntimeVersion, TraceBlockResponse } from '@polkadot/types/interfaces/state';
 import type { ApplyExtrinsicResult, ChainProperties, ChainType, Health, NetworkState, NodeRole, PeerInfo, SyncState } from '@polkadot/types/interfaces/system';
 import type { IExtrinsic, Observable } from '@polkadot/types/types';
 
@@ -156,12 +155,6 @@
        * Upload new code without instantiating a contract from it
        **/
       uploadCode: AugmentedRpc<(uploadRequest: CodeUploadRequest | { origin?: any; code?: any; storageDepositLimit?: any } | string | Uint8Array, at?: BlockHash | string | Uint8Array) => Observable<CodeUploadResult>>;
-    };
-    dev: {
-      /**
-       * Reexecute the specified `block_hash` and gather statistics while doing so
-       **/
-      getBlockStats: AugmentedRpc<(at: Hash | string | Uint8Array) => Observable<Option<BlockStats>>>;
     };
     engine: {
       /**
@@ -341,9 +334,9 @@
     };
     grandpa: {
       /**
-       * Prove finality for the given block number, returning the Justification for the last block in the set.
+       * Prove finality for the range (begin; end] hash.
        **/
-      proveFinality: AugmentedRpc<(blockNumber: BlockNumber | AnyNumber | Uint8Array) => Observable<Option<EncodedFinalityProofs>>>;
+      proveFinality: AugmentedRpc<(begin: BlockHash | string | Uint8Array, end: BlockHash | string | Uint8Array, authoritiesSetId?: u64 | AnyNumber | Uint8Array) => Observable<Option<EncodedFinalityProofs>>>;
       /**
        * Returns the state of the current best round state as well as the ongoing background rounds
        **/
@@ -480,10 +473,6 @@
        * Provides a way to trace the re-execution of a single block
        **/
       traceBlock: AugmentedRpc<(block: Hash | string | Uint8Array, targets: Option<Text> | null | object | string | Uint8Array, storageKeys: Option<Text> | null | object | string | Uint8Array, methods: Option<Text> | null | object | string | Uint8Array) => Observable<TraceBlockResponse>>;
-      /**
-       * Check current migration state
-       **/
-      trieMigrationStatus: AugmentedRpc<(at?: BlockHash | string | Uint8Array) => Observable<MigrationStatusResult>>;
     };
     syncstate: {
       /**
@@ -631,6 +620,14 @@
        **/
       nextSponsored: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, account: PalletEvmAccountBasicCrossAccountIdRepr | { Substrate: any } | { Ethereum: any } | string | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<u64>>>;
       /**
+       * Get property permissions
+       **/
+      propertyPermissions: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsPropertyKeyPermission>>>;
+      /**
+       * Get token data
+       **/
+      tokenData: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<UpDataStructsTokenData>>;
+      /**
        * Check if token exists
        **/
       tokenExists: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<bool>>;
@@ -639,6 +636,10 @@
        **/
       tokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
       /**
+       * Get token properties
+       **/
+      tokenProperties: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, propertyKeys: Vec<Text> | (Text | string)[], at?: Hash | string | Uint8Array) => Observable<Vec<UpDataStructsProperty>>>;
+      /**
        * Get token owner, in case of nested token - find parent recursive
        **/
       topmostTokenOwner: AugmentedRpc<(collection: u32 | AnyNumber | Uint8Array, tokenId: u32 | AnyNumber | Uint8Array, at?: Hash | string | Uint8Array) => Observable<Option<PalletEvmAccountBasicCrossAccountIdRepr>>>;
modifiedtests/src/interfaces/augment-api-tx.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-tx.ts
+++ b/tests/src/interfaces/augment-api-tx.ts
@@ -378,7 +378,7 @@
        * - Weight of derivative `call` execution + 10,000.
        * # </weight>
        **/
-      sudo: AugmentedSubmittable<(call: Call) => SubmittableExtrinsic<ApiType>, [Call]>;
+      sudo: AugmentedSubmittable<(call: Call | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call]>;
       /**
        * Authenticates the sudo key and dispatches a function call with `Signed` origin from
        * a given account.
@@ -392,7 +392,7 @@
        * - Weight of derivative `call` execution + 10,000.
        * # </weight>
        **/
-      sudoAs: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, call: Call) => SubmittableExtrinsic<ApiType>, [MultiAddress, Call]>;
+      sudoAs: AugmentedSubmittable<(who: MultiAddress | { Id: any } | { Index: any } | { Raw: any } | { Address32: any } | { Address20: any } | string | Uint8Array, call: Call | string | Uint8Array) => SubmittableExtrinsic<ApiType>, [MultiAddress, Call]>;
       /**
        * Authenticates the sudo key and dispatches a function call with `Root` origin.
        * This function does not check the weight of the call, and instead allows the
@@ -405,7 +405,7 @@
        * - The weight of this call is defined by the caller.
        * # </weight>
        **/
-      sudoUncheckedWeight: AugmentedSubmittable<(call: Call, weight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, u64]>;
+      sudoUncheckedWeight: AugmentedSubmittable<(call: Call | string | Uint8Array, weight: u64 | AnyNumber | Uint8Array) => SubmittableExtrinsic<ApiType>, [Call, u64]>;
       /**
        * Generic tx
        **/
modifiedtests/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, FrameSupportStorageBoundedBTreeSet, 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, 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, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1AbridgedHrmpChannel, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsMetaUpdatePermission, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipState, 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 './unique';
+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, FrameSupportStorageBoundedBTreeSet, 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, 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, PhantomTypeUpDataStructsRpcCollection, PhantomTypeUpDataStructsTokenData, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV1AbridgedHostConfiguration, PolkadotPrimitivesV1AbridgedHrmpChannel, PolkadotPrimitivesV1PersistedValidationData, PolkadotPrimitivesV1UpgradeRestriction, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpTrieStorageProof, SpVersionRuntimeVersion, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionField, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExData, UpDataStructsMetaUpdatePermission, UpDataStructsNestingRule, UpDataStructsProperties, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsRpcCollection, UpDataStructsSchemaVersion, 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 './unique';
 import type { Data, StorageKey } from '@polkadot/types';
 import type { BitVec, Bool, Bytes, I128, I16, I256, I32, I64, I8, Json, Null, 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';
@@ -23,7 +23,6 @@
 import type { FundIndex, FundInfo, LastContribution, TrieIndex } from '@polkadot/types/interfaces/crowdloan';
 import type { ConfigData, MessageId, OverweightIndex, PageCounter, PageIndexData } from '@polkadot/types/interfaces/cumulus';
 import type { AccountVote, AccountVoteSplit, AccountVoteStandard, Conviction, Delegations, PreimageStatus, PreimageStatusAvailable, PriorLock, PropIndex, Proposal, ProxyState, ReferendumIndex, ReferendumInfo, ReferendumInfoFinished, ReferendumInfoTo239, ReferendumStatus, Tally, Voting, VotingDelegating, VotingDirect, VotingDirectVote } from '@polkadot/types/interfaces/democracy';
-import type { BlockStats } from '@polkadot/types/interfaces/dev';
 import type { ApprovalFlag, DefunctVoter, Renouncing, SetIndex, Vote, VoteIndex, VoteThreshold, VoterInfo } from '@polkadot/types/interfaces/elections';
 import type { CreatedBlock, ImportedAux } from '@polkadot/types/interfaces/engine';
 import type { BlockV0, BlockV1, BlockV2, EIP1559Transaction, EIP2930Transaction, EthAccessList, EthAccessListItem, EthAccount, EthAddress, EthBlock, EthBloom, EthCallRequest, EthFilter, EthFilterAddress, EthFilterChanges, EthFilterTopic, EthFilterTopicEntry, EthFilterTopicInner, EthHeader, EthLog, EthReceipt, EthRichBlock, EthRichHeader, EthStorageProof, EthSubKind, EthSubParams, EthSubResult, EthSyncInfo, EthSyncStatus, EthTransaction, EthTransactionAction, EthTransactionCondition, EthTransactionRequest, EthTransactionSignature, EthTransactionStatus, EthWork, EthereumAccountId, EthereumAddress, EthereumLookupSource, EthereumSignature, LegacyTransaction, TransactionV0, TransactionV1, TransactionV2 } from '@polkadot/types/interfaces/eth';
@@ -52,9 +51,9 @@
 import type { BeefyKey, FullIdentification, IdentificationTuple, Keys, MembershipProof, SessionIndex, SessionKeys1, SessionKeys10, SessionKeys10B, SessionKeys2, SessionKeys3, SessionKeys4, SessionKeys5, SessionKeys6, SessionKeys6B, SessionKeys7, SessionKeys7B, SessionKeys8, SessionKeys8B, SessionKeys9, SessionKeys9B, ValidatorCount } from '@polkadot/types/interfaces/session';
 import type { Bid, BidKind, SocietyJudgement, SocietyVote, StrikeCount, VouchingStatus } from '@polkadot/types/interfaces/society';
 import type { ActiveEraInfo, CompactAssignments, CompactAssignmentsTo257, CompactAssignmentsTo265, CompactAssignmentsWith16, CompactAssignmentsWith24, CompactScore, CompactScoreCompact, ElectionCompute, ElectionPhase, ElectionResult, ElectionScore, ElectionSize, ElectionStatus, EraIndex, EraPoints, EraRewardPoints, EraRewards, Exposure, ExtendedBalance, Forcing, IndividualExposure, KeyType, MomentOf, Nominations, NominatorIndex, NominatorIndexCompact, OffchainAccuracy, OffchainAccuracyCompact, PhragmenScore, Points, RawSolution, RawSolutionTo265, RawSolutionWith16, RawSolutionWith24, ReadySolution, RewardDestination, RewardPoint, RoundSnapshot, SeatHolder, SignedSubmission, SignedSubmissionOf, SignedSubmissionTo276, SlashJournalEntry, SlashingSpans, SlashingSpansTo204, SolutionOrSnapshotSize, SolutionSupport, SolutionSupports, SpanIndex, SpanRecord, StakingLedger, StakingLedgerTo223, StakingLedgerTo240, SubmissionIndicesOf, Supports, UnappliedSlash, UnappliedSlashOther, UnlockChunk, ValidatorIndex, ValidatorIndexCompact, ValidatorPrefs, ValidatorPrefsTo145, ValidatorPrefsTo196, ValidatorPrefsWithBlocked, ValidatorPrefsWithCommission, VoteWeight, Voter } from '@polkadot/types/interfaces/staking';
-import type { ApiId, BlockTrace, BlockTraceEvent, BlockTraceEventData, BlockTraceSpan, KeyValueOption, MigrationStatusResult, ReadProof, RuntimeVersion, RuntimeVersionApi, RuntimeVersionPartial, SpecVersion, StorageChangeSet, TraceBlockResponse, TraceError } from '@polkadot/types/interfaces/state';
+import type { ApiId, BlockTrace, BlockTraceEvent, BlockTraceEventData, BlockTraceSpan, KeyValueOption, ReadProof, RuntimeVersion, RuntimeVersionApi, RuntimeVersionPartial, SpecVersion, StorageChangeSet, TraceBlockResponse, TraceError } from '@polkadot/types/interfaces/state';
 import type { WeightToFeeCoefficient } from '@polkadot/types/interfaces/support';
-import type { AccountInfo, AccountInfoWithDualRefCount, AccountInfoWithProviders, AccountInfoWithRefCount, AccountInfoWithRefCountU8, AccountInfoWithTripleRefCount, ApplyExtrinsicResult, ArithmeticError, BlockLength, BlockWeights, ChainProperties, ChainType, ConsumedWeight, DigestOf, DispatchClass, DispatchError, DispatchErrorModule, DispatchErrorModuleU8a, DispatchErrorTo198, DispatchInfo, DispatchInfoTo190, DispatchInfoTo244, DispatchOutcome, DispatchResult, DispatchResultOf, DispatchResultTo198, Event, EventId, EventIndex, EventRecord, Health, InvalidTransaction, Key, LastRuntimeUpgradeInfo, NetworkState, NetworkStatePeerset, NetworkStatePeersetInfo, NodeRole, NotConnectedPeer, Peer, PeerEndpoint, PeerEndpointAddr, PeerInfo, PeerPing, PerDispatchClassU32, PerDispatchClassWeight, PerDispatchClassWeightsPerClass, Phase, RawOrigin, RefCount, RefCountTo259, SyncState, SystemOrigin, TokenError, TransactionValidityError, UnknownTransaction, WeightPerClass } from '@polkadot/types/interfaces/system';
+import type { AccountInfo, AccountInfoWithDualRefCount, AccountInfoWithProviders, AccountInfoWithRefCount, AccountInfoWithRefCountU8, AccountInfoWithTripleRefCount, ApplyExtrinsicResult, ArithmeticError, BlockLength, BlockWeights, ChainProperties, ChainType, ConsumedWeight, DigestOf, DispatchClass, DispatchError, DispatchErrorModule, DispatchErrorTo198, DispatchInfo, DispatchInfoTo190, DispatchInfoTo244, DispatchOutcome, DispatchResult, DispatchResultOf, DispatchResultTo198, Event, EventId, EventIndex, EventRecord, Health, InvalidTransaction, Key, LastRuntimeUpgradeInfo, NetworkState, NetworkStatePeerset, NetworkStatePeersetInfo, NodeRole, NotConnectedPeer, Peer, PeerEndpoint, PeerEndpointAddr, PeerInfo, PeerPing, PerDispatchClassU32, PerDispatchClassWeight, PerDispatchClassWeightsPerClass, Phase, RawOrigin, RefCount, RefCountTo259, SyncState, SystemOrigin, TokenError, TransactionValidityError, UnknownTransaction, WeightPerClass } from '@polkadot/types/interfaces/system';
 import type { Bounty, BountyIndex, BountyStatus, BountyStatusActive, BountyStatusCuratorProposed, BountyStatusPendingPayout, OpenTip, OpenTipFinderTo225, OpenTipTip, OpenTipTo225, TreasuryProposal } from '@polkadot/types/interfaces/treasury';
 import type { Multiplier } from '@polkadot/types/interfaces/txpayment';
 import type { ClassDetails, ClassId, ClassMetadata, DepositBalance, DepositBalanceOf, DestroyWitness, InstanceDetails, InstanceId, InstanceMetadata } from '@polkadot/types/interfaces/uniques';
@@ -154,7 +153,6 @@
     BlockNumber: BlockNumber;
     BlockNumberFor: BlockNumberFor;
     BlockNumberOf: BlockNumberOf;
-    BlockStats: BlockStats;
     BlockTrace: BlockTrace;
     BlockTraceEvent: BlockTraceEvent;
     BlockTraceEventData: BlockTraceEventData;
@@ -329,7 +327,6 @@
     DispatchClass: DispatchClass;
     DispatchError: DispatchError;
     DispatchErrorModule: DispatchErrorModule;
-    DispatchErrorModuleU8a: DispatchErrorModuleU8a;
     DispatchErrorTo198: DispatchErrorTo198;
     DispatchFeePayment: DispatchFeePayment;
     DispatchInfo: DispatchInfo;
@@ -661,7 +658,6 @@
     MetadataV13: MetadataV13;
     MetadataV14: MetadataV14;
     MetadataV9: MetadataV9;
-    MigrationStatusResult: MigrationStatusResult;
     MmrLeafProof: MmrLeafProof;
     MmrRootHash: MmrRootHash;
     ModuleConstantMetadataV10: ModuleConstantMetadataV10;
@@ -849,7 +845,8 @@
     PerU16: PerU16;
     Phantom: Phantom;
     PhantomData: PhantomData;
-    PhantomTypeUpDataStructs: PhantomTypeUpDataStructs;
+    PhantomTypeUpDataStructsRpcCollection: PhantomTypeUpDataStructsRpcCollection;
+    PhantomTypeUpDataStructsTokenData: PhantomTypeUpDataStructsTokenData;
     Phase: Phase;
     PhragmenScore: PhragmenScore;
     Points: Points;
@@ -1189,6 +1186,7 @@
     UpDataStructsSchemaVersion: UpDataStructsSchemaVersion;
     UpDataStructsSponsoringRateLimit: UpDataStructsSponsoringRateLimit;
     UpDataStructsSponsorshipState: UpDataStructsSponsorshipState;
+    UpDataStructsTokenData: UpDataStructsTokenData;
     UpgradeGoAhead: UpgradeGoAhead;
     UpgradeRestriction: UpgradeRestriction;
     UpwardMessage: UpwardMessage;
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -23,7 +23,7 @@
    * Lookup10: sp_trie::storage_proof::StorageProof
    **/
   SpTrieStorageProof: {
-    trieNodes: 'BTreeSet<Bytes>'
+    trieNodes: 'Vec<Bytes>'
   },
   /**
    * Lookup13: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
@@ -1469,7 +1469,7 @@
   /**
    * Lookup171: frame_support::storage::bounded_btree_set::BoundedBTreeSet<up_data_structs::CollectionId, S>
    **/
-  FrameSupportStorageBoundedBTreeSet: 'BTreeSet<u32>',
+  FrameSupportStorageBoundedBTreeSet: 'Vec<u32>',
   /**
    * Lookup177: up_data_structs::MetaUpdatePermission
    **/
@@ -1487,7 +1487,9 @@
    * Lookup181: up_data_structs::PropertyPermission
    **/
   UpDataStructsPropertyPermission: {
-    _enum: ['None', 'AdminConst', 'Admin', 'ItemOwnerConst', 'ItemOwner', 'ItemOwnerOrAdmin']
+    mutable: 'bool',
+    collectionAdmin: 'bool',
+    tokenOwner: 'bool'
   },
   /**
    * Lookup184: up_data_structs::Property
@@ -1520,7 +1522,8 @@
    **/
   UpDataStructsCreateNftData: {
     constData: 'Bytes',
-    variableData: 'Bytes'
+    variableData: 'Bytes',
+    properties: 'Vec<UpDataStructsProperty>'
   },
   /**
    * Lookup191: up_data_structs::CreateFungibleData
@@ -1553,6 +1556,7 @@
   UpDataStructsCreateNftExData: {
     constData: 'Bytes',
     variableData: 'Bytes',
+    properties: 'Vec<UpDataStructsProperty>',
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
@@ -2324,12 +2328,24 @@
     alive: 'u32'
   },
   /**
-   * Lookup325: PhantomType::up_data_structs<up_data_structs::RpcCollection<sp_core::crypto::AccountId32>>
+   * Lookup325: PhantomType::up_data_structs<up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>>
    **/
-  PhantomTypeUpDataStructs: '[Lookup326;0]',
+  PhantomTypeUpDataStructsTokenData: '[Lookup326;0]',
   /**
-   * Lookup326: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+   * Lookup326: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
+  UpDataStructsTokenData: {
+    constData: 'Bytes',
+    properties: 'Vec<UpDataStructsProperty>',
+    owner: 'Option<PalletEvmAccountBasicCrossAccountIdRepr>'
+  },
+  /**
+   * Lookup329: PhantomType::up_data_structs<up_data_structs::RpcCollection<sp_core::crypto::AccountId32>>
+   **/
+  PhantomTypeUpDataStructsRpcCollection: '[Lookup330;0]',
+  /**
+   * Lookup330: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+   **/
   UpDataStructsRpcCollection: {
     owner: 'AccountId32',
     mode: 'UpDataStructsCollectionMode',
@@ -2347,32 +2363,32 @@
     metaUpdatePermission: 'UpDataStructsMetaUpdatePermission'
   },
   /**
-   * Lookup328: pallet_common::pallet::Error<T>
+   * Lookup332: pallet_common::pallet::Error<T>
    **/
   PalletCommonError: {
     _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'TokenVariableDataLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'NestingIsDisabled', 'OnlyOwnerAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached']
   },
   /**
-   * Lookup330: pallet_fungible::pallet::Error<T>
+   * Lookup334: pallet_fungible::pallet::Error<T>
    **/
   PalletFungibleError: {
-    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'PropertiesNotAllowed']
+    _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup331: pallet_refungible::ItemData
+   * Lookup335: pallet_refungible::ItemData
    **/
   PalletRefungibleItemData: {
     constData: 'Bytes',
     variableData: 'Bytes'
   },
   /**
-   * Lookup335: pallet_refungible::pallet::Error<T>
+   * Lookup339: pallet_refungible::pallet::Error<T>
    **/
   PalletRefungibleError: {
-    _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RefungibleDisallowsNesting', 'PropertiesNotAllowed']
+    _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup336: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup340: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletNonfungibleItemData: {
     constData: 'Bytes',
@@ -2380,25 +2396,25 @@
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup337: pallet_nonfungible::pallet::Error<T>
+   * Lookup341: pallet_nonfungible::pallet::Error<T>
    **/
   PalletNonfungibleError: {
     _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount']
   },
   /**
-   * Lookup338: pallet_structure::pallet::Error<T>
+   * Lookup342: pallet_structure::pallet::Error<T>
    **/
   PalletStructureError: {
     _enum: ['OuroborosDetected', 'DepthLimit', 'TokenNotFound']
   },
   /**
-   * Lookup340: pallet_evm::pallet::Error<T>
+   * Lookup344: pallet_evm::pallet::Error<T>
    **/
   PalletEvmError: {
     _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce']
   },
   /**
-   * Lookup343: fp_rpc::TransactionStatus
+   * Lookup347: fp_rpc::TransactionStatus
    **/
   FpRpcTransactionStatus: {
     transactionHash: 'H256',
@@ -2410,11 +2426,11 @@
     logsBloom: 'EthbloomBloom'
   },
   /**
-   * Lookup346: ethbloom::Bloom
+   * Lookup350: ethbloom::Bloom
    **/
   EthbloomBloom: '[u8;256]',
   /**
-   * Lookup348: ethereum::receipt::ReceiptV3
+   * Lookup352: ethereum::receipt::ReceiptV3
    **/
   EthereumReceiptReceiptV3: {
     _enum: {
@@ -2424,7 +2440,7 @@
     }
   },
   /**
-   * Lookup349: ethereum::receipt::EIP658ReceiptData
+   * Lookup353: ethereum::receipt::EIP658ReceiptData
    **/
   EthereumReceiptEip658ReceiptData: {
     statusCode: 'u8',
@@ -2433,7 +2449,7 @@
     logs: 'Vec<EthereumLog>'
   },
   /**
-   * Lookup350: ethereum::block::Block<ethereum::transaction::TransactionV2>
+   * Lookup354: ethereum::block::Block<ethereum::transaction::TransactionV2>
    **/
   EthereumBlock: {
     header: 'EthereumHeader',
@@ -2441,7 +2457,7 @@
     ommers: 'Vec<EthereumHeader>'
   },
   /**
-   * Lookup351: ethereum::header::Header
+   * Lookup355: ethereum::header::Header
    **/
   EthereumHeader: {
     parentHash: 'H256',
@@ -2461,41 +2477,41 @@
     nonce: 'EthereumTypesHashH64'
   },
   /**
-   * Lookup352: ethereum_types::hash::H64
+   * Lookup356: ethereum_types::hash::H64
    **/
   EthereumTypesHashH64: '[u8;8]',
   /**
-   * Lookup357: pallet_ethereum::pallet::Error<T>
+   * Lookup361: pallet_ethereum::pallet::Error<T>
    **/
   PalletEthereumError: {
     _enum: ['InvalidSignature', 'PreLogExists']
   },
   /**
-   * Lookup358: pallet_evm_coder_substrate::pallet::Error<T>
+   * Lookup362: pallet_evm_coder_substrate::pallet::Error<T>
    **/
   PalletEvmCoderSubstrateError: {
     _enum: ['OutOfGas', 'OutOfFund']
   },
   /**
-   * Lookup359: pallet_evm_contract_helpers::SponsoringModeT
+   * Lookup363: pallet_evm_contract_helpers::SponsoringModeT
    **/
   PalletEvmContractHelpersSponsoringModeT: {
     _enum: ['Disabled', 'Allowlisted', 'Generous']
   },
   /**
-   * Lookup361: pallet_evm_contract_helpers::pallet::Error<T>
+   * Lookup365: pallet_evm_contract_helpers::pallet::Error<T>
    **/
   PalletEvmContractHelpersError: {
     _enum: ['NoPermission']
   },
   /**
-   * Lookup362: pallet_evm_migration::pallet::Error<T>
+   * Lookup366: pallet_evm_migration::pallet::Error<T>
    **/
   PalletEvmMigrationError: {
     _enum: ['AccountNotEmpty', 'AccountIsNotMigrating']
   },
   /**
-   * Lookup364: sp_runtime::MultiSignature
+   * Lookup368: sp_runtime::MultiSignature
    **/
   SpRuntimeMultiSignature: {
     _enum: {
@@ -2505,39 +2521,39 @@
     }
   },
   /**
-   * Lookup365: sp_core::ed25519::Signature
+   * Lookup369: sp_core::ed25519::Signature
    **/
   SpCoreEd25519Signature: '[u8;64]',
   /**
-   * Lookup367: sp_core::sr25519::Signature
+   * Lookup371: sp_core::sr25519::Signature
    **/
   SpCoreSr25519Signature: '[u8;64]',
   /**
-   * Lookup368: sp_core::ecdsa::Signature
+   * Lookup372: sp_core::ecdsa::Signature
    **/
   SpCoreEcdsaSignature: '[u8;65]',
   /**
-   * Lookup371: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+   * Lookup375: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
    **/
   FrameSystemExtensionsCheckSpecVersion: 'Null',
   /**
-   * Lookup372: frame_system::extensions::check_genesis::CheckGenesis<T>
+   * Lookup376: frame_system::extensions::check_genesis::CheckGenesis<T>
    **/
   FrameSystemExtensionsCheckGenesis: 'Null',
   /**
-   * Lookup375: frame_system::extensions::check_nonce::CheckNonce<T>
+   * Lookup379: frame_system::extensions::check_nonce::CheckNonce<T>
    **/
   FrameSystemExtensionsCheckNonce: 'Compact<u32>',
   /**
-   * Lookup376: frame_system::extensions::check_weight::CheckWeight<T>
+   * Lookup380: frame_system::extensions::check_weight::CheckWeight<T>
    **/
   FrameSystemExtensionsCheckWeight: 'Null',
   /**
-   * Lookup377: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+   * Lookup381: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
    **/
   PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
   /**
-   * Lookup378: opal_runtime::Runtime
+   * Lookup382: opal_runtime::Runtime
    **/
   OpalRuntimeRuntime: 'Null'
 };
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -2,7 +2,7 @@
 /* eslint-disable */
 
 declare module '@polkadot/types/lookup' {
-  import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+  import type { BTreeMap, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
   import type { ITuple } from '@polkadot/types-codec/types';
   import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
   import type { Event } from '@polkadot/types/interfaces/system';
@@ -23,7 +23,7 @@
 
   /** @name SpTrieStorageProof (10) */
   export interface SpTrieStorageProof extends Struct {
-    readonly trieNodes: BTreeSet<Bytes>;
+    readonly trieNodes: Vec<Bytes>;
   }
 
   /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (13) */
@@ -1605,7 +1605,7 @@
   }
 
   /** @name FrameSupportStorageBoundedBTreeSet (171) */
-  export interface FrameSupportStorageBoundedBTreeSet extends BTreeSet<u32> {}
+  export interface FrameSupportStorageBoundedBTreeSet extends Vec<u32> {}
 
   /** @name UpDataStructsMetaUpdatePermission (177) */
   export interface UpDataStructsMetaUpdatePermission extends Enum {
@@ -1622,14 +1622,10 @@
   }
 
   /** @name UpDataStructsPropertyPermission (181) */
-  export interface UpDataStructsPropertyPermission extends Enum {
-    readonly isNone: boolean;
-    readonly isAdminConst: boolean;
-    readonly isAdmin: boolean;
-    readonly isItemOwnerConst: boolean;
-    readonly isItemOwner: boolean;
-    readonly isItemOwnerOrAdmin: boolean;
-    readonly type: 'None' | 'AdminConst' | 'Admin' | 'ItemOwnerConst' | 'ItemOwner' | 'ItemOwnerOrAdmin';
+  export interface UpDataStructsPropertyPermission extends Struct {
+    readonly mutable: bool;
+    readonly collectionAdmin: bool;
+    readonly tokenOwner: bool;
   }
 
   /** @name UpDataStructsProperty (184) */
@@ -1662,6 +1658,7 @@
   export interface UpDataStructsCreateNftData extends Struct {
     readonly constData: Bytes;
     readonly variableData: Bytes;
+    readonly properties: Vec<UpDataStructsProperty>;
   }
 
   /** @name UpDataStructsCreateFungibleData (191) */
@@ -1693,6 +1690,7 @@
   export interface UpDataStructsCreateNftExData extends Struct {
     readonly constData: Bytes;
     readonly variableData: Bytes;
+    readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
@@ -2534,10 +2532,20 @@
     readonly alive: u32;
   }
 
-  /** @name PhantomTypeUpDataStructs (325) */
-  export interface PhantomTypeUpDataStructs extends Vec<UpDataStructsRpcCollection> {}
+  /** @name PhantomTypeUpDataStructsTokenData (325) */
+  export interface PhantomTypeUpDataStructsTokenData extends Vec<UpDataStructsTokenData> {}
+
+  /** @name UpDataStructsTokenData (326) */
+  export interface UpDataStructsTokenData extends Struct {
+    readonly constData: Bytes;
+    readonly properties: Vec<UpDataStructsProperty>;
+    readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+  }
+
+  /** @name PhantomTypeUpDataStructsRpcCollection (329) */
+  export interface PhantomTypeUpDataStructsRpcCollection extends Vec<UpDataStructsRpcCollection> {}
 
-  /** @name UpDataStructsRpcCollection (326) */
+  /** @name UpDataStructsRpcCollection (330) */
   export interface UpDataStructsRpcCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -2555,7 +2563,7 @@
     readonly metaUpdatePermission: UpDataStructsMetaUpdatePermission;
   }
 
-  /** @name PalletCommonError (328) */
+  /** @name PalletCommonError (332) */
   export interface PalletCommonError extends Enum {
     readonly isCollectionNotFound: boolean;
     readonly isMustBeTokenOwner: boolean;
@@ -2590,46 +2598,46 @@
     readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'TokenVariableDataLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'NestingIsDisabled' | 'OnlyOwnerAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached';
   }
 
-  /** @name PalletFungibleError (330) */
+  /** @name PalletFungibleError (334) */
   export interface PalletFungibleError extends Enum {
     readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isFungibleItemsHaveNoId: boolean;
     readonly isFungibleItemsDontHaveData: boolean;
     readonly isFungibleDisallowsNesting: boolean;
-    readonly isPropertiesNotAllowed: boolean;
-    readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'PropertiesNotAllowed';
+    readonly isSettingPropertiesNotAllowed: boolean;
+    readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletRefungibleItemData (331) */
+  /** @name PalletRefungibleItemData (335) */
   export interface PalletRefungibleItemData extends Struct {
     readonly constData: Bytes;
     readonly variableData: Bytes;
   }
 
-  /** @name PalletRefungibleError (335) */
+  /** @name PalletRefungibleError (339) */
   export interface PalletRefungibleError extends Enum {
     readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isWrongRefungiblePieces: boolean;
     readonly isRefungibleDisallowsNesting: boolean;
-    readonly isPropertiesNotAllowed: boolean;
-    readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'PropertiesNotAllowed';
+    readonly isSettingPropertiesNotAllowed: boolean;
+    readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletNonfungibleItemData (336) */
+  /** @name PalletNonfungibleItemData (340) */
   export interface PalletNonfungibleItemData extends Struct {
     readonly constData: Bytes;
     readonly variableData: Bytes;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name PalletNonfungibleError (337) */
+  /** @name PalletNonfungibleError (341) */
   export interface PalletNonfungibleError extends Enum {
     readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isNonfungibleItemsHaveNoAmount: boolean;
     readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount';
   }
 
-  /** @name PalletStructureError (338) */
+  /** @name PalletStructureError (342) */
   export interface PalletStructureError extends Enum {
     readonly isOuroborosDetected: boolean;
     readonly isDepthLimit: boolean;
@@ -2637,7 +2645,7 @@
     readonly type: 'OuroborosDetected' | 'DepthLimit' | 'TokenNotFound';
   }
 
-  /** @name PalletEvmError (340) */
+  /** @name PalletEvmError (344) */
   export interface PalletEvmError extends Enum {
     readonly isBalanceLow: boolean;
     readonly isFeeOverflow: boolean;
@@ -2648,7 +2656,7 @@
     readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce';
   }
 
-  /** @name FpRpcTransactionStatus (343) */
+  /** @name FpRpcTransactionStatus (347) */
   export interface FpRpcTransactionStatus extends Struct {
     readonly transactionHash: H256;
     readonly transactionIndex: u32;
@@ -2659,10 +2667,10 @@
     readonly logsBloom: EthbloomBloom;
   }
 
-  /** @name EthbloomBloom (346) */
+  /** @name EthbloomBloom (350) */
   export interface EthbloomBloom extends U8aFixed {}
 
-  /** @name EthereumReceiptReceiptV3 (348) */
+  /** @name EthereumReceiptReceiptV3 (352) */
   export interface EthereumReceiptReceiptV3 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -2673,7 +2681,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumReceiptEip658ReceiptData (349) */
+  /** @name EthereumReceiptEip658ReceiptData (353) */
   export interface EthereumReceiptEip658ReceiptData extends Struct {
     readonly statusCode: u8;
     readonly usedGas: U256;
@@ -2681,14 +2689,14 @@
     readonly logs: Vec<EthereumLog>;
   }
 
-  /** @name EthereumBlock (350) */
+  /** @name EthereumBlock (354) */
   export interface EthereumBlock extends Struct {
     readonly header: EthereumHeader;
     readonly transactions: Vec<EthereumTransactionTransactionV2>;
     readonly ommers: Vec<EthereumHeader>;
   }
 
-  /** @name EthereumHeader (351) */
+  /** @name EthereumHeader (355) */
   export interface EthereumHeader extends Struct {
     readonly parentHash: H256;
     readonly ommersHash: H256;
@@ -2707,24 +2715,24 @@
     readonly nonce: EthereumTypesHashH64;
   }
 
-  /** @name EthereumTypesHashH64 (352) */
+  /** @name EthereumTypesHashH64 (356) */
   export interface EthereumTypesHashH64 extends U8aFixed {}
 
-  /** @name PalletEthereumError (357) */
+  /** @name PalletEthereumError (361) */
   export interface PalletEthereumError extends Enum {
     readonly isInvalidSignature: boolean;
     readonly isPreLogExists: boolean;
     readonly type: 'InvalidSignature' | 'PreLogExists';
   }
 
-  /** @name PalletEvmCoderSubstrateError (358) */
+  /** @name PalletEvmCoderSubstrateError (362) */
   export interface PalletEvmCoderSubstrateError extends Enum {
     readonly isOutOfGas: boolean;
     readonly isOutOfFund: boolean;
     readonly type: 'OutOfGas' | 'OutOfFund';
   }
 
-  /** @name PalletEvmContractHelpersSponsoringModeT (359) */
+  /** @name PalletEvmContractHelpersSponsoringModeT (363) */
   export interface PalletEvmContractHelpersSponsoringModeT extends Enum {
     readonly isDisabled: boolean;
     readonly isAllowlisted: boolean;
@@ -2732,20 +2740,20 @@
     readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
   }
 
-  /** @name PalletEvmContractHelpersError (361) */
+  /** @name PalletEvmContractHelpersError (365) */
   export interface PalletEvmContractHelpersError extends Enum {
     readonly isNoPermission: boolean;
     readonly type: 'NoPermission';
   }
 
-  /** @name PalletEvmMigrationError (362) */
+  /** @name PalletEvmMigrationError (366) */
   export interface PalletEvmMigrationError extends Enum {
     readonly isAccountNotEmpty: boolean;
     readonly isAccountIsNotMigrating: boolean;
     readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating';
   }
 
-  /** @name SpRuntimeMultiSignature (364) */
+  /** @name SpRuntimeMultiSignature (368) */
   export interface SpRuntimeMultiSignature extends Enum {
     readonly isEd25519: boolean;
     readonly asEd25519: SpCoreEd25519Signature;
@@ -2756,31 +2764,31 @@
     readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
   }
 
-  /** @name SpCoreEd25519Signature (365) */
+  /** @name SpCoreEd25519Signature (369) */
   export interface SpCoreEd25519Signature extends U8aFixed {}
 
-  /** @name SpCoreSr25519Signature (367) */
+  /** @name SpCoreSr25519Signature (371) */
   export interface SpCoreSr25519Signature extends U8aFixed {}
 
-  /** @name SpCoreEcdsaSignature (368) */
+  /** @name SpCoreEcdsaSignature (372) */
   export interface SpCoreEcdsaSignature extends U8aFixed {}
 
-  /** @name FrameSystemExtensionsCheckSpecVersion (371) */
+  /** @name FrameSystemExtensionsCheckSpecVersion (375) */
   export type FrameSystemExtensionsCheckSpecVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckGenesis (372) */
+  /** @name FrameSystemExtensionsCheckGenesis (376) */
   export type FrameSystemExtensionsCheckGenesis = Null;
 
-  /** @name FrameSystemExtensionsCheckNonce (375) */
+  /** @name FrameSystemExtensionsCheckNonce (379) */
   export interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
 
-  /** @name FrameSystemExtensionsCheckWeight (376) */
+  /** @name FrameSystemExtensionsCheckWeight (380) */
   export type FrameSystemExtensionsCheckWeight = Null;
 
-  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (377) */
+  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (381) */
   export interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
 
-  /** @name OpalRuntimeRuntime (378) */
+  /** @name OpalRuntimeRuntime (382) */
   export type OpalRuntimeRuntime = Null;
 
 } // declare module
modifiedtests/src/interfaces/unique/definitions.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/definitions.ts
+++ b/tests/src/interfaces/unique/definitions.ts
@@ -54,13 +54,26 @@
     topmostTokenOwner: fun('Get token owner, in case of nested token - find parent recursive', [collectionParam, tokenParam], `Option<${CROSS_ACCOUNT_ID_TYPE}>`),
     constMetadata: fun('Get token constant metadata', [collectionParam, tokenParam], 'Vec<u8>'),
     variableMetadata: fun('Get token variable metadata', [collectionParam, tokenParam], 'Vec<u8>'),
-
     collectionProperties: fun(
       'Get collection properties',
       [collectionParam, propertyKeysParam],
       'Vec<UpDataStructsProperty>',
     ),
-
+    tokenProperties: fun(
+      'Get token properties',
+      [collectionParam, tokenParam, propertyKeysParam],
+      'Vec<UpDataStructsProperty>',
+    ),
+    propertyPermissions: fun(
+      'Get property permissions',
+      [collectionParam, propertyKeysParam],
+      'Vec<UpDataStructsPropertyKeyPermission>',
+    ),
+    tokenData: fun(
+      'Get token data',
+      [collectionParam, tokenParam, propertyKeysParam],
+      'UpDataStructsTokenData',
+    ),
     tokenExists: fun('Check if token exists', [collectionParam, tokenParam], 'bool'),
     collectionById: fun('Get collection by specified id', [collectionParam], 'Option<UpDataStructsRpcCollection>'),
     collectionStats: fun('Get collection stats', [], 'UpDataStructsCollectionStats'),
modifiedtests/src/interfaces/unique/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/unique/types.ts
+++ b/tests/src/interfaces/unique/types.ts
@@ -1,7 +1,7 @@
 // Auto-generated via `yarn polkadot-types-from-defs`, do not edit
 /* eslint-disable */
 
-import type { BTreeMap, BTreeSet, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
+import type { BTreeMap, Bytes, Compact, Enum, Null, Option, Result, Struct, Text, U256, U8aFixed, Vec, bool, u128, u16, u32, u64, u8 } from '@polkadot/types-codec';
 import type { ITuple } from '@polkadot/types-codec/types';
 import type { AccountId32, Call, H160, H256, MultiAddress, Perbill } from '@polkadot/types/interfaces/runtime';
 import type { Event } from '@polkadot/types/interfaces/system';
@@ -447,7 +447,7 @@
 export interface FrameSupportPalletId extends U8aFixed {}
 
 /** @name FrameSupportStorageBoundedBTreeSet */
-export interface FrameSupportStorageBoundedBTreeSet extends BTreeSet<u32> {}
+export interface FrameSupportStorageBoundedBTreeSet extends Vec<u32> {}
 
 /** @name FrameSupportTokensMiscBalanceStatus */
 export interface FrameSupportTokensMiscBalanceStatus extends Enum {
@@ -1086,8 +1086,8 @@
   readonly isFungibleItemsHaveNoId: boolean;
   readonly isFungibleItemsDontHaveData: boolean;
   readonly isFungibleDisallowsNesting: boolean;
-  readonly isPropertiesNotAllowed: boolean;
-  readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'PropertiesNotAllowed';
+  readonly isSettingPropertiesNotAllowed: boolean;
+  readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
 }
 
 /** @name PalletInflationCall */
@@ -1118,8 +1118,8 @@
   readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
   readonly isWrongRefungiblePieces: boolean;
   readonly isRefungibleDisallowsNesting: boolean;
-  readonly isPropertiesNotAllowed: boolean;
-  readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'PropertiesNotAllowed';
+  readonly isSettingPropertiesNotAllowed: boolean;
+  readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
 }
 
 /** @name PalletRefungibleItemData */
@@ -1632,8 +1632,11 @@
   readonly type: 'Attempted' | 'Sent' | 'UnexpectedResponse' | 'ResponseReady' | 'Notified' | 'NotifyOverweight' | 'NotifyDispatchError' | 'NotifyDecodeFailed' | 'InvalidResponder' | 'InvalidResponderVersion' | 'ResponseTaken' | 'AssetsTrapped' | 'VersionChangeNotified' | 'SupportedVersionChanged' | 'NotifyTargetSendFail' | 'NotifyTargetMigrationFail';
 }
 
-/** @name PhantomTypeUpDataStructs */
-export interface PhantomTypeUpDataStructs extends Vec<Lookup326> {}
+/** @name PhantomTypeUpDataStructsRpcCollection */
+export interface PhantomTypeUpDataStructsRpcCollection extends Vec<Lookup330> {}
+
+/** @name PhantomTypeUpDataStructsTokenData */
+export interface PhantomTypeUpDataStructsTokenData extends Vec<Lookup326> {}
 
 /** @name PolkadotCorePrimitivesInboundDownwardMessage */
 export interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
@@ -1782,7 +1785,7 @@
 
 /** @name SpTrieStorageProof */
 export interface SpTrieStorageProof extends Struct {
-  readonly trieNodes: BTreeSet<Bytes>;
+  readonly trieNodes: Vec<Bytes>;
 }
 
 /** @name SpVersionRuntimeVersion */
@@ -1908,12 +1911,14 @@
 export interface UpDataStructsCreateNftData extends Struct {
   readonly constData: Bytes;
   readonly variableData: Bytes;
+  readonly properties: Vec<UpDataStructsProperty>;
 }
 
 /** @name UpDataStructsCreateNftExData */
 export interface UpDataStructsCreateNftExData extends Struct {
   readonly constData: Bytes;
   readonly variableData: Bytes;
+  readonly properties: Vec<UpDataStructsProperty>;
   readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
 }
 
@@ -1968,14 +1973,10 @@
 }
 
 /** @name UpDataStructsPropertyPermission */
-export interface UpDataStructsPropertyPermission extends Enum {
-  readonly isNone: boolean;
-  readonly isAdminConst: boolean;
-  readonly isAdmin: boolean;
-  readonly isItemOwnerConst: boolean;
-  readonly isItemOwner: boolean;
-  readonly isItemOwnerOrAdmin: boolean;
-  readonly type: 'None' | 'AdminConst' | 'Admin' | 'ItemOwnerConst' | 'ItemOwner' | 'ItemOwnerOrAdmin';
+export interface UpDataStructsPropertyPermission extends Struct {
+  readonly mutable: bool;
+  readonly collectionAdmin: bool;
+  readonly tokenOwner: bool;
 }
 
 /** @name UpDataStructsRpcCollection */
@@ -2021,6 +2022,13 @@
   readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
 }
 
+/** @name UpDataStructsTokenData */
+export interface UpDataStructsTokenData extends Struct {
+  readonly constData: Bytes;
+  readonly properties: Vec<UpDataStructsProperty>;
+  readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
+}
+
 /** @name XcmDoubleEncoded */
 export interface XcmDoubleEncoded extends Struct {
   readonly encoded: Bytes;
modifiedtests/src/nesting/migration-check.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/migration-check.test.ts
+++ b/tests/src/nesting/migration-check.test.ts
@@ -5,6 +5,8 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {strToUTF16} from '../util/util';
 import waitNewBlocks from '../substrate/wait-new-blocks';
+// Used for polkadot-launch signalling
+import find from 'find-process';
 
 // todo skip
 describe('Migration testing for pallet-common', () => {
@@ -54,13 +56,12 @@
     let newVersion = oldVersion!;
     let connectionFailCounter = 0;
 
-    // Cooperate with polkadot-launch if it's running (assuming custom name change), and send a custom signal
-    const find = require('find-process');
-    find('name', 'polkadot-launch', true).then(function (list: [any]) {
-      for (let proc of list) {
+    // Cooperate with polkadot-launch if it's running (assuming custom name change to 'polkadot-launch'), and send a custom signal
+    find('name', 'polkadot-launch', true).then((list) => {
+      for (const proc of list) {
         process.kill(proc.pid, 'SIGUSR1');
       }
-    })
+    });
 
     // And wait for the parachain upgrade
     while (newVersion == oldVersion! && connectionFailCounter < 2) {
addedtests/src/nesting/properties.test.tsdiffbeforeafterboth
--- /dev/null
+++ b/tests/src/nesting/properties.test.ts
@@ -0,0 +1,652 @@
+import {expect} from 'chai';
+import privateKey from '../substrate/privateKey';
+import usingApi, {executeTransaction} from '../substrate/substrate-api';
+import {
+  addCollectionAdminExpectSuccess,
+  createCollectionExpectSuccess,
+  createItemExpectSuccess,
+  getCreateCollectionResult,
+  transferExpectSuccess,
+} from '../util/helpers';
+import {IKeyringPair} from '@polkadot/types/types';
+
+let alice: IKeyringPair;
+let bob: IKeyringPair;
+let charlie: IKeyringPair;
+
+// ---------- COLLECTION PROPERTIES
+
+describe('Integration Test: Collection Properties', () => {
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+  });
+
+  it('Reads properties from a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+      const properties = (await api.query.common.collectionProperties(collection)).toJSON();
+      expect(properties.map).to.be.empty;
+      expect(properties.consumedSpace).to.equal(0);
+    });
+  });
+
+  it('Sets properties for a collection', async () => {
+    await usingApi(async api => {
+      const events = await executeTransaction(api, bob, api.tx.unique.createCollectionEx({mode: 'NFT'}));
+      const {collectionId} = getCreateCollectionResult(events);
+
+      // As owner
+      await expect(executeTransaction(
+        api, 
+        bob, 
+        api.tx.unique.setCollectionProperties(collectionId, [{key: 'electron', value: 'come bond'}]), 
+      )).to.not.be.rejected;
+
+      await addCollectionAdminExpectSuccess(bob, collectionId, alice.address);
+
+      // As administrator
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collectionId, [{key: 'black hole'}]), 
+      )).to.not.be.rejected;
+
+      const properties = (await api.rpc.unique.collectionProperties(collectionId, ['electron', 'black hole'])).toJSON();
+      expect(properties).to.be.deep.equal([
+        {key: `0x${Buffer.from('electron').toString('hex')}`, value: `0x${Buffer.from('come bond').toString('hex')}`},
+        {key: `0x${Buffer.from('black hole').toString('hex')}`, value: `0x${Buffer.from('').toString('hex')}`},
+      ]);
+    });
+  });
+
+  it('Changes properties of a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black hole'}]), 
+      )).to.not.be.rejected;
+
+      // Mutate the properties
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'bonded'}, {key: 'black hole', value: 'LIGO'}]), 
+      )).to.not.be.rejected;
+
+      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();
+      expect(properties).to.be.deep.equal([
+        {key: `0x${Buffer.from('electron').toString('hex')}`, value: `0x${Buffer.from('bonded').toString('hex')}`},
+        {key: `0x${Buffer.from('black hole').toString('hex')}`, value: `0x${Buffer.from('LIGO').toString('hex')}`},
+      ]);
+    });
+  });
+
+  it('Deletes properties of a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black hole', value: 'LIGO'}]), 
+      )).to.not.be.rejected;
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.deleteCollectionProperties(collection, ['electron']), 
+      )).to.not.be.rejected;
+
+      const properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();
+      expect(properties).to.be.deep.equal([
+        {key: `0x${Buffer.from('black hole').toString('hex')}`, value: `0x${Buffer.from('LIGO').toString('hex')}`},
+      ]);
+    });
+  });
+});
+
+describe('Negative Integration Test: Collection Properties', () => {
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+  });
+  
+  it('Fails to set properties in a collection if not its onwer/administrator', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        bob, 
+        api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'come bond'}, {key: 'black hole', value: 'LIGO'}]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+  
+      const properties = (await api.query.common.collectionProperties(collection)).toJSON();
+      expect(properties.map).to.be.empty;
+      expect(properties.consumedSpace).to.equal(0);
+    });
+  });
+  
+  it('Fails to set properties that exceed the limits', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+      const spaceLimit = (await api.query.common.collectionProperties(collection)).toJSON().spaceLimit as number; 
+
+      // Mute the general tx parsing error, too many bytes to process
+      {
+        console.error = () => {};
+        await expect(executeTransaction(
+          api, 
+          alice, 
+          api.tx.unique.setCollectionProperties(collection, [{key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 9))}]), 
+        )).to.be.rejected;
+      }
+
+      let properties = (await api.rpc.unique.collectionProperties(collection, ['electron'])).toJSON();
+      expect(properties).to.be.empty;
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collection, [
+          {key: 'electron', value: 'low high '.repeat(Math.ceil(spaceLimit! / 18))}, 
+          {key: 'black hole', value: '0'.repeat(Math.ceil(spaceLimit! / 2))}, 
+        ]), 
+      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+      properties = (await api.rpc.unique.collectionProperties(collection, ['electron', 'black hole'])).toJSON();
+      expect(properties).to.be.empty;
+    });
+  });
+  
+  it('Fails to set more properties than it is allowed', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      const propertiesToBeSet = [];
+      for (let i = 0; i < 65; i++) {
+        propertiesToBeSet.push({
+          key: 'electron ' + i,
+          value: Math.random() > 0.5 ? 'high' : 'low',
+        });
+      }
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setCollectionProperties(collection, propertiesToBeSet), 
+      )).to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+      const properties = (await api.query.common.collectionProperties(collection)).toJSON();
+      expect(properties.map).to.be.empty;
+      expect(properties.consumedSpace).to.equal(0);
+    });
+  });
+});
+
+// ---------- ACCESS RIGHTS
+
+describe('Integration Test: Access Rights to Token Properties', () => {
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+  });
+  
+  it('Reads access rights to properties of a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();
+      expect(propertyRights).to.be.empty;
+    });
+  });
+  
+  it('Sets access rights to properties of a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true}}]), 
+      )).to.not.be.rejected;
+
+      await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'mindgame', permission: {collectionAdmin: true, tokenOwner: false}}]), 
+      )).to.not.be.rejected;
+
+      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery', 'mindgame'])).toJSON();
+      expect(propertyRights).to.be.deep.equal([
+        {key: `0x${Buffer.from('skullduggery').toString('hex')}`, permission: {'mutable': true, 'collectionAdmin': false, 'tokenOwner': false}},
+        {key: `0x${Buffer.from('mindgame').toString('hex')}`, permission: {'mutable': false, 'collectionAdmin': true, 'tokenOwner': false}},
+      ]);
+    });
+  });
+  
+  it('Changes access rights to properties of a collection', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, collectionAdmin: true}}]), 
+      )).to.not.be.rejected;
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 
+      )).to.not.be.rejected;
+
+      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();
+      expect(propertyRights).to.be.deep.equal([
+        {key: `0x${Buffer.from('skullduggery').toString('hex')}`, permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+      ]);
+    });
+  });
+});
+
+describe('Negative Integration Test: Access Rights to Token Properties', () => {
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+  });
+
+  it('Prevents from setting access rights to properties of a collection if not an onwer/admin', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        bob, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: true, tokenOwner: true}}]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+
+      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();
+      expect(propertyRights).to.be.empty;
+    });
+  });
+
+  it('Prevents from adding too many possible properties', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      const constitution = [];
+      for (let i = 0; i < 65; i++) {
+        constitution.push({
+          key: 'property ' + i,
+          permission: Math.random() > 0.5 ? {mutable: true, collectionAdmin: true, tokenOwner: true} : {},
+        });
+      }
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, constitution), 
+      )).to.be.rejectedWith(/common\.PropertyLimitReached/);
+
+      const propertyRights = (await api.query.common.collectionPropertyPermissions(collection)).toJSON();
+      expect(propertyRights).to.be.empty;
+    });
+  });
+
+  it('Prevents access rights to be modified if constant', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {mutable: false, tokenOwner: true}}]), 
+      )).to.not.be.rejected;
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'skullduggery', permission: {}}]), 
+      )).to.be.rejectedWith(/common\.NoPermission/);
+
+      const propertyRights = (await api.rpc.unique.propertyPermissions(collection, ['skullduggery'])).toJSON();
+      expect(propertyRights).to.deep.equal([
+        {key: `0x${Buffer.from('skullduggery').toString('hex')}`, permission: {'mutable': false, 'collectionAdmin': false, 'tokenOwner': true}},
+      ]);
+    });
+  });
+});
+
+// ---------- TOKEN PROPERTIES
+
+describe('Integration Test: Token Properties', () => {
+  let collection: number;
+  let token: number;
+  let permissions: {permission: any, signers: IKeyringPair[]}[];
+
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+    charlie = privateKey('//Charlie');
+
+    permissions = [
+      {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob]},
+      {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob]},
+      {permission: {mutable: true, tokenOwner: true}, signers: [charlie]},
+      {permission: {mutable: false, tokenOwner: true}, signers: [charlie]},
+      {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+      {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie]},
+    ];
+  });
+
+  beforeEach(async () => {
+    collection = await createCollectionExpectSuccess();
+    token = await createItemExpectSuccess(alice, collection, 'NFT');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await transferExpectSuccess(collection, token, alice, charlie);
+  });
+  
+  it('Reads properties of a token', async () => {
+    await usingApi(async api => {
+      const collection = await createCollectionExpectSuccess();
+      const token = await createItemExpectSuccess(alice, collection, 'NFT');
+  
+      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
+      expect(properties.map).to.be.empty;
+      expect(properties.consumedSpace).to.be.equal(0);
+
+      const tokenData = (await api.rpc.unique.tokenData(collection, token, ['anything'])).toJSON().properties;
+      expect(tokenData).to.be.empty;
+    });
+  });
+
+  it('Assigns properties to a token according to permissions', async () => {
+    await usingApi(async api => {
+      const propertyKeys: string[] = [];
+      let i = 0;
+      for (const permission of permissions) {
+        for (const signer of permission.signers) {
+          const key = i + ' ' + signer.address;
+          propertyKeys.push(key);
+
+          await expect(executeTransaction(
+            api, 
+            alice, 
+            api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 
+          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
+
+          await expect(executeTransaction(
+            api, 
+            signer, 
+            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 
+          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
+        }
+
+        i++;
+      }
+
+      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];
+      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];
+      for (let i = 0; i < properties.length; i++) {
+        expect(properties[i].value).to.be.equal(`0x${Buffer.from('Serotonin increase').toString('hex')}`);
+        expect(tokensData[i].value).to.be.equal(`0x${Buffer.from('Serotonin increase').toString('hex')}`);
+      }
+    });
+  });
+
+  it('Changes properties of a token according to permissions', async () => {
+    await usingApi(async api => {
+      const propertyKeys: string[] = [];
+      let i = 0;
+      for (const permission of permissions) {
+        if (!permission.permission.mutable) continue;
+        
+        for (const signer of permission.signers) {
+          const key = i + ' ' + signer.address;
+          propertyKeys.push(key);
+
+          await expect(executeTransaction(
+            api, 
+            alice, 
+            api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 
+          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
+
+          await expect(executeTransaction(
+            api, 
+            signer, 
+            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 
+          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
+
+          await expect(executeTransaction(
+            api, 
+            signer, 
+            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin stable'}]), 
+          ), `on changing property ${i} by ${signer.address}`).to.not.be.rejected;
+        }
+
+        i++;
+      }
+
+      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];
+      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];
+      for (let i = 0; i < properties.length; i++) {
+        expect(properties[i].value).to.be.equal(`0x${Buffer.from('Serotonin stable').toString('hex')}`);
+        expect(tokensData[i].value).to.be.equal(`0x${Buffer.from('Serotonin stable').toString('hex')}`);
+      }
+    });
+  });
+
+  it('Deletes properties of a token according to permissions', async () => {
+    await usingApi(async api => {
+      const propertyKeys: string[] = [];
+      let i = 0;
+
+      for (const permission of permissions) {
+        if (!permission.permission.mutable) continue;
+        
+        for (const signer of permission.signers) {
+          const key = i + ' ' + signer.address;
+          propertyKeys.push(key);
+
+          await expect(executeTransaction(
+            api, 
+            alice, 
+            api.tx.unique.setPropertyPermissions(collection, [{key: key, permission: permission.permission}]), 
+          ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
+
+          await expect(executeTransaction(
+            api, 
+            signer, 
+            api.tx.unique.setTokenProperties(collection, token, [{key: key, value: 'Serotonin increase'}]), 
+          ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
+
+          await expect(executeTransaction(
+            api, 
+            signer, 
+            api.tx.unique.deleteTokenProperties(collection, token, [key]), 
+          ), `on deleting property ${i} by ${signer.address}`).to.not.be.rejected;
+        }
+        
+        i++;
+      }
+
+      const properties = (await api.rpc.unique.tokenProperties(collection, token, propertyKeys)).toJSON() as any[];
+      expect(properties).to.be.empty;
+      const tokensData = (await api.rpc.unique.tokenData(collection, token, propertyKeys)).toJSON().properties as any[];
+      expect(tokensData).to.be.empty;
+      expect((await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace).to.be.equal(0);
+    });
+  });
+});
+
+describe('Negative Integration Test: Token Properties', () => {
+  let collection: number;
+  let token: number;
+  let originalSpace: number;
+  let constitution: {permission: any, signers: IKeyringPair[], sinner: IKeyringPair}[];
+
+  before(async () => {
+    alice = privateKey('//Alice');
+    bob = privateKey('//Bob');
+    charlie = privateKey('//Charlie');
+    const dave = privateKey('//Dave');
+
+    constitution = [
+      {permission: {mutable: true, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+      {permission: {mutable: false, collectionAdmin: true}, signers: [alice, bob], sinner: charlie},
+      {permission: {mutable: true, tokenOwner: true}, signers: [charlie], sinner: alice},
+      {permission: {mutable: false, tokenOwner: true}, signers: [charlie], sinner: alice},
+      {permission: {mutable: true, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+      {permission: {mutable: false, collectionAdmin: true, tokenOwner: true}, signers: [alice, bob, charlie], sinner: dave},
+    ];
+  });
+
+  beforeEach(async () => {
+    collection = await createCollectionExpectSuccess();
+    token = await createItemExpectSuccess(alice, collection, 'NFT');
+    await addCollectionAdminExpectSuccess(alice, collection, bob.address);
+    await transferExpectSuccess(collection, token, alice, charlie);
+        
+    await usingApi(async api => {
+      let i = 0;
+      for (const passage of constitution) {
+        const signer = passage.signers[0];
+        
+        await expect(executeTransaction(
+          api, 
+          alice, 
+          api.tx.unique.setPropertyPermissions(collection, [{key: i, permission: passage.permission}]), 
+        ), `on setting permission ${i} by ${signer.address}`).to.not.be.rejected;
+
+        await expect(executeTransaction(
+          api, 
+          signer, 
+          api.tx.unique.setTokenProperties(collection, token, [{key: i, value: 'Serotonin increase'}]), 
+        ), `on adding property ${i} by ${signer.address}`).to.not.be.rejected;
+
+        i++;
+      }
+
+      originalSpace = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON().consumedSpace as number;
+    });
+  });
+
+  it('Forbids changing/deleting properties of a token if the user is outside of permissions', async () => {
+    await usingApi(async api => {
+      let i = -1;
+      for (const forbiddance of constitution) {
+        i++;
+        if (!forbiddance.permission.mutable) continue;
+
+        await expect(executeTransaction(
+          api, 
+          forbiddance.sinner, 
+          api.tx.unique.setTokenProperties(collection, token, [{key: i, value: 'Serotonin down'}]), 
+        ), `on failing to change property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);
+
+        await expect(executeTransaction(
+          api, 
+          forbiddance.sinner, 
+          api.tx.unique.deleteTokenProperties(collection, token, [forbiddance.permission]), 
+        ), `on failing to delete property ${i} by ${forbiddance.sinner.address}`).to.be.rejectedWith(/common\.NoPermission/);
+      }
+
+      // todo RPC?
+      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
+      expect(properties.consumedSpace).to.be.equal(originalSpace);
+    });
+  });
+
+  it('Forbids changing/deleting properties of a token if the property is permanent (constant)', async () => {
+    await usingApi(async api => {
+      let i = -1;
+      for (const permission of constitution) {
+        i++;
+        if (permission.permission.mutable) continue;
+
+        await expect(executeTransaction(
+          api, 
+          permission.signers[0], 
+          api.tx.unique.setTokenProperties(collection, token, [{key: i, value: 'Serotonin down'}]), 
+        ), `on failing to change property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);
+
+        await expect(executeTransaction(
+          api, 
+          permission.signers[0], 
+          api.tx.unique.deleteTokenProperties(collection, token, [i.toString()]), 
+        ), `on failing to delete property ${i} by ${permission.signers[0].address}`).to.be.rejectedWith(/common\.NoPermission/);
+      }
+
+      // todo RPC?
+      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
+      expect(properties.consumedSpace).to.be.equal(originalSpace);
+    });
+  });
+
+  it('Forbids adding properties to a token if the property is not declared / forbidden with the \'None\' permission', async () => {
+    await usingApi(async api => {
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [{key: 'non-existent', value: 'I exist!'}]), 
+      ), 'on failing to add a previously non-existent property').to.be.rejectedWith(/common\.NoPermission/);
+        
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [{key: 'now-existent', permission: {}}]), 
+      ), 'on setting a new non-permitted property').to.not.be.rejected;
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [{key: 'now-existent', value: 'I exist!'}]), 
+      ), 'on failing to add a property forbidden by the \'None\' permission').to.be.rejectedWith(/common\.NoPermission/);
+
+      expect((await api.rpc.unique.tokenProperties(collection, token, ['non-existent', 'now-existent'])).toJSON()).to.be.empty;
+      const properties = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
+      expect(properties.consumedSpace).to.be.equal(originalSpace);
+    });
+  });
+
+  it('Forbids adding too many properties to a token', async () => {
+    await usingApi(async api => {
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setPropertyPermissions(collection, [
+          {key: 'a holy book', permission: {collectionAdmin: true, tokenOwner: true}}, 
+          {key: 'young years', permission: {collectionAdmin: true, tokenOwner: true}},
+        ]), 
+      ), 'on setting a new non-permitted property').to.not.be.rejected;
+
+      // Mute the general tx parsing error
+      {
+        console.error = () => {};
+        await expect(executeTransaction(
+          api, 
+          alice, 
+          api.tx.unique.setCollectionProperties(collection, [{key: 'a holy book', value: 'word '.repeat(6554)}]), 
+        )).to.be.rejected;
+      }
+
+      await expect(executeTransaction(
+        api, 
+        alice, 
+        api.tx.unique.setTokenProperties(collection, token, [
+          {key: 'a holy book', value: 'word '.repeat(3277)}, 
+          {key: 'young years', value: 'neverending'.repeat(1490)},
+        ]), 
+      )).to.be.rejectedWith(/common\.NoSpaceForProperty/);
+
+      expect((await api.rpc.unique.tokenProperties(collection, token, ['a holy book', 'young years'])).toJSON()).to.be.empty;
+      const propertiesMap = (await api.query.nonfungible.tokenProperties(collection, token)).toJSON();
+      expect(propertiesMap.consumedSpace).to.be.equal(originalSpace);
+    });
+  });
+});
\ No newline at end of file
modifiedtests/src/nesting/unnest.test.tsdiffbeforeafterboth
--- a/tests/src/nesting/unnest.test.ts
+++ b/tests/src/nesting/unnest.test.ts
@@ -10,7 +10,6 @@
   getTopmostTokenOwner, 
   normalizeAccountId, 
   setCollectionLimitsExpectSuccess, 
-  transferExpectFailure, 
   transferExpectSuccess, 
 } from '../util/helpers';
 import {IKeyringPair} from '@polkadot/types/types';