--- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -632,6 +632,19 @@ }); return promise; } + + async eventOutcome(maxBlocksToWait: number, eventSection: string, eventMethod: string) { + const eventRecord = await this.event(maxBlocksToWait, eventSection, eventMethod); + + if (eventRecord == null) { + return null; + } + + const event = eventRecord!.event; + const outcome = event.data[1] as EventT; + + return outcome; + } } class SessionGroup { --- a/tests/src/xcm/xcmQuartz.test.ts +++ b/tests/src/xcm/xcmQuartz.test.ts @@ -19,6 +19,7 @@ import config from '../config'; import {XcmV2TraitsError} from '../interfaces'; import {itSub, expect, describeXCM, usingPlaygrounds, usingKaruraPlaygrounds, usingRelayPlaygrounds, usingMoonriverPlaygrounds, usingStateminePlaygrounds, usingShidenPlaygrounds} from '../util'; +import {DevUniqueHelper} from '../util/playgrounds/unique.dev'; const QUARTZ_CHAIN = 2095; const STATEMINE_CHAIN = 1000; @@ -643,61 +644,139 @@ }); }); -// These tests are relevant only when the foreign asset pallet is disabled +// These tests are relevant only when +// the the corresponding foreign assets are not registered describeXCM('[XCM] Integration test: Quartz rejects non-native tokens', () => { let alice: IKeyringPair; + let alith: IKeyringPair; + + const testAmount = 100_000_000_000n; + let quartzParachainJunction; + let quartzAccountJunction; + + let quartzParachainMultilocation: any; + let quartzAccountMultilocation: any; + let quartzCombinedMultilocation: any; before(async () => { await usingPlaygrounds(async (helper, privateKey) => { alice = await privateKey('//Alice'); - // Set the default version to wrap the first message to other chains. - await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); - }); - }); + quartzParachainJunction = {Parachain: QUARTZ_CHAIN}; + quartzAccountJunction = { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }; - itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => { - await usingKaruraPlaygrounds(karuraUrl, async (helper) => { - const destination = { + quartzParachainMultilocation = { V1: { parents: 1, interior: { - X2: [ - {Parachain: QUARTZ_CHAIN}, - { - AccountId32: { - network: 'Any', - id: alice.addressRaw, - }, - }, - ], + X1: quartzParachainJunction, }, }, }; - const id = { - Token: 'KAR', + quartzAccountMultilocation = { + V1: { + parents: 0, + interior: { + X1: quartzAccountJunction, + }, + }, }; - await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited'); + quartzCombinedMultilocation = { + V1: { + parents: 1, + interior: { + X2: [quartzParachainJunction, quartzAccountJunction], + }, + }, + }; + + // Set the default version to wrap the first message to other chains. + await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); }); + // eslint-disable-next-line require-await + await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => { + alith = helper.account.alithAccount(); + }); + }); + + const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => { const maxWaitBlocks = 3; - const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail'); + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); expect( xcmpQueueFailEvent != null, - '[Karura] xcmpQueue.FailEvent event is expected', + `[reject ${network} tokens] 'xcmpQueue.FailEvent' event is expected`, ).to.be.true; - const event = xcmpQueueFailEvent!.event; - const outcome = event.data[1] as XcmV2TraitsError; - expect( - outcome.isFailedToTransactAsset, - '[Karura] The XCM error should be `FailedToTransactAsset`', + xcmpQueueFailEvent!.isFailedToTransactAsset, + `[reject ${network} tokens] The XCM error should be 'FailedToTransactAsset'`, ).to.be.true; + }; + + itSub('Quartz rejects KAR tokens from Karura', async ({helper}) => { + await usingKaruraPlaygrounds(karuraUrl, async (helper) => { + const id = { + Token: 'KAR', + }; + const destination = quartzCombinedMultilocation; + await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited'); + }); + + await expectFailedToTransact('KAR', helper); + }); + + itSub('Quartz rejects MOVR tokens from Moonriver', async ({helper}) => { + await usingMoonriverPlaygrounds(moonriverUrl, async (helper) => { + const id = 'SelfReserve'; + const destination = quartzCombinedMultilocation; + await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited'); + }); + + await expectFailedToTransact('MOVR', helper); + }); + + itSub('Quartz rejects SDN tokens from Shiden', async ({helper}) => { + await usingShidenPlaygrounds(shidenUrl, async (helper) => { + const destinationParachain = quartzParachainMultilocation; + const beneficiary = quartzAccountMultilocation; + const assets = { + V1: [{ + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: testAmount, + }, + }], + }; + const feeAssetItem = 0; + + await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [ + destinationParachain, + beneficiary, + assets, + feeAssetItem, + ]); + }); + + await expectFailedToTransact('SDN', helper); }); }); --- a/tests/src/xcm/xcmUnique.test.ts +++ b/tests/src/xcm/xcmUnique.test.ts @@ -19,6 +19,7 @@ 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'; const UNIQUE_CHAIN = 2037; const STATEMINT_CHAIN = 1000; @@ -645,61 +646,139 @@ }); }); -// These tests are relevant only when the foreign asset pallet is disabled +// These tests are relevant only when +// the the corresponding foreign assets are not registered describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => { let alice: IKeyringPair; + let alith: IKeyringPair; + + const testAmount = 100_000_000_000n; + let uniqueParachainJunction; + let uniqueAccountJunction; + + let uniqueParachainMultilocation: any; + let uniqueAccountMultilocation: any; + let uniqueCombinedMultilocation: any; before(async () => { await usingPlaygrounds(async (helper, privateKey) => { alice = await privateKey('//Alice'); - // Set the default version to wrap the first message to other chains. - await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); - }); - }); + uniqueParachainJunction = {Parachain: UNIQUE_CHAIN}; + uniqueAccountJunction = { + AccountId32: { + network: 'Any', + id: alice.addressRaw, + }, + }; - itSub('Unique rejects ACA tokens from Acala', async ({helper}) => { - await usingAcalaPlaygrounds(acalaUrl, async (helper) => { - const destination = { + uniqueParachainMultilocation = { V1: { parents: 1, interior: { - X2: [ - {Parachain: UNIQUE_CHAIN}, - { - AccountId32: { - network: 'Any', - id: alice.addressRaw, - }, - }, - ], + X1: uniqueParachainJunction, }, }, }; - const id = { - Token: 'ACA', + uniqueAccountMultilocation = { + V1: { + parents: 0, + interior: { + X1: uniqueAccountJunction, + }, + }, }; - await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, 'Unlimited'); + uniqueCombinedMultilocation = { + V1: { + parents: 1, + interior: { + X2: [uniqueParachainJunction, uniqueAccountJunction], + }, + }, + }; + + // Set the default version to wrap the first message to other chains. + await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION); }); + // eslint-disable-next-line require-await + await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => { + alith = helper.account.alithAccount(); + }); + }); + + const expectFailedToTransact = async (network: string, helper: DevUniqueHelper) => { const maxWaitBlocks = 3; - const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail'); + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); expect( xcmpQueueFailEvent != null, - '[Acala] xcmpQueue.FailEvent event is expected', + `[reject ${network} tokens] 'xcmpQueue.FailEvent' event is expected`, ).to.be.true; - const event = xcmpQueueFailEvent!.event; - const outcome = event.data[1] as XcmV2TraitsError; - expect( - outcome.isFailedToTransactAsset, - '[Acala] The XCM error should be `FailedToTransactAsset`', + xcmpQueueFailEvent!.isFailedToTransactAsset, + `[reject ${network} tokens] The XCM error should be 'FailedToTransactAsset'`, ).to.be.true; + }; + + itSub('Unique rejects ACA tokens from Acala', async ({helper}) => { + await usingAcalaPlaygrounds(acalaUrl, async (helper) => { + const id = { + Token: 'ACA', + }; + const destination = uniqueCombinedMultilocation; + await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited'); + }); + + await expectFailedToTransact('ACA', helper); + }); + + itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => { + await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => { + const id = 'SelfReserve'; + const destination = uniqueCombinedMultilocation; + await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited'); + }); + + await expectFailedToTransact('GLMR', helper); + }); + + itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => { + await usingAstarPlaygrounds(astarUrl, async (helper) => { + const destinationParachain = uniqueParachainMultilocation; + const beneficiary = uniqueAccountMultilocation; + const assets = { + V1: [{ + id: { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + fun: { + Fungible: testAmount, + }, + }], + }; + const feeAssetItem = 0; + + await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [ + destinationParachain, + beneficiary, + assets, + feeAssetItem, + ]); + }); + + await expectFailedToTransact('ASTR', helper); }); });