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
--- a/tests/src/util/playgrounds/unique.ts
+++ b/tests/src/util/playgrounds/unique.ts
@@ -642,6 +642,10 @@
     return call(...params);
   }
 
+  encodeApiCall(apiCall: string, params: any[]) {
+    return this.constructApiCall(apiCall, params).method.toHex();
+  }
+
   async executeExtrinsic(sender: TSigner, extrinsic: string, params: any[], expectSuccess=true, options: Partial<SignerOptions>|null = null/*, failureMessage='expected success'*/) {
     if(this.api === null) throw Error('API not initialized');
     if(!extrinsic.startsWith('api.tx.')) throw Error(`${extrinsic} is not transaction`);
modifiedtests/src/xcm/xcmQuartz.test.tsdiffbeforeafterboth
15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.
1616
17import {IKeyringPair} from '@polkadot/types/types';17import {IKeyringPair} from '@polkadot/types/types';
18import {blake2AsHex} from '@polkadot/util-crypto';
19import config from '../config';18import config from '../config';
20import {XcmV2TraitsError} from '../interfaces';19import {XcmV2TraitsError} from '../interfaces';
21import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';20import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util';
680 });679 });
681680
682 const maxWaitBlocks = 3;681 const maxWaitBlocks = 3;
682 const outcomeField = 1;
683683
684 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(684 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
685 maxWaitBlocks,685 maxWaitBlocks,
686 'xcmpQueue',686 'xcmpQueue',
687 'Fail',687 'Fail',
688 outcomeField,
688 );689 );
689690
690 expect(691 expect(
738 },739 },
739 };740 };
740741
741 const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(742 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
742 targetAccount.addressRaw,743 targetAccount.addressRaw,
743 {744 {
744 Concrete: {745 Concrete: {
753 testAmount,754 testAmount,
754 );755 );
755756
757 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
758 targetAccount.addressRaw,
759 {
760 Concrete: {
761 parents: 0,
762 interior: 'Here',
763 },
764 },
765 testAmount,
766 );
767
768 // Try to trick Quartz using full QTZ identification
756 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {769 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
757 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);770 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
758 });771 });
759772
760 const maxWaitBlocks = 3;773 const maxWaitBlocks = 3;
761
762 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(774 const outcomeField = 1;
775
776 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
763 maxWaitBlocks,777 maxWaitBlocks,
764 'xcmpQueue',778 'xcmpQueue',
765 'Fail',779 'Fail',
780 outcomeField,
766 );781 );
767782
768 expect(783 expect(
775 'The XCM error should be \'isUntrustedReserveLocation\'',790 'The XCM error should be \'isUntrustedReserveLocation\'',
776 ).to.be.true;791 ).to.be.true;
777792
778 const accountBalance = await helper.balance.getSubstrate(targetAccount.address);793 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
779 expect(accountBalance).to.be.equal(0n);794 expect(accountBalance).to.be.equal(0n);
795
796 // Try to trick Quartz using shortened QTZ identification
797 await usingKaruraPlaygrounds(karuraUrl, async (helper) => {
798 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
799 });
800
801 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
802 maxWaitBlocks,
803 'xcmpQueue',
804 'Fail',
805 outcomeField,
806 );
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 \'isUntrustedReserveLocation\'',
816 ).to.be.true;
817
818 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
819 expect(accountBalance).to.be.equal(0n);
780 });820 });
781});821});
782822
845885
846 const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {886 const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => {
847 const maxWaitBlocks = 3;887 const maxWaitBlocks = 3;
888 const outcomeField = 1;
848889
849 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(890 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
850 maxWaitBlocks,891 maxWaitBlocks,
851 'xcmpQueue',892 'xcmpQueue',
852 'Fail',893 'Fail',
894 outcomeField,
853 );895 );
854896
855 expect(897 expect(
918960
919describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {961describeXCM('[XCM] Integration test: Exchanging QTZ with Moonriver', () => {
920 // Quartz constants962 // Quartz constants
921 let quartzDonor: IKeyringPair;963 let alice: IKeyringPair;
922 let quartzAssetLocation;964 let quartzAssetLocation;
923965
924 let randomAccountQuartz: IKeyringPair;966 let randomAccountQuartz: IKeyringPair;
927 // Moonriver constants969 // Moonriver constants
928 let assetId: string;970 let assetId: string;
929
930 const councilVotingThreshold = 2;
931 const technicalCommitteeThreshold = 2;
932 const votingPeriod = 3;
933 const delayPeriod = 0;
934971
935 const quartzAssetMetadata = {972 const quartzAssetMetadata = {
936 name: 'xcQuartz',973 name: 'xcQuartz',
952989
953 before(async () => {990 before(async () => {
954 await usingPlaygrounds(async (helper, privateKey) => {991 await usingPlaygrounds(async (helper, privateKey) => {
955 quartzDonor = await privateKey('//Alice');992 alice = await privateKey('//Alice');
956 [randomAccountQuartz] = await helper.arrange.createAccounts([0n], quartzDonor);993 [randomAccountQuartz] = await helper.arrange.createAccounts([0n], alice);
957994
958 balanceForeignQtzTokenInit = 0n;995 balanceForeignQtzTokenInit = 0n;
959996
960 // Set the default version to wrap the first message to other chains.997 // Set the default version to wrap the first message to other chains.
961 const alice = quartzDonor;
962 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);998 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);
963 });999 });
9641000
994 unitsPerSecond,1030 unitsPerSecond,
995 numAssetsWeightHint,1031 numAssetsWeightHint,
996 });1032 });
997 const proposalHash = blake2AsHex(encodedProposal);
9981033
999 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);1034 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);
1000 console.log('Encoded length %d', encodedProposal.length);1035
1001 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);
1002
1003 // >>> Note motion preimage >>>
1004 console.log('Note motion preimage.......');
1005 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);1036 await helper.fastDemocracy.executeProposal('register QTZ foreign asset', encodedProposal);
1006 console.log('Note motion preimage.......DONE');
1007 // <<< Note motion preimage <<<
1008
1009 // >>> Propose external motion through council >>>
1010 console.log('Propose external motion through council.......');
1011 const externalMotion = helper.democracy.externalProposeMajority({Legacy: proposalHash});
1012 const encodedMotion = externalMotion?.method.toHex() || '';
1013 const motionHash = blake2AsHex(encodedMotion);
1014 console.log('Motion hash is %s', motionHash);
1015
1016 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);
1017
1018 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;
1019 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);
1020 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);
1021
1022 await helper.collective.council.close(
1023 dorothyAccount,
1024 motionHash,
1025 councilProposalIdx,
1026 {
1027 refTime: 1_000_000_000,
1028 proofSize: 1_000_000,
1029 },
1030 externalMotion.encodedLength,
1031 );
1032 console.log('Propose external motion through council.......DONE');
1033 // <<< Propose external motion through council <<<
1034
1035 // >>> Fast track proposal through technical committee >>>
1036 console.log('Fast track proposal through technical committee.......');
1037 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);
1038 const encodedFastTrack = fastTrack?.method.toHex() || '';
1039 const fastTrackHash = blake2AsHex(encodedFastTrack);
1040 console.log('FastTrack hash is %s', fastTrackHash);
1041
1042 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);
1043
1044 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;
1045 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);
1046 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);
1047
1048 await helper.collective.techCommittee.close(
1049 baltatharAccount,
1050 fastTrackHash,
1051 techProposalIdx,
1052 {
1053 refTime: 1_000_000_000,
1054 proofSize: 1_000_000,
1055 },
1056 fastTrack.encodedLength,
1057 );
1058 console.log('Fast track proposal through technical committee.......DONE');
1059 // <<< Fast track proposal through technical committee <<<
1060
1061 // >>> Referendum voting >>>
1062 console.log('Referendum voting.......');
1063 await helper.democracy.referendumVote(dorothyAccount, 0, {
1064 balance: 10_000_000_000_000_000_000n,
1065 vote: {aye: true, conviction: 1},
1066 });
1067 console.log('Referendum voting.......DONE');
1068 // <<< Referendum voting <<<
10691037
1070 // >>> Acquire Quartz AssetId Info on Moonriver >>>1038 // >>> Acquire Quartz AssetId Info on Moonriver >>>
1071 console.log('Acquire Quartz AssetId Info on Moonriver.......');1039 console.log('Acquire Quartz AssetId Info on Moonriver.......');
1072
1073 // Wait for the democracy execute
1074 await helper.wait.newBlocks(5);
10751040
1076 assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();1041 assetId = (await helper.assetManager.assetTypeId(quartzAssetLocation)).toString();
10771042
1089 });1054 });
10901055
1091 await usingPlaygrounds(async (helper) => {1056 await usingPlaygrounds(async (helper) => {
1092 await helper.balance.transferToSubstrate(quartzDonor, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);1057 await helper.balance.transferToSubstrate(alice, randomAccountQuartz.address, 10n * TRANSFER_AMOUNT);
1093 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);1058 balanceQuartzTokenInit = await helper.balance.getSubstrate(randomAccountQuartz.address);
1094 });1059 });
1095 });1060 });
1197 expect(qtzFees == 0n).to.be.true;1162 expect(qtzFees == 0n).to.be.true;
1198 });1163 });
11991164
1200 // eslint-disable-next-line require-await
1201 itSub.skip('Moonriver can send only up to its balance', async ({helper}) => {1165 itSub('Moonriver can send only up to its balance', async ({helper}) => {
1166 // set Moonriver's sovereign account's balance
1167 const moonriverBalance = 10000n * (10n ** QTZ_DECIMALS);
1168 const moonriverSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONRIVER_CHAIN);
1169 await helper.getSudo().balance.setBalanceSubstrate(alice, moonriverSovereignAccount, moonriverBalance);
1170
1171 const moreThanMoonriverHas = moonriverBalance * 2n;
1172
1173 let targetAccountBalance = 0n;
1174 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);
1175
1176 const quartzMultilocation = {
1177 V1: {
1178 parents: 1,
1179 interior: {
1180 X1: {Parachain: QUARTZ_CHAIN},
1181 },
1182 },
1183 };
1184
1185 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
1186 targetAccount.addressRaw,
1187 {
1188 Concrete: {
1189 parents: 0,
1190 interior: 'Here',
1191 },
1192 },
1193 moreThanMoonriverHas,
1194 );
1195
1196 // Try to trick Quartz
1197 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1198 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgram]);
1199
1200 // Needed to bypass the call filter.
1201 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
1202 await helper.fastDemocracy.executeProposal('try to spend more QTZ than Moonriver has', batchCall);
1203 });
1204
1205 const maxWaitBlocks = 3;
1206 const outcomeField = 1;
1207
1202 throw Error('Not yet implemented');1208 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1209 maxWaitBlocks,
1210 'xcmpQueue',
1211 'Fail',
1212 outcomeField,
1213 );
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\'',
1223 ).to.be.true;
1224
1225 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1226 expect(targetAccountBalance).to.be.equal(0n);
1227
1228 // But Moonriver still can send the correct amount
1229 const validTransferAmount = moonriverBalance / 2n;
1230 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
1231 targetAccount.addressRaw,
1232 {
1233 Concrete: {
1234 parents: 0,
1235 interior: 'Here',
1236 },
1237 },
1238 validTransferAmount,
1239 );
1240
1241 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1242 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, validXcmProgram]);
1243
1244 // Needed to bypass the call filter.
1245 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);
1246 await helper.fastDemocracy.executeProposal('Spend the correct amount of QTZ', batchCall);
1247 });
1248
1249 await helper.wait.newBlocks(maxWaitBlocks);
1250
1251 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);
1252 expect(targetAccountBalance).to.be.equal(validTransferAmount);
1203 });1253 });
12041254
1205 // eslint-disable-next-line require-await
1206 itSub.skip('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {1255 itSub('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => {
1256 const testAmount = 10_000n * (10n ** QTZ_DECIMALS);
1257 const [targetAccount] = await helper.arrange.createAccounts([0n], alice);
1258
1259 const quartzMultilocation = {
1260 V1: {
1261 parents: 1,
1262 interior: {
1263 X1: {
1264 Parachain: QUARTZ_CHAIN,
1265 },
1266 },
1267 },
1268 };
1269
1270 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
1271 targetAccount.addressRaw,
1272 {
1273 Concrete: {
1274 parents: 0,
1275 interior: {
1276 X1: {
1277 Parachain: QUARTZ_CHAIN,
1278 },
1279 },
1280 },
1281 },
1282 testAmount,
1283 );
1284
1285 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
1286 targetAccount.addressRaw,
1287 {
1288 Concrete: {
1289 parents: 0,
1290 interior: 'Here',
1291 },
1292 },
1293 testAmount,
1294 );
1295
1296 // Try to trick Quartz using full QTZ identification
1297 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1298 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramFullId]);
1299
1300 // Needed to bypass the call filter.
1301 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);
1303 });
1304
1305 const maxWaitBlocks = 3;
1306 const outcomeField = 1;
1307
1207 throw Error('Not yet implemented');1308 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1309 maxWaitBlocks,
1310 'xcmpQueue',
1311 'Fail',
1312 outcomeField,
1313 );
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\'',
1323 ).to.be.true;
1324
1325 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1326 expect(accountBalance).to.be.equal(0n);
1327
1328 // Try to trick Quartz using shortened QTZ identification
1329 await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => {
1330 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [quartzMultilocation, maliciousXcmProgramHereId]);
1331
1332 // Needed to bypass the call filter.
1333 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);
1335 });
1336
1337 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1338 maxWaitBlocks,
1339 'xcmpQueue',
1340 'Fail',
1341 outcomeField,
1342 );
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\'',
1352 ).to.be.true;
1353
1354 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1355 expect(accountBalance).to.be.equal(0n);
1208 });1356 });
1209});1357});
12101358
1456 });1604 });
14571605
1458 const maxWaitBlocks = 3;1606 const maxWaitBlocks = 3;
1607 const outcomeField = 1;
14591608
1460 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(1609 const xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1461 maxWaitBlocks,1610 maxWaitBlocks,
1462 'xcmpQueue',1611 'xcmpQueue',
1463 'Fail',1612 'Fail',
1613 outcomeField,
1464 );1614 );
14651615
1466 expect(1616 expect(
1514 },1664 },
1515 };1665 };
15161666
1517 const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited(1667 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
1518 targetAccount.addressRaw,1668 targetAccount.addressRaw,
1519 {1669 {
1520 Concrete: {1670 Concrete: {
1529 testAmount,1679 testAmount,
1530 );1680 );
15311681
1682 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(
1683 targetAccount.addressRaw,
1684 {
1685 Concrete: {
1686 parents: 0,
1687 interior: 'Here',
1688 },
1689 },
1690 testAmount,
1691 );
1692
1693 // Try to trick Quartz using full QTZ identification
1532 await usingShidenPlaygrounds(shidenUrl, async (helper) => {1694 await usingShidenPlaygrounds(shidenUrl, async (helper) => {
1533 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram);1695 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramFullId);
1534 });1696 });
15351697
1536 const maxWaitBlocks = 3;1698 const maxWaitBlocks = 3;
1537
1538 const xcmpQueueFailEvent = await helper.wait.eventOutcome<XcmV2TraitsError>(1699 const outcomeField = 1;
1700
1701 let xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1539 maxWaitBlocks,1702 maxWaitBlocks,
1540 'xcmpQueue',1703 'xcmpQueue',
1541 'Fail',1704 'Fail',
1705 outcomeField,
1542 );1706 );
15431707
1544 expect(1708 expect(
1551 'The XCM error should be \'isUntrustedReserveLocation\'',1715 'The XCM error should be \'isUntrustedReserveLocation\'',
1552 ).to.be.true;1716 ).to.be.true;
15531717
1554 const accountBalance = await helper.balance.getSubstrate(targetAccount.address);1718 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1555 expect(accountBalance).to.be.equal(0n);1719 expect(accountBalance).to.be.equal(0n);
1720
1721 // Try to trick Quartz using shortened QTZ identification
1722 await usingShidenPlaygrounds(shidenUrl, async (helper) => {
1723 await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgramHereId);
1724 });
1725
1726 xcmpQueueFailEvent = await helper.wait.eventData<XcmV2TraitsError>(
1727 maxWaitBlocks,
1728 'xcmpQueue',
1729 'Fail',
1730 outcomeField,
1731 );
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\'',
1741 ).to.be.true;
1742
1743 accountBalance = await helper.balance.getSubstrate(targetAccount.address);
1744 expect(accountBalance).to.be.equal(0n);
1556 });1745 });
1557});1746});
15581747
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);
   });