git.delta.rocks / unique-network / refs/commits / 668280b1206d

difftreelog

feat(xcm tests) `XcmHelper` integraion for QTZ\UNQ

PraetorP2023-09-29parent: #06b395f.patch.diff
in: master

6 files changed

modified.baedeker/.gitignorediffbeforeafterboth
--- a/.baedeker/.gitignore
+++ b/.baedeker/.gitignore
@@ -1,4 +1,5 @@
 /.bdk-env
-/rewrites.jsonnet
+/rewrites*.jsonnet
 /vendor
 /baedeker-library
+!/rewrites.example.jsonnet
\ No newline at end of file
modified.github/workflows/xcm.ymldiffbeforeafterboth
after · .github/workflows/xcm.yml
1name: xcm-testnet23# Controls when the action will run.4on:5  workflow_call:67  # Allows you to run this workflow manually from the Actions tab8  workflow_dispatch:910#Define Workflow variables11env:12  REPO_URL: ${{ github.server_url }}/${{ github.repository }}1314# A workflow run is made up of one or more jobs that can run sequentially or in parallel15jobs:16  prepare-execution-marix:17    name: Prepare execution matrix1819    runs-on: [self-hosted-ci]20    outputs:21      matrix: ${{ steps.create_matrix.outputs.matrix }}2223    steps:24      - name: Clean Workspace25        uses: AutoModality/action-clean@v1.1.02627      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it28      - uses: actions/checkout@v3.1.029        with:30          ref: ${{ github.head_ref }} #Checking out head commit3132      - name: Read .env file33        uses: xom9ikk/dotenv@v23435      - name: Create Execution matrix36        uses: CertainLach/create-matrix-action@v437        id: create_matrix38        with:39          matrix: |40            network {opal}, relay_branch {${{ env.UNIQUEWEST_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.WESTMINT_BUILD_BRANCH }}}, astar_version {${{ env.ASTAR_BUILD_BRANCH }}}, polkadex_version {${{ env.POLKADEX_BUILD_BRANCH }}}, runtest {testXcmOpal}, runtime_features {opal-runtime}41            network {quartz}, relay_branch {${{ env.KUSAMA_MAINNET_BRANCH }}}, acala_version {${{ env.KARURA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONRIVER_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINE_BUILD_BRANCH }}}, astar_version {${{ env.SHIDEN_BUILD_BRANCH }}}, polkadex_version {${{ env.POLKADEX_BUILD_BRANCH }}}, runtest {testFullXcmQuartz}, runtime_features {quartz-runtime}42            network {unique}, relay_branch {${{ env.POLKADOT_MAINNET_BRANCH }}}, acala_version {${{ env.ACALA_BUILD_BRANCH }}}, moonbeam_version {${{ env.MOONBEAM_BUILD_BRANCH }}}, cumulus_version {${{ env.STATEMINT_BUILD_BRANCH }}}, astar_version {${{ env.ASTAR_BUILD_BRANCH }}}, polkadex_version {${{ env.POLKADEX_BUILD_BRANCH }}}, runtest {testFullXcmUnique}, runtime_features {unique-runtime}4344  xcm:45    needs: prepare-execution-marix46    # The type of runner that the job will run on47    runs-on: [XL]4849    timeout-minutes: 6005051    name: ${{ matrix.network }}5253    continue-on-error: true #Do not stop testing of matrix runs failed.  As it decided during PR review - it required 50/50& Let's check it with false.5455    strategy:56      matrix:57        include: ${{fromJson(needs.prepare-execution-marix.outputs.matrix)}}5859    steps:60      - name: Skip if pull request is in Draft61        if: github.event.pull_request.draft == true62        run: exit 16364      - name: Clean Workspace65        uses: AutoModality/action-clean@v1.1.06667      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it68      - uses: actions/checkout@v3.1.069        with:70          ref: ${{ github.head_ref }} #Checking out head commit7172      # Prepare SHA73      - name: Prepare SHA74        uses: ./.github/actions/prepare7576      - name: Read .env file77        uses: xom9ikk/dotenv@v27879      - name: Log in to Docker Hub80        uses: docker/login-action@v2.1.081        with:82          username: ${{ secrets.CORE_DOCKERHUB_USERNAME }}83          password: ${{ secrets.CORE_DOCKERHUB_TOKEN }}8485      # Check POLKADOT version and build it if it doesn't exist in repository86      - name: Generate ENV related extend Dockerfile file for POLKADOT87        uses: cuchi/jinja2-action@v1.2.088        with:89          template: .docker/Dockerfile-polkadot.j290          output_file: .docker/Dockerfile-polkadot.${{ matrix.relay_branch }}.yml91          variables: |92            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}93            POLKADOT_BUILD_BRANCH=${{ matrix.relay_branch }}9495      - name: Check if the dockerhub repository contains the needed version POLKADOT96        run: |97          # aquire token98            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)99            export TOKEN=$TOKEN100101          # Get TAGS from DOCKERHUB POLKADOT repository102            POLKADOT_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-polkadot/tags/?page_size=100 | jq -r '."results"[]["name"]')103          # Show TAGS104            echo "POLKADOT TAGS:"105            echo $POLKADOT_TAGS106          # Check correct version POLKADOT and build it if it doesn't exist in POLKADOT TAGS107            if [[ ${POLKADOT_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.relay_branch }}"($|[[:space:]]) ]]; then108                echo "Repository has needed POLKADOT version";109                docker pull uniquenetwork/builder-polkadot:${{ matrix.relay_branch }}110            else111                echo "Repository has not needed POLKADOT version, so build it";112                cd .docker/ && docker build --file ./Dockerfile-polkadot.${{ matrix.relay_branch }}.yml --tag uniquenetwork/builder-polkadot:${{ matrix.relay_branch }} .113                echo "Push needed POLKADOT version to the repository";114                docker push uniquenetwork/builder-polkadot:${{ matrix.relay_branch }}115            fi116        shell: bash117118      # Check ACALA version and build it if it doesn't exist in repository119      - name: Generate ENV related extend Dockerfile file for ACALA120        uses: cuchi/jinja2-action@v1.2.0121        with:122          template: .docker/Dockerfile-acala.j2123          output_file: .docker/Dockerfile-acala.${{ matrix.acala_version }}.yml124          variables: |125            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}126            ACALA_BUILD_BRANCH=${{ matrix.acala_version }}127128      - name: Check if the dockerhub repository contains the needed ACALA version129        run: |130          # aquire token131            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)132            export TOKEN=$TOKEN133134          # Get TAGS from DOCKERHUB repository135            ACALA_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-acala/tags/?page_size=100 | jq -r '."results"[]["name"]')136          # Show TAGS137            echo "ACALA TAGS:"138            echo $ACALA_TAGS139          # Check correct version ACALA and build it if it doesn't exist in ACALA TAGS140            if [[ ${ACALA_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.acala_version }}"($|[[:space:]]) ]]; then141                echo "Repository has needed ACALA version";142                docker pull uniquenetwork/builder-acala:${{ matrix.acala_version }}143            else144                echo "Repository has not needed ACALA version, so build it";145                cd .docker/ && docker build --file ./Dockerfile-acala.${{ matrix.acala_version }}.yml --tag uniquenetwork/builder-acala:${{ matrix.acala_version }} .146                echo "Push needed ACALA version to the repository";147                docker push uniquenetwork/builder-acala:${{ matrix.acala_version }}148            fi149        shell: bash150151      # Check MOONBEAM version and build it if it doesn't exist in repository152      - name: Generate ENV related extend Dockerfile file for MOONBEAM153        uses: cuchi/jinja2-action@v1.2.0154        with:155          template: .docker/Dockerfile-moonbeam.j2156          output_file: .docker/Dockerfile-moonbeam.${{ matrix.moonbeam_version }}.yml157          variables: |158            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}159            MOONBEAM_BUILD_BRANCH=${{ matrix.moonbeam_version }}160161      - name: Check if the dockerhub repository contains the needed MOONBEAM version162        run: |163          # aquire token164            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)165            export TOKEN=$TOKEN166167          # Get TAGS from DOCKERHUB repository168            MOONBEAM_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-moonbeam/tags/?page_size=100 | jq -r '."results"[]["name"]')169          # Show TAGS170            echo "MOONBEAM TAGS:"171            echo $MOONBEAM_TAGS172          # Check correct version MOONBEAM and build it if it doesn't exist in MOONBEAM TAGS173            if [[ ${MOONBEAM_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.moonbeam_version }}"($|[[:space:]]) ]]; then174                echo "Repository has needed MOONBEAM version";175                docker pull uniquenetwork/builder-moonbeam:${{ matrix.moonbeam_version }}176            else177                echo "Repository has not needed MOONBEAM version, so build it";178                cd .docker/ && docker build --file ./Dockerfile-moonbeam.${{ matrix.moonbeam_version }}.yml --tag uniquenetwork/builder-moonbeam:${{ matrix.moonbeam_version }} .179                echo "Push needed MOONBEAM version to the repository";180                docker push uniquenetwork/builder-moonbeam:${{ matrix.moonbeam_version }}181            fi182        shell: bash183184      # Check CUMULUS version and build it if it doesn't exist in repository185      - name: Generate ENV related extend Dockerfile file for CUMULUS186        uses: cuchi/jinja2-action@v1.2.0187        with:188          template: .docker/Dockerfile-cumulus.j2189          output_file: .docker/Dockerfile-cumulus.${{ matrix.cumulus_version }}.yml190          variables: |191            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}192            CUMULUS_BUILD_BRANCH=${{ matrix.cumulus_version }}193194      - name: Check if the dockerhub repository contains the needed CUMULUS version195        run: |196          # aquire token197            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)198            export TOKEN=$TOKEN199200          # Get TAGS from DOCKERHUB repository201            CUMULUS_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-cumulus/tags/?page_size=100 | jq -r '."results"[]["name"]')202          # Show TAGS203            echo "CUMULUS TAGS:"204            echo $CUMULUS_TAGS205          # Check correct version CUMULUS and build it if it doesn't exist in CUMULUS TAGS206            if [[ ${CUMULUS_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.cumulus_version }}"($|[[:space:]]) ]]; then207                echo "Repository has needed CUMULUS version";208                docker pull uniquenetwork/builder-cumulus:${{ matrix.cumulus_version }}209            else210                echo "Repository has not needed CUMULUS version, so build it";211                cd .docker/ && docker build --file ./Dockerfile-cumulus.${{ matrix.cumulus_version }}.yml --tag uniquenetwork/builder-cumulus:${{ matrix.cumulus_version }} .212                echo "Push needed CUMULUS version to the repository";213                docker push uniquenetwork/builder-cumulus:${{ matrix.cumulus_version }}214            fi215        shell: bash216217      # Check ASTAR version and build it if it doesn't exist in repository218      - name: Generate ENV related extend Dockerfile file for ASTAR219        uses: cuchi/jinja2-action@v1.2.0220        with:221          template: .docker/Dockerfile-astar.j2222          output_file: .docker/Dockerfile-astar.${{ matrix.astar_version }}.yml223          variables: |224            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}225            ASTAR_BUILD_BRANCH=${{ matrix.astar_version }}226227      - name: Check if the dockerhub repository contains the needed ASTAR version228        run: |229          # aquire token230            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)231            export TOKEN=$TOKEN232233          # Get TAGS from DOCKERHUB repository234            ASTAR_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-astar/tags/?page_size=100 | jq -r '."results"[]["name"]')235          # Show TAGS236            echo "ASTAR TAGS:"237            echo $ASTAR_TAGS238          # Check correct version ASTAR and build it if it doesn't exist in ASTAR TAGS239            if [[ ${ASTAR_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.astar_version }}"($|[[:space:]]) ]]; then240                echo "Repository has needed ASTAR version";241                docker pull uniquenetwork/builder-astar:${{ matrix.astar_version }}242            else243                echo "Repository has not needed ASTAR version, so build it";244                cd .docker/ && docker build --file ./Dockerfile-astar.${{ matrix.astar_version }}.yml --tag uniquenetwork/builder-astar:${{ matrix.astar_version }} .245                echo "Push needed ASTAR version to the repository";246                docker push uniquenetwork/builder-astar:${{ matrix.astar_version }}247            fi248        shell: bash249250      # Check POLKADEX version and build it if it doesn't exist in repository251      - name: Generate ENV related extend Dockerfile file for POLKADEX252        uses: cuchi/jinja2-action@v1.2.0253        with:254          template: .docker/Dockerfile-polkadex.j2255          output_file: .docker/Dockerfile-polkadex.${{ matrix.polkadex_version }}.yml256          variables: |257            RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }}258            POLKADEX_BUILD_BRANCH=${{ matrix.polkadex_version }}259260      - name: Check if the dockerhub repository contains the needed POLKADEX version261        run: |262          # aquire token263            TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d '{"username": "'${{ secrets.CORE_DOCKERHUB_USERNAME }}'", "password": "'${{ secrets.CORE_DOCKERHUB_TOKEN }}'"}' https://hub.docker.com/v2/users/login/ | jq -r .token)264            export TOKEN=$TOKEN265266          # Get TAGS from DOCKERHUB repository267            POLKADEX_TAGS=$(curl -s -H "Authorization: JWT ${TOKEN}" https://hub.docker.com/v2/repositories/uniquenetwork/builder-polkadex/tags/?page_size=100 | jq -r '."results"[]["name"]')268          # Show TAGS269            echo "POLKADEX TAGS:"270            echo $POLKADEX_TAGS271          # Check correct version POLKADEX and build it if it doesn't exist in POLKADEX TAGS272            if [[ ${POLKADEX_TAGS[*]} =~ (^|[[:space:]])"${{ matrix.polkadex_version }}"($|[[:space:]]) ]]; then273                echo "Repository has needed POLKADEX version";274                docker pull uniquenetwork/builder-polkadex:${{ matrix.polkadex_version }}275            else276                echo "Repository has not needed POLKADEX version, so build it";277                cd .docker/ && docker build --file ./Dockerfile-polkadex.${{ matrix.polkadex_version }}.yml --tag uniquenetwork/builder-polkadex:${{ matrix.polkadex_version }} .278                echo "Push needed POLKADEX version to the repository";279                docker push uniquenetwork/builder-polkadex:${{ matrix.polkadex_version }}280            fi281        shell: bash282283      - name: Build unique-chain284        run: |285          docker build --file .docker/Dockerfile-unique \286            --build-arg RUNTIME_FEATURES=${{ matrix.runtime_features }} \287            --build-arg RUST_TOOLCHAIN=${{ env.RUST_TOOLCHAIN }} \288            --tag uniquenetwork/ci-xcm-local:${{ matrix.network }}-${{ env.REF_SLUG }}-${{ env.BUILD_SHA }} \289            .290291      - name: Push docker image version292        run: docker push uniquenetwork/ci-xcm-local:${{ matrix.network }}-${{ env.REF_SLUG }}-${{ env.BUILD_SHA }}293294      - uses: actions/setup-node@v3.5.1295        with:296          node-version: 18297298      - name: Install baedeker299        uses: UniqueNetwork/baedeker-action/setup@built300301      - name: Setup library302        run: mkdir -p .baedeker/vendor/ && git clone https://github.com/UniqueNetwork/baedeker-library .baedeker/vendor/baedeker-library303304      - name: Start network305        uses: UniqueNetwork/baedeker-action@built306        id: bdk307        with:308          jpath: |309            .baedeker/vendor310          tla-str: |311            relay_spec=${{ env.RELAY_CHAIN_TYPE }}-local312          inputs: |313            .baedeker/xcm-${{ matrix.network }}.jsonnet314            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/polkadot':{dockerImage:'uniquenetwork/builder-polkadot:${{ matrix.relay_branch }}'}})315            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/unique':{dockerImage:'uniquenetwork/ci-xcm-local:${{ matrix.network }}-${{ env.REF_SLUG }}-${{ env.BUILD_SHA }}'}})316            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/acala':{dockerImage:'uniquenetwork/builder-acala:${{ matrix.acala_version }}'}})317            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/moonbeam':{dockerImage:'uniquenetwork/builder-moonbeam:${{ matrix.moonbeam_version }}'}})318            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/cumulus':{dockerImage:'uniquenetwork/builder-cumulus:${{ matrix.cumulus_version }}'}})319            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/astar':{dockerImage:'uniquenetwork/builder-astar:${{ matrix.astar_version }}'}})320            snippet:(import 'baedeker-library/ops/rewrites.libsonnet').rewriteNodePaths({'bin/polkadex':{dockerImage:'uniquenetwork/builder-polkadex:${{ matrix.polkadex_version }}'}})321322      - name: Upload network config323        uses: actions/upload-artifact@v3324        with:325          name: ${{ matrix.network }}-network-config326          path: ${{ steps.bdk.outputs.composeProject }}327          retention-days: 2328329      - name: Run XCM tests330        working-directory: tests331        run: |332          yarn install333          yarn add mochawesome334          # Wanted by both wait_for_first_block335          export RPC_URL="${RELAY_OPAL_HTTP_URL:-${RELAY_QUARTZ_HTTP_URL:-${RELAY_UNIQUE_HTTP_URL:-}}}"336          ./scripts/wait_for_first_block.sh337          echo "Ready to start tests"338          NOW=$(date +%s) && yarn ${{ matrix.runtest }} --reporter mochawesome --reporter-options reportFilename=test-${NOW}339340      - name: XCM Test Report341        uses: phoenix-actions/test-reporting@v10342        id: test-report343        if: success() || failure()344        with:345          name: XCM Tests ${{ matrix.network }}346          path: tests/mochawesome-report/test-*.json347          reporter: mochawesome-json348          fail-on-error: 'false'349350      - name: Clean Workspace351        if: always()352        uses: AutoModality/action-clean@v1.1.0353354      - name: Remove builder cache355        if: always()356        run: |357          docker system prune -a -f
modifiedtests/src/xcm/lowLevelXcmQuartz.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/lowLevelXcmQuartz.test.ts
+++ b/tests/src/xcm/lowLevelXcmQuartz.test.ts
@@ -15,35 +15,16 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds,  usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util';
-import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';
-import {STATEMINE_CHAIN, QUARTZ_CHAIN, KARURA_CHAIN, MOONRIVER_CHAIN, SHIDEN_CHAIN, STATEMINE_DECIMALS, KARURA_DECIMALS, QTZ_DECIMALS, RELAY_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, relayUrl, shidenUrl, statemineUrl, SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT} from './xcm.types';
-
+import {itSub, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds,  usingMoonriverPlaygrounds, usingShidenPlaygrounds, usingRelayPlaygrounds} from '../util';
+import {QUARTZ_CHAIN,  QTZ_DECIMALS,  SHIDEN_DECIMALS, karuraUrl, moonriverUrl,  shidenUrl,  SAFE_XCM_VERSION, XcmTestHelper, TRANSFER_AMOUNT, SENDER_BUDGET, relayUrl} from './xcm.types';
+import {hexToString} from '@polkadot/util';
 
 const testHelper = new XcmTestHelper('quartz');
 
 describeXCM('[XCMLL] Integration test: Exchanging tokens with Karura', () => {
   let alice: IKeyringPair;
   let randomAccount: IKeyringPair;
-
-  let balanceQuartzTokenInit: bigint;
-  let balanceQuartzTokenMiddle: bigint;
-  let balanceQuartzTokenFinal: bigint;
-  let balanceKaruraTokenInit: bigint;
-  let balanceKaruraTokenMiddle: bigint;
-  let balanceKaruraTokenFinal: bigint;
-  let balanceQuartzForeignTokenInit: bigint;
-  let balanceQuartzForeignTokenMiddle: bigint;
-  let balanceQuartzForeignTokenFinal: bigint;
 
-  // computed by a test transfer from prod Quartz to prod Karura.
-  // 2 QTZ sent https://quartz.subscan.io/xcm_message/kusama-f60d821b049f8835a3005ce7102285006f5b61e9
-  // 1.919176000000000000 QTZ received (you can check Karura's chain state in the corresponding block)
-  const expectedKaruraIncomeFee = 2000000000000000000n - 1919176000000000000n;
-  const karuraEps = 8n * 10n ** 16n;
-
-  let karuraBackwardTransferAmount: bigint;
-
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       alice = await privateKey('//Alice');
@@ -72,15 +53,19 @@
         minimalBalance: 1000000000000000000n,
       };
 
-      await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+      const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
+        hexToString(v.toJSON()['symbol'])) as string[];
+
+      if(!assets.includes('QTZ')) {
+        await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+      } else {
+        console.log('QTZ token already registered on Karura assetRegistry pallet');
+      }
       await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
-      balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);
-      balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
     });
 
     await usingPlaygrounds(async (helper) => {
-      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);
-      balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccount.address);
+      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
     });
   });
 
@@ -100,67 +85,17 @@
 // the the corresponding foreign assets are not registered
 describeXCM('[XCMLL] Integration test: Quartz rejects non-native tokens', () => {
   let alice: IKeyringPair;
-  let alith: IKeyringPair;
 
-  const testAmount = 100_000_000_000n;
-  let quartzParachainJunction;
-  let quartzAccountJunction;
 
-  let quartzParachainMultilocation: any;
-  let quartzAccountMultilocation: any;
-  let quartzCombinedMultilocation: any;
-
-  let messageSent: any;
-
-  const maxWaitBlocks = 3;
-
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       alice = await privateKey('//Alice');
 
-      quartzParachainJunction = {Parachain: QUARTZ_CHAIN};
-      quartzAccountJunction = {
-        AccountId32: {
-          network: 'Any',
-          id: alice.addressRaw,
-        },
-      };
-
-      quartzParachainMultilocation = {
-        V2: {
-          parents: 1,
-          interior: {
-            X1: quartzParachainJunction,
-          },
-        },
-      };
 
-      quartzAccountMultilocation = {
-        V2: {
-          parents: 0,
-          interior: {
-            X1: quartzAccountJunction,
-          },
-        },
-      };
 
-      quartzCombinedMultilocation = {
-        V2: {
-          parents: 1,
-          interior: {
-            X2: [quartzParachainJunction, quartzAccountJunction],
-          },
-        },
-      };
-
       // Set the default version to wrap the first message to other chains.
       await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
     });
-
-    // eslint-disable-next-line require-await
-    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
-      alith = helper.account.alithAccount();
-    });
   });
 
   itSub('Quartz rejects KAR tokens from Karura', async () => {
@@ -195,22 +130,12 @@
     minimalBalance: 1n,
   };
 
-  let balanceQuartzTokenInit: bigint;
-  let balanceQuartzTokenMiddle: bigint;
-  let balanceQuartzTokenFinal: bigint;
-  let balanceForeignQtzTokenInit: bigint;
-  let balanceForeignQtzTokenMiddle: bigint;
-  let balanceForeignQtzTokenFinal: bigint;
-  let balanceMovrTokenInit: bigint;
-  let balanceMovrTokenMiddle: bigint;
-  let balanceMovrTokenFinal: bigint;
 
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       alice = await privateKey('//Alice');
       [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
 
-      balanceForeignQtzTokenInit = 0n;
 
       // Set the default version to wrap the first message to other chains.
       await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
@@ -239,20 +164,22 @@
       const isSufficient = true;
       const unitsPerSecond = 1n;
       const numAssetsWeightHint = 0;
+      if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
+        console.log('Quartz asset already registered on Moonriver');
+      } else {
+        const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+          location: quartzAssetLocation,
+          metadata: quartzAssetMetadata,
+          existentialDeposit,
+          isSufficient,
+          unitsPerSecond,
+          numAssetsWeightHint,
+        });
 
-      const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
-        location: quartzAssetLocation,
-        metadata: quartzAssetMetadata,
-        existentialDeposit,
-        isSufficient,
-        unitsPerSecond,
-        numAssetsWeightHint,
-      });
-
-      console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-
-      await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+        console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
 
+        await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+      }
       // >>> Acquire Quartz AssetId Info on Moonriver >>>
       console.log('Acquire Quartz AssetId Info on Moonriver.......');
 
@@ -267,13 +194,10 @@
       await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonriver.address, 11_000_000_000_000_000_000n);
       console.log('Sponsoring random Account.......DONE');
       // <<< Sponsoring random Account <<<
-
-      balanceMovrTokenInit = await helper.balance.getEthereum(randomAccountMoonriver.address);
     });
 
     await usingPlaygrounds(async (helper) => {
       await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
-      balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);
     });
   });
 
@@ -296,7 +220,7 @@
 
 describeXCM('[XCMLL] Integration test: Exchanging tokens with Shiden', () => {
   let alice: IKeyringPair;
-  let sender: IKeyringPair;
+  let randomAccount: IKeyringPair;
 
   const QTZ_ASSET_ID_ON_SHIDEN = 1;
   const QTZ_MINIMAL_BALANCE_ON_SHIDEN = 1n;
@@ -304,71 +228,69 @@
   // Quartz -> Shiden
   const shidenInitialBalance = 1n * (10n ** SHIDEN_DECIMALS); // 1 SHD, existential deposit required to actually create the account on Shiden
   const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours?
-  const qtzToShidenTransferred = 10n * (10n ** QTZ_DECIMALS); // 10 QTZ
-  const qtzToShidenArrived = 9_999_999_999_088_000_000n; // 9.999 ... QTZ, Shiden takes a commision in foreign tokens
 
-  // Shiden -> Quartz
-  const qtzFromShidenTransfered = 5n * (10n ** QTZ_DECIMALS); // 5 QTZ
-  const qtzOnShidenLeft = qtzToShidenArrived - qtzFromShidenTransfered; // 4.999_999_999_088_000_000n QTZ
 
-  let balanceAfterQuartzToShidenXCM: bigint;
 
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       alice = await privateKey('//Alice');
-      [sender] = await helper.arrange.createAccounts([100n], alice);
-      console.log('sender', sender.address);
+      randomAccount = helper.arrange.createEmptyAccount();
+      await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
+      console.log('sender: ', randomAccount.address);
 
       // Set the default version to wrap the first message to other chains.
       await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
     });
 
     await usingShidenPlaygrounds(shidenUrl, async (helper) => {
-      console.log('1. Create foreign asset and metadata');
-      // TODO update metadata with values from production
-      await helper.assets.create(
-        alice,
-        QTZ_ASSET_ID_ON_SHIDEN,
-        alice.address,
-        QTZ_MINIMAL_BALANCE_ON_SHIDEN,
-      );
+      if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
+        console.log('1. Create foreign asset and metadata');
+        // TODO update metadata with values from production
+        await helper.assets.create(
+          alice,
+          QTZ_ASSET_ID_ON_SHIDEN,
+          alice.address,
+          QTZ_MINIMAL_BALANCE_ON_SHIDEN,
+        );
 
-      await helper.assets.setMetadata(
-        alice,
-        QTZ_ASSET_ID_ON_SHIDEN,
-        'Cross chain QTZ',
-        'xcQTZ',
-        Number(QTZ_DECIMALS),
-      );
+        await helper.assets.setMetadata(
+          alice,
+          QTZ_ASSET_ID_ON_SHIDEN,
+          'Cross chain QTZ',
+          'xcQTZ',
+          Number(QTZ_DECIMALS),
+        );
 
-      console.log('2. Register asset location on Shiden');
-      const assetLocation = {
-        V2: {
-          parents: 1,
-          interior: {
-            X1: {
-              Parachain: QUARTZ_CHAIN,
+        console.log('2. Register asset location on Shiden');
+        const assetLocation = {
+          V2: {
+            parents: 1,
+            interior: {
+              X1: {
+                Parachain: QUARTZ_CHAIN,
+              },
             },
           },
-        },
-      };
-
-      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
+        };
 
-      console.log('3. Set QTZ payment for XCM execution on Shiden');
-      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
 
+        console.log('3. Set QTZ payment for XCM execution on Shiden');
+        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+      } else {
+        console.log('QTZ is already registered on Shiden');
+      }
       console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
-      await helper.balance.transferToSubstrate(alice, sender.address, shidenInitialBalance);
+      await helper.balance.transferToSubstrate(alice, randomAccount.address, shidenInitialBalance);
     });
   });
 
   itSub('Should connect and send QTZ to Shiden', async () => {
-    await testHelper.sendUnqTo('shiden', sender);
+    await testHelper.sendUnqTo('shiden', randomAccount);
   });
 
   itSub('Should connect to Shiden and send QTZ back', async () => {
-    await testHelper.sendUnqBack('shiden', alice, sender);
+    await testHelper.sendUnqBack('shiden', alice, randomAccount);
   });
 
   itSub('Shiden can send only up to its balance', async () => {
modifiedtests/src/xcm/lowLevelXcmUnique.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/lowLevelXcmUnique.test.ts
+++ b/tests/src/xcm/lowLevelXcmUnique.test.ts
@@ -16,320 +16,16 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import config from '../config';
-import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds, requirePalletsOrSkip, Pallets} from '../util';
-import {Event} from '../util/playgrounds/unique.dev';
+import {itSub, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds} from '../util';
 import {nToBigInt} from '@polkadot/util';
 import {hexToString} from '@polkadot/util';
-import {ASTAR_DECIMALS, NETWORKS, SAFE_XCM_VERSION, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl, expectFailedToTransact, expectUntrustedReserveLocationFail, getDevPlayground, mapToChainId, mapToChainUrl, maxWaitBlocks, moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types';
-
-
-const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;
-const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;
-const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;
-const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;
-const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;
-
-let balanceUniqueTokenInit: bigint;
-let balanceUniqueTokenMiddle: bigint;
-let balanceUniqueTokenFinal: bigint;
-let unqFees: bigint;
+import {ASTAR_DECIMALS, SAFE_XCM_VERSION, SENDER_BUDGET, UNIQUE_CHAIN, UNQ_DECIMALS, XcmTestHelper, acalaUrl, astarUrl,  moonbeamUrl, polkadexUrl, relayUrl, uniqueAssetId} from './xcm.types';
 
 const testHelper = new XcmTestHelper('unique');
-
-async function genericSendUnqTo(
-  networkName: keyof typeof NETWORKS,
-  randomAccount: IKeyringPair,
-  randomAccountOnTargetChain = randomAccount,
-) {
-  const networkUrl = mapToChainUrl(networkName);
-  const targetPlayground = getDevPlayground(networkName);
-  await usingPlaygrounds(async (helper) => {
-    balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
-    const destination = {
-      V2: {
-        parents: 1,
-        interior: {
-          X1: {
-            Parachain: mapToChainId(networkName),
-          },
-        },
-      },
-    };
-
-    const beneficiary = {
-      V2: {
-        parents: 0,
-        interior: {
-          X1: (
-            networkName == 'moonbeam' ?
-              {
-                AccountKey20: {
-                  network: 'Any',
-                  key: randomAccountOnTargetChain.address,
-                },
-              }
-              :
-              {
-                AccountId32: {
-                  network: 'Any',
-                  id: randomAccountOnTargetChain.addressRaw,
-                },
-              }
-          ),
-        },
-      },
-    };
-
-    const assets = {
-      V2: [
-        {
-          id: {
-            Concrete: {
-              parents: 0,
-              interior: 'Here',
-            },
-          },
-          fun: {
-            Fungible: TRANSFER_AMOUNT,
-          },
-        },
-      ],
-    };
-    const feeAssetItem = 0;
-
-    await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');
-    const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-    balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
-
-    unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
-    console.log('[Unique -> %s] transaction fees on Unique: %s UNQ', networkName, helper.util.bigIntToDecimals(unqFees));
-    expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
-
-    await targetPlayground(networkUrl, async (helper) => {
-      /*
-        Since only the parachain part of the Polkadex
-        infrastructure is launched (without their
-        solochain validators), processing incoming
-        assets will lead to an error.
-        This error indicates that the Polkadex chain
-        received a message from the Unique network,
-        since the hash is being checked to ensure
-        it matches what was sent.
-      */
-      if(networkName == 'polkadex') {
-        await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);
-      } else {
-        await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);
-      }
-    });
-
-  });
-}
-
-async function genericSendUnqBack(
-  networkName: keyof typeof NETWORKS,
-  sudoer: IKeyringPair,
-  randomAccountOnUnq: IKeyringPair,
-) {
-  const networkUrl = mapToChainUrl(networkName);
-
-  const targetPlayground = getDevPlayground(networkName);
-  await usingPlaygrounds(async (helper) => {
-
-    const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
-      randomAccountOnUnq.addressRaw,
-      uniqueAssetId,
-      SENDBACK_AMOUNT,
-    );
-
-    let xcmProgramSent: any;
-
 
-    await targetPlayground(networkUrl, async (helper) => {
-      if('getSudo' in helper) {
-        await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, xcmProgram);
-        xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      } else if('fastDemocracy' in helper) {
-        const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, xcmProgram]);
-        // Needed to bypass the call filter.
-        const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
-        await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
-        xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-    });
-
-    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);
-
-    balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);
-
-    expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees - STAYED_ON_TARGET_CHAIN);
-
-  });
-}
 
-async function genericSendOnlyOwnedBalance(
-  networkName: keyof typeof NETWORKS,
-  sudoer: IKeyringPair,
-) {
-  const networkUrl = mapToChainUrl(networkName);
-  const targetPlayground = getDevPlayground(networkName);
 
-  const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);
 
-  await usingPlaygrounds(async (helper) => {
-    const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));
-    await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);
-    const moreThanTargetChainHas = 2n * targetChainBalance;
-
-    const targetAccount = helper.arrange.createEmptyAccount();
-
-    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
-      targetAccount.addressRaw,
-      {
-        Concrete: {
-          parents: 0,
-          interior: 'Here',
-        },
-      },
-      moreThanTargetChainHas,
-    );
-
-    let maliciousXcmProgramSent: any;
-
-
-    await targetPlayground(networkUrl, async (helper) => {
-      if('getSudo' in helper) {
-        await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgram);
-        maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      } else if('fastDemocracy' in helper) {
-        const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);
-        // Needed to bypass the call filter.
-        const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
-        await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
-        maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-    });
-
-    await expectFailedToTransact(helper, maliciousXcmProgramSent);
-
-    const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
-    expect(targetAccountBalance).to.be.equal(0n);
-  });
-}
-
-async function genericReserveTransferUNQfrom(netwokrName: keyof typeof NETWORKS, sudoer: IKeyringPair) {
-  const networkUrl = mapToChainUrl(netwokrName);
-  const targetPlayground = getDevPlayground(netwokrName);
-
-  await usingPlaygrounds(async (helper) => {
-    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
-    const targetAccount = helper.arrange.createEmptyAccount();
-
-    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
-      targetAccount.addressRaw,
-      uniqueAssetId,
-      testAmount,
-    );
-
-    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
-      targetAccount.addressRaw,
-      {
-        Concrete: {
-          parents: 0,
-          interior: 'Here',
-        },
-      },
-      testAmount,
-    );
-
-    let maliciousXcmProgramFullIdSent: any;
-    let maliciousXcmProgramHereIdSent: any;
-    const maxWaitBlocks = 3;
-
-    // Try to trick Unique using full UNQ identification
-    await targetPlayground(networkUrl, async (helper) => {
-      if('getSudo' in helper) {
-        await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
-        maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-      // Moonbeam case
-      else if('fastDemocracy' in helper) {
-        const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
-        // Needed to bypass the call filter.
-        const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
-        await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using path asset identification`,batchCall);
-
-        maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-    });
-
-
-    await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);
-
-    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
-    expect(accountBalance).to.be.equal(0n);
-
-    // Try to trick Unique using shortened UNQ identification
-    await targetPlayground(networkUrl, async (helper) => {
-      if('getSudo' in helper) {
-        await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramHereId);
-        maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-      else if('fastDemocracy' in helper) {
-        const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);
-        // Needed to bypass the call filter.
-        const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
-        await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);
-
-        maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-    });
-
-    await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);
-
-    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
-    expect(accountBalance).to.be.equal(0n);
-  });
-}
-
-async function genericRejectNativeTokensFrom(networkName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {
-  const networkUrl = mapToChainUrl(networkName);
-  const targetPlayground = getDevPlayground(networkName);
-  let messageSent: any;
-
-  await usingPlaygrounds(async (helper) => {
-    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
-      helper.arrange.createEmptyAccount().addressRaw,
-      {
-        Concrete: {
-          parents: 1,
-          interior: {
-            X1: {
-              Parachain: mapToChainId(networkName),
-            },
-          },
-        },
-      },
-      TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,
-    );
-    await targetPlayground(networkUrl, async (helper) => {
-      if('getSudo' in helper) {
-        await helper.getSudo().xcm.send(sudoerOnTargetChain, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
-        messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      } else if('fastDemocracy' in helper) {
-        const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
-        // Needed to bypass the call filter.
-        const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
-        await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);
-
-        messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
-      }
-    });
-    await expectFailedToTransact(helper, messageSent);
-  });
-}
-
-
 describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {
   let alice: IKeyringPair;
   let randomAccount: IKeyringPair;
@@ -375,24 +71,23 @@
 
     await usingPlaygrounds(async (helper) => {
       await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
-      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
     });
   });
 
   itSub('Should connect and send UNQ to Acala', async () => {
-    await genericSendUnqTo('acala', randomAccount);
+    await testHelper.sendUnqTo('acala', randomAccount);
   });
 
   itSub('Should connect to Acala and send UNQ back', async () => {
-    await genericSendUnqBack('acala', alice, randomAccount);
+    await testHelper.sendUnqBack('acala', alice, randomAccount);
   });
 
   itSub('Acala can send only up to its balance', async () => {
-    await genericSendOnlyOwnedBalance('acala', alice);
+    await testHelper.sendOnlyOwnedBalance('acala', alice);
   });
 
   itSub('Should not accept reserve transfer of UNQ from Acala', async () => {
-    await genericReserveTransferUNQfrom('acala', alice);
+    await testHelper.reserveTransferUNQfrom('acala', alice);
   });
 });
 
@@ -430,7 +125,6 @@
 
     await usingPlaygrounds(async (helper) => {
       await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);
-      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);
     });
   });
 
@@ -467,19 +161,19 @@
   });
 
   itSub('Unique rejects ACA tokens from Acala', async () => {
-    await genericRejectNativeTokensFrom('acala', alice);
+    await testHelper.rejectNativeTokensFrom('acala', alice);
   });
 
   itSub('Unique rejects GLMR tokens from Moonbeam', async () => {
-    await genericRejectNativeTokensFrom('moonbeam', alice);
+    await testHelper.rejectNativeTokensFrom('moonbeam', alice);
   });
 
   itSub('Unique rejects ASTR tokens from Astar', async () => {
-    await genericRejectNativeTokensFrom('astar', alice);
+    await testHelper.rejectNativeTokensFrom('astar', alice);
   });
 
   itSub('Unique rejects PDX tokens from Polkadex', async () => {
-    await genericRejectNativeTokensFrom('polkadex', alice);
+    await testHelper.rejectNativeTokensFrom('polkadex', alice);
   });
 });
 
@@ -570,7 +264,6 @@
 
     await usingPlaygrounds(async (helper) => {
       await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);
-      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);
     });
   });
 
@@ -657,19 +350,19 @@
   });
 
   itSub('Should connect and send UNQ to Astar', async () => {
-    await genericSendUnqTo('astar', randomAccount);
+    await testHelper.sendUnqTo('astar', randomAccount);
   });
 
   itSub('Should connect to Astar and send UNQ back', async () => {
-    await genericSendUnqBack('astar', alice, randomAccount);
+    await testHelper.sendUnqBack('astar', alice, randomAccount);
   });
 
   itSub('Astar can send only up to its balance', async () => {
-    await genericSendOnlyOwnedBalance('astar', alice);
+    await testHelper.sendOnlyOwnedBalance('astar', alice);
   });
 
   itSub('Should not accept reserve transfer of UNQ from Astar', async () => {
-    await genericReserveTransferUNQfrom('astar', alice);
+    await testHelper.reserveTransferUNQfrom('astar', alice);
   });
 });
 
modifiedtests/src/xcm/xcm.types.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcm.types.ts
+++ b/tests/src/xcm/xcm.types.ts
@@ -3,7 +3,6 @@
 import {expect, usingAcalaPlaygrounds, usingAstarPlaygrounds, usingKaruraPlaygrounds, usingMoonbeamPlaygrounds, usingMoonriverPlaygrounds, usingPlaygrounds, usingPolkadexPlaygrounds, usingRelayPlaygrounds, usingShidenPlaygrounds} from '../util';
 import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';
 import config from '../config';
-import {blake2AsHex} from '@polkadot/util-crypto';
 
 export const UNIQUE_CHAIN = +(process.env.RELAY_UNIQUE_ID || 2037);
 export const STATEMINT_CHAIN = +(process.env.RELAY_STATEMINT_ID || 1000);
@@ -136,10 +135,10 @@
 }
 
 export const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;
-const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;
-const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;
-const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;
-const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;
+export const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;
+export const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;
+export const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;
+export const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;
 
 export class XcmTestHelper {
   private _balanceUniqueTokenInit: bigint = 0n;
@@ -163,6 +162,7 @@
         return UNIQUE_CHAIN;
     }
   }
+
   private _isAddress20FormatFor(network: NetworkNames) {
     switch (network) {
       case 'moonbeam':
@@ -173,6 +173,19 @@
     }
   }
 
+  private _runtimeVersionedMultilocation() {
+    return {
+      V3: {
+        parents: 1,
+        interior: {
+          X1: {
+            Parachain: this._getNativeId(),
+          },
+        },
+      },
+    };
+  }
+
   uniqueChainMultilocationForRelay() {
     return {
       V3: {
@@ -250,8 +263,8 @@
       this._balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);
 
       this._unqFees = this._balanceUniqueTokenInit - this._balanceUniqueTokenMiddle - TRANSFER_AMOUNT;
-      console.log('[Unique -> %s] transaction fees on Unique: %s UNQ', networkName, helper.util.bigIntToDecimals(this._unqFees));
-      expect(this._unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;
+      console.log('[%s -> %s] transaction fees: %s', this._nativeRuntime, networkName, helper.util.bigIntToDecimals(this._unqFees));
+      expect(this._unqFees > 0n, 'Negative fees, looks like nothing was transferred').to.be.true;
 
       await targetPlayground(networkUrl, async (helper) => {
       /*
@@ -302,10 +315,10 @@
 
       await targetPlayground(networkUrl, async (helper) => {
         if('getSudo' in helper) {
-          await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, xcmProgram);
+          await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), xcmProgram);
           xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
         } else if('fastDemocracy' in helper) {
-          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, xcmProgram]);
+          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), xcmProgram]);
           // Needed to bypass the call filter.
           const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
           await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
@@ -354,10 +367,10 @@
 
       await targetPlayground(networkUrl, async (helper) => {
         if('getSudo' in helper) {
-          await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgram);
+          await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgram);
           maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
         } else if('fastDemocracy' in helper) {
-          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);
+          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgram]);
           // Needed to bypass the call filter.
           const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
           await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);
@@ -413,12 +426,12 @@
       // Try to trick Unique using full UNQ identification
       await targetPlayground(networkUrl, async (helper) => {
         if('getSudo' in helper) {
-          await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
+          await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
           maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
         }
         // Moonbeam case
         else if('fastDemocracy' in helper) {
-          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
+          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
           // Needed to bypass the call filter.
           const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
           await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using path asset identification`,batchCall);
@@ -436,11 +449,11 @@
       // Try to trick Unique using shortened UNQ identification
       await targetPlayground(networkUrl, async (helper) => {
         if('getSudo' in helper) {
-          await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramHereId);
+          await helper.getSudo().xcm.send(sudoer, this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId);
           maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
         }
         else if('fastDemocracy' in helper) {
-          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);
+          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramHereId]);
           // Needed to bypass the call filter.
           const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
           await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);
@@ -478,10 +491,10 @@
       );
       await targetPlayground(networkUrl, async (helper) => {
         if('getSudo' in helper) {
-          await helper.getSudo().xcm.send(sudoerOnTargetChain, uniqueVersionedMultilocation, maliciousXcmProgramFullId);
+          await helper.getSudo().xcm.send(sudoerOnTargetChain, this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId);
           messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
         } else if('fastDemocracy' in helper) {
-          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);
+          const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [this._runtimeVersionedMultilocation(), maliciousXcmProgramFullId]);
           // Needed to bypass the call filter.
           const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
           await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmQuartz.test.ts
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -18,6 +18,7 @@
 import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';
 import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';
 import {STATEMINE_CHAIN, QUARTZ_CHAIN, KARURA_CHAIN, MOONRIVER_CHAIN, SHIDEN_CHAIN, STATEMINE_DECIMALS, KARURA_DECIMALS, QTZ_DECIMALS, RELAY_DECIMALS, SHIDEN_DECIMALS, karuraUrl, moonriverUrl, relayUrl, shidenUrl, statemineUrl} from './xcm.types';
+import {hexToString} from '@polkadot/util';
 
 
 
@@ -483,7 +484,14 @@
         minimalBalance: 1000000000000000000n,
       };
 
-      await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+      const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v]: [any, any]) =>
+        hexToString(v.toJSON()['symbol'])) as string[];
+
+      if(!assets.includes('QTZ')) {
+        await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);
+      } else {
+        console.log('QTZ token already registered on Karura assetRegistry pallet');
+      }
       await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);
       balanceKaruraTokenInit = await helper.balance.getSubstrate(randomAccount.address);
       balanceQuartzForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});
@@ -969,19 +977,22 @@
       const unitsPerSecond = 1n;
       const numAssetsWeightHint = 0;
 
-      const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
-        location: quartzAssetLocation,
-        metadata: quartzAssetMetadata,
-        existentialDeposit,
-        isSufficient,
-        unitsPerSecond,
-        numAssetsWeightHint,
-      });
-
-      console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
+      if((await helper.assetManager.assetTypeId(quartzAssetLocation)).toJSON()) {
+        console.log('Quartz asset already registered on Moonriver');
+      } else {
+        const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({
+          location: quartzAssetLocation,
+          metadata: quartzAssetMetadata,
+          existentialDeposit,
+          isSufficient,
+          unitsPerSecond,
+          numAssetsWeightHint,
+        });
 
-      await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+        console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
 
+        await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
+      }
       // >>> Acquire Quartz AssetId Info on Moonriver >>>
       console.log('Acquire Quartz AssetId Info on Moonriver.......');
 
@@ -1298,40 +1309,43 @@
     });
 
     await usingShidenPlaygrounds(shidenUrl, async (helper) => {
-      console.log('1. Create foreign asset and metadata');
-      // TODO update metadata with values from production
-      await helper.assets.create(
-        alice,
-        QTZ_ASSET_ID_ON_SHIDEN,
-        alice.address,
-        QTZ_MINIMAL_BALANCE_ON_SHIDEN,
-      );
+      if(!(await helper.callRpc('api.query.assets.asset', [QTZ_ASSET_ID_ON_SHIDEN])).toJSON()) {
+        console.log('1. Create foreign asset and metadata');
+        // TODO update metadata with values from production
+        await helper.assets.create(
+          alice,
+          QTZ_ASSET_ID_ON_SHIDEN,
+          alice.address,
+          QTZ_MINIMAL_BALANCE_ON_SHIDEN,
+        );
 
-      await helper.assets.setMetadata(
-        alice,
-        QTZ_ASSET_ID_ON_SHIDEN,
-        'Cross chain QTZ',
-        'xcQTZ',
-        Number(QTZ_DECIMALS),
-      );
+        await helper.assets.setMetadata(
+          alice,
+          QTZ_ASSET_ID_ON_SHIDEN,
+          'Cross chain QTZ',
+          'xcQTZ',
+          Number(QTZ_DECIMALS),
+        );
 
-      console.log('2. Register asset location on Shiden');
-      const assetLocation = {
-        V2: {
-          parents: 1,
-          interior: {
-            X1: {
-              Parachain: QUARTZ_CHAIN,
+        console.log('2. Register asset location on Shiden');
+        const assetLocation = {
+          V2: {
+            parents: 1,
+            interior: {
+              X1: {
+                Parachain: QUARTZ_CHAIN,
+              },
             },
           },
-        },
-      };
+        };
 
-      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
-
-      console.log('3. Set QTZ payment for XCM execution on Shiden');
-      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, QTZ_ASSET_ID_ON_SHIDEN]);
 
+        console.log('3. Set QTZ payment for XCM execution on Shiden');
+        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
+      } else {
+        console.log('QTZ is already registered on Shiden');
+      }
       console.log('4. Transfer 1 SDN to recipient to create the account (needed due to existential balance)');
       await helper.balance.transferToSubstrate(alice, sender.address, shidenInitialBalance);
     });