From 1b19b1f3b608722897632e745c34cb33f2b9707a Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Wed, 12 Apr 2023 12:38:52 +0000 Subject: [PATCH] test: untrusted reserve locations --- --- a/tests/src/util/playgrounds/unique.dev.ts +++ b/tests/src/util/playgrounds/unique.dev.ts @@ -421,18 +421,13 @@ return capture; } - makeXcmProgramWithdrawDeposit(beneficiary: Uint8Array, amount: bigint | string) { + makeXcmProgramWithdrawDeposit(beneficiary: Uint8Array, id: any, amount: bigint | string) { return { V2: [ { WithdrawAsset: [ { - id: { - Concrete: { - parents: 0, - interior: 'Here', - }, - }, + id, fun: { Fungible: amount, }, @@ -442,12 +437,54 @@ { BuyExecution: { fees: { - id: { - Concrete: { - parents: 0, - interior: 'Here', + id, + fun: { + Fungible: amount, + }, + }, + weightLimit: 'Unlimited' + }, + }, + { + DepositAsset: { + assets: { + Wild: 'All' + }, + maxAssets: 1, + beneficiary: { + parents: 0, + interior: { + X1: { + AccountId32: { + network: 'Any', + id: beneficiary + }, }, }, + }, + }, + }, + ], + }; + } + + makeXcmProgramReserveAssetDeposited(beneficiary: Uint8Array, id: any, amount: bigint | string) { + return { + V2: [ + { + ReserveAssetDeposited: [ + { + id, + fun: { + Fungible: amount, + }, + }, + ], + }, + { + BuyExecution: { + fees: { + id, fun: { Fungible: amount, }, @@ -472,7 +509,7 @@ }, }, }, - } + }, }, ], }; --- a/tests/src/util/playgrounds/unique.ts +++ b/tests/src/util/playgrounds/unique.ts @@ -3021,6 +3021,18 @@ await this.teleportAssets(signer, destination, beneficiary, assets, feeAssetItem); } + + async send(signer: IKeyringPair, destination: any, message: any) { + await this.helper.executeExtrinsic( + signer, + `api.tx.${this.palletName}.send`, + [ + destination, + message, + ], + true, + ); + } } class XTokensGroup extends HelperGroup { @@ -3284,6 +3296,7 @@ assetRegistry: AcalaAssetRegistryGroup; xTokens: XTokensGroup; tokens: TokensGroup; + xcm: XcmGroup; constructor(logger?: ILogger, options: {[key: string]: any} = {}) { super(logger, options.helperBase ?? AcalaHelper); @@ -3292,6 +3305,7 @@ this.assetRegistry = new AcalaAssetRegistryGroup(this); this.xTokens = new XTokensGroup(this); this.tokens = new TokensGroup(this); + this.xcm = new XcmGroup(this, 'polkadotXcm'); } getSudo() { --- a/tests/src/xcm/xcmQuartz.test.ts +++ b/tests/src/xcm/xcmQuartz.test.ts @@ -663,19 +663,20 @@ }, }; - const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanKaruraHas); + const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + moreThanKaruraHas, + ); // Try to trick Quartz await usingKaruraPlaygrounds(karuraUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - quartzMultilocation, - maliciousXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram); }); const maxWaitBlocks = 3; @@ -701,18 +702,19 @@ // But Karura still can send the correct amount const validTransferAmount = karuraBalance / 2n; - const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount); + const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + validTransferAmount, + ); await usingKaruraPlaygrounds(karuraUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - quartzMultilocation, - validXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram); }); await helper.wait.newBlocks(maxWaitBlocks); @@ -720,6 +722,62 @@ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address); expect(targetAccountBalance).to.be.equal(validTransferAmount); }); + + itSub('Should not accept reserve transfer of QTZ from Karura', async ({helper}) => { + const testAmount = 10_000n * (10n ** QTZ_DECIMALS); + const [targetAccount] = await helper.arrange.createAccounts([0n], alice); + + const quartzMultilocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }; + + const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited( + targetAccount.addressRaw, + { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }, + testAmount, + ); + + await usingKaruraPlaygrounds(karuraUrl, async (helper) => { + await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram); + }); + + const maxWaitBlocks = 3; + + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); + + expect( + xcmpQueueFailEvent != null, + `'xcmpQueue.FailEvent' event is expected`, + ).to.be.true; + + expect( + xcmpQueueFailEvent!.isUntrustedReserveLocation, + `The XCM error should be 'isUntrustedReserveLocation'`, + ).to.be.true; + + const accountBalance = await helper.balance.getSubstrate(targetAccount.address); + expect(accountBalance).to.be.equal(0n); + }); }); // These tests are relevant only when @@ -1142,6 +1200,10 @@ itSub.skip('Moonriver can send only up to its balance', async ({helper}) => { throw Error("Not yet implemented"); }); + + itSub.skip('Should not accept reserve transfer of QTZ from Moonriver', async ({helper}) => { + throw Error("Not yet implemented"); + }); }); describeXCM('[XCM] Integration test: Exchanging tokens with Shiden', () => { @@ -1375,19 +1437,20 @@ }, }; - const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanShidenHas); + const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + moreThanShidenHas, + ); // Try to trick Quartz await usingShidenPlaygrounds(shidenUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - quartzMultilocation, - maliciousXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram); }); const maxWaitBlocks = 3; @@ -1413,18 +1476,19 @@ // But Shiden still can send the correct amount const validTransferAmount = shidenBalance / 2n; - const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount); + const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + validTransferAmount, + ); await usingShidenPlaygrounds(shidenUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - quartzMultilocation, - validXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, quartzMultilocation, validXcmProgram); }); await helper.wait.newBlocks(maxWaitBlocks); @@ -1432,4 +1496,60 @@ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address); expect(targetAccountBalance).to.be.equal(validTransferAmount); }); + + itSub('Should not accept reserve transfer of QTZ from Shiden', async ({helper}) => { + const testAmount = 10_000n * (10n ** QTZ_DECIMALS); + const [targetAccount] = await helper.arrange.createAccounts([0n], alice); + + const quartzMultilocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }; + + const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited( + targetAccount.addressRaw, + { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: QUARTZ_CHAIN, + }, + }, + }, + }, + testAmount, + ); + + await usingShidenPlaygrounds(shidenUrl, async (helper) => { + await helper.getSudo().xcm.send(alice, quartzMultilocation, maliciousXcmProgram); + }); + + const maxWaitBlocks = 3; + + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); + + expect( + xcmpQueueFailEvent != null, + `'xcmpQueue.FailEvent' event is expected`, + ).to.be.true; + + expect( + xcmpQueueFailEvent!.isUntrustedReserveLocation, + `The XCM error should be 'isUntrustedReserveLocation'`, + ).to.be.true; + + const accountBalance = await helper.balance.getSubstrate(targetAccount.address); + expect(accountBalance).to.be.equal(0n); + }); }); --- a/tests/src/xcm/xcmUnique.test.ts +++ b/tests/src/xcm/xcmUnique.test.ts @@ -665,19 +665,20 @@ }, }; - const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanAcalaHas); + const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + moreThanAcalaHas, + ); // Try to trick Unique await usingAcalaPlaygrounds(acalaUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - uniqueMultilocation, - maliciousXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram); }); const maxWaitBlocks = 3; @@ -703,18 +704,19 @@ // But Acala still can send the correct amount const validTransferAmount = acalaBalance / 2n; - const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount); + const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + validTransferAmount, + ); await usingAcalaPlaygrounds(acalaUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - uniqueMultilocation, - validXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, uniqueMultilocation, validXcmProgram); }); await helper.wait.newBlocks(maxWaitBlocks); @@ -722,6 +724,62 @@ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address); expect(targetAccountBalance).to.be.equal(validTransferAmount); }); + + itSub('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); + + const uniqueMultilocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }; + + const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited( + targetAccount.addressRaw, + { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }, + testAmount, + ); + + await usingAcalaPlaygrounds(acalaUrl, async (helper) => { + await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram); + }); + + const maxWaitBlocks = 3; + + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); + + expect( + xcmpQueueFailEvent != null, + `'xcmpQueue.FailEvent' event is expected`, + ).to.be.true; + + expect( + xcmpQueueFailEvent!.isUntrustedReserveLocation, + `The XCM error should be 'isUntrustedReserveLocation'`, + ).to.be.true; + + const accountBalance = await helper.balance.getSubstrate(targetAccount.address); + expect(accountBalance).to.be.equal(0n); + }); }); // These tests are relevant only when @@ -1145,6 +1203,10 @@ itSub.skip('Moonbeam can send only up to its balance', async ({helper}) => { throw Error("Not yet implemented"); }); + + itSub.skip('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => { + throw Error("Not yet implemented"); + }); }); describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => { @@ -1356,63 +1418,7 @@ console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`); expect(balanceUNQ).to.eq(balanceAfterUniqueToAstarXCM + unqFromAstarTransfered); }); - - itSub.skip('Should not accept limitedReserveTransfer of UNQ from ASTAR', async ({helper}) => { - await usingAstarPlaygrounds(astarUrl, async (helper) => { - const destination = { - V1: { - parents: 1, - interior: { - X1: { - Parachain: UNIQUE_CHAIN, - }, - }, - }, - }; - - const beneficiary = { - V1: { - parents: 0, - interior: { - X1: { - AccountId32: { - network: 'Any', - id: randomAccount.addressRaw, - }, - }, - }, - }, - }; - const assets = { - V1: [ - { - id: { - Concrete: { - parents: 1, - interior: { - X1: { - Parachain: UNIQUE_CHAIN, - }, - }, - }, - }, - fun: { - Fungible: unqFromAstarTransfered, - }, - }, - ], - }; - - // Initial balance is 1 ASTAR - expect(await helper.balance.getSubstrate(randomAccount.address)).to.eq(astarInitialBalance); - - const feeAssetItem = 0; - // TODO: expect rejected: - await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited'); - }); - }); - itSub('Astar can send only up to its balance', async ({helper}) => { // set Astar's sovereign account's balance const astarBalance = 10000n * (10n ** UNQ_DECIMALS); @@ -1433,19 +1439,20 @@ }, }; - const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, moreThanShidenHas); + const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + moreThanShidenHas, + ); // Try to trick Unique await usingAstarPlaygrounds(astarUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - uniqueMultilocation, - maliciousXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram); }); const maxWaitBlocks = 3; @@ -1471,18 +1478,19 @@ // But Astar still can send the correct amount const validTransferAmount = astarBalance / 2n; - const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(targetAccount.addressRaw, validTransferAmount); + const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit( + targetAccount.addressRaw, + { + Concrete: { + parents: 0, + interior: 'Here', + }, + }, + validTransferAmount, + ); await usingAstarPlaygrounds(astarUrl, async (helper) => { - await helper.getSudo().executeExtrinsic( - alice, - 'api.tx.polkadotXcm.send', - [ - uniqueMultilocation, - validXcmProgram, - ], - true, - ); + await helper.getSudo().xcm.send(alice, uniqueMultilocation, validXcmProgram); }); await helper.wait.newBlocks(maxWaitBlocks); @@ -1490,4 +1498,61 @@ targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address); expect(targetAccountBalance).to.be.equal(validTransferAmount); }); + + itSub('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); + + const uniqueMultilocation = { + V1: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }; + + const maliciousXcmProgram = helper.arrange.makeXcmProgramReserveAssetDeposited( + targetAccount.addressRaw, + { + Concrete: { + parents: 1, + interior: { + X1: { + Parachain: UNIQUE_CHAIN, + }, + }, + }, + }, + testAmount, + ); + + await usingAstarPlaygrounds(astarUrl, async (helper) => { + await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgram); + }); + + const maxWaitBlocks = 3; + + const xcmpQueueFailEvent = await helper.wait.eventOutcome( + maxWaitBlocks, + 'xcmpQueue', + 'Fail', + ); + + expect( + xcmpQueueFailEvent != null, + `'xcmpQueue.FailEvent' event is expected`, + ).to.be.true; + + expect( + xcmpQueueFailEvent!.isUntrustedReserveLocation, + `The XCM error should be 'isUntrustedReserveLocation'`, + ).to.be.true; + + const accountBalance = await helper.balance.getSubstrate(targetAccount.address); + expect(accountBalance).to.be.equal(0n); + }); + }); -- gitstuff