git.delta.rocks / unique-network / refs/commits / 8a18c9958995

difftreelog

refactor event helpers

Daniel Shiposha2023-04-21parent: #6e3cf5e.patch.diff
in: master

4 files changed

modifiedtests/src/scheduler.seqtest.tsdiffbeforeafterboth
--- a/tests/src/scheduler.seqtest.ts
+++ b/tests/src/scheduler.seqtest.ts
@@ -16,7 +16,7 @@
 
 import {expect, itSched, itSub, Pallets, requirePalletsOrSkip, usingPlaygrounds} from './util';
 import {IKeyringPair} from '@polkadot/types/types';
-import {DevUniqueHelper} from './util/playgrounds/unique.dev';
+import {DevUniqueHelper, Event} from './util/playgrounds/unique.dev';
 
 describe('Scheduling token and balance transfers', () => {
   let superuser: IKeyringPair;
@@ -411,19 +411,13 @@
     const priority = 112;
     await helper.getSudo().scheduler.changePriority(superuser, scheduledId, priority);
 
-    const priorityChanged = await helper.wait.event(
-      waitForBlocks,
-      'scheduler',
-      'PriorityChanged',
-    );
-
-    expect(priorityChanged !== null).to.be.true;
+    const priorityChanged = await helper.wait.expectEvent(waitForBlocks, Event.Scheduler.PriorityChanged);
 
-    const [blockNumber, index] = priorityChanged!.event.data[0].toJSON() as any[];
+    const [blockNumber, index] = priorityChanged.task();
     expect(blockNumber).to.be.equal(executionBlock);
     expect(index).to.be.equal(0);
 
-    expect(priorityChanged!.event.data[1].toString()).to.be.equal(priority.toString());
+    expect(priorityChanged.priority().toString()).to.be.equal(priority.toString());
   });
 
   itSub('Prioritized operations execute in valid order', async ({helper}) => {
@@ -668,13 +662,7 @@
     await expect(helper.scheduler.changePriority(alice, scheduledId, priority))
       .to.be.rejectedWith(/BadOrigin/);
 
-    const priorityChanged = await helper.wait.event(
-      waitForBlocks,
-      'scheduler',
-      'PriorityChanged',
-    );
-
-    expect(priorityChanged === null).to.be.true;
+    await helper.wait.expectEvent(waitForBlocks, Event.Scheduler.PriorityChanged);
   });
 });
 
modifiedtests/src/util/playgrounds/unique.dev.tsdiffbeforeafterboth
--- a/tests/src/util/playgrounds/unique.dev.ts
+++ b/tests/src/util/playgrounds/unique.dev.ts
@@ -9,7 +9,7 @@
 import {IKeyringPair} from '@polkadot/types/types';
 import {EventRecord} from '@polkadot/types/interfaces';
 import {ICrossAccountId, IPovInfo, TSigner} from './types';
-import {FrameSystemEventRecord} from '@polkadot/types/lookup';
+import {FrameSystemEventRecord, XcmV2TraitsError} from '@polkadot/types/lookup';
 import {VoidFn} from '@polkadot/api/types';
 import {Pallets} from '..';
 import {spawnSync} from 'child_process';
@@ -59,6 +59,130 @@
   }
 }
 
+export interface IEventHelper {
+  section(): string;
+
+  method(): string;
+
+  bindEventRecord(e: FrameSystemEventRecord): void;
+
+  raw(): FrameSystemEventRecord;
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function EventHelper(section: string, method: string) {
+  return class implements IEventHelper {
+    eventRecord: FrameSystemEventRecord | null;
+    _section: string;
+    _method: string;
+
+    constructor() {
+      this.eventRecord = null;
+      this._section = section;
+      this._method = method;
+    }
+
+    section(): string {
+      return this._section;
+    }
+
+    method(): string {
+      return this._method;
+    }
+
+    bindEventRecord(e: FrameSystemEventRecord) {
+      this.eventRecord = e;
+    }
+
+    raw() {
+      return this.eventRecord!;
+    }
+
+    eventJsonData<T = any>(index: number) {
+      return this.raw().event.data[index].toJSON() as T;
+    }
+
+    eventData<T>(index: number) {
+      return this.raw().event.data[index] as T;
+    }
+  };
+}
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+function EventSection(section: string) {
+  return class Section {
+    static section = section;
+
+    static Method(name: string) {
+      return EventHelper(Section.section, name);
+    }
+  };
+}
+
+export class Event {
+  static Democracy = class extends EventSection('democracy') {
+    static Started = class extends this.Method('Started') {
+      referendumIndex() {
+        return this.eventJsonData<number>(0);
+      }
+
+      threshold() {
+        return this.eventJsonData(1);
+      }
+    };
+
+    static Voted = class extends this.Method('Voted') {
+      voter() {
+        return this.eventJsonData(0);
+      }
+
+      referendumIndex() {
+        return this.eventJsonData<number>(1);
+      }
+
+      vote() {
+        return this.eventJsonData(2);
+      }
+    };
+
+    static Passed = class extends this.Method('Passed') {
+      referendumIndex() {
+        return this.eventJsonData<number>(0);
+      }
+    };
+  };
+
+  static Scheduler = class extends EventSection('scheduler') {
+    static PriorityChanged = class extends this.Method('PriorityChanged') {
+      task() {
+        return this.eventJsonData(0);
+      }
+
+      priority() {
+        return this.eventJsonData(1);
+      }
+    };
+  };
+
+  static XcmpQueue = class extends EventSection('xcmpQueue') {
+    static XcmpMessageSent = class extends this.Method('XcmpMessageSent') {
+      messageHash() {
+        return this.eventJsonData(0);
+      }
+    };
+
+    static Fail = class extends this.Method('Fail') {
+      messageHash() {
+        return this.eventJsonData(0);
+      }
+
+      outcome() {
+        return this.eventData<XcmV2TraitsError>(1);
+      }
+    };
+  };
+}
+
 export class DevUniqueHelper extends UniqueHelper {
   /**
    * Arrange methods for tests
@@ -634,12 +758,12 @@
     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<number>(3, 'democracy', 'Started', refIndexField);
+    const democracyStarted = await this.helper.wait.expectEvent(3, Event.Democracy.Started);
+    const referendumIndex = democracyStarted.referendumIndex();
 
     // >>> Referendum voting >>>
     console.log(`\t* Referendum #${referendumIndex} voting.......`);
-    await this.helper.democracy.referendumVote(dorothyAccount, referendumIndex!, {
+    await this.helper.democracy.referendumVote(dorothyAccount, referendumIndex, {
       balance: 10_000_000_000_000_000_000n,
       vote: {aye: true, conviction: 1},
     });
@@ -647,7 +771,10 @@
     // <<< Referendum voting <<<
 
     // Wait the proposal to pass
-    await this.helper.wait.event(3, 'democracy', 'Passed');
+    await this.helper.wait.expectEvent(3, Event.Democracy.Passed, event => {
+      return event.referendumIndex() == referendumIndex;
+    });
+
     await this.helper.wait.newBlocks(1);
 
     console.log(`[democracy] executing '${proposalDesciption}' proposal.......DONE`);
@@ -794,13 +921,18 @@
     return promise;
   }
 
-  event(maxBlocksToWait: number, eventSection: string, eventMethod: string) {
+  event<T extends IEventHelper>(
+    maxBlocksToWait: number,
+    eventHelperType: new () => T,
+    filter: (_: T) => boolean = () => { return true; },
+  ) {
     // eslint-disable-next-line no-async-promise-executor
-    const promise = new Promise<EventRecord | null>(async (resolve) => {
+    const promise = new Promise<T | null>(async (resolve) => {
       const unsubscribe = await this.helper.getApi().rpc.chain.subscribeNewHeads(async header => {
+        const eventHelper = new eventHelperType();
         const blockNumber = header.number.toHuman();
         const blockHash = header.hash;
-        const eventIdStr = `${eventSection}.${eventMethod}`;
+        const eventIdStr = `${eventHelper.section()}.${eventHelper.method()}`;
         const waitLimitStr = `wait blocks remaining: ${maxBlocksToWait}`;
 
         this.helper.logger.log(`[Block #${blockNumber}] Waiting for event \`${eventIdStr}\` (${waitLimitStr})`);
@@ -809,16 +941,24 @@
         const eventRecords = (await apiAt.query.system.events()) as any;
 
         const neededEvent = eventRecords.toArray().find((r: FrameSystemEventRecord) => {
-          return r.event.section == eventSection && r.event.method == eventMethod;
+          if (
+            r.event.section == eventHelper.section()
+            && r.event.method == eventHelper.method()
+          ) {
+            eventHelper.bindEventRecord(r);
+            return filter(eventHelper);
+          } else {
+            return false;
+          }
         });
 
         if (neededEvent) {
           unsubscribe();
-          resolve(neededEvent);
+          resolve(eventHelper);
         } else if (maxBlocksToWait > 0) {
           maxBlocksToWait--;
         } else {
-          this.helper.logger.log(`Event \`${eventIdStr}\` is NOT found`);
+          this.helper.logger.log(`Eligible event \`${eventIdStr}\` is NOT found`);
           unsubscribe();
           resolve(null);
         }
@@ -827,17 +967,18 @@
     return promise;
   }
 
-  async eventData<EventT>(maxBlocksToWait: number, eventSection: string, eventMethod: string, fieldIndex: number) {
-    const eventRecord = await this.event(maxBlocksToWait, eventSection, eventMethod);
-
-    if (eventRecord == null) {
-      return null;
+  async expectEvent<T extends IEventHelper>(
+    maxBlocksToWait: number,
+    eventHelperType: new () => T,
+    filter: (e: T) => boolean = () => { return true; },
+  ) {
+    const e = await this.event(maxBlocksToWait, eventHelperType, filter);
+    if (e == null) {
+      const eventHelper = new eventHelperType();
+      throw Error(`The event '${eventHelper.section()}.${eventHelper.method()}' is expected`);
+    } else {
+      return e;
     }
-
-    const event = eventRecord!.event;
-    const data = event.data[fieldIndex] as EventT;
-
-    return data;
   }
 }
 
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import config from '../config';18import config from '../config';
19import {XcmV2TraitsError} from '../interfaces';
20import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';19import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';
21import {DevUniqueHelper} from '../util/playgrounds/unique.dev';20import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';
2221
23const QUARTZ_CHAIN = 2095;22const QUARTZ_CHAIN = 2095;
24const STATEMINE_CHAIN = 1000;23const STATEMINE_CHAIN = 1000;
673 moreThanKaruraHas,672 moreThanKaruraHas,
674 );673 );
674
675 let maliciousXcmProgramSent: any;
676 const maxWaitBlocks = 3;
675677
676 // Try to trick Quartz678 // Try to trick Quartz
677 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {679 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
678 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);680 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
681
682 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
679 });683 });
680
681 const maxWaitBlocks = 3;
682 const outcomeField = 1;
683684
684 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(685 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
685 maxWaitBlocks,686 return event.messageHash() == maliciousXcmProgramSent.messageHash()
686 'xcmpQueue',687 && event.outcome().isFailedToTransactAsset;
687 'Fail',
688 outcomeField,
689 );688 });
690
691 expect(
692 xcmpQueueFailEvent != null,
693 '\'xcmpQueue.FailEvent\' event is expected',
694 ).to.be.true;
695
696 expect(
697 xcmpQueueFailEvent!.isFailedToTransactAsset,
698 `The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
699 ).to.be.true;
700689
701 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);690 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
702 expect(targetAccountBalance).to.be.equal(0n);691 expect(targetAccountBalance).to.be.equal(0n);
765 testAmount,754 testAmount,
766 );755 );
756
757 let maliciousXcmProgramFullIdSent: any;
758 let maliciousXcmProgramHereIdSent: any;
759 const maxWaitBlocks = 3;
767760
768 // Try to trick Quartz using full QTZ identification761 // Try to trick Quartz using full QTZ identification
769 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {762 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
770 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);763 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
764
765 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
771 });766 });
772
773 const maxWaitBlocks = 3;
774 const outcomeField = 1;
775767
776 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(768 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
777 maxWaitBlocks,769 return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
778 'xcmpQueue',770 && event.outcome().isUntrustedReserveLocation;
779 'Fail',
780 outcomeField,
781 );771 });
782
783 expect(
784 xcmpQueueFailEvent != null,
785 '\'xcmpQueue.FailEvent\' event is expected',
786 ).to.be.true;
787
788 expect(
789 xcmpQueueFailEvent!.isUntrustedReserveLocation,
790 `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
791 ).to.be.true;
792772
793 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);773 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
794 expect(accountBalance).to.be.equal(0n);774 expect(accountBalance).to.be.equal(0n);
797 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {777 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
798 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);778 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
779
780 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
799 });781 });
800782
801 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(783 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
802 maxWaitBlocks,784 return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
803 'xcmpQueue',785 && event.outcome().isUntrustedReserveLocation;
804 'Fail',
805 outcomeField,
806 );786 });
807
808 expect(
809 xcmpQueueFailEvent != null,
810 '\'xcmpQueue.FailEvent\' event is expected',
811 ).to.be.true;
812
813 expect(
814 xcmpQueueFailEvent!.isUntrustedReserveLocation,
815 `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
816 ).to.be.true;
817787
818 accountBalance = await helper.balance.getSubstrate(targetAccount.address);788 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
819 expect(accountBalance).to.be.equal(0n);789 expect(accountBalance).to.be.equal(0n);
834 let quartzAccountMultilocation: any;804 let quartzAccountMultilocation: any;
835 let quartzCombinedMultilocation: any;805 let quartzCombinedMultilocation: any;
806
807 let messageSent: any;
808
809 const maxWaitBlocks = 3;
836810
837 before(async () => {811 before(async () => {
838 await usingPlaygrounds(async (helper, privateKey) => {812 await usingPlaygrounds(async (helper, privateKey) => {
883 });857 });
884 });858 });
885859
886 const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {860 const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
887 const maxWaitBlocks = 3;
888 const outcomeField = 1;
889
890 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(861 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
891 maxWaitBlocks,862 return event.messageHash() == messageSent.messageHash()
892 'xcmpQueue',863 && event.outcome().isFailedToTransactAsset;
893 'Fail',
894 outcomeField,
895 );864 });
896
897 expect(
898 xcmpQueueFailEvent != null,
899 `[reject ${network} tokens] 'xcmpQueue.FailEvent' event is expected`,
900 ).to.be.true;
901
902 expect(
903 xcmpQueueFailEvent!.isFailedToTransactAsset,
904 `[reject ${network} tokens] The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
905 ).to.be.true;
906 };865 };
907866
908 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {867 itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => {
913 const destination = quartzCombinedMultilocation;872 const destination = quartzCombinedMultilocation;
914 await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');873 await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
874
875 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
915 });876 });
916877
917 await expectFailedToTransact('KAR', helper);878 await expectFailedToTransact(helper, messageSent);
918 });879 });
919880
920 itSub('Quartz rejects MOVR tokens from Moonriver', async ({helper}) => {881 itSub('Quartz rejects MOVR tokens from Moonriver', async ({helper}) => {
923 const destination = quartzCombinedMultilocation;884 const destination = quartzCombinedMultilocation;
924 await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');885 await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
886
887 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
925 });888 });
926889
927 await expectFailedToTransact('MOVR', helper);890 await expectFailedToTransact(helper, messageSent);
928 });891 });
929892
930 itSub('Quartz rejects SDN tokens from Shiden', async ({helper}) => {893 itSub('Quartz rejects SDN tokens from Shiden', async ({helper}) => {
953 feeAssetItem,916 feeAssetItem,
954 ]);917 ]);
918
919 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
955 });920 });
956921
957 await expectFailedToTransact('SDN', helper);922 await expectFailedToTransact(helper, messageSent);
958 });923 });
959});924});
960925
1193 moreThanMoonriverHas,1158 moreThanMoonriverHas,
1194 );1159 );
1160
1161 let maliciousXcmProgramSent: any;
1162 const maxWaitBlocks = 3;
11951163
1196 // Try to trick Quartz1164 // Try to trick Quartz
1197 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {1165 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1201 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1169 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
1202 await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);1170 await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);
1171
1172 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1203 });1173 });
1204
1205 const maxWaitBlocks = 3;
1206 const outcomeField = 1;
12071174
1208 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1175 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1209 maxWaitBlocks,1176 return event.messageHash() == maliciousXcmProgramSent.messageHash()
1210 'xcmpQueue',1177 && event.outcome().isFailedToTransactAsset;
1211 'Fail',
1212 outcomeField,
1213 );1178 });
1214
1215 expect(
1216 xcmpQueueFailEvent != null,
1217 '\'xcmpQueue.FailEvent\' event is expected',
1218 ).to.be.true;
1219
1220 expect(
1221 xcmpQueueFailEvent!.isFailedToTransactAsset,
1222 `The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
1223 ).to.be.true;
12241179
1225 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1180 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1226 expect(targetAccountBalance).to.be.equal(0n);1181 expect(targetAccountBalance).to.be.equal(0n);
1293 testAmount,1248 testAmount,
1294 );1249 );
1250
1251 let maliciousXcmProgramFullIdSent: any;
1252 let maliciousXcmProgramHereIdSent: any;
1253 const maxWaitBlocks = 3;
12951254
1296 // Try to trick Quartz using full QTZ identification1255 // Try to trick Quartz using full QTZ identification
1297 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {1256 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1301 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1260 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
1302 await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using path asset identification', batchCall);1261 await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using path asset identification', batchCall);
1262
1263 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1303 });1264 });
1304
1305 const maxWaitBlocks = 3;
1306 const outcomeField = 1;
13071265
1308 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1266 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1309 maxWaitBlocks,1267 return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
1310 'xcmpQueue',1268 && event.outcome().isUntrustedReserveLocation;
1311 'Fail',
1312 outcomeField,
1313 );1269 });
1314
1315 expect(
1316 xcmpQueueFailEvent != null,
1317 '\'xcmpQueue.FailEvent\' event is expected',
1318 ).to.be.true;
1319
1320 expect(
1321 xcmpQueueFailEvent!.isUntrustedReserveLocation,
1322 `The XCM error should be 'isUntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
1323 ).to.be.true;
13241270
1325 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1271 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1326 expect(accountBalance).to.be.equal(0n);1272 expect(accountBalance).to.be.equal(0n);
1333 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1279 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
1334 await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using "here" asset identification', batchCall);1280 await helper.fastDemocracy.executeProposal('try to act like a reserve location for QTZ using "here" asset identification', batchCall);
1281
1282 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1335 });1283 });
13361284
1337 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1285 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1338 maxWaitBlocks,1286 return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
1339 'xcmpQueue',1287 && event.outcome().isUntrustedReserveLocation;
1340 'Fail',
1341 outcomeField,
1342 );1288 });
1343
1344 expect(
1345 xcmpQueueFailEvent != null,
1346 '\'xcmpQueue.FailEvent\' event is expected',
1347 ).to.be.true;
1348
1349 expect(
1350 xcmpQueueFailEvent!.isUntrustedReserveLocation,
1351 `The XCM error should be 'isUntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
1352 ).to.be.true;
13531289
1354 accountBalance = await helper.balance.getSubstrate(targetAccount.address);1290 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1355 expect(accountBalance).to.be.equal(0n);1291 expect(accountBalance).to.be.equal(0n);
1598 moreThanShidenHas,1534 moreThanShidenHas,
1599 );1535 );
1536
1537 let maliciousXcmProgramSent: any;
1538 const maxWaitBlocks = 3;
16001539
1601 // Try to trick Quartz1540 // Try to trick Quartz
1602 await usingShidenPlaygrounds(shidenUrl, async (helper) => {1541 await usingShidenPlaygrounds(shidenUrl, async (helper) => {
1603 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);1542 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);
1543
1544 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1604 });1545 });
1605
1606 const maxWaitBlocks = 3;
1607 const outcomeField = 1;
16081546
1609 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1547 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1610 maxWaitBlocks,1548 return event.messageHash() == maliciousXcmProgramSent.messageHash()
1611 'xcmpQueue',1549 && event.outcome().isFailedToTransactAsset;
1612 'Fail',
1613 outcomeField,
1614 );1550 });
1615
1616 expect(
1617 xcmpQueueFailEvent != null,
1618 '\'xcmpQueue.FailEvent\' event is expected',
1619 ).to.be.true;
1620
1621 expect(
1622 xcmpQueueFailEvent!.isFailedToTransactAsset,
1623 `The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
1624 ).to.be.true;
16251551
1626 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1552 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1627 expect(targetAccountBalance).to.be.equal(0n);1553 expect(targetAccountBalance).to.be.equal(0n);
1690 testAmount,1616 testAmount,
1691 );1617 );
1618
1619 let maliciousXcmProgramFullIdSent: any;
1620 let maliciousXcmProgramHereIdSent: any;
1621 const maxWaitBlocks = 3;
16921622
1693 // Try to trick Quartz using full QTZ identification1623 // Try to trick Quartz using full QTZ identification
1694 await usingShidenPlaygrounds(shidenUrl, async (helper) => {1624 await usingShidenPlaygrounds(shidenUrl, async (helper) => {
1695 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);1625 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
1626
1627 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1696 });1628 });
1697
1698 const maxWaitBlocks = 3;
1699 const outcomeField = 1;
17001629
1701 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1630 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1702 maxWaitBlocks,1631 return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
1703 'xcmpQueue',1632 && event.outcome().isUntrustedReserveLocation;
1704 'Fail',
1705 outcomeField,
1706 );1633 });
1707
1708 expect(
1709 xcmpQueueFailEvent != null,
1710 '\'xcmpQueue.FailEvent\' event is expected',
1711 ).to.be.true;
1712
1713 expect(
1714 xcmpQueueFailEvent!.isUntrustedReserveLocation,
1715 `The XCM error should be 'isUntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
1716 ).to.be.true;
17171634
1718 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1635 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1719 expect(accountBalance).to.be.equal(0n);1636 expect(accountBalance).to.be.equal(0n);
1722 await usingShidenPlaygrounds(shidenUrl, async (helper) => {1639 await usingShidenPlaygrounds(shidenUrl, async (helper) => {
1723 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);1640 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
1641
1642 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
1724 });1643 });
17251644
1726 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(1645 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
1727 maxWaitBlocks,1646 return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
1728 'xcmpQueue',1647 && event.outcome().isUntrustedReserveLocation;
1729 'Fail',
1730 outcomeField,
1731 );1648 });
1732
1733 expect(
1734 xcmpQueueFailEvent != null,
1735 '\'xcmpQueue.FailEvent\' event is expected',
1736 ).to.be.true;
1737
1738 expect(
1739 xcmpQueueFailEvent!.isUntrustedReserveLocation,
1740 `The XCM error should be 'isUntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
1741 ).to.be.true;
17421649
1743 accountBalance = await helper.balance.getSubstrate(targetAccount.address);1650 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1744 expect(accountBalance).to.be.equal(0n);1651 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
@@ -16,9 +16,8 @@
 
 import {IKeyringPair} from '@polkadot/types/types';
 import config from '../config';
-import {XcmV2TraitsError} from '../interfaces';
 import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds} from '../util';
-import {DevUniqueHelper} from '../util/playgrounds/unique.dev';
+import {DevUniqueHelper, Event} from '../util/playgrounds/unique.dev';
 
 const UNIQUE_CHAIN = 2037;
 const STATEMINT_CHAIN = 1000;
@@ -675,30 +674,20 @@
       moreThanAcalaHas,
     );
 
+    let maliciousXcmProgramSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique
     await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
       await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram);
+
+      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
     });
 
-    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', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramSent.messageHash()
+        && event.outcome().isFailedToTransactAsset;
+    });
 
     targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(targetAccountBalance).to.be.equal(0n);
@@ -767,30 +756,21 @@
       testAmount,
     );
 
+    let maliciousXcmProgramFullIdSent: any;
+    let maliciousXcmProgramHereIdSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique using full UNQ identification
     await usingAcalaPlaygrounds(acalaUrl, async (helper) => {
       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,
-    );
+      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent != null,
-      '\'xcmpQueue.FailEvent\' event is expected',
-    ).to.be.true;
-
-    expect(
-      xcmpQueueFailEvent!.isUntrustedReserveLocation,
-      `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
@@ -798,24 +778,14 @@
     // 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;
+      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent!.isUntrustedReserveLocation,
-      `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
@@ -836,6 +806,10 @@
   let uniqueAccountMultilocation: any;
   let uniqueCombinedMultilocation: any;
 
+  let messageSent: any;
+
+  const maxWaitBlocks = 3;
+
   before(async () => {
     await usingPlaygrounds(async (helper, privateKey) => {
       alice = await privateKey('//Alice');
@@ -885,26 +859,11 @@
     });
   });
 
-  const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {
-    const maxWaitBlocks = 3;
-    const outcomeField = 1;
-
-    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
-      maxWaitBlocks,
-      'xcmpQueue',
-      'Fail',
-      outcomeField,
-    );
-
-    expect(
-      xcmpQueueFailEvent != null,
-      `[reject ${network} tokens] 'xcmpQueue.FailEvent' event is expected`,
-    ).to.be.true;
-
-    expect(
-      xcmpQueueFailEvent!.isFailedToTransactAsset,
-      `[reject ${network} tokens] The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+  const expectFailedToTransact = async (helper: DevUniqueHelper, messageSent: any) => {
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == messageSent.messageHash()
+        && event.outcome().isFailedToTransactAsset;
+    });
   };
 
   itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {
@@ -914,9 +873,11 @@
       };
       const destination = uniqueCombinedMultilocation;
       await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');
+
+      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
     });
 
-    await expectFailedToTransact('ACA', helper);
+    await expectFailedToTransact(helper, messageSent);
   });
 
   itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => {
@@ -924,9 +885,11 @@
       const id = 'SelfReserve';
       const destination = uniqueCombinedMultilocation;
       await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');
+
+      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
     });
 
-    await expectFailedToTransact('GLMR', helper);
+    await expectFailedToTransact(helper, messageSent);
   });
 
   itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => {
@@ -954,9 +917,11 @@
         assets,
         feeAssetItem,
       ]);
+
+      messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
     });
 
-    await expectFailedToTransact('ASTR', helper);
+    await expectFailedToTransact(helper, messageSent);
   });
 });
 
@@ -1196,6 +1161,9 @@
       moreThanMoonbeamHas,
     );
 
+    let maliciousXcmProgramSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique
     await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
       const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, maliciousXcmProgram]);
@@ -1203,27 +1171,14 @@
       // 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;
+      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent!.isFailedToTransactAsset,
-      `The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramSent.messageHash()
+        && event.outcome().isFailedToTransactAsset;
+    });
 
     targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(targetAccountBalance).to.be.equal(0n);
@@ -1296,6 +1251,10 @@
       testAmount,
     );
 
+    let maliciousXcmProgramFullIdSent: any;
+    let maliciousXcmProgramHereIdSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique using full UNQ identification
     await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {
       const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueMultilocation, maliciousXcmProgramFullId]);
@@ -1303,27 +1262,14 @@
       // 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;
+      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent!.isUntrustedReserveLocation,
-      `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
@@ -1335,24 +1281,14 @@
       // 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;
+      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent!.isUntrustedReserveLocation,
-      `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
@@ -1600,31 +1536,21 @@
       moreThanAstarHas,
     );
 
+    let maliciousXcmProgramSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
       await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram);
+
+      maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
     });
 
-    const maxWaitBlocks = 3;
-    const outcomeField = 1;
-
-    const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
-      maxWaitBlocks,
-      'xcmpQueue',
-      'Fail',
-      outcomeField,
-    );
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramSent.messageHash()
+        && event.outcome().isFailedToTransactAsset;
+    });
 
-    expect(
-      xcmpQueueFailEvent != null,
-      '\'xcmpQueue.FailEvent\' event is expected',
-    ).to.be.true;
-
-    expect(
-      xcmpQueueFailEvent!.isFailedToTransactAsset,
-      `The XCM error should be 'FailedToTransactAsset', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
-
     targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(targetAccountBalance).to.be.equal(0n);
 
@@ -1692,30 +1618,21 @@
       testAmount,
     );
 
+    let maliciousXcmProgramFullIdSent: any;
+    let maliciousXcmProgramHereIdSent: any;
+    const maxWaitBlocks = 3;
+
     // Try to trick Unique using full UNQ identification
     await usingAstarPlaygrounds(astarUrl, async (helper) => {
       await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);
-    });
 
-    const maxWaitBlocks = 3;
-    const outcomeField = 1;
+      maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    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 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramFullIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);
@@ -1723,24 +1640,14 @@
     // 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(
-      xcmpQueueFailEvent != null,
-      '\'xcmpQueue.FailEvent\' event is expected',
-    ).to.be.true;
+      maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);
+    });
 
-    expect(
-      xcmpQueueFailEvent!.isUntrustedReserveLocation,
-      `The XCM error should be 'UntrustedReserveLocation', got '${xcmpQueueFailEvent!.toHuman()}'`,
-    ).to.be.true;
+    await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => {
+      return event.messageHash() == maliciousXcmProgramHereIdSent.messageHash()
+        && event.outcome().isUntrustedReserveLocation;
+    });
 
     accountBalance = await helper.balance.getSubstrate(targetAccount.address);
     expect(accountBalance).to.be.equal(0n);