git.delta.rocks / unique-network / refs/commits / 74b1ef40cf52

difftreelog

fix xcm tests

Daniel Shiposha2023-11-23parent: #c16a17a.patch.diff
in: master

5 files changed

modifiedjs-packages/playgrounds/unique.xcm.tsdiffbeforeafterboth
--- a/js-packages/playgrounds/unique.xcm.ts
+++ b/js-packages/playgrounds/unique.xcm.ts
@@ -104,17 +104,17 @@
 }
 
 export class ForeignAssetsGroup extends HelperGroup<UniqueHelper> {
-  async register(signer: TSigner, location: any, name: string, tokenPrefix: string, mode: 'NFT' | { Fungible: number }) {
+  async register(signer: TSigner, assetId: any, name: string, tokenPrefix: string, mode: 'NFT' | { Fungible: number }) {
     await this.helper.executeExtrinsic(
       signer,
       'api.tx.foreignAssets.forceRegisterForeignAsset',
-      [location, this.helper.util.str2vec(name), tokenPrefix, mode],
+      [assetId, this.helper.util.str2vec(name), tokenPrefix, mode],
       true,
     );
   }
 
-  async foreignCollectionId(location: any) {
-    return (await this.helper.callRpc('api.query.foreignAssets.foreignReserveLocationToCollection', [location])).toJSON();
+  async foreignCollectionId(assetId: any) {
+    return (await this.helper.callRpc('api.query.foreignAssets.foreignAssetToCollection', [assetId])).toJSON();
   }
 }
 
modifiedjs-packages/tests/xcm/xcm.types.tsdiffbeforeafterboth
--- a/js-packages/tests/xcm/xcm.types.ts
+++ b/js-packages/tests/xcm/xcm.types.ts
@@ -512,15 +512,16 @@
         parents: 1,
         interior: 'Here',
       };
+      const relayAssetId = {Concrete: relayLocation};
 
-      const relayCollectionId = await helper.foreignAssets.foreignCollectionId(relayLocation);
+      const relayCollectionId = await helper.foreignAssets.foreignCollectionId(relayAssetId);
       if(relayCollectionId == null) {
         const name = 'Relay Tokens';
         const tokenPrefix = 'xDOT';
         const decimals = 10;
-        await helper.getSudo().foreignAssets.register(alice, relayLocation, name, tokenPrefix, {Fungible: decimals});
+        await helper.getSudo().foreignAssets.register(alice, relayAssetId, name, tokenPrefix, {Fungible: decimals});
 
-        return await helper.foreignAssets.foreignCollectionId(relayLocation);
+        return await helper.foreignAssets.foreignCollectionId(relayAssetId);
       } else {
         console.log('Relay foreign collection is already registered');
         return relayCollectionId;
modifiedjs-packages/tests/xcm/xcmOpal.test.tsdiffbeforeafterboth
--- a/js-packages/tests/xcm/xcmOpal.test.ts
+++ b/js-packages/tests/xcm/xcmOpal.test.ts
@@ -17,7 +17,7 @@
 import type {IKeyringPair} from '@polkadot/types/types';
 import config from '../config.js';
 import {itSub, expect, describeXCM, usingPlaygrounds, usingWestmintPlaygrounds, usingRelayPlaygrounds} from '../util/index.js';
-import {XcmTestHelper} from './xcm.types';
+import {XcmTestHelper} from './xcm.types.js';
 
 const STATEMINE_CHAIN = +(process.env.RELAY_WESTMINT_ID || 1000);
 const UNIQUE_CHAIN = +(process.env.RELAY_OPAL_ID || 2095);
@@ -120,16 +120,23 @@
           },
         ]},
       };
+      const assetId = {Concrete: location};
 
-      if(await helper.foreignAssets.foreignCollectionId(location) == null) {
+      if(await helper.foreignAssets.foreignCollectionId(assetId) == null) {
         const tokenPrefix = USDT_ASSET_METADATA_NAME;
-        await helper.getSudo().foreignAssets.register(alice, location, USDT_ASSET_METADATA_NAME, tokenPrefix, {Fungible: USDT_ASSET_METADATA_DECIMALS});
+        await helper.getSudo().foreignAssets.register(
+          alice,
+          assetId,
+          USDT_ASSET_METADATA_NAME,
+          tokenPrefix,
+          {Fungible: USDT_ASSET_METADATA_DECIMALS},
+        );
       } else {
         console.log('Foreign collection is already registered on Opal');
       }
 
       balanceOpalBefore = await helper.balance.getSubstrate(alice.address);
-      usdtCollectionId = await helper.foreignAssets.foreignCollectionId(location);
+      usdtCollectionId = await helper.foreignAssets.foreignCollectionId(assetId);
     });
 
     // Providing the relay currency to the unique sender account
modifiedjs-packages/tests/xcm/xcmQuartz.test.tsdiffbeforeafterboth
--- a/js-packages/tests/xcm/xcmQuartz.test.ts
+++ b/js-packages/tests/xcm/xcmQuartz.test.ts
@@ -19,7 +19,7 @@
 import {DevUniqueHelper, Event} from '@unique/playgrounds/unique.dev.js';
 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.js';
 import {hexToString} from '@polkadot/util';
-import {XcmTestHelper} from './xcm.types';
+import {XcmTestHelper} from './xcm.types.js';
 
 const STATEMINE_PALLET_INSTANCE = 50;
 
@@ -130,16 +130,17 @@
           },
         ]},
       };
+      const assetId = {Concrete: location};
 
-      if(await helper.foreignAssets.foreignCollectionId(location) == null) {
+      if(await helper.foreignAssets.foreignCollectionId(assetId) == null) {
         const tokenPrefix = USDT_ASSET_METADATA_NAME;
-        await helper.getSudo().foreignAssets.register(alice, location, USDT_ASSET_METADATA_NAME, tokenPrefix, {Fungible: USDT_ASSET_METADATA_DECIMALS});
+        await helper.getSudo().foreignAssets.register(alice, assetId, USDT_ASSET_METADATA_NAME, tokenPrefix, {Fungible: USDT_ASSET_METADATA_DECIMALS});
       } else {
         console.log('Foreign collection is already registered on Quartz');
       }
 
       balanceQuartzBefore = await helper.balance.getSubstrate(alice.address);
-      usdtCollectionId = await helper.foreignAssets.foreignCollectionId(location);
+      usdtCollectionId = await helper.foreignAssets.foreignCollectionId(assetId);
     });
 
 
modifiedjs-packages/tests/xcm/xcmUnique.test.tsdiffbeforeafterboth
before · js-packages/tests/xcm/xcmUnique.test.ts
1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import type {IKeyringPair} from '@polkadot/types/types';18import config from '../config.js';19import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util/index.js';20import {Event} from '@unique/playgrounds/unique.dev.js';21import {hexToString, nToBigInt} from '@polkadot/util';22import {ACALA_CHAIN, ASTAR_CHAIN, MOONBEAM_CHAIN, POLKADEX_CHAIN, SAFE_XCM_VERSION, STATEMINT_CHAIN, UNIQUE_CHAIN, expectFailedToTransact, expectUntrustedReserveLocationFail, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types.js';23import {XcmTestHelper} from './xcm.types';2425const STATEMINT_PALLET_INSTANCE = 50;2627const relayUrl = config.relayUrl;28const statemintUrl = config.statemintUrl;29const acalaUrl = config.acalaUrl;30const moonbeamUrl = config.moonbeamUrl;31const astarUrl = config.astarUrl;32const polkadexUrl = config.polkadexUrl;3334const RELAY_DECIMALS = 12;35const STATEMINT_DECIMALS = 12;36const ACALA_DECIMALS = 12;37const ASTAR_DECIMALS = 18n;38const UNQ_DECIMALS = 18n;3940const TRANSFER_AMOUNT = 2000000000000000000000000n;4142const FUNDING_AMOUNT = 3_500_000_0000_000_000n;4344const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;4546const USDT_ASSET_ID = 100;47const USDT_ASSET_METADATA_DECIMALS = 18;48const USDT_ASSET_METADATA_NAME = 'USDT';49const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';50const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;51const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;5253const testHelper = new XcmTestHelper('unique');5455describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {56  let alice: IKeyringPair;57  let bob: IKeyringPair;5859  let balanceStmnBefore: bigint;60  let balanceStmnAfter: bigint;6162  let balanceUniqueBefore: bigint;63  let balanceUniqueAfter: bigint;64  let balanceUniqueFinal: bigint;6566  let balanceBobBefore: bigint;67  let balanceBobAfter: bigint;68  let balanceBobFinal: bigint;6970  let balanceBobRelayTokenBefore: bigint;71  let balanceBobRelayTokenAfter: bigint;7273  let usdtCollectionId: number;74  let relayCollectionId: number;7576  before(async () => {77    await usingPlaygrounds(async (helper, privateKey) => {78      alice = await privateKey('//Alice');79      bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor8081      // Set the default version to wrap the first message to other chains.82      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);8384      relayCollectionId = await testHelper.registerRelayNativeTokenOnUnique(alice);85    });8687    await usingRelayPlaygrounds(relayUrl, async (helper) => {88      // Fund accounts on Statemint89      await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);90      await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);91    });9293    await usingStatemintPlaygrounds(statemintUrl, async (helper) => {94      const assetInfo = await helper.assets.assetInfo(USDT_ASSET_ID);95      if(assetInfo == null) {96        await helper.assets.create(97          alice,98          USDT_ASSET_ID,99          alice.address,100          USDT_ASSET_METADATA_MINIMAL_BALANCE,101        );102        await helper.assets.setMetadata(103          alice,104          USDT_ASSET_ID,105          USDT_ASSET_METADATA_NAME,106          USDT_ASSET_METADATA_DESCRIPTION,107          USDT_ASSET_METADATA_DECIMALS,108        );109      } else {110        console.log('The USDT asset is already registered on AssetHub');111      }112113      await helper.assets.mint(114        alice,115        USDT_ASSET_ID,116        alice.address,117        USDT_ASSET_AMOUNT,118      );119120      const sovereignFundingAmount = 3_500_000_000n;121122      // funding parachain sovereing account on Statemint.123      // The sovereign account should be created before any action124      // (the assets pallet on Statemint check if the sovereign account exists)125      const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);126      await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);127    });128129130    await usingPlaygrounds(async (helper) => {131      const location = {132        parents: 1,133        interior: {X3: [134          {135            Parachain: STATEMINT_CHAIN,136          },137          {138            PalletInstance: STATEMINT_PALLET_INSTANCE,139          },140          {141            GeneralIndex: USDT_ASSET_ID,142          },143        ]},144      };145146      if(await helper.foreignAssets.foreignCollectionId(location) == null) {147        const tokenPrefix = USDT_ASSET_METADATA_NAME;148        await helper.getSudo().foreignAssets.register(alice, location, USDT_ASSET_METADATA_NAME, tokenPrefix, {Fungible: USDT_ASSET_METADATA_DECIMALS});149      } else {150        console.log('Foreign collection is already registered on Unique');151      }152153      balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);154      usdtCollectionId = await helper.foreignAssets.foreignCollectionId(location);155    });156157158    // Providing the relay currency to the unique sender account159    // (fee for USDT XCM are paid in relay tokens)160    await usingRelayPlaygrounds(relayUrl, async (helper) => {161      const destination = {162        V2: {163          parents: 0,164          interior: {X1: {165            Parachain: UNIQUE_CHAIN,166          },167          },168        }};169170      const beneficiary = {171        V2: {172          parents: 0,173          interior: {X1: {174            AccountId32: {175              network: 'Any',176              id: alice.addressRaw,177            },178          }},179        },180      };181182      const assets = {183        V2: [184          {185            id: {186              Concrete: {187                parents: 0,188                interior: 'Here',189              },190            },191            fun: {192              Fungible: TRANSFER_AMOUNT_RELAY,193            },194          },195        ],196      };197198      const feeAssetItem = 0;199200      await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');201    });202203  });204205  itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {206    await usingStatemintPlaygrounds(statemintUrl, async (helper) => {207      const dest = {208        V2: {209          parents: 1,210          interior: {X1: {211            Parachain: UNIQUE_CHAIN,212          },213          },214        }};215216      const beneficiary = {217        V2: {218          parents: 0,219          interior: {X1: {220            AccountId32: {221              network: 'Any',222              id: alice.addressRaw,223            },224          }},225        },226      };227228      const assets = {229        V2: [230          {231            id: {232              Concrete: {233                parents: 0,234                interior: {235                  X2: [236                    {237                      PalletInstance: STATEMINT_PALLET_INSTANCE,238                    },239                    {240                      GeneralIndex: USDT_ASSET_ID,241                    },242                  ]},243              },244            },245            fun: {246              Fungible: TRANSFER_AMOUNT,247            },248          },249        ],250      };251252      const feeAssetItem = 0;253254      balanceStmnBefore = await helper.balance.getSubstrate(alice.address);255      await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');256257      balanceStmnAfter = await helper.balance.getSubstrate(alice.address);258259      // common good parachain take commission in it native token260      console.log(261        '[Statemint -> Unique] transaction fees on Statemint: %s WND',262        helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),263      );264      expect(balanceStmnBefore > balanceStmnAfter).to.be.true;265266    });267268269    // ensure that asset has been delivered270    await helper.wait.newBlocks(3);271272    const free = await helper.ft.getBalance(usdtCollectionId, {Substrate: alice.address});273274    balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);275276    console.log(277      '[Statemint -> Unique] transaction fees on Unique: %s USDT',278      helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),279    );280    console.log(281      '[Statemint -> Unique] transaction fees on Unique: %s UNQ',282      helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),283    );284    // commission has not paid in USDT token285    expect(free).to.be.equal(TRANSFER_AMOUNT);286    // ... and parachain native token287    expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;288  });289290  itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {291    const destination = {292      V2: {293        parents: 1,294        interior: {X2: [295          {296            Parachain: STATEMINT_CHAIN,297          },298          {299            AccountId32: {300              network: 'Any',301              id: alice.addressRaw,302            },303          },304        ]},305      },306    };307308    const relayFee = 400_000_000_000_000n;309    const currencies: [any, bigint][] = [310      [311        usdtCollectionId,312        TRANSFER_AMOUNT,313      ],314      [315        relayCollectionId,316        relayFee,317      ],318    ];319320    const feeItem = 1;321322    await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');323324    // the commission has been paid in parachain native token325    balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);326    console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueFinal));327    expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;328329    await usingStatemintPlaygrounds(statemintUrl, async (helper) => {330      await helper.wait.newBlocks(3);331332      // The USDT token never paid fees. Its amount not changed from begin value.333      // Also check that xcm transfer has been succeeded334      expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;335    });336  });337338  itSub('Should connect and send Relay token to Unique', async ({helper}) => {339    balanceBobBefore = await helper.balance.getSubstrate(bob.address);340    balanceBobRelayTokenBefore = await helper.ft.getBalance(relayCollectionId, {Substrate: bob.address});341342    await usingRelayPlaygrounds(relayUrl, async (helper) => {343      const destination = {344        V2: {345          parents: 0,346          interior: {X1: {347            Parachain: UNIQUE_CHAIN,348          },349          },350        }};351352      const beneficiary = {353        V2: {354          parents: 0,355          interior: {X1: {356            AccountId32: {357              network: 'Any',358              id: bob.addressRaw,359            },360          }},361        },362      };363364      const assets = {365        V2: [366          {367            id: {368              Concrete: {369                parents: 0,370                interior: 'Here',371              },372            },373            fun: {374              Fungible: TRANSFER_AMOUNT_RELAY,375            },376          },377        ],378      };379380      const feeAssetItem = 0;381382      await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');383    });384385    await helper.wait.newBlocks(3);386387    balanceBobAfter = await helper.balance.getSubstrate(bob.address);388    balanceBobRelayTokenAfter = await helper.ft.getBalance(relayCollectionId, {Substrate: bob.address});389390    const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;391    const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;392    console.log(393      '[Relay (Westend) -> Unique] transaction fees: %s UNQ',394      helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),395    );396    console.log(397      '[Relay (Westend) -> Unique] transaction fees: %s WND',398      helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),399    );400    console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);401    expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;402    expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;403  });404405  itSub('Should connect and send Relay token back', async ({helper}) => {406    let relayTokenBalanceBefore: bigint;407    let relayTokenBalanceAfter: bigint;408    await usingRelayPlaygrounds(relayUrl, async (helper) => {409      relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);410    });411412    const destination = {413      V2: {414        parents: 1,415        interior: {416          X1:{417            AccountId32: {418              network: 'Any',419              id: bob.addressRaw,420            },421          },422        },423      },424    };425426    const currencies: any = [427      [428        relayCollectionId,429        TRANSFER_AMOUNT_RELAY,430      ],431    ];432433    const feeItem = 0;434435    await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');436437    balanceBobFinal = await helper.balance.getSubstrate(bob.address);438    console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ',  helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));439440    await usingRelayPlaygrounds(relayUrl, async (helper) => {441      await helper.wait.newBlocks(10);442      relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);443444      const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;445      console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));446      expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;447    });448  });449});450451describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {452  let alice: IKeyringPair;453  let randomAccount: IKeyringPair;454455  let balanceUniqueTokenInit: bigint;456  let balanceUniqueTokenMiddle: bigint;457  let balanceUniqueTokenFinal: bigint;458  let balanceAcalaTokenInit: bigint;459  let balanceAcalaTokenMiddle: bigint;460  let balanceAcalaTokenFinal: bigint;461  let balanceUniqueForeignTokenInit: bigint;462  let balanceUniqueForeignTokenMiddle: bigint;463  let balanceUniqueForeignTokenFinal: bigint;464465  // computed by a test transfer from prod Unique to prod Acala.466  // 2 UNQ sent https://unique.subscan.io/xcm_message/polkadot-bad0b68847e2398af25d482e9ee6f9c1f9ec2a48467  // 1.898970000000000000 UNQ received (you can check Acala's chain state in the corresponding block)468  const expectedAcalaIncomeFee = 2000000000000000000n - 1898970000000000000n;469  const acalaEps = 8n * 10n ** 16n;470471  let acalaBackwardTransferAmount: bigint;472473  before(async () => {474    await usingPlaygrounds(async (helper, privateKey) => {475      alice = await privateKey('//Alice');476      [randomAccount] = await helper.arrange.createAccounts([0n], alice);477478      // Set the default version to wrap the first message to other chains.479      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);480    });481482    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {483      const destination = {484        V2: {485          parents: 1,486          interior: {487            X1: {488              Parachain: UNIQUE_CHAIN,489            },490          },491        },492      };493494      const metadata = {495        name: 'Unique Network',496        symbol: 'UNQ',497        decimals: 18,498        minimalBalance: 1250000000000000000n,499      };500      const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>501        hexToString(v.toJSON()['symbol'])) as string[];502503      if(!assets.includes('UNQ')) {504        await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);505      } else {506        console.log('UNQ token already registered on Acala assetRegistry pallet');507      }508      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);509      balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);510      balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});511    });512513    await usingPlaygrounds(async (helper) => {514      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);515      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);516    });517  });518519  itSub('Should connect and send UNQ to Acala', async ({helper}) => {520521    const destination = {522      V2: {523        parents: 1,524        interior: {525          X1: {526            Parachain: ACALA_CHAIN,527          },528        },529      },530    };531532    const beneficiary = {533      V2: {534        parents: 0,535        interior: {536          X1: {537            AccountId32: {538              network: 'Any',539              id: randomAccount.addressRaw,540            },541          },542        },543      },544    };545546    const assets = {547      V2: [548        {549          id: {550            Concrete: {551              parents: 0,552              interior: 'Here',553            },554          },555          fun: {556            Fungible: TRANSFER_AMOUNT,557          },558        },559      ],560    };561562    const feeAssetItem = 0;563564    await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');565    balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);566567    const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;568    console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));569    expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;570571    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {572      await helper.wait.newBlocks(3);573574      balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});575      balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);576577      const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;578      const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;579      acalaBackwardTransferAmount = unqIncomeTransfer;580581      const acaUnqFees = TRANSFER_AMOUNT - unqIncomeTransfer;582583      console.log(584        '[Unique -> Acala] transaction fees on Acala: %s ACA',585        helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),586      );587      console.log(588        '[Unique -> Acala] transaction fees on Acala: %s UNQ',589        helper.util.bigIntToDecimals(acaUnqFees),590      );591      console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));592      expect(acaFees == 0n).to.be.true;593594      const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;595596      expect(597        bigintAbs(acaUnqFees - expectedAcalaIncomeFee) < acalaEps,598        'Acala took different income fee, check the Acala foreign asset config',599      ).to.be.true;600    });601  });602603  itSub('Should connect to Acala and send UNQ back', async ({helper}) => {604    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {605      const destination = {606        V2: {607          parents: 1,608          interior: {609            X2: [610              {Parachain: UNIQUE_CHAIN},611              {612                AccountId32: {613                  network: 'Any',614                  id: randomAccount.addressRaw,615                },616              },617            ],618          },619        },620      };621622      const id = {623        ForeignAsset: 0,624      };625626      await helper.xTokens.transfer(randomAccount, id, acalaBackwardTransferAmount, destination, 'Unlimited');627      balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);628      balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);629630      const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;631      const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;632633      console.log(634        '[Acala -> Unique] transaction fees on Acala: %s ACA',635        helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),636      );637      console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));638639      expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;640      expect(unqOutcomeTransfer == acalaBackwardTransferAmount).to.be.true;641    });642643    await helper.wait.newBlocks(3);644645    balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);646    const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;647    expect(actuallyDelivered > 0).to.be.true;648649    console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));650651    const unqFees = acalaBackwardTransferAmount - actuallyDelivered;652    console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));653    expect(unqFees == 0n).to.be.true;654  });655656  itSub('Acala can send only up to its balance', async ({helper}) => {657    // set Acala's sovereign account's balance658    const acalaBalance = 10000n * (10n ** UNQ_DECIMALS);659    const acalaSovereignAccount = helper.address.paraSiblingSovereignAccount(ACALA_CHAIN);660    await helper.getSudo().balance.setBalanceSubstrate(alice, acalaSovereignAccount, acalaBalance);661662    const moreThanAcalaHas = acalaBalance * 2n;663664    let targetAccountBalance = 0n;665    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);666667    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(668      targetAccount.addressRaw,669      {670        Concrete: {671          parents: 0,672          interior: 'Here',673        },674      },675      moreThanAcalaHas,676    );677678    let maliciousXcmProgramSent: any;679    const maxWaitBlocks = 3;680681    // Try to trick Unique682    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {683      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);684685      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);686    });687688    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash689        && event.outcome.isFailedToTransactAsset);690691    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);692    expect(targetAccountBalance).to.be.equal(0n);693694    // But Acala still can send the correct amount695    const validTransferAmount = acalaBalance / 2n;696    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(697      targetAccount.addressRaw,698      {699        Concrete: {700          parents: 0,701          interior: 'Here',702        },703      },704      validTransferAmount,705    );706707    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {708      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);709    });710711    await helper.wait.newBlocks(maxWaitBlocks);712713    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);714    expect(targetAccountBalance).to.be.equal(validTransferAmount);715  });716717  itSub('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {718    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);719    const [targetAccount] = await helper.arrange.createAccounts([0n], alice);720721    const uniqueMultilocation = {722      V2: {723        parents: 1,724        interior: {725          X1: {726            Parachain: UNIQUE_CHAIN,727          },728        },729      },730    };731732    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(733      targetAccount.addressRaw,734      uniqueAssetId,735      testAmount,736    );737738    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(739      targetAccount.addressRaw,740      {741        Concrete: {742          parents: 0,743          interior: 'Here',744        },745      },746      testAmount,747    );748749    let maliciousXcmProgramFullIdSent: any;750    let maliciousXcmProgramHereIdSent: any;751    const maxWaitBlocks = 3;752753    // Try to trick Unique using full UNQ identification754    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {755      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);756757      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);758    });759760    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash761        && event.outcome.isUntrustedReserveLocation);762763    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);764    expect(accountBalance).to.be.equal(0n);765766    // Try to trick Unique using shortened UNQ identification767    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {768      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);769770      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);771    });772773    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash774        && event.outcome.isUntrustedReserveLocation);775776    accountBalance = await helper.balance.getSubstrate(targetAccount.address);777    expect(accountBalance).to.be.equal(0n);778  });779});780781describeXCM('[XCM] Integration test: Exchanging tokens with Polkadex', () => {782  let alice: IKeyringPair;783  let randomAccount: IKeyringPair;784  let unqFees: bigint;785  let balanceUniqueTokenInit: bigint;786  let balanceUniqueTokenMiddle: bigint;787  let balanceUniqueTokenFinal: bigint;788  const maxWaitBlocks = 6;789790  before(async () => {791    await usingPlaygrounds(async (helper, privateKey) => {792      alice = await privateKey('//Alice');793      [randomAccount] = await helper.arrange.createAccounts([0n], alice);794795      // Set the default version to wrap the first message to other chains.796      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);797    });798799    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {800      const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))801        .toJSON() as [])802        .map(nToBigInt).length != 0;803      /*804      Check whether the Unique token has been added805      to the whitelist, since an error will occur806      if it is added again. Needed for debugging807      when this test is run multiple times.808      */809      if(isWhitelisted) {810        console.log('UNQ token is already whitelisted on Polkadex');811      } else {812        await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);813      }814815      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);816    });817818    await usingPlaygrounds(async (helper) => {819      await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);820      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);821    });822  });823824  itSub('Should connect and send UNQ to Polkadex', async ({helper}) => {825826    const destination = {827      V2: {828        parents: 1,829        interior: {830          X1: {831            Parachain: POLKADEX_CHAIN,832          },833        },834      },835    };836837    const beneficiary = {838      V2: {839        parents: 0,840        interior: {841          X1: {842            AccountId32: {843              network: 'Any',844              id: randomAccount.addressRaw,845            },846          },847        },848      },849    };850851    const assets = {852      V2: [853        {854          id: {855            Concrete: {856              parents: 0,857              interior: 'Here',858            },859          },860          fun: {861            Fungible: TRANSFER_AMOUNT,862          },863        },864      ],865    };866867    const feeAssetItem = 0;868869    await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');870    const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);871    balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);872873    unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;874    console.log('[Unique -> Polkadex] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));875    expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;876877    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {878      /*879        Since only the parachain part of the Polkadex880        infrastructure is launched (without their881        solochain validators), processing incoming882        assets will lead to an error.883        This error indicates that the Polkadex chain884        received a message from the Unique network,885        since the hash is being checked to ensure886        it matches what was sent.887      */888      await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);889    });890  });891892893  itSub('Should connect to Polkadex and send UNQ back', async ({helper}) => {894895    const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(896      randomAccount.addressRaw,897      uniqueAssetId,898      TRANSFER_AMOUNT,899    );900901    let xcmProgramSent: any;902903904    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {905      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, xcmProgram);906907      xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);908    });909910    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);911912    balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);913914    expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees);915  });916917  itSub('Polkadex can send only up to its balance', async ({helper}) => {918    const polkadexBalance = 10000n * (10n ** UNQ_DECIMALS);919    const polkadexSovereignAccount = helper.address.paraSiblingSovereignAccount(POLKADEX_CHAIN);920    await helper.getSudo().balance.setBalanceSubstrate(alice, polkadexSovereignAccount, polkadexBalance);921    const moreThanPolkadexHas = 2n * polkadexBalance;922923    const targetAccount = helper.arrange.createEmptyAccount();924925    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(926      targetAccount.addressRaw,927      {928        Concrete: {929          parents: 0,930          interior: 'Here',931        },932      },933      moreThanPolkadexHas,934    );935936    let maliciousXcmProgramSent: any;937938939    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {940      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);941942      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);943    });944945    await expectFailedToTransact(helper, maliciousXcmProgramSent);946947    const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);948    expect(targetAccountBalance).to.be.equal(0n);949  });950951  itSub('Should not accept reserve transfer of UNQ from Polkadex', async ({helper}) => {952    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);953    const targetAccount = helper.arrange.createEmptyAccount();954955    const uniqueMultilocation = {956      V2: {957        parents: 1,958        interior: {959          X1: {960            Parachain: UNIQUE_CHAIN,961          },962        },963      },964    };965966    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(967      targetAccount.addressRaw,968      uniqueAssetId,969      testAmount,970    );971972    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(973      targetAccount.addressRaw,974      {975        Concrete: {976          parents: 0,977          interior: 'Here',978        },979      },980      testAmount,981    );982983    let maliciousXcmProgramFullIdSent: any;984    let maliciousXcmProgramHereIdSent: any;985    const maxWaitBlocks = 3;986987    // Try to trick Unique using full UNQ identification988    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {989      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);990991      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);992    });993994    await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);995996    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);997    expect(accountBalance).to.be.equal(0n);998999    // Try to trick Unique using shortened UNQ identification1000    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {1001      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);10021003      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1004    });10051006    await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);10071008    accountBalance = await helper.balance.getSubstrate(targetAccount.address);1009    expect(accountBalance).to.be.equal(0n);1010  });1011});10121013// These tests are relevant only when1014// the the corresponding foreign assets are not registered1015describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {1016  let alice: IKeyringPair;1017  let alith: IKeyringPair;10181019  const testAmount = 100_000_000_000n;1020  let uniqueParachainJunction;1021  let uniqueAccountJunction;10221023  let uniqueParachainMultilocation: any;1024  let uniqueAccountMultilocation: any;1025  let uniqueCombinedMultilocation: any;1026  let uniqueCombinedMultilocationAcala: any; // TODO remove when Acala goes V210271028  let messageSent: any;10291030  const maxWaitBlocks = 3;10311032  before(async () => {1033    await usingPlaygrounds(async (helper, privateKey) => {1034      alice = await privateKey('//Alice');10351036      uniqueParachainJunction = {Parachain: UNIQUE_CHAIN};1037      uniqueAccountJunction = {1038        AccountId32: {1039          network: 'Any',1040          id: alice.addressRaw,1041        },1042      };10431044      uniqueParachainMultilocation = {1045        V2: {1046          parents: 1,1047          interior: {1048            X1: uniqueParachainJunction,1049          },1050        },1051      };10521053      uniqueAccountMultilocation = {1054        V2: {1055          parents: 0,1056          interior: {1057            X1: uniqueAccountJunction,1058          },1059        },1060      };10611062      uniqueCombinedMultilocation = {1063        V2: {1064          parents: 1,1065          interior: {1066            X2: [uniqueParachainJunction, uniqueAccountJunction],1067          },1068        },1069      };10701071      uniqueCombinedMultilocationAcala = {1072        V2: {1073          parents: 1,1074          interior: {1075            X2: [uniqueParachainJunction, uniqueAccountJunction],1076          },1077        },1078      };10791080      // Set the default version to wrap the first message to other chains.1081      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1082    });10831084    // eslint-disable-next-line require-await1085    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1086      alith = helper.account.alithAccount();1087    });1088  });1089109010911092  itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {1093    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {1094      const id = {1095        Token: 'ACA',1096      };1097      const destination = uniqueCombinedMultilocationAcala;1098      await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');10991100      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1101    });11021103    await expectFailedToTransact(helper, messageSent);1104  });11051106  itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => {1107    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1108      const id = 'SelfReserve';1109      const destination = uniqueCombinedMultilocation;1110      await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');11111112      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1113    });11141115    await expectFailedToTransact(helper, messageSent);1116  });11171118  itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => {1119    await usingAstarPlaygrounds(astarUrl, async (helper) => {1120      const destinationParachain = uniqueParachainMultilocation;1121      const beneficiary = uniqueAccountMultilocation;1122      const assets = {1123        V2: [{1124          id: {1125            Concrete: {1126              parents: 0,1127              interior: 'Here',1128            },1129          },1130          fun: {1131            Fungible: testAmount,1132          },1133        }],1134      };1135      const feeAssetItem = 0;11361137      await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [1138        destinationParachain,1139        beneficiary,1140        assets,1141        feeAssetItem,1142      ]);11431144      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1145    });11461147    await expectFailedToTransact(helper, messageSent);1148  });11491150  itSub('Unique rejects PDX tokens from Polkadex', async ({helper}) => {11511152    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1153      helper.arrange.createEmptyAccount().addressRaw,1154      {1155        Concrete: {1156          parents: 1,1157          interior: {1158            X1: {1159              Parachain: POLKADEX_CHAIN,1160            },1161          },1162        },1163      },1164      testAmount,1165    );11661167    await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {1168      await helper.getSudo().xcm.send(alice, uniqueParachainMultilocation, maliciousXcmProgramFullId);1169      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1170    });11711172    await expectFailedToTransact(helper, messageSent);1173  });1174});11751176describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {1177  // Unique constants1178  let alice: IKeyringPair;1179  let uniqueAssetLocation;11801181  let randomAccountUnique: IKeyringPair;1182  let randomAccountMoonbeam: IKeyringPair;11831184  // Moonbeam constants1185  let assetId: string;11861187  const uniqueAssetMetadata = {1188    name: 'xcUnique',1189    symbol: 'xcUNQ',1190    decimals: 18,1191    isFrozen: false,1192    minimalBalance: 1n,1193  };11941195  let balanceUniqueTokenInit: bigint;1196  let balanceUniqueTokenMiddle: bigint;1197  let balanceUniqueTokenFinal: bigint;1198  let balanceForeignUnqTokenInit: bigint;1199  let balanceForeignUnqTokenMiddle: bigint;1200  let balanceForeignUnqTokenFinal: bigint;1201  let balanceGlmrTokenInit: bigint;1202  let balanceGlmrTokenMiddle: bigint;1203  let balanceGlmrTokenFinal: bigint;12041205  before(async () => {1206    await usingPlaygrounds(async (helper, privateKey) => {1207      alice = await privateKey('//Alice');1208      [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);12091210      balanceForeignUnqTokenInit = 0n;12111212      // Set the default version to wrap the first message to other chains.1213      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1214    });12151216    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1217      const alithAccount = helper.account.alithAccount();1218      const baltatharAccount = helper.account.baltatharAccount();1219      const dorothyAccount = helper.account.dorothyAccount();12201221      randomAccountMoonbeam = helper.account.create();12221223      // >>> Sponsoring Dorothy >>>1224      console.log('Sponsoring Dorothy.......');1225      await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);1226      console.log('Sponsoring Dorothy.......DONE');1227      // <<< Sponsoring Dorothy <<<12281229      uniqueAssetLocation = {1230        XCM: {1231          parents: 1,1232          interior: {X1: {Parachain: UNIQUE_CHAIN}},1233        },1234      };1235      const existentialDeposit = 1n;1236      const isSufficient = true;1237      const unitsPerSecond = 1n;1238      const numAssetsWeightHint = 0;12391240      if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {1241        console.log('Unique asset is already registered on MoonBeam');1242      } else {1243        const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({1244          location: uniqueAssetLocation,1245          metadata: uniqueAssetMetadata,1246          existentialDeposit,1247          isSufficient,1248          unitsPerSecond,1249          numAssetsWeightHint,1250        });12511252        console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);12531254        await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);1255      }12561257      // >>> Acquire Unique AssetId Info on Moonbeam >>>1258      console.log('Acquire Unique AssetId Info on Moonbeam.......');12591260      assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();1261      console.log('UNQ asset ID is %s', assetId);1262      console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');1263      // >>> Acquire Unique AssetId Info on Moonbeam >>>12641265      // >>> Sponsoring random Account >>>1266      console.log('Sponsoring random Account.......');1267      await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);1268      console.log('Sponsoring random Account.......DONE');1269      // <<< Sponsoring random Account <<<12701271      balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);1272    });12731274    await usingPlaygrounds(async (helper) => {1275      await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);1276      balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);1277    });1278  });12791280  itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {1281    const currencyId = 0;1282    const dest = {1283      V2: {1284        parents: 1,1285        interior: {1286          X2: [1287            {Parachain: MOONBEAM_CHAIN},1288            {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},1289          ],1290        },1291      },1292    };1293    const amount = TRANSFER_AMOUNT;12941295    await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');12961297    balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);1298    expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;12991300    const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;1301    console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));1302    expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;13031304    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1305      await helper.wait.newBlocks(3);1306      balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);13071308      const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;1309      console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));1310      expect(glmrFees == 0n).to.be.true;13111312      balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;13131314      const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;1315      console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));1316      expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;1317    });1318  });13191320  itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {1321    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1322      const asset = {1323        V2: {1324          id: {1325            Concrete: {1326              parents: 1,1327              interior: {1328                X1: {Parachain: UNIQUE_CHAIN},1329              },1330            },1331          },1332          fun: {1333            Fungible: TRANSFER_AMOUNT,1334          },1335        },1336      };1337      const destination = {1338        V2: {1339          parents: 1,1340          interior: {1341            X2: [1342              {Parachain: UNIQUE_CHAIN},1343              {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},1344            ],1345          },1346        },1347      };13481349      await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, 'Unlimited');13501351      balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);13521353      const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;1354      console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));1355      expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;13561357      const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);13581359      expect(unqRandomAccountAsset).to.be.null;13601361      balanceForeignUnqTokenFinal = 0n;13621363      const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;1364      console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));1365      expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;1366    });13671368    await helper.wait.newBlocks(3);13691370    balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);1371    const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;1372    expect(actuallyDelivered > 0).to.be.true;13731374    console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));13751376    const unqFees = TRANSFER_AMOUNT - actuallyDelivered;1377    console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));1378    expect(unqFees == 0n).to.be.true;1379  });13801381  itSub('Moonbeam can send only up to its balance', async ({helper}) => {1382    // set Moonbeam's sovereign account's balance1383    const moonbeamBalance = 10000n * (10n ** UNQ_DECIMALS);1384    const moonbeamSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONBEAM_CHAIN);1385    await helper.getSudo().balance.setBalanceSubstrate(alice, moonbeamSovereignAccount, moonbeamBalance);13861387    const moreThanMoonbeamHas = moonbeamBalance * 2n;13881389    let targetAccountBalance = 0n;1390    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);13911392    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1393      targetAccount.addressRaw,1394      {1395        Concrete: {1396          parents: 0,1397          interior: 'Here',1398        },1399      },1400      moreThanMoonbeamHas,1401    );14021403    let maliciousXcmProgramSent: any;1404    const maxWaitBlocks = 3;14051406    // Try to trick Unique1407    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1408      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);14091410      // Needed to bypass the call filter.1411      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1412      await helper.fastDemocracy.executeProposal('try to spend more UNQ than Moonbeam has', batchCall);14131414      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1415    });14161417    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash1418        && event.outcome.isFailedToTransactAsset);14191420    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1421    expect(targetAccountBalance).to.be.equal(0n);14221423    // But Moonbeam still can send the correct amount1424    const validTransferAmount = moonbeamBalance / 2n;1425    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1426      targetAccount.addressRaw,1427      {1428        Concrete: {1429          parents: 0,1430          interior: 'Here',1431        },1432      },1433      validTransferAmount,1434    );14351436    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1437      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, validXcmProgram]);14381439      // Needed to bypass the call filter.1440      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1441      await helper.fastDemocracy.executeProposal('Spend the correct amount of UNQ', batchCall);1442    });14431444    await helper.wait.newBlocks(maxWaitBlocks);14451446    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1447    expect(targetAccountBalance).to.be.equal(validTransferAmount);1448  });14491450  itSub('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {1451    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);1452    const [targetAccount] = await helper.arrange.createAccounts([0n], alice);14531454    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1455      targetAccount.addressRaw,1456      uniqueAssetId,1457      testAmount,1458    );14591460    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(1461      targetAccount.addressRaw,1462      {1463        Concrete: {1464          parents: 0,1465          interior: 'Here',1466        },1467      },1468      testAmount,1469    );14701471    let maliciousXcmProgramFullIdSent: any;1472    let maliciousXcmProgramHereIdSent: any;1473    const maxWaitBlocks = 3;14741475    // Try to trick Unique using full UNQ identification1476    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1477      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);14781479      // Needed to bypass the call filter.1480      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1481      await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using path asset identification', batchCall);14821483      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1484    });14851486    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash1487        && event.outcome.isUntrustedReserveLocation);14881489    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1490    expect(accountBalance).to.be.equal(0n);14911492    // Try to trick Unique using shortened UNQ identification1493    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1494      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);14951496      // Needed to bypass the call filter.1497      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1498      await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using "here" asset identification', batchCall);14991500      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1501    });15021503    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash1504        && event.outcome.isUntrustedReserveLocation);15051506    accountBalance = await helper.balance.getSubstrate(targetAccount.address);1507    expect(accountBalance).to.be.equal(0n);1508  });1509});15101511describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {1512  let alice: IKeyringPair;1513  let randomAccount: IKeyringPair;15141515  const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar1516  const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar15171518  // Unique -> Astar1519  const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.1520  const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar1521  const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ1522  const unqToAstarArrived = 9_962_196_000_000_000_000n; // 9.962 ... UNQ, Astar takes a commision in foreign tokens15231524  // Astar -> Unique1525  const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ1526  const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.962_219_600_000_000_000n UNQ15271528  let balanceAfterUniqueToAstarXCM: bigint;15291530  before(async () => {1531    await usingPlaygrounds(async (helper, privateKey) => {1532      alice = await privateKey('//Alice');1533      [randomAccount] = await helper.arrange.createAccounts([100n], alice);1534      console.log('randomAccount', randomAccount.address);15351536      // Set the default version to wrap the first message to other chains.1537      await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1538    });15391540    await usingAstarPlaygrounds(astarUrl, async (helper) => {1541      if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {1542        console.log('1. Create foreign asset and metadata');1543        await helper.getSudo().assets.forceCreate(1544          alice,1545          UNQ_ASSET_ID_ON_ASTAR,1546          alice.address,1547          UNQ_MINIMAL_BALANCE_ON_ASTAR,1548        );15491550        await helper.assets.setMetadata(1551          alice,1552          UNQ_ASSET_ID_ON_ASTAR,1553          'Unique Network',1554          'UNQ',1555          Number(UNQ_DECIMALS),1556        );15571558        console.log('2. Register asset location on Astar');1559        const assetLocation = {1560          V2: {1561            parents: 1,1562            interior: {1563              X1: {1564                Parachain: UNIQUE_CHAIN,1565              },1566            },1567          },1568        };15691570        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);15711572        console.log('3. Set UNQ payment for XCM execution on Astar');1573        await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);1574      } else {1575        console.log('UNQ is already registered on Astar');1576      }1577      console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');1578      await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);1579    });1580  });15811582  itSub('Should connect and send UNQ to Astar', async ({helper}) => {1583    const destination = {1584      V2: {1585        parents: 1,1586        interior: {1587          X1: {1588            Parachain: ASTAR_CHAIN,1589          },1590        },1591      },1592    };15931594    const beneficiary = {1595      V2: {1596        parents: 0,1597        interior: {1598          X1: {1599            AccountId32: {1600              network: 'Any',1601              id: randomAccount.addressRaw,1602            },1603          },1604        },1605      },1606    };16071608    const assets = {1609      V2: [1610        {1611          id: {1612            Concrete: {1613              parents: 0,1614              interior: 'Here',1615            },1616          },1617          fun: {1618            Fungible: unqToAstarTransferred,1619          },1620        },1621      ],1622    };16231624    // Initial balance is 100 UNQ1625    const balanceBefore = await helper.balance.getSubstrate(randomAccount.address);1626    console.log(`Initial balance is: ${balanceBefore}`);16271628    const feeAssetItem = 0;1629    await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');16301631    // Balance after reserve transfer is less than 901632    balanceAfterUniqueToAstarXCM = await helper.balance.getSubstrate(randomAccount.address);1633    console.log(`UNQ Balance on Unique after XCM is: ${balanceAfterUniqueToAstarXCM}`);1634    console.log(`Unique's UNQ commission is: ${balanceBefore - balanceAfterUniqueToAstarXCM}`);1635    expect(balanceBefore - balanceAfterUniqueToAstarXCM > 0).to.be.true;16361637    await usingAstarPlaygrounds(astarUrl, async (helper) => {1638      await helper.wait.newBlocks(3);1639      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);1640      const astarBalance = await helper.balance.getSubstrate(randomAccount.address);16411642      console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);1643      console.log(`Astar's UNQ commission is: ${unqToAstarTransferred - xcUNQbalance!}`);16441645      expect(xcUNQbalance).to.eq(unqToAstarArrived);1646      // Astar balance does not changed1647      expect(astarBalance).to.eq(astarInitialBalance);1648    });1649  });16501651  itSub('Should connect to Astar and send UNQ back', async ({helper}) => {1652    await usingAstarPlaygrounds(astarUrl, async (helper) => {1653      const destination = {1654        V2: {1655          parents: 1,1656          interior: {1657            X1: {1658              Parachain: UNIQUE_CHAIN,1659            },1660          },1661        },1662      };16631664      const beneficiary = {1665        V2: {1666          parents: 0,1667          interior: {1668            X1: {1669              AccountId32: {1670                network: 'Any',1671                id: randomAccount.addressRaw,1672              },1673            },1674          },1675        },1676      };16771678      const assets = {1679        V2: [1680          {1681            id: {1682              Concrete: {1683                parents: 1,1684                interior: {1685                  X1: {1686                    Parachain: UNIQUE_CHAIN,1687                  },1688                },1689              },1690            },1691            fun: {1692              Fungible: unqFromAstarTransfered,1693            },1694          },1695        ],1696      };16971698      // Initial balance is 1 ASTR1699      const balanceASTRbefore = await helper.balance.getSubstrate(randomAccount.address);1700      console.log(`ASTR balance is: ${balanceASTRbefore}, it does not changed`);1701      expect(balanceASTRbefore).to.eq(astarInitialBalance);17021703      const feeAssetItem = 0;1704      // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw1705      await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);17061707      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);1708      const balanceAstar = await helper.balance.getSubstrate(randomAccount.address);1709      console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);17101711      // Assert: xcUNQ balance correctly decreased1712      expect(xcUNQbalance).to.eq(unqOnAstarLeft);1713      // Assert: ASTR balance is 0.996...1714      expect(balanceAstar / (10n ** (ASTAR_DECIMALS - 3n))).to.eq(996n);1715    });17161717    await helper.wait.newBlocks(3);1718    const balanceUNQ = await helper.balance.getSubstrate(randomAccount.address);1719    console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`);1720    expect(balanceUNQ).to.eq(balanceAfterUniqueToAstarXCM + unqFromAstarTransfered);1721  });17221723  itSub('Astar can send only up to its balance', async ({helper}) => {1724    // set Astar's sovereign account's balance1725    const astarBalance = 10000n * (10n ** UNQ_DECIMALS);1726    const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);1727    await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);17281729    const moreThanAstarHas = astarBalance * 2n;17301731    let targetAccountBalance = 0n;1732    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);17331734    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1735      targetAccount.addressRaw,1736      {1737        Concrete: {1738          parents: 0,1739          interior: 'Here',1740        },1741      },1742      moreThanAstarHas,1743    );17441745    let maliciousXcmProgramSent: any;1746    const maxWaitBlocks = 3;17471748    // Try to trick Unique1749    await usingAstarPlaygrounds(astarUrl, async (helper) => {1750      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);17511752      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1753    });17541755    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash1756        && event.outcome.isFailedToTransactAsset);17571758    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1759    expect(targetAccountBalance).to.be.equal(0n);17601761    // But Astar still can send the correct amount1762    const validTransferAmount = astarBalance / 2n;1763    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1764      targetAccount.addressRaw,1765      {1766        Concrete: {1767          parents: 0,1768          interior: 'Here',1769        },1770      },1771      validTransferAmount,1772    );17731774    await usingAstarPlaygrounds(astarUrl, async (helper) => {1775      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);1776    });17771778    await helper.wait.newBlocks(maxWaitBlocks);17791780    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1781    expect(targetAccountBalance).to.be.equal(validTransferAmount);1782  });17831784  itSub('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {1785    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);1786    const [targetAccount] = await helper.arrange.createAccounts([0n], alice);17871788    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1789      targetAccount.addressRaw,1790      uniqueAssetId,1791      testAmount,1792    );17931794    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(1795      targetAccount.addressRaw,1796      {1797        Concrete: {1798          parents: 0,1799          interior: 'Here',1800        },1801      },1802      testAmount,1803    );18041805    let maliciousXcmProgramFullIdSent: any;1806    let maliciousXcmProgramHereIdSent: any;1807    const maxWaitBlocks = 3;18081809    // Try to trick Unique using full UNQ identification1810    await usingAstarPlaygrounds(astarUrl, async (helper) => {1811      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramFullId);18121813      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1814    });18151816    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash1817        && event.outcome.isUntrustedReserveLocation);18181819    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1820    expect(accountBalance).to.be.equal(0n);18211822    // Try to trick Unique using shortened UNQ identification1823    await usingAstarPlaygrounds(astarUrl, async (helper) => {1824      await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramHereId);18251826      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1827    });18281829    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash1830        && event.outcome.isUntrustedReserveLocation);18311832    accountBalance = await helper.balance.getSubstrate(targetAccount.address);1833    expect(accountBalance).to.be.equal(0n);1834  });1835});