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

difftreelog

fix PR

Trubnikov Sergey2022-12-12parent: #6028430.patch.diff
in: master

18 files changed

modifiedpallets/common/src/lib.rsdiffbeforeafterboth
--- a/pallets/common/src/lib.rs
+++ b/pallets/common/src/lib.rs
@@ -284,7 +284,7 @@
 		self.check_is_internal()?;
 		ensure!(
 			self.collection.sponsorship.pending_sponsor() == Some(sender),
-			Error::<T>::ConfirmUnsetSponsorFail
+			Error::<T>::ConfirmSponsorshipFail
 		);
 
 		self.collection.sponsorship = SponsorshipState::Confirmed(sender.clone());
@@ -303,7 +303,7 @@
 	/// Remove collection sponsor.
 	pub fn remove_sponsor(&mut self, sender: &T::CrossAccountId) -> DispatchResult {
 		self.check_is_internal()?;
-		self.check_is_owner(sender)?;
+		self.check_is_owner_or_admin(sender)?;
 
 		self.collection.sponsorship = SponsorshipState::Disabled;
 
@@ -420,7 +420,7 @@
 		self.check_is_owner(&caller)?;
 		self.collection.owner = new_owner.as_sub().clone();
 
-		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnedChanged(
+		<Pallet<T>>::deposit_event(Event::<T>::CollectionOwnerChanged(
 			self.id,
 			new_owner.as_sub().clone(),
 		));
@@ -663,7 +663,7 @@
 		),
 
 		/// Collection owned was changed.
-		CollectionOwnedChanged(
+		CollectionOwnerChanged(
 			/// ID of the affected collection.
 			CollectionId,
 			/// New owner address.
@@ -785,10 +785,10 @@
 		CollectionIsInternal,
 
 		/// This address is not set as sponsor, use setCollectionSponsor first.
-		ConfirmUnsetSponsorFail,
+		ConfirmSponsorshipFail,
 
 		/// The user is not an administrator.
-		UserIsNotAdmin,
+		UserIsNotCollectionAdmin,
 	}
 
 	/// Storage of the count of created collections. Essentially contains the last collection ID.
@@ -1578,7 +1578,7 @@
 			if admin {
 				return Ok(());
 			} else {
-				ensure!(false, Error::<T>::UserIsNotAdmin);
+				return Err(Error::<T>::UserIsNotCollectionAdmin.into());
 			}
 		}
 		let amount = <AdminAmount<T>>::get(collection.id);
@@ -1591,8 +1591,6 @@
 				amount <= Self::collection_admins_limit(),
 				<Error<T>>::CollectionAdminCountExceeded,
 			);
-
-			// =========
 
 			<AdminAmount<T>>::insert(collection.id, amount);
 			<IsAdmin<T>>::insert((collection.id, user), true);
modifiedtests/src/change-collection-owner.test.tsdiffbeforeafterboth
--- a/tests/src/change-collection-owner.test.ts
+++ b/tests/src/change-collection-owner.test.ts
@@ -146,7 +146,7 @@
     const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
     const removeSponsorTx = () => collection.removeSponsor(alice);
     await expect(setSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
-    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
     await expect(removeSponsorTx()).to.be.rejectedWith(/common\.NoPermission/);
 
     const limits = {
modifiedtests/src/confirmSponsorship.test.tsdiffbeforeafterboth
--- a/tests/src/confirmSponsorship.test.ts
+++ b/tests/src/confirmSponsorship.test.ts
@@ -207,14 +207,14 @@
     const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
     await collection.setSponsor(alice, bob.address);
     const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
-    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 
   itSub('(!negative test!) Confirm sponsorship using owner address', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
     await collection.setSponsor(alice, bob.address);
     const confirmSponsorshipTx = () => collection.confirmSponsorship(alice);
-    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 
   itSub('(!negative test!) Confirm sponsorship by collection admin', async ({helper}) => {
@@ -222,13 +222,13 @@
     await collection.setSponsor(alice, bob.address);
     await collection.addAdmin(alice, {Substrate: charlie.address});
     const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
-    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 
   itSub('(!negative test!) Confirm sponsorship without sponsor being set with setCollectionSponsor', async ({helper}) => {
     const collection = await helper.nft.mintCollection(alice, {name: 'col', description: 'descr', tokenPrefix: 'COL'});
     const confirmSponsorshipTx = () => collection.confirmSponsorship(charlie);
-    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(confirmSponsorshipTx()).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 
   itSub('(!negative test!) Confirm sponsorship in a collection that was destroyed', async ({helper}) => {
modifiedtests/src/eth/collectionSponsoring.test.tsdiffbeforeafterboth
--- a/tests/src/eth/collectionSponsoring.test.ts
+++ b/tests/src/eth/collectionSponsoring.test.ts
@@ -128,7 +128,7 @@
       let sponsorship = (await collectionSub.getData())!.raw.sponsorship;
       expect(sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsorEth, true));
       // Account cannot confirm sponsorship if it is not set as a sponsor
-      await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+      await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
       
       // Sponsor can confirm sponsorship:
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsorEth});
@@ -257,7 +257,7 @@
       await collectionEvm.methods[testCase](testCase === 'setCollectionSponsor' ? sponsor : sponsorCross).send();
       let collectionData = (await collectionSub.getData())!;
       expect(collectionData.raw.sponsorship.Unconfirmed).to.be.eq(helper.address.ethToSubstrate(sponsor, true));
-      await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+      await expect(collectionEvm.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
   
       await collectionEvm.methods.confirmCollectionSponsorship().send({from: sponsor});
       collectionData = (await collectionSub.getData())!;
modifiedtests/src/eth/createFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createFTCollection.test.ts
+++ b/tests/src/eth/createFTCollection.test.ts
@@ -46,7 +46,7 @@
     let data = (await helper.rft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -69,7 +69,7 @@
     let data = (await helper.rft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -192,7 +192,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor, true);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(peasantCollection.methods
@@ -217,7 +217,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'ft', sponsor);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(peasantCollection.methods
modifiedtests/src/eth/createNFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createNFTCollection.test.ts
+++ b/tests/src/eth/createNFTCollection.test.ts
@@ -86,7 +86,7 @@
     let data = (await helper.nft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -109,7 +109,7 @@
     let data = (await helper.nft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -203,7 +203,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor, true);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(malfeasantCollection.methods
@@ -228,7 +228,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'nft', sponsor);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(malfeasantCollection.methods
modifiedtests/src/eth/createRFTCollection.test.tsdiffbeforeafterboth
--- a/tests/src/eth/createRFTCollection.test.ts
+++ b/tests/src/eth/createRFTCollection.test.ts
@@ -121,7 +121,7 @@
     let data = (await helper.rft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -143,7 +143,7 @@
     let data = (await helper.rft.getData(collectionId))!;
     expect(data.raw.sponsorship.Unconfirmed).to.be.equal(evmToAddress(sponsor, Number(ss58Format)));
 
-    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+    await expect(collection.methods.confirmCollectionSponsorship().call()).to.be.rejectedWith('ConfirmSponsorshipFail');
 
     const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
     await sponsorCollection.methods.confirmCollectionSponsorship().send();
@@ -235,7 +235,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor, true);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(peasantCollection.methods
@@ -260,7 +260,7 @@
       const sponsorCollection = helper.ethNativeContract.collection(collectionAddress, 'rft', sponsor);
       await expect(sponsorCollection.methods
         .confirmCollectionSponsorship()
-        .call()).to.be.rejectedWith('ConfirmUnsetSponsorFail');
+        .call()).to.be.rejectedWith('ConfirmSponsorshipFail');
     }
     {
       await expect(peasantCollection.methods
modifiedtests/src/eth/events.test.tsdiffbeforeafterboth
--- a/tests/src/eth/events.test.ts
+++ b/tests/src/eth/events.test.ts
@@ -18,6 +18,7 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {EthUniqueHelper, itEth, usingEthPlaygrounds} from './util';
 import {TCollectionMode} from '../util/playgrounds/types';
+import {Pallets, requirePalletsOrSkip} from '../util';
 
 let donor: IKeyringPair;
   
@@ -253,7 +254,7 @@
   collectionHelper.events.allEvents((_: any, event: any) => {
     ethEvents.push(event);
   });
-  const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnedChanged']}]);
+  const {unsubscribe, collectedEvents: subEvents} = await helper.subscribeEvents([{section: 'common', names: ['CollectionOwnerChanged']}]);
   {
     await collection.methods.changeCollectionOwnerCross(new_owner).send({from: owner});
     await helper.wait.newBlocks(1);
@@ -265,7 +266,7 @@
         },
       },
     ]);
-    expect(subEvents).to.be.like([{method: 'CollectionOwnedChanged'}]);
+    expect(subEvents).to.be.like([{method: 'CollectionOwnerChanged'}]);
   }
   unsubscribe();
 }
@@ -401,6 +402,7 @@
   }
   {
     await collection.methods.deleteProperties(tokenId, ['A']).send({from: owner});
+    await helper.wait.newBlocks(1);
     expect(ethEvents).to.be.like([
       {
         event: 'TokenChanged',
@@ -437,7 +439,7 @@
     await testCollectionLimitSet(helper, mode);
   });
     
-  itEth('CollectionChanged event for CollectionOwnedChanged', async ({helper}) => {
+  itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
     await testCollectionOwnedChanged(helper, mode);
   });
     
@@ -477,7 +479,7 @@
     await testCollectionLimitSet(helper, mode);
   });
     
-  itEth('CollectionChanged event for CollectionOwnedChanged', async ({helper}) => {
+  itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
     await testCollectionOwnedChanged(helper, mode);
   });
     
@@ -497,6 +499,13 @@
 describe('[RFT] Sync sub & eth events', () => {
   const mode: TCollectionMode = 'rft';
 
+  before(async function() {
+    await usingEthPlaygrounds(async (helper, privateKey) => {
+      requirePalletsOrSkip(this, helper, [Pallets.ReFungible]);
+      const _donor = await privateKey({filename: __filename});
+    });
+  });
+
   itEth('CollectionCreated and CollectionDestroyed events', async ({helper}) => {
     await testCollectionCreatedAndDestroy(helper, mode);
   });
@@ -521,7 +530,7 @@
     await testCollectionLimitSet(helper, mode);
   });
     
-  itEth('CollectionChanged event for CollectionOwnedChanged', async ({helper}) => {
+  itEth('CollectionChanged event for CollectionOwnerChanged', async ({helper}) => {
     await testCollectionOwnedChanged(helper, mode);
   });
     
modifiedtests/src/interfaces/augment-api-errors.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-errors.ts
+++ b/tests/src/interfaces/augment-api-errors.ts
@@ -145,6 +145,10 @@
        **/
       CollectionTokenPrefixLimitExceeded: AugmentedError<ApiType>;
       /**
+       * This address is not set as sponsor, use setCollectionSponsor first.
+       **/
+      ConfirmSponsorshipFail: AugmentedError<ApiType>;
+      /**
        * Empty property keys are forbidden
        **/
       EmptyPropertyKey: AugmentedError<ApiType>;
@@ -217,6 +221,10 @@
        **/
       UserIsNotAllowedToNest: AugmentedError<ApiType>;
       /**
+       * The user is not an administrator.
+       **/
+      UserIsNotCollectionAdmin: AugmentedError<ApiType>;
+      /**
        * Generic error
        **/
       [key: string]: AugmentedError<ApiType>;
@@ -845,10 +853,6 @@
        * Decimal_points parameter must be lower than [`up_data_structs::MAX_DECIMAL_POINTS`].
        **/
       CollectionDecimalPointLimitExceeded: AugmentedError<ApiType>;
-      /**
-       * This address is not set as sponsor, use setCollectionSponsor first.
-       **/
-      ConfirmUnsetSponsorFail: AugmentedError<ApiType>;
       /**
        * Length of items properties must be greater than 0.
        **/
modifiedtests/src/interfaces/augment-api-events.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-api-events.ts
+++ b/tests/src/interfaces/augment-api-events.ts
@@ -103,6 +103,14 @@
     };
     common: {
       /**
+       * Address was added to the allow list.
+       **/
+      AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      /**
+       * Address was removed from the allow list.
+       **/
+      AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      /**
        * Amount pieces of token owned by `sender` was approved for `spender`.
        **/
       Approved: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
@@ -111,6 +119,14 @@
        **/
       ApprovedForAll: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmAccountBasicCrossAccountIdRepr, bool]>;
       /**
+       * Collection admin was added.
+       **/
+      CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      /**
+       * Collection admin was removed.
+       **/
+      CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+      /**
        * New collection was created
        **/
       CollectionCreated: AugmentedEvent<ApiType, [u32, u8, AccountId32]>;
@@ -119,6 +135,18 @@
        **/
       CollectionDestroyed: AugmentedEvent<ApiType, [u32]>;
       /**
+       * Collection limits were set.
+       **/
+      CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
+      /**
+       * Collection owned was changed.
+       **/
+      CollectionOwnerChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
+      /**
+       * Collection permissions were set.
+       **/
+      CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
+      /**
        * The property has been deleted.
        **/
       CollectionPropertyDeleted: AugmentedEvent<ApiType, [u32, Bytes]>;
@@ -127,6 +155,14 @@
        **/
       CollectionPropertySet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
+       * Collection sponsor was removed.
+       **/
+      CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
+      /**
+       * Collection sponsor was set.
+       **/
+      CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
+      /**
        * New item was created.
        **/
       ItemCreated: AugmentedEvent<ApiType, [u32, u32, PalletEvmAccountBasicCrossAccountIdRepr, u128]>;
@@ -139,6 +175,10 @@
        **/
       PropertyPermissionSet: AugmentedEvent<ApiType, [u32, Bytes]>;
       /**
+       * New sponsor was confirm.
+       **/
+      SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
+      /**
        * The token property has been deleted.
        **/
       TokenPropertyDeleted: AugmentedEvent<ApiType, [u32, u32, Bytes]>;
@@ -688,89 +728,6 @@
        * We have ended a spend period and will now allocate funds.
        **/
       Spending: AugmentedEvent<ApiType, [budgetRemaining: u128], { budgetRemaining: u128 }>;
-      /**
-       * Generic event
-       **/
-      [key: string]: AugmentedEvent<ApiType>;
-    };
-    unique: {
-      /**
-       * Address was added to the allow list
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * user: Address of the added account.
-       **/
-      AllowListAddressAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      /**
-       * Address was removed from the allow list
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * user: Address of the removed account.
-       **/
-      AllowListAddressRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      /**
-       * Collection admin was added
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * admin: Admin address.
-       **/
-      CollectionAdminAdded: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      /**
-       * Collection admin was removed
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * admin: Removed admin address.
-       **/
-      CollectionAdminRemoved: AugmentedEvent<ApiType, [u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-      /**
-       * Collection limits were set
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       **/
-      CollectionLimitSet: AugmentedEvent<ApiType, [u32]>;
-      /**
-       * Collection owned was changed
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * owner: New owner address.
-       **/
-      CollectionOwnedChanged: AugmentedEvent<ApiType, [u32, AccountId32]>;
-      /**
-       * Collection permissions were set
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       **/
-      CollectionPermissionSet: AugmentedEvent<ApiType, [u32]>;
-      /**
-       * Collection sponsor was removed
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       **/
-      CollectionSponsorRemoved: AugmentedEvent<ApiType, [u32]>;
-      /**
-       * Collection sponsor was set
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * owner: New sponsor address.
-       **/
-      CollectionSponsorSet: AugmentedEvent<ApiType, [u32, AccountId32]>;
-      /**
-       * New sponsor was confirm
-       * 
-       * # Arguments
-       * * collection_id: ID of the affected collection.
-       * * sponsor: New sponsor address.
-       **/
-      SponsorshipConfirmed: AugmentedEvent<ApiType, [u32, AccountId32]>;
       /**
        * Generic event
        **/
modifiedtests/src/interfaces/augment-types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/augment-types.ts
+++ b/tests/src/interfaces/augment-types.ts
@@ -5,7 +5,7 @@
 // this is required to allow for ambient/previous definitions
 import '@polkadot/types/types/registry';
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from './default';
 import type { Data, StorageKey } from '@polkadot/types';
 import type { BitVec, Bool, Bytes, F32, F64, I128, I16, I256, I32, I64, I8, Json, Null, OptionBool, Raw, Text, Type, U128, U16, U256, U32, U64, U8, USize, bool, f32, f64, 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';
@@ -902,7 +902,6 @@
     PalletTreasuryProposal: PalletTreasuryProposal;
     PalletUniqueCall: PalletUniqueCall;
     PalletUniqueError: PalletUniqueError;
-    PalletUniqueRawEvent: PalletUniqueRawEvent;
     PalletUniqueSchedulerV2BlockAgenda: PalletUniqueSchedulerV2BlockAgenda;
     PalletUniqueSchedulerV2Call: PalletUniqueSchedulerV2Call;
     PalletUniqueSchedulerV2Error: PalletUniqueSchedulerV2Error;
modifiedtests/src/interfaces/default/types.tsdiffbeforeafterboth
--- a/tests/src/interfaces/default/types.ts
+++ b/tests/src/interfaces/default/types.ts
@@ -1269,7 +1269,9 @@
   readonly isEmptyPropertyKey: boolean;
   readonly isCollectionIsExternal: boolean;
   readonly isCollectionIsInternal: boolean;
-  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal';
+  readonly isConfirmSponsorshipFail: boolean;
+  readonly isUserIsNotCollectionAdmin: boolean;
+  readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin';
 }
 
 /** @name PalletCommonEvent */
@@ -1298,7 +1300,27 @@
   readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
   readonly isPropertyPermissionSet: boolean;
   readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
-  readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
+  readonly isAllowListAddressAdded: boolean;
+  readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+  readonly isAllowListAddressRemoved: boolean;
+  readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+  readonly isCollectionAdminAdded: boolean;
+  readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+  readonly isCollectionAdminRemoved: boolean;
+  readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+  readonly isCollectionLimitSet: boolean;
+  readonly asCollectionLimitSet: u32;
+  readonly isCollectionOwnerChanged: boolean;
+  readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
+  readonly isCollectionPermissionSet: boolean;
+  readonly asCollectionPermissionSet: u32;
+  readonly isCollectionSponsorSet: boolean;
+  readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
+  readonly isSponsorshipConfirmed: boolean;
+  readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
+  readonly isCollectionSponsorRemoved: boolean;
+  readonly asCollectionSponsorRemoved: u32;
+  readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
 }
 
 /** @name PalletConfigurationCall */
@@ -2324,35 +2346,9 @@
 /** @name PalletUniqueError */
 export interface PalletUniqueError extends Enum {
   readonly isCollectionDecimalPointLimitExceeded: boolean;
-  readonly isConfirmUnsetSponsorFail: boolean;
   readonly isEmptyArgument: boolean;
   readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
-  readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
-}
-
-/** @name PalletUniqueRawEvent */
-export interface PalletUniqueRawEvent extends Enum {
-  readonly isCollectionSponsorRemoved: boolean;
-  readonly asCollectionSponsorRemoved: u32;
-  readonly isCollectionAdminAdded: boolean;
-  readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-  readonly isCollectionOwnedChanged: boolean;
-  readonly asCollectionOwnedChanged: ITuple<[u32, AccountId32]>;
-  readonly isCollectionSponsorSet: boolean;
-  readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
-  readonly isSponsorshipConfirmed: boolean;
-  readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
-  readonly isCollectionAdminRemoved: boolean;
-  readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-  readonly isAllowListAddressRemoved: boolean;
-  readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-  readonly isAllowListAddressAdded: boolean;
-  readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-  readonly isCollectionLimitSet: boolean;
-  readonly asCollectionLimitSet: u32;
-  readonly isCollectionPermissionSet: boolean;
-  readonly asCollectionPermissionSet: u32;
-  readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet';
+  readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
 }
 
 /** @name PalletUniqueSchedulerV2BlockAgenda */
modifiedtests/src/interfaces/lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/lookup.ts
+++ b/tests/src/interfaces/lookup.ts
@@ -989,34 +989,8 @@
     }
   },
   /**
-   * Lookup89: pallet_unique::RawEvent<sp_core::crypto::AccountId32, pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
-   **/
-  PalletUniqueRawEvent: {
-    _enum: {
-      CollectionSponsorRemoved: 'u32',
-      CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
-      CollectionOwnedChanged: '(u32,AccountId32)',
-      CollectionSponsorSet: '(u32,AccountId32)',
-      SponsorshipConfirmed: '(u32,AccountId32)',
-      CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
-      AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
-      AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
-      CollectionLimitSet: 'u32',
-      CollectionPermissionSet: 'u32'
-    }
-  },
-  /**
-   * Lookup90: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
+   * Lookup89: pallet_unique_scheduler_v2::pallet::Event<T>
    **/
-  PalletEvmAccountBasicCrossAccountIdRepr: {
-    _enum: {
-      Substrate: 'AccountId32',
-      Ethereum: 'H160'
-    }
-  },
-  /**
-   * Lookup93: pallet_unique_scheduler_v2::pallet::Event<T>
-   **/
   PalletUniqueSchedulerV2Event: {
     _enum: {
       Scheduled: {
@@ -1047,7 +1021,7 @@
     }
   },
   /**
-   * Lookup96: pallet_common::pallet::Event<T>
+   * Lookup92: pallet_common::pallet::Event<T>
    **/
   PalletCommonEvent: {
     _enum: {
@@ -1062,11 +1036,30 @@
       CollectionPropertyDeleted: '(u32,Bytes)',
       TokenPropertySet: '(u32,u32,Bytes)',
       TokenPropertyDeleted: '(u32,u32,Bytes)',
-      PropertyPermissionSet: '(u32,Bytes)'
+      PropertyPermissionSet: '(u32,Bytes)',
+      AllowListAddressAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+      AllowListAddressRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+      CollectionAdminAdded: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+      CollectionAdminRemoved: '(u32,PalletEvmAccountBasicCrossAccountIdRepr)',
+      CollectionLimitSet: 'u32',
+      CollectionOwnerChanged: '(u32,AccountId32)',
+      CollectionPermissionSet: 'u32',
+      CollectionSponsorSet: '(u32,AccountId32)',
+      SponsorshipConfirmed: '(u32,AccountId32)',
+      CollectionSponsorRemoved: 'u32'
+    }
+  },
+  /**
+   * Lookup95: pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>
+   **/
+  PalletEvmAccountBasicCrossAccountIdRepr: {
+    _enum: {
+      Substrate: 'AccountId32',
+      Ethereum: 'H160'
     }
   },
   /**
-   * Lookup100: pallet_structure::pallet::Event<T>
+   * Lookup99: pallet_structure::pallet::Event<T>
    **/
   PalletStructureEvent: {
     _enum: {
@@ -1074,7 +1067,7 @@
     }
   },
   /**
-   * Lookup101: pallet_rmrk_core::pallet::Event<T>
+   * Lookup100: pallet_rmrk_core::pallet::Event<T>
    **/
   PalletRmrkCoreEvent: {
     _enum: {
@@ -1151,7 +1144,7 @@
     }
   },
   /**
-   * Lookup102: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
+   * Lookup101: rmrk_traits::nft::AccountIdOrCollectionNftTuple<sp_core::crypto::AccountId32>
    **/
   RmrkTraitsNftAccountIdOrCollectionNftTuple: {
     _enum: {
@@ -1160,7 +1153,7 @@
     }
   },
   /**
-   * Lookup106: pallet_rmrk_equip::pallet::Event<T>
+   * Lookup105: pallet_rmrk_equip::pallet::Event<T>
    **/
   PalletRmrkEquipEvent: {
     _enum: {
@@ -1175,7 +1168,7 @@
     }
   },
   /**
-   * Lookup107: pallet_app_promotion::pallet::Event<T>
+   * Lookup106: pallet_app_promotion::pallet::Event<T>
    **/
   PalletAppPromotionEvent: {
     _enum: {
@@ -1186,7 +1179,7 @@
     }
   },
   /**
-   * Lookup108: pallet_foreign_assets::module::Event<T>
+   * Lookup107: pallet_foreign_assets::module::Event<T>
    **/
   PalletForeignAssetsModuleEvent: {
     _enum: {
@@ -1211,7 +1204,7 @@
     }
   },
   /**
-   * Lookup109: pallet_foreign_assets::module::AssetMetadata<Balance>
+   * Lookup108: pallet_foreign_assets::module::AssetMetadata<Balance>
    **/
   PalletForeignAssetsModuleAssetMetadata: {
     name: 'Bytes',
@@ -1220,7 +1213,7 @@
     minimalBalance: 'u128'
   },
   /**
-   * Lookup110: pallet_evm::pallet::Event<T>
+   * Lookup109: pallet_evm::pallet::Event<T>
    **/
   PalletEvmEvent: {
     _enum: {
@@ -1242,7 +1235,7 @@
     }
   },
   /**
-   * Lookup111: ethereum::log::Log
+   * Lookup110: ethereum::log::Log
    **/
   EthereumLog: {
     address: 'H160',
@@ -1250,7 +1243,7 @@
     data: 'Bytes'
   },
   /**
-   * Lookup113: pallet_ethereum::pallet::Event
+   * Lookup112: pallet_ethereum::pallet::Event
    **/
   PalletEthereumEvent: {
     _enum: {
@@ -1263,7 +1256,7 @@
     }
   },
   /**
-   * Lookup114: evm_core::error::ExitReason
+   * Lookup113: evm_core::error::ExitReason
    **/
   EvmCoreErrorExitReason: {
     _enum: {
@@ -1274,13 +1267,13 @@
     }
   },
   /**
-   * Lookup115: evm_core::error::ExitSucceed
+   * Lookup114: evm_core::error::ExitSucceed
    **/
   EvmCoreErrorExitSucceed: {
     _enum: ['Stopped', 'Returned', 'Suicided']
   },
   /**
-   * Lookup116: evm_core::error::ExitError
+   * Lookup115: evm_core::error::ExitError
    **/
   EvmCoreErrorExitError: {
     _enum: {
@@ -1302,13 +1295,13 @@
     }
   },
   /**
-   * Lookup119: evm_core::error::ExitRevert
+   * Lookup118: evm_core::error::ExitRevert
    **/
   EvmCoreErrorExitRevert: {
     _enum: ['Reverted']
   },
   /**
-   * Lookup120: evm_core::error::ExitFatal
+   * Lookup119: evm_core::error::ExitFatal
    **/
   EvmCoreErrorExitFatal: {
     _enum: {
@@ -1319,7 +1312,7 @@
     }
   },
   /**
-   * Lookup121: pallet_evm_contract_helpers::pallet::Event<T>
+   * Lookup120: pallet_evm_contract_helpers::pallet::Event<T>
    **/
   PalletEvmContractHelpersEvent: {
     _enum: {
@@ -1329,25 +1322,25 @@
     }
   },
   /**
-   * Lookup122: pallet_evm_migration::pallet::Event<T>
+   * Lookup121: pallet_evm_migration::pallet::Event<T>
    **/
   PalletEvmMigrationEvent: {
     _enum: ['TestEvent']
   },
   /**
-   * Lookup123: pallet_maintenance::pallet::Event<T>
+   * Lookup122: pallet_maintenance::pallet::Event<T>
    **/
   PalletMaintenanceEvent: {
     _enum: ['MaintenanceEnabled', 'MaintenanceDisabled']
   },
   /**
-   * Lookup124: pallet_test_utils::pallet::Event<T>
+   * Lookup123: pallet_test_utils::pallet::Event<T>
    **/
   PalletTestUtilsEvent: {
     _enum: ['ValueIsSet', 'ShouldRollback', 'BatchCompleted']
   },
   /**
-   * Lookup125: frame_system::Phase
+   * Lookup124: frame_system::Phase
    **/
   FrameSystemPhase: {
     _enum: {
@@ -1357,14 +1350,14 @@
     }
   },
   /**
-   * Lookup127: frame_system::LastRuntimeUpgradeInfo
+   * Lookup126: frame_system::LastRuntimeUpgradeInfo
    **/
   FrameSystemLastRuntimeUpgradeInfo: {
     specVersion: 'Compact<u32>',
     specName: 'Text'
   },
   /**
-   * Lookup128: frame_system::pallet::Call<T>
+   * Lookup127: frame_system::pallet::Call<T>
    **/
   FrameSystemCall: {
     _enum: {
@@ -1402,7 +1395,7 @@
     }
   },
   /**
-   * Lookup133: frame_system::limits::BlockWeights
+   * Lookup132: frame_system::limits::BlockWeights
    **/
   FrameSystemLimitsBlockWeights: {
     baseBlock: 'SpWeightsWeightV2Weight',
@@ -1410,7 +1403,7 @@
     perClass: 'FrameSupportDispatchPerDispatchClassWeightsPerClass'
   },
   /**
-   * Lookup134: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
+   * Lookup133: frame_support::dispatch::PerDispatchClass<frame_system::limits::WeightsPerClass>
    **/
   FrameSupportDispatchPerDispatchClassWeightsPerClass: {
     normal: 'FrameSystemLimitsWeightsPerClass',
@@ -1418,7 +1411,7 @@
     mandatory: 'FrameSystemLimitsWeightsPerClass'
   },
   /**
-   * Lookup135: frame_system::limits::WeightsPerClass
+   * Lookup134: frame_system::limits::WeightsPerClass
    **/
   FrameSystemLimitsWeightsPerClass: {
     baseExtrinsic: 'SpWeightsWeightV2Weight',
@@ -1427,13 +1420,13 @@
     reserved: 'Option<SpWeightsWeightV2Weight>'
   },
   /**
-   * Lookup137: frame_system::limits::BlockLength
+   * Lookup136: frame_system::limits::BlockLength
    **/
   FrameSystemLimitsBlockLength: {
     max: 'FrameSupportDispatchPerDispatchClassU32'
   },
   /**
-   * Lookup138: frame_support::dispatch::PerDispatchClass<T>
+   * Lookup137: frame_support::dispatch::PerDispatchClass<T>
    **/
   FrameSupportDispatchPerDispatchClassU32: {
     normal: 'u32',
@@ -1441,14 +1434,14 @@
     mandatory: 'u32'
   },
   /**
-   * Lookup139: sp_weights::RuntimeDbWeight
+   * Lookup138: sp_weights::RuntimeDbWeight
    **/
   SpWeightsRuntimeDbWeight: {
     read: 'u64',
     write: 'u64'
   },
   /**
-   * Lookup140: sp_version::RuntimeVersion
+   * Lookup139: sp_version::RuntimeVersion
    **/
   SpVersionRuntimeVersion: {
     specName: 'Text',
@@ -1461,13 +1454,13 @@
     stateVersion: 'u8'
   },
   /**
-   * Lookup145: frame_system::pallet::Error<T>
+   * Lookup144: frame_system::pallet::Error<T>
    **/
   FrameSystemError: {
     _enum: ['InvalidSpecName', 'SpecVersionNeedsToIncrease', 'FailedToExtractRuntimeVersion', 'NonDefaultComposite', 'NonZeroRefCount', 'CallFiltered']
   },
   /**
-   * Lookup146: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
+   * Lookup145: polkadot_primitives::v2::PersistedValidationData<primitive_types::H256, N>
    **/
   PolkadotPrimitivesV2PersistedValidationData: {
     parentHead: 'Bytes',
@@ -1476,19 +1469,19 @@
     maxPovSize: 'u32'
   },
   /**
-   * Lookup149: polkadot_primitives::v2::UpgradeRestriction
+   * Lookup148: polkadot_primitives::v2::UpgradeRestriction
    **/
   PolkadotPrimitivesV2UpgradeRestriction: {
     _enum: ['Present']
   },
   /**
-   * Lookup150: sp_trie::storage_proof::StorageProof
+   * Lookup149: sp_trie::storage_proof::StorageProof
    **/
   SpTrieStorageProof: {
     trieNodes: 'BTreeSet<Bytes>'
   },
   /**
-   * Lookup152: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
+   * Lookup151: cumulus_pallet_parachain_system::relay_state_snapshot::MessagingStateSnapshot
    **/
   CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot: {
     dmqMqcHead: 'H256',
@@ -1497,7 +1490,7 @@
     egressChannels: 'Vec<(u32,PolkadotPrimitivesV2AbridgedHrmpChannel)>'
   },
   /**
-   * Lookup155: polkadot_primitives::v2::AbridgedHrmpChannel
+   * Lookup154: polkadot_primitives::v2::AbridgedHrmpChannel
    **/
   PolkadotPrimitivesV2AbridgedHrmpChannel: {
     maxCapacity: 'u32',
@@ -1508,7 +1501,7 @@
     mqcHead: 'Option<H256>'
   },
   /**
-   * Lookup156: polkadot_primitives::v2::AbridgedHostConfiguration
+   * Lookup155: polkadot_primitives::v2::AbridgedHostConfiguration
    **/
   PolkadotPrimitivesV2AbridgedHostConfiguration: {
     maxCodeSize: 'u32',
@@ -1522,14 +1515,14 @@
     validationUpgradeDelay: 'u32'
   },
   /**
-   * Lookup162: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
+   * Lookup161: polkadot_core_primitives::OutboundHrmpMessage<polkadot_parachain::primitives::Id>
    **/
   PolkadotCorePrimitivesOutboundHrmpMessage: {
     recipient: 'u32',
     data: 'Bytes'
   },
   /**
-   * Lookup163: cumulus_pallet_parachain_system::pallet::Call<T>
+   * Lookup162: cumulus_pallet_parachain_system::pallet::Call<T>
    **/
   CumulusPalletParachainSystemCall: {
     _enum: {
@@ -1548,7 +1541,7 @@
     }
   },
   /**
-   * Lookup164: cumulus_primitives_parachain_inherent::ParachainInherentData
+   * Lookup163: cumulus_primitives_parachain_inherent::ParachainInherentData
    **/
   CumulusPrimitivesParachainInherentParachainInherentData: {
     validationData: 'PolkadotPrimitivesV2PersistedValidationData',
@@ -1557,27 +1550,27 @@
     horizontalMessages: 'BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>'
   },
   /**
-   * Lookup166: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
+   * Lookup165: polkadot_core_primitives::InboundDownwardMessage<BlockNumber>
    **/
   PolkadotCorePrimitivesInboundDownwardMessage: {
     sentAt: 'u32',
     msg: 'Bytes'
   },
   /**
-   * Lookup169: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
+   * Lookup168: polkadot_core_primitives::InboundHrmpMessage<BlockNumber>
    **/
   PolkadotCorePrimitivesInboundHrmpMessage: {
     sentAt: 'u32',
     data: 'Bytes'
   },
   /**
-   * Lookup172: cumulus_pallet_parachain_system::pallet::Error<T>
+   * Lookup171: cumulus_pallet_parachain_system::pallet::Error<T>
    **/
   CumulusPalletParachainSystemError: {
     _enum: ['OverlappingUpgrades', 'ProhibitedByPolkadot', 'TooBig', 'ValidationDataNotAvailable', 'HostConfigurationNotAvailable', 'NotScheduled', 'NothingAuthorized', 'Unauthorized']
   },
   /**
-   * Lookup174: pallet_balances::BalanceLock<Balance>
+   * Lookup173: pallet_balances::BalanceLock<Balance>
    **/
   PalletBalancesBalanceLock: {
     id: '[u8;8]',
@@ -1585,26 +1578,26 @@
     reasons: 'PalletBalancesReasons'
   },
   /**
-   * Lookup175: pallet_balances::Reasons
+   * Lookup174: pallet_balances::Reasons
    **/
   PalletBalancesReasons: {
     _enum: ['Fee', 'Misc', 'All']
   },
   /**
-   * Lookup178: pallet_balances::ReserveData<ReserveIdentifier, Balance>
+   * Lookup177: pallet_balances::ReserveData<ReserveIdentifier, Balance>
    **/
   PalletBalancesReserveData: {
     id: '[u8;16]',
     amount: 'u128'
   },
   /**
-   * Lookup180: pallet_balances::Releases
+   * Lookup179: pallet_balances::Releases
    **/
   PalletBalancesReleases: {
     _enum: ['V1_0_0', 'V2_0_0']
   },
   /**
-   * Lookup181: pallet_balances::pallet::Call<T, I>
+   * Lookup180: pallet_balances::pallet::Call<T, I>
    **/
   PalletBalancesCall: {
     _enum: {
@@ -1637,13 +1630,13 @@
     }
   },
   /**
-   * Lookup184: pallet_balances::pallet::Error<T, I>
+   * Lookup183: pallet_balances::pallet::Error<T, I>
    **/
   PalletBalancesError: {
     _enum: ['VestingBalance', 'LiquidityRestrictions', 'InsufficientBalance', 'ExistentialDeposit', 'KeepAlive', 'ExistingVestingSchedule', 'DeadAccount', 'TooManyReserves']
   },
   /**
-   * Lookup186: pallet_timestamp::pallet::Call<T>
+   * Lookup185: pallet_timestamp::pallet::Call<T>
    **/
   PalletTimestampCall: {
     _enum: {
@@ -1653,13 +1646,13 @@
     }
   },
   /**
-   * Lookup188: pallet_transaction_payment::Releases
+   * Lookup187: pallet_transaction_payment::Releases
    **/
   PalletTransactionPaymentReleases: {
     _enum: ['V1Ancient', 'V2']
   },
   /**
-   * Lookup189: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
+   * Lookup188: pallet_treasury::Proposal<sp_core::crypto::AccountId32, Balance>
    **/
   PalletTreasuryProposal: {
     proposer: 'AccountId32',
@@ -1668,7 +1661,7 @@
     bond: 'u128'
   },
   /**
-   * Lookup192: pallet_treasury::pallet::Call<T, I>
+   * Lookup191: pallet_treasury::pallet::Call<T, I>
    **/
   PalletTreasuryCall: {
     _enum: {
@@ -1692,17 +1685,17 @@
     }
   },
   /**
-   * Lookup195: frame_support::PalletId
+   * Lookup194: frame_support::PalletId
    **/
   FrameSupportPalletId: '[u8;8]',
   /**
-   * Lookup196: pallet_treasury::pallet::Error<T, I>
+   * Lookup195: pallet_treasury::pallet::Error<T, I>
    **/
   PalletTreasuryError: {
     _enum: ['InsufficientProposersBalance', 'InvalidIndex', 'TooManyApprovals', 'InsufficientPermission', 'ProposalNotApproved']
   },
   /**
-   * Lookup197: pallet_sudo::pallet::Call<T>
+   * Lookup196: pallet_sudo::pallet::Call<T>
    **/
   PalletSudoCall: {
     _enum: {
@@ -1726,7 +1719,7 @@
     }
   },
   /**
-   * Lookup199: orml_vesting::module::Call<T>
+   * Lookup198: orml_vesting::module::Call<T>
    **/
   OrmlVestingModuleCall: {
     _enum: {
@@ -1745,7 +1738,7 @@
     }
   },
   /**
-   * Lookup201: orml_xtokens::module::Call<T>
+   * Lookup200: orml_xtokens::module::Call<T>
    **/
   OrmlXtokensModuleCall: {
     _enum: {
@@ -1788,7 +1781,7 @@
     }
   },
   /**
-   * Lookup202: xcm::VersionedMultiAsset
+   * Lookup201: xcm::VersionedMultiAsset
    **/
   XcmVersionedMultiAsset: {
     _enum: {
@@ -1797,7 +1790,7 @@
     }
   },
   /**
-   * Lookup205: orml_tokens::module::Call<T>
+   * Lookup204: orml_tokens::module::Call<T>
    **/
   OrmlTokensModuleCall: {
     _enum: {
@@ -1831,7 +1824,7 @@
     }
   },
   /**
-   * Lookup206: cumulus_pallet_xcmp_queue::pallet::Call<T>
+   * Lookup205: cumulus_pallet_xcmp_queue::pallet::Call<T>
    **/
   CumulusPalletXcmpQueueCall: {
     _enum: {
@@ -1880,7 +1873,7 @@
     }
   },
   /**
-   * Lookup207: pallet_xcm::pallet::Call<T>
+   * Lookup206: pallet_xcm::pallet::Call<T>
    **/
   PalletXcmCall: {
     _enum: {
@@ -1934,7 +1927,7 @@
     }
   },
   /**
-   * Lookup208: xcm::VersionedXcm<RuntimeCall>
+   * Lookup207: xcm::VersionedXcm<RuntimeCall>
    **/
   XcmVersionedXcm: {
     _enum: {
@@ -1944,7 +1937,7 @@
     }
   },
   /**
-   * Lookup209: xcm::v0::Xcm<RuntimeCall>
+   * Lookup208: xcm::v0::Xcm<RuntimeCall>
    **/
   XcmV0Xcm: {
     _enum: {
@@ -1998,7 +1991,7 @@
     }
   },
   /**
-   * Lookup211: xcm::v0::order::Order<RuntimeCall>
+   * Lookup210: xcm::v0::order::Order<RuntimeCall>
    **/
   XcmV0Order: {
     _enum: {
@@ -2041,7 +2034,7 @@
     }
   },
   /**
-   * Lookup213: xcm::v0::Response
+   * Lookup212: xcm::v0::Response
    **/
   XcmV0Response: {
     _enum: {
@@ -2049,7 +2042,7 @@
     }
   },
   /**
-   * Lookup214: xcm::v1::Xcm<RuntimeCall>
+   * Lookup213: xcm::v1::Xcm<RuntimeCall>
    **/
   XcmV1Xcm: {
     _enum: {
@@ -2108,7 +2101,7 @@
     }
   },
   /**
-   * Lookup216: xcm::v1::order::Order<RuntimeCall>
+   * Lookup215: xcm::v1::order::Order<RuntimeCall>
    **/
   XcmV1Order: {
     _enum: {
@@ -2153,7 +2146,7 @@
     }
   },
   /**
-   * Lookup218: xcm::v1::Response
+   * Lookup217: xcm::v1::Response
    **/
   XcmV1Response: {
     _enum: {
@@ -2162,11 +2155,11 @@
     }
   },
   /**
-   * Lookup232: cumulus_pallet_xcm::pallet::Call<T>
+   * Lookup231: cumulus_pallet_xcm::pallet::Call<T>
    **/
   CumulusPalletXcmCall: 'Null',
   /**
-   * Lookup233: cumulus_pallet_dmp_queue::pallet::Call<T>
+   * Lookup232: cumulus_pallet_dmp_queue::pallet::Call<T>
    **/
   CumulusPalletDmpQueueCall: {
     _enum: {
@@ -2177,7 +2170,7 @@
     }
   },
   /**
-   * Lookup234: pallet_inflation::pallet::Call<T>
+   * Lookup233: pallet_inflation::pallet::Call<T>
    **/
   PalletInflationCall: {
     _enum: {
@@ -2187,7 +2180,7 @@
     }
   },
   /**
-   * Lookup235: pallet_unique::Call<T>
+   * Lookup234: pallet_unique::Call<T>
    **/
   PalletUniqueCall: {
     _enum: {
@@ -2324,7 +2317,7 @@
     }
   },
   /**
-   * Lookup240: up_data_structs::CollectionMode
+   * Lookup239: up_data_structs::CollectionMode
    **/
   UpDataStructsCollectionMode: {
     _enum: {
@@ -2334,7 +2327,7 @@
     }
   },
   /**
-   * Lookup241: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
+   * Lookup240: up_data_structs::CreateCollectionData<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCreateCollectionData: {
     mode: 'UpDataStructsCollectionMode',
@@ -2349,13 +2342,13 @@
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup243: up_data_structs::AccessMode
+   * Lookup242: up_data_structs::AccessMode
    **/
   UpDataStructsAccessMode: {
     _enum: ['Normal', 'AllowList']
   },
   /**
-   * Lookup245: up_data_structs::CollectionLimits
+   * Lookup244: up_data_structs::CollectionLimits
    **/
   UpDataStructsCollectionLimits: {
     accountTokenOwnershipLimit: 'Option<u32>',
@@ -2369,7 +2362,7 @@
     transfersEnabled: 'Option<bool>'
   },
   /**
-   * Lookup247: up_data_structs::SponsoringRateLimit
+   * Lookup246: up_data_structs::SponsoringRateLimit
    **/
   UpDataStructsSponsoringRateLimit: {
     _enum: {
@@ -2378,7 +2371,7 @@
     }
   },
   /**
-   * Lookup250: up_data_structs::CollectionPermissions
+   * Lookup249: up_data_structs::CollectionPermissions
    **/
   UpDataStructsCollectionPermissions: {
     access: 'Option<UpDataStructsAccessMode>',
@@ -2386,7 +2379,7 @@
     nesting: 'Option<UpDataStructsNestingPermissions>'
   },
   /**
-   * Lookup252: up_data_structs::NestingPermissions
+   * Lookup251: up_data_structs::NestingPermissions
    **/
   UpDataStructsNestingPermissions: {
     tokenOwner: 'bool',
@@ -2394,18 +2387,18 @@
     restricted: 'Option<UpDataStructsOwnerRestrictedSet>'
   },
   /**
-   * Lookup254: up_data_structs::OwnerRestrictedSet
+   * Lookup253: up_data_structs::OwnerRestrictedSet
    **/
   UpDataStructsOwnerRestrictedSet: 'BTreeSet<u32>',
   /**
-   * Lookup259: up_data_structs::PropertyKeyPermission
+   * Lookup258: up_data_structs::PropertyKeyPermission
    **/
   UpDataStructsPropertyKeyPermission: {
     key: 'Bytes',
     permission: 'UpDataStructsPropertyPermission'
   },
   /**
-   * Lookup260: up_data_structs::PropertyPermission
+   * Lookup259: up_data_structs::PropertyPermission
    **/
   UpDataStructsPropertyPermission: {
     mutable: 'bool',
@@ -2413,14 +2406,14 @@
     tokenOwner: 'bool'
   },
   /**
-   * Lookup263: up_data_structs::Property
+   * Lookup262: up_data_structs::Property
    **/
   UpDataStructsProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup266: up_data_structs::CreateItemData
+   * Lookup265: up_data_structs::CreateItemData
    **/
   UpDataStructsCreateItemData: {
     _enum: {
@@ -2430,26 +2423,26 @@
     }
   },
   /**
-   * Lookup267: up_data_structs::CreateNftData
+   * Lookup266: up_data_structs::CreateNftData
    **/
   UpDataStructsCreateNftData: {
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup268: up_data_structs::CreateFungibleData
+   * Lookup267: up_data_structs::CreateFungibleData
    **/
   UpDataStructsCreateFungibleData: {
     value: 'u128'
   },
   /**
-   * Lookup269: up_data_structs::CreateReFungibleData
+   * Lookup268: up_data_structs::CreateReFungibleData
    **/
   UpDataStructsCreateReFungibleData: {
     pieces: 'u128',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup272: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup271: up_data_structs::CreateItemExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateItemExData: {
     _enum: {
@@ -2460,14 +2453,14 @@
     }
   },
   /**
-   * Lookup274: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup273: up_data_structs::CreateNftExData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateNftExData: {
     properties: 'Vec<UpDataStructsProperty>',
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup281: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup280: up_data_structs::CreateRefungibleExSingleOwner<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateRefungibleExSingleOwner: {
     user: 'PalletEvmAccountBasicCrossAccountIdRepr',
@@ -2475,14 +2468,14 @@
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup283: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup282: up_data_structs::CreateRefungibleExMultipleOwners<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsCreateRefungibleExMultipleOwners: {
     users: 'BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>',
     properties: 'Vec<UpDataStructsProperty>'
   },
   /**
-   * Lookup284: pallet_unique_scheduler_v2::pallet::Call<T>
+   * Lookup283: pallet_unique_scheduler_v2::pallet::Call<T>
    **/
   PalletUniqueSchedulerV2Call: {
     _enum: {
@@ -2526,7 +2519,7 @@
     }
   },
   /**
-   * Lookup287: pallet_configuration::pallet::Call<T>
+   * Lookup286: pallet_configuration::pallet::Call<T>
    **/
   PalletConfigurationCall: {
     _enum: {
@@ -2539,15 +2532,15 @@
     }
   },
   /**
-   * Lookup289: pallet_template_transaction_payment::Call<T>
+   * Lookup288: pallet_template_transaction_payment::Call<T>
    **/
   PalletTemplateTransactionPaymentCall: 'Null',
   /**
-   * Lookup290: pallet_structure::pallet::Call<T>
+   * Lookup289: pallet_structure::pallet::Call<T>
    **/
   PalletStructureCall: 'Null',
   /**
-   * Lookup291: pallet_rmrk_core::pallet::Call<T>
+   * Lookup290: pallet_rmrk_core::pallet::Call<T>
    **/
   PalletRmrkCoreCall: {
     _enum: {
@@ -2638,7 +2631,7 @@
     }
   },
   /**
-   * Lookup297: rmrk_traits::resource::ResourceTypes<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup296: rmrk_traits::resource::ResourceTypes<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceResourceTypes: {
     _enum: {
@@ -2648,7 +2641,7 @@
     }
   },
   /**
-   * Lookup299: rmrk_traits::resource::BasicResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup298: rmrk_traits::resource::BasicResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceBasicResource: {
     src: 'Option<Bytes>',
@@ -2657,7 +2650,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup301: rmrk_traits::resource::ComposableResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup300: rmrk_traits::resource::ComposableResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceComposableResource: {
     parts: 'Vec<u32>',
@@ -2668,7 +2661,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup302: rmrk_traits::resource::SlotResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup301: rmrk_traits::resource::SlotResource<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceSlotResource: {
     base: 'u32',
@@ -2679,7 +2672,7 @@
     thumb: 'Option<Bytes>'
   },
   /**
-   * Lookup305: pallet_rmrk_equip::pallet::Call<T>
+   * Lookup304: pallet_rmrk_equip::pallet::Call<T>
    **/
   PalletRmrkEquipCall: {
     _enum: {
@@ -2700,7 +2693,7 @@
     }
   },
   /**
-   * Lookup308: rmrk_traits::part::PartType<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup307: rmrk_traits::part::PartType<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartPartType: {
     _enum: {
@@ -2709,7 +2702,7 @@
     }
   },
   /**
-   * Lookup310: rmrk_traits::part::FixedPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup309: rmrk_traits::part::FixedPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartFixedPart: {
     id: 'u32',
@@ -2717,7 +2710,7 @@
     src: 'Bytes'
   },
   /**
-   * Lookup311: rmrk_traits::part::SlotPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup310: rmrk_traits::part::SlotPart<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartSlotPart: {
     id: 'u32',
@@ -2726,7 +2719,7 @@
     z: 'u32'
   },
   /**
-   * Lookup312: rmrk_traits::part::EquippableList<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup311: rmrk_traits::part::EquippableList<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPartEquippableList: {
     _enum: {
@@ -2736,7 +2729,7 @@
     }
   },
   /**
-   * Lookup314: rmrk_traits::theme::Theme<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>, S>>
+   * Lookup313: rmrk_traits::theme::Theme<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>, S>>
    **/
   RmrkTraitsTheme: {
     name: 'Bytes',
@@ -2744,14 +2737,14 @@
     inherit: 'bool'
   },
   /**
-   * Lookup316: rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup315: rmrk_traits::theme::ThemeProperty<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsThemeThemeProperty: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup318: pallet_app_promotion::pallet::Call<T>
+   * Lookup317: pallet_app_promotion::pallet::Call<T>
    **/
   PalletAppPromotionCall: {
     _enum: {
@@ -2780,7 +2773,7 @@
     }
   },
   /**
-   * Lookup319: pallet_foreign_assets::module::Call<T>
+   * Lookup318: pallet_foreign_assets::module::Call<T>
    **/
   PalletForeignAssetsModuleCall: {
     _enum: {
@@ -2797,7 +2790,7 @@
     }
   },
   /**
-   * Lookup320: pallet_evm::pallet::Call<T>
+   * Lookup319: pallet_evm::pallet::Call<T>
    **/
   PalletEvmCall: {
     _enum: {
@@ -2840,7 +2833,7 @@
     }
   },
   /**
-   * Lookup326: pallet_ethereum::pallet::Call<T>
+   * Lookup325: pallet_ethereum::pallet::Call<T>
    **/
   PalletEthereumCall: {
     _enum: {
@@ -2850,7 +2843,7 @@
     }
   },
   /**
-   * Lookup327: ethereum::transaction::TransactionV2
+   * Lookup326: ethereum::transaction::TransactionV2
    **/
   EthereumTransactionTransactionV2: {
     _enum: {
@@ -2860,7 +2853,7 @@
     }
   },
   /**
-   * Lookup328: ethereum::transaction::LegacyTransaction
+   * Lookup327: ethereum::transaction::LegacyTransaction
    **/
   EthereumTransactionLegacyTransaction: {
     nonce: 'U256',
@@ -2872,7 +2865,7 @@
     signature: 'EthereumTransactionTransactionSignature'
   },
   /**
-   * Lookup329: ethereum::transaction::TransactionAction
+   * Lookup328: ethereum::transaction::TransactionAction
    **/
   EthereumTransactionTransactionAction: {
     _enum: {
@@ -2881,7 +2874,7 @@
     }
   },
   /**
-   * Lookup330: ethereum::transaction::TransactionSignature
+   * Lookup329: ethereum::transaction::TransactionSignature
    **/
   EthereumTransactionTransactionSignature: {
     v: 'u64',
@@ -2889,7 +2882,7 @@
     s: 'H256'
   },
   /**
-   * Lookup332: ethereum::transaction::EIP2930Transaction
+   * Lookup331: ethereum::transaction::EIP2930Transaction
    **/
   EthereumTransactionEip2930Transaction: {
     chainId: 'u64',
@@ -2905,14 +2898,14 @@
     s: 'H256'
   },
   /**
-   * Lookup334: ethereum::transaction::AccessListItem
+   * Lookup333: ethereum::transaction::AccessListItem
    **/
   EthereumTransactionAccessListItem: {
     address: 'H160',
     storageKeys: 'Vec<H256>'
   },
   /**
-   * Lookup335: ethereum::transaction::EIP1559Transaction
+   * Lookup334: ethereum::transaction::EIP1559Transaction
    **/
   EthereumTransactionEip1559Transaction: {
     chainId: 'u64',
@@ -2929,7 +2922,7 @@
     s: 'H256'
   },
   /**
-   * Lookup336: pallet_evm_migration::pallet::Call<T>
+   * Lookup335: pallet_evm_migration::pallet::Call<T>
    **/
   PalletEvmMigrationCall: {
     _enum: {
@@ -2953,13 +2946,13 @@
     }
   },
   /**
-   * Lookup340: pallet_maintenance::pallet::Call<T>
+   * Lookup339: pallet_maintenance::pallet::Call<T>
    **/
   PalletMaintenanceCall: {
     _enum: ['enable', 'disable']
   },
   /**
-   * Lookup341: pallet_test_utils::pallet::Call<T>
+   * Lookup340: pallet_test_utils::pallet::Call<T>
    **/
   PalletTestUtilsCall: {
     _enum: {
@@ -2982,32 +2975,32 @@
     }
   },
   /**
-   * Lookup343: pallet_sudo::pallet::Error<T>
+   * Lookup342: pallet_sudo::pallet::Error<T>
    **/
   PalletSudoError: {
     _enum: ['RequireSudo']
   },
   /**
-   * Lookup345: orml_vesting::module::Error<T>
+   * Lookup344: orml_vesting::module::Error<T>
    **/
   OrmlVestingModuleError: {
     _enum: ['ZeroVestingPeriod', 'ZeroVestingPeriodCount', 'InsufficientBalanceToLock', 'TooManyVestingSchedules', 'AmountLow', 'MaxVestingSchedulesExceeded']
   },
   /**
-   * Lookup346: orml_xtokens::module::Error<T>
+   * Lookup345: orml_xtokens::module::Error<T>
    **/
   OrmlXtokensModuleError: {
     _enum: ['AssetHasNoReserve', 'NotCrossChainTransfer', 'InvalidDest', 'NotCrossChainTransferableCurrency', 'UnweighableMessage', 'XcmExecutionFailed', 'CannotReanchor', 'InvalidAncestry', 'InvalidAsset', 'DestinationNotInvertible', 'BadVersion', 'DistinctReserveForAssetAndFee', 'ZeroFee', 'ZeroAmount', 'TooManyAssetsBeingSent', 'AssetIndexNonExistent', 'FeeNotEnough', 'NotSupportedMultiLocation', 'MinXcmFeeNotDefined']
   },
   /**
-   * Lookup349: orml_tokens::BalanceLock<Balance>
+   * Lookup348: orml_tokens::BalanceLock<Balance>
    **/
   OrmlTokensBalanceLock: {
     id: '[u8;8]',
     amount: 'u128'
   },
   /**
-   * Lookup351: orml_tokens::AccountData<Balance>
+   * Lookup350: orml_tokens::AccountData<Balance>
    **/
   OrmlTokensAccountData: {
     free: 'u128',
@@ -3015,20 +3008,20 @@
     frozen: 'u128'
   },
   /**
-   * Lookup353: orml_tokens::ReserveData<ReserveIdentifier, Balance>
+   * Lookup352: orml_tokens::ReserveData<ReserveIdentifier, Balance>
    **/
   OrmlTokensReserveData: {
     id: 'Null',
     amount: 'u128'
   },
   /**
-   * Lookup355: orml_tokens::module::Error<T>
+   * Lookup354: orml_tokens::module::Error<T>
    **/
   OrmlTokensModuleError: {
     _enum: ['BalanceTooLow', 'AmountIntoBalanceFailed', 'LiquidityRestrictions', 'MaxLocksExceeded', 'KeepAlive', 'ExistentialDeposit', 'DeadAccount', 'TooManyReserves']
   },
   /**
-   * Lookup357: cumulus_pallet_xcmp_queue::InboundChannelDetails
+   * Lookup356: cumulus_pallet_xcmp_queue::InboundChannelDetails
    **/
   CumulusPalletXcmpQueueInboundChannelDetails: {
     sender: 'u32',
@@ -3036,19 +3029,19 @@
     messageMetadata: 'Vec<(u32,PolkadotParachainPrimitivesXcmpMessageFormat)>'
   },
   /**
-   * Lookup358: cumulus_pallet_xcmp_queue::InboundState
+   * Lookup357: cumulus_pallet_xcmp_queue::InboundState
    **/
   CumulusPalletXcmpQueueInboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup361: polkadot_parachain::primitives::XcmpMessageFormat
+   * Lookup360: polkadot_parachain::primitives::XcmpMessageFormat
    **/
   PolkadotParachainPrimitivesXcmpMessageFormat: {
     _enum: ['ConcatenatedVersionedXcm', 'ConcatenatedEncodedBlob', 'Signals']
   },
   /**
-   * Lookup364: cumulus_pallet_xcmp_queue::OutboundChannelDetails
+   * Lookup363: cumulus_pallet_xcmp_queue::OutboundChannelDetails
    **/
   CumulusPalletXcmpQueueOutboundChannelDetails: {
     recipient: 'u32',
@@ -3058,13 +3051,13 @@
     lastIndex: 'u16'
   },
   /**
-   * Lookup365: cumulus_pallet_xcmp_queue::OutboundState
+   * Lookup364: cumulus_pallet_xcmp_queue::OutboundState
    **/
   CumulusPalletXcmpQueueOutboundState: {
     _enum: ['Ok', 'Suspended']
   },
   /**
-   * Lookup367: cumulus_pallet_xcmp_queue::QueueConfigData
+   * Lookup366: cumulus_pallet_xcmp_queue::QueueConfigData
    **/
   CumulusPalletXcmpQueueQueueConfigData: {
     suspendThreshold: 'u32',
@@ -3075,29 +3068,29 @@
     xcmpMaxIndividualWeight: 'SpWeightsWeightV2Weight'
   },
   /**
-   * Lookup369: cumulus_pallet_xcmp_queue::pallet::Error<T>
+   * Lookup368: cumulus_pallet_xcmp_queue::pallet::Error<T>
    **/
   CumulusPalletXcmpQueueError: {
     _enum: ['FailedToSend', 'BadXcmOrigin', 'BadXcm', 'BadOverweightIndex', 'WeightOverLimit']
   },
   /**
-   * Lookup370: pallet_xcm::pallet::Error<T>
+   * Lookup369: pallet_xcm::pallet::Error<T>
    **/
   PalletXcmError: {
     _enum: ['Unreachable', 'SendFailure', 'Filtered', 'UnweighableMessage', 'DestinationNotInvertible', 'Empty', 'CannotReanchor', 'TooManyAssets', 'InvalidOrigin', 'BadVersion', 'BadLocation', 'NoSubscription', 'AlreadySubscribed']
   },
   /**
-   * Lookup371: cumulus_pallet_xcm::pallet::Error<T>
+   * Lookup370: cumulus_pallet_xcm::pallet::Error<T>
    **/
   CumulusPalletXcmError: 'Null',
   /**
-   * Lookup372: cumulus_pallet_dmp_queue::ConfigData
+   * Lookup371: cumulus_pallet_dmp_queue::ConfigData
    **/
   CumulusPalletDmpQueueConfigData: {
     maxIndividual: 'SpWeightsWeightV2Weight'
   },
   /**
-   * Lookup373: cumulus_pallet_dmp_queue::PageIndexData
+   * Lookup372: cumulus_pallet_dmp_queue::PageIndexData
    **/
   CumulusPalletDmpQueuePageIndexData: {
     beginUsed: 'u32',
@@ -3105,26 +3098,26 @@
     overweightCount: 'u64'
   },
   /**
-   * Lookup376: cumulus_pallet_dmp_queue::pallet::Error<T>
+   * Lookup375: cumulus_pallet_dmp_queue::pallet::Error<T>
    **/
   CumulusPalletDmpQueueError: {
     _enum: ['Unknown', 'OverLimit']
   },
   /**
-   * Lookup380: pallet_unique::Error<T>
+   * Lookup379: pallet_unique::Error<T>
    **/
   PalletUniqueError: {
-    _enum: ['CollectionDecimalPointLimitExceeded', 'ConfirmUnsetSponsorFail', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
+    _enum: ['CollectionDecimalPointLimitExceeded', 'EmptyArgument', 'RepartitionCalledOnNonRefungibleCollection']
   },
   /**
-   * Lookup381: pallet_unique_scheduler_v2::BlockAgenda<T>
+   * Lookup380: pallet_unique_scheduler_v2::BlockAgenda<T>
    **/
   PalletUniqueSchedulerV2BlockAgenda: {
     agenda: 'Vec<Option<PalletUniqueSchedulerV2Scheduled>>',
     freePlaces: 'u32'
   },
   /**
-   * Lookup384: pallet_unique_scheduler_v2::Scheduled<Name, pallet_unique_scheduler_v2::ScheduledCall<T>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
+   * Lookup383: pallet_unique_scheduler_v2::Scheduled<Name, pallet_unique_scheduler_v2::ScheduledCall<T>, BlockNumber, opal_runtime::OriginCaller, sp_core::crypto::AccountId32>
    **/
   PalletUniqueSchedulerV2Scheduled: {
     maybeId: 'Option<[u8;32]>',
@@ -3134,7 +3127,7 @@
     origin: 'OpalRuntimeOriginCaller'
   },
   /**
-   * Lookup385: pallet_unique_scheduler_v2::ScheduledCall<T>
+   * Lookup384: pallet_unique_scheduler_v2::ScheduledCall<T>
    **/
   PalletUniqueSchedulerV2ScheduledCall: {
     _enum: {
@@ -3149,7 +3142,7 @@
     }
   },
   /**
-   * Lookup387: opal_runtime::OriginCaller
+   * Lookup386: opal_runtime::OriginCaller
    **/
   OpalRuntimeOriginCaller: {
     _enum: {
@@ -3258,7 +3251,7 @@
     }
   },
   /**
-   * Lookup388: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
+   * Lookup387: frame_support::dispatch::RawOrigin<sp_core::crypto::AccountId32>
    **/
   FrameSupportDispatchRawOrigin: {
     _enum: {
@@ -3268,7 +3261,7 @@
     }
   },
   /**
-   * Lookup389: pallet_xcm::pallet::Origin
+   * Lookup388: pallet_xcm::pallet::Origin
    **/
   PalletXcmOrigin: {
     _enum: {
@@ -3277,7 +3270,7 @@
     }
   },
   /**
-   * Lookup390: cumulus_pallet_xcm::pallet::Origin
+   * Lookup389: cumulus_pallet_xcm::pallet::Origin
    **/
   CumulusPalletXcmOrigin: {
     _enum: {
@@ -3286,7 +3279,7 @@
     }
   },
   /**
-   * Lookup391: pallet_ethereum::RawOrigin
+   * Lookup390: pallet_ethereum::RawOrigin
    **/
   PalletEthereumRawOrigin: {
     _enum: {
@@ -3294,17 +3287,17 @@
     }
   },
   /**
-   * Lookup392: sp_core::Void
+   * Lookup391: sp_core::Void
    **/
   SpCoreVoid: 'Null',
   /**
-   * Lookup394: pallet_unique_scheduler_v2::pallet::Error<T>
+   * Lookup393: pallet_unique_scheduler_v2::pallet::Error<T>
    **/
   PalletUniqueSchedulerV2Error: {
     _enum: ['FailedToSchedule', 'AgendaIsExhausted', 'ScheduledCallCorrupted', 'PreimageNotFound', 'TooBigScheduledCall', 'NotFound', 'TargetBlockNumberInPast', 'Named']
   },
   /**
-   * Lookup395: up_data_structs::Collection<sp_core::crypto::AccountId32>
+   * Lookup394: up_data_structs::Collection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsCollection: {
     owner: 'AccountId32',
@@ -3318,7 +3311,7 @@
     flags: '[u8;1]'
   },
   /**
-   * Lookup396: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
+   * Lookup395: up_data_structs::SponsorshipState<sp_core::crypto::AccountId32>
    **/
   UpDataStructsSponsorshipStateAccountId32: {
     _enum: {
@@ -3328,7 +3321,7 @@
     }
   },
   /**
-   * Lookup398: up_data_structs::Properties
+   * Lookup397: up_data_structs::Properties
    **/
   UpDataStructsProperties: {
     map: 'UpDataStructsPropertiesMapBoundedVec',
@@ -3336,15 +3329,15 @@
     spaceLimit: 'u32'
   },
   /**
-   * Lookup399: up_data_structs::PropertiesMap<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup398: up_data_structs::PropertiesMap<sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   UpDataStructsPropertiesMapBoundedVec: 'BTreeMap<Bytes, Bytes>',
   /**
-   * Lookup404: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
+   * Lookup403: up_data_structs::PropertiesMap<up_data_structs::PropertyPermission>
    **/
   UpDataStructsPropertiesMapPropertyPermission: 'BTreeMap<Bytes, UpDataStructsPropertyPermission>',
   /**
-   * Lookup411: up_data_structs::CollectionStats
+   * Lookup410: up_data_structs::CollectionStats
    **/
   UpDataStructsCollectionStats: {
     created: 'u32',
@@ -3352,18 +3345,18 @@
     alive: 'u32'
   },
   /**
-   * Lookup412: up_data_structs::TokenChild
+   * Lookup411: up_data_structs::TokenChild
    **/
   UpDataStructsTokenChild: {
     token: 'u32',
     collection: 'u32'
   },
   /**
-   * Lookup413: PhantomType::up_data_structs<T>
+   * Lookup412: PhantomType::up_data_structs<T>
    **/
   PhantomTypeUpDataStructs: '[(UpDataStructsTokenData,UpDataStructsRpcCollection,RmrkTraitsCollectionCollectionInfo,RmrkTraitsNftNftInfo,RmrkTraitsResourceResourceInfo,RmrkTraitsPropertyPropertyInfo,RmrkTraitsBaseBaseInfo,RmrkTraitsPartPartType,RmrkTraitsTheme,RmrkTraitsNftNftChild);0]',
   /**
-   * Lookup415: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup414: up_data_structs::TokenData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsTokenData: {
     properties: 'Vec<UpDataStructsProperty>',
@@ -3371,7 +3364,7 @@
     pieces: 'u128'
   },
   /**
-   * Lookup417: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
+   * Lookup416: up_data_structs::RpcCollection<sp_core::crypto::AccountId32>
    **/
   UpDataStructsRpcCollection: {
     owner: 'AccountId32',
@@ -3388,14 +3381,14 @@
     flags: 'UpDataStructsRpcCollectionFlags'
   },
   /**
-   * Lookup418: up_data_structs::RpcCollectionFlags
+   * Lookup417: up_data_structs::RpcCollectionFlags
    **/
   UpDataStructsRpcCollectionFlags: {
     foreign: 'bool',
     erc721metadata: 'bool'
   },
   /**
-   * Lookup419: rmrk_traits::collection::CollectionInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
+   * Lookup418: rmrk_traits::collection::CollectionInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::crypto::AccountId32>
    **/
   RmrkTraitsCollectionCollectionInfo: {
     issuer: 'AccountId32',
@@ -3405,7 +3398,7 @@
     nftsCount: 'u32'
   },
   /**
-   * Lookup420: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup419: rmrk_traits::nft::NftInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsNftNftInfo: {
     owner: 'RmrkTraitsNftAccountIdOrCollectionNftTuple',
@@ -3415,14 +3408,14 @@
     pending: 'bool'
   },
   /**
-   * Lookup422: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
+   * Lookup421: rmrk_traits::nft::RoyaltyInfo<sp_core::crypto::AccountId32, sp_arithmetic::per_things::Permill>
    **/
   RmrkTraitsNftRoyaltyInfo: {
     recipient: 'AccountId32',
     amount: 'Permill'
   },
   /**
-   * Lookup423: rmrk_traits::resource::ResourceInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup422: rmrk_traits::resource::ResourceInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsResourceResourceInfo: {
     id: 'u32',
@@ -3431,14 +3424,14 @@
     pendingRemoval: 'bool'
   },
   /**
-   * Lookup424: rmrk_traits::property::PropertyInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup423: rmrk_traits::property::PropertyInfo<sp_core::bounded::bounded_vec::BoundedVec<T, S>, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsPropertyPropertyInfo: {
     key: 'Bytes',
     value: 'Bytes'
   },
   /**
-   * Lookup425: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
+   * Lookup424: rmrk_traits::base::BaseInfo<sp_core::crypto::AccountId32, sp_core::bounded::bounded_vec::BoundedVec<T, S>>
    **/
   RmrkTraitsBaseBaseInfo: {
     issuer: 'AccountId32',
@@ -3446,92 +3439,92 @@
     symbol: 'Bytes'
   },
   /**
-   * Lookup426: rmrk_traits::nft::NftChild
+   * Lookup425: rmrk_traits::nft::NftChild
    **/
   RmrkTraitsNftNftChild: {
     collectionId: 'u32',
     nftId: 'u32'
   },
   /**
-   * Lookup428: pallet_common::pallet::Error<T>
+   * Lookup427: pallet_common::pallet::Error<T>
    **/
   PalletCommonError: {
-    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal']
+    _enum: ['CollectionNotFound', 'MustBeTokenOwner', 'NoPermission', 'CantDestroyNotEmptyCollection', 'PublicMintingNotAllowed', 'AddressNotInAllowlist', 'CollectionNameLimitExceeded', 'CollectionDescriptionLimitExceeded', 'CollectionTokenPrefixLimitExceeded', 'TotalCollectionsLimitExceeded', 'CollectionAdminCountExceeded', 'CollectionLimitBoundsExceeded', 'OwnerPermissionsCantBeReverted', 'TransferNotAllowed', 'AccountTokenLimitExceeded', 'CollectionTokenLimitExceeded', 'MetadataFlagFrozen', 'TokenNotFound', 'TokenValueTooLow', 'ApprovedValueTooLow', 'CantApproveMoreThanOwned', 'AddressIsZero', 'UnsupportedOperation', 'NotSufficientFounds', 'UserIsNotAllowedToNest', 'SourceCollectionIsNotAllowedToNest', 'CollectionFieldSizeExceeded', 'NoSpaceForProperty', 'PropertyLimitReached', 'PropertyKeyIsTooLong', 'InvalidCharacterInPropertyKey', 'EmptyPropertyKey', 'CollectionIsExternal', 'CollectionIsInternal', 'ConfirmSponsorshipFail', 'UserIsNotCollectionAdmin']
   },
   /**
-   * Lookup430: pallet_fungible::pallet::Error<T>
+   * Lookup429: pallet_fungible::pallet::Error<T>
    **/
   PalletFungibleError: {
     _enum: ['NotFungibleDataUsedToMintFungibleCollectionToken', 'FungibleItemsHaveNoId', 'FungibleItemsDontHaveData', 'FungibleDisallowsNesting', 'SettingPropertiesNotAllowed', 'SettingAllowanceForAllNotAllowed']
   },
   /**
-   * Lookup431: pallet_refungible::ItemData
+   * Lookup430: pallet_refungible::ItemData
    **/
   PalletRefungibleItemData: {
     constData: 'Bytes'
   },
   /**
-   * Lookup436: pallet_refungible::pallet::Error<T>
+   * Lookup435: pallet_refungible::pallet::Error<T>
    **/
   PalletRefungibleError: {
     _enum: ['NotRefungibleDataUsedToMintFungibleCollectionToken', 'WrongRefungiblePieces', 'RepartitionWhileNotOwningAllPieces', 'RefungibleDisallowsNesting', 'SettingPropertiesNotAllowed']
   },
   /**
-   * Lookup437: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup436: pallet_nonfungible::ItemData<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   PalletNonfungibleItemData: {
     owner: 'PalletEvmAccountBasicCrossAccountIdRepr'
   },
   /**
-   * Lookup439: up_data_structs::PropertyScope
+   * Lookup438: up_data_structs::PropertyScope
    **/
   UpDataStructsPropertyScope: {
     _enum: ['None', 'Rmrk']
   },
   /**
-   * Lookup441: pallet_nonfungible::pallet::Error<T>
+   * Lookup440: pallet_nonfungible::pallet::Error<T>
    **/
   PalletNonfungibleError: {
     _enum: ['NotNonfungibleDataUsedToMintFungibleCollectionToken', 'NonfungibleItemsHaveNoAmount', 'CantBurnNftWithChildren']
   },
   /**
-   * Lookup442: pallet_structure::pallet::Error<T>
+   * Lookup441: pallet_structure::pallet::Error<T>
    **/
   PalletStructureError: {
     _enum: ['OuroborosDetected', 'DepthLimit', 'BreadthLimit', 'TokenNotFound']
   },
   /**
-   * Lookup443: pallet_rmrk_core::pallet::Error<T>
+   * Lookup442: pallet_rmrk_core::pallet::Error<T>
    **/
   PalletRmrkCoreError: {
     _enum: ['CorruptedCollectionType', 'RmrkPropertyKeyIsTooLong', 'RmrkPropertyValueIsTooLong', 'RmrkPropertyIsNotFound', 'UnableToDecodeRmrkData', 'CollectionNotEmpty', 'NoAvailableCollectionId', 'NoAvailableNftId', 'CollectionUnknown', 'NoPermission', 'NonTransferable', 'CollectionFullOrLocked', 'ResourceDoesntExist', 'CannotSendToDescendentOrSelf', 'CannotAcceptNonOwnedNft', 'CannotRejectNonOwnedNft', 'CannotRejectNonPendingNft', 'ResourceNotPending', 'NoAvailableResourceId']
   },
   /**
-   * Lookup445: pallet_rmrk_equip::pallet::Error<T>
+   * Lookup444: pallet_rmrk_equip::pallet::Error<T>
    **/
   PalletRmrkEquipError: {
     _enum: ['PermissionError', 'NoAvailableBaseId', 'NoAvailablePartId', 'BaseDoesntExist', 'NeedsDefaultThemeFirst', 'PartDoesntExist', 'NoEquippableOnFixedPart']
   },
   /**
-   * Lookup451: pallet_app_promotion::pallet::Error<T>
+   * Lookup450: pallet_app_promotion::pallet::Error<T>
    **/
   PalletAppPromotionError: {
     _enum: ['AdminNotSet', 'NoPermission', 'NotSufficientFunds', 'PendingForBlockOverflow', 'SponsorNotSet', 'IncorrectLockedBalanceOperation']
   },
   /**
-   * Lookup452: pallet_foreign_assets::module::Error<T>
+   * Lookup451: pallet_foreign_assets::module::Error<T>
    **/
   PalletForeignAssetsModuleError: {
     _enum: ['BadLocation', 'MultiLocationExisted', 'AssetIdNotExists', 'AssetIdExisted']
   },
   /**
-   * Lookup454: pallet_evm::pallet::Error<T>
+   * Lookup453: pallet_evm::pallet::Error<T>
    **/
   PalletEvmError: {
     _enum: ['BalanceLow', 'FeeOverflow', 'PaymentOverflow', 'WithdrawFailed', 'GasPriceTooLow', 'InvalidNonce', 'GasLimitTooLow', 'GasLimitTooHigh', 'Undefined', 'Reentrancy']
   },
   /**
-   * Lookup457: fp_rpc::TransactionStatus
+   * Lookup456: fp_rpc::TransactionStatus
    **/
   FpRpcTransactionStatus: {
     transactionHash: 'H256',
@@ -3543,11 +3536,11 @@
     logsBloom: 'EthbloomBloom'
   },
   /**
-   * Lookup459: ethbloom::Bloom
+   * Lookup458: ethbloom::Bloom
    **/
   EthbloomBloom: '[u8;256]',
   /**
-   * Lookup461: ethereum::receipt::ReceiptV3
+   * Lookup460: ethereum::receipt::ReceiptV3
    **/
   EthereumReceiptReceiptV3: {
     _enum: {
@@ -3557,7 +3550,7 @@
     }
   },
   /**
-   * Lookup462: ethereum::receipt::EIP658ReceiptData
+   * Lookup461: ethereum::receipt::EIP658ReceiptData
    **/
   EthereumReceiptEip658ReceiptData: {
     statusCode: 'u8',
@@ -3566,7 +3559,7 @@
     logs: 'Vec<EthereumLog>'
   },
   /**
-   * Lookup463: ethereum::block::Block<ethereum::transaction::TransactionV2>
+   * Lookup462: ethereum::block::Block<ethereum::transaction::TransactionV2>
    **/
   EthereumBlock: {
     header: 'EthereumHeader',
@@ -3574,7 +3567,7 @@
     ommers: 'Vec<EthereumHeader>'
   },
   /**
-   * Lookup464: ethereum::header::Header
+   * Lookup463: ethereum::header::Header
    **/
   EthereumHeader: {
     parentHash: 'H256',
@@ -3594,23 +3587,23 @@
     nonce: 'EthereumTypesHashH64'
   },
   /**
-   * Lookup465: ethereum_types::hash::H64
+   * Lookup464: ethereum_types::hash::H64
    **/
   EthereumTypesHashH64: '[u8;8]',
   /**
-   * Lookup470: pallet_ethereum::pallet::Error<T>
+   * Lookup469: pallet_ethereum::pallet::Error<T>
    **/
   PalletEthereumError: {
     _enum: ['InvalidSignature', 'PreLogExists']
   },
   /**
-   * Lookup471: pallet_evm_coder_substrate::pallet::Error<T>
+   * Lookup470: pallet_evm_coder_substrate::pallet::Error<T>
    **/
   PalletEvmCoderSubstrateError: {
     _enum: ['OutOfGas', 'OutOfFund']
   },
   /**
-   * Lookup472: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
+   * Lookup471: up_data_structs::SponsorshipState<pallet_evm::account::BasicCrossAccountIdRepr<sp_core::crypto::AccountId32>>
    **/
   UpDataStructsSponsorshipStateBasicCrossAccountIdRepr: {
     _enum: {
@@ -3620,35 +3613,35 @@
     }
   },
   /**
-   * Lookup473: pallet_evm_contract_helpers::SponsoringModeT
+   * Lookup472: pallet_evm_contract_helpers::SponsoringModeT
    **/
   PalletEvmContractHelpersSponsoringModeT: {
     _enum: ['Disabled', 'Allowlisted', 'Generous']
   },
   /**
-   * Lookup479: pallet_evm_contract_helpers::pallet::Error<T>
+   * Lookup478: pallet_evm_contract_helpers::pallet::Error<T>
    **/
   PalletEvmContractHelpersError: {
     _enum: ['NoPermission', 'NoPendingSponsor', 'TooManyMethodsHaveSponsoredLimit']
   },
   /**
-   * Lookup480: pallet_evm_migration::pallet::Error<T>
+   * Lookup479: pallet_evm_migration::pallet::Error<T>
    **/
   PalletEvmMigrationError: {
     _enum: ['AccountNotEmpty', 'AccountIsNotMigrating', 'BadEvent']
   },
   /**
-   * Lookup481: pallet_maintenance::pallet::Error<T>
+   * Lookup480: pallet_maintenance::pallet::Error<T>
    **/
   PalletMaintenanceError: 'Null',
   /**
-   * Lookup482: pallet_test_utils::pallet::Error<T>
+   * Lookup481: pallet_test_utils::pallet::Error<T>
    **/
   PalletTestUtilsError: {
     _enum: ['TestPalletDisabled', 'TriggerRollback']
   },
   /**
-   * Lookup484: sp_runtime::MultiSignature
+   * Lookup483: sp_runtime::MultiSignature
    **/
   SpRuntimeMultiSignature: {
     _enum: {
@@ -3658,51 +3651,51 @@
     }
   },
   /**
-   * Lookup485: sp_core::ed25519::Signature
+   * Lookup484: sp_core::ed25519::Signature
    **/
   SpCoreEd25519Signature: '[u8;64]',
   /**
-   * Lookup487: sp_core::sr25519::Signature
+   * Lookup486: sp_core::sr25519::Signature
    **/
   SpCoreSr25519Signature: '[u8;64]',
   /**
-   * Lookup488: sp_core::ecdsa::Signature
+   * Lookup487: sp_core::ecdsa::Signature
    **/
   SpCoreEcdsaSignature: '[u8;65]',
   /**
-   * Lookup491: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
+   * Lookup490: frame_system::extensions::check_spec_version::CheckSpecVersion<T>
    **/
   FrameSystemExtensionsCheckSpecVersion: 'Null',
   /**
-   * Lookup492: frame_system::extensions::check_tx_version::CheckTxVersion<T>
+   * Lookup491: frame_system::extensions::check_tx_version::CheckTxVersion<T>
    **/
   FrameSystemExtensionsCheckTxVersion: 'Null',
   /**
-   * Lookup493: frame_system::extensions::check_genesis::CheckGenesis<T>
+   * Lookup492: frame_system::extensions::check_genesis::CheckGenesis<T>
    **/
   FrameSystemExtensionsCheckGenesis: 'Null',
   /**
-   * Lookup496: frame_system::extensions::check_nonce::CheckNonce<T>
+   * Lookup495: frame_system::extensions::check_nonce::CheckNonce<T>
    **/
   FrameSystemExtensionsCheckNonce: 'Compact<u32>',
   /**
-   * Lookup497: frame_system::extensions::check_weight::CheckWeight<T>
+   * Lookup496: frame_system::extensions::check_weight::CheckWeight<T>
    **/
   FrameSystemExtensionsCheckWeight: 'Null',
   /**
-   * Lookup498: opal_runtime::runtime_common::maintenance::CheckMaintenance
+   * Lookup497: opal_runtime::runtime_common::maintenance::CheckMaintenance
    **/
   OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance: 'Null',
   /**
-   * Lookup499: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
+   * Lookup498: pallet_template_transaction_payment::ChargeTransactionPayment<opal_runtime::Runtime>
    **/
   PalletTemplateTransactionPaymentChargeTransactionPayment: 'Compact<u128>',
   /**
-   * Lookup500: opal_runtime::Runtime
+   * Lookup499: opal_runtime::Runtime
    **/
   OpalRuntimeRuntime: 'Null',
   /**
-   * Lookup501: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
+   * Lookup500: pallet_ethereum::FakeTransactionFinalizer<opal_runtime::Runtime>
    **/
   PalletEthereumFakeTransactionFinalizer: 'Null'
 };
modifiedtests/src/interfaces/registry.tsdiffbeforeafterboth
--- a/tests/src/interfaces/registry.ts
+++ b/tests/src/interfaces/registry.ts
@@ -5,7 +5,7 @@
 // this is required to allow for ambient/previous definitions
 import '@polkadot/types/types/registry';
 
-import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueRawEvent, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
+import type { CumulusPalletDmpQueueCall, CumulusPalletDmpQueueConfigData, CumulusPalletDmpQueueError, CumulusPalletDmpQueueEvent, CumulusPalletDmpQueuePageIndexData, CumulusPalletParachainSystemCall, CumulusPalletParachainSystemError, CumulusPalletParachainSystemEvent, CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot, CumulusPalletXcmCall, CumulusPalletXcmError, CumulusPalletXcmEvent, CumulusPalletXcmOrigin, 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, FrameSupportDispatchDispatchClass, FrameSupportDispatchDispatchInfo, FrameSupportDispatchPays, FrameSupportDispatchPerDispatchClassU32, FrameSupportDispatchPerDispatchClassWeight, FrameSupportDispatchPerDispatchClassWeightsPerClass, FrameSupportDispatchRawOrigin, FrameSupportPalletId, FrameSupportTokensMiscBalanceStatus, FrameSystemAccountInfo, FrameSystemCall, FrameSystemError, FrameSystemEvent, FrameSystemEventRecord, FrameSystemExtensionsCheckGenesis, FrameSystemExtensionsCheckNonce, FrameSystemExtensionsCheckSpecVersion, FrameSystemExtensionsCheckTxVersion, FrameSystemExtensionsCheckWeight, FrameSystemLastRuntimeUpgradeInfo, FrameSystemLimitsBlockLength, FrameSystemLimitsBlockWeights, FrameSystemLimitsWeightsPerClass, FrameSystemPhase, OpalRuntimeOriginCaller, OpalRuntimeRuntime, OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance, OrmlTokensAccountData, OrmlTokensBalanceLock, OrmlTokensModuleCall, OrmlTokensModuleError, OrmlTokensModuleEvent, OrmlTokensReserveData, OrmlVestingModuleCall, OrmlVestingModuleError, OrmlVestingModuleEvent, OrmlVestingVestingSchedule, OrmlXtokensModuleCall, OrmlXtokensModuleError, OrmlXtokensModuleEvent, PalletAppPromotionCall, PalletAppPromotionError, PalletAppPromotionEvent, PalletBalancesAccountData, PalletBalancesBalanceLock, PalletBalancesCall, PalletBalancesError, PalletBalancesEvent, PalletBalancesReasons, PalletBalancesReleases, PalletBalancesReserveData, PalletCommonError, PalletCommonEvent, PalletConfigurationCall, PalletEthereumCall, PalletEthereumError, PalletEthereumEvent, PalletEthereumFakeTransactionFinalizer, PalletEthereumRawOrigin, PalletEvmAccountBasicCrossAccountIdRepr, PalletEvmCall, PalletEvmCoderSubstrateError, PalletEvmContractHelpersError, PalletEvmContractHelpersEvent, PalletEvmContractHelpersSponsoringModeT, PalletEvmError, PalletEvmEvent, PalletEvmMigrationCall, PalletEvmMigrationError, PalletEvmMigrationEvent, PalletForeignAssetsAssetIds, PalletForeignAssetsModuleAssetMetadata, PalletForeignAssetsModuleCall, PalletForeignAssetsModuleError, PalletForeignAssetsModuleEvent, PalletForeignAssetsNativeCurrency, PalletFungibleError, PalletInflationCall, PalletMaintenanceCall, PalletMaintenanceError, PalletMaintenanceEvent, PalletNonfungibleError, PalletNonfungibleItemData, PalletRefungibleError, PalletRefungibleItemData, PalletRmrkCoreCall, PalletRmrkCoreError, PalletRmrkCoreEvent, PalletRmrkEquipCall, PalletRmrkEquipError, PalletRmrkEquipEvent, PalletStructureCall, PalletStructureError, PalletStructureEvent, PalletSudoCall, PalletSudoError, PalletSudoEvent, PalletTemplateTransactionPaymentCall, PalletTemplateTransactionPaymentChargeTransactionPayment, PalletTestUtilsCall, PalletTestUtilsError, PalletTestUtilsEvent, PalletTimestampCall, PalletTransactionPaymentEvent, PalletTransactionPaymentReleases, PalletTreasuryCall, PalletTreasuryError, PalletTreasuryEvent, PalletTreasuryProposal, PalletUniqueCall, PalletUniqueError, PalletUniqueSchedulerV2BlockAgenda, PalletUniqueSchedulerV2Call, PalletUniqueSchedulerV2Error, PalletUniqueSchedulerV2Event, PalletUniqueSchedulerV2Scheduled, PalletUniqueSchedulerV2ScheduledCall, PalletXcmCall, PalletXcmError, PalletXcmEvent, PalletXcmOrigin, PhantomTypeUpDataStructs, PolkadotCorePrimitivesInboundDownwardMessage, PolkadotCorePrimitivesInboundHrmpMessage, PolkadotCorePrimitivesOutboundHrmpMessage, PolkadotParachainPrimitivesXcmpMessageFormat, PolkadotPrimitivesV2AbridgedHostConfiguration, PolkadotPrimitivesV2AbridgedHrmpChannel, PolkadotPrimitivesV2PersistedValidationData, PolkadotPrimitivesV2UpgradeRestriction, RmrkTraitsBaseBaseInfo, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftAccountIdOrCollectionNftTuple, RmrkTraitsNftNftChild, RmrkTraitsNftNftInfo, RmrkTraitsNftRoyaltyInfo, RmrkTraitsPartEquippableList, RmrkTraitsPartFixedPart, RmrkTraitsPartPartType, RmrkTraitsPartSlotPart, RmrkTraitsPropertyPropertyInfo, RmrkTraitsResourceBasicResource, RmrkTraitsResourceComposableResource, RmrkTraitsResourceResourceInfo, RmrkTraitsResourceResourceTypes, RmrkTraitsResourceSlotResource, RmrkTraitsTheme, RmrkTraitsThemeThemeProperty, SpCoreEcdsaSignature, SpCoreEd25519Signature, SpCoreSr25519Signature, SpCoreVoid, SpRuntimeArithmeticError, SpRuntimeDigest, SpRuntimeDigestDigestItem, SpRuntimeDispatchError, SpRuntimeModuleError, SpRuntimeMultiSignature, SpRuntimeTokenError, SpRuntimeTransactionalError, SpTrieStorageProof, SpVersionRuntimeVersion, SpWeightsRuntimeDbWeight, SpWeightsWeightV2Weight, UpDataStructsAccessMode, UpDataStructsCollection, UpDataStructsCollectionLimits, UpDataStructsCollectionMode, UpDataStructsCollectionPermissions, UpDataStructsCollectionStats, UpDataStructsCreateCollectionData, UpDataStructsCreateFungibleData, UpDataStructsCreateItemData, UpDataStructsCreateItemExData, UpDataStructsCreateNftData, UpDataStructsCreateNftExData, UpDataStructsCreateReFungibleData, UpDataStructsCreateRefungibleExMultipleOwners, UpDataStructsCreateRefungibleExSingleOwner, UpDataStructsNestingPermissions, UpDataStructsOwnerRestrictedSet, UpDataStructsProperties, UpDataStructsPropertiesMapBoundedVec, UpDataStructsPropertiesMapPropertyPermission, UpDataStructsProperty, UpDataStructsPropertyKeyPermission, UpDataStructsPropertyPermission, UpDataStructsPropertyScope, UpDataStructsRpcCollection, UpDataStructsRpcCollectionFlags, UpDataStructsSponsoringRateLimit, UpDataStructsSponsorshipStateAccountId32, UpDataStructsSponsorshipStateBasicCrossAccountIdRepr, UpDataStructsTokenChild, UpDataStructsTokenData, XcmDoubleEncoded, XcmV0Junction, XcmV0JunctionBodyId, XcmV0JunctionBodyPart, XcmV0JunctionNetworkId, XcmV0MultiAsset, XcmV0MultiLocation, XcmV0Order, XcmV0OriginKind, XcmV0Response, XcmV0Xcm, XcmV1Junction, XcmV1MultiAsset, XcmV1MultiLocation, XcmV1MultiassetAssetId, XcmV1MultiassetAssetInstance, XcmV1MultiassetFungibility, XcmV1MultiassetMultiAssetFilter, XcmV1MultiassetMultiAssets, XcmV1MultiassetWildFungibility, XcmV1MultiassetWildMultiAsset, XcmV1MultilocationJunctions, XcmV1Order, XcmV1Response, XcmV1Xcm, XcmV2Instruction, XcmV2Response, XcmV2TraitsError, XcmV2TraitsOutcome, XcmV2WeightLimit, XcmV2Xcm, XcmVersionedMultiAsset, XcmVersionedMultiAssets, XcmVersionedMultiLocation, XcmVersionedXcm } from '@polkadot/types/lookup';
 
 declare module '@polkadot/types/types/registry' {
   interface InterfaceTypes {
@@ -162,7 +162,6 @@
     PalletTreasuryProposal: PalletTreasuryProposal;
     PalletUniqueCall: PalletUniqueCall;
     PalletUniqueError: PalletUniqueError;
-    PalletUniqueRawEvent: PalletUniqueRawEvent;
     PalletUniqueSchedulerV2BlockAgenda: PalletUniqueSchedulerV2BlockAgenda;
     PalletUniqueSchedulerV2Call: PalletUniqueSchedulerV2Call;
     PalletUniqueSchedulerV2Error: PalletUniqueSchedulerV2Error;
modifiedtests/src/interfaces/types-lookup.tsdiffbeforeafterboth
--- a/tests/src/interfaces/types-lookup.ts
+++ b/tests/src/interfaces/types-lookup.ts
@@ -1109,41 +1109,7 @@
     readonly type: 'InvalidFormat' | 'UnsupportedVersion' | 'ExecutedDownward' | 'WeightExhausted' | 'OverweightEnqueued' | 'OverweightServiced';
   }
 
-  /** @name PalletUniqueRawEvent (89) */
-  interface PalletUniqueRawEvent extends Enum {
-    readonly isCollectionSponsorRemoved: boolean;
-    readonly asCollectionSponsorRemoved: u32;
-    readonly isCollectionAdminAdded: boolean;
-    readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-    readonly isCollectionOwnedChanged: boolean;
-    readonly asCollectionOwnedChanged: ITuple<[u32, AccountId32]>;
-    readonly isCollectionSponsorSet: boolean;
-    readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
-    readonly isSponsorshipConfirmed: boolean;
-    readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
-    readonly isCollectionAdminRemoved: boolean;
-    readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-    readonly isAllowListAddressRemoved: boolean;
-    readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-    readonly isAllowListAddressAdded: boolean;
-    readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
-    readonly isCollectionLimitSet: boolean;
-    readonly asCollectionLimitSet: u32;
-    readonly isCollectionPermissionSet: boolean;
-    readonly asCollectionPermissionSet: u32;
-    readonly type: 'CollectionSponsorRemoved' | 'CollectionAdminAdded' | 'CollectionOwnedChanged' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionAdminRemoved' | 'AllowListAddressRemoved' | 'AllowListAddressAdded' | 'CollectionLimitSet' | 'CollectionPermissionSet';
-  }
-
-  /** @name PalletEvmAccountBasicCrossAccountIdRepr (90) */
-  interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
-    readonly isSubstrate: boolean;
-    readonly asSubstrate: AccountId32;
-    readonly isEthereum: boolean;
-    readonly asEthereum: H160;
-    readonly type: 'Substrate' | 'Ethereum';
-  }
-
-  /** @name PalletUniqueSchedulerV2Event (93) */
+  /** @name PalletUniqueSchedulerV2Event (89) */
   interface PalletUniqueSchedulerV2Event extends Enum {
     readonly isScheduled: boolean;
     readonly asScheduled: {
@@ -1179,7 +1145,7 @@
     readonly type: 'Scheduled' | 'Canceled' | 'Dispatched' | 'PriorityChanged' | 'CallUnavailable' | 'PermanentlyOverweight';
   }
 
-  /** @name PalletCommonEvent (96) */
+  /** @name PalletCommonEvent (92) */
   interface PalletCommonEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: ITuple<[u32, u8, AccountId32]>;
@@ -1205,17 +1171,46 @@
     readonly asTokenPropertyDeleted: ITuple<[u32, u32, Bytes]>;
     readonly isPropertyPermissionSet: boolean;
     readonly asPropertyPermissionSet: ITuple<[u32, Bytes]>;
-    readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet';
+    readonly isAllowListAddressAdded: boolean;
+    readonly asAllowListAddressAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+    readonly isAllowListAddressRemoved: boolean;
+    readonly asAllowListAddressRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+    readonly isCollectionAdminAdded: boolean;
+    readonly asCollectionAdminAdded: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+    readonly isCollectionAdminRemoved: boolean;
+    readonly asCollectionAdminRemoved: ITuple<[u32, PalletEvmAccountBasicCrossAccountIdRepr]>;
+    readonly isCollectionLimitSet: boolean;
+    readonly asCollectionLimitSet: u32;
+    readonly isCollectionOwnerChanged: boolean;
+    readonly asCollectionOwnerChanged: ITuple<[u32, AccountId32]>;
+    readonly isCollectionPermissionSet: boolean;
+    readonly asCollectionPermissionSet: u32;
+    readonly isCollectionSponsorSet: boolean;
+    readonly asCollectionSponsorSet: ITuple<[u32, AccountId32]>;
+    readonly isSponsorshipConfirmed: boolean;
+    readonly asSponsorshipConfirmed: ITuple<[u32, AccountId32]>;
+    readonly isCollectionSponsorRemoved: boolean;
+    readonly asCollectionSponsorRemoved: u32;
+    readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'ItemCreated' | 'ItemDestroyed' | 'Transfer' | 'Approved' | 'ApprovedForAll' | 'CollectionPropertySet' | 'CollectionPropertyDeleted' | 'TokenPropertySet' | 'TokenPropertyDeleted' | 'PropertyPermissionSet' | 'AllowListAddressAdded' | 'AllowListAddressRemoved' | 'CollectionAdminAdded' | 'CollectionAdminRemoved' | 'CollectionLimitSet' | 'CollectionOwnerChanged' | 'CollectionPermissionSet' | 'CollectionSponsorSet' | 'SponsorshipConfirmed' | 'CollectionSponsorRemoved';
+  }
+
+  /** @name PalletEvmAccountBasicCrossAccountIdRepr (95) */
+  interface PalletEvmAccountBasicCrossAccountIdRepr extends Enum {
+    readonly isSubstrate: boolean;
+    readonly asSubstrate: AccountId32;
+    readonly isEthereum: boolean;
+    readonly asEthereum: H160;
+    readonly type: 'Substrate' | 'Ethereum';
   }
 
-  /** @name PalletStructureEvent (100) */
+  /** @name PalletStructureEvent (99) */
   interface PalletStructureEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: Result<Null, SpRuntimeDispatchError>;
     readonly type: 'Executed';
   }
 
-  /** @name PalletRmrkCoreEvent (101) */
+  /** @name PalletRmrkCoreEvent (100) */
   interface PalletRmrkCoreEvent extends Enum {
     readonly isCollectionCreated: boolean;
     readonly asCollectionCreated: {
@@ -1305,7 +1300,7 @@
     readonly type: 'CollectionCreated' | 'CollectionDestroyed' | 'IssuerChanged' | 'CollectionLocked' | 'NftMinted' | 'NftBurned' | 'NftSent' | 'NftAccepted' | 'NftRejected' | 'PropertySet' | 'ResourceAdded' | 'ResourceRemoval' | 'ResourceAccepted' | 'ResourceRemovalAccepted' | 'PrioritySet';
   }
 
-  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (102) */
+  /** @name RmrkTraitsNftAccountIdOrCollectionNftTuple (101) */
   interface RmrkTraitsNftAccountIdOrCollectionNftTuple extends Enum {
     readonly isAccountId: boolean;
     readonly asAccountId: AccountId32;
@@ -1314,7 +1309,7 @@
     readonly type: 'AccountId' | 'CollectionAndNftTuple';
   }
 
-  /** @name PalletRmrkEquipEvent (106) */
+  /** @name PalletRmrkEquipEvent (105) */
   interface PalletRmrkEquipEvent extends Enum {
     readonly isBaseCreated: boolean;
     readonly asBaseCreated: {
@@ -1329,7 +1324,7 @@
     readonly type: 'BaseCreated' | 'EquippablesUpdated';
   }
 
-  /** @name PalletAppPromotionEvent (107) */
+  /** @name PalletAppPromotionEvent (106) */
   interface PalletAppPromotionEvent extends Enum {
     readonly isStakingRecalculation: boolean;
     readonly asStakingRecalculation: ITuple<[AccountId32, u128, u128]>;
@@ -1342,7 +1337,7 @@
     readonly type: 'StakingRecalculation' | 'Stake' | 'Unstake' | 'SetAdmin';
   }
 
-  /** @name PalletForeignAssetsModuleEvent (108) */
+  /** @name PalletForeignAssetsModuleEvent (107) */
   interface PalletForeignAssetsModuleEvent extends Enum {
     readonly isForeignAssetRegistered: boolean;
     readonly asForeignAssetRegistered: {
@@ -1369,7 +1364,7 @@
     readonly type: 'ForeignAssetRegistered' | 'ForeignAssetUpdated' | 'AssetRegistered' | 'AssetUpdated';
   }
 
-  /** @name PalletForeignAssetsModuleAssetMetadata (109) */
+  /** @name PalletForeignAssetsModuleAssetMetadata (108) */
   interface PalletForeignAssetsModuleAssetMetadata extends Struct {
     readonly name: Bytes;
     readonly symbol: Bytes;
@@ -1377,7 +1372,7 @@
     readonly minimalBalance: u128;
   }
 
-  /** @name PalletEvmEvent (110) */
+  /** @name PalletEvmEvent (109) */
   interface PalletEvmEvent extends Enum {
     readonly isLog: boolean;
     readonly asLog: {
@@ -1402,14 +1397,14 @@
     readonly type: 'Log' | 'Created' | 'CreatedFailed' | 'Executed' | 'ExecutedFailed';
   }
 
-  /** @name EthereumLog (111) */
+  /** @name EthereumLog (110) */
   interface EthereumLog extends Struct {
     readonly address: H160;
     readonly topics: Vec<H256>;
     readonly data: Bytes;
   }
 
-  /** @name PalletEthereumEvent (113) */
+  /** @name PalletEthereumEvent (112) */
   interface PalletEthereumEvent extends Enum {
     readonly isExecuted: boolean;
     readonly asExecuted: {
@@ -1421,7 +1416,7 @@
     readonly type: 'Executed';
   }
 
-  /** @name EvmCoreErrorExitReason (114) */
+  /** @name EvmCoreErrorExitReason (113) */
   interface EvmCoreErrorExitReason extends Enum {
     readonly isSucceed: boolean;
     readonly asSucceed: EvmCoreErrorExitSucceed;
@@ -1434,7 +1429,7 @@
     readonly type: 'Succeed' | 'Error' | 'Revert' | 'Fatal';
   }
 
-  /** @name EvmCoreErrorExitSucceed (115) */
+  /** @name EvmCoreErrorExitSucceed (114) */
   interface EvmCoreErrorExitSucceed extends Enum {
     readonly isStopped: boolean;
     readonly isReturned: boolean;
@@ -1442,7 +1437,7 @@
     readonly type: 'Stopped' | 'Returned' | 'Suicided';
   }
 
-  /** @name EvmCoreErrorExitError (116) */
+  /** @name EvmCoreErrorExitError (115) */
   interface EvmCoreErrorExitError extends Enum {
     readonly isStackUnderflow: boolean;
     readonly isStackOverflow: boolean;
@@ -1463,13 +1458,13 @@
     readonly type: 'StackUnderflow' | 'StackOverflow' | 'InvalidJump' | 'InvalidRange' | 'DesignatedInvalid' | 'CallTooDeep' | 'CreateCollision' | 'CreateContractLimit' | 'OutOfOffset' | 'OutOfGas' | 'OutOfFund' | 'PcUnderflow' | 'CreateEmpty' | 'Other' | 'InvalidCode';
   }
 
-  /** @name EvmCoreErrorExitRevert (119) */
+  /** @name EvmCoreErrorExitRevert (118) */
   interface EvmCoreErrorExitRevert extends Enum {
     readonly isReverted: boolean;
     readonly type: 'Reverted';
   }
 
-  /** @name EvmCoreErrorExitFatal (120) */
+  /** @name EvmCoreErrorExitFatal (119) */
   interface EvmCoreErrorExitFatal extends Enum {
     readonly isNotSupported: boolean;
     readonly isUnhandledInterrupt: boolean;
@@ -1480,7 +1475,7 @@
     readonly type: 'NotSupported' | 'UnhandledInterrupt' | 'CallErrorAsFatal' | 'Other';
   }
 
-  /** @name PalletEvmContractHelpersEvent (121) */
+  /** @name PalletEvmContractHelpersEvent (120) */
   interface PalletEvmContractHelpersEvent extends Enum {
     readonly isContractSponsorSet: boolean;
     readonly asContractSponsorSet: ITuple<[H160, AccountId32]>;
@@ -1491,20 +1486,20 @@
     readonly type: 'ContractSponsorSet' | 'ContractSponsorshipConfirmed' | 'ContractSponsorRemoved';
   }
 
-  /** @name PalletEvmMigrationEvent (122) */
+  /** @name PalletEvmMigrationEvent (121) */
   interface PalletEvmMigrationEvent extends Enum {
     readonly isTestEvent: boolean;
     readonly type: 'TestEvent';
   }
 
-  /** @name PalletMaintenanceEvent (123) */
+  /** @name PalletMaintenanceEvent (122) */
   interface PalletMaintenanceEvent extends Enum {
     readonly isMaintenanceEnabled: boolean;
     readonly isMaintenanceDisabled: boolean;
     readonly type: 'MaintenanceEnabled' | 'MaintenanceDisabled';
   }
 
-  /** @name PalletTestUtilsEvent (124) */
+  /** @name PalletTestUtilsEvent (123) */
   interface PalletTestUtilsEvent extends Enum {
     readonly isValueIsSet: boolean;
     readonly isShouldRollback: boolean;
@@ -1512,7 +1507,7 @@
     readonly type: 'ValueIsSet' | 'ShouldRollback' | 'BatchCompleted';
   }
 
-  /** @name FrameSystemPhase (125) */
+  /** @name FrameSystemPhase (124) */
   interface FrameSystemPhase extends Enum {
     readonly isApplyExtrinsic: boolean;
     readonly asApplyExtrinsic: u32;
@@ -1521,13 +1516,13 @@
     readonly type: 'ApplyExtrinsic' | 'Finalization' | 'Initialization';
   }
 
-  /** @name FrameSystemLastRuntimeUpgradeInfo (127) */
+  /** @name FrameSystemLastRuntimeUpgradeInfo (126) */
   interface FrameSystemLastRuntimeUpgradeInfo extends Struct {
     readonly specVersion: Compact<u32>;
     readonly specName: Text;
   }
 
-  /** @name FrameSystemCall (128) */
+  /** @name FrameSystemCall (127) */
   interface FrameSystemCall extends Enum {
     readonly isFillBlock: boolean;
     readonly asFillBlock: {
@@ -1569,21 +1564,21 @@
     readonly type: 'FillBlock' | 'Remark' | 'SetHeapPages' | 'SetCode' | 'SetCodeWithoutChecks' | 'SetStorage' | 'KillStorage' | 'KillPrefix' | 'RemarkWithEvent';
   }
 
-  /** @name FrameSystemLimitsBlockWeights (133) */
+  /** @name FrameSystemLimitsBlockWeights (132) */
   interface FrameSystemLimitsBlockWeights extends Struct {
     readonly baseBlock: SpWeightsWeightV2Weight;
     readonly maxBlock: SpWeightsWeightV2Weight;
     readonly perClass: FrameSupportDispatchPerDispatchClassWeightsPerClass;
   }
 
-  /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (134) */
+  /** @name FrameSupportDispatchPerDispatchClassWeightsPerClass (133) */
   interface FrameSupportDispatchPerDispatchClassWeightsPerClass extends Struct {
     readonly normal: FrameSystemLimitsWeightsPerClass;
     readonly operational: FrameSystemLimitsWeightsPerClass;
     readonly mandatory: FrameSystemLimitsWeightsPerClass;
   }
 
-  /** @name FrameSystemLimitsWeightsPerClass (135) */
+  /** @name FrameSystemLimitsWeightsPerClass (134) */
   interface FrameSystemLimitsWeightsPerClass extends Struct {
     readonly baseExtrinsic: SpWeightsWeightV2Weight;
     readonly maxExtrinsic: Option<SpWeightsWeightV2Weight>;
@@ -1591,25 +1586,25 @@
     readonly reserved: Option<SpWeightsWeightV2Weight>;
   }
 
-  /** @name FrameSystemLimitsBlockLength (137) */
+  /** @name FrameSystemLimitsBlockLength (136) */
   interface FrameSystemLimitsBlockLength extends Struct {
     readonly max: FrameSupportDispatchPerDispatchClassU32;
   }
 
-  /** @name FrameSupportDispatchPerDispatchClassU32 (138) */
+  /** @name FrameSupportDispatchPerDispatchClassU32 (137) */
   interface FrameSupportDispatchPerDispatchClassU32 extends Struct {
     readonly normal: u32;
     readonly operational: u32;
     readonly mandatory: u32;
   }
 
-  /** @name SpWeightsRuntimeDbWeight (139) */
+  /** @name SpWeightsRuntimeDbWeight (138) */
   interface SpWeightsRuntimeDbWeight extends Struct {
     readonly read: u64;
     readonly write: u64;
   }
 
-  /** @name SpVersionRuntimeVersion (140) */
+  /** @name SpVersionRuntimeVersion (139) */
   interface SpVersionRuntimeVersion extends Struct {
     readonly specName: Text;
     readonly implName: Text;
@@ -1621,7 +1616,7 @@
     readonly stateVersion: u8;
   }
 
-  /** @name FrameSystemError (145) */
+  /** @name FrameSystemError (144) */
   interface FrameSystemError extends Enum {
     readonly isInvalidSpecName: boolean;
     readonly isSpecVersionNeedsToIncrease: boolean;
@@ -1632,7 +1627,7 @@
     readonly type: 'InvalidSpecName' | 'SpecVersionNeedsToIncrease' | 'FailedToExtractRuntimeVersion' | 'NonDefaultComposite' | 'NonZeroRefCount' | 'CallFiltered';
   }
 
-  /** @name PolkadotPrimitivesV2PersistedValidationData (146) */
+  /** @name PolkadotPrimitivesV2PersistedValidationData (145) */
   interface PolkadotPrimitivesV2PersistedValidationData extends Struct {
     readonly parentHead: Bytes;
     readonly relayParentNumber: u32;
@@ -1640,18 +1635,18 @@
     readonly maxPovSize: u32;
   }
 
-  /** @name PolkadotPrimitivesV2UpgradeRestriction (149) */
+  /** @name PolkadotPrimitivesV2UpgradeRestriction (148) */
   interface PolkadotPrimitivesV2UpgradeRestriction extends Enum {
     readonly isPresent: boolean;
     readonly type: 'Present';
   }
 
-  /** @name SpTrieStorageProof (150) */
+  /** @name SpTrieStorageProof (149) */
   interface SpTrieStorageProof extends Struct {
     readonly trieNodes: BTreeSet<Bytes>;
   }
 
-  /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (152) */
+  /** @name CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot (151) */
   interface CumulusPalletParachainSystemRelayStateSnapshotMessagingStateSnapshot extends Struct {
     readonly dmqMqcHead: H256;
     readonly relayDispatchQueueSize: ITuple<[u32, u32]>;
@@ -1659,7 +1654,7 @@
     readonly egressChannels: Vec<ITuple<[u32, PolkadotPrimitivesV2AbridgedHrmpChannel]>>;
   }
 
-  /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (155) */
+  /** @name PolkadotPrimitivesV2AbridgedHrmpChannel (154) */
   interface PolkadotPrimitivesV2AbridgedHrmpChannel extends Struct {
     readonly maxCapacity: u32;
     readonly maxTotalSize: u32;
@@ -1669,7 +1664,7 @@
     readonly mqcHead: Option<H256>;
   }
 
-  /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (156) */
+  /** @name PolkadotPrimitivesV2AbridgedHostConfiguration (155) */
   interface PolkadotPrimitivesV2AbridgedHostConfiguration extends Struct {
     readonly maxCodeSize: u32;
     readonly maxHeadDataSize: u32;
@@ -1682,13 +1677,13 @@
     readonly validationUpgradeDelay: u32;
   }
 
-  /** @name PolkadotCorePrimitivesOutboundHrmpMessage (162) */
+  /** @name PolkadotCorePrimitivesOutboundHrmpMessage (161) */
   interface PolkadotCorePrimitivesOutboundHrmpMessage extends Struct {
     readonly recipient: u32;
     readonly data: Bytes;
   }
 
-  /** @name CumulusPalletParachainSystemCall (163) */
+  /** @name CumulusPalletParachainSystemCall (162) */
   interface CumulusPalletParachainSystemCall extends Enum {
     readonly isSetValidationData: boolean;
     readonly asSetValidationData: {
@@ -1709,7 +1704,7 @@
     readonly type: 'SetValidationData' | 'SudoSendUpwardMessage' | 'AuthorizeUpgrade' | 'EnactAuthorizedUpgrade';
   }
 
-  /** @name CumulusPrimitivesParachainInherentParachainInherentData (164) */
+  /** @name CumulusPrimitivesParachainInherentParachainInherentData (163) */
   interface CumulusPrimitivesParachainInherentParachainInherentData extends Struct {
     readonly validationData: PolkadotPrimitivesV2PersistedValidationData;
     readonly relayChainState: SpTrieStorageProof;
@@ -1717,19 +1712,19 @@
     readonly horizontalMessages: BTreeMap<u32, Vec<PolkadotCorePrimitivesInboundHrmpMessage>>;
   }
 
-  /** @name PolkadotCorePrimitivesInboundDownwardMessage (166) */
+  /** @name PolkadotCorePrimitivesInboundDownwardMessage (165) */
   interface PolkadotCorePrimitivesInboundDownwardMessage extends Struct {
     readonly sentAt: u32;
     readonly msg: Bytes;
   }
 
-  /** @name PolkadotCorePrimitivesInboundHrmpMessage (169) */
+  /** @name PolkadotCorePrimitivesInboundHrmpMessage (168) */
   interface PolkadotCorePrimitivesInboundHrmpMessage extends Struct {
     readonly sentAt: u32;
     readonly data: Bytes;
   }
 
-  /** @name CumulusPalletParachainSystemError (172) */
+  /** @name CumulusPalletParachainSystemError (171) */
   interface CumulusPalletParachainSystemError extends Enum {
     readonly isOverlappingUpgrades: boolean;
     readonly isProhibitedByPolkadot: boolean;
@@ -1742,14 +1737,14 @@
     readonly type: 'OverlappingUpgrades' | 'ProhibitedByPolkadot' | 'TooBig' | 'ValidationDataNotAvailable' | 'HostConfigurationNotAvailable' | 'NotScheduled' | 'NothingAuthorized' | 'Unauthorized';
   }
 
-  /** @name PalletBalancesBalanceLock (174) */
+  /** @name PalletBalancesBalanceLock (173) */
   interface PalletBalancesBalanceLock extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
     readonly reasons: PalletBalancesReasons;
   }
 
-  /** @name PalletBalancesReasons (175) */
+  /** @name PalletBalancesReasons (174) */
   interface PalletBalancesReasons extends Enum {
     readonly isFee: boolean;
     readonly isMisc: boolean;
@@ -1757,20 +1752,20 @@
     readonly type: 'Fee' | 'Misc' | 'All';
   }
 
-  /** @name PalletBalancesReserveData (178) */
+  /** @name PalletBalancesReserveData (177) */
   interface PalletBalancesReserveData extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
   }
 
-  /** @name PalletBalancesReleases (180) */
+  /** @name PalletBalancesReleases (179) */
   interface PalletBalancesReleases extends Enum {
     readonly isV100: boolean;
     readonly isV200: boolean;
     readonly type: 'V100' | 'V200';
   }
 
-  /** @name PalletBalancesCall (181) */
+  /** @name PalletBalancesCall (180) */
   interface PalletBalancesCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -1807,7 +1802,7 @@
     readonly type: 'Transfer' | 'SetBalance' | 'ForceTransfer' | 'TransferKeepAlive' | 'TransferAll' | 'ForceUnreserve';
   }
 
-  /** @name PalletBalancesError (184) */
+  /** @name PalletBalancesError (183) */
   interface PalletBalancesError extends Enum {
     readonly isVestingBalance: boolean;
     readonly isLiquidityRestrictions: boolean;
@@ -1820,7 +1815,7 @@
     readonly type: 'VestingBalance' | 'LiquidityRestrictions' | 'InsufficientBalance' | 'ExistentialDeposit' | 'KeepAlive' | 'ExistingVestingSchedule' | 'DeadAccount' | 'TooManyReserves';
   }
 
-  /** @name PalletTimestampCall (186) */
+  /** @name PalletTimestampCall (185) */
   interface PalletTimestampCall extends Enum {
     readonly isSet: boolean;
     readonly asSet: {
@@ -1829,14 +1824,14 @@
     readonly type: 'Set';
   }
 
-  /** @name PalletTransactionPaymentReleases (188) */
+  /** @name PalletTransactionPaymentReleases (187) */
   interface PalletTransactionPaymentReleases extends Enum {
     readonly isV1Ancient: boolean;
     readonly isV2: boolean;
     readonly type: 'V1Ancient' | 'V2';
   }
 
-  /** @name PalletTreasuryProposal (189) */
+  /** @name PalletTreasuryProposal (188) */
   interface PalletTreasuryProposal extends Struct {
     readonly proposer: AccountId32;
     readonly value: u128;
@@ -1844,7 +1839,7 @@
     readonly bond: u128;
   }
 
-  /** @name PalletTreasuryCall (192) */
+  /** @name PalletTreasuryCall (191) */
   interface PalletTreasuryCall extends Enum {
     readonly isProposeSpend: boolean;
     readonly asProposeSpend: {
@@ -1871,10 +1866,10 @@
     readonly type: 'ProposeSpend' | 'RejectProposal' | 'ApproveProposal' | 'Spend' | 'RemoveApproval';
   }
 
-  /** @name FrameSupportPalletId (195) */
+  /** @name FrameSupportPalletId (194) */
   interface FrameSupportPalletId extends U8aFixed {}
 
-  /** @name PalletTreasuryError (196) */
+  /** @name PalletTreasuryError (195) */
   interface PalletTreasuryError extends Enum {
     readonly isInsufficientProposersBalance: boolean;
     readonly isInvalidIndex: boolean;
@@ -1884,7 +1879,7 @@
     readonly type: 'InsufficientProposersBalance' | 'InvalidIndex' | 'TooManyApprovals' | 'InsufficientPermission' | 'ProposalNotApproved';
   }
 
-  /** @name PalletSudoCall (197) */
+  /** @name PalletSudoCall (196) */
   interface PalletSudoCall extends Enum {
     readonly isSudo: boolean;
     readonly asSudo: {
@@ -1907,7 +1902,7 @@
     readonly type: 'Sudo' | 'SudoUncheckedWeight' | 'SetKey' | 'SudoAs';
   }
 
-  /** @name OrmlVestingModuleCall (199) */
+  /** @name OrmlVestingModuleCall (198) */
   interface OrmlVestingModuleCall extends Enum {
     readonly isClaim: boolean;
     readonly isVestedTransfer: boolean;
@@ -1927,7 +1922,7 @@
     readonly type: 'Claim' | 'VestedTransfer' | 'UpdateVestingSchedules' | 'ClaimFor';
   }
 
-  /** @name OrmlXtokensModuleCall (201) */
+  /** @name OrmlXtokensModuleCall (200) */
   interface OrmlXtokensModuleCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -1974,7 +1969,7 @@
     readonly type: 'Transfer' | 'TransferMultiasset' | 'TransferWithFee' | 'TransferMultiassetWithFee' | 'TransferMulticurrencies' | 'TransferMultiassets';
   }
 
-  /** @name XcmVersionedMultiAsset (202) */
+  /** @name XcmVersionedMultiAsset (201) */
   interface XcmVersionedMultiAsset extends Enum {
     readonly isV0: boolean;
     readonly asV0: XcmV0MultiAsset;
@@ -1983,7 +1978,7 @@
     readonly type: 'V0' | 'V1';
   }
 
-  /** @name OrmlTokensModuleCall (205) */
+  /** @name OrmlTokensModuleCall (204) */
   interface OrmlTokensModuleCall extends Enum {
     readonly isTransfer: boolean;
     readonly asTransfer: {
@@ -2020,7 +2015,7 @@
     readonly type: 'Transfer' | 'TransferAll' | 'TransferKeepAlive' | 'ForceTransfer' | 'SetBalance';
   }
 
-  /** @name CumulusPalletXcmpQueueCall (206) */
+  /** @name CumulusPalletXcmpQueueCall (205) */
   interface CumulusPalletXcmpQueueCall extends Enum {
     readonly isServiceOverweight: boolean;
     readonly asServiceOverweight: {
@@ -2056,7 +2051,7 @@
     readonly type: 'ServiceOverweight' | 'SuspendXcmExecution' | 'ResumeXcmExecution' | 'UpdateSuspendThreshold' | 'UpdateDropThreshold' | 'UpdateResumeThreshold' | 'UpdateThresholdWeight' | 'UpdateWeightRestrictDecay' | 'UpdateXcmpMaxIndividualWeight';
   }
 
-  /** @name PalletXcmCall (207) */
+  /** @name PalletXcmCall (206) */
   interface PalletXcmCall extends Enum {
     readonly isSend: boolean;
     readonly asSend: {
@@ -2118,7 +2113,7 @@
     readonly type: 'Send' | 'TeleportAssets' | 'ReserveTransferAssets' | 'Execute' | 'ForceXcmVersion' | 'ForceDefaultXcmVersion' | 'ForceSubscribeVersionNotify' | 'ForceUnsubscribeVersionNotify' | 'LimitedReserveTransferAssets' | 'LimitedTeleportAssets';
   }
 
-  /** @name XcmVersionedXcm (208) */
+  /** @name XcmVersionedXcm (207) */
   interface XcmVersionedXcm extends Enum {
     readonly isV0: boolean;
     readonly asV0: XcmV0Xcm;
@@ -2129,7 +2124,7 @@
     readonly type: 'V0' | 'V1' | 'V2';
   }
 
-  /** @name XcmV0Xcm (209) */
+  /** @name XcmV0Xcm (208) */
   interface XcmV0Xcm extends Enum {
     readonly isWithdrawAsset: boolean;
     readonly asWithdrawAsset: {
@@ -2192,7 +2187,7 @@
     readonly type: 'WithdrawAsset' | 'ReserveAssetDeposit' | 'TeleportAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom';
   }
 
-  /** @name XcmV0Order (211) */
+  /** @name XcmV0Order (210) */
   interface XcmV0Order extends Enum {
     readonly isNull: boolean;
     readonly isDepositAsset: boolean;
@@ -2240,14 +2235,14 @@
     readonly type: 'Null' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
   }
 
-  /** @name XcmV0Response (213) */
+  /** @name XcmV0Response (212) */
   interface XcmV0Response extends Enum {
     readonly isAssets: boolean;
     readonly asAssets: Vec<XcmV0MultiAsset>;
     readonly type: 'Assets';
   }
 
-  /** @name XcmV1Xcm (214) */
+  /** @name XcmV1Xcm (213) */
   interface XcmV1Xcm extends Enum {
     readonly isWithdrawAsset: boolean;
     readonly asWithdrawAsset: {
@@ -2316,7 +2311,7 @@
     readonly type: 'WithdrawAsset' | 'ReserveAssetDeposited' | 'ReceiveTeleportedAsset' | 'QueryResponse' | 'TransferAsset' | 'TransferReserveAsset' | 'Transact' | 'HrmpNewChannelOpenRequest' | 'HrmpChannelAccepted' | 'HrmpChannelClosing' | 'RelayedFrom' | 'SubscribeVersion' | 'UnsubscribeVersion';
   }
 
-  /** @name XcmV1Order (216) */
+  /** @name XcmV1Order (215) */
   interface XcmV1Order extends Enum {
     readonly isNoop: boolean;
     readonly isDepositAsset: boolean;
@@ -2366,7 +2361,7 @@
     readonly type: 'Noop' | 'DepositAsset' | 'DepositReserveAsset' | 'ExchangeAsset' | 'InitiateReserveWithdraw' | 'InitiateTeleport' | 'QueryHolding' | 'BuyExecution';
   }
 
-  /** @name XcmV1Response (218) */
+  /** @name XcmV1Response (217) */
   interface XcmV1Response extends Enum {
     readonly isAssets: boolean;
     readonly asAssets: XcmV1MultiassetMultiAssets;
@@ -2375,10 +2370,10 @@
     readonly type: 'Assets' | 'Version';
   }
 
-  /** @name CumulusPalletXcmCall (232) */
+  /** @name CumulusPalletXcmCall (231) */
   type CumulusPalletXcmCall = Null;
 
-  /** @name CumulusPalletDmpQueueCall (233) */
+  /** @name CumulusPalletDmpQueueCall (232) */
   interface CumulusPalletDmpQueueCall extends Enum {
     readonly isServiceOverweight: boolean;
     readonly asServiceOverweight: {
@@ -2388,7 +2383,7 @@
     readonly type: 'ServiceOverweight';
   }
 
-  /** @name PalletInflationCall (234) */
+  /** @name PalletInflationCall (233) */
   interface PalletInflationCall extends Enum {
     readonly isStartInflation: boolean;
     readonly asStartInflation: {
@@ -2397,7 +2392,7 @@
     readonly type: 'StartInflation';
   }
 
-  /** @name PalletUniqueCall (235) */
+  /** @name PalletUniqueCall (234) */
   interface PalletUniqueCall extends Enum {
     readonly isCreateCollection: boolean;
     readonly asCreateCollection: {
@@ -2561,7 +2556,7 @@
     readonly type: 'CreateCollection' | 'CreateCollectionEx' | 'DestroyCollection' | 'AddToAllowList' | 'RemoveFromAllowList' | 'ChangeCollectionOwner' | 'AddCollectionAdmin' | 'RemoveCollectionAdmin' | 'SetCollectionSponsor' | 'ConfirmSponsorship' | 'RemoveCollectionSponsor' | 'CreateItem' | 'CreateMultipleItems' | 'SetCollectionProperties' | 'DeleteCollectionProperties' | 'SetTokenProperties' | 'DeleteTokenProperties' | 'SetTokenPropertyPermissions' | 'CreateMultipleItemsEx' | 'SetTransfersEnabledFlag' | 'BurnItem' | 'BurnFrom' | 'Transfer' | 'Approve' | 'TransferFrom' | 'SetCollectionLimits' | 'SetCollectionPermissions' | 'Repartition' | 'SetAllowanceForAll';
   }
 
-  /** @name UpDataStructsCollectionMode (240) */
+  /** @name UpDataStructsCollectionMode (239) */
   interface UpDataStructsCollectionMode extends Enum {
     readonly isNft: boolean;
     readonly isFungible: boolean;
@@ -2570,7 +2565,7 @@
     readonly type: 'Nft' | 'Fungible' | 'ReFungible';
   }
 
-  /** @name UpDataStructsCreateCollectionData (241) */
+  /** @name UpDataStructsCreateCollectionData (240) */
   interface UpDataStructsCreateCollectionData extends Struct {
     readonly mode: UpDataStructsCollectionMode;
     readonly access: Option<UpDataStructsAccessMode>;
@@ -2584,14 +2579,14 @@
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsAccessMode (243) */
+  /** @name UpDataStructsAccessMode (242) */
   interface UpDataStructsAccessMode extends Enum {
     readonly isNormal: boolean;
     readonly isAllowList: boolean;
     readonly type: 'Normal' | 'AllowList';
   }
 
-  /** @name UpDataStructsCollectionLimits (245) */
+  /** @name UpDataStructsCollectionLimits (244) */
   interface UpDataStructsCollectionLimits extends Struct {
     readonly accountTokenOwnershipLimit: Option<u32>;
     readonly sponsoredDataSize: Option<u32>;
@@ -2604,7 +2599,7 @@
     readonly transfersEnabled: Option<bool>;
   }
 
-  /** @name UpDataStructsSponsoringRateLimit (247) */
+  /** @name UpDataStructsSponsoringRateLimit (246) */
   interface UpDataStructsSponsoringRateLimit extends Enum {
     readonly isSponsoringDisabled: boolean;
     readonly isBlocks: boolean;
@@ -2612,43 +2607,43 @@
     readonly type: 'SponsoringDisabled' | 'Blocks';
   }
 
-  /** @name UpDataStructsCollectionPermissions (250) */
+  /** @name UpDataStructsCollectionPermissions (249) */
   interface UpDataStructsCollectionPermissions extends Struct {
     readonly access: Option<UpDataStructsAccessMode>;
     readonly mintMode: Option<bool>;
     readonly nesting: Option<UpDataStructsNestingPermissions>;
   }
 
-  /** @name UpDataStructsNestingPermissions (252) */
+  /** @name UpDataStructsNestingPermissions (251) */
   interface UpDataStructsNestingPermissions extends Struct {
     readonly tokenOwner: bool;
     readonly collectionAdmin: bool;
     readonly restricted: Option<UpDataStructsOwnerRestrictedSet>;
   }
 
-  /** @name UpDataStructsOwnerRestrictedSet (254) */
+  /** @name UpDataStructsOwnerRestrictedSet (253) */
   interface UpDataStructsOwnerRestrictedSet extends BTreeSet<u32> {}
 
-  /** @name UpDataStructsPropertyKeyPermission (259) */
+  /** @name UpDataStructsPropertyKeyPermission (258) */
   interface UpDataStructsPropertyKeyPermission extends Struct {
     readonly key: Bytes;
     readonly permission: UpDataStructsPropertyPermission;
   }
 
-  /** @name UpDataStructsPropertyPermission (260) */
+  /** @name UpDataStructsPropertyPermission (259) */
   interface UpDataStructsPropertyPermission extends Struct {
     readonly mutable: bool;
     readonly collectionAdmin: bool;
     readonly tokenOwner: bool;
   }
 
-  /** @name UpDataStructsProperty (263) */
+  /** @name UpDataStructsProperty (262) */
   interface UpDataStructsProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name UpDataStructsCreateItemData (266) */
+  /** @name UpDataStructsCreateItemData (265) */
   interface UpDataStructsCreateItemData extends Enum {
     readonly isNft: boolean;
     readonly asNft: UpDataStructsCreateNftData;
@@ -2659,23 +2654,23 @@
     readonly type: 'Nft' | 'Fungible' | 'ReFungible';
   }
 
-  /** @name UpDataStructsCreateNftData (267) */
+  /** @name UpDataStructsCreateNftData (266) */
   interface UpDataStructsCreateNftData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateFungibleData (268) */
+  /** @name UpDataStructsCreateFungibleData (267) */
   interface UpDataStructsCreateFungibleData extends Struct {
     readonly value: u128;
   }
 
-  /** @name UpDataStructsCreateReFungibleData (269) */
+  /** @name UpDataStructsCreateReFungibleData (268) */
   interface UpDataStructsCreateReFungibleData extends Struct {
     readonly pieces: u128;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateItemExData (272) */
+  /** @name UpDataStructsCreateItemExData (271) */
   interface UpDataStructsCreateItemExData extends Enum {
     readonly isNft: boolean;
     readonly asNft: Vec<UpDataStructsCreateNftExData>;
@@ -2688,26 +2683,26 @@
     readonly type: 'Nft' | 'Fungible' | 'RefungibleMultipleItems' | 'RefungibleMultipleOwners';
   }
 
-  /** @name UpDataStructsCreateNftExData (274) */
+  /** @name UpDataStructsCreateNftExData (273) */
   interface UpDataStructsCreateNftExData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name UpDataStructsCreateRefungibleExSingleOwner (281) */
+  /** @name UpDataStructsCreateRefungibleExSingleOwner (280) */
   interface UpDataStructsCreateRefungibleExSingleOwner extends Struct {
     readonly user: PalletEvmAccountBasicCrossAccountIdRepr;
     readonly pieces: u128;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name UpDataStructsCreateRefungibleExMultipleOwners (283) */
+  /** @name UpDataStructsCreateRefungibleExMultipleOwners (282) */
   interface UpDataStructsCreateRefungibleExMultipleOwners extends Struct {
     readonly users: BTreeMap<PalletEvmAccountBasicCrossAccountIdRepr, u128>;
     readonly properties: Vec<UpDataStructsProperty>;
   }
 
-  /** @name PalletUniqueSchedulerV2Call (284) */
+  /** @name PalletUniqueSchedulerV2Call (283) */
   interface PalletUniqueSchedulerV2Call extends Enum {
     readonly isSchedule: boolean;
     readonly asSchedule: {
@@ -2756,7 +2751,7 @@
     readonly type: 'Schedule' | 'Cancel' | 'ScheduleNamed' | 'CancelNamed' | 'ScheduleAfter' | 'ScheduleNamedAfter' | 'ChangeNamedPriority';
   }
 
-  /** @name PalletConfigurationCall (287) */
+  /** @name PalletConfigurationCall (286) */
   interface PalletConfigurationCall extends Enum {
     readonly isSetWeightToFeeCoefficientOverride: boolean;
     readonly asSetWeightToFeeCoefficientOverride: {
@@ -2769,13 +2764,13 @@
     readonly type: 'SetWeightToFeeCoefficientOverride' | 'SetMinGasPriceOverride';
   }
 
-  /** @name PalletTemplateTransactionPaymentCall (289) */
+  /** @name PalletTemplateTransactionPaymentCall (288) */
   type PalletTemplateTransactionPaymentCall = Null;
 
-  /** @name PalletStructureCall (290) */
+  /** @name PalletStructureCall (289) */
   type PalletStructureCall = Null;
 
-  /** @name PalletRmrkCoreCall (291) */
+  /** @name PalletRmrkCoreCall (290) */
   interface PalletRmrkCoreCall extends Enum {
     readonly isCreateCollection: boolean;
     readonly asCreateCollection: {
@@ -2881,7 +2876,7 @@
     readonly type: 'CreateCollection' | 'DestroyCollection' | 'ChangeCollectionIssuer' | 'LockCollection' | 'MintNft' | 'BurnNft' | 'Send' | 'AcceptNft' | 'RejectNft' | 'AcceptResource' | 'AcceptResourceRemoval' | 'SetProperty' | 'SetPriority' | 'AddBasicResource' | 'AddComposableResource' | 'AddSlotResource' | 'RemoveResource';
   }
 
-  /** @name RmrkTraitsResourceResourceTypes (297) */
+  /** @name RmrkTraitsResourceResourceTypes (296) */
   interface RmrkTraitsResourceResourceTypes extends Enum {
     readonly isBasic: boolean;
     readonly asBasic: RmrkTraitsResourceBasicResource;
@@ -2892,7 +2887,7 @@
     readonly type: 'Basic' | 'Composable' | 'Slot';
   }
 
-  /** @name RmrkTraitsResourceBasicResource (299) */
+  /** @name RmrkTraitsResourceBasicResource (298) */
   interface RmrkTraitsResourceBasicResource extends Struct {
     readonly src: Option<Bytes>;
     readonly metadata: Option<Bytes>;
@@ -2900,7 +2895,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name RmrkTraitsResourceComposableResource (301) */
+  /** @name RmrkTraitsResourceComposableResource (300) */
   interface RmrkTraitsResourceComposableResource extends Struct {
     readonly parts: Vec<u32>;
     readonly base: u32;
@@ -2910,7 +2905,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name RmrkTraitsResourceSlotResource (302) */
+  /** @name RmrkTraitsResourceSlotResource (301) */
   interface RmrkTraitsResourceSlotResource extends Struct {
     readonly base: u32;
     readonly src: Option<Bytes>;
@@ -2920,7 +2915,7 @@
     readonly thumb: Option<Bytes>;
   }
 
-  /** @name PalletRmrkEquipCall (305) */
+  /** @name PalletRmrkEquipCall (304) */
   interface PalletRmrkEquipCall extends Enum {
     readonly isCreateBase: boolean;
     readonly asCreateBase: {
@@ -2942,7 +2937,7 @@
     readonly type: 'CreateBase' | 'ThemeAdd' | 'Equippable';
   }
 
-  /** @name RmrkTraitsPartPartType (308) */
+  /** @name RmrkTraitsPartPartType (307) */
   interface RmrkTraitsPartPartType extends Enum {
     readonly isFixedPart: boolean;
     readonly asFixedPart: RmrkTraitsPartFixedPart;
@@ -2951,14 +2946,14 @@
     readonly type: 'FixedPart' | 'SlotPart';
   }
 
-  /** @name RmrkTraitsPartFixedPart (310) */
+  /** @name RmrkTraitsPartFixedPart (309) */
   interface RmrkTraitsPartFixedPart extends Struct {
     readonly id: u32;
     readonly z: u32;
     readonly src: Bytes;
   }
 
-  /** @name RmrkTraitsPartSlotPart (311) */
+  /** @name RmrkTraitsPartSlotPart (310) */
   interface RmrkTraitsPartSlotPart extends Struct {
     readonly id: u32;
     readonly equippable: RmrkTraitsPartEquippableList;
@@ -2966,7 +2961,7 @@
     readonly z: u32;
   }
 
-  /** @name RmrkTraitsPartEquippableList (312) */
+  /** @name RmrkTraitsPartEquippableList (311) */
   interface RmrkTraitsPartEquippableList extends Enum {
     readonly isAll: boolean;
     readonly isEmpty: boolean;
@@ -2975,20 +2970,20 @@
     readonly type: 'All' | 'Empty' | 'Custom';
   }
 
-  /** @name RmrkTraitsTheme (314) */
+  /** @name RmrkTraitsTheme (313) */
   interface RmrkTraitsTheme extends Struct {
     readonly name: Bytes;
     readonly properties: Vec<RmrkTraitsThemeThemeProperty>;
     readonly inherit: bool;
   }
 
-  /** @name RmrkTraitsThemeThemeProperty (316) */
+  /** @name RmrkTraitsThemeThemeProperty (315) */
   interface RmrkTraitsThemeThemeProperty extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name PalletAppPromotionCall (318) */
+  /** @name PalletAppPromotionCall (317) */
   interface PalletAppPromotionCall extends Enum {
     readonly isSetAdminAddress: boolean;
     readonly asSetAdminAddress: {
@@ -3022,7 +3017,7 @@
     readonly type: 'SetAdminAddress' | 'Stake' | 'Unstake' | 'SponsorCollection' | 'StopSponsoringCollection' | 'SponsorContract' | 'StopSponsoringContract' | 'PayoutStakers';
   }
 
-  /** @name PalletForeignAssetsModuleCall (319) */
+  /** @name PalletForeignAssetsModuleCall (318) */
   interface PalletForeignAssetsModuleCall extends Enum {
     readonly isRegisterForeignAsset: boolean;
     readonly asRegisterForeignAsset: {
@@ -3039,7 +3034,7 @@
     readonly type: 'RegisterForeignAsset' | 'UpdateForeignAsset';
   }
 
-  /** @name PalletEvmCall (320) */
+  /** @name PalletEvmCall (319) */
   interface PalletEvmCall extends Enum {
     readonly isWithdraw: boolean;
     readonly asWithdraw: {
@@ -3084,7 +3079,7 @@
     readonly type: 'Withdraw' | 'Call' | 'Create' | 'Create2';
   }
 
-  /** @name PalletEthereumCall (326) */
+  /** @name PalletEthereumCall (325) */
   interface PalletEthereumCall extends Enum {
     readonly isTransact: boolean;
     readonly asTransact: {
@@ -3093,7 +3088,7 @@
     readonly type: 'Transact';
   }
 
-  /** @name EthereumTransactionTransactionV2 (327) */
+  /** @name EthereumTransactionTransactionV2 (326) */
   interface EthereumTransactionTransactionV2 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumTransactionLegacyTransaction;
@@ -3104,7 +3099,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumTransactionLegacyTransaction (328) */
+  /** @name EthereumTransactionLegacyTransaction (327) */
   interface EthereumTransactionLegacyTransaction extends Struct {
     readonly nonce: U256;
     readonly gasPrice: U256;
@@ -3115,7 +3110,7 @@
     readonly signature: EthereumTransactionTransactionSignature;
   }
 
-  /** @name EthereumTransactionTransactionAction (329) */
+  /** @name EthereumTransactionTransactionAction (328) */
   interface EthereumTransactionTransactionAction extends Enum {
     readonly isCall: boolean;
     readonly asCall: H160;
@@ -3123,14 +3118,14 @@
     readonly type: 'Call' | 'Create';
   }
 
-  /** @name EthereumTransactionTransactionSignature (330) */
+  /** @name EthereumTransactionTransactionSignature (329) */
   interface EthereumTransactionTransactionSignature extends Struct {
     readonly v: u64;
     readonly r: H256;
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionEip2930Transaction (332) */
+  /** @name EthereumTransactionEip2930Transaction (331) */
   interface EthereumTransactionEip2930Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -3145,13 +3140,13 @@
     readonly s: H256;
   }
 
-  /** @name EthereumTransactionAccessListItem (334) */
+  /** @name EthereumTransactionAccessListItem (333) */
   interface EthereumTransactionAccessListItem extends Struct {
     readonly address: H160;
     readonly storageKeys: Vec<H256>;
   }
 
-  /** @name EthereumTransactionEip1559Transaction (335) */
+  /** @name EthereumTransactionEip1559Transaction (334) */
   interface EthereumTransactionEip1559Transaction extends Struct {
     readonly chainId: u64;
     readonly nonce: U256;
@@ -3167,7 +3162,7 @@
     readonly s: H256;
   }
 
-  /** @name PalletEvmMigrationCall (336) */
+  /** @name PalletEvmMigrationCall (335) */
   interface PalletEvmMigrationCall extends Enum {
     readonly isBegin: boolean;
     readonly asBegin: {
@@ -3194,14 +3189,14 @@
     readonly type: 'Begin' | 'SetData' | 'Finish' | 'InsertEthLogs' | 'InsertEvents';
   }
 
-  /** @name PalletMaintenanceCall (340) */
+  /** @name PalletMaintenanceCall (339) */
   interface PalletMaintenanceCall extends Enum {
     readonly isEnable: boolean;
     readonly isDisable: boolean;
     readonly type: 'Enable' | 'Disable';
   }
 
-  /** @name PalletTestUtilsCall (341) */
+  /** @name PalletTestUtilsCall (340) */
   interface PalletTestUtilsCall extends Enum {
     readonly isEnable: boolean;
     readonly isSetTestValue: boolean;
@@ -3226,13 +3221,13 @@
     readonly type: 'Enable' | 'SetTestValue' | 'SetTestValueAndRollback' | 'IncTestValue' | 'SelfCancelingInc' | 'JustTakeFee' | 'BatchAll';
   }
 
-  /** @name PalletSudoError (343) */
+  /** @name PalletSudoError (342) */
   interface PalletSudoError extends Enum {
     readonly isRequireSudo: boolean;
     readonly type: 'RequireSudo';
   }
 
-  /** @name OrmlVestingModuleError (345) */
+  /** @name OrmlVestingModuleError (344) */
   interface OrmlVestingModuleError extends Enum {
     readonly isZeroVestingPeriod: boolean;
     readonly isZeroVestingPeriodCount: boolean;
@@ -3243,7 +3238,7 @@
     readonly type: 'ZeroVestingPeriod' | 'ZeroVestingPeriodCount' | 'InsufficientBalanceToLock' | 'TooManyVestingSchedules' | 'AmountLow' | 'MaxVestingSchedulesExceeded';
   }
 
-  /** @name OrmlXtokensModuleError (346) */
+  /** @name OrmlXtokensModuleError (345) */
   interface OrmlXtokensModuleError extends Enum {
     readonly isAssetHasNoReserve: boolean;
     readonly isNotCrossChainTransfer: boolean;
@@ -3267,26 +3262,26 @@
     readonly type: 'AssetHasNoReserve' | 'NotCrossChainTransfer' | 'InvalidDest' | 'NotCrossChainTransferableCurrency' | 'UnweighableMessage' | 'XcmExecutionFailed' | 'CannotReanchor' | 'InvalidAncestry' | 'InvalidAsset' | 'DestinationNotInvertible' | 'BadVersion' | 'DistinctReserveForAssetAndFee' | 'ZeroFee' | 'ZeroAmount' | 'TooManyAssetsBeingSent' | 'AssetIndexNonExistent' | 'FeeNotEnough' | 'NotSupportedMultiLocation' | 'MinXcmFeeNotDefined';
   }
 
-  /** @name OrmlTokensBalanceLock (349) */
+  /** @name OrmlTokensBalanceLock (348) */
   interface OrmlTokensBalanceLock extends Struct {
     readonly id: U8aFixed;
     readonly amount: u128;
   }
 
-  /** @name OrmlTokensAccountData (351) */
+  /** @name OrmlTokensAccountData (350) */
   interface OrmlTokensAccountData extends Struct {
     readonly free: u128;
     readonly reserved: u128;
     readonly frozen: u128;
   }
 
-  /** @name OrmlTokensReserveData (353) */
+  /** @name OrmlTokensReserveData (352) */
   interface OrmlTokensReserveData extends Struct {
     readonly id: Null;
     readonly amount: u128;
   }
 
-  /** @name OrmlTokensModuleError (355) */
+  /** @name OrmlTokensModuleError (354) */
   interface OrmlTokensModuleError extends Enum {
     readonly isBalanceTooLow: boolean;
     readonly isAmountIntoBalanceFailed: boolean;
@@ -3299,21 +3294,21 @@
     readonly type: 'BalanceTooLow' | 'AmountIntoBalanceFailed' | 'LiquidityRestrictions' | 'MaxLocksExceeded' | 'KeepAlive' | 'ExistentialDeposit' | 'DeadAccount' | 'TooManyReserves';
   }
 
-  /** @name CumulusPalletXcmpQueueInboundChannelDetails (357) */
+  /** @name CumulusPalletXcmpQueueInboundChannelDetails (356) */
   interface CumulusPalletXcmpQueueInboundChannelDetails extends Struct {
     readonly sender: u32;
     readonly state: CumulusPalletXcmpQueueInboundState;
     readonly messageMetadata: Vec<ITuple<[u32, PolkadotParachainPrimitivesXcmpMessageFormat]>>;
   }
 
-  /** @name CumulusPalletXcmpQueueInboundState (358) */
+  /** @name CumulusPalletXcmpQueueInboundState (357) */
   interface CumulusPalletXcmpQueueInboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (361) */
+  /** @name PolkadotParachainPrimitivesXcmpMessageFormat (360) */
   interface PolkadotParachainPrimitivesXcmpMessageFormat extends Enum {
     readonly isConcatenatedVersionedXcm: boolean;
     readonly isConcatenatedEncodedBlob: boolean;
@@ -3321,7 +3316,7 @@
     readonly type: 'ConcatenatedVersionedXcm' | 'ConcatenatedEncodedBlob' | 'Signals';
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (364) */
+  /** @name CumulusPalletXcmpQueueOutboundChannelDetails (363) */
   interface CumulusPalletXcmpQueueOutboundChannelDetails extends Struct {
     readonly recipient: u32;
     readonly state: CumulusPalletXcmpQueueOutboundState;
@@ -3330,14 +3325,14 @@
     readonly lastIndex: u16;
   }
 
-  /** @name CumulusPalletXcmpQueueOutboundState (365) */
+  /** @name CumulusPalletXcmpQueueOutboundState (364) */
   interface CumulusPalletXcmpQueueOutboundState extends Enum {
     readonly isOk: boolean;
     readonly isSuspended: boolean;
     readonly type: 'Ok' | 'Suspended';
   }
 
-  /** @name CumulusPalletXcmpQueueQueueConfigData (367) */
+  /** @name CumulusPalletXcmpQueueQueueConfigData (366) */
   interface CumulusPalletXcmpQueueQueueConfigData extends Struct {
     readonly suspendThreshold: u32;
     readonly dropThreshold: u32;
@@ -3347,7 +3342,7 @@
     readonly xcmpMaxIndividualWeight: SpWeightsWeightV2Weight;
   }
 
-  /** @name CumulusPalletXcmpQueueError (369) */
+  /** @name CumulusPalletXcmpQueueError (368) */
   interface CumulusPalletXcmpQueueError extends Enum {
     readonly isFailedToSend: boolean;
     readonly isBadXcmOrigin: boolean;
@@ -3357,7 +3352,7 @@
     readonly type: 'FailedToSend' | 'BadXcmOrigin' | 'BadXcm' | 'BadOverweightIndex' | 'WeightOverLimit';
   }
 
-  /** @name PalletXcmError (370) */
+  /** @name PalletXcmError (369) */
   interface PalletXcmError extends Enum {
     readonly isUnreachable: boolean;
     readonly isSendFailure: boolean;
@@ -3375,44 +3370,43 @@
     readonly type: 'Unreachable' | 'SendFailure' | 'Filtered' | 'UnweighableMessage' | 'DestinationNotInvertible' | 'Empty' | 'CannotReanchor' | 'TooManyAssets' | 'InvalidOrigin' | 'BadVersion' | 'BadLocation' | 'NoSubscription' | 'AlreadySubscribed';
   }
 
-  /** @name CumulusPalletXcmError (371) */
+  /** @name CumulusPalletXcmError (370) */
   type CumulusPalletXcmError = Null;
 
-  /** @name CumulusPalletDmpQueueConfigData (372) */
+  /** @name CumulusPalletDmpQueueConfigData (371) */
   interface CumulusPalletDmpQueueConfigData extends Struct {
     readonly maxIndividual: SpWeightsWeightV2Weight;
   }
 
-  /** @name CumulusPalletDmpQueuePageIndexData (373) */
+  /** @name CumulusPalletDmpQueuePageIndexData (372) */
   interface CumulusPalletDmpQueuePageIndexData extends Struct {
     readonly beginUsed: u32;
     readonly endUsed: u32;
     readonly overweightCount: u64;
   }
 
-  /** @name CumulusPalletDmpQueueError (376) */
+  /** @name CumulusPalletDmpQueueError (375) */
   interface CumulusPalletDmpQueueError extends Enum {
     readonly isUnknown: boolean;
     readonly isOverLimit: boolean;
     readonly type: 'Unknown' | 'OverLimit';
   }
 
-  /** @name PalletUniqueError (380) */
+  /** @name PalletUniqueError (379) */
   interface PalletUniqueError extends Enum {
     readonly isCollectionDecimalPointLimitExceeded: boolean;
-    readonly isConfirmUnsetSponsorFail: boolean;
     readonly isEmptyArgument: boolean;
     readonly isRepartitionCalledOnNonRefungibleCollection: boolean;
-    readonly type: 'CollectionDecimalPointLimitExceeded' | 'ConfirmUnsetSponsorFail' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
+    readonly type: 'CollectionDecimalPointLimitExceeded' | 'EmptyArgument' | 'RepartitionCalledOnNonRefungibleCollection';
   }
 
-  /** @name PalletUniqueSchedulerV2BlockAgenda (381) */
+  /** @name PalletUniqueSchedulerV2BlockAgenda (380) */
   interface PalletUniqueSchedulerV2BlockAgenda extends Struct {
     readonly agenda: Vec<Option<PalletUniqueSchedulerV2Scheduled>>;
     readonly freePlaces: u32;
   }
 
-  /** @name PalletUniqueSchedulerV2Scheduled (384) */
+  /** @name PalletUniqueSchedulerV2Scheduled (383) */
   interface PalletUniqueSchedulerV2Scheduled extends Struct {
     readonly maybeId: Option<U8aFixed>;
     readonly priority: u8;
@@ -3421,7 +3415,7 @@
     readonly origin: OpalRuntimeOriginCaller;
   }
 
-  /** @name PalletUniqueSchedulerV2ScheduledCall (385) */
+  /** @name PalletUniqueSchedulerV2ScheduledCall (384) */
   interface PalletUniqueSchedulerV2ScheduledCall extends Enum {
     readonly isInline: boolean;
     readonly asInline: Bytes;
@@ -3433,7 +3427,7 @@
     readonly type: 'Inline' | 'PreimageLookup';
   }
 
-  /** @name OpalRuntimeOriginCaller (387) */
+  /** @name OpalRuntimeOriginCaller (386) */
   interface OpalRuntimeOriginCaller extends Enum {
     readonly isSystem: boolean;
     readonly asSystem: FrameSupportDispatchRawOrigin;
@@ -3447,7 +3441,7 @@
     readonly type: 'System' | 'Void' | 'PolkadotXcm' | 'CumulusXcm' | 'Ethereum';
   }
 
-  /** @name FrameSupportDispatchRawOrigin (388) */
+  /** @name FrameSupportDispatchRawOrigin (387) */
   interface FrameSupportDispatchRawOrigin extends Enum {
     readonly isRoot: boolean;
     readonly isSigned: boolean;
@@ -3456,7 +3450,7 @@
     readonly type: 'Root' | 'Signed' | 'None';
   }
 
-  /** @name PalletXcmOrigin (389) */
+  /** @name PalletXcmOrigin (388) */
   interface PalletXcmOrigin extends Enum {
     readonly isXcm: boolean;
     readonly asXcm: XcmV1MultiLocation;
@@ -3465,7 +3459,7 @@
     readonly type: 'Xcm' | 'Response';
   }
 
-  /** @name CumulusPalletXcmOrigin (390) */
+  /** @name CumulusPalletXcmOrigin (389) */
   interface CumulusPalletXcmOrigin extends Enum {
     readonly isRelay: boolean;
     readonly isSiblingParachain: boolean;
@@ -3473,17 +3467,17 @@
     readonly type: 'Relay' | 'SiblingParachain';
   }
 
-  /** @name PalletEthereumRawOrigin (391) */
+  /** @name PalletEthereumRawOrigin (390) */
   interface PalletEthereumRawOrigin extends Enum {
     readonly isEthereumTransaction: boolean;
     readonly asEthereumTransaction: H160;
     readonly type: 'EthereumTransaction';
   }
 
-  /** @name SpCoreVoid (392) */
+  /** @name SpCoreVoid (391) */
   type SpCoreVoid = Null;
 
-  /** @name PalletUniqueSchedulerV2Error (394) */
+  /** @name PalletUniqueSchedulerV2Error (393) */
   interface PalletUniqueSchedulerV2Error extends Enum {
     readonly isFailedToSchedule: boolean;
     readonly isAgendaIsExhausted: boolean;
@@ -3496,7 +3490,7 @@
     readonly type: 'FailedToSchedule' | 'AgendaIsExhausted' | 'ScheduledCallCorrupted' | 'PreimageNotFound' | 'TooBigScheduledCall' | 'NotFound' | 'TargetBlockNumberInPast' | 'Named';
   }
 
-  /** @name UpDataStructsCollection (395) */
+  /** @name UpDataStructsCollection (394) */
   interface UpDataStructsCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -3509,7 +3503,7 @@
     readonly flags: U8aFixed;
   }
 
-  /** @name UpDataStructsSponsorshipStateAccountId32 (396) */
+  /** @name UpDataStructsSponsorshipStateAccountId32 (395) */
   interface UpDataStructsSponsorshipStateAccountId32 extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -3519,43 +3513,43 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name UpDataStructsProperties (398) */
+  /** @name UpDataStructsProperties (397) */
   interface UpDataStructsProperties extends Struct {
     readonly map: UpDataStructsPropertiesMapBoundedVec;
     readonly consumedSpace: u32;
     readonly spaceLimit: u32;
   }
 
-  /** @name UpDataStructsPropertiesMapBoundedVec (399) */
+  /** @name UpDataStructsPropertiesMapBoundedVec (398) */
   interface UpDataStructsPropertiesMapBoundedVec extends BTreeMap<Bytes, Bytes> {}
 
-  /** @name UpDataStructsPropertiesMapPropertyPermission (404) */
+  /** @name UpDataStructsPropertiesMapPropertyPermission (403) */
   interface UpDataStructsPropertiesMapPropertyPermission extends BTreeMap<Bytes, UpDataStructsPropertyPermission> {}
 
-  /** @name UpDataStructsCollectionStats (411) */
+  /** @name UpDataStructsCollectionStats (410) */
   interface UpDataStructsCollectionStats extends Struct {
     readonly created: u32;
     readonly destroyed: u32;
     readonly alive: u32;
   }
 
-  /** @name UpDataStructsTokenChild (412) */
+  /** @name UpDataStructsTokenChild (411) */
   interface UpDataStructsTokenChild extends Struct {
     readonly token: u32;
     readonly collection: u32;
   }
 
-  /** @name PhantomTypeUpDataStructs (413) */
+  /** @name PhantomTypeUpDataStructs (412) */
   interface PhantomTypeUpDataStructs extends Vec<ITuple<[UpDataStructsTokenData, UpDataStructsRpcCollection, RmrkTraitsCollectionCollectionInfo, RmrkTraitsNftNftInfo, RmrkTraitsResourceResourceInfo, RmrkTraitsPropertyPropertyInfo, RmrkTraitsBaseBaseInfo, RmrkTraitsPartPartType, RmrkTraitsTheme, RmrkTraitsNftNftChild]>> {}
 
-  /** @name UpDataStructsTokenData (415) */
+  /** @name UpDataStructsTokenData (414) */
   interface UpDataStructsTokenData extends Struct {
     readonly properties: Vec<UpDataStructsProperty>;
     readonly owner: Option<PalletEvmAccountBasicCrossAccountIdRepr>;
     readonly pieces: u128;
   }
 
-  /** @name UpDataStructsRpcCollection (417) */
+  /** @name UpDataStructsRpcCollection (416) */
   interface UpDataStructsRpcCollection extends Struct {
     readonly owner: AccountId32;
     readonly mode: UpDataStructsCollectionMode;
@@ -3571,13 +3565,13 @@
     readonly flags: UpDataStructsRpcCollectionFlags;
   }
 
-  /** @name UpDataStructsRpcCollectionFlags (418) */
+  /** @name UpDataStructsRpcCollectionFlags (417) */
   interface UpDataStructsRpcCollectionFlags extends Struct {
     readonly foreign: bool;
     readonly erc721metadata: bool;
   }
 
-  /** @name RmrkTraitsCollectionCollectionInfo (419) */
+  /** @name RmrkTraitsCollectionCollectionInfo (418) */
   interface RmrkTraitsCollectionCollectionInfo extends Struct {
     readonly issuer: AccountId32;
     readonly metadata: Bytes;
@@ -3586,7 +3580,7 @@
     readonly nftsCount: u32;
   }
 
-  /** @name RmrkTraitsNftNftInfo (420) */
+  /** @name RmrkTraitsNftNftInfo (419) */
   interface RmrkTraitsNftNftInfo extends Struct {
     readonly owner: RmrkTraitsNftAccountIdOrCollectionNftTuple;
     readonly royalty: Option<RmrkTraitsNftRoyaltyInfo>;
@@ -3595,13 +3589,13 @@
     readonly pending: bool;
   }
 
-  /** @name RmrkTraitsNftRoyaltyInfo (422) */
+  /** @name RmrkTraitsNftRoyaltyInfo (421) */
   interface RmrkTraitsNftRoyaltyInfo extends Struct {
     readonly recipient: AccountId32;
     readonly amount: Permill;
   }
 
-  /** @name RmrkTraitsResourceResourceInfo (423) */
+  /** @name RmrkTraitsResourceResourceInfo (422) */
   interface RmrkTraitsResourceResourceInfo extends Struct {
     readonly id: u32;
     readonly resource: RmrkTraitsResourceResourceTypes;
@@ -3609,26 +3603,26 @@
     readonly pendingRemoval: bool;
   }
 
-  /** @name RmrkTraitsPropertyPropertyInfo (424) */
+  /** @name RmrkTraitsPropertyPropertyInfo (423) */
   interface RmrkTraitsPropertyPropertyInfo extends Struct {
     readonly key: Bytes;
     readonly value: Bytes;
   }
 
-  /** @name RmrkTraitsBaseBaseInfo (425) */
+  /** @name RmrkTraitsBaseBaseInfo (424) */
   interface RmrkTraitsBaseBaseInfo extends Struct {
     readonly issuer: AccountId32;
     readonly baseType: Bytes;
     readonly symbol: Bytes;
   }
 
-  /** @name RmrkTraitsNftNftChild (426) */
+  /** @name RmrkTraitsNftNftChild (425) */
   interface RmrkTraitsNftNftChild extends Struct {
     readonly collectionId: u32;
     readonly nftId: u32;
   }
 
-  /** @name PalletCommonError (428) */
+  /** @name PalletCommonError (427) */
   interface PalletCommonError extends Enum {
     readonly isCollectionNotFound: boolean;
     readonly isMustBeTokenOwner: boolean;
@@ -3664,10 +3658,12 @@
     readonly isEmptyPropertyKey: boolean;
     readonly isCollectionIsExternal: boolean;
     readonly isCollectionIsInternal: boolean;
-    readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal';
+    readonly isConfirmSponsorshipFail: boolean;
+    readonly isUserIsNotCollectionAdmin: boolean;
+    readonly type: 'CollectionNotFound' | 'MustBeTokenOwner' | 'NoPermission' | 'CantDestroyNotEmptyCollection' | 'PublicMintingNotAllowed' | 'AddressNotInAllowlist' | 'CollectionNameLimitExceeded' | 'CollectionDescriptionLimitExceeded' | 'CollectionTokenPrefixLimitExceeded' | 'TotalCollectionsLimitExceeded' | 'CollectionAdminCountExceeded' | 'CollectionLimitBoundsExceeded' | 'OwnerPermissionsCantBeReverted' | 'TransferNotAllowed' | 'AccountTokenLimitExceeded' | 'CollectionTokenLimitExceeded' | 'MetadataFlagFrozen' | 'TokenNotFound' | 'TokenValueTooLow' | 'ApprovedValueTooLow' | 'CantApproveMoreThanOwned' | 'AddressIsZero' | 'UnsupportedOperation' | 'NotSufficientFounds' | 'UserIsNotAllowedToNest' | 'SourceCollectionIsNotAllowedToNest' | 'CollectionFieldSizeExceeded' | 'NoSpaceForProperty' | 'PropertyLimitReached' | 'PropertyKeyIsTooLong' | 'InvalidCharacterInPropertyKey' | 'EmptyPropertyKey' | 'CollectionIsExternal' | 'CollectionIsInternal' | 'ConfirmSponsorshipFail' | 'UserIsNotCollectionAdmin';
   }
 
-  /** @name PalletFungibleError (430) */
+  /** @name PalletFungibleError (429) */
   interface PalletFungibleError extends Enum {
     readonly isNotFungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isFungibleItemsHaveNoId: boolean;
@@ -3678,12 +3674,12 @@
     readonly type: 'NotFungibleDataUsedToMintFungibleCollectionToken' | 'FungibleItemsHaveNoId' | 'FungibleItemsDontHaveData' | 'FungibleDisallowsNesting' | 'SettingPropertiesNotAllowed' | 'SettingAllowanceForAllNotAllowed';
   }
 
-  /** @name PalletRefungibleItemData (431) */
+  /** @name PalletRefungibleItemData (430) */
   interface PalletRefungibleItemData extends Struct {
     readonly constData: Bytes;
   }
 
-  /** @name PalletRefungibleError (436) */
+  /** @name PalletRefungibleError (435) */
   interface PalletRefungibleError extends Enum {
     readonly isNotRefungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isWrongRefungiblePieces: boolean;
@@ -3693,19 +3689,19 @@
     readonly type: 'NotRefungibleDataUsedToMintFungibleCollectionToken' | 'WrongRefungiblePieces' | 'RepartitionWhileNotOwningAllPieces' | 'RefungibleDisallowsNesting' | 'SettingPropertiesNotAllowed';
   }
 
-  /** @name PalletNonfungibleItemData (437) */
+  /** @name PalletNonfungibleItemData (436) */
   interface PalletNonfungibleItemData extends Struct {
     readonly owner: PalletEvmAccountBasicCrossAccountIdRepr;
   }
 
-  /** @name UpDataStructsPropertyScope (439) */
+  /** @name UpDataStructsPropertyScope (438) */
   interface UpDataStructsPropertyScope extends Enum {
     readonly isNone: boolean;
     readonly isRmrk: boolean;
     readonly type: 'None' | 'Rmrk';
   }
 
-  /** @name PalletNonfungibleError (441) */
+  /** @name PalletNonfungibleError (440) */
   interface PalletNonfungibleError extends Enum {
     readonly isNotNonfungibleDataUsedToMintFungibleCollectionToken: boolean;
     readonly isNonfungibleItemsHaveNoAmount: boolean;
@@ -3713,7 +3709,7 @@
     readonly type: 'NotNonfungibleDataUsedToMintFungibleCollectionToken' | 'NonfungibleItemsHaveNoAmount' | 'CantBurnNftWithChildren';
   }
 
-  /** @name PalletStructureError (442) */
+  /** @name PalletStructureError (441) */
   interface PalletStructureError extends Enum {
     readonly isOuroborosDetected: boolean;
     readonly isDepthLimit: boolean;
@@ -3722,7 +3718,7 @@
     readonly type: 'OuroborosDetected' | 'DepthLimit' | 'BreadthLimit' | 'TokenNotFound';
   }
 
-  /** @name PalletRmrkCoreError (443) */
+  /** @name PalletRmrkCoreError (442) */
   interface PalletRmrkCoreError extends Enum {
     readonly isCorruptedCollectionType: boolean;
     readonly isRmrkPropertyKeyIsTooLong: boolean;
@@ -3746,7 +3742,7 @@
     readonly type: 'CorruptedCollectionType' | 'RmrkPropertyKeyIsTooLong' | 'RmrkPropertyValueIsTooLong' | 'RmrkPropertyIsNotFound' | 'UnableToDecodeRmrkData' | 'CollectionNotEmpty' | 'NoAvailableCollectionId' | 'NoAvailableNftId' | 'CollectionUnknown' | 'NoPermission' | 'NonTransferable' | 'CollectionFullOrLocked' | 'ResourceDoesntExist' | 'CannotSendToDescendentOrSelf' | 'CannotAcceptNonOwnedNft' | 'CannotRejectNonOwnedNft' | 'CannotRejectNonPendingNft' | 'ResourceNotPending' | 'NoAvailableResourceId';
   }
 
-  /** @name PalletRmrkEquipError (445) */
+  /** @name PalletRmrkEquipError (444) */
   interface PalletRmrkEquipError extends Enum {
     readonly isPermissionError: boolean;
     readonly isNoAvailableBaseId: boolean;
@@ -3758,7 +3754,7 @@
     readonly type: 'PermissionError' | 'NoAvailableBaseId' | 'NoAvailablePartId' | 'BaseDoesntExist' | 'NeedsDefaultThemeFirst' | 'PartDoesntExist' | 'NoEquippableOnFixedPart';
   }
 
-  /** @name PalletAppPromotionError (451) */
+  /** @name PalletAppPromotionError (450) */
   interface PalletAppPromotionError extends Enum {
     readonly isAdminNotSet: boolean;
     readonly isNoPermission: boolean;
@@ -3769,7 +3765,7 @@
     readonly type: 'AdminNotSet' | 'NoPermission' | 'NotSufficientFunds' | 'PendingForBlockOverflow' | 'SponsorNotSet' | 'IncorrectLockedBalanceOperation';
   }
 
-  /** @name PalletForeignAssetsModuleError (452) */
+  /** @name PalletForeignAssetsModuleError (451) */
   interface PalletForeignAssetsModuleError extends Enum {
     readonly isBadLocation: boolean;
     readonly isMultiLocationExisted: boolean;
@@ -3778,7 +3774,7 @@
     readonly type: 'BadLocation' | 'MultiLocationExisted' | 'AssetIdNotExists' | 'AssetIdExisted';
   }
 
-  /** @name PalletEvmError (454) */
+  /** @name PalletEvmError (453) */
   interface PalletEvmError extends Enum {
     readonly isBalanceLow: boolean;
     readonly isFeeOverflow: boolean;
@@ -3793,7 +3789,7 @@
     readonly type: 'BalanceLow' | 'FeeOverflow' | 'PaymentOverflow' | 'WithdrawFailed' | 'GasPriceTooLow' | 'InvalidNonce' | 'GasLimitTooLow' | 'GasLimitTooHigh' | 'Undefined' | 'Reentrancy';
   }
 
-  /** @name FpRpcTransactionStatus (457) */
+  /** @name FpRpcTransactionStatus (456) */
   interface FpRpcTransactionStatus extends Struct {
     readonly transactionHash: H256;
     readonly transactionIndex: u32;
@@ -3804,10 +3800,10 @@
     readonly logsBloom: EthbloomBloom;
   }
 
-  /** @name EthbloomBloom (459) */
+  /** @name EthbloomBloom (458) */
   interface EthbloomBloom extends U8aFixed {}
 
-  /** @name EthereumReceiptReceiptV3 (461) */
+  /** @name EthereumReceiptReceiptV3 (460) */
   interface EthereumReceiptReceiptV3 extends Enum {
     readonly isLegacy: boolean;
     readonly asLegacy: EthereumReceiptEip658ReceiptData;
@@ -3818,7 +3814,7 @@
     readonly type: 'Legacy' | 'Eip2930' | 'Eip1559';
   }
 
-  /** @name EthereumReceiptEip658ReceiptData (462) */
+  /** @name EthereumReceiptEip658ReceiptData (461) */
   interface EthereumReceiptEip658ReceiptData extends Struct {
     readonly statusCode: u8;
     readonly usedGas: U256;
@@ -3826,14 +3822,14 @@
     readonly logs: Vec<EthereumLog>;
   }
 
-  /** @name EthereumBlock (463) */
+  /** @name EthereumBlock (462) */
   interface EthereumBlock extends Struct {
     readonly header: EthereumHeader;
     readonly transactions: Vec<EthereumTransactionTransactionV2>;
     readonly ommers: Vec<EthereumHeader>;
   }
 
-  /** @name EthereumHeader (464) */
+  /** @name EthereumHeader (463) */
   interface EthereumHeader extends Struct {
     readonly parentHash: H256;
     readonly ommersHash: H256;
@@ -3852,24 +3848,24 @@
     readonly nonce: EthereumTypesHashH64;
   }
 
-  /** @name EthereumTypesHashH64 (465) */
+  /** @name EthereumTypesHashH64 (464) */
   interface EthereumTypesHashH64 extends U8aFixed {}
 
-  /** @name PalletEthereumError (470) */
+  /** @name PalletEthereumError (469) */
   interface PalletEthereumError extends Enum {
     readonly isInvalidSignature: boolean;
     readonly isPreLogExists: boolean;
     readonly type: 'InvalidSignature' | 'PreLogExists';
   }
 
-  /** @name PalletEvmCoderSubstrateError (471) */
+  /** @name PalletEvmCoderSubstrateError (470) */
   interface PalletEvmCoderSubstrateError extends Enum {
     readonly isOutOfGas: boolean;
     readonly isOutOfFund: boolean;
     readonly type: 'OutOfGas' | 'OutOfFund';
   }
 
-  /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (472) */
+  /** @name UpDataStructsSponsorshipStateBasicCrossAccountIdRepr (471) */
   interface UpDataStructsSponsorshipStateBasicCrossAccountIdRepr extends Enum {
     readonly isDisabled: boolean;
     readonly isUnconfirmed: boolean;
@@ -3879,7 +3875,7 @@
     readonly type: 'Disabled' | 'Unconfirmed' | 'Confirmed';
   }
 
-  /** @name PalletEvmContractHelpersSponsoringModeT (473) */
+  /** @name PalletEvmContractHelpersSponsoringModeT (472) */
   interface PalletEvmContractHelpersSponsoringModeT extends Enum {
     readonly isDisabled: boolean;
     readonly isAllowlisted: boolean;
@@ -3887,7 +3883,7 @@
     readonly type: 'Disabled' | 'Allowlisted' | 'Generous';
   }
 
-  /** @name PalletEvmContractHelpersError (479) */
+  /** @name PalletEvmContractHelpersError (478) */
   interface PalletEvmContractHelpersError extends Enum {
     readonly isNoPermission: boolean;
     readonly isNoPendingSponsor: boolean;
@@ -3895,7 +3891,7 @@
     readonly type: 'NoPermission' | 'NoPendingSponsor' | 'TooManyMethodsHaveSponsoredLimit';
   }
 
-  /** @name PalletEvmMigrationError (480) */
+  /** @name PalletEvmMigrationError (479) */
   interface PalletEvmMigrationError extends Enum {
     readonly isAccountNotEmpty: boolean;
     readonly isAccountIsNotMigrating: boolean;
@@ -3903,17 +3899,17 @@
     readonly type: 'AccountNotEmpty' | 'AccountIsNotMigrating' | 'BadEvent';
   }
 
-  /** @name PalletMaintenanceError (481) */
+  /** @name PalletMaintenanceError (480) */
   type PalletMaintenanceError = Null;
 
-  /** @name PalletTestUtilsError (482) */
+  /** @name PalletTestUtilsError (481) */
   interface PalletTestUtilsError extends Enum {
     readonly isTestPalletDisabled: boolean;
     readonly isTriggerRollback: boolean;
     readonly type: 'TestPalletDisabled' | 'TriggerRollback';
   }
 
-  /** @name SpRuntimeMultiSignature (484) */
+  /** @name SpRuntimeMultiSignature (483) */
   interface SpRuntimeMultiSignature extends Enum {
     readonly isEd25519: boolean;
     readonly asEd25519: SpCoreEd25519Signature;
@@ -3924,40 +3920,40 @@
     readonly type: 'Ed25519' | 'Sr25519' | 'Ecdsa';
   }
 
-  /** @name SpCoreEd25519Signature (485) */
+  /** @name SpCoreEd25519Signature (484) */
   interface SpCoreEd25519Signature extends U8aFixed {}
 
-  /** @name SpCoreSr25519Signature (487) */
+  /** @name SpCoreSr25519Signature (486) */
   interface SpCoreSr25519Signature extends U8aFixed {}
 
-  /** @name SpCoreEcdsaSignature (488) */
+  /** @name SpCoreEcdsaSignature (487) */
   interface SpCoreEcdsaSignature extends U8aFixed {}
 
-  /** @name FrameSystemExtensionsCheckSpecVersion (491) */
+  /** @name FrameSystemExtensionsCheckSpecVersion (490) */
   type FrameSystemExtensionsCheckSpecVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckTxVersion (492) */
+  /** @name FrameSystemExtensionsCheckTxVersion (491) */
   type FrameSystemExtensionsCheckTxVersion = Null;
 
-  /** @name FrameSystemExtensionsCheckGenesis (493) */
+  /** @name FrameSystemExtensionsCheckGenesis (492) */
   type FrameSystemExtensionsCheckGenesis = Null;
 
-  /** @name FrameSystemExtensionsCheckNonce (496) */
+  /** @name FrameSystemExtensionsCheckNonce (495) */
   interface FrameSystemExtensionsCheckNonce extends Compact<u32> {}
 
-  /** @name FrameSystemExtensionsCheckWeight (497) */
+  /** @name FrameSystemExtensionsCheckWeight (496) */
   type FrameSystemExtensionsCheckWeight = Null;
 
-  /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (498) */
+  /** @name OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance (497) */
   type OpalRuntimeRuntimeCommonMaintenanceCheckMaintenance = Null;
 
-  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (499) */
+  /** @name PalletTemplateTransactionPaymentChargeTransactionPayment (498) */
   interface PalletTemplateTransactionPaymentChargeTransactionPayment extends Compact<u128> {}
 
-  /** @name OpalRuntimeRuntime (500) */
+  /** @name OpalRuntimeRuntime (499) */
   type OpalRuntimeRuntime = Null;
 
-  /** @name PalletEthereumFakeTransactionFinalizer (501) */
+  /** @name PalletEthereumFakeTransactionFinalizer (500) */
   type PalletEthereumFakeTransactionFinalizer = Null;
 
 } // declare module
modifiedtests/src/removeCollectionAdmin.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionAdmin.test.ts
+++ b/tests/src/removeCollectionAdmin.test.ts
@@ -51,7 +51,7 @@
     const adminListBeforeAddAdmin = await collection.getAdmins();
     expect(adminListBeforeAddAdmin).to.have.lengthOf(0);
 
-    await expect(collection.removeAdmin(alice, {Substrate: alice.address})).to.be.rejectedWith('common.UserIsNotAdmin');
+    await expect(collection.removeAdmin(alice, {Substrate: alice.address})).to.be.rejectedWith('common.UserIsNotCollectionAdmin');
   });
 });
 
modifiedtests/src/removeCollectionSponsor.test.tsdiffbeforeafterboth
--- a/tests/src/removeCollectionSponsor.test.ts
+++ b/tests/src/removeCollectionSponsor.test.ts
@@ -21,11 +21,12 @@
   let donor: IKeyringPair;
   let alice: IKeyringPair;
   let bob: IKeyringPair;
+  let charlie: IKeyringPair;
 
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       donor = await privateKey({filename: __filename});
-      [alice, bob] = await helper.arrange.createAccounts([10n, 10n], donor);
+      [alice, bob, charlie] = await helper.arrange.createAccounts([20n, 10n, 10n], donor);
     });
   });
 
@@ -69,6 +70,12 @@
     await expect(collection.removeSponsor(alice)).to.not.be.rejected;
   });
 
+  itSub('Remove sponsor for a collection with collection admin permissions', async ({helper}) => {
+    const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'});
+    await collection.setSponsor(alice, bob.address);
+    await collection.addAdmin(alice, {Substrate: charlie.address});
+    await expect(collection.removeSponsor(charlie)).not.to.be.rejected;
+  });
 });
 
 describe('(!negative test!) integration test: ext. removeCollectionSponsor():', () => {
@@ -86,13 +93,6 @@
   itSub('(!negative test!) Remove sponsor for a collection that never existed', async ({helper}) => {
     const collectionId = (1 << 32) - 1;
     await expect(helper.collection.removeSponsor(alice, collectionId)).to.be.rejectedWith(/common\.CollectionNotFound/);
-  });
-
-  itSub('(!negative test!) Remove sponsor for a collection with collection admin permissions', async ({helper}) => {
-    const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-1', tokenPrefix: 'RCS'});
-    await collection.setSponsor(alice, bob.address);
-    await collection.addAdmin(alice, {Substrate: charlie.address});
-    await expect(collection.removeSponsor(charlie)).to.be.rejectedWith(/common\.NoPermission/);
   });
 
   itSub('(!negative test!) Remove sponsor for a collection by regular user', async ({helper}) => {
@@ -112,7 +112,7 @@
     const collection = await helper.nft.mintCollection(alice, {name: 'RemoveCollectionSponsor-Neg-4', tokenPrefix: 'RCS'});
     await collection.setSponsor(alice, bob.address);
     await collection.removeSponsor(alice);
-    await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 
   itSub('Set - confirm - remove - confirm: Sponsor cannot come back', async ({helper}) => {
@@ -120,6 +120,6 @@
     await collection.setSponsor(alice, bob.address);
     await collection.confirmSponsorship(bob);
     await collection.removeSponsor(alice);
-    await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmUnsetSponsorFail/);
+    await expect(collection.confirmSponsorship(bob)).to.be.rejectedWith(/common\.ConfirmSponsorshipFail/);
   });
 });
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
before · tests/src/util/playgrounds/unique.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15  IApiListeners,16  IBlock,17  IEvent,18  IChainProperties,19  ICollectionCreationOptions,20  ICollectionLimits,21  ICollectionPermissions,22  ICrossAccountId,23  ICrossAccountIdLower,24  ILogger,25  INestingPermissions,26  IProperty,27  IStakingInfo,28  ISchedulerOptions,29  ISubstrateBalance,30  IToken,31  ITokenPropertyPermission,32  ITransactionResult,33  IUniqueHelperLog,34  TApiAllowedListeners,35  TEthereumAccount,36  TSigner,37  TSubstrateAccount,38  TNetworks,39  IForeignAssetMetadata,40  AcalaAssetMetadata,41  MoonbeamAssetInfo,42  DemocracyStandardAccountVote,43  IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';46import type {Vec} from '@polkadot/types-codec';47import {FrameSystemEventRecord} from '@polkadot/types/lookup';4849export class CrossAccountId implements ICrossAccountId {50  Substrate?: TSubstrateAccount;51  Ethereum?: TEthereumAccount;5253  constructor(account: ICrossAccountId) {54    if (account.Substrate) this.Substrate = account.Substrate;55    if (account.Ethereum) this.Ethereum = account.Ethereum;56  }5758  static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {59    switch (domain) {60      case 'Substrate': return new CrossAccountId({Substrate: account.address});61      case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();62    }63  }6465  static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {66    return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});67  }6869  static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {70    return encodeAddress(decodeAddress(address), ss58Format);71  }7273  static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {74    return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});75  }7677  withNormalizedSubstrate(ss58Format = 42): CrossAccountId {78    if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);79    return this;80  }8182  static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {83    return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));84  }8586  toEthereum(): CrossAccountId {87    if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});88    return this;89  }9091  static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92    return evmToAddress(address, ss58Format);93  }9495  toSubstrate(ss58Format?: number): CrossAccountId {96    if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});97    return this;98  }99100  toLowerCase(): CrossAccountId {101    if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();102    if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();103    return this;104  }105}106107const nesting = {108  toChecksumAddress(address: string): string {109    if (typeof address === 'undefined') return '';110111    if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);112113    address = address.toLowerCase().replace(/^0x/i,'');114    const addressHash = keccakAsHex(address).replace(/^0x/i,'');115    const checksumAddress = ['0x'];116117    for (let i = 0; i < address.length; i++) {118      // If ith character is 8 to f then make it uppercase119      if (parseInt(addressHash[i], 16) > 7) {120        checksumAddress.push(address[i].toUpperCase());121      } else {122        checksumAddress.push(address[i]);123      }124    }125    return checksumAddress.join('');126  },127  tokenIdToAddress(collectionId: number, tokenId: number) {128    return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);129  },130};131132class UniqueUtil {133  static transactionStatus = {134    NOT_READY: 'NotReady',135    FAIL: 'Fail',136    SUCCESS: 'Success',137  };138139  static chainLogType = {140    EXTRINSIC: 'extrinsic',141    RPC: 'rpc',142  };143144  static getTokenAccount(token: IToken): CrossAccountId {145    return new CrossAccountId({Ethereum: this.getTokenAddress(token)});146  }147148  static getTokenAddress(token: IToken): string {149    return nesting.tokenIdToAddress(token.collectionId, token.tokenId);150  }151152  static getDefaultLogger(): ILogger {153    return {154      log(msg: any, level = 'INFO') {155        console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));156      },157      level: {158        ERROR: 'ERROR',159        WARNING: 'WARNING',160        INFO: 'INFO',161      },162    };163  }164165  static vec2str(arr: string[] | number[]) {166    return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');167  }168169  static str2vec(string: string) {170    if (typeof string !== 'string') return string;171    return Array.from(string).map(x => x.charCodeAt(0));172  }173174  static fromSeed(seed: string, ss58Format = 42) {175    const keyring = new Keyring({type: 'sr25519', ss58Format});176    return keyring.addFromUri(seed);177  }178179  static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {180    if (creationResult.status !== this.transactionStatus.SUCCESS) {181      throw Error('Unable to create collection!');182    }183184    let collectionId = null;185    creationResult.result.events.forEach(({event: {data, method, section}}) => {186      if ((section === 'common') && (method === 'CollectionCreated')) {187        collectionId = parseInt(data[0].toString(), 10);188      }189    });190191    if (collectionId === null) {192      throw Error('No CollectionCreated event was found!');193    }194195    return collectionId;196  }197198  static extractTokensFromCreationResult(creationResult: ITransactionResult): {199    success: boolean,200    tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],201  } {202    if (creationResult.status !== this.transactionStatus.SUCCESS) {203      throw Error('Unable to create tokens!');204    }205    let success = false;206    const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];207    creationResult.result.events.forEach(({event: {data, method, section}}) => {208      if (method === 'ExtrinsicSuccess') {209        success = true;210      } else if ((section === 'common') && (method === 'ItemCreated')) {211        tokens.push({212          collectionId: parseInt(data[0].toString(), 10),213          tokenId: parseInt(data[1].toString(), 10),214          owner: data[2].toHuman(),215          amount: data[3].toBigInt(),216        });217      }218    });219    return {success, tokens};220  }221222  static extractTokensFromBurnResult(burnResult: ITransactionResult): {223    success: boolean,224    tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],225  } {226    if (burnResult.status !== this.transactionStatus.SUCCESS) {227      throw Error('Unable to burn tokens!');228    }229    let success = false;230    const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];231    burnResult.result.events.forEach(({event: {data, method, section}}) => {232      if (method === 'ExtrinsicSuccess') {233        success = true;234      } else if ((section === 'common') && (method === 'ItemDestroyed')) {235        tokens.push({236          collectionId: parseInt(data[0].toString(), 10),237          tokenId: parseInt(data[1].toString(), 10),238          owner: data[2].toHuman(),239          amount: data[3].toBigInt(),240        });241      }242    });243    return {success, tokens};244  }245246  static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {247    let eventId = null;248    events.forEach(({event: {data, method, section}}) => {249      if ((section === expectedSection) && (method === expectedMethod)) {250        eventId = parseInt(data[0].toString(), 10);251      }252    });253254    if (eventId === null) {255      throw Error(`No ${expectedMethod} event was found!`);256    }257    return eventId === collectionId;258  }259260  static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {261    const normalizeAddress = (address: string | ICrossAccountId) => {262      if(typeof address === 'string') return address;263      const obj = {} as any;264      Object.keys(address).forEach(k => {265        obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];266      });267      if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);268      if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();269      return address;270    };271    let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;272    events.forEach(({event: {data, method, section}}) => {273      if ((section === 'common') && (method === 'Transfer')) {274        const hData = (data as any).toJSON();275        transfer = {276          collectionId: hData[0],277          tokenId: hData[1],278          from: normalizeAddress(hData[2]),279          to: normalizeAddress(hData[3]),280          amount: BigInt(hData[4]),281        };282      }283    });284    let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;285    isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);286    isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);287    isSuccess = isSuccess && amount === transfer.amount;288    return isSuccess;289  }290291  static bigIntToDecimals(number: bigint, decimals = 18) {292    const numberStr = number.toString();293    const dotPos = numberStr.length - decimals;294295    if (dotPos <= 0) {296      return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;297    } else {298      const intPart = numberStr.substring(0, dotPos);299      const fractPart = numberStr.substring(dotPos);300      return intPart + '.' + fractPart;301    }302  }303}304305class UniqueEventHelper {306  private static extractIndex(index: any): [number, number] | string {307    if(index.toRawType() === '[u8;2]') return [index[0], index[1]];308    return index.toJSON();309  }310311  private static extractSub(data: any, subTypes: any): {[key: string]: any} {312    let obj: any = {};313    let index = 0;314315    if (data.entries) {316      for(const [key, value] of data.entries()) {317        obj[key] = this.extractData(value, subTypes[index]);318        index++;319      }320    } else obj = data.toJSON();321322    return obj;323  }324325  private static extractData(data: any, type: any): any {326    if(!type) return data.toHuman();327    if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();328    if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();329    if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);330    return data.toHuman();331  }332333  public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {334    const parsedEvents: IEvent[] = [];335336    events.forEach((record) => {337      const {event, phase} = record;338      const types = event.typeDef;339340      const eventData: IEvent = {341        section: event.section.toString(),342        method: event.method.toString(),343        index: this.extractIndex(event.index),344        data: [],345        phase: phase.toJSON(),346      };347348      event.data.forEach((val: any, index: number) => {349        eventData.data.push(this.extractData(val, types[index]));350      });351352      parsedEvents.push(eventData);353    });354355    return parsedEvents;356  }357}358359export class ChainHelperBase {360  helperBase: any;361362  transactionStatus = UniqueUtil.transactionStatus;363  chainLogType = UniqueUtil.chainLogType;364  util: typeof UniqueUtil;365  eventHelper: typeof UniqueEventHelper;366  logger: ILogger;367  api: ApiPromise | null;368  forcedNetwork: TNetworks | null;369  network: TNetworks | null;370  chainLog: IUniqueHelperLog[];371  children: ChainHelperBase[];372  address: AddressGroup;373  chain: ChainGroup;374375  constructor(logger?: ILogger, helperBase?: any) {376    this.helperBase = helperBase;377378    this.util = UniqueUtil;379    this.eventHelper = UniqueEventHelper;380    if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();381    this.logger = logger;382    this.api = null;383    this.forcedNetwork = null;384    this.network = null;385    this.chainLog = [];386    this.children = [];387    this.address = new AddressGroup(this);388    this.chain = new ChainGroup(this);389  }390391  clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {392    Object.setPrototypeOf(helperCls.prototype, this);393    const newHelper = new helperCls(this.logger, options);394395    newHelper.api = this.api;396    newHelper.network = this.network;397    newHelper.forceNetwork = this.forceNetwork;398399    this.children.push(newHelper);400401    return newHelper;402  }403404  getApi(): ApiPromise {405    if(this.api === null) throw Error('API not initialized');406    return this.api;407  }408409  async subscribeEvents(expectedEvents: {section: string, names: string[]}[]) {410    const collectedEvents: IEvent[] = [];411    const unsubscribe = await this.getApi().query.system.events((events: Vec<FrameSystemEventRecord>) => {412      const ievents = this.eventHelper.extractEvents(events);413      ievents.forEach((event) => {414        expectedEvents.forEach((e => {415          if (event.section === e.section && e.names.includes(event.method)) {416            collectedEvents.push(event);417          }418        }));419      });420    });421    return {unsubscribe: unsubscribe as any, collectedEvents};422  }423424  clearChainLog(): void {425    this.chainLog = [];426  }427428  forceNetwork(value: TNetworks): void {429    this.forcedNetwork = value;430  }431432  async connect(wsEndpoint: string, listeners?: IApiListeners) {433    if (this.api !== null) throw Error('Already connected');434    const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);435    this.api = api;436    this.network = network;437  }438439  async disconnect() {440    for (const child of this.children) {441      child.clearApi();442    }443444    if (this.api === null) return;445    await this.api.disconnect();446    this.clearApi();447  }448449  clearApi() {450    this.api = null;451    this.network = null;452  }453454  static async detectNetwork(api: ApiPromise): Promise<TNetworks> {455    const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;456    const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];457458    if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;459460    if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;461    return 'opal';462  }463464  static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {465    const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});466    await api.isReady;467468    const network = await this.detectNetwork(api);469470    await api.disconnect();471472    return network;473  }474475  static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{476    api: ApiPromise;477    network: TNetworks;478  }> {479    if(typeof network === 'undefined' || network === null) network = 'opal';480    const supportedRPC = {481      opal: {482        unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,483      },484      quartz: {485        unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,486      },487      unique: {488        unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,489      },490      rococo: {},491      westend: {},492      moonbeam: {},493      moonriver: {},494      acala: {},495      karura: {},496      westmint: {},497    };498    if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);499    const rpc = supportedRPC[network];500501    // TODO: investigate how to replace rpc in runtime502    // api._rpcCore.addUserInterfaces(rpc);503504    const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});505506    await api.isReadyOrError;507508    if (typeof listeners === 'undefined') listeners = {};509    for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {510      if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;511      api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);512    }513514    return {api, network};515  }516517  getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {518    const {events, status} = data;519    if (status.isReady) {520      return this.transactionStatus.NOT_READY;521    }522    if (status.isBroadcast) {523      return this.transactionStatus.NOT_READY;524    }525    if (status.isInBlock || status.isFinalized) {526      const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');527      if (errors.length > 0) {528        return this.transactionStatus.FAIL;529      }530      if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {531        return this.transactionStatus.SUCCESS;532      }533    }534535    return this.transactionStatus.FAIL;536  }537538  signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {539    const sign = (callback: any) => {540      if(options !== null) return transaction.signAndSend(sender, options, callback);541      return transaction.signAndSend(sender, callback);542    };543    // eslint-disable-next-line no-async-promise-executor544    return new Promise(async (resolve, reject) => {545      try {546        const unsub = await sign((result: any) => {547          const status = this.getTransactionStatus(result);548549          if (status === this.transactionStatus.SUCCESS) {550            this.logger.log(`${label} successful`);551            unsub();552            resolve({result, status});553          } else if (status === this.transactionStatus.FAIL) {554            let moduleError = null;555556            if (result.hasOwnProperty('dispatchError')) {557              const dispatchError = result['dispatchError'];558559              if (dispatchError) {560                if (dispatchError.isModule) {561                  const modErr = dispatchError.asModule;562                  const errorMeta = dispatchError.registry.findMetaError(modErr);563564                  moduleError = `${errorMeta.section}.${errorMeta.name}`;565                } else {566                  moduleError = dispatchError.toHuman();567                }568              } else {569                this.logger.log(result, this.logger.level.ERROR);570              }571            }572573            this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);574            unsub();575            reject({status, moduleError, result});576          }577        });578      } catch (e) {579        this.logger.log(e, this.logger.level.ERROR);580        reject(e);581      }582    });583  }584585  async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {586    const api = this.getApi();587    const signingInfo = await api.derive.tx.signingInfo(signer.address);588589    // We need to sign the tx because590    // unsigned transactions does not have an inclusion fee591    tx.sign(signer, {592      blockHash: api.genesisHash,593      genesisHash: api.genesisHash,594      runtimeVersion: api.runtimeVersion,595      nonce: signingInfo.nonce,596    });597598    if (len === null) {599      return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;600    } else {601      return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;602    }603  }604605  constructApiCall(apiCall: string, params: any[]) {606    if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);607    let call = this.getApi() as any;608    for(const part of apiCall.slice(4).split('.')) {609      call = call[part];610    }611    return call(...params);612  }613614  async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {615    if(this.api === null) throw Error('API not initialized');616    if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);617618    const startTime = (new Date()).getTime();619    let result: ITransactionResult;620    let events: IEvent[] = [];621    try {622      result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;623      events = this.eventHelper.extractEvents(result.result.events);624    }625    catch(e) {626      if(!(e as object).hasOwnProperty('status')) throw e;627      result = e as ITransactionResult;628    }629630    const endTime = (new Date()).getTime();631632    const log = {633      executedAt: endTime,634      executionTime: endTime - startTime,635      type: this.chainLogType.EXTRINSIC,636      status: result.status,637      call: extrinsic,638      signer: this.getSignerAddress(sender),639      params,640    } as IUniqueHelperLog;641642    if(result.status !== this.transactionStatus.SUCCESS) {643      if (result.moduleError) log.moduleError = result.moduleError;644      else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;645    }646    if(events.length > 0) log.events = events;647648    this.chainLog.push(log);649650    if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {651      if (result.moduleError) throw Error(`${result.moduleError}`);652      else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));653    }654    return result;655  }656657  async callRpc(rpc: string, params?: any[]) {658    if(typeof params === 'undefined') params = [];659    if(this.api === null) throw Error('API not initialized');660    if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);661662    const startTime = (new Date()).getTime();663    let result;664    let error = null;665    const log = {666      type: this.chainLogType.RPC,667      call: rpc,668      params,669    } as IUniqueHelperLog;670671    try {672      result = await this.constructApiCall(rpc, params);673    }674    catch(e) {675      error = e;676    }677678    const endTime = (new Date()).getTime();679680    log.executedAt = endTime;681    log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';682    log.executionTime = endTime - startTime;683684    this.chainLog.push(log);685686    if(error !== null) throw error;687688    return result;689  }690691  getSignerAddress(signer: IKeyringPair | string): string {692    if(typeof signer === 'string') return signer;693    return signer.address;694  }695696  fetchAllPalletNames(): string[] {697    if(this.api === null) throw Error('API not initialized');698    return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());699  }700701  fetchMissingPalletNames(requiredPallets: string[]): string[] {702    const palletNames = this.fetchAllPalletNames();703    return requiredPallets.filter(p => !palletNames.includes(p));704  }705}706707708class HelperGroup<T extends ChainHelperBase> {709  helper: T;710711  constructor(uniqueHelper: T) {712    this.helper = uniqueHelper;713  }714}715716717class CollectionGroup extends HelperGroup<UniqueHelper> {718  /**719 * Get number of blocks when sponsored transaction is available.720 *721 * @param collectionId ID of collection722 * @param tokenId ID of token723 * @param addressObj address for which the sponsorship is checked724 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});725 * @returns number of blocks or null if sponsorship hasn't been set726 */727  async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {728    return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();729  }730731  /**732   * Get the number of created collections.733   *734   * @returns number of created collections735   */736  async getTotalCount(): Promise<number> {737    return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();738  }739740  /**741   * Get information about the collection with additional data,742   * including the number of tokens it contains, its administrators,743   * the normalized address of the collection's owner, and decoded name and description.744   *745   * @param collectionId ID of collection746   * @example await getData(2)747   * @returns collection information object748   */749  async getData(collectionId: number): Promise<{750    id: number;751    name: string;752    description: string;753    tokensCount: number;754    admins: CrossAccountId[];755    normalizedOwner: TSubstrateAccount;756    raw: any757  } | null> {758    const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);759    const humanCollection = collection.toHuman(), collectionData = {760      id: collectionId, name: null, description: null, tokensCount: 0, admins: [],761      raw: humanCollection,762    } as any, jsonCollection = collection.toJSON();763    if (humanCollection === null) return null;764    collectionData.raw.limits = jsonCollection.limits;765    collectionData.raw.permissions = jsonCollection.permissions;766    collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);767    for (const key of ['name', 'description']) {768      collectionData[key] = this.helper.util.vec2str(humanCollection[key]);769    }770771    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))772      ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)773      : 0;774    collectionData.admins = await this.getAdmins(collectionId);775776    return collectionData;777  }778779  /**780   * Get the addresses of the collection's administrators, optionally normalized.781   *782   * @param collectionId ID of collection783   * @param normalize whether to normalize the addresses to the default ss58 format784   * @example await getAdmins(1)785   * @returns array of administrators786   */787  async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {788    const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();789790    return normalize791      ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())792      : admins;793  }794795  /**796   * Get the addresses added to the collection allow-list, optionally normalized.797   * @param collectionId ID of collection798   * @param normalize whether to normalize the addresses to the default ss58 format799   * @example await getAllowList(1)800   * @returns array of allow-listed addresses801   */802  async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {803    const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();804    return normalize805      ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())806      : allowListed;807  }808809  /**810   * Get the effective limits of the collection instead of null for default values811   *812   * @param collectionId ID of collection813   * @example await getEffectiveLimits(2)814   * @returns object of collection limits815   */816  async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {817    return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();818  }819820  /**821   * Burns the collection if the signer has sufficient permissions and collection is empty.822   *823   * @param signer keyring of signer824   * @param collectionId ID of collection825   * @example await helper.collection.burn(aliceKeyring, 3);826   * @returns ```true``` if extrinsic success, otherwise ```false```827   */828  async burn(signer: TSigner, collectionId: number): Promise<boolean> {829    const result = await this.helper.executeExtrinsic(830      signer,831      'api.tx.unique.destroyCollection', [collectionId],832      true,833    );834835    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');836  }837838  /**839   * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.840   *841   * @param signer keyring of signer842   * @param collectionId ID of collection843   * @param sponsorAddress Sponsor substrate address844   * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")845   * @returns ```true``` if extrinsic success, otherwise ```false```846   */847  async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {848    const result = await this.helper.executeExtrinsic(849      signer,850      'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],851      true,852    );853854    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');855  }856857  /**858   * Confirms consent to sponsor the collection on behalf of the signer.859   *860   * @param signer keyring of signer861   * @param collectionId ID of collection862   * @example confirmSponsorship(aliceKeyring, 10)863   * @returns ```true``` if extrinsic success, otherwise ```false```864   */865  async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {866    const result = await this.helper.executeExtrinsic(867      signer,868      'api.tx.unique.confirmSponsorship', [collectionId],869      true,870    );871872    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');873  }874875  /**876   * Removes the sponsor of a collection, regardless if it consented or not.877   *878   * @param signer keyring of signer879   * @param collectionId ID of collection880   * @example removeSponsor(aliceKeyring, 10)881   * @returns ```true``` if extrinsic success, otherwise ```false```882   */883  async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {884    const result = await this.helper.executeExtrinsic(885      signer,886      'api.tx.unique.removeCollectionSponsor', [collectionId],887      true,888    );889890    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');891  }892893  /**894   * Sets the limits of the collection. At least one limit must be specified for a correct call.895   *896   * @param signer keyring of signer897   * @param collectionId ID of collection898   * @param limits collection limits object899   * @example900   * await setLimits(901   *   aliceKeyring,902   *   10,903   *   {904   *     sponsorTransferTimeout: 0,905   *     ownerCanDestroy: false906   *   }907   * )908   * @returns ```true``` if extrinsic success, otherwise ```false```909   */910  async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {911    const result = await this.helper.executeExtrinsic(912      signer,913      'api.tx.unique.setCollectionLimits', [collectionId, limits],914      true,915    );916917    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');918  }919920  /**921   * Changes the owner of the collection to the new Substrate address.922   *923   * @param signer keyring of signer924   * @param collectionId ID of collection925   * @param ownerAddress substrate address of new owner926   * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")927   * @returns ```true``` if extrinsic success, otherwise ```false```928   */929  async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {930    const result = await this.helper.executeExtrinsic(931      signer,932      'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],933      true,934    );935936    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnedChanged');937  }938939  /**940   * Adds a collection administrator.941   *942   * @param signer keyring of signer943   * @param collectionId ID of collection944   * @param adminAddressObj Administrator address (substrate or ethereum)945   * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})946   * @returns ```true``` if extrinsic success, otherwise ```false```947   */948  async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {949    const result = await this.helper.executeExtrinsic(950      signer,951      'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],952      true,953    );954955    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');956  }957958  /**959   * Removes a collection administrator.960   *961   * @param signer keyring of signer962   * @param collectionId ID of collection963   * @param adminAddressObj Administrator address (substrate or ethereum)964   * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})965   * @returns ```true``` if extrinsic success, otherwise ```false```966   */967  async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {968    const result = await this.helper.executeExtrinsic(969      signer,970      'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],971      true,972    );973974    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');975  }976977  /**978   * Check if user is in allow list.979   *980   * @param collectionId ID of collection981   * @param user Account to check982   * @example await getAdmins(1)983   * @returns is user in allow list984   */985  async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {986    return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();987  }988989  /**990   * Adds an address to allow list991   * @param signer keyring of signer992   * @param collectionId ID of collection993   * @param addressObj address to add to the allow list994   * @returns ```true``` if extrinsic success, otherwise ```false```995   */996  async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {997    const result = await this.helper.executeExtrinsic(998      signer,999      'api.tx.unique.addToAllowList', [collectionId, addressObj],1000      true,1001    );10021003    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1004  }10051006  /**1007   * Removes an address from allow list1008   *1009   * @param signer keyring of signer1010   * @param collectionId ID of collection1011   * @param addressObj address to remove from the allow list1012   * @returns ```true``` if extrinsic success, otherwise ```false```1013   */1014  async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1015    const result = await this.helper.executeExtrinsic(1016      signer,1017      'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1018      true,1019    );10201021    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1022  }10231024  /**1025   * Sets onchain permissions for selected collection.1026   *1027   * @param signer keyring of signer1028   * @param collectionId ID of collection1029   * @param permissions collection permissions object1030   * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1031   * @returns ```true``` if extrinsic success, otherwise ```false```1032   */1033  async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1034    const result = await this.helper.executeExtrinsic(1035      signer,1036      'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1037      true,1038    );10391040    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1041  }10421043  /**1044   * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1045   *1046   * @param signer keyring of signer1047   * @param collectionId ID of collection1048   * @param permissions nesting permissions object1049   * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1050   * @returns ```true``` if extrinsic success, otherwise ```false```1051   */1052  async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1053    return await this.setPermissions(signer, collectionId, {nesting: permissions});1054  }10551056  /**1057   * Disables nesting for selected collection.1058   *1059   * @param signer keyring of signer1060   * @param collectionId ID of collection1061   * @example disableNesting(aliceKeyring, 10);1062   * @returns ```true``` if extrinsic success, otherwise ```false```1063   */1064  async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1065    return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1066  }10671068  /**1069   * Sets onchain properties to the collection.1070   *1071   * @param signer keyring of signer1072   * @param collectionId ID of collection1073   * @param properties array of property objects1074   * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1075   * @returns ```true``` if extrinsic success, otherwise ```false```1076   */1077  async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1078    const result = await this.helper.executeExtrinsic(1079      signer,1080      'api.tx.unique.setCollectionProperties', [collectionId, properties],1081      true,1082    );10831084    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1085  }10861087  /**1088   * Get collection properties.1089   *1090   * @param collectionId ID of collection1091   * @param propertyKeys optionally filter the returned properties to only these keys1092   * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1093   * @returns array of key-value pairs1094   */1095  async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1096    return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1097  }10981099  async getCollectionOptions(collectionId: number) {1100    return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1101  }11021103  /**1104   * Deletes onchain properties from the collection.1105   *1106   * @param signer keyring of signer1107   * @param collectionId ID of collection1108   * @param propertyKeys array of property keys to delete1109   * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1110   * @returns ```true``` if extrinsic success, otherwise ```false```1111   */1112  async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1113    const result = await this.helper.executeExtrinsic(1114      signer,1115      'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1116      true,1117    );11181119    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1120  }11211122  /**1123   * Changes the owner of the token.1124   *1125   * @param signer keyring of signer1126   * @param collectionId ID of collection1127   * @param tokenId ID of token1128   * @param addressObj address of a new owner1129   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1130   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1131   * @returns true if the token success, otherwise false1132   */1133  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1134    const result = await this.helper.executeExtrinsic(1135      signer,1136      'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1137      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1138    );11391140    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1141  }11421143  /**1144   *1145   * Change ownership of a token(s) on behalf of the owner.1146   *1147   * @param signer keyring of signer1148   * @param collectionId ID of collection1149   * @param tokenId ID of token1150   * @param fromAddressObj address on behalf of which the token will be sent1151   * @param toAddressObj new token owner1152   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1153   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1154   * @returns true if the token success, otherwise false1155   */1156  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1157    const result = await this.helper.executeExtrinsic(1158      signer,1159      'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1160      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1161    );1162    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1163  }11641165  /**1166   *1167   * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1168   *1169   * @param signer keyring of signer1170   * @param collectionId ID of collection1171   * @param tokenId ID of token1172   * @param amount amount of tokens to be burned. For NFT must be set to 1n1173   * @example burnToken(aliceKeyring, 10, 5);1174   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1175   */1176  async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1177    const burnResult = await this.helper.executeExtrinsic(1178      signer,1179      'api.tx.unique.burnItem', [collectionId, tokenId, amount],1180      true, // `Unable to burn token for ${label}`,1181    );1182    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1183    if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1184    return burnedTokens.success;1185  }11861187  /**1188   * Destroys a concrete instance of NFT on behalf of the owner1189   *1190   * @param signer keyring of signer1191   * @param collectionId ID of collection1192   * @param tokenId ID of token1193   * @param fromAddressObj address on behalf of which the token will be burnt1194   * @param amount amount of tokens to be burned. For NFT must be set to 1n1195   * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1196   * @returns ```true``` if extrinsic success, otherwise ```false```1197   */1198  async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1199    const burnResult = await this.helper.executeExtrinsic(1200      signer,1201      'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1202      true, // `Unable to burn token from for ${label}`,1203    );1204    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1205    return burnedTokens.success && burnedTokens.tokens.length > 0;1206  }12071208  /**1209   * Set, change, or remove approved address to transfer the ownership of the NFT.1210   *1211   * @param signer keyring of signer1212   * @param collectionId ID of collection1213   * @param tokenId ID of token1214   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1215   * @param amount amount of token to be approved. For NFT must be set to 1n1216   * @returns ```true``` if extrinsic success, otherwise ```false```1217   */1218  async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1219    const approveResult = await this.helper.executeExtrinsic(1220      signer,1221      'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1222      true, // `Unable to approve token for ${label}`,1223    );12241225    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1226  }12271228  /**1229   * Get the amount of token pieces approved to transfer or burn. Normally 0.1230   *1231   * @param collectionId ID of collection1232   * @param tokenId ID of token1233   * @param toAccountObj address which is approved to use token pieces1234   * @param fromAccountObj address which may have allowed the use of its owned tokens1235   * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1236   * @returns number of approved to transfer pieces1237   */1238  async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1239    return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1240  }12411242  /**1243   * Get the last created token ID in a collection1244   *1245   * @param collectionId ID of collection1246   * @example getLastTokenId(10);1247   * @returns id of the last created token1248   */1249  async getLastTokenId(collectionId: number): Promise<number> {1250    return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1251  }12521253  /**1254   * Check if token exists1255   *1256   * @param collectionId ID of collection1257   * @param tokenId ID of token1258   * @example doesTokenExist(10, 20);1259   * @returns true if the token exists, otherwise false1260   */1261  async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1262    return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1263  }1264}12651266class NFTnRFT extends CollectionGroup {1267  /**1268   * Get tokens owned by account1269   *1270   * @param collectionId ID of collection1271   * @param addressObj tokens owner1272   * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1273   * @returns array of token ids owned by account1274   */1275  async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1276    return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1277  }12781279  /**1280   * Get token data1281   *1282   * @param collectionId ID of collection1283   * @param tokenId ID of token1284   * @param propertyKeys optionally filter the token properties to only these keys1285   * @param blockHashAt optionally query the data at some block with this hash1286   * @example getToken(10, 5);1287   * @returns human readable token data1288   */1289  async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1290    properties: IProperty[];1291    owner: CrossAccountId;1292    normalizedOwner: CrossAccountId;1293  }| null> {1294    let tokenData;1295    if(typeof blockHashAt === 'undefined') {1296      tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1297    }1298    else {1299      if(propertyKeys.length == 0) {1300        const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1301        if(!collection) return null;1302        propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1303      }1304      tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1305    }1306    tokenData = tokenData.toHuman();1307    if (tokenData === null || tokenData.owner === null) return null;1308    const owner = {} as any;1309    for (const key of Object.keys(tokenData.owner)) {1310      owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1311        ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1312        : tokenData.owner[key];1313    }1314    tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1315    return tokenData;1316  }13171318  /**1319   * Set permissions to change token properties1320   *1321   * @param signer keyring of signer1322   * @param collectionId ID of collection1323   * @param permissions permissions to change a property by the collection admin or token owner1324   * @example setTokenPropertyPermissions(1325   *   aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1326   * )1327   * @returns true if extrinsic success otherwise false1328   */1329  async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1330    const result = await this.helper.executeExtrinsic(1331      signer,1332      'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1333      true,1334    );13351336    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1337  }13381339  /**1340   * Get token property permissions.1341   *1342   * @param collectionId ID of collection1343   * @param propertyKeys optionally filter the returned property permissions to only these keys1344   * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1345   * @returns array of key-permission pairs1346   */1347  async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1348    return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1349  }13501351  /**1352   * Set token properties1353   *1354   * @param signer keyring of signer1355   * @param collectionId ID of collection1356   * @param tokenId ID of token1357   * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1358   * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1359   * @returns ```true``` if extrinsic success, otherwise ```false```1360   */1361  async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1362    const result = await this.helper.executeExtrinsic(1363      signer,1364      'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1365      true,1366    );13671368    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1369  }13701371  /**1372   * Get properties, metadata assigned to a token.1373   *1374   * @param collectionId ID of collection1375   * @param tokenId ID of token1376   * @param propertyKeys optionally filter the returned properties to only these keys1377   * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1378   * @returns array of key-value pairs1379   */1380  async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1381    return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1382  }13831384  /**1385   * Delete the provided properties of a token1386   * @param signer keyring of signer1387   * @param collectionId ID of collection1388   * @param tokenId ID of token1389   * @param propertyKeys property keys to be deleted1390   * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1391   * @returns ```true``` if extrinsic success, otherwise ```false```1392   */1393  async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1394    const result = await this.helper.executeExtrinsic(1395      signer,1396      'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1397      true,1398    );13991400    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1401  }14021403  /**1404   * Mint new collection1405   *1406   * @param signer keyring of signer1407   * @param collectionOptions basic collection options and properties1408   * @param mode NFT or RFT type of a collection1409   * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1410   * @returns object of the created collection1411   */1412  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1413    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1414    collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1415    for (const key of ['name', 'description', 'tokenPrefix']) {1416      if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1417    }1418    const creationResult = await this.helper.executeExtrinsic(1419      signer,1420      'api.tx.unique.createCollectionEx', [collectionOptions],1421      true, // errorLabel,1422    );1423    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1424  }14251426  getCollectionObject(_collectionId: number): any {1427    return null;1428  }14291430  getTokenObject(_collectionId: number, _tokenId: number): any {1431    return null;1432  }14331434  /**1435   * Tells whether the given `owner` approves the `operator`.1436   * @param collectionId ID of collection1437   * @param owner owner address1438   * @param operator operator addrees1439   * @returns true if operator is enabled1440   */1441  async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1442    return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1443  }14441445  /** Sets or unsets the approval of a given operator.1446   *  The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1447   *  @param operator Operator1448   *  @param approved Should operator status be granted or revoked?1449   *  @returns ```true``` if extrinsic success, otherwise ```false```1450   */1451  async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1452    const result = await this.helper.executeExtrinsic(1453      signer,1454      'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1455      true,1456    );1457    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1458  }1459}146014611462class NFTGroup extends NFTnRFT {1463  /**1464   * Get collection object1465   * @param collectionId ID of collection1466   * @example getCollectionObject(2);1467   * @returns instance of UniqueNFTCollection1468   */1469  getCollectionObject(collectionId: number): UniqueNFTCollection {1470    return new UniqueNFTCollection(collectionId, this.helper);1471  }14721473  /**1474   * Get token object1475   * @param collectionId ID of collection1476   * @param tokenId ID of token1477   * @example getTokenObject(10, 5);1478   * @returns instance of UniqueNFTToken1479   */1480  getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1481    return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1482  }14831484  /**1485   * Get token's owner1486   * @param collectionId ID of collection1487   * @param tokenId ID of token1488   * @param blockHashAt optionally query the data at the block with this hash1489   * @example getTokenOwner(10, 5);1490   * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1491   */1492  async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1493    let owner;1494    if (typeof blockHashAt === 'undefined') {1495      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1496    } else {1497      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1498    }1499    return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1500  }15011502  /**1503   * Is token approved to transfer1504   * @param collectionId ID of collection1505   * @param tokenId ID of token1506   * @param toAccountObj address to be approved1507   * @returns ```true``` if extrinsic success, otherwise ```false```1508   */1509  async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1510    return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1511  }15121513  /**1514   * Changes the owner of the token.1515   *1516   * @param signer keyring of signer1517   * @param collectionId ID of collection1518   * @param tokenId ID of token1519   * @param addressObj address of a new owner1520   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1521   * @returns ```true``` if extrinsic success, otherwise ```false```1522   */1523  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1524    return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1525  }15261527  /**1528   *1529   * Change ownership of a NFT on behalf of the owner.1530   *1531   * @param signer keyring of signer1532   * @param collectionId ID of collection1533   * @param tokenId ID of token1534   * @param fromAddressObj address on behalf of which the token will be sent1535   * @param toAddressObj new token owner1536   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1537   * @returns ```true``` if extrinsic success, otherwise ```false```1538   */1539  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1540    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1541  }15421543  /**1544   * Recursively find the address that owns the token1545   * @param collectionId ID of collection1546   * @param tokenId ID of token1547   * @param blockHashAt1548   * @example getTokenTopmostOwner(10, 5);1549   * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1550   */1551  async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1552    let owner;1553    if (typeof blockHashAt === 'undefined') {1554      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1555    } else {1556      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1557    }15581559    if (owner === null) return null;15601561    return owner.toHuman();1562  }15631564  /**1565   * Get tokens nested in the provided token1566   * @param collectionId ID of collection1567   * @param tokenId ID of token1568   * @param blockHashAt optionally query the data at the block with this hash1569   * @example getTokenChildren(10, 5);1570   * @returns tokens whose depth of nesting is <= 51571   */1572  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1573    let children;1574    if(typeof blockHashAt === 'undefined') {1575      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1576    } else {1577      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1578    }15791580    return children.toJSON().map((x: any) => {1581      return {collectionId: x.collection, tokenId: x.token};1582    });1583  }15841585  /**1586   * Nest one token into another1587   * @param signer keyring of signer1588   * @param tokenObj token to be nested1589   * @param rootTokenObj token to be parent1590   * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1591   * @returns ```true``` if extrinsic success, otherwise ```false```1592   */1593  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1594    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1595    const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1596    if(!result) {1597      throw Error('Unable to nest token!');1598    }1599    return result;1600  }16011602  /**1603   * Remove token from nested state1604   * @param signer keyring of signer1605   * @param tokenObj token to unnest1606   * @param rootTokenObj parent of a token1607   * @param toAddressObj address of a new token owner1608   * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1609   * @returns ```true``` if extrinsic success, otherwise ```false```1610   */1611  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1612    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1613    const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1614    if(!result) {1615      throw Error('Unable to unnest token!');1616    }1617    return result;1618  }16191620  /**1621   * Mint new collection1622   * @param signer keyring of signer1623   * @param collectionOptions Collection options1624   * @example1625   * mintCollection(aliceKeyring, {1626   *   name: 'New',1627   *   description: 'New collection',1628   *   tokenPrefix: 'NEW',1629   * })1630   * @returns object of the created collection1631   */1632  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1633    return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1634  }16351636  /**1637   * Mint new token1638   * @param signer keyring of signer1639   * @param data token data1640   * @returns created token object1641   */1642  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1643    const creationResult = await this.helper.executeExtrinsic(1644      signer,1645      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1646        nft: {1647          properties: data.properties,1648        },1649      }],1650      true,1651    );1652    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1653    if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1654    if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1655    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1656  }16571658  /**1659   * Mint multiple NFT tokens1660   * @param signer keyring of signer1661   * @param collectionId ID of collection1662   * @param tokens array of tokens with owner and properties1663   * @example1664   * mintMultipleTokens(aliceKeyring, 10, [{1665   *     owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1666   *     properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1667   *   },{1668   *     owner: {Ethereum: "0x9F0583DbB855d..."},1669   *     properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1670   * }]);1671   * @returns ```true``` if extrinsic success, otherwise ```false```1672   */1673  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1674    const creationResult = await this.helper.executeExtrinsic(1675      signer,1676      'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1677      true,1678    );1679    const collection = this.getCollectionObject(collectionId);1680    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1681  }16821683  /**1684   * Mint multiple NFT tokens with one owner1685   * @param signer keyring of signer1686   * @param collectionId ID of collection1687   * @param owner tokens owner1688   * @param tokens array of tokens with owner and properties1689   * @example1690   * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1691   *   properties: [{1692   *   key: "gender",1693   *   value: "female",1694   *  },{1695   *   key: "age",1696   *   value: "33",1697   *  }],1698   * }]);1699   * @returns array of newly created tokens1700   */1701  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1702    const rawTokens = [];1703    for (const token of tokens) {1704      const raw = {NFT: {properties: token.properties}};1705      rawTokens.push(raw);1706    }1707    const creationResult = await this.helper.executeExtrinsic(1708      signer,1709      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1710      true,1711    );1712    const collection = this.getCollectionObject(collectionId);1713    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1714  }17151716  /**1717   * Set, change, or remove approved address to transfer the ownership of the NFT.1718   *1719   * @param signer keyring of signer1720   * @param collectionId ID of collection1721   * @param tokenId ID of token1722   * @param toAddressObj address to approve1723   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1724   * @returns ```true``` if extrinsic success, otherwise ```false```1725   */1726  approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1727    return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1728  }1729}173017311732class RFTGroup extends NFTnRFT {1733  /**1734   * Get collection object1735   * @param collectionId ID of collection1736   * @example getCollectionObject(2);1737   * @returns instance of UniqueRFTCollection1738   */1739  getCollectionObject(collectionId: number): UniqueRFTCollection {1740    return new UniqueRFTCollection(collectionId, this.helper);1741  }17421743  /**1744   * Get token object1745   * @param collectionId ID of collection1746   * @param tokenId ID of token1747   * @example getTokenObject(10, 5);1748   * @returns instance of UniqueNFTToken1749   */1750  getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1751    return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1752  }17531754  /**1755   * Get top 10 token owners with the largest number of pieces1756   * @param collectionId ID of collection1757   * @param tokenId ID of token1758   * @example getTokenTop10Owners(10, 5);1759   * @returns array of top 10 owners1760   */1761  async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1762    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1763  }17641765  /**1766   * Get number of pieces owned by address1767   * @param collectionId ID of collection1768   * @param tokenId ID of token1769   * @param addressObj address token owner1770   * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1771   * @returns number of pieces ownerd by address1772   */1773  async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1774    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1775  }17761777  /**1778   * Transfer pieces of token to another address1779   * @param signer keyring of signer1780   * @param collectionId ID of collection1781   * @param tokenId ID of token1782   * @param addressObj address of a new owner1783   * @param amount number of pieces to be transfered1784   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1785   * @returns ```true``` if extrinsic success, otherwise ```false```1786   */1787  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1788    return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1789  }17901791  /**1792   * Change ownership of some pieces of RFT on behalf of the owner.1793   * @param signer keyring of signer1794   * @param collectionId ID of collection1795   * @param tokenId ID of token1796   * @param fromAddressObj address on behalf of which the token will be sent1797   * @param toAddressObj new token owner1798   * @param amount number of pieces to be transfered1799   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1800   * @returns ```true``` if extrinsic success, otherwise ```false```1801   */1802  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1803    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1804  }18051806  /**1807   * Mint new collection1808   * @param signer keyring of signer1809   * @param collectionOptions Collection options1810   * @example1811   * mintCollection(aliceKeyring, {1812   *   name: 'New',1813   *   description: 'New collection',1814   *   tokenPrefix: 'NEW',1815   * })1816   * @returns object of the created collection1817   */1818  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1819    return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1820  }18211822  /**1823   * Mint new token1824   * @param signer keyring of signer1825   * @param data token data1826   * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1827   * @returns created token object1828   */1829  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1830    const creationResult = await this.helper.executeExtrinsic(1831      signer,1832      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1833        refungible: {1834          pieces: data.pieces,1835          properties: data.properties,1836        },1837      }],1838      true,1839    );1840    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1841    if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1842    if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1843    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1844  }18451846  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1847    throw Error('Not implemented');1848    const creationResult = await this.helper.executeExtrinsic(1849      signer,1850      'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1851      true, // `Unable to mint RFT tokens for ${label}`,1852    );1853    const collection = this.getCollectionObject(collectionId);1854    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1855  }18561857  /**1858   * Mint multiple RFT tokens with one owner1859   * @param signer keyring of signer1860   * @param collectionId ID of collection1861   * @param owner tokens owner1862   * @param tokens array of tokens with properties and pieces1863   * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1864   * @returns array of newly created RFT tokens1865   */1866  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1867    const rawTokens = [];1868    for (const token of tokens) {1869      const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1870      rawTokens.push(raw);1871    }1872    const creationResult = await this.helper.executeExtrinsic(1873      signer,1874      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1875      true,1876    );1877    const collection = this.getCollectionObject(collectionId);1878    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1879  }18801881  /**1882   * Destroys a concrete instance of RFT.1883   * @param signer keyring of signer1884   * @param collectionId ID of collection1885   * @param tokenId ID of token1886   * @param amount number of pieces to be burnt1887   * @example burnToken(aliceKeyring, 10, 5);1888   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1889   */1890  async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1891    return await super.burnToken(signer, collectionId, tokenId, amount);1892  }18931894  /**1895   * Destroys a concrete instance of RFT on behalf of the owner.1896   * @param signer keyring of signer1897   * @param collectionId ID of collection1898   * @param tokenId ID of token1899   * @param fromAddressObj address on behalf of which the token will be burnt1900   * @param amount number of pieces to be burnt1901   * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1902   * @returns ```true``` if extrinsic success, otherwise ```false```1903   */1904  async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1905    return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1906  }19071908  /**1909   * Set, change, or remove approved address to transfer the ownership of the RFT.1910   *1911   * @param signer keyring of signer1912   * @param collectionId ID of collection1913   * @param tokenId ID of token1914   * @param toAddressObj address to approve1915   * @param amount number of pieces to be approved1916   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1917   * @returns true if the token success, otherwise false1918   */1919  approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1920    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1921  }19221923  /**1924   * Get total number of pieces1925   * @param collectionId ID of collection1926   * @param tokenId ID of token1927   * @example getTokenTotalPieces(10, 5);1928   * @returns number of pieces1929   */1930  async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1931    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1932  }19331934  /**1935   * Change number of token pieces. Signer must be the owner of all token pieces.1936   * @param signer keyring of signer1937   * @param collectionId ID of collection1938   * @param tokenId ID of token1939   * @param amount new number of pieces1940   * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1941   * @returns true if the repartion was success, otherwise false1942   */1943  async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1944    const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1945    const repartitionResult = await this.helper.executeExtrinsic(1946      signer,1947      'api.tx.unique.repartition', [collectionId, tokenId, amount],1948      true,1949    );1950    if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1951    return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1952  }1953}195419551956class FTGroup extends CollectionGroup {1957  /**1958   * Get collection object1959   * @param collectionId ID of collection1960   * @example getCollectionObject(2);1961   * @returns instance of UniqueFTCollection1962   */1963  getCollectionObject(collectionId: number): UniqueFTCollection {1964    return new UniqueFTCollection(collectionId, this.helper);1965  }19661967  /**1968   * Mint new fungible collection1969   * @param signer keyring of signer1970   * @param collectionOptions Collection options1971   * @param decimalPoints number of token decimals1972   * @example1973   * mintCollection(aliceKeyring, {1974   *   name: 'New',1975   *   description: 'New collection',1976   *   tokenPrefix: 'NEW',1977   * }, 18)1978   * @returns newly created fungible collection1979   */1980  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {1981    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1982    if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1983    collectionOptions.mode = {fungible: decimalPoints};1984    for (const key of ['name', 'description', 'tokenPrefix']) {1985      if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1986    }1987    const creationResult = await this.helper.executeExtrinsic(1988      signer,1989      'api.tx.unique.createCollectionEx', [collectionOptions],1990      true,1991    );1992    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1993  }19941995  /**1996   * Mint tokens1997   * @param signer keyring of signer1998   * @param collectionId ID of collection1999   * @param owner address owner of new tokens2000   * @param amount amount of tokens to be meanted2001   * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2002   * @returns ```true``` if extrinsic success, otherwise ```false```2003   */2004  async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2005    const creationResult = await this.helper.executeExtrinsic(2006      signer,2007      'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2008        fungible: {2009          value: amount,2010        },2011      }],2012      true, // `Unable to mint fungible tokens for ${label}`,2013    );2014    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2015  }20162017  /**2018   * Mint multiple Fungible tokens with one owner2019   * @param signer keyring of signer2020   * @param collectionId ID of collection2021   * @param owner tokens owner2022   * @param tokens array of tokens with properties and pieces2023   * @returns ```true``` if extrinsic success, otherwise ```false```2024   */2025  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {2026    const rawTokens = [];2027    for (const token of tokens) {2028      const raw = {Fungible: {Value: token.value}};2029      rawTokens.push(raw);2030    }2031    const creationResult = await this.helper.executeExtrinsic(2032      signer,2033      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2034      true,2035    );2036    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2037  }20382039  /**2040   * Get the top 10 owners with the largest balance for the Fungible collection2041   * @param collectionId ID of collection2042   * @example getTop10Owners(10);2043   * @returns array of ```ICrossAccountId```2044   */2045  async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2046    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2047  }20482049  /**2050   * Get account balance2051   * @param collectionId ID of collection2052   * @param addressObj address of owner2053   * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2054   * @returns amount of fungible tokens owned by address2055   */2056  async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2057    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2058  }20592060  /**2061   * Transfer tokens to address2062   * @param signer keyring of signer2063   * @param collectionId ID of collection2064   * @param toAddressObj address recipient2065   * @param amount amount of tokens to be sent2066   * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2067   * @returns ```true``` if extrinsic success, otherwise ```false```2068   */2069  async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2070    return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2071  }20722073  /**2074   * Transfer some tokens on behalf of the owner.2075   * @param signer keyring of signer2076   * @param collectionId ID of collection2077   * @param fromAddressObj address on behalf of which tokens will be sent2078   * @param toAddressObj address where token to be sent2079   * @param amount number of tokens to be sent2080   * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2081   * @returns ```true``` if extrinsic success, otherwise ```false```2082   */2083  async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2084    return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2085  }20862087  /**2088   * Destroy some amount of tokens2089   * @param signer keyring of signer2090   * @param collectionId ID of collection2091   * @param amount amount of tokens to be destroyed2092   * @example burnTokens(aliceKeyring, 10, 1000n);2093   * @returns ```true``` if extrinsic success, otherwise ```false```2094   */2095  async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2096    return await super.burnToken(signer, collectionId, 0, amount);2097  }20982099  /**2100   * Burn some tokens on behalf of the owner.2101   * @param signer keyring of signer2102   * @param collectionId ID of collection2103   * @param fromAddressObj address on behalf of which tokens will be burnt2104   * @param amount amount of tokens to be burnt2105   * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2106   * @returns ```true``` if extrinsic success, otherwise ```false```2107   */2108  async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2109    return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2110  }21112112  /**2113   * Get total collection supply2114   * @param collectionId2115   * @returns2116   */2117  async getTotalPieces(collectionId: number): Promise<bigint> {2118    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2119  }21202121  /**2122   * Set, change, or remove approved address to transfer tokens.2123   *2124   * @param signer keyring of signer2125   * @param collectionId ID of collection2126   * @param toAddressObj address to be approved2127   * @param amount amount of tokens to be approved2128   * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2129   * @returns ```true``` if extrinsic success, otherwise ```false```2130   */2131  approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2132    return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2133  }21342135  /**2136   * Get amount of fungible tokens approved to transfer2137   * @param collectionId ID of collection2138   * @param fromAddressObj owner of tokens2139   * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2140   * @returns number of tokens approved for the transfer2141   */2142  getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2143    return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2144  }2145}214621472148class ChainGroup extends HelperGroup<ChainHelperBase> {2149  /**2150   * Get system properties of a chain2151   * @example getChainProperties();2152   * @returns ss58Format, token decimals, and token symbol2153   */2154  getChainProperties(): IChainProperties {2155    const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2156    return {2157      ss58Format: properties.ss58Format.toJSON(),2158      tokenDecimals: properties.tokenDecimals.toJSON(),2159      tokenSymbol: properties.tokenSymbol.toJSON(),2160    };2161  }21622163  /**2164   * Get chain header2165   * @example getLatestBlockNumber();2166   * @returns the number of the last block2167   */2168  async getLatestBlockNumber(): Promise<number> {2169    return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2170  }21712172  /**2173   * Get block hash by block number2174   * @param blockNumber number of block2175   * @example getBlockHashByNumber(12345);2176   * @returns hash of a block2177   */2178  async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2179    const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2180    if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2181    return blockHash;2182  }21832184  // TODO add docs2185  async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2186    const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2187    if (!blockHash) return null;2188    return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2189  }21902191  /**2192   * Get account nonce2193   * @param address substrate address2194   * @example getNonce("5GrwvaEF5zXb26Fz...");2195   * @returns number, account's nonce2196   */2197  async getNonce(address: TSubstrateAccount): Promise<number> {2198    return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2199  }2200}22012202class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2203  /**2204 * Get substrate address balance2205 * @param address substrate address2206 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2207 * @returns amount of tokens on address2208 */2209  async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2210    return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2211  }22122213  /**2214   * Transfer tokens to substrate address2215   * @param signer keyring of signer2216   * @param address substrate address of a recipient2217   * @param amount amount of tokens to be transfered2218   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2219   * @returns ```true``` if extrinsic success, otherwise ```false```2220   */2221  async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2222    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);22232224    let transfer = {from: null, to: null, amount: 0n} as any;2225    result.result.events.forEach(({event: {data, method, section}}) => {2226      if ((section === 'balances') && (method === 'Transfer')) {2227        transfer = {2228          from: this.helper.address.normalizeSubstrate(data[0]),2229          to: this.helper.address.normalizeSubstrate(data[1]),2230          amount: BigInt(data[2]),2231        };2232      }2233    });2234    const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2235      && this.helper.address.normalizeSubstrate(address) === transfer.to2236      && BigInt(amount) === transfer.amount;2237    return isSuccess;2238  }22392240  /**2241   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2242   * @param address substrate address2243   * @returns2244   */2245  async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2246    const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2247    return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2248  }2249}22502251class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2252  /**2253   * Get ethereum address balance2254   * @param address ethereum address2255   * @example getEthereum("0x9F0583DbB855d...")2256   * @returns amount of tokens on address2257   */2258  async getEthereum(address: TEthereumAccount): Promise<bigint> {2259    return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2260  }22612262  /**2263   * Transfer tokens to address2264   * @param signer keyring of signer2265   * @param address Ethereum address of a recipient2266   * @param amount amount of tokens to be transfered2267   * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2268   * @returns ```true``` if extrinsic success, otherwise ```false```2269   */2270  async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2271    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);22722273    let transfer = {from: null, to: null, amount: 0n} as any;2274    result.result.events.forEach(({event: {data, method, section}}) => {2275      if ((section === 'balances') && (method === 'Transfer')) {2276        transfer = {2277          from: data[0].toString(),2278          to: data[1].toString(),2279          amount: BigInt(data[2]),2280        };2281      }2282    });2283    const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2284      && address === transfer.to2285      && BigInt(amount) === transfer.amount;2286    return isSuccess;2287  }2288}22892290class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2291  subBalanceGroup: SubstrateBalanceGroup<T>;2292  ethBalanceGroup: EthereumBalanceGroup<T>;22932294  constructor(helper: T) {2295    super(helper);2296    this.subBalanceGroup = new SubstrateBalanceGroup(helper);2297    this.ethBalanceGroup = new EthereumBalanceGroup(helper);2298  }22992300  getCollectionCreationPrice(): bigint {2301    return 2n * this.getOneTokenNominal();2302  }2303  /**2304   * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2305   * @example getOneTokenNominal()2306   * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2307   */2308  getOneTokenNominal(): bigint {2309    const chainProperties = this.helper.chain.getChainProperties();2310    return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2311  }23122313  /**2314   * Get substrate address balance2315   * @param address substrate address2316   * @example getSubstrate("5GrwvaEF5zXb26Fz...")2317   * @returns amount of tokens on address2318   */2319  getSubstrate(address: TSubstrateAccount): Promise<bigint> {2320    return this.subBalanceGroup.getSubstrate(address);2321  }23222323  /**2324   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2325   * @param address substrate address2326   * @returns2327   */2328  getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2329    return this.subBalanceGroup.getSubstrateFull(address);2330  }23312332  /**2333   * Get ethereum address balance2334   * @param address ethereum address2335   * @example getEthereum("0x9F0583DbB855d...")2336   * @returns amount of tokens on address2337   */2338  getEthereum(address: TEthereumAccount): Promise<bigint> {2339    return this.ethBalanceGroup.getEthereum(address);2340  }23412342  /**2343   * Transfer tokens to substrate address2344   * @param signer keyring of signer2345   * @param address substrate address of a recipient2346   * @param amount amount of tokens to be transfered2347   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2348   * @returns ```true``` if extrinsic success, otherwise ```false```2349   */2350  transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2351    return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2352  }23532354  async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2355    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23562357    let transfer = {from: null, to: null, amount: 0n} as any;2358    result.result.events.forEach(({event: {data, method, section}}) => {2359      if ((section === 'balances') && (method === 'Transfer')) {2360        transfer = {2361          from: this.helper.address.normalizeSubstrate(data[0]),2362          to: this.helper.address.normalizeSubstrate(data[1]),2363          amount: BigInt(data[2]),2364        };2365      }2366    });2367    let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2368    isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2369    isSuccess = isSuccess && BigInt(amount) === transfer.amount;2370    return isSuccess;2371  }2372}23732374class AddressGroup extends HelperGroup<ChainHelperBase> {2375  /**2376   * Normalizes the address to the specified ss58 format, by default ```42```.2377   * @param address substrate address2378   * @param ss58Format format for address conversion, by default ```42```2379   * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2380   * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2381   */2382  normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2383    return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2384  }23852386  /**2387   * Get address in the connected chain format2388   * @param address substrate address2389   * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2390   * @returns address in chain format2391   */2392  normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2393    return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2394  }23952396  /**2397   * Get substrate mirror of an ethereum address2398   * @param ethAddress ethereum address2399   * @param toChainFormat false for normalized account2400   * @example ethToSubstrate('0x9F0583DbB855d...')2401   * @returns substrate mirror of a provided ethereum address2402   */2403  ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2404    return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2405  }24062407  /**2408   * Get ethereum mirror of a substrate address2409   * @param subAddress substrate account2410   * @example substrateToEth("5DnSF6RRjwteE3BrC...")2411   * @returns ethereum mirror of a provided substrate address2412   */2413  substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2414    return CrossAccountId.translateSubToEth(subAddress);2415  }24162417  /**2418   * Encode key to substrate address2419   * @param key key for encoding address2420   * @param ss58Format prefix for encoding to the address of the corresponding network2421   * @returns encoded substrate address2422   */2423  encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2424    const u8a :Uint8Array = typeof key === 'string'2425      ? hexToU8a(key)2426      : typeof key === 'bigint'2427        ? hexToU8a(key.toString(16))2428        : key;2429  2430    if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2431      throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);2432    }2433  2434    const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2435    if (!allowedDecodedLengths.includes(u8a.length)) {2436      throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2437    }2438  2439    const u8aPrefix = ss58Format < 642440      ? new Uint8Array([ss58Format])2441      : new Uint8Array([2442        ((ss58Format & 0xfc) >> 2) | 0x40,2443        (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2444      ]);24452446    const input = u8aConcat(u8aPrefix, u8a);2447  2448    return base58Encode(u8aConcat(2449      input,2450      blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2451    ));2452  }24532454  /**2455   * Restore substrate address from bigint representation2456   * @param number decimal representation of substrate address2457   * @returns substrate address2458   */2459  restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2460    if (this.helper.api === null) {2461      throw 'Not connected';2462    }2463    const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2464    if (res === undefined || res === null) {2465      throw 'Restore address error';2466    }2467    return res.toString();2468  }24692470  /**2471   * Convert etherium cross account id to substrate cross account id2472   * @param ethCrossAccount etherium cross account2473   * @returns substrate cross account id2474   */2475  convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2476    if (ethCrossAccount.sub === '0') {2477      return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2478    }2479    2480    const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2481    return {Substrate: ss58};2482  }24832484  paraSiblingSovereignAccount(paraid: number) {2485    // We are getting a *sibling* parachain sovereign account,2486    // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2487    const siblingPrefix = '0x7369626c';24882489    const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2490    const suffix = '000000000000000000000000000000000000000000000000';24912492    return siblingPrefix + encodedParaId + suffix;2493  }2494}24952496class StakingGroup extends HelperGroup<UniqueHelper> {2497  /**2498   * Stake tokens for App Promotion2499   * @param signer keyring of signer2500   * @param amountToStake amount of tokens to stake2501   * @param label extra label for log2502   * @returns2503   */2504  async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2505    if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2506    const _stakeResult = await this.helper.executeExtrinsic(2507      signer, 'api.tx.appPromotion.stake',2508      [amountToStake], true,2509    );2510    // TODO extract info from stakeResult2511    return true;2512  }25132514  /**2515   * Unstake tokens for App Promotion2516   * @param signer keyring of signer2517   * @param amountToUnstake amount of tokens to unstake2518   * @param label extra label for log2519   * @returns block number where balances will be unlocked2520   */2521  async unstake(signer: TSigner, label?: string): Promise<number> {2522    if(typeof label === 'undefined') label = `${signer.address}`;2523    const _unstakeResult = await this.helper.executeExtrinsic(2524      signer, 'api.tx.appPromotion.unstake',2525      [], true,2526    );2527    // TODO extract block number fron events2528    return 1;2529  }25302531  /**2532   * Get total staked amount for address2533   * @param address substrate or ethereum address2534   * @returns total staked amount2535   */2536  async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2537    if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2538    return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2539  }25402541  /**2542   * Get total staked per block2543   * @param address substrate or ethereum address2544   * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2545   */2546  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2547    const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2548    return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2549      return {2550        block: block.toBigInt(),2551        amount: amount.toBigInt(),2552      };2553    });2554  }25552556  /**2557   * Get total pending unstake amount for address2558   * @param address substrate or ethereum address2559   * @returns total pending unstake amount2560   */2561  async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2562    return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2563  }25642565  /**2566   * Get pending unstake amount per block for address2567   * @param address substrate or ethereum address2568   * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2569   */2570  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2571    const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2572    const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2573      return {2574        block: block.toBigInt(),2575        amount: amount.toBigInt(),2576      };2577    });2578    return result;2579  }2580}25812582class SchedulerGroup extends HelperGroup<UniqueHelper> {2583  constructor(helper: UniqueHelper) {2584    super(helper);2585  }25862587  cancelScheduled(signer: TSigner, scheduledId: string) {2588    return this.helper.executeExtrinsic(2589      signer,2590      'api.tx.scheduler.cancelNamed',2591      [scheduledId],2592      true,2593    );2594  }25952596  changePriority(signer: TSigner, scheduledId: string, priority: number) {2597    return this.helper.executeExtrinsic(2598      signer,2599      'api.tx.scheduler.changeNamedPriority',2600      [scheduledId, priority],2601      true,2602    );2603  }26042605  scheduleAt<T extends UniqueHelper>(2606    executionBlockNumber: number,2607    options: ISchedulerOptions = {},2608  ) {2609    return this.schedule<T>('schedule', executionBlockNumber, options);2610  }26112612  scheduleAfter<T extends UniqueHelper>(2613    blocksBeforeExecution: number,2614    options: ISchedulerOptions = {},2615  ) {2616    return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2617  }26182619  schedule<T extends UniqueHelper>(2620    scheduleFn: 'schedule' | 'scheduleAfter',2621    blocksNum: number,2622    options: ISchedulerOptions = {},2623  ) {2624    // eslint-disable-next-line @typescript-eslint/naming-convention2625    const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2626    return this.helper.clone(ScheduledHelperType, {2627      scheduleFn,2628      blocksNum,2629      options,2630    }) as T;2631  }2632}26332634class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2635  async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2636    await this.helper.executeExtrinsic(2637      signer,2638      'api.tx.foreignAssets.registerForeignAsset',2639      [ownerAddress, location, metadata],2640      true,2641    );2642  }26432644  async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2645    await this.helper.executeExtrinsic(2646      signer,2647      'api.tx.foreignAssets.updateForeignAsset',2648      [foreignAssetId, location, metadata],2649      true,2650    );2651  }2652}26532654class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2655  palletName: string;26562657  constructor(helper: T, palletName: string) {2658    super(helper);26592660    this.palletName = palletName;2661  }26622663  async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) {2664    await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true);2665  }2666}26672668class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2669  async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) {2670    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2671  }26722673  async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) {2674    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2675  }26762677  async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) {2678    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2679  }2680}26812682class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2683  async accounts(address: string, currencyId: any) {2684    const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2685    return BigInt(free);2686  }2687}26882689class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2690  async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2691    await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2692  }26932694  async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2695    await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2696  }26972698  async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2699    await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2700  }27012702  async account(assetId: string | number, address: string) {2703    const accountAsset = (2704      await this.helper.callRpc('api.query.assets.account', [assetId, address])2705    ).toJSON()! as any;27062707    if (accountAsset !== null) {2708      return BigInt(accountAsset['balance']);2709    } else {2710      return null;2711    }2712  }2713}27142715class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2716  async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2717    await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2718  }2719}27202721class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2722  makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2723    const apiPrefix = 'api.tx.assetManager.';27242725    const registerTx = this.helper.constructApiCall(2726      apiPrefix + 'registerForeignAsset',2727      [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2728    );27292730    const setUnitsTx = this.helper.constructApiCall(2731      apiPrefix + 'setAssetUnitsPerSecond',2732      [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2733    );27342735    const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2736    const encodedProposal = batchCall?.method.toHex() || '';2737    return encodedProposal;2738  }27392740  async assetTypeId(location: any) {2741    return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2742  }2743}27442745class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2746  async notePreimage(signer: TSigner, encodedProposal: string) {2747    await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true);2748  }27492750  externalProposeMajority(proposalHash: string) {2751    return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]);2752  }27532754  fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2755    return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2756  }27572758  async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2759    await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2760  }2761}27622763class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2764  collective: string;27652766  constructor(helper: MoonbeamHelper, collective: string) {2767    super(helper);27682769    this.collective = collective;2770  }27712772  async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2773    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2774  }27752776  async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2777    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2778  }27792780  async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) {2781    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2782  }27832784  async proposalCount() {2785    return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2786  }2787}27882789export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2790export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;27912792export class UniqueHelper extends ChainHelperBase {2793  balance: BalanceGroup<UniqueHelper>;2794  collection: CollectionGroup;2795  nft: NFTGroup;2796  rft: RFTGroup;2797  ft: FTGroup;2798  staking: StakingGroup;2799  scheduler: SchedulerGroup;2800  foreignAssets: ForeignAssetsGroup;2801  xcm: XcmGroup<UniqueHelper>;2802  xTokens: XTokensGroup<UniqueHelper>;2803  tokens: TokensGroup<UniqueHelper>;28042805  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2806    super(logger, options.helperBase ?? UniqueHelper);28072808    this.balance = new BalanceGroup(this);2809    this.collection = new CollectionGroup(this);2810    this.nft = new NFTGroup(this);2811    this.rft = new RFTGroup(this);2812    this.ft = new FTGroup(this);2813    this.staking = new StakingGroup(this);2814    this.scheduler = new SchedulerGroup(this);2815    this.foreignAssets = new ForeignAssetsGroup(this);2816    this.xcm = new XcmGroup(this, 'polkadotXcm');2817    this.xTokens = new XTokensGroup(this);2818    this.tokens = new TokensGroup(this);2819  }28202821  getSudo<T extends UniqueHelper>() {2822    // eslint-disable-next-line @typescript-eslint/naming-convention2823    const SudoHelperType = SudoHelper(this.helperBase);2824    return this.clone(SudoHelperType) as T;2825  }2826}28272828export class XcmChainHelper extends ChainHelperBase {2829  async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2830    const wsProvider = new WsProvider(wsEndpoint);2831    this.api = new ApiPromise({2832      provider: wsProvider,2833    });2834    await this.api.isReadyOrError;2835    this.network = await UniqueHelper.detectNetwork(this.api);2836  }2837}28382839export class RelayHelper extends XcmChainHelper {2840  xcm: XcmGroup<RelayHelper>;28412842  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2843    super(logger, options.helperBase ?? RelayHelper);28442845    this.xcm = new XcmGroup(this, 'xcmPallet');2846  }2847}28482849export class WestmintHelper extends XcmChainHelper {2850  balance: SubstrateBalanceGroup<WestmintHelper>;2851  xcm: XcmGroup<WestmintHelper>;2852  assets: AssetsGroup<WestmintHelper>;2853  xTokens: XTokensGroup<WestmintHelper>;28542855  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2856    super(logger, options.helperBase ?? WestmintHelper);28572858    this.balance = new SubstrateBalanceGroup(this);2859    this.xcm = new XcmGroup(this, 'polkadotXcm');2860    this.assets = new AssetsGroup(this);2861    this.xTokens = new XTokensGroup(this);2862  }2863}28642865export class MoonbeamHelper extends XcmChainHelper {2866  balance: EthereumBalanceGroup<MoonbeamHelper>;2867  assetManager: MoonbeamAssetManagerGroup;2868  assets: AssetsGroup<MoonbeamHelper>;2869  xTokens: XTokensGroup<MoonbeamHelper>;2870  democracy: MoonbeamDemocracyGroup;2871  collective: {2872    council: MoonbeamCollectiveGroup,2873    techCommittee: MoonbeamCollectiveGroup,2874  };28752876  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2877    super(logger, options.helperBase ?? MoonbeamHelper);28782879    this.balance = new EthereumBalanceGroup(this);2880    this.assetManager = new MoonbeamAssetManagerGroup(this);2881    this.assets = new AssetsGroup(this);2882    this.xTokens = new XTokensGroup(this);2883    this.democracy = new MoonbeamDemocracyGroup(this);2884    this.collective = {2885      council: new MoonbeamCollectiveGroup(this, 'councilCollective'),2886      techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),2887    };2888  }2889}28902891export class AcalaHelper extends XcmChainHelper {2892  balance: SubstrateBalanceGroup<AcalaHelper>;2893  assetRegistry: AcalaAssetRegistryGroup;2894  xTokens: XTokensGroup<AcalaHelper>;2895  tokens: TokensGroup<AcalaHelper>;28962897  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2898    super(logger, options.helperBase ?? AcalaHelper);28992900    this.balance = new SubstrateBalanceGroup(this);2901    this.assetRegistry = new AcalaAssetRegistryGroup(this);2902    this.xTokens = new XTokensGroup(this);2903    this.tokens = new TokensGroup(this);2904  }29052906  getSudo<T extends AcalaHelper>() {2907    // eslint-disable-next-line @typescript-eslint/naming-convention2908    const SudoHelperType = SudoHelper(this.helperBase);2909    return this.clone(SudoHelperType) as T;2910  }2911}29122913// eslint-disable-next-line @typescript-eslint/naming-convention2914function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2915  return class extends Base {2916    scheduleFn: 'schedule' | 'scheduleAfter';2917    blocksNum: number;2918    options: ISchedulerOptions;29192920    constructor(...args: any[]) {2921      const logger = args[0] as ILogger;2922      const options = args[1] as {2923        scheduleFn: 'schedule' | 'scheduleAfter',2924        blocksNum: number,2925        options: ISchedulerOptions2926      };29272928      super(logger);29292930      this.scheduleFn = options.scheduleFn;2931      this.blocksNum = options.blocksNum;2932      this.options = options.options;2933    }29342935    executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2936      const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2937      2938      const mandatorySchedArgs = [2939        this.blocksNum,2940        this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2941        this.options.priority ?? null,2942        scheduledTx,2943      ];2944      2945      let schedArgs;2946      let scheduleFn;29472948      if (this.options.scheduledId) {2949        schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];29502951        if (this.scheduleFn == 'schedule') {2952          scheduleFn = 'scheduleNamed';2953        } else if (this.scheduleFn == 'scheduleAfter') {2954          scheduleFn = 'scheduleNamedAfter';2955        }2956      } else {2957        schedArgs = mandatorySchedArgs;2958        scheduleFn = this.scheduleFn;2959      }29602961      const extrinsic = 'api.tx.scheduler.' +  scheduleFn;29622963      return super.executeExtrinsic(2964        sender,2965        extrinsic,2966        schedArgs,2967        expectSuccess,2968      );2969    }2970  };2971}29722973// eslint-disable-next-line @typescript-eslint/naming-convention2974function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {2975  return class extends Base {2976    constructor(...args: any[]) {2977      super(...args);2978    }29792980    executeExtrinsic (2981      sender: IKeyringPair,2982      extrinsic: string,2983      params: any[],2984      expectSuccess?: boolean,2985    ): Promise<ITransactionResult> {2986      const call = this.constructApiCall(extrinsic, params);2987      return super.executeExtrinsic(2988        sender,2989        'api.tx.sudo.sudo',2990        [call],2991        expectSuccess,2992      );2993    }2994  };2995}29962997export class UniqueBaseCollection {2998  helper: UniqueHelper;2999  collectionId: number;30003001  constructor(collectionId: number, uniqueHelper: UniqueHelper) {3002    this.collectionId = collectionId;3003    this.helper = uniqueHelper;3004  }30053006  async getData() {3007    return await this.helper.collection.getData(this.collectionId);3008  }30093010  async getLastTokenId() {3011    return await this.helper.collection.getLastTokenId(this.collectionId);3012  }30133014  async doesTokenExist(tokenId: number) {3015    return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3016  }30173018  async getAdmins() {3019    return await this.helper.collection.getAdmins(this.collectionId);3020  }30213022  async getAllowList() {3023    return await this.helper.collection.getAllowList(this.collectionId);3024  }30253026  async getEffectiveLimits() {3027    return await this.helper.collection.getEffectiveLimits(this.collectionId);3028  }30293030  async getProperties(propertyKeys?: string[] | null) {3031    return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3032  }30333034  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3035    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3036  }30373038  async getOptions() {3039    return await this.helper.collection.getCollectionOptions(this.collectionId);3040  }30413042  async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3043    return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3044  }30453046  async confirmSponsorship(signer: TSigner) {3047    return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3048  }30493050  async removeSponsor(signer: TSigner) {3051    return await this.helper.collection.removeSponsor(signer, this.collectionId);3052  }30533054  async setLimits(signer: TSigner, limits: ICollectionLimits) {3055    return await this.helper.collection.setLimits(signer, this.collectionId, limits);3056  }30573058  async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3059    return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3060  }30613062  async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3063    return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3064  }30653066  async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3067    return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3068  }30693070  async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3071    return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3072  }30733074  async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3075    return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3076  }30773078  async setProperties(signer: TSigner, properties: IProperty[]) {3079    return await this.helper.collection.setProperties(signer, this.collectionId, properties);3080  }30813082  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3083    return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3084  }30853086  async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3087    return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3088  }30893090  async enableNesting(signer: TSigner, permissions: INestingPermissions) {3091    return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3092  }30933094  async disableNesting(signer: TSigner) {3095    return await this.helper.collection.disableNesting(signer, this.collectionId);3096  }30973098  async burn(signer: TSigner) {3099    return await this.helper.collection.burn(signer, this.collectionId);3100  }31013102  scheduleAt<T extends UniqueHelper>(3103    executionBlockNumber: number,3104    options: ISchedulerOptions = {},3105  ) {3106    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3107    return new UniqueBaseCollection(this.collectionId, scheduledHelper);3108  }31093110  scheduleAfter<T extends UniqueHelper>(3111    blocksBeforeExecution: number,3112    options: ISchedulerOptions = {},3113  ) {3114    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3115    return new UniqueBaseCollection(this.collectionId, scheduledHelper);3116  }31173118  getSudo<T extends UniqueHelper>() {3119    return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3120  }3121}312231233124export class UniqueNFTCollection extends UniqueBaseCollection {3125  getTokenObject(tokenId: number) {3126    return new UniqueNFToken(tokenId, this);3127  }31283129  async getTokensByAddress(addressObj: ICrossAccountId) {3130    return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3131  }31323133  async getToken(tokenId: number, blockHashAt?: string) {3134    return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3135  }31363137  async getTokenOwner(tokenId: number, blockHashAt?: string) {3138    return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3139  }31403141  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3142    return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3143  }31443145  async getTokenChildren(tokenId: number, blockHashAt?: string) {3146    return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3147  }31483149  async getPropertyPermissions(propertyKeys: string[] | null = null) {3150    return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3151  }31523153  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3154    return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3155  }31563157  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3158    return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3159  }31603161  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3162    return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3163  }31643165  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3166    return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3167  }31683169  async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3170    return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3171  }31723173  async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3174    return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3175  }31763177  async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3178    return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3179  }31803181  async burnToken(signer: TSigner, tokenId: number) {3182    return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3183  }31843185  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3186    return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3187  }31883189  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3190    return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3191  }31923193  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3194    return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3195  }31963197  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3198    return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3199  }32003201  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3202    return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3203  }32043205  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3206    return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3207  }32083209  scheduleAt<T extends UniqueHelper>(3210    executionBlockNumber: number,3211    options: ISchedulerOptions = {},3212  ) {3213    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3214    return new UniqueNFTCollection(this.collectionId, scheduledHelper);3215  }32163217  scheduleAfter<T extends UniqueHelper>(3218    blocksBeforeExecution: number,3219    options: ISchedulerOptions = {},3220  ) {3221    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3222    return new UniqueNFTCollection(this.collectionId, scheduledHelper);3223  }32243225  getSudo<T extends UniqueHelper>() {3226    return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3227  }3228}322932303231export class UniqueRFTCollection extends UniqueBaseCollection {3232  getTokenObject(tokenId: number) {3233    return new UniqueRFToken(tokenId, this);3234  }32353236  async getToken(tokenId: number, blockHashAt?: string) {3237    return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3238  }32393240  async getTokensByAddress(addressObj: ICrossAccountId) {3241    return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3242  }32433244  async getTop10TokenOwners(tokenId: number) {3245    return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3246  }32473248  async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3249    return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3250  }32513252  async getTokenTotalPieces(tokenId: number) {3253    return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3254  }32553256  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3257    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3258  }32593260  async getPropertyPermissions(propertyKeys: string[] | null = null) {3261    return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3262  }32633264  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3265    return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3266  }32673268  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3269    return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3270  }32713272  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3273    return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3274  }32753276  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3277    return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3278  }32793280  async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3281    return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3282  }32833284  async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3285    return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3286  }32873288  async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3289    return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3290  }32913292  async burnToken(signer: TSigner, tokenId: number, amount=1n) {3293    return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3294  }32953296  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId,  amount=1n) {3297    return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3298  }32993300  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3301    return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3302  }33033304  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3305    return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3306  }33073308  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3309    return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3310  }33113312  scheduleAt<T extends UniqueHelper>(3313    executionBlockNumber: number,3314    options: ISchedulerOptions = {},3315  ) {3316    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3317    return new UniqueRFTCollection(this.collectionId, scheduledHelper);3318  }33193320  scheduleAfter<T extends UniqueHelper>(3321    blocksBeforeExecution: number,3322    options: ISchedulerOptions = {},3323  ) {3324    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3325    return new UniqueRFTCollection(this.collectionId, scheduledHelper);3326  }33273328  getSudo<T extends UniqueHelper>() {3329    return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3330  }3331}333233333334export class UniqueFTCollection extends UniqueBaseCollection {3335  async getBalance(addressObj: ICrossAccountId) {3336    return await this.helper.ft.getBalance(this.collectionId, addressObj);3337  }33383339  async getTotalPieces() {3340    return await this.helper.ft.getTotalPieces(this.collectionId);3341  }33423343  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3344    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3345  }33463347  async getTop10Owners() {3348    return await this.helper.ft.getTop10Owners(this.collectionId);3349  }33503351  async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3352    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3353  }33543355  async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3356    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3357  }33583359  async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3360    return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3361  }33623363  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3364    return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3365  }33663367  async burnTokens(signer: TSigner, amount=1n) {3368    return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3369  }33703371  async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3372    return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3373  }33743375  async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3376    return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3377  }33783379  scheduleAt<T extends UniqueHelper>(3380    executionBlockNumber: number,3381    options: ISchedulerOptions = {},3382  ) {3383    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3384    return new UniqueFTCollection(this.collectionId, scheduledHelper);3385  }33863387  scheduleAfter<T extends UniqueHelper>(3388    blocksBeforeExecution: number,3389    options: ISchedulerOptions = {},3390  ) {3391    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3392    return new UniqueFTCollection(this.collectionId, scheduledHelper);3393  }33943395  getSudo<T extends UniqueHelper>() {3396    return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3397  }3398}339934003401export class UniqueBaseToken {3402  collection: UniqueNFTCollection | UniqueRFTCollection;3403  collectionId: number;3404  tokenId: number;34053406  constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3407    this.collection = collection;3408    this.collectionId = collection.collectionId;3409    this.tokenId = tokenId;3410  }34113412  async getNextSponsored(addressObj: ICrossAccountId) {3413    return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3414  }34153416  async getProperties(propertyKeys?: string[] | null) {3417    return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3418  }34193420  async setProperties(signer: TSigner, properties: IProperty[]) {3421    return await this.collection.setTokenProperties(signer, this.tokenId, properties);3422  }34233424  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3425    return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3426  }34273428  async doesExist() {3429    return await this.collection.doesTokenExist(this.tokenId);3430  }34313432  nestingAccount() {3433    return this.collection.helper.util.getTokenAccount(this);3434  }34353436  scheduleAt<T extends UniqueHelper>(3437    executionBlockNumber: number,3438    options: ISchedulerOptions = {},3439  ) {3440    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3441    return new UniqueBaseToken(this.tokenId, scheduledCollection);3442  }34433444  scheduleAfter<T extends UniqueHelper>(3445    blocksBeforeExecution: number,3446    options: ISchedulerOptions = {},3447  ) {3448    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3449    return new UniqueBaseToken(this.tokenId, scheduledCollection);3450  }34513452  getSudo<T extends UniqueHelper>() {3453    return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3454  }3455}345634573458export class UniqueNFToken extends UniqueBaseToken {3459  collection: UniqueNFTCollection;34603461  constructor(tokenId: number, collection: UniqueNFTCollection) {3462    super(tokenId, collection);3463    this.collection = collection;3464  }34653466  async getData(blockHashAt?: string) {3467    return await this.collection.getToken(this.tokenId, blockHashAt);3468  }34693470  async getOwner(blockHashAt?: string) {3471    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3472  }34733474  async getTopmostOwner(blockHashAt?: string) {3475    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3476  }34773478  async getChildren(blockHashAt?: string) {3479    return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3480  }34813482  async nest(signer: TSigner, toTokenObj: IToken) {3483    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3484  }34853486  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3487    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3488  }34893490  async transfer(signer: TSigner, addressObj: ICrossAccountId) {3491    return await this.collection.transferToken(signer, this.tokenId, addressObj);3492  }34933494  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3495    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3496  }34973498  async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3499    return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3500  }35013502  async isApproved(toAddressObj: ICrossAccountId) {3503    return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3504  }35053506  async burn(signer: TSigner) {3507    return await this.collection.burnToken(signer, this.tokenId);3508  }35093510  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3511    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3512  }35133514  scheduleAt<T extends UniqueHelper>(3515    executionBlockNumber: number,3516    options: ISchedulerOptions = {},3517  ) {3518    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3519    return new UniqueNFToken(this.tokenId, scheduledCollection);3520  }35213522  scheduleAfter<T extends UniqueHelper>(3523    blocksBeforeExecution: number,3524    options: ISchedulerOptions = {},3525  ) {3526    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3527    return new UniqueNFToken(this.tokenId, scheduledCollection);3528  }35293530  getSudo<T extends UniqueHelper>() {3531    return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3532  }3533}35343535export class UniqueRFToken extends UniqueBaseToken {3536  collection: UniqueRFTCollection;35373538  constructor(tokenId: number, collection: UniqueRFTCollection) {3539    super(tokenId, collection);3540    this.collection = collection;3541  }35423543  async getData(blockHashAt?: string) {3544    return await this.collection.getToken(this.tokenId, blockHashAt);3545  }35463547  async getTop10Owners() {3548    return await this.collection.getTop10TokenOwners(this.tokenId);3549  }35503551  async getBalance(addressObj: ICrossAccountId) {3552    return await this.collection.getTokenBalance(this.tokenId, addressObj);3553  }35543555  async getTotalPieces() {3556    return await this.collection.getTokenTotalPieces(this.tokenId);3557  }35583559  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3560    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3561  }35623563  async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3564    return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3565  }35663567  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3568    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3569  }35703571  async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3572    return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3573  }35743575  async repartition(signer: TSigner, amount: bigint) {3576    return await this.collection.repartitionToken(signer, this.tokenId, amount);3577  }35783579  async burn(signer: TSigner, amount=1n) {3580    return await this.collection.burnToken(signer, this.tokenId, amount);3581  }35823583  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3584    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3585  }35863587  scheduleAt<T extends UniqueHelper>(3588    executionBlockNumber: number,3589    options: ISchedulerOptions = {},3590  ) {3591    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3592    return new UniqueRFToken(this.tokenId, scheduledCollection);3593  }35943595  scheduleAfter<T extends UniqueHelper>(3596    blocksBeforeExecution: number,3597    options: ISchedulerOptions = {},3598  ) {3599    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3600    return new UniqueRFToken(this.tokenId, scheduledCollection);3601  }36023603  getSudo<T extends UniqueHelper>() {3604    return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3605  }3606}
after · tests/src/util/playgrounds/unique.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// SPDX-License-Identifier: Apache-2.034/* eslint-disable @typescript-eslint/no-var-requires */5/* eslint-disable function-call-argument-newline */6/* eslint-disable no-prototype-builtins */78import {ApiPromise, WsProvider, Keyring} from '@polkadot/api';9import {ApiInterfaceEvents, SignerOptions} from '@polkadot/api/types';10import {encodeAddress, decodeAddress, keccakAsHex, evmToAddress, addressToEvm, base58Encode, blake2AsU8a} from '@polkadot/util-crypto';11import {IKeyringPair} from '@polkadot/types/types';12import {hexToU8a} from '@polkadot/util/hex';13import {u8aConcat} from '@polkadot/util/u8a';14import {15  IApiListeners,16  IBlock,17  IEvent,18  IChainProperties,19  ICollectionCreationOptions,20  ICollectionLimits,21  ICollectionPermissions,22  ICrossAccountId,23  ICrossAccountIdLower,24  ILogger,25  INestingPermissions,26  IProperty,27  IStakingInfo,28  ISchedulerOptions,29  ISubstrateBalance,30  IToken,31  ITokenPropertyPermission,32  ITransactionResult,33  IUniqueHelperLog,34  TApiAllowedListeners,35  TEthereumAccount,36  TSigner,37  TSubstrateAccount,38  TNetworks,39  IForeignAssetMetadata,40  AcalaAssetMetadata,41  MoonbeamAssetInfo,42  DemocracyStandardAccountVote,43  IEthCrossAccountId,44} from './types';45import {RuntimeDispatchInfo} from '@polkadot/types/interfaces';46import type {Vec} from '@polkadot/types-codec';47import {FrameSystemEventRecord} from '@polkadot/types/lookup';4849export class CrossAccountId implements ICrossAccountId {50  Substrate?: TSubstrateAccount;51  Ethereum?: TEthereumAccount;5253  constructor(account: ICrossAccountId) {54    if (account.Substrate) this.Substrate = account.Substrate;55    if (account.Ethereum) this.Ethereum = account.Ethereum;56  }5758  static fromKeyring(account: IKeyringPair, domain: 'Substrate' | 'Ethereum' = 'Substrate') {59    switch (domain) {60      case 'Substrate': return new CrossAccountId({Substrate: account.address});61      case 'Ethereum': return new CrossAccountId({Substrate: account.address}).toEthereum();62    }63  }6465  static fromLowerCaseKeys(address: ICrossAccountIdLower): CrossAccountId {66    return new CrossAccountId({Substrate: address.substrate, Ethereum: address.ethereum});67  }6869  static normalizeSubstrateAddress(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {70    return encodeAddress(decodeAddress(address), ss58Format);71  }7273  static withNormalizedSubstrate(address: TSubstrateAccount, ss58Format = 42): CrossAccountId {74    return new CrossAccountId({Substrate: CrossAccountId.normalizeSubstrateAddress(address, ss58Format)});75  }7677  withNormalizedSubstrate(ss58Format = 42): CrossAccountId {78    if (this.Substrate) return CrossAccountId.withNormalizedSubstrate(this.Substrate, ss58Format);79    return this;80  }8182  static translateSubToEth(address: TSubstrateAccount): TEthereumAccount {83    return nesting.toChecksumAddress('0x' + Array.from(addressToEvm(address), i => i.toString(16).padStart(2, '0')).join(''));84  }8586  toEthereum(): CrossAccountId {87    if (this.Substrate) return new CrossAccountId({Ethereum: CrossAccountId.translateSubToEth(this.Substrate)});88    return this;89  }9091  static translateEthToSub(address: TEthereumAccount, ss58Format?: number): TSubstrateAccount {92    return evmToAddress(address, ss58Format);93  }9495  toSubstrate(ss58Format?: number): CrossAccountId {96    if (this.Ethereum) return new CrossAccountId({Substrate: CrossAccountId.translateEthToSub(this.Ethereum, ss58Format)});97    return this;98  }99100  toLowerCase(): CrossAccountId {101    if (this.Substrate) this.Substrate = this.Substrate.toLowerCase();102    if (this.Ethereum) this.Ethereum = this.Ethereum.toLowerCase();103    return this;104  }105}106107const nesting = {108  toChecksumAddress(address: string): string {109    if (typeof address === 'undefined') return '';110111    if(!/^(0x)?[0-9a-f]{40}$/i.test(address)) throw new Error(`Given address "${address}" is not a valid Ethereum address.`);112113    address = address.toLowerCase().replace(/^0x/i,'');114    const addressHash = keccakAsHex(address).replace(/^0x/i,'');115    const checksumAddress = ['0x'];116117    for (let i = 0; i < address.length; i++) {118      // If ith character is 8 to f then make it uppercase119      if (parseInt(addressHash[i], 16) > 7) {120        checksumAddress.push(address[i].toUpperCase());121      } else {122        checksumAddress.push(address[i]);123      }124    }125    return checksumAddress.join('');126  },127  tokenIdToAddress(collectionId: number, tokenId: number) {128    return this.toChecksumAddress(`0xf8238ccfff8ed887463fd5e0${collectionId.toString(16).padStart(8, '0')}${tokenId.toString(16).padStart(8, '0')}`);129  },130};131132class UniqueUtil {133  static transactionStatus = {134    NOT_READY: 'NotReady',135    FAIL: 'Fail',136    SUCCESS: 'Success',137  };138139  static chainLogType = {140    EXTRINSIC: 'extrinsic',141    RPC: 'rpc',142  };143144  static getTokenAccount(token: IToken): CrossAccountId {145    return new CrossAccountId({Ethereum: this.getTokenAddress(token)});146  }147148  static getTokenAddress(token: IToken): string {149    return nesting.tokenIdToAddress(token.collectionId, token.tokenId);150  }151152  static getDefaultLogger(): ILogger {153    return {154      log(msg: any, level = 'INFO') {155        console[level.toLocaleLowerCase() === 'error' ? 'error' : 'log'](...(Array.isArray(msg) ? msg : [msg]));156      },157      level: {158        ERROR: 'ERROR',159        WARNING: 'WARNING',160        INFO: 'INFO',161      },162    };163  }164165  static vec2str(arr: string[] | number[]) {166    return arr.map(x => String.fromCharCode(parseInt(x.toString()))).join('');167  }168169  static str2vec(string: string) {170    if (typeof string !== 'string') return string;171    return Array.from(string).map(x => x.charCodeAt(0));172  }173174  static fromSeed(seed: string, ss58Format = 42) {175    const keyring = new Keyring({type: 'sr25519', ss58Format});176    return keyring.addFromUri(seed);177  }178179  static extractCollectionIdFromCreationResult(creationResult: ITransactionResult): number {180    if (creationResult.status !== this.transactionStatus.SUCCESS) {181      throw Error('Unable to create collection!');182    }183184    let collectionId = null;185    creationResult.result.events.forEach(({event: {data, method, section}}) => {186      if ((section === 'common') && (method === 'CollectionCreated')) {187        collectionId = parseInt(data[0].toString(), 10);188      }189    });190191    if (collectionId === null) {192      throw Error('No CollectionCreated event was found!');193    }194195    return collectionId;196  }197198  static extractTokensFromCreationResult(creationResult: ITransactionResult): {199    success: boolean,200    tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],201  } {202    if (creationResult.status !== this.transactionStatus.SUCCESS) {203      throw Error('Unable to create tokens!');204    }205    let success = false;206    const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];207    creationResult.result.events.forEach(({event: {data, method, section}}) => {208      if (method === 'ExtrinsicSuccess') {209        success = true;210      } else if ((section === 'common') && (method === 'ItemCreated')) {211        tokens.push({212          collectionId: parseInt(data[0].toString(), 10),213          tokenId: parseInt(data[1].toString(), 10),214          owner: data[2].toHuman(),215          amount: data[3].toBigInt(),216        });217      }218    });219    return {success, tokens};220  }221222  static extractTokensFromBurnResult(burnResult: ITransactionResult): {223    success: boolean,224    tokens: {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[],225  } {226    if (burnResult.status !== this.transactionStatus.SUCCESS) {227      throw Error('Unable to burn tokens!');228    }229    let success = false;230    const tokens = [] as {collectionId: number, tokenId: number, owner: CrossAccountId, amount: bigint}[];231    burnResult.result.events.forEach(({event: {data, method, section}}) => {232      if (method === 'ExtrinsicSuccess') {233        success = true;234      } else if ((section === 'common') && (method === 'ItemDestroyed')) {235        tokens.push({236          collectionId: parseInt(data[0].toString(), 10),237          tokenId: parseInt(data[1].toString(), 10),238          owner: data[2].toHuman(),239          amount: data[3].toBigInt(),240        });241      }242    });243    return {success, tokens};244  }245246  static findCollectionInEvents(events: {event: IEvent}[], collectionId: number, expectedSection: string, expectedMethod: string): boolean {247    let eventId = null;248    events.forEach(({event: {data, method, section}}) => {249      if ((section === expectedSection) && (method === expectedMethod)) {250        eventId = parseInt(data[0].toString(), 10);251      }252    });253254    if (eventId === null) {255      throw Error(`No ${expectedMethod} event was found!`);256    }257    return eventId === collectionId;258  }259260  static isTokenTransferSuccess(events: {event: IEvent}[], collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {261    const normalizeAddress = (address: string | ICrossAccountId) => {262      if(typeof address === 'string') return address;263      const obj = {} as any;264      Object.keys(address).forEach(k => {265        obj[k.toLocaleLowerCase()] = address[k as 'Substrate' | 'Ethereum'];266      });267      if(obj.substrate) return CrossAccountId.withNormalizedSubstrate(obj.substrate);268      if(obj.ethereum) return CrossAccountId.fromLowerCaseKeys(obj).toLowerCase();269      return address;270    };271    let transfer = {collectionId: null, tokenId: null, from: null, to: null, amount: 1} as any;272    events.forEach(({event: {data, method, section}}) => {273      if ((section === 'common') && (method === 'Transfer')) {274        const hData = (data as any).toJSON();275        transfer = {276          collectionId: hData[0],277          tokenId: hData[1],278          from: normalizeAddress(hData[2]),279          to: normalizeAddress(hData[3]),280          amount: BigInt(hData[4]),281        };282      }283    });284    let isSuccess = parseInt(collectionId.toString()) === transfer.collectionId && parseInt(tokenId.toString()) === transfer.tokenId;285    isSuccess = isSuccess && JSON.stringify(normalizeAddress(fromAddressObj)) === JSON.stringify(transfer.from);286    isSuccess = isSuccess && JSON.stringify(normalizeAddress(toAddressObj)) === JSON.stringify(transfer.to);287    isSuccess = isSuccess && amount === transfer.amount;288    return isSuccess;289  }290291  static bigIntToDecimals(number: bigint, decimals = 18) {292    const numberStr = number.toString();293    const dotPos = numberStr.length - decimals;294295    if (dotPos <= 0) {296      return '0.' + '0'.repeat(Math.abs(dotPos)) + numberStr;297    } else {298      const intPart = numberStr.substring(0, dotPos);299      const fractPart = numberStr.substring(dotPos);300      return intPart + '.' + fractPart;301    }302  }303}304305class UniqueEventHelper {306  private static extractIndex(index: any): [number, number] | string {307    if(index.toRawType() === '[u8;2]') return [index[0], index[1]];308    return index.toJSON();309  }310311  private static extractSub(data: any, subTypes: any): {[key: string]: any} {312    let obj: any = {};313    let index = 0;314315    if (data.entries) {316      for(const [key, value] of data.entries()) {317        obj[key] = this.extractData(value, subTypes[index]);318        index++;319      }320    } else obj = data.toJSON();321322    return obj;323  }324325  private static extractData(data: any, type: any): any {326    if(!type) return data.toHuman();327    if (['u16', 'u32'].indexOf(type.type) > -1) return data.toNumber();328    if (['u64', 'u128', 'u256'].indexOf(type.type) > -1) return data.toBigInt();329    if(type.hasOwnProperty('sub')) return this.extractSub(data, type.sub);330    return data.toHuman();331  }332333  public static extractEvents(events: {event: any, phase: any}[]): IEvent[] {334    const parsedEvents: IEvent[] = [];335336    events.forEach((record) => {337      const {event, phase} = record;338      const types = event.typeDef;339340      const eventData: IEvent = {341        section: event.section.toString(),342        method: event.method.toString(),343        index: this.extractIndex(event.index),344        data: [],345        phase: phase.toJSON(),346      };347348      event.data.forEach((val: any, index: number) => {349        eventData.data.push(this.extractData(val, types[index]));350      });351352      parsedEvents.push(eventData);353    });354355    return parsedEvents;356  }357}358359export class ChainHelperBase {360  helperBase: any;361362  transactionStatus = UniqueUtil.transactionStatus;363  chainLogType = UniqueUtil.chainLogType;364  util: typeof UniqueUtil;365  eventHelper: typeof UniqueEventHelper;366  logger: ILogger;367  api: ApiPromise | null;368  forcedNetwork: TNetworks | null;369  network: TNetworks | null;370  chainLog: IUniqueHelperLog[];371  children: ChainHelperBase[];372  address: AddressGroup;373  chain: ChainGroup;374375  constructor(logger?: ILogger, helperBase?: any) {376    this.helperBase = helperBase;377378    this.util = UniqueUtil;379    this.eventHelper = UniqueEventHelper;380    if (typeof logger == 'undefined') logger = this.util.getDefaultLogger();381    this.logger = logger;382    this.api = null;383    this.forcedNetwork = null;384    this.network = null;385    this.chainLog = [];386    this.children = [];387    this.address = new AddressGroup(this);388    this.chain = new ChainGroup(this);389  }390391  clone(helperCls: ChainHelperBaseConstructor, options: {[key: string]: any} = {}) {392    Object.setPrototypeOf(helperCls.prototype, this);393    const newHelper = new helperCls(this.logger, options);394395    newHelper.api = this.api;396    newHelper.network = this.network;397    newHelper.forceNetwork = this.forceNetwork;398399    this.children.push(newHelper);400401    return newHelper;402  }403404  getApi(): ApiPromise {405    if(this.api === null) throw Error('API not initialized');406    return this.api;407  }408409  async subscribeEvents(expectedEvents: {section: string, names: string[]}[]) {410    const collectedEvents: IEvent[] = [];411    const unsubscribe = await this.getApi().query.system.events((events: Vec<FrameSystemEventRecord>) => {412      const ievents = this.eventHelper.extractEvents(events);413      ievents.forEach((event) => {414        expectedEvents.forEach((e => {415          if (event.section === e.section && e.names.includes(event.method)) {416            collectedEvents.push(event);417          }418        }));419      });420    });421    return {unsubscribe: unsubscribe as any, collectedEvents};422  }423424  clearChainLog(): void {425    this.chainLog = [];426  }427428  forceNetwork(value: TNetworks): void {429    this.forcedNetwork = value;430  }431432  async connect(wsEndpoint: string, listeners?: IApiListeners) {433    if (this.api !== null) throw Error('Already connected');434    const {api, network} = await ChainHelperBase.createConnection(wsEndpoint, listeners, this.forcedNetwork);435    this.api = api;436    this.network = network;437  }438439  async disconnect() {440    for (const child of this.children) {441      child.clearApi();442    }443444    if (this.api === null) return;445    await this.api.disconnect();446    this.clearApi();447  }448449  clearApi() {450    this.api = null;451    this.network = null;452  }453454  static async detectNetwork(api: ApiPromise): Promise<TNetworks> {455    const spec = (await api.query.system.lastRuntimeUpgrade()).toJSON() as any;456    const xcmChains = ['rococo', 'westend', 'westmint', 'acala', 'karura', 'moonbeam', 'moonriver'];457458    if(xcmChains.indexOf(spec.specName) > -1) return spec.specName;459460    if(['quartz', 'unique'].indexOf(spec.specName) > -1) return spec.specName;461    return 'opal';462  }463464  static async detectNetworkByWsEndpoint(wsEndpoint: string): Promise<TNetworks> {465    const api = new ApiPromise({provider: new WsProvider(wsEndpoint)});466    await api.isReady;467468    const network = await this.detectNetwork(api);469470    await api.disconnect();471472    return network;473  }474475  static async createConnection(wsEndpoint: string, listeners?: IApiListeners, network?: TNetworks | null): Promise<{476    api: ApiPromise;477    network: TNetworks;478  }> {479    if(typeof network === 'undefined' || network === null) network = 'opal';480    const supportedRPC = {481      opal: {482        unique: require('@unique-nft/opal-testnet-types/definitions').unique.rpc,483      },484      quartz: {485        unique: require('@unique-nft/quartz-mainnet-types/definitions').unique.rpc,486      },487      unique: {488        unique: require('@unique-nft/unique-mainnet-types/definitions').unique.rpc,489      },490      rococo: {},491      westend: {},492      moonbeam: {},493      moonriver: {},494      acala: {},495      karura: {},496      westmint: {},497    };498    if(!supportedRPC.hasOwnProperty(network)) network = await this.detectNetworkByWsEndpoint(wsEndpoint);499    const rpc = supportedRPC[network];500501    // TODO: investigate how to replace rpc in runtime502    // api._rpcCore.addUserInterfaces(rpc);503504    const api = new ApiPromise({provider: new WsProvider(wsEndpoint), rpc});505506    await api.isReadyOrError;507508    if (typeof listeners === 'undefined') listeners = {};509    for (const event of ['connected', 'disconnected', 'error', 'ready', 'decorated']) {510      if (!listeners.hasOwnProperty(event) || typeof listeners[event as TApiAllowedListeners] === 'undefined') continue;511      api.on(event as ApiInterfaceEvents, listeners[event as TApiAllowedListeners] as (...args: any[]) => any);512    }513514    return {api, network};515  }516517  getTransactionStatus(data: {events: {event: IEvent}[], status: any}) {518    const {events, status} = data;519    if (status.isReady) {520      return this.transactionStatus.NOT_READY;521    }522    if (status.isBroadcast) {523      return this.transactionStatus.NOT_READY;524    }525    if (status.isInBlock || status.isFinalized) {526      const errors = events.filter(e => e.event.method === 'ExtrinsicFailed');527      if (errors.length > 0) {528        return this.transactionStatus.FAIL;529      }530      if (events.filter(e => e.event.method === 'ExtrinsicSuccess').length > 0) {531        return this.transactionStatus.SUCCESS;532      }533    }534535    return this.transactionStatus.FAIL;536  }537538  signTransaction(sender: TSigner, transaction: any, options: Partial<SignerOptions> | null = null, label = 'transaction') {539    const sign = (callback: any) => {540      if(options !== null) return transaction.signAndSend(sender, options, callback);541      return transaction.signAndSend(sender, callback);542    };543    // eslint-disable-next-line no-async-promise-executor544    return new Promise(async (resolve, reject) => {545      try {546        const unsub = await sign((result: any) => {547          const status = this.getTransactionStatus(result);548549          if (status === this.transactionStatus.SUCCESS) {550            this.logger.log(`${label} successful`);551            unsub();552            resolve({result, status});553          } else if (status === this.transactionStatus.FAIL) {554            let moduleError = null;555556            if (result.hasOwnProperty('dispatchError')) {557              const dispatchError = result['dispatchError'];558559              if (dispatchError) {560                if (dispatchError.isModule) {561                  const modErr = dispatchError.asModule;562                  const errorMeta = dispatchError.registry.findMetaError(modErr);563564                  moduleError = `${errorMeta.section}.${errorMeta.name}`;565                } else {566                  moduleError = dispatchError.toHuman();567                }568              } else {569                this.logger.log(result, this.logger.level.ERROR);570              }571            }572573            this.logger.log(`Something went wrong with ${label}. Status: ${status}`, this.logger.level.ERROR);574            unsub();575            reject({status, moduleError, result});576          }577        });578      } catch (e) {579        this.logger.log(e, this.logger.level.ERROR);580        reject(e);581      }582    });583  }584585  async getPaymentInfo(signer: TSigner, tx: any, len: number | null) {586    const api = this.getApi();587    const signingInfo = await api.derive.tx.signingInfo(signer.address);588589    // We need to sign the tx because590    // unsigned transactions does not have an inclusion fee591    tx.sign(signer, {592      blockHash: api.genesisHash,593      genesisHash: api.genesisHash,594      runtimeVersion: api.runtimeVersion,595      nonce: signingInfo.nonce,596    });597598    if (len === null) {599      return (await this.callRpc('api.rpc.payment.queryInfo', [tx.toHex()])) as RuntimeDispatchInfo;600    } else {601      return (await api.call.transactionPaymentApi.queryInfo(tx, len)) as RuntimeDispatchInfo;602    }603  }604605  constructApiCall(apiCall: string, params: any[]) {606    if(!apiCall.startsWith('api.')) throw Error(`Invalid api call: ${apiCall}`);607    let call = this.getApi() as any;608    for(const part of apiCall.slice(4).split('.')) {609      call = call[part];610    }611    return call(...params);612  }613614  async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {615    if(this.api === null) throw Error('API not initialized');616    if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);617618    const startTime = (new Date()).getTime();619    let result: ITransactionResult;620    let events: IEvent[] = [];621    try {622      result = await this.signTransaction(sender, this.constructApiCall(extrinsic, params), options, extrinsic) as ITransactionResult;623      events = this.eventHelper.extractEvents(result.result.events);624    }625    catch(e) {626      if(!(e as object).hasOwnProperty('status')) throw e;627      result = e as ITransactionResult;628    }629630    const endTime = (new Date()).getTime();631632    const log = {633      executedAt: endTime,634      executionTime: endTime - startTime,635      type: this.chainLogType.EXTRINSIC,636      status: result.status,637      call: extrinsic,638      signer: this.getSignerAddress(sender),639      params,640    } as IUniqueHelperLog;641642    if(result.status !== this.transactionStatus.SUCCESS) {643      if (result.moduleError) log.moduleError = result.moduleError;644      else if (result.result.dispatchError) log.dispatchError = result.result.dispatchError;645    }646    if(events.length > 0) log.events = events;647648    this.chainLog.push(log);649650    if(expectSuccess && result.status !== this.transactionStatus.SUCCESS) {651      if (result.moduleError) throw Error(`${result.moduleError}`);652      else if (result.result.dispatchError) throw Error(JSON.stringify(result.result.dispatchError));653    }654    return result;655  }656657  async callRpc(rpc: string, params?: any[]) {658    if(typeof params === 'undefined') params = [];659    if(this.api === null) throw Error('API not initialized');660    if(!rpc.startsWith('api.rpc.') && !rpc.startsWith('api.query.')) throw Error(`${rpc} is not RPC call`);661662    const startTime = (new Date()).getTime();663    let result;664    let error = null;665    const log = {666      type: this.chainLogType.RPC,667      call: rpc,668      params,669    } as IUniqueHelperLog;670671    try {672      result = await this.constructApiCall(rpc, params);673    }674    catch(e) {675      error = e;676    }677678    const endTime = (new Date()).getTime();679680    log.executedAt = endTime;681    log.status = (error === null ? this.transactionStatus.SUCCESS : this.transactionStatus.FAIL) as 'Fail' | 'Success';682    log.executionTime = endTime - startTime;683684    this.chainLog.push(log);685686    if(error !== null) throw error;687688    return result;689  }690691  getSignerAddress(signer: IKeyringPair | string): string {692    if(typeof signer === 'string') return signer;693    return signer.address;694  }695696  fetchAllPalletNames(): string[] {697    if(this.api === null) throw Error('API not initialized');698    return this.api.runtimeMetadata.asLatest.pallets.map(m => m.name.toString().toLowerCase());699  }700701  fetchMissingPalletNames(requiredPallets: string[]): string[] {702    const palletNames = this.fetchAllPalletNames();703    return requiredPallets.filter(p => !palletNames.includes(p));704  }705}706707708class HelperGroup<T extends ChainHelperBase> {709  helper: T;710711  constructor(uniqueHelper: T) {712    this.helper = uniqueHelper;713  }714}715716717class CollectionGroup extends HelperGroup<UniqueHelper> {718  /**719 * Get number of blocks when sponsored transaction is available.720 *721 * @param collectionId ID of collection722 * @param tokenId ID of token723 * @param addressObj address for which the sponsorship is checked724 * @example await getTokenNextSponsored(1, 2, {Substrate: '5DfhbVfww7ThF8q6f3...'});725 * @returns number of blocks or null if sponsorship hasn't been set726 */727  async getTokenNextSponsored(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<number | null> {728    return (await this.helper.callRpc('api.rpc.unique.nextSponsored', [collectionId, addressObj, tokenId])).toJSON();729  }730731  /**732   * Get the number of created collections.733   *734   * @returns number of created collections735   */736  async getTotalCount(): Promise<number> {737    return (await this.helper.callRpc('api.rpc.unique.collectionStats')).created.toNumber();738  }739740  /**741   * Get information about the collection with additional data,742   * including the number of tokens it contains, its administrators,743   * the normalized address of the collection's owner, and decoded name and description.744   *745   * @param collectionId ID of collection746   * @example await getData(2)747   * @returns collection information object748   */749  async getData(collectionId: number): Promise<{750    id: number;751    name: string;752    description: string;753    tokensCount: number;754    admins: CrossAccountId[];755    normalizedOwner: TSubstrateAccount;756    raw: any757  } | null> {758    const collection = await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId]);759    const humanCollection = collection.toHuman(), collectionData = {760      id: collectionId, name: null, description: null, tokensCount: 0, admins: [],761      raw: humanCollection,762    } as any, jsonCollection = collection.toJSON();763    if (humanCollection === null) return null;764    collectionData.raw.limits = jsonCollection.limits;765    collectionData.raw.permissions = jsonCollection.permissions;766    collectionData.normalizedOwner = this.helper.address.normalizeSubstrate(collectionData.raw.owner);767    for (const key of ['name', 'description']) {768      collectionData[key] = this.helper.util.vec2str(humanCollection[key]);769    }770771    collectionData.tokensCount = (['RFT', 'NFT'].includes(humanCollection.mode))772      ? await this.helper[humanCollection.mode.toLocaleLowerCase() as 'nft' | 'rft'].getLastTokenId(collectionId)773      : 0;774    collectionData.admins = await this.getAdmins(collectionId);775776    return collectionData;777  }778779  /**780   * Get the addresses of the collection's administrators, optionally normalized.781   *782   * @param collectionId ID of collection783   * @param normalize whether to normalize the addresses to the default ss58 format784   * @example await getAdmins(1)785   * @returns array of administrators786   */787  async getAdmins(collectionId: number, normalize = false): Promise<CrossAccountId[]> {788    const admins = (await this.helper.callRpc('api.rpc.unique.adminlist', [collectionId])).toHuman();789790    return normalize791      ? admins.map((address: CrossAccountId) => address.withNormalizedSubstrate())792      : admins;793  }794795  /**796   * Get the addresses added to the collection allow-list, optionally normalized.797   * @param collectionId ID of collection798   * @param normalize whether to normalize the addresses to the default ss58 format799   * @example await getAllowList(1)800   * @returns array of allow-listed addresses801   */802  async getAllowList(collectionId: number, normalize = false): Promise<CrossAccountId[]> {803    const allowListed = (await this.helper.callRpc('api.rpc.unique.allowlist', [collectionId])).toHuman();804    return normalize805      ? allowListed.map((address: CrossAccountId) => address.withNormalizedSubstrate())806      : allowListed;807  }808809  /**810   * Get the effective limits of the collection instead of null for default values811   *812   * @param collectionId ID of collection813   * @example await getEffectiveLimits(2)814   * @returns object of collection limits815   */816  async getEffectiveLimits(collectionId: number): Promise<ICollectionLimits> {817    return (await this.helper.callRpc('api.rpc.unique.effectiveCollectionLimits', [collectionId])).toJSON();818  }819820  /**821   * Burns the collection if the signer has sufficient permissions and collection is empty.822   *823   * @param signer keyring of signer824   * @param collectionId ID of collection825   * @example await helper.collection.burn(aliceKeyring, 3);826   * @returns ```true``` if extrinsic success, otherwise ```false```827   */828  async burn(signer: TSigner, collectionId: number): Promise<boolean> {829    const result = await this.helper.executeExtrinsic(830      signer,831      'api.tx.unique.destroyCollection', [collectionId],832      true,833    );834835    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionDestroyed');836  }837838  /**839   * Sets the sponsor for the collection (Requires the Substrate address). Needs confirmation by the sponsor.840   *841   * @param signer keyring of signer842   * @param collectionId ID of collection843   * @param sponsorAddress Sponsor substrate address844   * @example setSponsor(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")845   * @returns ```true``` if extrinsic success, otherwise ```false```846   */847  async setSponsor(signer: TSigner, collectionId: number, sponsorAddress: TSubstrateAccount): Promise<boolean> {848    const result = await this.helper.executeExtrinsic(849      signer,850      'api.tx.unique.setCollectionSponsor', [collectionId, sponsorAddress],851      true,852    );853854    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorSet');855  }856857  /**858   * Confirms consent to sponsor the collection on behalf of the signer.859   *860   * @param signer keyring of signer861   * @param collectionId ID of collection862   * @example confirmSponsorship(aliceKeyring, 10)863   * @returns ```true``` if extrinsic success, otherwise ```false```864   */865  async confirmSponsorship(signer: TSigner, collectionId: number): Promise<boolean> {866    const result = await this.helper.executeExtrinsic(867      signer,868      'api.tx.unique.confirmSponsorship', [collectionId],869      true,870    );871872    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'SponsorshipConfirmed');873  }874875  /**876   * Removes the sponsor of a collection, regardless if it consented or not.877   *878   * @param signer keyring of signer879   * @param collectionId ID of collection880   * @example removeSponsor(aliceKeyring, 10)881   * @returns ```true``` if extrinsic success, otherwise ```false```882   */883  async removeSponsor(signer: TSigner, collectionId: number): Promise<boolean> {884    const result = await this.helper.executeExtrinsic(885      signer,886      'api.tx.unique.removeCollectionSponsor', [collectionId],887      true,888    );889890    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionSponsorRemoved');891  }892893  /**894   * Sets the limits of the collection. At least one limit must be specified for a correct call.895   *896   * @param signer keyring of signer897   * @param collectionId ID of collection898   * @param limits collection limits object899   * @example900   * await setLimits(901   *   aliceKeyring,902   *   10,903   *   {904   *     sponsorTransferTimeout: 0,905   *     ownerCanDestroy: false906   *   }907   * )908   * @returns ```true``` if extrinsic success, otherwise ```false```909   */910  async setLimits(signer: TSigner, collectionId: number, limits: ICollectionLimits): Promise<boolean> {911    const result = await this.helper.executeExtrinsic(912      signer,913      'api.tx.unique.setCollectionLimits', [collectionId, limits],914      true,915    );916917    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionLimitSet');918  }919920  /**921   * Changes the owner of the collection to the new Substrate address.922   *923   * @param signer keyring of signer924   * @param collectionId ID of collection925   * @param ownerAddress substrate address of new owner926   * @example changeOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...")927   * @returns ```true``` if extrinsic success, otherwise ```false```928   */929  async changeOwner(signer: TSigner, collectionId: number, ownerAddress: TSubstrateAccount): Promise<boolean> {930    const result = await this.helper.executeExtrinsic(931      signer,932      'api.tx.unique.changeCollectionOwner', [collectionId, ownerAddress],933      true,934    );935936    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionOwnerChanged');937  }938939  /**940   * Adds a collection administrator.941   *942   * @param signer keyring of signer943   * @param collectionId ID of collection944   * @param adminAddressObj Administrator address (substrate or ethereum)945   * @example addAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})946   * @returns ```true``` if extrinsic success, otherwise ```false```947   */948  async addAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {949    const result = await this.helper.executeExtrinsic(950      signer,951      'api.tx.unique.addCollectionAdmin', [collectionId, adminAddressObj],952      true,953    );954955    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminAdded');956  }957958  /**959   * Removes a collection administrator.960   *961   * @param signer keyring of signer962   * @param collectionId ID of collection963   * @param adminAddressObj Administrator address (substrate or ethereum)964   * @example removeAdmin(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."})965   * @returns ```true``` if extrinsic success, otherwise ```false```966   */967  async removeAdmin(signer: TSigner, collectionId: number, adminAddressObj: ICrossAccountId): Promise<boolean> {968    const result = await this.helper.executeExtrinsic(969      signer,970      'api.tx.unique.removeCollectionAdmin', [collectionId, adminAddressObj],971      true,972    );973974    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionAdminRemoved');975  }976977  /**978   * Check if user is in allow list.979   *980   * @param collectionId ID of collection981   * @param user Account to check982   * @example await getAdmins(1)983   * @returns is user in allow list984   */985  async allowed(collectionId: number, user: ICrossAccountId): Promise<boolean> {986    return (await this.helper.callRpc('api.rpc.unique.allowed', [collectionId, user])).toJSON();987  }988989  /**990   * Adds an address to allow list991   * @param signer keyring of signer992   * @param collectionId ID of collection993   * @param addressObj address to add to the allow list994   * @returns ```true``` if extrinsic success, otherwise ```false```995   */996  async addToAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {997    const result = await this.helper.executeExtrinsic(998      signer,999      'api.tx.unique.addToAllowList', [collectionId, addressObj],1000      true,1001    );10021003    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressAdded');1004  }10051006  /**1007   * Removes an address from allow list1008   *1009   * @param signer keyring of signer1010   * @param collectionId ID of collection1011   * @param addressObj address to remove from the allow list1012   * @returns ```true``` if extrinsic success, otherwise ```false```1013   */1014  async removeFromAllowList(signer: TSigner, collectionId: number, addressObj: ICrossAccountId): Promise<boolean> {1015    const result = await this.helper.executeExtrinsic(1016      signer,1017      'api.tx.unique.removeFromAllowList', [collectionId, addressObj],1018      true,1019    );10201021    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'AllowListAddressRemoved');1022  }10231024  /**1025   * Sets onchain permissions for selected collection.1026   *1027   * @param signer keyring of signer1028   * @param collectionId ID of collection1029   * @param permissions collection permissions object1030   * @example setPermissions(aliceKeyring, 10, {access:'AllowList', mintMode: true, nesting: {collectionAdmin: true, tokenOwner: true}});1031   * @returns ```true``` if extrinsic success, otherwise ```false```1032   */1033  async setPermissions(signer: TSigner, collectionId: number, permissions: ICollectionPermissions): Promise<boolean> {1034    const result = await this.helper.executeExtrinsic(1035      signer,1036      'api.tx.unique.setCollectionPermissions', [collectionId, permissions],1037      true,1038    );10391040    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPermissionSet');1041  }10421043  /**1044   * Enables nesting for selected collection. If `restricted` set, you can nest only tokens from specified collections.1045   *1046   * @param signer keyring of signer1047   * @param collectionId ID of collection1048   * @param permissions nesting permissions object1049   * @example enableNesting(aliceKeyring, 10, {collectionAdmin: true, tokenOwner: true});1050   * @returns ```true``` if extrinsic success, otherwise ```false```1051   */1052  async enableNesting(signer: TSigner, collectionId: number, permissions: INestingPermissions): Promise<boolean> {1053    return await this.setPermissions(signer, collectionId, {nesting: permissions});1054  }10551056  /**1057   * Disables nesting for selected collection.1058   *1059   * @param signer keyring of signer1060   * @param collectionId ID of collection1061   * @example disableNesting(aliceKeyring, 10);1062   * @returns ```true``` if extrinsic success, otherwise ```false```1063   */1064  async disableNesting(signer: TSigner, collectionId: number): Promise<boolean> {1065    return await this.setPermissions(signer, collectionId, {nesting: {tokenOwner: false, collectionAdmin: false}});1066  }10671068  /**1069   * Sets onchain properties to the collection.1070   *1071   * @param signer keyring of signer1072   * @param collectionId ID of collection1073   * @param properties array of property objects1074   * @example setProperties(aliceKeyring, 10, [{key: "gender", value: "male"}]);1075   * @returns ```true``` if extrinsic success, otherwise ```false```1076   */1077  async setProperties(signer: TSigner, collectionId: number, properties: IProperty[]): Promise<boolean> {1078    const result = await this.helper.executeExtrinsic(1079      signer,1080      'api.tx.unique.setCollectionProperties', [collectionId, properties],1081      true,1082    );10831084    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertySet');1085  }10861087  /**1088   * Get collection properties.1089   *1090   * @param collectionId ID of collection1091   * @param propertyKeys optionally filter the returned properties to only these keys1092   * @example getProperties(1219, ['location', 'date', 'time', 'isParadise']);1093   * @returns array of key-value pairs1094   */1095  async getProperties(collectionId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1096    return (await this.helper.callRpc('api.rpc.unique.collectionProperties', [collectionId, propertyKeys])).toHuman();1097  }10981099  async getCollectionOptions(collectionId: number) {1100    return (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1101  }11021103  /**1104   * Deletes onchain properties from the collection.1105   *1106   * @param signer keyring of signer1107   * @param collectionId ID of collection1108   * @param propertyKeys array of property keys to delete1109   * @example deleteProperties(aliceKeyring, 10, ["gender", "age"]);1110   * @returns ```true``` if extrinsic success, otherwise ```false```1111   */1112  async deleteProperties(signer: TSigner, collectionId: number, propertyKeys: string[]): Promise<boolean> {1113    const result = await this.helper.executeExtrinsic(1114      signer,1115      'api.tx.unique.deleteCollectionProperties', [collectionId, propertyKeys],1116      true,1117    );11181119    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'CollectionPropertyDeleted');1120  }11211122  /**1123   * Changes the owner of the token.1124   *1125   * @param signer keyring of signer1126   * @param collectionId ID of collection1127   * @param tokenId ID of token1128   * @param addressObj address of a new owner1129   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1130   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1131   * @returns true if the token success, otherwise false1132   */1133  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1134    const result = await this.helper.executeExtrinsic(1135      signer,1136      'api.tx.unique.transfer', [addressObj, collectionId, tokenId, amount],1137      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1138    );11391140    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, {Substrate: typeof signer === 'string' ? signer : signer.address}, addressObj, amount);1141  }11421143  /**1144   *1145   * Change ownership of a token(s) on behalf of the owner.1146   *1147   * @param signer keyring of signer1148   * @param collectionId ID of collection1149   * @param tokenId ID of token1150   * @param fromAddressObj address on behalf of which the token will be sent1151   * @param toAddressObj new token owner1152   * @param amount amount of tokens to be transfered. For NFT must be set to 1n1153   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg"}, {Ethereum: "0x9F0583DbB85..."})1154   * @returns true if the token success, otherwise false1155   */1156  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1157    const result = await this.helper.executeExtrinsic(1158      signer,1159      'api.tx.unique.transferFrom', [fromAddressObj, toAddressObj, collectionId, tokenId, amount],1160      true, // `Unable to transfer token #${tokenId} from collection #${collectionId}`,1161    );1162    return this.helper.util.isTokenTransferSuccess(result.result.events, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1163  }11641165  /**1166   *1167   * Destroys a concrete instance of NFT/RFT or burns a specified amount of fungible tokens.1168   *1169   * @param signer keyring of signer1170   * @param collectionId ID of collection1171   * @param tokenId ID of token1172   * @param amount amount of tokens to be burned. For NFT must be set to 1n1173   * @example burnToken(aliceKeyring, 10, 5);1174   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1175   */1176  async burnToken(signer: TSigner, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1177    const burnResult = await this.helper.executeExtrinsic(1178      signer,1179      'api.tx.unique.burnItem', [collectionId, tokenId, amount],1180      true, // `Unable to burn token for ${label}`,1181    );1182    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1183    if (burnedTokens.tokens.length > 1) throw Error('Burned multiple tokens');1184    return burnedTokens.success;1185  }11861187  /**1188   * Destroys a concrete instance of NFT on behalf of the owner1189   *1190   * @param signer keyring of signer1191   * @param collectionId ID of collection1192   * @param tokenId ID of token1193   * @param fromAddressObj address on behalf of which the token will be burnt1194   * @param amount amount of tokens to be burned. For NFT must be set to 1n1195   * @example burnTokenFrom(aliceKeyring, 10, {Substrate: "5DyN4Y92vZCjv38fg..."}, 5, {Ethereum: "0x9F0583DbB85..."})1196   * @returns ```true``` if extrinsic success, otherwise ```false```1197   */1198  async burnTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1199    const burnResult = await this.helper.executeExtrinsic(1200      signer,1201      'api.tx.unique.burnFrom', [collectionId, fromAddressObj, tokenId, amount],1202      true, // `Unable to burn token from for ${label}`,1203    );1204    const burnedTokens = this.helper.util.extractTokensFromBurnResult(burnResult);1205    return burnedTokens.success && burnedTokens.tokens.length > 0;1206  }12071208  /**1209   * Set, change, or remove approved address to transfer the ownership of the NFT.1210   *1211   * @param signer keyring of signer1212   * @param collectionId ID of collection1213   * @param tokenId ID of token1214   * @param toAddressObj Substrate or Ethereum address which gets approved use of the signer's tokens1215   * @param amount amount of token to be approved. For NFT must be set to 1n1216   * @returns ```true``` if extrinsic success, otherwise ```false```1217   */1218  async approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1219    const approveResult = await this.helper.executeExtrinsic(1220      signer,1221      'api.tx.unique.approve', [toAddressObj, collectionId, tokenId, amount],1222      true, // `Unable to approve token for ${label}`,1223    );12241225    return this.helper.util.findCollectionInEvents(approveResult.result.events, collectionId, 'common', 'Approved');1226  }12271228  /**1229   * Get the amount of token pieces approved to transfer or burn. Normally 0.1230   *1231   * @param collectionId ID of collection1232   * @param tokenId ID of token1233   * @param toAccountObj address which is approved to use token pieces1234   * @param fromAccountObj address which may have allowed the use of its owned tokens1235   * @example getTokenApprovedPieces(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5ERZNF88Mm7UGfPP3mdG..."})1236   * @returns number of approved to transfer pieces1237   */1238  async getTokenApprovedPieces(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId, fromAccountObj: ICrossAccountId): Promise<bigint> {1239    return (await this.helper.callRpc('api.rpc.unique.allowance', [collectionId, fromAccountObj, toAccountObj, tokenId])).toBigInt();1240  }12411242  /**1243   * Get the last created token ID in a collection1244   *1245   * @param collectionId ID of collection1246   * @example getLastTokenId(10);1247   * @returns id of the last created token1248   */1249  async getLastTokenId(collectionId: number): Promise<number> {1250    return (await this.helper.callRpc('api.rpc.unique.lastTokenId', [collectionId])).toNumber();1251  }12521253  /**1254   * Check if token exists1255   *1256   * @param collectionId ID of collection1257   * @param tokenId ID of token1258   * @example doesTokenExist(10, 20);1259   * @returns true if the token exists, otherwise false1260   */1261  async doesTokenExist(collectionId: number, tokenId: number): Promise<boolean> {1262    return (await this.helper.callRpc('api.rpc.unique.tokenExists', [collectionId, tokenId])).toJSON();1263  }1264}12651266class NFTnRFT extends CollectionGroup {1267  /**1268   * Get tokens owned by account1269   *1270   * @param collectionId ID of collection1271   * @param addressObj tokens owner1272   * @example getTokensByAddress(10, {Substrate: "5DyN4Y92vZCjv38fg..."})1273   * @returns array of token ids owned by account1274   */1275  async getTokensByAddress(collectionId: number, addressObj: ICrossAccountId): Promise<number[]> {1276    return (await this.helper.callRpc('api.rpc.unique.accountTokens', [collectionId, addressObj])).toJSON();1277  }12781279  /**1280   * Get token data1281   *1282   * @param collectionId ID of collection1283   * @param tokenId ID of token1284   * @param propertyKeys optionally filter the token properties to only these keys1285   * @param blockHashAt optionally query the data at some block with this hash1286   * @example getToken(10, 5);1287   * @returns human readable token data1288   */1289  async getToken(collectionId: number, tokenId: number, propertyKeys: string[] = [], blockHashAt?: string): Promise<{1290    properties: IProperty[];1291    owner: CrossAccountId;1292    normalizedOwner: CrossAccountId;1293  }| null> {1294    let tokenData;1295    if(typeof blockHashAt === 'undefined') {1296      tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId]);1297    }1298    else {1299      if(propertyKeys.length == 0) {1300        const collection = (await this.helper.callRpc('api.rpc.unique.collectionById', [collectionId])).toHuman();1301        if(!collection) return null;1302        propertyKeys = collection.tokenPropertyPermissions.map((x: ITokenPropertyPermission) => x.key);1303      }1304      tokenData = await this.helper.callRpc('api.rpc.unique.tokenData', [collectionId, tokenId, propertyKeys, blockHashAt]);1305    }1306    tokenData = tokenData.toHuman();1307    if (tokenData === null || tokenData.owner === null) return null;1308    const owner = {} as any;1309    for (const key of Object.keys(tokenData.owner)) {1310      owner[key.toLocaleLowerCase()] = key.toLocaleLowerCase() == 'substrate'1311        ? CrossAccountId.normalizeSubstrateAddress(tokenData.owner[key])1312        : tokenData.owner[key];1313    }1314    tokenData.normalizedOwner = CrossAccountId.fromLowerCaseKeys(owner);1315    return tokenData;1316  }13171318  /**1319   * Set permissions to change token properties1320   *1321   * @param signer keyring of signer1322   * @param collectionId ID of collection1323   * @param permissions permissions to change a property by the collection admin or token owner1324   * @example setTokenPropertyPermissions(1325   *   aliceKeyring, 10, [{key: "gender", permission: {tokenOwner: true, mutable: true, collectionAdmin: true}}]1326   * )1327   * @returns true if extrinsic success otherwise false1328   */1329  async setTokenPropertyPermissions(signer: TSigner, collectionId: number, permissions: ITokenPropertyPermission[]): Promise<boolean> {1330    const result = await this.helper.executeExtrinsic(1331      signer,1332      'api.tx.unique.setTokenPropertyPermissions', [collectionId, permissions],1333      true,1334    );13351336    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'PropertyPermissionSet');1337  }13381339  /**1340   * Get token property permissions.1341   *1342   * @param collectionId ID of collection1343   * @param propertyKeys optionally filter the returned property permissions to only these keys1344   * @example getPropertyPermissions(1219, ['location', 'date', 'time', 'isParadise']);1345   * @returns array of key-permission pairs1346   */1347  async getPropertyPermissions(collectionId: number, propertyKeys: string[] | null = null): Promise<ITokenPropertyPermission[]> {1348    return (await this.helper.callRpc('api.rpc.unique.propertyPermissions', [collectionId, ...(propertyKeys === null ? [] : [propertyKeys])])).toHuman();1349  }13501351  /**1352   * Set token properties1353   *1354   * @param signer keyring of signer1355   * @param collectionId ID of collection1356   * @param tokenId ID of token1357   * @param properties key-value pairs of metadata which to add to a token. Keys must be permitted in the collection1358   * @example setTokenProperties(aliceKeyring, 10, 5, [{key: "gender", value: "female"}, {key: "age", value: "23"}])1359   * @returns ```true``` if extrinsic success, otherwise ```false```1360   */1361  async setTokenProperties(signer: TSigner, collectionId: number, tokenId: number, properties: IProperty[]): Promise<boolean> {1362    const result = await this.helper.executeExtrinsic(1363      signer,1364      'api.tx.unique.setTokenProperties', [collectionId, tokenId, properties],1365      true,1366    );13671368    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertySet');1369  }13701371  /**1372   * Get properties, metadata assigned to a token.1373   *1374   * @param collectionId ID of collection1375   * @param tokenId ID of token1376   * @param propertyKeys optionally filter the returned properties to only these keys1377   * @example getTokenProperties(1219, ['location', 'date', 'time', 'isParadise']);1378   * @returns array of key-value pairs1379   */1380  async getTokenProperties(collectionId: number, tokenId: number, propertyKeys?: string[] | null): Promise<IProperty[]> {1381    return (await this.helper.callRpc('api.rpc.unique.tokenProperties', [collectionId, tokenId, propertyKeys])).toHuman();1382  }13831384  /**1385   * Delete the provided properties of a token1386   * @param signer keyring of signer1387   * @param collectionId ID of collection1388   * @param tokenId ID of token1389   * @param propertyKeys property keys to be deleted1390   * @example deleteTokenProperties(aliceKeyring, 10, 5, ["gender", "age"])1391   * @returns ```true``` if extrinsic success, otherwise ```false```1392   */1393  async deleteTokenProperties(signer: TSigner, collectionId: number, tokenId: number, propertyKeys: string[]): Promise<boolean> {1394    const result = await this.helper.executeExtrinsic(1395      signer,1396      'api.tx.unique.deleteTokenProperties', [collectionId, tokenId, propertyKeys],1397      true,1398    );13991400    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'TokenPropertyDeleted');1401  }14021403  /**1404   * Mint new collection1405   *1406   * @param signer keyring of signer1407   * @param collectionOptions basic collection options and properties1408   * @param mode NFT or RFT type of a collection1409   * @example mintCollection(aliceKeyring, {name: 'New', description: "New collection", tokenPrefix: "NEW"}, "NFT")1410   * @returns object of the created collection1411   */1412  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions, mode: 'NFT' | 'RFT'): Promise<UniqueBaseCollection> {1413    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1414    collectionOptions.mode = (mode === 'NFT') ? {nft: null} : {refungible: null};1415    for (const key of ['name', 'description', 'tokenPrefix']) {1416      if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1417    }1418    const creationResult = await this.helper.executeExtrinsic(1419      signer,1420      'api.tx.unique.createCollectionEx', [collectionOptions],1421      true, // errorLabel,1422    );1423    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1424  }14251426  getCollectionObject(_collectionId: number): any {1427    return null;1428  }14291430  getTokenObject(_collectionId: number, _tokenId: number): any {1431    return null;1432  }14331434  /**1435   * Tells whether the given `owner` approves the `operator`.1436   * @param collectionId ID of collection1437   * @param owner owner address1438   * @param operator operator addrees1439   * @returns true if operator is enabled1440   */1441  async allowanceForAll(collectionId: number, owner: ICrossAccountId, operator: ICrossAccountId): Promise<boolean> {1442    return (await this.helper.callRpc('api.rpc.unique.allowanceForAll', [collectionId, owner, operator])).toJSON();1443  }14441445  /** Sets or unsets the approval of a given operator.1446   *  The `operator` is allowed to transfer all tokens of the `caller` on their behalf.1447   *  @param operator Operator1448   *  @param approved Should operator status be granted or revoked?1449   *  @returns ```true``` if extrinsic success, otherwise ```false```1450   */1451  async setAllowanceForAll(signer: TSigner, collectionId: number, operator: ICrossAccountId, approved: boolean): Promise<boolean> {1452    const result = await this.helper.executeExtrinsic(1453      signer,1454      'api.tx.unique.setAllowanceForAll', [collectionId, operator, approved],1455      true,1456    );1457    return this.helper.util.findCollectionInEvents(result.result.events, collectionId, 'common', 'ApprovedForAll');1458  }1459}146014611462class NFTGroup extends NFTnRFT {1463  /**1464   * Get collection object1465   * @param collectionId ID of collection1466   * @example getCollectionObject(2);1467   * @returns instance of UniqueNFTCollection1468   */1469  getCollectionObject(collectionId: number): UniqueNFTCollection {1470    return new UniqueNFTCollection(collectionId, this.helper);1471  }14721473  /**1474   * Get token object1475   * @param collectionId ID of collection1476   * @param tokenId ID of token1477   * @example getTokenObject(10, 5);1478   * @returns instance of UniqueNFTToken1479   */1480  getTokenObject(collectionId: number, tokenId: number): UniqueNFToken {1481    return new UniqueNFToken(tokenId, this.getCollectionObject(collectionId));1482  }14831484  /**1485   * Get token's owner1486   * @param collectionId ID of collection1487   * @param tokenId ID of token1488   * @param blockHashAt optionally query the data at the block with this hash1489   * @example getTokenOwner(10, 5);1490   * @returns Address in CrossAccountId format, e.g. {Substrate: "5DnSF6RRjwteE3BrCj..."}1491   */1492  async getTokenOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId> {1493    let owner;1494    if (typeof blockHashAt === 'undefined') {1495      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId]);1496    } else {1497      owner = await this.helper.callRpc('api.rpc.unique.tokenOwner', [collectionId, tokenId, blockHashAt]);1498    }1499    return CrossAccountId.fromLowerCaseKeys(owner.toJSON());1500  }15011502  /**1503   * Is token approved to transfer1504   * @param collectionId ID of collection1505   * @param tokenId ID of token1506   * @param toAccountObj address to be approved1507   * @returns ```true``` if extrinsic success, otherwise ```false```1508   */1509  async isTokenApproved(collectionId: number, tokenId: number, toAccountObj: ICrossAccountId): Promise<boolean> {1510    return (await this.getTokenApprovedPieces(collectionId, tokenId, toAccountObj, await this.getTokenOwner(collectionId, tokenId))) === 1n;1511  }15121513  /**1514   * Changes the owner of the token.1515   *1516   * @param signer keyring of signer1517   * @param collectionId ID of collection1518   * @param tokenId ID of token1519   * @param addressObj address of a new owner1520   * @example transferToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1521   * @returns ```true``` if extrinsic success, otherwise ```false```1522   */1523  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<boolean> {1524    return await super.transferToken(signer, collectionId, tokenId, addressObj, 1n);1525  }15261527  /**1528   *1529   * Change ownership of a NFT on behalf of the owner.1530   *1531   * @param signer keyring of signer1532   * @param collectionId ID of collection1533   * @param tokenId ID of token1534   * @param fromAddressObj address on behalf of which the token will be sent1535   * @param toAddressObj new token owner1536   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Ethereum: "0x9F0583DbB85..."})1537   * @returns ```true``` if extrinsic success, otherwise ```false```1538   */1539  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId): Promise<boolean> {1540    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, 1n);1541  }15421543  /**1544   * Recursively find the address that owns the token1545   * @param collectionId ID of collection1546   * @param tokenId ID of token1547   * @param blockHashAt1548   * @example getTokenTopmostOwner(10, 5);1549   * @returns address in CrossAccountId format, e.g. {Substrate: "5DyN4Y92vZCjv38fg..."}1550   */1551  async getTokenTopmostOwner(collectionId: number, tokenId: number, blockHashAt?: string): Promise<CrossAccountId | null> {1552    let owner;1553    if (typeof blockHashAt === 'undefined') {1554      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId]);1555    } else {1556      owner = await this.helper.callRpc('api.rpc.unique.topmostTokenOwner', [collectionId, tokenId, blockHashAt]);1557    }15581559    if (owner === null) return null;15601561    return owner.toHuman();1562  }15631564  /**1565   * Get tokens nested in the provided token1566   * @param collectionId ID of collection1567   * @param tokenId ID of token1568   * @param blockHashAt optionally query the data at the block with this hash1569   * @example getTokenChildren(10, 5);1570   * @returns tokens whose depth of nesting is <= 51571   */1572  async getTokenChildren(collectionId: number, tokenId: number, blockHashAt?: string): Promise<IToken[]> {1573    let children;1574    if(typeof blockHashAt === 'undefined') {1575      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId]);1576    } else {1577      children = await this.helper.callRpc('api.rpc.unique.tokenChildren', [collectionId, tokenId, blockHashAt]);1578    }15791580    return children.toJSON().map((x: any) => {1581      return {collectionId: x.collection, tokenId: x.token};1582    });1583  }15841585  /**1586   * Nest one token into another1587   * @param signer keyring of signer1588   * @param tokenObj token to be nested1589   * @param rootTokenObj token to be parent1590   * @example nestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4});1591   * @returns ```true``` if extrinsic success, otherwise ```false```1592   */1593  async nestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken): Promise<boolean> {1594    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1595    const result = await this.transferToken(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress);1596    if(!result) {1597      throw Error('Unable to nest token!');1598    }1599    return result;1600  }16011602  /**1603   * Remove token from nested state1604   * @param signer keyring of signer1605   * @param tokenObj token to unnest1606   * @param rootTokenObj parent of a token1607   * @param toAddressObj address of a new token owner1608   * @example unnestToken(aliceKeyring, {collectionId: 10, tokenId: 5}, {collectionId: 10, tokenId: 4}, {Substrate: "5DyN4Y92vZCjv38fg..."});1609   * @returns ```true``` if extrinsic success, otherwise ```false```1610   */1611  async unnestToken(signer: TSigner, tokenObj: IToken, rootTokenObj: IToken, toAddressObj: ICrossAccountId): Promise<boolean> {1612    const rootTokenAddress = this.helper.util.getTokenAccount(rootTokenObj);1613    const result = await this.transferTokenFrom(signer, tokenObj.collectionId, tokenObj.tokenId, rootTokenAddress, toAddressObj);1614    if(!result) {1615      throw Error('Unable to unnest token!');1616    }1617    return result;1618  }16191620  /**1621   * Mint new collection1622   * @param signer keyring of signer1623   * @param collectionOptions Collection options1624   * @example1625   * mintCollection(aliceKeyring, {1626   *   name: 'New',1627   *   description: 'New collection',1628   *   tokenPrefix: 'NEW',1629   * })1630   * @returns object of the created collection1631   */1632  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueNFTCollection> {1633    return await super.mintCollection(signer, collectionOptions, 'NFT') as UniqueNFTCollection;1634  }16351636  /**1637   * Mint new token1638   * @param signer keyring of signer1639   * @param data token data1640   * @returns created token object1641   */1642  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; properties?: IProperty[]; }): Promise<UniqueNFToken> {1643    const creationResult = await this.helper.executeExtrinsic(1644      signer,1645      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1646        nft: {1647          properties: data.properties,1648        },1649      }],1650      true,1651    );1652    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1653    if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1654    if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1655    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1656  }16571658  /**1659   * Mint multiple NFT tokens1660   * @param signer keyring of signer1661   * @param collectionId ID of collection1662   * @param tokens array of tokens with owner and properties1663   * @example1664   * mintMultipleTokens(aliceKeyring, 10, [{1665   *     owner: {Substrate: "5DyN4Y92vZCjv38fg..."},1666   *     properties: [{key: "gender", value: "male"},{key: "age", value: "45"}],1667   *   },{1668   *     owner: {Ethereum: "0x9F0583DbB855d..."},1669   *     properties: [{key: "gender", value: "female"},{key: "age", value: "22"}],1670   * }]);1671   * @returns ```true``` if extrinsic success, otherwise ```false```1672   */1673  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1674    const creationResult = await this.helper.executeExtrinsic(1675      signer,1676      'api.tx.unique.createMultipleItemsEx', [collectionId, {NFT: tokens}],1677      true,1678    );1679    const collection = this.getCollectionObject(collectionId);1680    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1681  }16821683  /**1684   * Mint multiple NFT tokens with one owner1685   * @param signer keyring of signer1686   * @param collectionId ID of collection1687   * @param owner tokens owner1688   * @param tokens array of tokens with owner and properties1689   * @example1690   * mintMultipleTokensWithOneOwner(aliceKeyring, 10, "5DyN4Y92vZCjv38fg...", [{1691   *   properties: [{1692   *   key: "gender",1693   *   value: "female",1694   *  },{1695   *   key: "age",1696   *   value: "33",1697   *  }],1698   * }]);1699   * @returns array of newly created tokens1700   */1701  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {properties?: IProperty[]}[]): Promise<UniqueNFToken[]> {1702    const rawTokens = [];1703    for (const token of tokens) {1704      const raw = {NFT: {properties: token.properties}};1705      rawTokens.push(raw);1706    }1707    const creationResult = await this.helper.executeExtrinsic(1708      signer,1709      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1710      true,1711    );1712    const collection = this.getCollectionObject(collectionId);1713    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1714  }17151716  /**1717   * Set, change, or remove approved address to transfer the ownership of the NFT.1718   *1719   * @param signer keyring of signer1720   * @param collectionId ID of collection1721   * @param tokenId ID of token1722   * @param toAddressObj address to approve1723   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."})1724   * @returns ```true``` if extrinsic success, otherwise ```false```1725   */1726  approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId) {1727    return super.approveToken(signer, collectionId, tokenId, toAddressObj, 1n);1728  }1729}173017311732class RFTGroup extends NFTnRFT {1733  /**1734   * Get collection object1735   * @param collectionId ID of collection1736   * @example getCollectionObject(2);1737   * @returns instance of UniqueRFTCollection1738   */1739  getCollectionObject(collectionId: number): UniqueRFTCollection {1740    return new UniqueRFTCollection(collectionId, this.helper);1741  }17421743  /**1744   * Get token object1745   * @param collectionId ID of collection1746   * @param tokenId ID of token1747   * @example getTokenObject(10, 5);1748   * @returns instance of UniqueNFTToken1749   */1750  getTokenObject(collectionId: number, tokenId: number): UniqueRFToken {1751    return new UniqueRFToken(tokenId, this.getCollectionObject(collectionId));1752  }17531754  /**1755   * Get top 10 token owners with the largest number of pieces1756   * @param collectionId ID of collection1757   * @param tokenId ID of token1758   * @example getTokenTop10Owners(10, 5);1759   * @returns array of top 10 owners1760   */1761  async getTokenTop10Owners(collectionId: number, tokenId: number): Promise<CrossAccountId[]> {1762    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, tokenId])).toJSON().map(CrossAccountId.fromLowerCaseKeys);1763  }17641765  /**1766   * Get number of pieces owned by address1767   * @param collectionId ID of collection1768   * @param tokenId ID of token1769   * @param addressObj address token owner1770   * @example getTokenBalance(10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."});1771   * @returns number of pieces ownerd by address1772   */1773  async getTokenBalance(collectionId: number, tokenId: number, addressObj: ICrossAccountId): Promise<bigint> {1774    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, tokenId])).toBigInt();1775  }17761777  /**1778   * Transfer pieces of token to another address1779   * @param signer keyring of signer1780   * @param collectionId ID of collection1781   * @param tokenId ID of token1782   * @param addressObj address of a new owner1783   * @param amount number of pieces to be transfered1784   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2000n)1785   * @returns ```true``` if extrinsic success, otherwise ```false```1786   */1787  async transferToken(signer: TSigner, collectionId: number, tokenId: number, addressObj: ICrossAccountId, amount=1n): Promise<boolean> {1788    return await super.transferToken(signer, collectionId, tokenId, addressObj, amount);1789  }17901791  /**1792   * Change ownership of some pieces of RFT on behalf of the owner.1793   * @param signer keyring of signer1794   * @param collectionId ID of collection1795   * @param tokenId ID of token1796   * @param fromAddressObj address on behalf of which the token will be sent1797   * @param toAddressObj new token owner1798   * @param amount number of pieces to be transfered1799   * @example transferTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, {Substrate: "5DfhbVfww7ThF8q6f3i..."}, 2000n)1800   * @returns ```true``` if extrinsic success, otherwise ```false```1801   */1802  async transferTokenFrom(signer: TSigner, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1803    return await super.transferTokenFrom(signer, collectionId, tokenId, fromAddressObj, toAddressObj, amount);1804  }18051806  /**1807   * Mint new collection1808   * @param signer keyring of signer1809   * @param collectionOptions Collection options1810   * @example1811   * mintCollection(aliceKeyring, {1812   *   name: 'New',1813   *   description: 'New collection',1814   *   tokenPrefix: 'NEW',1815   * })1816   * @returns object of the created collection1817   */1818  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}): Promise<UniqueRFTCollection> {1819    return await super.mintCollection(signer, collectionOptions, 'RFT') as UniqueRFTCollection;1820  }18211822  /**1823   * Mint new token1824   * @param signer keyring of signer1825   * @param data token data1826   * @example mintToken(aliceKeyring, {collectionId: 10, owner: {Substrate: '5GHoZe9c73RYbVzq...'}, pieces: 10000n});1827   * @returns created token object1828   */1829  async mintToken(signer: TSigner, data: { collectionId: number; owner: ICrossAccountId | string; pieces: bigint; properties?: IProperty[]; }): Promise<UniqueRFToken> {1830    const creationResult = await this.helper.executeExtrinsic(1831      signer,1832      'api.tx.unique.createItem', [data.collectionId, (typeof data.owner === 'string') ? {Substrate: data.owner} : data.owner, {1833        refungible: {1834          pieces: data.pieces,1835          properties: data.properties,1836        },1837      }],1838      true,1839    );1840    const createdTokens = this.helper.util.extractTokensFromCreationResult(creationResult);1841    if (createdTokens.tokens.length > 1) throw Error('Minted multiple tokens');1842    if (createdTokens.tokens.length < 1) throw Error('No tokens minted');1843    return this.getTokenObject(data.collectionId, createdTokens.tokens[0].tokenId);1844  }18451846  async mintMultipleTokens(signer: TSigner, collectionId: number, tokens: {owner: ICrossAccountId, pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1847    throw Error('Not implemented');1848    const creationResult = await this.helper.executeExtrinsic(1849      signer,1850      'api.tx.unique.createMultipleItemsEx', [collectionId, {RefungibleMultipleOwners: tokens}],1851      true, // `Unable to mint RFT tokens for ${label}`,1852    );1853    const collection = this.getCollectionObject(collectionId);1854    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1855  }18561857  /**1858   * Mint multiple RFT tokens with one owner1859   * @param signer keyring of signer1860   * @param collectionId ID of collection1861   * @param owner tokens owner1862   * @param tokens array of tokens with properties and pieces1863   * @example mintMultipleTokensWithOneOwner(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, [{pieces: 100000n, properties: [{key: "gender", value: "male"}]}]);1864   * @returns array of newly created RFT tokens1865   */1866  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, owner: ICrossAccountId, tokens: {pieces: bigint, properties?: IProperty[]}[]): Promise<UniqueRFToken[]> {1867    const rawTokens = [];1868    for (const token of tokens) {1869      const raw = {ReFungible: {pieces: token.pieces, properties: token.properties}};1870      rawTokens.push(raw);1871    }1872    const creationResult = await this.helper.executeExtrinsic(1873      signer,1874      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],1875      true,1876    );1877    const collection = this.getCollectionObject(collectionId);1878    return this.helper.util.extractTokensFromCreationResult(creationResult).tokens.map((x: IToken) => collection.getTokenObject(x.tokenId));1879  }18801881  /**1882   * Destroys a concrete instance of RFT.1883   * @param signer keyring of signer1884   * @param collectionId ID of collection1885   * @param tokenId ID of token1886   * @param amount number of pieces to be burnt1887   * @example burnToken(aliceKeyring, 10, 5);1888   * @returns ```true``` if the extrinsic is successful, otherwise ```false```1889   */1890  async burnToken(signer: IKeyringPair, collectionId: number, tokenId: number, amount=1n): Promise<boolean> {1891    return await super.burnToken(signer, collectionId, tokenId, amount);1892  }18931894  /**1895   * Destroys a concrete instance of RFT on behalf of the owner.1896   * @param signer keyring of signer1897   * @param collectionId ID of collection1898   * @param tokenId ID of token1899   * @param fromAddressObj address on behalf of which the token will be burnt1900   * @param amount number of pieces to be burnt1901   * @example burnTokenFrom(aliceKeyring, 10, 5, {Substrate: "5DyN4Y92vZCjv38fg..."}, 2n)1902   * @returns ```true``` if extrinsic success, otherwise ```false```1903   */1904  async burnTokenFrom(signer: IKeyringPair, collectionId: number, tokenId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {1905    return await super.burnTokenFrom(signer, collectionId, tokenId, fromAddressObj, amount);1906  }19071908  /**1909   * Set, change, or remove approved address to transfer the ownership of the RFT.1910   *1911   * @param signer keyring of signer1912   * @param collectionId ID of collection1913   * @param tokenId ID of token1914   * @param toAddressObj address to approve1915   * @param amount number of pieces to be approved1916   * @example approveToken(aliceKeyring, 10, 5, {Substrate: "5GHoZe9c73RYbVzq..."}, "", 10000n);1917   * @returns true if the token success, otherwise false1918   */1919  approveToken(signer: IKeyringPair, collectionId: number, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {1920    return super.approveToken(signer, collectionId, tokenId, toAddressObj, amount);1921  }19221923  /**1924   * Get total number of pieces1925   * @param collectionId ID of collection1926   * @param tokenId ID of token1927   * @example getTokenTotalPieces(10, 5);1928   * @returns number of pieces1929   */1930  async getTokenTotalPieces(collectionId: number, tokenId: number): Promise<bigint> {1931    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, tokenId])).unwrap().toBigInt();1932  }19331934  /**1935   * Change number of token pieces. Signer must be the owner of all token pieces.1936   * @param signer keyring of signer1937   * @param collectionId ID of collection1938   * @param tokenId ID of token1939   * @param amount new number of pieces1940   * @example repartitionToken(aliceKeyring, 10, 5, 12345n);1941   * @returns true if the repartion was success, otherwise false1942   */1943  async repartitionToken(signer: TSigner, collectionId: number, tokenId: number, amount: bigint): Promise<boolean> {1944    const currentAmount = await this.getTokenTotalPieces(collectionId, tokenId);1945    const repartitionResult = await this.helper.executeExtrinsic(1946      signer,1947      'api.tx.unique.repartition', [collectionId, tokenId, amount],1948      true,1949    );1950    if(currentAmount < amount) return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemCreated');1951    return this.helper.util.findCollectionInEvents(repartitionResult.result.events, collectionId, 'common', 'ItemDestroyed');1952  }1953}195419551956class FTGroup extends CollectionGroup {1957  /**1958   * Get collection object1959   * @param collectionId ID of collection1960   * @example getCollectionObject(2);1961   * @returns instance of UniqueFTCollection1962   */1963  getCollectionObject(collectionId: number): UniqueFTCollection {1964    return new UniqueFTCollection(collectionId, this.helper);1965  }19661967  /**1968   * Mint new fungible collection1969   * @param signer keyring of signer1970   * @param collectionOptions Collection options1971   * @param decimalPoints number of token decimals1972   * @example1973   * mintCollection(aliceKeyring, {1974   *   name: 'New',1975   *   description: 'New collection',1976   *   tokenPrefix: 'NEW',1977   * }, 18)1978   * @returns newly created fungible collection1979   */1980  async mintCollection(signer: TSigner, collectionOptions: ICollectionCreationOptions = {}, decimalPoints = 0): Promise<UniqueFTCollection> {1981    collectionOptions = JSON.parse(JSON.stringify(collectionOptions)) as ICollectionCreationOptions; // Clone object1982    if(collectionOptions.tokenPropertyPermissions) throw Error('Fungible collections has no tokenPropertyPermissions');1983    collectionOptions.mode = {fungible: decimalPoints};1984    for (const key of ['name', 'description', 'tokenPrefix']) {1985      if (typeof collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] === 'string') collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] = this.helper.util.str2vec(collectionOptions[key as 'name' | 'description' | 'tokenPrefix'] as string);1986    }1987    const creationResult = await this.helper.executeExtrinsic(1988      signer,1989      'api.tx.unique.createCollectionEx', [collectionOptions],1990      true,1991    );1992    return this.getCollectionObject(this.helper.util.extractCollectionIdFromCreationResult(creationResult));1993  }19941995  /**1996   * Mint tokens1997   * @param signer keyring of signer1998   * @param collectionId ID of collection1999   * @param owner address owner of new tokens2000   * @param amount amount of tokens to be meanted2001   * @example mintTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq"}, 1000n);2002   * @returns ```true``` if extrinsic success, otherwise ```false```2003   */2004  async mintTokens(signer: TSigner, collectionId: number, amount: bigint, owner: ICrossAccountId | string): Promise<boolean> {2005    const creationResult = await this.helper.executeExtrinsic(2006      signer,2007      'api.tx.unique.createItem', [collectionId, (typeof owner === 'string') ? {Substrate: owner} : owner, {2008        fungible: {2009          value: amount,2010        },2011      }],2012      true, // `Unable to mint fungible tokens for ${label}`,2013    );2014    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2015  }20162017  /**2018   * Mint multiple Fungible tokens with one owner2019   * @param signer keyring of signer2020   * @param collectionId ID of collection2021   * @param owner tokens owner2022   * @param tokens array of tokens with properties and pieces2023   * @returns ```true``` if extrinsic success, otherwise ```false```2024   */2025  async mintMultipleTokensWithOneOwner(signer: TSigner, collectionId: number, tokens: {value: bigint}[], owner: ICrossAccountId): Promise<boolean> {2026    const rawTokens = [];2027    for (const token of tokens) {2028      const raw = {Fungible: {Value: token.value}};2029      rawTokens.push(raw);2030    }2031    const creationResult = await this.helper.executeExtrinsic(2032      signer,2033      'api.tx.unique.createMultipleItems', [collectionId, owner, rawTokens],2034      true,2035    );2036    return this.helper.util.findCollectionInEvents(creationResult.result.events, collectionId, 'common', 'ItemCreated');2037  }20382039  /**2040   * Get the top 10 owners with the largest balance for the Fungible collection2041   * @param collectionId ID of collection2042   * @example getTop10Owners(10);2043   * @returns array of ```ICrossAccountId```2044   */2045  async getTop10Owners(collectionId: number): Promise<CrossAccountId[]> {2046    return (await this.helper.callRpc('api.rpc.unique.tokenOwners', [collectionId, 0])).toJSON().map(CrossAccountId.fromLowerCaseKeys);2047  }20482049  /**2050   * Get account balance2051   * @param collectionId ID of collection2052   * @param addressObj address of owner2053   * @example getBalance(10, {Substrate: "5GHoZe9c73RYbVzq..."})2054   * @returns amount of fungible tokens owned by address2055   */2056  async getBalance(collectionId: number, addressObj: ICrossAccountId): Promise<bigint> {2057    return (await this.helper.callRpc('api.rpc.unique.balance', [collectionId, addressObj, 0])).toBigInt();2058  }20592060  /**2061   * Transfer tokens to address2062   * @param signer keyring of signer2063   * @param collectionId ID of collection2064   * @param toAddressObj address recipient2065   * @param amount amount of tokens to be sent2066   * @example transfer(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2067   * @returns ```true``` if extrinsic success, otherwise ```false```2068   */2069  async transfer(signer: TSigner, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2070    return await super.transferToken(signer, collectionId, 0, toAddressObj, amount);2071  }20722073  /**2074   * Transfer some tokens on behalf of the owner.2075   * @param signer keyring of signer2076   * @param collectionId ID of collection2077   * @param fromAddressObj address on behalf of which tokens will be sent2078   * @param toAddressObj address where token to be sent2079   * @param amount number of tokens to be sent2080   * @example transferFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, {Substrate: "5DfhbVfww7ThF8q6f3ij..."}, 10000n);2081   * @returns ```true``` if extrinsic success, otherwise ```false```2082   */2083  async transferFrom(signer: TSigner, collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {2084    return await super.transferTokenFrom(signer, collectionId, 0, fromAddressObj, toAddressObj, amount);2085  }20862087  /**2088   * Destroy some amount of tokens2089   * @param signer keyring of signer2090   * @param collectionId ID of collection2091   * @param amount amount of tokens to be destroyed2092   * @example burnTokens(aliceKeyring, 10, 1000n);2093   * @returns ```true``` if extrinsic success, otherwise ```false```2094   */2095  async burnTokens(signer: IKeyringPair, collectionId: number, amount=1n): Promise<boolean> {2096    return await super.burnToken(signer, collectionId, 0, amount);2097  }20982099  /**2100   * Burn some tokens on behalf of the owner.2101   * @param signer keyring of signer2102   * @param collectionId ID of collection2103   * @param fromAddressObj address on behalf of which tokens will be burnt2104   * @param amount amount of tokens to be burnt2105   * @example burnTokensFrom(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n);2106   * @returns ```true``` if extrinsic success, otherwise ```false```2107   */2108  async burnTokensFrom(signer: IKeyringPair, collectionId: number, fromAddressObj: ICrossAccountId, amount=1n): Promise<boolean> {2109    return await super.burnTokenFrom(signer, collectionId, 0, fromAddressObj, amount);2110  }21112112  /**2113   * Get total collection supply2114   * @param collectionId2115   * @returns2116   */2117  async getTotalPieces(collectionId: number): Promise<bigint> {2118    return (await this.helper.callRpc('api.rpc.unique.totalPieces', [collectionId, 0])).unwrap().toBigInt();2119  }21202121  /**2122   * Set, change, or remove approved address to transfer tokens.2123   *2124   * @param signer keyring of signer2125   * @param collectionId ID of collection2126   * @param toAddressObj address to be approved2127   * @param amount amount of tokens to be approved2128   * @example approveTokens(aliceKeyring, 10, {Substrate: "5GHoZe9c73RYbVzq..."}, 1000n)2129   * @returns ```true``` if extrinsic success, otherwise ```false```2130   */2131  approveTokens(signer: IKeyringPair, collectionId: number, toAddressObj: ICrossAccountId, amount=1n) {2132    return super.approveToken(signer, collectionId, 0, toAddressObj, amount);2133  }21342135  /**2136   * Get amount of fungible tokens approved to transfer2137   * @param collectionId ID of collection2138   * @param fromAddressObj owner of tokens2139   * @param toAddressObj the address approved for the transfer of tokens on behalf of the owner2140   * @returns number of tokens approved for the transfer2141   */2142  getApprovedTokens(collectionId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {2143    return super.getTokenApprovedPieces(collectionId, 0, toAddressObj, fromAddressObj);2144  }2145}214621472148class ChainGroup extends HelperGroup<ChainHelperBase> {2149  /**2150   * Get system properties of a chain2151   * @example getChainProperties();2152   * @returns ss58Format, token decimals, and token symbol2153   */2154  getChainProperties(): IChainProperties {2155    const properties = (this.helper.getApi() as any).registry.getChainProperties().toJSON();2156    return {2157      ss58Format: properties.ss58Format.toJSON(),2158      tokenDecimals: properties.tokenDecimals.toJSON(),2159      tokenSymbol: properties.tokenSymbol.toJSON(),2160    };2161  }21622163  /**2164   * Get chain header2165   * @example getLatestBlockNumber();2166   * @returns the number of the last block2167   */2168  async getLatestBlockNumber(): Promise<number> {2169    return (await this.helper.callRpc('api.rpc.chain.getHeader')).number.toNumber();2170  }21712172  /**2173   * Get block hash by block number2174   * @param blockNumber number of block2175   * @example getBlockHashByNumber(12345);2176   * @returns hash of a block2177   */2178  async getBlockHashByNumber(blockNumber: number): Promise<string | null> {2179    const blockHash = (await this.helper.callRpc('api.rpc.chain.getBlockHash', [blockNumber])).toJSON();2180    if(blockHash === '0x0000000000000000000000000000000000000000000000000000000000000000') return null;2181    return blockHash;2182  }21832184  // TODO add docs2185  async getBlock(blockHashOrNumber: string | number): Promise<IBlock | null> {2186    const blockHash = typeof blockHashOrNumber === 'string' ? blockHashOrNumber : await this.getBlockHashByNumber(blockHashOrNumber);2187    if (!blockHash) return null;2188    return (await this.helper.callRpc('api.rpc.chain.getBlock', [blockHash])).toHuman().block;2189  }21902191  /**2192   * Get account nonce2193   * @param address substrate address2194   * @example getNonce("5GrwvaEF5zXb26Fz...");2195   * @returns number, account's nonce2196   */2197  async getNonce(address: TSubstrateAccount): Promise<number> {2198    return (await this.helper.callRpc('api.query.system.account', [address])).nonce.toNumber();2199  }2200}22012202class SubstrateBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2203  /**2204 * Get substrate address balance2205 * @param address substrate address2206 * @example getSubstrate("5GrwvaEF5zXb26Fz...")2207 * @returns amount of tokens on address2208 */2209  async getSubstrate(address: TSubstrateAccount): Promise<bigint> {2210    return (await this.helper.callRpc('api.query.system.account', [address])).data.free.toBigInt();2211  }22122213  /**2214   * Transfer tokens to substrate address2215   * @param signer keyring of signer2216   * @param address substrate address of a recipient2217   * @param amount amount of tokens to be transfered2218   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2219   * @returns ```true``` if extrinsic success, otherwise ```false```2220   */2221  async transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2222    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true/*, `Unable to transfer balance from ${this.helper.getSignerAddress(signer)} to ${address}`*/);22232224    let transfer = {from: null, to: null, amount: 0n} as any;2225    result.result.events.forEach(({event: {data, method, section}}) => {2226      if ((section === 'balances') && (method === 'Transfer')) {2227        transfer = {2228          from: this.helper.address.normalizeSubstrate(data[0]),2229          to: this.helper.address.normalizeSubstrate(data[1]),2230          amount: BigInt(data[2]),2231        };2232      }2233    });2234    const isSuccess = this.helper.address.normalizeSubstrate(typeof signer === 'string' ? signer : signer.address) === transfer.from2235      && this.helper.address.normalizeSubstrate(address) === transfer.to2236      && BigInt(amount) === transfer.amount;2237    return isSuccess;2238  }22392240  /**2241   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2242   * @param address substrate address2243   * @returns2244   */2245  async getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2246    const accountInfo = (await this.helper.callRpc('api.query.system.account', [address])).data;2247    return {free: accountInfo.free.toBigInt(), miscFrozen: accountInfo.miscFrozen.toBigInt(), feeFrozen: accountInfo.feeFrozen.toBigInt(), reserved: accountInfo.reserved.toBigInt()};2248  }2249}22502251class EthereumBalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2252  /**2253   * Get ethereum address balance2254   * @param address ethereum address2255   * @example getEthereum("0x9F0583DbB855d...")2256   * @returns amount of tokens on address2257   */2258  async getEthereum(address: TEthereumAccount): Promise<bigint> {2259    return (await this.helper.callRpc('api.rpc.eth.getBalance', [address])).toBigInt();2260  }22612262  /**2263   * Transfer tokens to address2264   * @param signer keyring of signer2265   * @param address Ethereum address of a recipient2266   * @param amount amount of tokens to be transfered2267   * @example transferToEthereum(alithKeyring, "0x9F0583DbB855d...", 100_000_000_000n);2268   * @returns ```true``` if extrinsic success, otherwise ```false```2269   */2270  async transferToEthereum(signer: TSigner, address: TEthereumAccount, amount: bigint | string): Promise<boolean> {2271    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.transfer', [address, amount], true);22722273    let transfer = {from: null, to: null, amount: 0n} as any;2274    result.result.events.forEach(({event: {data, method, section}}) => {2275      if ((section === 'balances') && (method === 'Transfer')) {2276        transfer = {2277          from: data[0].toString(),2278          to: data[1].toString(),2279          amount: BigInt(data[2]),2280        };2281      }2282    });2283    const isSuccess = (typeof signer === 'string' ? signer : signer.address) === transfer.from2284      && address === transfer.to2285      && BigInt(amount) === transfer.amount;2286    return isSuccess;2287  }2288}22892290class BalanceGroup<T extends ChainHelperBase> extends HelperGroup<T> {2291  subBalanceGroup: SubstrateBalanceGroup<T>;2292  ethBalanceGroup: EthereumBalanceGroup<T>;22932294  constructor(helper: T) {2295    super(helper);2296    this.subBalanceGroup = new SubstrateBalanceGroup(helper);2297    this.ethBalanceGroup = new EthereumBalanceGroup(helper);2298  }22992300  getCollectionCreationPrice(): bigint {2301    return 2n * this.getOneTokenNominal();2302  }2303  /**2304   * Representation of the native token in the smallest unit - one OPAL (OPL), QUARTZ (QTZ), or UNIQUE (UNQ).2305   * @example getOneTokenNominal()2306   * @returns ```BigInt``` representation of the native token in the smallest unit, e.g. ```1_000_000_000_000_000_000n``` for QTZ.2307   */2308  getOneTokenNominal(): bigint {2309    const chainProperties = this.helper.chain.getChainProperties();2310    return 10n ** BigInt((chainProperties.tokenDecimals || [18])[0]);2311  }23122313  /**2314   * Get substrate address balance2315   * @param address substrate address2316   * @example getSubstrate("5GrwvaEF5zXb26Fz...")2317   * @returns amount of tokens on address2318   */2319  getSubstrate(address: TSubstrateAccount): Promise<bigint> {2320    return this.subBalanceGroup.getSubstrate(address);2321  }23222323  /**2324   * Get full substrate balance including free, miscFrozen, feeFrozen, and reserved2325   * @param address substrate address2326   * @returns2327   */2328  getSubstrateFull(address: TSubstrateAccount): Promise<ISubstrateBalance> {2329    return this.subBalanceGroup.getSubstrateFull(address);2330  }23312332  /**2333   * Get ethereum address balance2334   * @param address ethereum address2335   * @example getEthereum("0x9F0583DbB855d...")2336   * @returns amount of tokens on address2337   */2338  getEthereum(address: TEthereumAccount): Promise<bigint> {2339    return this.ethBalanceGroup.getEthereum(address);2340  }23412342  /**2343   * Transfer tokens to substrate address2344   * @param signer keyring of signer2345   * @param address substrate address of a recipient2346   * @param amount amount of tokens to be transfered2347   * @example transferToSubstrate(aliceKeyring, "5GrwvaEF5zXb26Fz...", 100_000_000_000n);2348   * @returns ```true``` if extrinsic success, otherwise ```false```2349   */2350  transferToSubstrate(signer: TSigner, address: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2351    return this.subBalanceGroup.transferToSubstrate(signer, address, amount);2352  }23532354  async forceTransferToSubstrate(signer: TSigner, from: TSubstrateAccount, to: TSubstrateAccount, amount: bigint | string): Promise<boolean> {2355    const result = await this.helper.executeExtrinsic(signer, 'api.tx.balances.forceTransfer', [from, to, amount], true);23562357    let transfer = {from: null, to: null, amount: 0n} as any;2358    result.result.events.forEach(({event: {data, method, section}}) => {2359      if ((section === 'balances') && (method === 'Transfer')) {2360        transfer = {2361          from: this.helper.address.normalizeSubstrate(data[0]),2362          to: this.helper.address.normalizeSubstrate(data[1]),2363          amount: BigInt(data[2]),2364        };2365      }2366    });2367    let isSuccess = this.helper.address.normalizeSubstrate(from) === transfer.from;2368    isSuccess = isSuccess && this.helper.address.normalizeSubstrate(to) === transfer.to;2369    isSuccess = isSuccess && BigInt(amount) === transfer.amount;2370    return isSuccess;2371  }2372}23732374class AddressGroup extends HelperGroup<ChainHelperBase> {2375  /**2376   * Normalizes the address to the specified ss58 format, by default ```42```.2377   * @param address substrate address2378   * @param ss58Format format for address conversion, by default ```42```2379   * @example normalizeSubstrate("unjKJQJrRd238pkUZZvzDQrfKuM39zBSnQ5zjAGAGcdRhaJTx") // returns 5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY2380   * @returns substrate address converted to normalized (i.e., starting with 5) or specified explicitly representation2381   */2382  normalizeSubstrate(address: TSubstrateAccount, ss58Format = 42): TSubstrateAccount {2383    return CrossAccountId.normalizeSubstrateAddress(address, ss58Format);2384  }23852386  /**2387   * Get address in the connected chain format2388   * @param address substrate address2389   * @example normalizeSubstrateToChainFormat("5GrwvaEF5zXb26Fz...") // returns unjKJQJrRd238pkUZZ... for Unique Network2390   * @returns address in chain format2391   */2392  normalizeSubstrateToChainFormat(address: TSubstrateAccount): TSubstrateAccount {2393    return this.normalizeSubstrate(address, this.helper.chain.getChainProperties().ss58Format);2394  }23952396  /**2397   * Get substrate mirror of an ethereum address2398   * @param ethAddress ethereum address2399   * @param toChainFormat false for normalized account2400   * @example ethToSubstrate('0x9F0583DbB855d...')2401   * @returns substrate mirror of a provided ethereum address2402   */2403  ethToSubstrate(ethAddress: TEthereumAccount, toChainFormat=false): TSubstrateAccount {2404    return CrossAccountId.translateEthToSub(ethAddress, toChainFormat ? this.helper.chain.getChainProperties().ss58Format : undefined);2405  }24062407  /**2408   * Get ethereum mirror of a substrate address2409   * @param subAddress substrate account2410   * @example substrateToEth("5DnSF6RRjwteE3BrC...")2411   * @returns ethereum mirror of a provided substrate address2412   */2413  substrateToEth(subAddress: TSubstrateAccount): TEthereumAccount {2414    return CrossAccountId.translateSubToEth(subAddress);2415  }24162417  /**2418   * Encode key to substrate address2419   * @param key key for encoding address2420   * @param ss58Format prefix for encoding to the address of the corresponding network2421   * @returns encoded substrate address2422   */2423  encodeSubstrateAddress (key: Uint8Array | string | bigint, ss58Format = 42): string {2424    const u8a :Uint8Array = typeof key === 'string'2425      ? hexToU8a(key)2426      : typeof key === 'bigint'2427        ? hexToU8a(key.toString(16))2428        : key;2429  2430    if (ss58Format < 0 || ss58Format > 16383 || [46, 47].includes(ss58Format)) {2431      throw new Error(`ss58Format is not valid, received ${typeof ss58Format} "${ss58Format}"`);2432    }2433  2434    const allowedDecodedLengths = [1, 2, 4, 8, 32, 33];2435    if (!allowedDecodedLengths.includes(u8a.length)) {2436      throw new Error(`key length is not valid, received ${u8a.length}, valid values are ${allowedDecodedLengths.join(', ')}`);2437    }2438  2439    const u8aPrefix = ss58Format < 642440      ? new Uint8Array([ss58Format])2441      : new Uint8Array([2442        ((ss58Format & 0xfc) >> 2) | 0x40,2443        (ss58Format >> 8) | ((ss58Format & 0x03) << 6),2444      ]);24452446    const input = u8aConcat(u8aPrefix, u8a);2447  2448    return base58Encode(u8aConcat(2449      input,2450      blake2AsU8a(input).subarray(0, [32, 33].includes(u8a.length) ? 2 : 1),2451    ));2452  }24532454  /**2455   * Restore substrate address from bigint representation2456   * @param number decimal representation of substrate address2457   * @returns substrate address2458   */2459  restoreCrossAccountFromBigInt(number: bigint): TSubstrateAccount {2460    if (this.helper.api === null) {2461      throw 'Not connected';2462    }2463    const res = this.helper.api.registry.createType('AccountId', '0x' + number.toString(16).padStart(64, '0')).toJSON();2464    if (res === undefined || res === null) {2465      throw 'Restore address error';2466    }2467    return res.toString();2468  }24692470  /**2471   * Convert etherium cross account id to substrate cross account id2472   * @param ethCrossAccount etherium cross account2473   * @returns substrate cross account id2474   */2475  convertCrossAccountFromEthCrossAccount(ethCrossAccount: IEthCrossAccountId): ICrossAccountId {2476    if (ethCrossAccount.sub === '0') {2477      return {Ethereum: ethCrossAccount.eth.toLocaleLowerCase()};2478    }2479    2480    const ss58 = this.restoreCrossAccountFromBigInt(BigInt(ethCrossAccount.sub));2481    return {Substrate: ss58};2482  }24832484  paraSiblingSovereignAccount(paraid: number) {2485    // We are getting a *sibling* parachain sovereign account,2486    // so we need a sibling prefix: encoded(b"sibl") == 0x7369626c2487    const siblingPrefix = '0x7369626c';24882489    const encodedParaId = this.helper.getApi().createType('u32', paraid).toHex(true).substring(2);2490    const suffix = '000000000000000000000000000000000000000000000000';24912492    return siblingPrefix + encodedParaId + suffix;2493  }2494}24952496class StakingGroup extends HelperGroup<UniqueHelper> {2497  /**2498   * Stake tokens for App Promotion2499   * @param signer keyring of signer2500   * @param amountToStake amount of tokens to stake2501   * @param label extra label for log2502   * @returns2503   */2504  async stake(signer: TSigner, amountToStake: bigint, label?: string): Promise<boolean> {2505    if(typeof label === 'undefined') label = `${signer.address} amount: ${amountToStake}`;2506    const _stakeResult = await this.helper.executeExtrinsic(2507      signer, 'api.tx.appPromotion.stake',2508      [amountToStake], true,2509    );2510    // TODO extract info from stakeResult2511    return true;2512  }25132514  /**2515   * Unstake tokens for App Promotion2516   * @param signer keyring of signer2517   * @param amountToUnstake amount of tokens to unstake2518   * @param label extra label for log2519   * @returns block number where balances will be unlocked2520   */2521  async unstake(signer: TSigner, label?: string): Promise<number> {2522    if(typeof label === 'undefined') label = `${signer.address}`;2523    const _unstakeResult = await this.helper.executeExtrinsic(2524      signer, 'api.tx.appPromotion.unstake',2525      [], true,2526    );2527    // TODO extract block number fron events2528    return 1;2529  }25302531  /**2532   * Get total staked amount for address2533   * @param address substrate or ethereum address2534   * @returns total staked amount2535   */2536  async getTotalStaked(address?: ICrossAccountId): Promise<bigint> {2537    if (address) return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked', [address])).toBigInt();2538    return (await this.helper.callRpc('api.rpc.appPromotion.totalStaked')).toBigInt();2539  }25402541  /**2542   * Get total staked per block2543   * @param address substrate or ethereum address2544   * @returns array of stakes. `block` – the number of the block in which the stake was made. `amount` - the number of tokens staked in the block2545   */2546  async getTotalStakedPerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2547    const rawTotalStakerdPerBlock = await this.helper.callRpc('api.rpc.appPromotion.totalStakedPerBlock', [address]);2548    return rawTotalStakerdPerBlock.map(([block, amount]: any[]) => {2549      return {2550        block: block.toBigInt(),2551        amount: amount.toBigInt(),2552      };2553    });2554  }25552556  /**2557   * Get total pending unstake amount for address2558   * @param address substrate or ethereum address2559   * @returns total pending unstake amount2560   */2561  async getPendingUnstake(address: ICrossAccountId): Promise<bigint> {2562    return (await this.helper.callRpc('api.rpc.appPromotion.pendingUnstake', [address])).toBigInt();2563  }25642565  /**2566   * Get pending unstake amount per block for address2567   * @param address substrate or ethereum address2568   * @returns array of pending stakes. `block` – the number of the block in which the unstake was made. `amount` - the number of tokens unstaked in the block2569   */2570  async getPendingUnstakePerBlock(address: ICrossAccountId): Promise<IStakingInfo[]> {2571    const rawUnstakedPerBlock = await this.helper.callRpc('api.rpc.appPromotion.pendingUnstakePerBlock', [address]);2572    const result = rawUnstakedPerBlock.map(([block, amount]: any[]) => {2573      return {2574        block: block.toBigInt(),2575        amount: amount.toBigInt(),2576      };2577    });2578    return result;2579  }2580}25812582class SchedulerGroup extends HelperGroup<UniqueHelper> {2583  constructor(helper: UniqueHelper) {2584    super(helper);2585  }25862587  cancelScheduled(signer: TSigner, scheduledId: string) {2588    return this.helper.executeExtrinsic(2589      signer,2590      'api.tx.scheduler.cancelNamed',2591      [scheduledId],2592      true,2593    );2594  }25952596  changePriority(signer: TSigner, scheduledId: string, priority: number) {2597    return this.helper.executeExtrinsic(2598      signer,2599      'api.tx.scheduler.changeNamedPriority',2600      [scheduledId, priority],2601      true,2602    );2603  }26042605  scheduleAt<T extends UniqueHelper>(2606    executionBlockNumber: number,2607    options: ISchedulerOptions = {},2608  ) {2609    return this.schedule<T>('schedule', executionBlockNumber, options);2610  }26112612  scheduleAfter<T extends UniqueHelper>(2613    blocksBeforeExecution: number,2614    options: ISchedulerOptions = {},2615  ) {2616    return this.schedule<T>('scheduleAfter', blocksBeforeExecution, options);2617  }26182619  schedule<T extends UniqueHelper>(2620    scheduleFn: 'schedule' | 'scheduleAfter',2621    blocksNum: number,2622    options: ISchedulerOptions = {},2623  ) {2624    // eslint-disable-next-line @typescript-eslint/naming-convention2625    const ScheduledHelperType = ScheduledUniqueHelper(this.helper.helperBase);2626    return this.helper.clone(ScheduledHelperType, {2627      scheduleFn,2628      blocksNum,2629      options,2630    }) as T;2631  }2632}26332634class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {2635  async register(signer: TSigner, ownerAddress: TSubstrateAccount, location: any, metadata: IForeignAssetMetadata) {2636    await this.helper.executeExtrinsic(2637      signer,2638      'api.tx.foreignAssets.registerForeignAsset',2639      [ownerAddress, location, metadata],2640      true,2641    );2642  }26432644  async update(signer: TSigner, foreignAssetId: number, location: any, metadata: IForeignAssetMetadata) {2645    await this.helper.executeExtrinsic(2646      signer,2647      'api.tx.foreignAssets.updateForeignAsset',2648      [foreignAssetId, location, metadata],2649      true,2650    );2651  }2652}26532654class XcmGroup<T extends ChainHelperBase> extends HelperGroup<T> {2655  palletName: string;26562657  constructor(helper: T, palletName: string) {2658    super(helper);26592660    this.palletName = palletName;2661  }26622663  async limitedReserveTransferAssets(signer: TSigner, destination: any, beneficiary: any, assets: any, feeAssetItem: number, weightLimit: number) {2664    await this.helper.executeExtrinsic(signer, `api.tx.${this.palletName}.limitedReserveTransferAssets`, [destination, beneficiary, assets, feeAssetItem, {Limited: weightLimit}], true);2665  }2666}26672668class XTokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2669  async transfer(signer: TSigner, currencyId: any, amount: bigint, destination: any, destWeight: number) {2670    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transfer', [currencyId, amount, destination, destWeight], true);2671  }26722673  async transferMultiasset(signer: TSigner, asset: any, destination: any, destWeight: number) {2674    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMultiasset', [asset, destination, destWeight], true);2675  }26762677  async transferMulticurrencies(signer: TSigner, currencies: any[], feeItem: number, destLocation: any, destWeight: number) {2678    await this.helper.executeExtrinsic(signer, 'api.tx.xTokens.transferMulticurrencies', [currencies, feeItem, destLocation, destWeight], true);2679  }2680}26812682class TokensGroup<T extends ChainHelperBase> extends HelperGroup<T> {2683  async accounts(address: string, currencyId: any) {2684    const {free} = (await this.helper.callRpc('api.query.tokens.accounts', [address, currencyId])).toJSON() as any;2685    return BigInt(free);2686  }2687}26882689class AssetsGroup<T extends ChainHelperBase> extends HelperGroup<T> {2690  async create(signer: TSigner, assetId: number, admin: string, minimalBalance: bigint) {2691    await this.helper.executeExtrinsic(signer, 'api.tx.assets.create', [assetId, admin, minimalBalance], true);2692  }26932694  async setMetadata(signer: TSigner, assetId: number, name: string, symbol: string, decimals: number) {2695    await this.helper.executeExtrinsic(signer, 'api.tx.assets.setMetadata', [assetId, name, symbol, decimals], true);2696  }26972698  async mint(signer: TSigner, assetId: number, beneficiary: string, amount: bigint) {2699    await this.helper.executeExtrinsic(signer, 'api.tx.assets.mint', [assetId, beneficiary, amount], true);2700  }27012702  async account(assetId: string | number, address: string) {2703    const accountAsset = (2704      await this.helper.callRpc('api.query.assets.account', [assetId, address])2705    ).toJSON()! as any;27062707    if (accountAsset !== null) {2708      return BigInt(accountAsset['balance']);2709    } else {2710      return null;2711    }2712  }2713}27142715class AcalaAssetRegistryGroup extends HelperGroup<AcalaHelper> {2716  async registerForeignAsset(signer: TSigner, destination: any, metadata: AcalaAssetMetadata) {2717    await this.helper.executeExtrinsic(signer, 'api.tx.assetRegistry.registerForeignAsset', [destination, metadata], true);2718  }2719}27202721class MoonbeamAssetManagerGroup extends HelperGroup<MoonbeamHelper> {2722  makeRegisterForeignAssetProposal(assetInfo: MoonbeamAssetInfo) {2723    const apiPrefix = 'api.tx.assetManager.';27242725    const registerTx = this.helper.constructApiCall(2726      apiPrefix + 'registerForeignAsset',2727      [assetInfo.location, assetInfo.metadata, assetInfo.existentialDeposit, assetInfo.isSufficient],2728    );27292730    const setUnitsTx = this.helper.constructApiCall(2731      apiPrefix + 'setAssetUnitsPerSecond',2732      [assetInfo.location, assetInfo.unitsPerSecond, assetInfo.numAssetsWeightHint],2733    );27342735    const batchCall = this.helper.getApi().tx.utility.batchAll([registerTx, setUnitsTx]);2736    const encodedProposal = batchCall?.method.toHex() || '';2737    return encodedProposal;2738  }27392740  async assetTypeId(location: any) {2741    return await this.helper.callRpc('api.query.assetManager.assetTypeId', [location]);2742  }2743}27442745class MoonbeamDemocracyGroup extends HelperGroup<MoonbeamHelper> {2746  async notePreimage(signer: TSigner, encodedProposal: string) {2747    await this.helper.executeExtrinsic(signer, 'api.tx.democracy.notePreimage', [encodedProposal], true);2748  }27492750  externalProposeMajority(proposalHash: string) {2751    return this.helper.constructApiCall('api.tx.democracy.externalProposeMajority', [proposalHash]);2752  }27532754  fastTrack(proposalHash: string, votingPeriod: number, delayPeriod: number) {2755    return this.helper.constructApiCall('api.tx.democracy.fastTrack', [proposalHash, votingPeriod, delayPeriod]);2756  }27572758  async referendumVote(signer: TSigner, referendumIndex: number, accountVote: DemocracyStandardAccountVote) {2759    await this.helper.executeExtrinsic(signer, 'api.tx.democracy.vote', [referendumIndex, {Standard: accountVote}], true);2760  }2761}27622763class MoonbeamCollectiveGroup extends HelperGroup<MoonbeamHelper> {2764  collective: string;27652766  constructor(helper: MoonbeamHelper, collective: string) {2767    super(helper);27682769    this.collective = collective;2770  }27712772  async propose(signer: TSigner, threshold: number, proposalHash: string, lengthBound: number) {2773    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.propose`, [threshold, proposalHash, lengthBound], true);2774  }27752776  async vote(signer: TSigner, proposalHash: string, proposalIndex: number, approve: boolean) {2777    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.vote`, [proposalHash, proposalIndex, approve], true);2778  }27792780  async close(signer: TSigner, proposalHash: string, proposalIndex: number, weightBound: number, lengthBound: number) {2781    await this.helper.executeExtrinsic(signer, `api.tx.${this.collective}.close`, [proposalHash, proposalIndex, weightBound, lengthBound], true);2782  }27832784  async proposalCount() {2785    return Number(await this.helper.callRpc(`api.query.${this.collective}.proposalCount`, []));2786  }2787}27882789export type ChainHelperBaseConstructor = new(...args: any[]) => ChainHelperBase;2790export type UniqueHelperConstructor = new(...args: any[]) => UniqueHelper;27912792export class UniqueHelper extends ChainHelperBase {2793  balance: BalanceGroup<UniqueHelper>;2794  collection: CollectionGroup;2795  nft: NFTGroup;2796  rft: RFTGroup;2797  ft: FTGroup;2798  staking: StakingGroup;2799  scheduler: SchedulerGroup;2800  foreignAssets: ForeignAssetsGroup;2801  xcm: XcmGroup<UniqueHelper>;2802  xTokens: XTokensGroup<UniqueHelper>;2803  tokens: TokensGroup<UniqueHelper>;28042805  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2806    super(logger, options.helperBase ?? UniqueHelper);28072808    this.balance = new BalanceGroup(this);2809    this.collection = new CollectionGroup(this);2810    this.nft = new NFTGroup(this);2811    this.rft = new RFTGroup(this);2812    this.ft = new FTGroup(this);2813    this.staking = new StakingGroup(this);2814    this.scheduler = new SchedulerGroup(this);2815    this.foreignAssets = new ForeignAssetsGroup(this);2816    this.xcm = new XcmGroup(this, 'polkadotXcm');2817    this.xTokens = new XTokensGroup(this);2818    this.tokens = new TokensGroup(this);2819  }28202821  getSudo<T extends UniqueHelper>() {2822    // eslint-disable-next-line @typescript-eslint/naming-convention2823    const SudoHelperType = SudoHelper(this.helperBase);2824    return this.clone(SudoHelperType) as T;2825  }2826}28272828export class XcmChainHelper extends ChainHelperBase {2829  async connect(wsEndpoint: string, _listeners?: any): Promise<void> {2830    const wsProvider = new WsProvider(wsEndpoint);2831    this.api = new ApiPromise({2832      provider: wsProvider,2833    });2834    await this.api.isReadyOrError;2835    this.network = await UniqueHelper.detectNetwork(this.api);2836  }2837}28382839export class RelayHelper extends XcmChainHelper {2840  xcm: XcmGroup<RelayHelper>;28412842  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2843    super(logger, options.helperBase ?? RelayHelper);28442845    this.xcm = new XcmGroup(this, 'xcmPallet');2846  }2847}28482849export class WestmintHelper extends XcmChainHelper {2850  balance: SubstrateBalanceGroup<WestmintHelper>;2851  xcm: XcmGroup<WestmintHelper>;2852  assets: AssetsGroup<WestmintHelper>;2853  xTokens: XTokensGroup<WestmintHelper>;28542855  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2856    super(logger, options.helperBase ?? WestmintHelper);28572858    this.balance = new SubstrateBalanceGroup(this);2859    this.xcm = new XcmGroup(this, 'polkadotXcm');2860    this.assets = new AssetsGroup(this);2861    this.xTokens = new XTokensGroup(this);2862  }2863}28642865export class MoonbeamHelper extends XcmChainHelper {2866  balance: EthereumBalanceGroup<MoonbeamHelper>;2867  assetManager: MoonbeamAssetManagerGroup;2868  assets: AssetsGroup<MoonbeamHelper>;2869  xTokens: XTokensGroup<MoonbeamHelper>;2870  democracy: MoonbeamDemocracyGroup;2871  collective: {2872    council: MoonbeamCollectiveGroup,2873    techCommittee: MoonbeamCollectiveGroup,2874  };28752876  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2877    super(logger, options.helperBase ?? MoonbeamHelper);28782879    this.balance = new EthereumBalanceGroup(this);2880    this.assetManager = new MoonbeamAssetManagerGroup(this);2881    this.assets = new AssetsGroup(this);2882    this.xTokens = new XTokensGroup(this);2883    this.democracy = new MoonbeamDemocracyGroup(this);2884    this.collective = {2885      council: new MoonbeamCollectiveGroup(this, 'councilCollective'),2886      techCommittee: new MoonbeamCollectiveGroup(this, 'techCommitteeCollective'),2887    };2888  }2889}28902891export class AcalaHelper extends XcmChainHelper {2892  balance: SubstrateBalanceGroup<AcalaHelper>;2893  assetRegistry: AcalaAssetRegistryGroup;2894  xTokens: XTokensGroup<AcalaHelper>;2895  tokens: TokensGroup<AcalaHelper>;28962897  constructor(logger?: ILogger, options: {[key: string]: any} = {}) {2898    super(logger, options.helperBase ?? AcalaHelper);28992900    this.balance = new SubstrateBalanceGroup(this);2901    this.assetRegistry = new AcalaAssetRegistryGroup(this);2902    this.xTokens = new XTokensGroup(this);2903    this.tokens = new TokensGroup(this);2904  }29052906  getSudo<T extends AcalaHelper>() {2907    // eslint-disable-next-line @typescript-eslint/naming-convention2908    const SudoHelperType = SudoHelper(this.helperBase);2909    return this.clone(SudoHelperType) as T;2910  }2911}29122913// eslint-disable-next-line @typescript-eslint/naming-convention2914function ScheduledUniqueHelper<T extends UniqueHelperConstructor>(Base: T) {2915  return class extends Base {2916    scheduleFn: 'schedule' | 'scheduleAfter';2917    blocksNum: number;2918    options: ISchedulerOptions;29192920    constructor(...args: any[]) {2921      const logger = args[0] as ILogger;2922      const options = args[1] as {2923        scheduleFn: 'schedule' | 'scheduleAfter',2924        blocksNum: number,2925        options: ISchedulerOptions2926      };29272928      super(logger);29292930      this.scheduleFn = options.scheduleFn;2931      this.blocksNum = options.blocksNum;2932      this.options = options.options;2933    }29342935    executeExtrinsic(sender: IKeyringPair, scheduledExtrinsic: string, scheduledParams: any[], expectSuccess?: boolean): Promise<ITransactionResult> {2936      const scheduledTx = this.constructApiCall(scheduledExtrinsic, scheduledParams);2937      2938      const mandatorySchedArgs = [2939        this.blocksNum,2940        this.options.periodic ? [this.options.periodic.period, this.options.periodic.repetitions] : null,2941        this.options.priority ?? null,2942        scheduledTx,2943      ];2944      2945      let schedArgs;2946      let scheduleFn;29472948      if (this.options.scheduledId) {2949        schedArgs = [this.options.scheduledId!, ...mandatorySchedArgs];29502951        if (this.scheduleFn == 'schedule') {2952          scheduleFn = 'scheduleNamed';2953        } else if (this.scheduleFn == 'scheduleAfter') {2954          scheduleFn = 'scheduleNamedAfter';2955        }2956      } else {2957        schedArgs = mandatorySchedArgs;2958        scheduleFn = this.scheduleFn;2959      }29602961      const extrinsic = 'api.tx.scheduler.' +  scheduleFn;29622963      return super.executeExtrinsic(2964        sender,2965        extrinsic,2966        schedArgs,2967        expectSuccess,2968      );2969    }2970  };2971}29722973// eslint-disable-next-line @typescript-eslint/naming-convention2974function SudoHelper<T extends ChainHelperBaseConstructor>(Base: T) {2975  return class extends Base {2976    constructor(...args: any[]) {2977      super(...args);2978    }29792980    executeExtrinsic (2981      sender: IKeyringPair,2982      extrinsic: string,2983      params: any[],2984      expectSuccess?: boolean,2985    ): Promise<ITransactionResult> {2986      const call = this.constructApiCall(extrinsic, params);2987      return super.executeExtrinsic(2988        sender,2989        'api.tx.sudo.sudo',2990        [call],2991        expectSuccess,2992      );2993    }2994  };2995}29962997export class UniqueBaseCollection {2998  helper: UniqueHelper;2999  collectionId: number;30003001  constructor(collectionId: number, uniqueHelper: UniqueHelper) {3002    this.collectionId = collectionId;3003    this.helper = uniqueHelper;3004  }30053006  async getData() {3007    return await this.helper.collection.getData(this.collectionId);3008  }30093010  async getLastTokenId() {3011    return await this.helper.collection.getLastTokenId(this.collectionId);3012  }30133014  async doesTokenExist(tokenId: number) {3015    return await this.helper.collection.doesTokenExist(this.collectionId, tokenId);3016  }30173018  async getAdmins() {3019    return await this.helper.collection.getAdmins(this.collectionId);3020  }30213022  async getAllowList() {3023    return await this.helper.collection.getAllowList(this.collectionId);3024  }30253026  async getEffectiveLimits() {3027    return await this.helper.collection.getEffectiveLimits(this.collectionId);3028  }30293030  async getProperties(propertyKeys?: string[] | null) {3031    return await this.helper.collection.getProperties(this.collectionId, propertyKeys);3032  }30333034  async getTokenNextSponsored(tokenId: number, addressObj: ICrossAccountId) {3035    return await this.helper.collection.getTokenNextSponsored(this.collectionId, tokenId, addressObj);3036  }30373038  async getOptions() {3039    return await this.helper.collection.getCollectionOptions(this.collectionId);3040  }30413042  async setSponsor(signer: TSigner, sponsorAddress: TSubstrateAccount) {3043    return await this.helper.collection.setSponsor(signer, this.collectionId, sponsorAddress);3044  }30453046  async confirmSponsorship(signer: TSigner) {3047    return await this.helper.collection.confirmSponsorship(signer, this.collectionId);3048  }30493050  async removeSponsor(signer: TSigner) {3051    return await this.helper.collection.removeSponsor(signer, this.collectionId);3052  }30533054  async setLimits(signer: TSigner, limits: ICollectionLimits) {3055    return await this.helper.collection.setLimits(signer, this.collectionId, limits);3056  }30573058  async changeOwner(signer: TSigner, ownerAddress: TSubstrateAccount) {3059    return await this.helper.collection.changeOwner(signer, this.collectionId, ownerAddress);3060  }30613062  async addAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3063    return await this.helper.collection.addAdmin(signer, this.collectionId, adminAddressObj);3064  }30653066  async addToAllowList(signer: TSigner, addressObj: ICrossAccountId) {3067    return await this.helper.collection.addToAllowList(signer, this.collectionId, addressObj);3068  }30693070  async removeFromAllowList(signer: TSigner, addressObj: ICrossAccountId) {3071    return await this.helper.collection.removeFromAllowList(signer, this.collectionId, addressObj);3072  }30733074  async removeAdmin(signer: TSigner, adminAddressObj: ICrossAccountId) {3075    return await this.helper.collection.removeAdmin(signer, this.collectionId, adminAddressObj);3076  }30773078  async setProperties(signer: TSigner, properties: IProperty[]) {3079    return await this.helper.collection.setProperties(signer, this.collectionId, properties);3080  }30813082  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3083    return await this.helper.collection.deleteProperties(signer, this.collectionId, propertyKeys);3084  }30853086  async setPermissions(signer: TSigner, permissions: ICollectionPermissions) {3087    return await this.helper.collection.setPermissions(signer, this.collectionId, permissions);3088  }30893090  async enableNesting(signer: TSigner, permissions: INestingPermissions) {3091    return await this.helper.collection.enableNesting(signer, this.collectionId, permissions);3092  }30933094  async disableNesting(signer: TSigner) {3095    return await this.helper.collection.disableNesting(signer, this.collectionId);3096  }30973098  async burn(signer: TSigner) {3099    return await this.helper.collection.burn(signer, this.collectionId);3100  }31013102  scheduleAt<T extends UniqueHelper>(3103    executionBlockNumber: number,3104    options: ISchedulerOptions = {},3105  ) {3106    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3107    return new UniqueBaseCollection(this.collectionId, scheduledHelper);3108  }31093110  scheduleAfter<T extends UniqueHelper>(3111    blocksBeforeExecution: number,3112    options: ISchedulerOptions = {},3113  ) {3114    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3115    return new UniqueBaseCollection(this.collectionId, scheduledHelper);3116  }31173118  getSudo<T extends UniqueHelper>() {3119    return new UniqueBaseCollection(this.collectionId, this.helper.getSudo<T>());3120  }3121}312231233124export class UniqueNFTCollection extends UniqueBaseCollection {3125  getTokenObject(tokenId: number) {3126    return new UniqueNFToken(tokenId, this);3127  }31283129  async getTokensByAddress(addressObj: ICrossAccountId) {3130    return await this.helper.nft.getTokensByAddress(this.collectionId, addressObj);3131  }31323133  async getToken(tokenId: number, blockHashAt?: string) {3134    return await this.helper.nft.getToken(this.collectionId, tokenId, [], blockHashAt);3135  }31363137  async getTokenOwner(tokenId: number, blockHashAt?: string) {3138    return await this.helper.nft.getTokenOwner(this.collectionId, tokenId, blockHashAt);3139  }31403141  async getTokenTopmostOwner(tokenId: number, blockHashAt?: string) {3142    return await this.helper.nft.getTokenTopmostOwner(this.collectionId, tokenId, blockHashAt);3143  }31443145  async getTokenChildren(tokenId: number, blockHashAt?: string) {3146    return await this.helper.nft.getTokenChildren(this.collectionId, tokenId, blockHashAt);3147  }31483149  async getPropertyPermissions(propertyKeys: string[] | null = null) {3150    return await this.helper.nft.getPropertyPermissions(this.collectionId, propertyKeys);3151  }31523153  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3154    return await this.helper.nft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3155  }31563157  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId) {3158    return await this.helper.nft.transferToken(signer, this.collectionId, tokenId, addressObj);3159  }31603161  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3162    return await this.helper.nft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj);3163  }31643165  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId) {3166    return await this.helper.nft.approveToken(signer, this.collectionId, tokenId, toAddressObj);3167  }31683169  async isTokenApproved(tokenId: number, toAddressObj: ICrossAccountId) {3170    return await this.helper.nft.isTokenApproved(this.collectionId, tokenId, toAddressObj);3171  }31723173  async mintToken(signer: TSigner, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3174    return await this.helper.nft.mintToken(signer, {collectionId: this.collectionId, owner, properties});3175  }31763177  async mintMultipleTokens(signer: TSigner, tokens: {owner: ICrossAccountId, properties?: IProperty[]}[]) {3178    return await this.helper.nft.mintMultipleTokens(signer, this.collectionId, tokens);3179  }31803181  async burnToken(signer: TSigner, tokenId: number) {3182    return await this.helper.nft.burnToken(signer, this.collectionId, tokenId);3183  }31843185  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId) {3186    return await this.helper.nft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj);3187  }31883189  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3190    return await this.helper.nft.setTokenProperties(signer, this.collectionId, tokenId, properties);3191  }31923193  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3194    return await this.helper.nft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3195  }31963197  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3198    return await this.helper.nft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3199  }32003201  async nestToken(signer: TSigner, tokenId: number, toTokenObj: IToken) {3202    return await this.helper.nft.nestToken(signer, {collectionId: this.collectionId, tokenId}, toTokenObj);3203  }32043205  async unnestToken(signer: TSigner, tokenId: number, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3206    return await this.helper.nft.unnestToken(signer, {collectionId: this.collectionId, tokenId}, fromTokenObj, toAddressObj);3207  }32083209  scheduleAt<T extends UniqueHelper>(3210    executionBlockNumber: number,3211    options: ISchedulerOptions = {},3212  ) {3213    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3214    return new UniqueNFTCollection(this.collectionId, scheduledHelper);3215  }32163217  scheduleAfter<T extends UniqueHelper>(3218    blocksBeforeExecution: number,3219    options: ISchedulerOptions = {},3220  ) {3221    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3222    return new UniqueNFTCollection(this.collectionId, scheduledHelper);3223  }32243225  getSudo<T extends UniqueHelper>() {3226    return new UniqueNFTCollection(this.collectionId, this.helper.getSudo<T>());3227  }3228}322932303231export class UniqueRFTCollection extends UniqueBaseCollection {3232  getTokenObject(tokenId: number) {3233    return new UniqueRFToken(tokenId, this);3234  }32353236  async getToken(tokenId: number, blockHashAt?: string) {3237    return await this.helper.rft.getToken(this.collectionId, tokenId, [], blockHashAt);3238  }32393240  async getTokensByAddress(addressObj: ICrossAccountId) {3241    return await this.helper.rft.getTokensByAddress(this.collectionId, addressObj);3242  }32433244  async getTop10TokenOwners(tokenId: number) {3245    return await this.helper.rft.getTokenTop10Owners(this.collectionId, tokenId);3246  }32473248  async getTokenBalance(tokenId: number, addressObj: ICrossAccountId) {3249    return await this.helper.rft.getTokenBalance(this.collectionId, tokenId, addressObj);3250  }32513252  async getTokenTotalPieces(tokenId: number) {3253    return await this.helper.rft.getTokenTotalPieces(this.collectionId, tokenId);3254  }32553256  async getTokenApprovedPieces(tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3257    return await this.helper.rft.getTokenApprovedPieces(this.collectionId, tokenId, toAddressObj, fromAddressObj);3258  }32593260  async getPropertyPermissions(propertyKeys: string[] | null = null) {3261    return await this.helper.rft.getPropertyPermissions(this.collectionId, propertyKeys);3262  }32633264  async getTokenProperties(tokenId: number, propertyKeys?: string[] | null) {3265    return await this.helper.rft.getTokenProperties(this.collectionId, tokenId, propertyKeys);3266  }32673268  async transferToken(signer: TSigner, tokenId: number, addressObj: ICrossAccountId, amount=1n) {3269    return await this.helper.rft.transferToken(signer, this.collectionId, tokenId, addressObj, amount);3270  }32713272  async transferTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3273    return await this.helper.rft.transferTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, toAddressObj, amount);3274  }32753276  async approveToken(signer: TSigner, tokenId: number, toAddressObj: ICrossAccountId, amount=1n) {3277    return await this.helper.rft.approveToken(signer, this.collectionId, tokenId, toAddressObj, amount);3278  }32793280  async repartitionToken(signer: TSigner, tokenId: number, amount: bigint) {3281    return await this.helper.rft.repartitionToken(signer, this.collectionId, tokenId, amount);3282  }32833284  async mintToken(signer: TSigner, pieces=1n, owner: ICrossAccountId = {Substrate: signer.address}, properties?: IProperty[]) {3285    return await this.helper.rft.mintToken(signer, {collectionId: this.collectionId, owner, pieces, properties});3286  }32873288  async mintMultipleTokens(signer: TSigner, tokens: {pieces: bigint, owner: ICrossAccountId, properties?: IProperty[]}[]) {3289    return await this.helper.rft.mintMultipleTokens(signer, this.collectionId, tokens);3290  }32913292  async burnToken(signer: TSigner, tokenId: number, amount=1n) {3293    return await this.helper.rft.burnToken(signer, this.collectionId, tokenId, amount);3294  }32953296  async burnTokenFrom(signer: TSigner, tokenId: number, fromAddressObj: ICrossAccountId,  amount=1n) {3297    return await this.helper.rft.burnTokenFrom(signer, this.collectionId, tokenId, fromAddressObj, amount);3298  }32993300  async setTokenProperties(signer: TSigner, tokenId: number, properties: IProperty[]) {3301    return await this.helper.rft.setTokenProperties(signer, this.collectionId, tokenId, properties);3302  }33033304  async deleteTokenProperties(signer: TSigner, tokenId: number, propertyKeys: string[]) {3305    return await this.helper.rft.deleteTokenProperties(signer, this.collectionId, tokenId, propertyKeys);3306  }33073308  async setTokenPropertyPermissions(signer: TSigner, permissions: ITokenPropertyPermission[]) {3309    return await this.helper.rft.setTokenPropertyPermissions(signer, this.collectionId, permissions);3310  }33113312  scheduleAt<T extends UniqueHelper>(3313    executionBlockNumber: number,3314    options: ISchedulerOptions = {},3315  ) {3316    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3317    return new UniqueRFTCollection(this.collectionId, scheduledHelper);3318  }33193320  scheduleAfter<T extends UniqueHelper>(3321    blocksBeforeExecution: number,3322    options: ISchedulerOptions = {},3323  ) {3324    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3325    return new UniqueRFTCollection(this.collectionId, scheduledHelper);3326  }33273328  getSudo<T extends UniqueHelper>() {3329    return new UniqueRFTCollection(this.collectionId, this.helper.getSudo<T>());3330  }3331}333233333334export class UniqueFTCollection extends UniqueBaseCollection {3335  async getBalance(addressObj: ICrossAccountId) {3336    return await this.helper.ft.getBalance(this.collectionId, addressObj);3337  }33383339  async getTotalPieces() {3340    return await this.helper.ft.getTotalPieces(this.collectionId);3341  }33423343  async getApprovedTokens(fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3344    return await this.helper.ft.getApprovedTokens(this.collectionId, fromAddressObj, toAddressObj);3345  }33463347  async getTop10Owners() {3348    return await this.helper.ft.getTop10Owners(this.collectionId);3349  }33503351  async mint(signer: TSigner, amount=1n, owner: ICrossAccountId = {Substrate: signer.address}) {3352    return await this.helper.ft.mintTokens(signer, this.collectionId, amount, owner);3353  }33543355  async mintWithOneOwner(signer: TSigner, tokens: {value: bigint}[], owner: ICrossAccountId = {Substrate: signer.address}) {3356    return await this.helper.ft.mintMultipleTokensWithOneOwner(signer, this.collectionId, tokens, owner);3357  }33583359  async transfer(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3360    return await this.helper.ft.transfer(signer, this.collectionId, toAddressObj, amount);3361  }33623363  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3364    return await this.helper.ft.transferFrom(signer, this.collectionId, fromAddressObj, toAddressObj, amount);3365  }33663367  async burnTokens(signer: TSigner, amount=1n) {3368    return await this.helper.ft.burnTokens(signer, this.collectionId, amount);3369  }33703371  async burnTokensFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3372    return await this.helper.ft.burnTokensFrom(signer, this.collectionId, fromAddressObj, amount);3373  }33743375  async approveTokens(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3376    return await this.helper.ft.approveTokens(signer, this.collectionId, toAddressObj, amount);3377  }33783379  scheduleAt<T extends UniqueHelper>(3380    executionBlockNumber: number,3381    options: ISchedulerOptions = {},3382  ) {3383    const scheduledHelper = this.helper.scheduler.scheduleAt<T>(executionBlockNumber, options);3384    return new UniqueFTCollection(this.collectionId, scheduledHelper);3385  }33863387  scheduleAfter<T extends UniqueHelper>(3388    blocksBeforeExecution: number,3389    options: ISchedulerOptions = {},3390  ) {3391    const scheduledHelper = this.helper.scheduler.scheduleAfter<T>(blocksBeforeExecution, options);3392    return new UniqueFTCollection(this.collectionId, scheduledHelper);3393  }33943395  getSudo<T extends UniqueHelper>() {3396    return new UniqueFTCollection(this.collectionId, this.helper.getSudo<T>());3397  }3398}339934003401export class UniqueBaseToken {3402  collection: UniqueNFTCollection | UniqueRFTCollection;3403  collectionId: number;3404  tokenId: number;34053406  constructor(tokenId: number, collection: UniqueNFTCollection | UniqueRFTCollection) {3407    this.collection = collection;3408    this.collectionId = collection.collectionId;3409    this.tokenId = tokenId;3410  }34113412  async getNextSponsored(addressObj: ICrossAccountId) {3413    return await this.collection.getTokenNextSponsored(this.tokenId, addressObj);3414  }34153416  async getProperties(propertyKeys?: string[] | null) {3417    return await this.collection.getTokenProperties(this.tokenId, propertyKeys);3418  }34193420  async setProperties(signer: TSigner, properties: IProperty[]) {3421    return await this.collection.setTokenProperties(signer, this.tokenId, properties);3422  }34233424  async deleteProperties(signer: TSigner, propertyKeys: string[]) {3425    return await this.collection.deleteTokenProperties(signer, this.tokenId, propertyKeys);3426  }34273428  async doesExist() {3429    return await this.collection.doesTokenExist(this.tokenId);3430  }34313432  nestingAccount() {3433    return this.collection.helper.util.getTokenAccount(this);3434  }34353436  scheduleAt<T extends UniqueHelper>(3437    executionBlockNumber: number,3438    options: ISchedulerOptions = {},3439  ) {3440    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3441    return new UniqueBaseToken(this.tokenId, scheduledCollection);3442  }34433444  scheduleAfter<T extends UniqueHelper>(3445    blocksBeforeExecution: number,3446    options: ISchedulerOptions = {},3447  ) {3448    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3449    return new UniqueBaseToken(this.tokenId, scheduledCollection);3450  }34513452  getSudo<T extends UniqueHelper>() {3453    return new UniqueBaseToken(this.tokenId, this.collection.getSudo<T>());3454  }3455}345634573458export class UniqueNFToken extends UniqueBaseToken {3459  collection: UniqueNFTCollection;34603461  constructor(tokenId: number, collection: UniqueNFTCollection) {3462    super(tokenId, collection);3463    this.collection = collection;3464  }34653466  async getData(blockHashAt?: string) {3467    return await this.collection.getToken(this.tokenId, blockHashAt);3468  }34693470  async getOwner(blockHashAt?: string) {3471    return await this.collection.getTokenOwner(this.tokenId, blockHashAt);3472  }34733474  async getTopmostOwner(blockHashAt?: string) {3475    return await this.collection.getTokenTopmostOwner(this.tokenId, blockHashAt);3476  }34773478  async getChildren(blockHashAt?: string) {3479    return await this.collection.getTokenChildren(this.tokenId, blockHashAt);3480  }34813482  async nest(signer: TSigner, toTokenObj: IToken) {3483    return await this.collection.nestToken(signer, this.tokenId, toTokenObj);3484  }34853486  async unnest(signer: TSigner, fromTokenObj: IToken, toAddressObj: ICrossAccountId) {3487    return await this.collection.unnestToken(signer, this.tokenId, fromTokenObj, toAddressObj);3488  }34893490  async transfer(signer: TSigner, addressObj: ICrossAccountId) {3491    return await this.collection.transferToken(signer, this.tokenId, addressObj);3492  }34933494  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId) {3495    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj);3496  }34973498  async approve(signer: TSigner, toAddressObj: ICrossAccountId) {3499    return await this.collection.approveToken(signer, this.tokenId, toAddressObj);3500  }35013502  async isApproved(toAddressObj: ICrossAccountId) {3503    return await this.collection.isTokenApproved(this.tokenId, toAddressObj);3504  }35053506  async burn(signer: TSigner) {3507    return await this.collection.burnToken(signer, this.tokenId);3508  }35093510  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId) {3511    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj);3512  }35133514  scheduleAt<T extends UniqueHelper>(3515    executionBlockNumber: number,3516    options: ISchedulerOptions = {},3517  ) {3518    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3519    return new UniqueNFToken(this.tokenId, scheduledCollection);3520  }35213522  scheduleAfter<T extends UniqueHelper>(3523    blocksBeforeExecution: number,3524    options: ISchedulerOptions = {},3525  ) {3526    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3527    return new UniqueNFToken(this.tokenId, scheduledCollection);3528  }35293530  getSudo<T extends UniqueHelper>() {3531    return new UniqueNFToken(this.tokenId, this.collection.getSudo<T>());3532  }3533}35343535export class UniqueRFToken extends UniqueBaseToken {3536  collection: UniqueRFTCollection;35373538  constructor(tokenId: number, collection: UniqueRFTCollection) {3539    super(tokenId, collection);3540    this.collection = collection;3541  }35423543  async getData(blockHashAt?: string) {3544    return await this.collection.getToken(this.tokenId, blockHashAt);3545  }35463547  async getTop10Owners() {3548    return await this.collection.getTop10TokenOwners(this.tokenId);3549  }35503551  async getBalance(addressObj: ICrossAccountId) {3552    return await this.collection.getTokenBalance(this.tokenId, addressObj);3553  }35543555  async getTotalPieces() {3556    return await this.collection.getTokenTotalPieces(this.tokenId);3557  }35583559  async getApprovedPieces(fromAddressObj: ICrossAccountId, toAccountObj: ICrossAccountId) {3560    return await this.collection.getTokenApprovedPieces(this.tokenId, fromAddressObj, toAccountObj);3561  }35623563  async transfer(signer: TSigner, addressObj: ICrossAccountId, amount=1n) {3564    return await this.collection.transferToken(signer, this.tokenId, addressObj, amount);3565  }35663567  async transferFrom(signer: TSigner, fromAddressObj: ICrossAccountId, toAddressObj: ICrossAccountId, amount=1n) {3568    return await this.collection.transferTokenFrom(signer, this.tokenId, fromAddressObj, toAddressObj, amount);3569  }35703571  async approve(signer: TSigner, toAddressObj: ICrossAccountId, amount=1n) {3572    return await this.collection.approveToken(signer, this.tokenId, toAddressObj, amount);3573  }35743575  async repartition(signer: TSigner, amount: bigint) {3576    return await this.collection.repartitionToken(signer, this.tokenId, amount);3577  }35783579  async burn(signer: TSigner, amount=1n) {3580    return await this.collection.burnToken(signer, this.tokenId, amount);3581  }35823583  async burnFrom(signer: TSigner, fromAddressObj: ICrossAccountId, amount=1n) {3584    return await this.collection.burnTokenFrom(signer, this.tokenId, fromAddressObj, amount);3585  }35863587  scheduleAt<T extends UniqueHelper>(3588    executionBlockNumber: number,3589    options: ISchedulerOptions = {},3590  ) {3591    const scheduledCollection = this.collection.scheduleAt<T>(executionBlockNumber, options);3592    return new UniqueRFToken(this.tokenId, scheduledCollection);3593  }35943595  scheduleAfter<T extends UniqueHelper>(3596    blocksBeforeExecution: number,3597    options: ISchedulerOptions = {},3598  ) {3599    const scheduledCollection = this.collection.scheduleAfter<T>(blocksBeforeExecution, options);3600    return new UniqueRFToken(this.tokenId, scheduledCollection);3601  }36023603  getSudo<T extends UniqueHelper>() {3604    return new UniqueRFToken(this.tokenId, this.collection.getSudo<T>());3605  }3606}