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

difftreelog

fix add/extend xcm tests for moonbeam, extend untrusted reserve location

Daniel Shiposha2023-04-13parent: #e02f22f.patch.diff
in: master

4 files changed

modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -2,7 +2,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 import {stringToU8a} from '@polkadot/util';
-import {encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';
+import {blake2AsHex, encodeAddress, mnemonicGenerate} from '@polkadot/util-crypto';
 import {UniqueHelper, MoonbeamHelper, ChainHelperBase, AcalaHelper, RelayHelper, WestmintHelper, AstarHelper} from './unique';
 import {ApiPromise, Keyring, WsProvider} from '@polkadot/api';
 import * as defs from '../../interfaces/definitions';
@@ -155,6 +155,7 @@
 export class DevMoonbeamHelper extends MoonbeamHelper {
   account: MoonbeamAccountGroup;
   wait: WaitGroup;
+  fastDemocracy: MoonbeamFastDemocracyGroup;
 
   constructor(logger: { log: (msg: any, level: any) => void, level: any }, options: {[key: string]: any} = {}) {
     options.helperBase = options.helperBase ?? DevMoonbeamHelper;
@@ -163,6 +164,7 @@
     super(logger, options);
     this.account = new MoonbeamAccountGroup(this);
     this.wait = new WaitGroup(this);
+    this.fastDemocracy = new MoonbeamFastDemocracyGroup(this);
   }
 }
 
@@ -554,6 +556,103 @@
   }
 }
 
+class MoonbeamFastDemocracyGroup {
+  helper: DevMoonbeamHelper;
+
+  constructor(helper: DevMoonbeamHelper) {
+    this.helper = helper;
+  }
+
+  async executeProposal(proposalDesciption: string, encodedProposal: string) {
+    const proposalHash = blake2AsHex(encodedProposal);
+
+    const alithAccount = this.helper.account.alithAccount();
+    const baltatharAccount = this.helper.account.baltatharAccount();
+    const dorothyAccount = this.helper.account.dorothyAccount();
+
+    const councilVotingThreshold = 2;
+    const technicalCommitteeThreshold = 2;
+    const fastTrackVotingPeriod = 3;
+    const fastTrackDelayPeriod = 0;
+
+    console.log(`[democracy] executing '${proposalDesciption}' proposal`);
+
+    // >>> Propose external motion through council >>>
+    console.log('\t* Propose external motion through council.......');
+    const externalMotion = this.helper.democracy.externalProposeMajority({Inline: encodedProposal});
+    const encodedMotion = externalMotion?.method.toHex() || '';
+    const motionHash = blake2AsHex(encodedMotion);
+    console.log('\t* Motion hash is %s', motionHash);
+
+    await this.helper.collective.council.propose(
+      baltatharAccount,
+      councilVotingThreshold,
+      externalMotion,
+      externalMotion.encodedLength,
+    );
+
+    const councilProposalIdx = await this.helper.collective.council.proposalCount() - 1;
+    await this.helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
+    await this.helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
+
+    await this.helper.collective.council.close(
+      dorothyAccount,
+      motionHash,
+      councilProposalIdx,
+      {
+        refTime: 1_000_000_000,
+        proofSize: 1_000_000,
+      },
+      externalMotion.encodedLength,
+    );
+    console.log('\t* Propose external motion through council.......DONE');
+    // <<< Propose external motion through council <<<
+
+    // >>> Fast track proposal through technical committee >>>
+    console.log('\t* Fast track proposal through technical committee.......');
+    const fastTrack = this.helper.democracy.fastTrack(proposalHash, fastTrackVotingPeriod, fastTrackDelayPeriod);
+    const encodedFastTrack = fastTrack?.method.toHex() || '';
+    const fastTrackHash = blake2AsHex(encodedFastTrack);
+    console.log('\t* FastTrack hash is %s', fastTrackHash);
+
+    await this.helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
+
+    const techProposalIdx = await this.helper.collective.techCommittee.proposalCount() - 1;
+    await this.helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
+    await this.helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
+
+    await this.helper.collective.techCommittee.close(
+      baltatharAccount,
+      fastTrackHash,
+      techProposalIdx,
+      {
+        refTime: 1_000_000_000,
+        proofSize: 1_000_000,
+      },
+      fastTrack.encodedLength,
+    );
+    console.log('\t* Fast track proposal through technical committee.......DONE');
+    // <<< Fast track proposal through technical committee <<<
+
+    const refIndexField = 0;
+    const referendumIndex = await this.helper.wait.eventData<any>(3, 'democracy', 'Started', refIndexField);
+
+    // >>> Referendum voting >>>
+    console.log(`\t* Referendum #${referendumIndex} voting.......`);
+    await this.helper.democracy.referendumVote(dorothyAccount, referendumIndex, {
+      balance: 10_000_000_000_000_000_000n,
+      vote: {aye: true, conviction: 1},
+    });
+    console.log(`\t* Referendum #${referendumIndex} voting.......DONE`);
+    // <<< Referendum voting <<<
+
+    // Wait for the democracy execute
+    await this.helper.wait.newBlocks(5);
+
+    console.log(`[democracy] executing '${proposalDesciption}' proposal.......DONE`);
+  }
+}
+
 class WaitGroup {
   helper: ChainHelperBase;
 
@@ -727,7 +826,7 @@
     return promise;
   }
 
-  async eventOutcome<EventT>(maxBlocksToWait: number, eventSection: string, eventMethod: string) {
+  async eventData<EventT>(maxBlocksToWait: number, eventSection: string, eventMethod: string, fieldIndex: number) {
     const eventRecord = await this.event(maxBlocksToWait, eventSection, eventMethod);
 
     if (eventRecord == null) {
@@ -735,9 +834,9 @@
     }
 
     const event = eventRecord!.event;
-    const outcome = event.data[1] as EventT;
+    const data = event.data[fieldIndex] as EventT;
 
-    return outcome;
+    return data;
   }
 }
 
modifiedtests/src/util/playgrounds/unique.tsdiffbeforeafterboth
642 return call(...params);642 return call(...params);
643 }643 }
644
645 encodeApiCall(apiCall: string, params: any[]) {
646 return this.constructApiCall(apiCall, params).method.toHex();
647 }
644648
645 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {649 async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {
646 if(this.api === null) throw Error('API not initialized');650 if(this.api === null) throw Error('API not initialized');
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmQuartz.test.ts
+++ b/tests/src/xcm/xcmQuartz.test.ts
@@ -15,7 +15,6 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {blake2AsHex} from '@polkadot/util-crypto';
 import config from '../config';
 import {XcmV2TraitsError} from '../interfaces';
 import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';
@@ -680,11 +679,13 @@
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -738,7 +739,7 @@
       },
     };
 
-    const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
       targetAccount.addressRaw,
       {
         Concrete: {
@@ -753,16 +754,55 @@
       testAmount,
     );
 
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Quartz using full QTZ identification
     await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
-      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
+      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Quartz using shortened QTZ identification
+    await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
+      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
+    });
+
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -775,7 +815,7 @@
       'The XCM error should be \'isUntrustedReserveLocation\'',
     ).to.be.true;
 
-    const accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
   });
 });
@@ -845,11 +885,13 @@
 
   const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -918,7 +960,7 @@
 
 describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {
   // Quartz constants
-  let quartzDonor: IKeyringPair;
+  let alice: IKeyringPair;
   let quartzAssetLocation;
 
   let randomAccountQuartz: IKeyringPair;
@@ -927,11 +969,6 @@
   // Moonriver constants
   let assetId: string;
 
-  const councilVotingThreshold = 2;
-  const technicalCommitteeThreshold = 2;
-  const votingPeriod = 3;
-  const delayPeriod = 0;
-
   const quartzAssetMetadata = {
     name: 'xcQuartz',
     symbol: 'xcQTZ',
@@ -952,13 +989,12 @@
 
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
-      quartzDonor = await privateKey('//Alice');
-      [randomAccountQuartz] = await helper.arrange.createAccounts([0n], quartzDonor);
+      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.
-      const alice = quartzDonor;
       await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
     });
 
@@ -994,84 +1030,13 @@
         unitsPerSecond,
         numAssetsWeightHint,
       });
-      const proposalHash = blake2AsHex(encodedProposal);
 
       console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-      console.log('Encoded length %d', encodedProposal.length);
-      console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);
 
-      // >>> Note motion preimage >>>
-      console.log('Note motion preimage.......');
-      await helper.democracy.notePreimage(baltatharAccount, encodedProposal);
-      console.log('Note motion preimage.......DONE');
-      // <<< Note motion preimage <<<
-
-      // >>> Propose external motion through council >>>
-      console.log('Propose external motion through council.......');
-      const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash});
-      const encodedMotion = externalMotion?.method.toHex() || '';
-      const motionHash = blake2AsHex(encodedMotion);
-      console.log('Motion hash is %s', motionHash);
-
-      await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);
-
-      const councilProposalIdx = await helper.collective.council.proposalCount() - 1;
-      await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
-      await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
-
-      await helper.collective.council.close(
-        dorothyAccount,
-        motionHash,
-        councilProposalIdx,
-        {
-          refTime: 1_000_000_000,
-          proofSize: 1_000_000,
-        },
-        externalMotion.encodedLength,
-      );
-      console.log('Propose external motion through council.......DONE');
-      // <<< Propose external motion through council <<<
-
-      // >>> Fast track proposal through technical committee >>>
-      console.log('Fast track proposal through technical committee.......');
-      const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);
-      const encodedFastTrack = fastTrack?.method.toHex() || '';
-      const fastTrackHash = blake2AsHex(encodedFastTrack);
-      console.log('FastTrack hash is %s', fastTrackHash);
-
-      await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
-
-      const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;
-      await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
-      await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
-
-      await helper.collective.techCommittee.close(
-        baltatharAccount,
-        fastTrackHash,
-        techProposalIdx,
-        {
-          refTime: 1_000_000_000,
-          proofSize: 1_000_000,
-        },
-        fastTrack.encodedLength,
-      );
-      console.log('Fast track proposal through technical committee.......DONE');
-      // <<< Fast track proposal through technical committee <<<
-
-      // >>> Referendum voting >>>
-      console.log('Referendum voting.......');
-      await helper.democracy.referendumVote(dorothyAccount, 0, {
-        balance: 10_000_000_000_000_000_000n,
-        vote: {aye: true, conviction: 1},
-      });
-      console.log('Referendum voting.......DONE');
-      // <<< Referendum voting <<<
+      await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
 
       // >>> Acquire Quartz AssetId Info on Moonriver >>>
       console.log('Acquire Quartz AssetId Info on Moonriver.......');
-
-      // Wait for the democracy execute
-      await helper.wait.newBlocks(5);
 
       assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
 
@@ -1089,7 +1054,7 @@
     });
 
     await usingPlaygrounds(async (helper) => {
-      await helper.balance.transferToSubstrate(quartzDonor, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
+      await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
       balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);
     });
   });
@@ -1197,14 +1162,197 @@
     expect(qtzFees == 0n).to.be.true;
   });
 
-  // eslint-disable-next-line require-await
-  itSub.skip('Moonriver can send only up to its balance', async ({helper}) => {
-    throw Error('Not yet implemented');
+  itSub('Moonriver can send only up to its balance', async ({helper}) => {
+    // set Moonriver's sovereign account's balance
+    const moonriverBalance = 10000n * (10n ** QTZ_DECIMALS);
+    const moonriverSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONRIVER_CHAIN);
+    await helper.getSudo().balance.setBalanceSubstrate(alice, moonriverSovereignAccount, moonriverBalance);
+
+    const moreThanMoonriverHas = moonriverBalance * 2n;
+
+    let targetAccountBalance = 0n;
+    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+    const quartzMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {Parachain: QUARTZ_CHAIN},
+        },
+      },
+    };
+
+    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      moreThanMoonriverHas,
+    );
+
+    // Try to trick Quartz
+    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgram]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);
+    });
+
+    const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isFailedToTransactAsset,
+      'The XCM error should be \'FailedToTransactAsset\'',
+    ).to.be.true;
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(0n);
+
+    // But Moonriver still can send the correct amount
+    const validTransferAmount = moonriverBalance / 2n;
+    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      validTransferAmount,
+    );
+
+    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, validXcmProgram]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('Spend the correct amount of QTZ', batchCall);
+    });
+
+    await helper.wait.newBlocks(maxWaitBlocks);
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(validTransferAmount);
   });
 
-  // eslint-disable-next-line require-await
-  itSub.skip('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {
-    throw Error('Not yet implemented');
+  itSub('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {
+    const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
+    const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+    const quartzMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {
+            Parachain: QUARTZ_CHAIN,
+          },
+        },
+      },
+    };
+
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: {
+            X1: {
+              Parachain: QUARTZ_CHAIN,
+            },
+          },
+        },
+      },
+      testAmount,
+    );
+
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Quartz using full QTZ identification
+    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramFullId]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using path asset identification', batchCall);
+    });
+
+    const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Quartz using shortened QTZ identification
+    await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramHereId]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using "here" asset identification', batchCall);
+    });
+
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
   });
 });
 
@@ -1456,11 +1604,13 @@
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -1514,7 +1664,7 @@
       },
     };
 
-    const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
       targetAccount.addressRaw,
       {
         Concrete: {
@@ -1529,16 +1679,55 @@
       testAmount,
     );
 
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Quartz using full QTZ identification
     await usingShidenPlaygrounds(shidenUrl, async (helper) => {
-      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
+      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Quartz using shortened QTZ identification
+    await usingShidenPlaygrounds(shidenUrl, async (helper) => {
+      await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
+    });
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -1551,7 +1740,7 @@
       'The XCM error should be \'isUntrustedReserveLocation\'',
     ).to.be.true;
 
-    const accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
   });
 });
modifiedtests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth
--- a/tests/src/xcm/xcmUnique.test.ts
+++ b/tests/src/xcm/xcmUnique.test.ts
@@ -15,7 +15,6 @@
 // along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
 
 import {IKeyringPair} from '@polkadot/types/types';
-import {blake2AsHex} from '@polkadot/util-crypto';
 import config from '../config';
 import {XcmV2TraitsError} from '../interfaces';
 import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds} from '../util';
@@ -682,11 +681,13 @@
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -725,7 +726,7 @@
     expect(targetAccountBalance).to.be.equal(validTransferAmount);
   });
 
-  itSub('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {
+  itSub.only('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {
     const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
     const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
 
@@ -740,7 +741,7 @@
       },
     };
 
-    const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
       targetAccount.addressRaw,
       {
         Concrete: {
@@ -755,16 +756,30 @@
       testAmount,
     );
 
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Unique using full UNQ identification
     await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
-      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram);
+      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -777,8 +792,33 @@
       'The XCM error should be \'isUntrustedReserveLocation\'',
     ).to.be.true;
 
-    const accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Unique using shortened UNQ identification
+    await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
+      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
+    });
+
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
   });
 });
 
@@ -847,11 +887,13 @@
 
   const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -920,7 +962,7 @@
 
 describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {
   // Unique constants
-  let uniqueDonor: IKeyringPair;
+  let alice: IKeyringPair;
   let uniqueAssetLocation;
 
   let randomAccountUnique: IKeyringPair;
@@ -929,11 +971,6 @@
   // Moonbeam constants
   let assetId: string;
 
-  const councilVotingThreshold = 2;
-  const technicalCommitteeThreshold = 2;
-  const votingPeriod = 3;
-  const delayPeriod = 0;
-
   const uniqueAssetMetadata = {
     name: 'xcUnique',
     symbol: 'xcUNQ',
@@ -954,13 +991,12 @@
 
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
-      uniqueDonor = await privateKey('//Alice');
-      [randomAccountUnique] = await helper.arrange.createAccounts([0n], uniqueDonor);
+      alice = await privateKey('//Alice');
+      [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);
 
       balanceForeignUnqTokenInit = 0n;
 
       // Set the default version to wrap the first message to other chains.
-      const alice = uniqueDonor;
       await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
     });
 
@@ -996,84 +1032,13 @@
         unitsPerSecond,
         numAssetsWeightHint,
       });
-      const proposalHash = blake2AsHex(encodedProposal);
 
       console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
-      console.log('Encoded length %d', encodedProposal.length);
-      console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);
-
-      // >>> Note motion preimage >>>
-      console.log('Note motion preimage.......');
-      await helper.democracy.notePreimage(baltatharAccount, encodedProposal);
-      console.log('Note motion preimage.......DONE');
-      // <<< Note motion preimage <<<
-
-      // >>> Propose external motion through council >>>
-      console.log('Propose external motion through council.......');
-      const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash});
-      const encodedMotion = externalMotion?.method.toHex() || '';
-      const motionHash = blake2AsHex(encodedMotion);
-      console.log('Motion hash is %s', motionHash);
-
-      await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);
-
-      const councilProposalIdx = await helper.collective.council.proposalCount() - 1;
-      await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
-      await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
-
-      await helper.collective.council.close(
-        dorothyAccount,
-        motionHash,
-        councilProposalIdx,
-        {
-          refTime: 1_000_000_000,
-          proofSize: 1_000_000,
-        },
-        externalMotion.encodedLength,
-      );
-      console.log('Propose external motion through council.......DONE');
-      // <<< Propose external motion through council <<<
 
-      // >>> Fast track proposal through technical committee >>>
-      console.log('Fast track proposal through technical committee.......');
-      const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);
-      const encodedFastTrack = fastTrack?.method.toHex() || '';
-      const fastTrackHash = blake2AsHex(encodedFastTrack);
-      console.log('FastTrack hash is %s', fastTrackHash);
-
-      await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
-
-      const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;
-      await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
-      await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
-
-      await helper.collective.techCommittee.close(
-        baltatharAccount,
-        fastTrackHash,
-        techProposalIdx,
-        {
-          refTime: 1_000_000_000,
-          proofSize: 1_000_000,
-        },
-        fastTrack.encodedLength,
-      );
-      console.log('Fast track proposal through technical committee.......DONE');
-      // <<< Fast track proposal through technical committee <<<
+      await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);
 
-      // >>> Referendum voting >>>
-      console.log('Referendum voting.......');
-      await helper.democracy.referendumVote(dorothyAccount, 0, {
-        balance: 10_000_000_000_000_000_000n,
-        vote: {aye: true, conviction: 1},
-      });
-      console.log('Referendum voting.......DONE');
-      // <<< Referendum voting <<<
-
       // >>> Acquire Unique AssetId Info on Moonbeam >>>
       console.log('Acquire Unique AssetId Info on Moonbeam.......');
-
-      // Wait for the democracy execute
-      await helper.wait.newBlocks(5);
 
       assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();
 
@@ -1091,7 +1056,7 @@
     });
 
     await usingPlaygrounds(async (helper) => {
-      await helper.balance.transferToSubstrate(uniqueDonor, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);
+      await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);
       balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);
     });
   });
@@ -1200,14 +1165,197 @@
     expect(unqFees == 0n).to.be.true;
   });
 
-  // eslint-disable-next-line require-await
-  itSub.skip('Moonbeam can send only up to its balance', async ({helper}) => {
-    throw Error('Not yet implemented');
+  itSub('Moonbeam can send only up to its balance', async ({helper}) => {
+    // set Moonbeam's sovereign account's balance
+    const moonbeamBalance = 10000n * (10n ** UNQ_DECIMALS);
+    const moonbeamSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONBEAM_CHAIN);
+    await helper.getSudo().balance.setBalanceSubstrate(alice, moonbeamSovereignAccount, moonbeamBalance);
+
+    const moreThanMoonbeamHas = moonbeamBalance * 2n;
+
+    let targetAccountBalance = 0n;
+    const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
+
+    const uniqueMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {Parachain: UNIQUE_CHAIN},
+        },
+      },
+    };
+
+    const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      moreThanMoonbeamHas,
+    );
+
+    // Try to trick Unique
+    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, maliciousXcmProgram]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to spend more UNQ than Moonbeam has', batchCall);
+    });
+
+    const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isFailedToTransactAsset,
+      'The XCM error should be \'FailedToTransactAsset\'',
+    ).to.be.true;
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(0n);
+
+    // But Moonbeam still can send the correct amount
+    const validTransferAmount = moonbeamBalance / 2n;
+    const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      validTransferAmount,
+    );
+
+    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, validXcmProgram]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('Spend the correct amount of UNQ', batchCall);
+    });
+
+    await helper.wait.newBlocks(maxWaitBlocks);
+
+    targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(targetAccountBalance).to.be.equal(validTransferAmount);
   });
 
-  // eslint-disable-next-line require-await
-  itSub.skip('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {
-    throw Error('Not yet implemented');
+  itSub.only('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {
+    const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
+    const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
+
+    const uniqueMultilocation = {
+      V1: {
+        parents: 1,
+        interior: {
+          X1: {
+            Parachain: UNIQUE_CHAIN,
+          },
+        },
+      },
+    };
+
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: {
+            X1: {
+              Parachain: UNIQUE_CHAIN,
+            },
+          },
+        },
+      },
+      testAmount,
+    );
+
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Unique using full UNQ identification
+    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, maliciousXcmProgramFullId]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using path asset identification', batchCall);
+    });
+
+    const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Unique using shortened UNQ identification
+    await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
+      const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, maliciousXcmProgramHereId]);
+
+      // Needed to bypass the call filter.
+      const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
+      await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using "here" asset identification', batchCall);
+    });
+
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
+
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
   });
 });
 
@@ -1215,14 +1363,14 @@
   let alice: IKeyringPair;
   let randomAccount: IKeyringPair;
 
-  const UNQ_ASSET_ID_ON_SHIDEN = 1;
-  const UNQ_MINIMAL_BALANCE_ON_SHIDEN = 1n;
+  const UNQ_ASSET_ID_ON_ASTAR = 1;
+  const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n;
 
   // Unique -> Astar
-  const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Shiden.
+  const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.
   const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours?
   const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ
-  const unqToAstarArrived = 9_999_999_999_088_000_000n; // 9.999 ... UNQ, Shiden takes a commision in foreign tokens
+  const unqToAstarArrived = 9_999_999_999_088_000_000n; // 9.999 ... UNQ, Astar takes a commision in foreign tokens
 
   // Astar -> Unique
   const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ
@@ -1245,14 +1393,14 @@
       // TODO update metadata with values from production
       await helper.assets.create(
         alice,
-        UNQ_ASSET_ID_ON_SHIDEN,
+        UNQ_ASSET_ID_ON_ASTAR,
         alice.address,
-        UNQ_MINIMAL_BALANCE_ON_SHIDEN,
+        UNQ_MINIMAL_BALANCE_ON_ASTAR,
       );
 
       await helper.assets.setMetadata(
         alice,
-        UNQ_ASSET_ID_ON_SHIDEN,
+        UNQ_ASSET_ID_ON_ASTAR,
         'Cross chain UNQ',
         'xcUNQ',
         Number(UNQ_DECIMALS),
@@ -1270,7 +1418,7 @@
         },
       };
 
-      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_SHIDEN]);
+      await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);
 
       console.log('3. Set UNQ payment for XCM execution on Astar');
       await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);
@@ -1337,7 +1485,7 @@
 
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
       await helper.wait.newBlocks(3);
-      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_SHIDEN, randomAccount.address);
+      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
       const astarBalance = await helper.balance.getSubstrate(randomAccount.address);
 
       console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
@@ -1405,7 +1553,7 @@
       // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw
       await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);
 
-      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_SHIDEN, randomAccount.address);
+      const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);
       const balanceAstar = await helper.balance.getSubstrate(randomAccount.address);
       console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);
 
@@ -1427,7 +1575,7 @@
     const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);
     await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);
 
-    const moreThanShidenHas = astarBalance * 2n;
+    const moreThanAstarHas = astarBalance * 2n;
 
     let targetAccountBalance = 0n;
     const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
@@ -1449,7 +1597,7 @@
           interior: 'Here',
         },
       },
-      moreThanShidenHas,
+      moreThanAstarHas,
     );
 
     // Try to trick Unique
@@ -1458,11 +1606,13 @@
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -1501,7 +1651,7 @@
     expect(targetAccountBalance).to.be.equal(validTransferAmount);
   });
 
-  itSub('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {
+  itSub.only('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {
     const testAmount = 10_000n * (10n ** UNQ_DECIMALS);
     const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
 
@@ -1516,7 +1666,7 @@
       },
     };
 
-    const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(
+    const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
       targetAccount.addressRaw,
       {
         Concrete: {
@@ -1531,16 +1681,55 @@
       testAmount,
     );
 
+    const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
+      targetAccount.addressRaw,
+      {
+        Concrete: {
+          parents: 0,
+          interior: 'Here',
+        },
+      },
+      testAmount,
+    );
+
+    // Try to trick Unique using full UNQ identification
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
-      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram);
+      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
     });
 
     const maxWaitBlocks = 3;
+    const outcomeField = 1;
+
+    let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
+      maxWaitBlocks,
+      'xcmpQueue',
+      'Fail',
+      outcomeField,
+    );
+
+    expect(
+      xcmpQueueFailEvent != null,
+      '\'xcmpQueue.FailEvent\' event is expected',
+    ).to.be.true;
+
+    expect(
+      xcmpQueueFailEvent!.isUntrustedReserveLocation,
+      'The XCM error should be \'isUntrustedReserveLocation\'',
+    ).to.be.true;
 
-    const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(
+    let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    expect(accountBalance).to.be.equal(0n);
+
+    // Try to trick Unique using shortened UNQ identification
+    await usingAstarPlaygrounds(astarUrl, async (helper) => {
+      await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);
+    });
+
+    xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
       maxWaitBlocks,
       'xcmpQueue',
       'Fail',
+      outcomeField,
     );
 
     expect(
@@ -1553,7 +1742,7 @@
       'The XCM error should be \'isUntrustedReserveLocation\'',
     ).to.be.true;
 
-    const accountBalance = await helper.balance.getSubstrate(targetAccount.address);
+    accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
   });