difftreelog
fix moonbeam/moonriver XCM tests
in: master
2 files changed
js-packages/tests/xcm/xcmQuartz.test.tsdiffbeforeafterboth--- a/js-packages/tests/xcm/xcmQuartz.test.ts
+++ b/js-packages/tests/xcm/xcmQuartz.test.ts
@@ -1020,9 +1020,7 @@
});
itSub('Should connect and send QTZ to Moonriver', async ({helper}) => {
- const currencyId = {
- NativeAssetId: 'Here',
- };
+ const currencyId = 0;
const dest = {
V2: {
parents: 1,
js-packages/tests/xcm/xcmUnique.test.tsdiffbeforeafterboth1// Copyright 2019-2022 Unique Network (Gibraltar) Ltd.2// This file is part of Unique Network.34// Unique Network is free software: you can redistribute it and/or modify5// it under the terms of the GNU General Public License as published by6// the Free Software Foundation, either version 3 of the License, or7// (at your option) any later version.89// Unique Network is distributed in the hope that it will be useful,10// but WITHOUT ANY WARRANTY; without even the implied warranty of11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the12// GNU General Public License for more details.1314// You should have received a copy of the GNU General Public License15// along with Unique Network. If not, see <http://www.gnu.org/licenses/>.1617import type {IKeyringPair} from '@polkadot/types/types';18import config from '../config.js';19import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds, usingStatemintPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util/index.js';20import {Event} from '@unique/playgrounds/unique.dev.js';21import {hexToString, nToBigInt} from '@polkadot/util';22import {ACALA_CHAIN, ASTAR_CHAIN, MOONBEAM_CHAIN, POLKADEX_CHAIN, SAFE_XCM_VERSION, STATEMINT_CHAIN, UNIQUE_CHAIN, expectFailedToTransact, expectUntrustedReserveLocationFail, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types.js';23import {XcmTestHelper} from './xcm.types';2425const STATEMINT_PALLET_INSTANCE = 50;2627const relayUrl = config.relayUrl;28const statemintUrl = config.statemintUrl;29const acalaUrl = config.acalaUrl;30const moonbeamUrl = config.moonbeamUrl;31const astarUrl = config.astarUrl;32const polkadexUrl = config.polkadexUrl;3334const RELAY_DECIMALS = 12;35const STATEMINT_DECIMALS = 12;36const ACALA_DECIMALS = 12;37const ASTAR_DECIMALS = 18n;38const UNQ_DECIMALS = 18n;3940const TRANSFER_AMOUNT = 2000000000000000000000000n;4142const FUNDING_AMOUNT = 3_500_000_0000_000_000n;4344const TRANSFER_AMOUNT_RELAY = 50_000_000_000_000_000n;4546const USDT_ASSET_ID = 100;47const USDT_ASSET_METADATA_DECIMALS = 18;48const USDT_ASSET_METADATA_NAME = 'USDT';49const USDT_ASSET_METADATA_DESCRIPTION = 'USDT';50const USDT_ASSET_METADATA_MINIMAL_BALANCE = 1n;51const USDT_ASSET_AMOUNT = 10_000_000_000_000_000_000_000_000n;5253const testHelper = new XcmTestHelper('unique');5455describeXCM('[XCM] Integration test: Exchanging USDT with Statemint', () => {56 let alice: IKeyringPair;57 let bob: IKeyringPair;5859 let balanceStmnBefore: bigint;60 let balanceStmnAfter: bigint;6162 let balanceUniqueBefore: bigint;63 let balanceUniqueAfter: bigint;64 let balanceUniqueFinal: bigint;6566 let balanceBobBefore: bigint;67 let balanceBobAfter: bigint;68 let balanceBobFinal: bigint;6970 let balanceBobRelayTokenBefore: bigint;71 let balanceBobRelayTokenAfter: bigint;7273 let usdtCollectionId: number;74 let relayCollectionId: number;7576 before(async () => {77 await usingPlaygrounds(async (helper, privateKey) => {78 alice = await privateKey('//Alice');79 bob = await privateKey('//Bob'); // sovereign account on Statemint funds donor8081 // Set the default version to wrap the first message to other chains.82 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);8384 relayCollectionId = await testHelper.registerRelayNativeTokenOnUnique(alice);85 });8687 await usingRelayPlaygrounds(relayUrl, async (helper) => {88 // Fund accounts on Statemint89 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, alice.addressRaw, FUNDING_AMOUNT);90 await helper.xcm.teleportNativeAsset(alice, STATEMINT_CHAIN, bob.addressRaw, FUNDING_AMOUNT);91 });9293 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {94 const assetInfo = await helper.assets.assetInfo(USDT_ASSET_ID);95 if(assetInfo == null) {96 await helper.assets.create(97 alice,98 USDT_ASSET_ID,99 alice.address,100 USDT_ASSET_METADATA_MINIMAL_BALANCE,101 );102 await helper.assets.setMetadata(103 alice,104 USDT_ASSET_ID,105 USDT_ASSET_METADATA_NAME,106 USDT_ASSET_METADATA_DESCRIPTION,107 USDT_ASSET_METADATA_DECIMALS,108 );109 } else {110 console.log('The USDT asset is already registered on AssetHub');111 }112113 await helper.assets.mint(114 alice,115 USDT_ASSET_ID,116 alice.address,117 USDT_ASSET_AMOUNT,118 );119120 const sovereignFundingAmount = 3_500_000_000n;121122 // funding parachain sovereing account on Statemint.123 // The sovereign account should be created before any action124 // (the assets pallet on Statemint check if the sovereign account exists)125 const parachainSovereingAccount = helper.address.paraSiblingSovereignAccount(UNIQUE_CHAIN);126 await helper.balance.transferToSubstrate(bob, parachainSovereingAccount, sovereignFundingAmount);127 });128129130 await usingPlaygrounds(async (helper) => {131 const location = {132 parents: 1,133 interior: {X3: [134 {135 Parachain: STATEMINT_CHAIN,136 },137 {138 PalletInstance: STATEMINT_PALLET_INSTANCE,139 },140 {141 GeneralIndex: USDT_ASSET_ID,142 },143 ]},144 };145146 if(await helper.foreignAssets.foreignCollectionId(location) == null) {147 const tokenPrefix = USDT_ASSET_METADATA_NAME;148 await helper.getSudo().foreignAssets.register(alice, location, USDT_ASSET_METADATA_NAME, tokenPrefix, {Fungible: USDT_ASSET_METADATA_DECIMALS});149 } else {150 console.log('Foreign collection is already registered on Unique');151 }152153 balanceUniqueBefore = await helper.balance.getSubstrate(alice.address);154 usdtCollectionId = await helper.foreignAssets.foreignCollectionId(location);155 });156157158 // Providing the relay currency to the unique sender account159 // (fee for USDT XCM are paid in relay tokens)160 await usingRelayPlaygrounds(relayUrl, async (helper) => {161 const destination = {162 V2: {163 parents: 0,164 interior: {X1: {165 Parachain: UNIQUE_CHAIN,166 },167 },168 }};169170 const beneficiary = {171 V2: {172 parents: 0,173 interior: {X1: {174 AccountId32: {175 network: 'Any',176 id: alice.addressRaw,177 },178 }},179 },180 };181182 const assets = {183 V2: [184 {185 id: {186 Concrete: {187 parents: 0,188 interior: 'Here',189 },190 },191 fun: {192 Fungible: TRANSFER_AMOUNT_RELAY,193 },194 },195 ],196 };197198 const feeAssetItem = 0;199200 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, 'Unlimited');201 });202203 });204205 itSub('Should connect and send USDT from Statemint to Unique', async ({helper}) => {206 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {207 const dest = {208 V2: {209 parents: 1,210 interior: {X1: {211 Parachain: UNIQUE_CHAIN,212 },213 },214 }};215216 const beneficiary = {217 V2: {218 parents: 0,219 interior: {X1: {220 AccountId32: {221 network: 'Any',222 id: alice.addressRaw,223 },224 }},225 },226 };227228 const assets = {229 V2: [230 {231 id: {232 Concrete: {233 parents: 0,234 interior: {235 X2: [236 {237 PalletInstance: STATEMINT_PALLET_INSTANCE,238 },239 {240 GeneralIndex: USDT_ASSET_ID,241 },242 ]},243 },244 },245 fun: {246 Fungible: TRANSFER_AMOUNT,247 },248 },249 ],250 };251252 const feeAssetItem = 0;253254 balanceStmnBefore = await helper.balance.getSubstrate(alice.address);255 await helper.xcm.limitedReserveTransferAssets(alice, dest, beneficiary, assets, feeAssetItem, 'Unlimited');256257 balanceStmnAfter = await helper.balance.getSubstrate(alice.address);258259 // common good parachain take commission in it native token260 console.log(261 '[Statemint -> Unique] transaction fees on Statemint: %s WND',262 helper.util.bigIntToDecimals(balanceStmnBefore - balanceStmnAfter, STATEMINT_DECIMALS),263 );264 expect(balanceStmnBefore > balanceStmnAfter).to.be.true;265266 });267268269 // ensure that asset has been delivered270 await helper.wait.newBlocks(3);271272 const free = await helper.ft.getBalance(usdtCollectionId, {Substrate: alice.address});273274 balanceUniqueAfter = await helper.balance.getSubstrate(alice.address);275276 console.log(277 '[Statemint -> Unique] transaction fees on Unique: %s USDT',278 helper.util.bigIntToDecimals(TRANSFER_AMOUNT - free, USDT_ASSET_METADATA_DECIMALS),279 );280 console.log(281 '[Statemint -> Unique] transaction fees on Unique: %s UNQ',282 helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueBefore),283 );284 // commission has not paid in USDT token285 expect(free).to.be.equal(TRANSFER_AMOUNT);286 // ... and parachain native token287 expect(balanceUniqueAfter == balanceUniqueBefore).to.be.true;288 });289290 itSub('Should connect and send USDT from Unique to Statemint back', async ({helper}) => {291 const destination = {292 V2: {293 parents: 1,294 interior: {X2: [295 {296 Parachain: STATEMINT_CHAIN,297 },298 {299 AccountId32: {300 network: 'Any',301 id: alice.addressRaw,302 },303 },304 ]},305 },306 };307308 const relayFee = 400_000_000_000_000n;309 const currencies: [any, bigint][] = [310 [311 usdtCollectionId,312 TRANSFER_AMOUNT,313 ],314 [315 relayCollectionId,316 relayFee,317 ],318 ];319320 const feeItem = 1;321322 await helper.xTokens.transferMulticurrencies(alice, currencies, feeItem, destination, 'Unlimited');323324 // the commission has been paid in parachain native token325 balanceUniqueFinal = await helper.balance.getSubstrate(alice.address);326 console.log('[Unique -> Statemint] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(balanceUniqueAfter - balanceUniqueFinal));327 expect(balanceUniqueAfter > balanceUniqueFinal).to.be.true;328329 await usingStatemintPlaygrounds(statemintUrl, async (helper) => {330 await helper.wait.newBlocks(3);331332 // The USDT token never paid fees. Its amount not changed from begin value.333 // Also check that xcm transfer has been succeeded334 expect((await helper.assets.account(USDT_ASSET_ID, alice.address))! == USDT_ASSET_AMOUNT).to.be.true;335 });336 });337338 itSub('Should connect and send Relay token to Unique', async ({helper}) => {339 balanceBobBefore = await helper.balance.getSubstrate(bob.address);340 balanceBobRelayTokenBefore = await helper.ft.getBalance(relayCollectionId, {Substrate: bob.address});341342 await usingRelayPlaygrounds(relayUrl, async (helper) => {343 const destination = {344 V2: {345 parents: 0,346 interior: {X1: {347 Parachain: UNIQUE_CHAIN,348 },349 },350 }};351352 const beneficiary = {353 V2: {354 parents: 0,355 interior: {X1: {356 AccountId32: {357 network: 'Any',358 id: bob.addressRaw,359 },360 }},361 },362 };363364 const assets = {365 V2: [366 {367 id: {368 Concrete: {369 parents: 0,370 interior: 'Here',371 },372 },373 fun: {374 Fungible: TRANSFER_AMOUNT_RELAY,375 },376 },377 ],378 };379380 const feeAssetItem = 0;381382 await helper.xcm.limitedReserveTransferAssets(bob, destination, beneficiary, assets, feeAssetItem, 'Unlimited');383 });384385 await helper.wait.newBlocks(3);386387 balanceBobAfter = await helper.balance.getSubstrate(bob.address);388 balanceBobRelayTokenAfter = await helper.ft.getBalance(relayCollectionId, {Substrate: bob.address});389390 const wndFeeOnUnique = balanceBobRelayTokenAfter - TRANSFER_AMOUNT_RELAY - balanceBobRelayTokenBefore;391 const wndDiffOnUnique = balanceBobRelayTokenAfter - balanceBobRelayTokenBefore;392 console.log(393 '[Relay (Westend) -> Unique] transaction fees: %s UNQ',394 helper.util.bigIntToDecimals(balanceBobAfter - balanceBobBefore),395 );396 console.log(397 '[Relay (Westend) -> Unique] transaction fees: %s WND',398 helper.util.bigIntToDecimals(wndFeeOnUnique, STATEMINT_DECIMALS),399 );400 console.log('[Relay (Westend) -> Unique] actually delivered: %s WND', wndDiffOnUnique);401 expect(wndFeeOnUnique == 0n, 'No incoming WND fees should be taken').to.be.true;402 expect(balanceBobBefore == balanceBobAfter, 'No incoming UNQ fees should be taken').to.be.true;403 });404405 itSub('Should connect and send Relay token back', async ({helper}) => {406 let relayTokenBalanceBefore: bigint;407 let relayTokenBalanceAfter: bigint;408 await usingRelayPlaygrounds(relayUrl, async (helper) => {409 relayTokenBalanceBefore = await helper.balance.getSubstrate(bob.address);410 });411412 const destination = {413 V2: {414 parents: 1,415 interior: {416 X1:{417 AccountId32: {418 network: 'Any',419 id: bob.addressRaw,420 },421 },422 },423 },424 };425426 const currencies: any = [427 [428 relayCollectionId,429 TRANSFER_AMOUNT_RELAY,430 ],431 ];432433 const feeItem = 0;434435 await helper.xTokens.transferMulticurrencies(bob, currencies, feeItem, destination, 'Unlimited');436437 balanceBobFinal = await helper.balance.getSubstrate(bob.address);438 console.log('[Unique -> Relay (Westend)] transaction fees: %s UNQ', helper.util.bigIntToDecimals(balanceBobAfter - balanceBobFinal));439440 await usingRelayPlaygrounds(relayUrl, async (helper) => {441 await helper.wait.newBlocks(10);442 relayTokenBalanceAfter = await helper.balance.getSubstrate(bob.address);443444 const diff = relayTokenBalanceAfter - relayTokenBalanceBefore;445 console.log('[Unique -> Relay (Westend)] actually delivered: %s WND', helper.util.bigIntToDecimals(diff, RELAY_DECIMALS));446 expect(diff > 0, 'Relay tokens was not delivered back').to.be.true;447 });448 });449});450451describeXCM('[XCM] Integration test: Exchanging tokens with Acala', () => {452 let alice: IKeyringPair;453 let randomAccount: IKeyringPair;454455 let balanceUniqueTokenInit: bigint;456 let balanceUniqueTokenMiddle: bigint;457 let balanceUniqueTokenFinal: bigint;458 let balanceAcalaTokenInit: bigint;459 let balanceAcalaTokenMiddle: bigint;460 let balanceAcalaTokenFinal: bigint;461 let balanceUniqueForeignTokenInit: bigint;462 let balanceUniqueForeignTokenMiddle: bigint;463 let balanceUniqueForeignTokenFinal: bigint;464465 // computed by a test transfer from prod Unique to prod Acala.466 // 2 UNQ sent https://unique.subscan.io/xcm_message/polkadot-bad0b68847e2398af25d482e9ee6f9c1f9ec2a48467 // 1.898970000000000000 UNQ received (you can check Acala's chain state in the corresponding block)468 const expectedAcalaIncomeFee = 2000000000000000000n - 1898970000000000000n;469 const acalaEps = 8n * 10n ** 16n;470471 let acalaBackwardTransferAmount: bigint;472473 before(async () => {474 await usingPlaygrounds(async (helper, privateKey) => {475 alice = await privateKey('//Alice');476 [randomAccount] = await helper.arrange.createAccounts([0n], alice);477478 // Set the default version to wrap the first message to other chains.479 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);480 });481482 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {483 const destination = {484 V2: {485 parents: 1,486 interior: {487 X1: {488 Parachain: UNIQUE_CHAIN,489 },490 },491 },492 };493494 const metadata = {495 name: 'Unique Network',496 symbol: 'UNQ',497 decimals: 18,498 minimalBalance: 1250000000000000000n,499 };500 const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>501 hexToString(v.toJSON()['symbol'])) as string[];502503 if(!assets.includes('UNQ')) {504 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);505 } else {506 console.log('UNQ token already registered on Acala assetRegistry pallet');507 }508 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);509 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);510 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});511 });512513 await usingPlaygrounds(async (helper) => {514 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);515 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);516 });517 });518519 itSub('Should connect and send UNQ to Acala', async ({helper}) => {520521 const destination = {522 V2: {523 parents: 1,524 interior: {525 X1: {526 Parachain: ACALA_CHAIN,527 },528 },529 },530 };531532 const beneficiary = {533 V2: {534 parents: 0,535 interior: {536 X1: {537 AccountId32: {538 network: 'Any',539 id: randomAccount.addressRaw,540 },541 },542 },543 },544 };545546 const assets = {547 V2: [548 {549 id: {550 Concrete: {551 parents: 0,552 interior: 'Here',553 },554 },555 fun: {556 Fungible: TRANSFER_AMOUNT,557 },558 },559 ],560 };561562 const feeAssetItem = 0;563564 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');565 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);566567 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;568 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));569 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;570571 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {572 await helper.wait.newBlocks(3);573574 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});575 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);576577 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;578 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;579 acalaBackwardTransferAmount = unqIncomeTransfer;580581 const acaUnqFees = TRANSFER_AMOUNT - unqIncomeTransfer;582583 console.log(584 '[Unique -> Acala] transaction fees on Acala: %s ACA',585 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),586 );587 console.log(588 '[Unique -> Acala] transaction fees on Acala: %s UNQ',589 helper.util.bigIntToDecimals(acaUnqFees),590 );591 console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));592 expect(acaFees == 0n).to.be.true;593594 const bigintAbs = (n: bigint) => (n < 0n) ? -n : n;595596 expect(597 bigintAbs(acaUnqFees - expectedAcalaIncomeFee) < acalaEps,598 'Acala took different income fee, check the Acala foreign asset config',599 ).to.be.true;600 });601 });602603 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {604 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {605 const destination = {606 V2: {607 parents: 1,608 interior: {609 X2: [610 {Parachain: UNIQUE_CHAIN},611 {612 AccountId32: {613 network: 'Any',614 id: randomAccount.addressRaw,615 },616 },617 ],618 },619 },620 };621622 const id = {623 ForeignAsset: 0,624 };625626 await helper.xTokens.transfer(randomAccount, id, acalaBackwardTransferAmount, destination, 'Unlimited');627 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);628 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);629630 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;631 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;632633 console.log(634 '[Acala -> Unique] transaction fees on Acala: %s ACA',635 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),636 );637 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));638639 expect(acaFees > 0, 'Negative fees ACA, looks like nothing was transferred').to.be.true;640 expect(unqOutcomeTransfer == acalaBackwardTransferAmount).to.be.true;641 });642643 await helper.wait.newBlocks(3);644645 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);646 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;647 expect(actuallyDelivered > 0).to.be.true;648649 console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));650651 const unqFees = acalaBackwardTransferAmount - actuallyDelivered;652 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));653 expect(unqFees == 0n).to.be.true;654 });655656 itSub('Acala can send only up to its balance', async ({helper}) => {657 // set Acala's sovereign account's balance658 const acalaBalance = 10000n * (10n ** UNQ_DECIMALS);659 const acalaSovereignAccount = helper.address.paraSiblingSovereignAccount(ACALA_CHAIN);660 await helper.getSudo().balance.setBalanceSubstrate(alice, acalaSovereignAccount, acalaBalance);661662 const moreThanAcalaHas = acalaBalance * 2n;663664 let targetAccountBalance = 0n;665 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);666667 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(668 targetAccount.addressRaw,669 {670 Concrete: {671 parents: 0,672 interior: 'Here',673 },674 },675 moreThanAcalaHas,676 );677678 let maliciousXcmProgramSent: any;679 const maxWaitBlocks = 3;680681 // Try to trick Unique682 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {683 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);684685 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);686 });687688 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash689 && event.outcome.isFailedToTransactAsset);690691 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);692 expect(targetAccountBalance).to.be.equal(0n);693694 // But Acala still can send the correct amount695 const validTransferAmount = acalaBalance / 2n;696 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(697 targetAccount.addressRaw,698 {699 Concrete: {700 parents: 0,701 interior: 'Here',702 },703 },704 validTransferAmount,705 );706707 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {708 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);709 });710711 await helper.wait.newBlocks(maxWaitBlocks);712713 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);714 expect(targetAccountBalance).to.be.equal(validTransferAmount);715 });716717 itSub('Should not accept reserve transfer of UNQ from Acala', async ({helper}) => {718 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);719 const [targetAccount] = await helper.arrange.createAccounts([0n], alice);720721 const uniqueMultilocation = {722 V2: {723 parents: 1,724 interior: {725 X1: {726 Parachain: UNIQUE_CHAIN,727 },728 },729 },730 };731732 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(733 targetAccount.addressRaw,734 uniqueAssetId,735 testAmount,736 );737738 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(739 targetAccount.addressRaw,740 {741 Concrete: {742 parents: 0,743 interior: 'Here',744 },745 },746 testAmount,747 );748749 let maliciousXcmProgramFullIdSent: any;750 let maliciousXcmProgramHereIdSent: any;751 const maxWaitBlocks = 3;752753 // Try to trick Unique using full UNQ identification754 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {755 await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);756757 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);758 });759760 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash761 && event.outcome.isUntrustedReserveLocation);762763 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);764 expect(accountBalance).to.be.equal(0n);765766 // Try to trick Unique using shortened UNQ identification767 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {768 await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);769770 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);771 });772773 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash774 && event.outcome.isUntrustedReserveLocation);775776 accountBalance = await helper.balance.getSubstrate(targetAccount.address);777 expect(accountBalance).to.be.equal(0n);778 });779});780781describeXCM('[XCM] Integration test: Exchanging tokens with Polkadex', () => {782 let alice: IKeyringPair;783 let randomAccount: IKeyringPair;784 let unqFees: bigint;785 let balanceUniqueTokenInit: bigint;786 let balanceUniqueTokenMiddle: bigint;787 let balanceUniqueTokenFinal: bigint;788 const maxWaitBlocks = 6;789790 before(async () => {791 await usingPlaygrounds(async (helper, privateKey) => {792 alice = await privateKey('//Alice');793 [randomAccount] = await helper.arrange.createAccounts([0n], alice);794795 // Set the default version to wrap the first message to other chains.796 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);797 });798799 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {800 const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))801 .toJSON() as [])802 .map(nToBigInt).length != 0;803 /*804 Check whether the Unique token has been added805 to the whitelist, since an error will occur806 if it is added again. Needed for debugging807 when this test is run multiple times.808 */809 if(isWhitelisted) {810 console.log('UNQ token is already whitelisted on Polkadex');811 } else {812 await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);813 }814815 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);816 });817818 await usingPlaygrounds(async (helper) => {819 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);820 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);821 });822 });823824 itSub('Should connect and send UNQ to Polkadex', async ({helper}) => {825826 const destination = {827 V2: {828 parents: 1,829 interior: {830 X1: {831 Parachain: POLKADEX_CHAIN,832 },833 },834 },835 };836837 const beneficiary = {838 V2: {839 parents: 0,840 interior: {841 X1: {842 AccountId32: {843 network: 'Any',844 id: randomAccount.addressRaw,845 },846 },847 },848 },849 };850851 const assets = {852 V2: [853 {854 id: {855 Concrete: {856 parents: 0,857 interior: 'Here',858 },859 },860 fun: {861 Fungible: TRANSFER_AMOUNT,862 },863 },864 ],865 };866867 const feeAssetItem = 0;868869 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');870 const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);871 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);872873 unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;874 console.log('[Unique -> Polkadex] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));875 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;876877 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {878 /*879 Since only the parachain part of the Polkadex880 infrastructure is launched (without their881 solochain validators), processing incoming882 assets will lead to an error.883 This error indicates that the Polkadex chain884 received a message from the Unique network,885 since the hash is being checked to ensure886 it matches what was sent.887 */888 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);889 });890 });891892893 itSub('Should connect to Polkadex and send UNQ back', async ({helper}) => {894895 const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(896 randomAccount.addressRaw,897 uniqueAssetId,898 TRANSFER_AMOUNT,899 );900901 let xcmProgramSent: any;902903904 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {905 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, xcmProgram);906907 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);908 });909910 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);911912 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);913914 expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees);915 });916917 itSub('Polkadex can send only up to its balance', async ({helper}) => {918 const polkadexBalance = 10000n * (10n ** UNQ_DECIMALS);919 const polkadexSovereignAccount = helper.address.paraSiblingSovereignAccount(POLKADEX_CHAIN);920 await helper.getSudo().balance.setBalanceSubstrate(alice, polkadexSovereignAccount, polkadexBalance);921 const moreThanPolkadexHas = 2n * polkadexBalance;922923 const targetAccount = helper.arrange.createEmptyAccount();924925 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(926 targetAccount.addressRaw,927 {928 Concrete: {929 parents: 0,930 interior: 'Here',931 },932 },933 moreThanPolkadexHas,934 );935936 let maliciousXcmProgramSent: any;937938939 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {940 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);941942 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);943 });944945 await expectFailedToTransact(helper, maliciousXcmProgramSent);946947 const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);948 expect(targetAccountBalance).to.be.equal(0n);949 });950951 itSub('Should not accept reserve transfer of UNQ from Polkadex', async ({helper}) => {952 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);953 const targetAccount = helper.arrange.createEmptyAccount();954955 const uniqueMultilocation = {956 V2: {957 parents: 1,958 interior: {959 X1: {960 Parachain: UNIQUE_CHAIN,961 },962 },963 },964 };965966 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(967 targetAccount.addressRaw,968 uniqueAssetId,969 testAmount,970 );971972 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(973 targetAccount.addressRaw,974 {975 Concrete: {976 parents: 0,977 interior: 'Here',978 },979 },980 testAmount,981 );982983 let maliciousXcmProgramFullIdSent: any;984 let maliciousXcmProgramHereIdSent: any;985 const maxWaitBlocks = 3;986987 // Try to trick Unique using full UNQ identification988 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {989 await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramFullId);990991 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);992 });993994 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);995996 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);997 expect(accountBalance).to.be.equal(0n);998999 // Try to trick Unique using shortened UNQ identification1000 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {1001 await helper.getSudo().xcm.send(alice, uniqueMultilocation, maliciousXcmProgramHereId);10021003 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1004 });10051006 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);10071008 accountBalance = await helper.balance.getSubstrate(targetAccount.address);1009 expect(accountBalance).to.be.equal(0n);1010 });1011});10121013// These tests are relevant only when1014// the the corresponding foreign assets are not registered1015describeXCM('[XCM] Integration test: Unique rejects non-native tokens', () => {1016 let alice: IKeyringPair;1017 let alith: IKeyringPair;10181019 const testAmount = 100_000_000_000n;1020 let uniqueParachainJunction;1021 let uniqueAccountJunction;10221023 let uniqueParachainMultilocation: any;1024 let uniqueAccountMultilocation: any;1025 let uniqueCombinedMultilocation: any;1026 let uniqueCombinedMultilocationAcala: any; // TODO remove when Acala goes V210271028 let messageSent: any;10291030 const maxWaitBlocks = 3;10311032 before(async () => {1033 await usingPlaygrounds(async (helper, privateKey) => {1034 alice = await privateKey('//Alice');10351036 uniqueParachainJunction = {Parachain: UNIQUE_CHAIN};1037 uniqueAccountJunction = {1038 AccountId32: {1039 network: 'Any',1040 id: alice.addressRaw,1041 },1042 };10431044 uniqueParachainMultilocation = {1045 V2: {1046 parents: 1,1047 interior: {1048 X1: uniqueParachainJunction,1049 },1050 },1051 };10521053 uniqueAccountMultilocation = {1054 V2: {1055 parents: 0,1056 interior: {1057 X1: uniqueAccountJunction,1058 },1059 },1060 };10611062 uniqueCombinedMultilocation = {1063 V2: {1064 parents: 1,1065 interior: {1066 X2: [uniqueParachainJunction, uniqueAccountJunction],1067 },1068 },1069 };10701071 uniqueCombinedMultilocationAcala = {1072 V2: {1073 parents: 1,1074 interior: {1075 X2: [uniqueParachainJunction, uniqueAccountJunction],1076 },1077 },1078 };10791080 // Set the default version to wrap the first message to other chains.1081 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1082 });10831084 // eslint-disable-next-line require-await1085 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1086 alith = helper.account.alithAccount();1087 });1088 });1089109010911092 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {1093 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {1094 const id = {1095 Token: 'ACA',1096 };1097 const destination = uniqueCombinedMultilocationAcala;1098 await helper.xTokens.transfer(alice, id, testAmount, destination, 'Unlimited');10991100 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1101 });11021103 await expectFailedToTransact(helper, messageSent);1104 });11051106 itSub('Unique rejects GLMR tokens from Moonbeam', async ({helper}) => {1107 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1108 const id = 'SelfReserve';1109 const destination = uniqueCombinedMultilocation;1110 await helper.xTokens.transfer(alith, id, testAmount, destination, 'Unlimited');11111112 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1113 });11141115 await expectFailedToTransact(helper, messageSent);1116 });11171118 itSub('Unique rejects ASTR tokens from Astar', async ({helper}) => {1119 await usingAstarPlaygrounds(astarUrl, async (helper) => {1120 const destinationParachain = uniqueParachainMultilocation;1121 const beneficiary = uniqueAccountMultilocation;1122 const assets = {1123 V2: [{1124 id: {1125 Concrete: {1126 parents: 0,1127 interior: 'Here',1128 },1129 },1130 fun: {1131 Fungible: testAmount,1132 },1133 }],1134 };1135 const feeAssetItem = 0;11361137 await helper.executeExtrinsic(alice, 'api.tx.polkadotXcm.reserveWithdrawAssets', [1138 destinationParachain,1139 beneficiary,1140 assets,1141 feeAssetItem,1142 ]);11431144 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1145 });11461147 await expectFailedToTransact(helper, messageSent);1148 });11491150 itSub('Unique rejects PDX tokens from Polkadex', async ({helper}) => {11511152 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1153 helper.arrange.createEmptyAccount().addressRaw,1154 {1155 Concrete: {1156 parents: 1,1157 interior: {1158 X1: {1159 Parachain: POLKADEX_CHAIN,1160 },1161 },1162 },1163 },1164 testAmount,1165 );11661167 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {1168 await helper.getSudo().xcm.send(alice, uniqueParachainMultilocation, maliciousXcmProgramFullId);1169 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1170 });11711172 await expectFailedToTransact(helper, messageSent);1173 });1174});11751176describeXCM('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {1177 // Unique constants1178 let alice: IKeyringPair;1179 let uniqueAssetLocation;11801181 let randomAccountUnique: IKeyringPair;1182 let randomAccountMoonbeam: IKeyringPair;11831184 // Moonbeam constants1185 let assetId: string;11861187 const uniqueAssetMetadata = {1188 name: 'xcUnique',1189 symbol: 'xcUNQ',1190 decimals: 18,1191 isFrozen: false,1192 minimalBalance: 1n,1193 };11941195 let balanceUniqueTokenInit: bigint;1196 let balanceUniqueTokenMiddle: bigint;1197 let balanceUniqueTokenFinal: bigint;1198 let balanceForeignUnqTokenInit: bigint;1199 let balanceForeignUnqTokenMiddle: bigint;1200 let balanceForeignUnqTokenFinal: bigint;1201 let balanceGlmrTokenInit: bigint;1202 let balanceGlmrTokenMiddle: bigint;1203 let balanceGlmrTokenFinal: bigint;12041205 before(async () => {1206 await usingPlaygrounds(async (helper, privateKey) => {1207 alice = await privateKey('//Alice');1208 [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);12091210 balanceForeignUnqTokenInit = 0n;12111212 // Set the default version to wrap the first message to other chains.1213 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1214 });12151216 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1217 const alithAccount = helper.account.alithAccount();1218 const baltatharAccount = helper.account.baltatharAccount();1219 const dorothyAccount = helper.account.dorothyAccount();12201221 randomAccountMoonbeam = helper.account.create();12221223 // >>> Sponsoring Dorothy >>>1224 console.log('Sponsoring Dorothy.......');1225 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);1226 console.log('Sponsoring Dorothy.......DONE');1227 // <<< Sponsoring Dorothy <<<12281229 uniqueAssetLocation = {1230 XCM: {1231 parents: 1,1232 interior: {X1: {Parachain: UNIQUE_CHAIN}},1233 },1234 };1235 const existentialDeposit = 1n;1236 const isSufficient = true;1237 const unitsPerSecond = 1n;1238 const numAssetsWeightHint = 0;12391240 if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {1241 console.log('Unique asset is already registered on MoonBeam');1242 } else {1243 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({1244 location: uniqueAssetLocation,1245 metadata: uniqueAssetMetadata,1246 existentialDeposit,1247 isSufficient,1248 unitsPerSecond,1249 numAssetsWeightHint,1250 });12511252 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);12531254 await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);1255 }12561257 // >>> Acquire Unique AssetId Info on Moonbeam >>>1258 console.log('Acquire Unique AssetId Info on Moonbeam.......');12591260 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();1261 console.log('UNQ asset ID is %s', assetId);1262 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');1263 // >>> Acquire Unique AssetId Info on Moonbeam >>>12641265 // >>> Sponsoring random Account >>>1266 console.log('Sponsoring random Account.......');1267 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);1268 console.log('Sponsoring random Account.......DONE');1269 // <<< Sponsoring random Account <<<12701271 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);1272 });12731274 await usingPlaygrounds(async (helper) => {1275 await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);1276 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);1277 });1278 });12791280 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {1281 const currencyId = {1282 NativeAssetId: 'Here',1283 };1284 const dest = {1285 V2: {1286 parents: 1,1287 interior: {1288 X2: [1289 {Parachain: MOONBEAM_CHAIN},1290 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},1291 ],1292 },1293 },1294 };1295 const amount = TRANSFER_AMOUNT;12961297 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, 'Unlimited');12981299 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);1300 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;13011302 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;1303 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));1304 expect(transactionFees > 0, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;13051306 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1307 await helper.wait.newBlocks(3);1308 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);13091310 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;1311 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));1312 expect(glmrFees == 0n).to.be.true;13131314 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;13151316 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;1317 console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));1318 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;1319 });1320 });13211322 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {1323 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1324 const asset = {1325 V2: {1326 id: {1327 Concrete: {1328 parents: 1,1329 interior: {1330 X1: {Parachain: UNIQUE_CHAIN},1331 },1332 },1333 },1334 fun: {1335 Fungible: TRANSFER_AMOUNT,1336 },1337 },1338 };1339 const destination = {1340 V2: {1341 parents: 1,1342 interior: {1343 X2: [1344 {Parachain: UNIQUE_CHAIN},1345 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},1346 ],1347 },1348 },1349 };13501351 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, 'Unlimited');13521353 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);13541355 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;1356 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));1357 expect(glmrFees > 0, 'Negative fees GLMR, looks like nothing was transferred').to.be.true;13581359 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);13601361 expect(unqRandomAccountAsset).to.be.null;13621363 balanceForeignUnqTokenFinal = 0n;13641365 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;1366 console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));1367 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;1368 });13691370 await helper.wait.newBlocks(3);13711372 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);1373 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;1374 expect(actuallyDelivered > 0).to.be.true;13751376 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));13771378 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;1379 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));1380 expect(unqFees == 0n).to.be.true;1381 });13821383 itSub('Moonbeam can send only up to its balance', async ({helper}) => {1384 // set Moonbeam's sovereign account's balance1385 const moonbeamBalance = 10000n * (10n ** UNQ_DECIMALS);1386 const moonbeamSovereignAccount = helper.address.paraSiblingSovereignAccount(MOONBEAM_CHAIN);1387 await helper.getSudo().balance.setBalanceSubstrate(alice, moonbeamSovereignAccount, moonbeamBalance);13881389 const moreThanMoonbeamHas = moonbeamBalance * 2n;13901391 let targetAccountBalance = 0n;1392 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);13931394 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1395 targetAccount.addressRaw,1396 {1397 Concrete: {1398 parents: 0,1399 interior: 'Here',1400 },1401 },1402 moreThanMoonbeamHas,1403 );14041405 let maliciousXcmProgramSent: any;1406 const maxWaitBlocks = 3;14071408 // Try to trick Unique1409 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1410 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);14111412 // Needed to bypass the call filter.1413 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1414 await helper.fastDemocracy.executeProposal('try to spend more UNQ than Moonbeam has', batchCall);14151416 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1417 });14181419 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash1420 && event.outcome.isFailedToTransactAsset);14211422 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1423 expect(targetAccountBalance).to.be.equal(0n);14241425 // But Moonbeam still can send the correct amount1426 const validTransferAmount = moonbeamBalance / 2n;1427 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1428 targetAccount.addressRaw,1429 {1430 Concrete: {1431 parents: 0,1432 interior: 'Here',1433 },1434 },1435 validTransferAmount,1436 );14371438 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1439 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, validXcmProgram]);14401441 // Needed to bypass the call filter.1442 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1443 await helper.fastDemocracy.executeProposal('Spend the correct amount of UNQ', batchCall);1444 });14451446 await helper.wait.newBlocks(maxWaitBlocks);14471448 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1449 expect(targetAccountBalance).to.be.equal(validTransferAmount);1450 });14511452 itSub('Should not accept reserve transfer of UNQ from Moonbeam', async ({helper}) => {1453 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);1454 const [targetAccount] = await helper.arrange.createAccounts([0n], alice);14551456 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1457 targetAccount.addressRaw,1458 uniqueAssetId,1459 testAmount,1460 );14611462 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(1463 targetAccount.addressRaw,1464 {1465 Concrete: {1466 parents: 0,1467 interior: 'Here',1468 },1469 },1470 testAmount,1471 );14721473 let maliciousXcmProgramFullIdSent: any;1474 let maliciousXcmProgramHereIdSent: any;1475 const maxWaitBlocks = 3;14761477 // Try to trick Unique using full UNQ identification1478 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1479 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);14801481 // Needed to bypass the call filter.1482 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1483 await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using path asset identification', batchCall);14841485 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1486 });14871488 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash1489 && event.outcome.isUntrustedReserveLocation);14901491 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1492 expect(accountBalance).to.be.equal(0n);14931494 // Try to trick Unique using shortened UNQ identification1495 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {1496 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);14971498 // Needed to bypass the call filter.1499 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);1500 await helper.fastDemocracy.executeProposal('try to act like a reserve location for UNQ using "here" asset identification', batchCall);15011502 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1503 });15041505 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash1506 && event.outcome.isUntrustedReserveLocation);15071508 accountBalance = await helper.balance.getSubstrate(targetAccount.address);1509 expect(accountBalance).to.be.equal(0n);1510 });1511});15121513describeXCM('[XCM] Integration test: Exchanging tokens with Astar', () => {1514 let alice: IKeyringPair;1515 let randomAccount: IKeyringPair;15161517 const UNQ_ASSET_ID_ON_ASTAR = 18_446_744_073_709_551_631n; // The value is taken from the live Astar1518 const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n; // The value is taken from the live Astar15191520 // Unique -> Astar1521 const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.1522 const unitsPerSecond = 9_451_000_000_000_000_000n; // The value is taken from the live Astar1523 const unqToAstarTransferred = 10n * (10n ** UNQ_DECIMALS); // 10 UNQ1524 const unqToAstarArrived = 9_962_196_000_000_000_000n; // 9.962 ... UNQ, Astar takes a commision in foreign tokens15251526 // Astar -> Unique1527 const unqFromAstarTransfered = 5n * (10n ** UNQ_DECIMALS); // 5 UNQ1528 const unqOnAstarLeft = unqToAstarArrived - unqFromAstarTransfered; // 4.962_219_600_000_000_000n UNQ15291530 let balanceAfterUniqueToAstarXCM: bigint;15311532 before(async () => {1533 await usingPlaygrounds(async (helper, privateKey) => {1534 alice = await privateKey('//Alice');1535 [randomAccount] = await helper.arrange.createAccounts([100n], alice);1536 console.log('randomAccount', randomAccount.address);15371538 // Set the default version to wrap the first message to other chains.1539 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);1540 });15411542 await usingAstarPlaygrounds(astarUrl, async (helper) => {1543 if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {1544 console.log('1. Create foreign asset and metadata');1545 await helper.getSudo().assets.forceCreate(1546 alice,1547 UNQ_ASSET_ID_ON_ASTAR,1548 alice.address,1549 UNQ_MINIMAL_BALANCE_ON_ASTAR,1550 );15511552 await helper.assets.setMetadata(1553 alice,1554 UNQ_ASSET_ID_ON_ASTAR,1555 'Unique Network',1556 'UNQ',1557 Number(UNQ_DECIMALS),1558 );15591560 console.log('2. Register asset location on Astar');1561 const assetLocation = {1562 V2: {1563 parents: 1,1564 interior: {1565 X1: {1566 Parachain: UNIQUE_CHAIN,1567 },1568 },1569 },1570 };15711572 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);15731574 console.log('3. Set UNQ payment for XCM execution on Astar');1575 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);1576 } else {1577 console.log('UNQ is already registered on Astar');1578 }1579 console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');1580 await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);1581 });1582 });15831584 itSub('Should connect and send UNQ to Astar', async ({helper}) => {1585 const destination = {1586 V2: {1587 parents: 1,1588 interior: {1589 X1: {1590 Parachain: ASTAR_CHAIN,1591 },1592 },1593 },1594 };15951596 const beneficiary = {1597 V2: {1598 parents: 0,1599 interior: {1600 X1: {1601 AccountId32: {1602 network: 'Any',1603 id: randomAccount.addressRaw,1604 },1605 },1606 },1607 },1608 };16091610 const assets = {1611 V2: [1612 {1613 id: {1614 Concrete: {1615 parents: 0,1616 interior: 'Here',1617 },1618 },1619 fun: {1620 Fungible: unqToAstarTransferred,1621 },1622 },1623 ],1624 };16251626 // Initial balance is 100 UNQ1627 const balanceBefore = await helper.balance.getSubstrate(randomAccount.address);1628 console.log(`Initial balance is: ${balanceBefore}`);16291630 const feeAssetItem = 0;1631 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');16321633 // Balance after reserve transfer is less than 901634 balanceAfterUniqueToAstarXCM = await helper.balance.getSubstrate(randomAccount.address);1635 console.log(`UNQ Balance on Unique after XCM is: ${balanceAfterUniqueToAstarXCM}`);1636 console.log(`Unique's UNQ commission is: ${balanceBefore-balanceAfterUniqueToAstarXCM}`);1637 expect(balanceBefore - balanceAfterUniqueToAstarXCM > 0).to.be.true;16381639 await usingAstarPlaygrounds(astarUrl, async (helper) => {1640 await helper.wait.newBlocks(3);1641 const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);1642 const astarBalance = await helper.balance.getSubstrate(randomAccount.address);16431644 console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);1645 console.log(`Astar's UNQ commission is: ${unqToAstarTransferred-xcUNQbalance!}`);16461647 expect(xcUNQbalance).to.eq(unqToAstarArrived);1648 // Astar balance does not changed1649 expect(astarBalance).to.eq(astarInitialBalance);1650 });1651 });16521653 itSub('Should connect to Astar and send UNQ back', async ({helper}) => {1654 await usingAstarPlaygrounds(astarUrl, async (helper) => {1655 const destination = {1656 V2: {1657 parents: 1,1658 interior: {1659 X1: {1660 Parachain: UNIQUE_CHAIN,1661 },1662 },1663 },1664 };16651666 const beneficiary = {1667 V2: {1668 parents: 0,1669 interior: {1670 X1: {1671 AccountId32: {1672 network: 'Any',1673 id: randomAccount.addressRaw,1674 },1675 },1676 },1677 },1678 };16791680 const assets = {1681 V2: [1682 {1683 id: {1684 Concrete: {1685 parents: 1,1686 interior: {1687 X1: {1688 Parachain: UNIQUE_CHAIN,1689 },1690 },1691 },1692 },1693 fun: {1694 Fungible: unqFromAstarTransfered,1695 },1696 },1697 ],1698 };16991700 // Initial balance is 1 ASTR1701 const balanceASTRbefore = await helper.balance.getSubstrate(randomAccount.address);1702 console.log(`ASTR balance is: ${balanceASTRbefore}, it does not changed`);1703 expect(balanceASTRbefore).to.eq(astarInitialBalance);17041705 const feeAssetItem = 0;1706 // this is non-standard polkadotXcm extension for Astar only. It calls InitiateReserveWithdraw1707 await helper.executeExtrinsic(randomAccount, 'api.tx.polkadotXcm.reserveWithdrawAssets', [destination, beneficiary, assets, feeAssetItem]);17081709 const xcUNQbalance = await helper.assets.account(UNQ_ASSET_ID_ON_ASTAR, randomAccount.address);1710 const balanceAstar = await helper.balance.getSubstrate(randomAccount.address);1711 console.log(`xcUNQ balance on Astar after XCM is: ${xcUNQbalance}`);17121713 // Assert: xcUNQ balance correctly decreased1714 expect(xcUNQbalance).to.eq(unqOnAstarLeft);1715 // Assert: ASTR balance is 0.996...1716 expect(balanceAstar / (10n ** (ASTAR_DECIMALS - 3n))).to.eq(996n);1717 });17181719 await helper.wait.newBlocks(3);1720 const balanceUNQ = await helper.balance.getSubstrate(randomAccount.address);1721 console.log(`UNQ Balance on Unique after XCM is: ${balanceUNQ}`);1722 expect(balanceUNQ).to.eq(balanceAfterUniqueToAstarXCM + unqFromAstarTransfered);1723 });17241725 itSub('Astar can send only up to its balance', async ({helper}) => {1726 // set Astar's sovereign account's balance1727 const astarBalance = 10000n * (10n ** UNQ_DECIMALS);1728 const astarSovereignAccount = helper.address.paraSiblingSovereignAccount(ASTAR_CHAIN);1729 await helper.getSudo().balance.setBalanceSubstrate(alice, astarSovereignAccount, astarBalance);17301731 const moreThanAstarHas = astarBalance * 2n;17321733 let targetAccountBalance = 0n;1734 const [targetAccount] = await helper.arrange.createAccounts([targetAccountBalance], alice);17351736 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1737 targetAccount.addressRaw,1738 {1739 Concrete: {1740 parents: 0,1741 interior: 'Here',1742 },1743 },1744 moreThanAstarHas,1745 );17461747 let maliciousXcmProgramSent: any;1748 const maxWaitBlocks = 3;17491750 // Try to trick Unique1751 await usingAstarPlaygrounds(astarUrl, async (helper) => {1752 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgram);17531754 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1755 });17561757 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramSent.messageHash1758 && event.outcome.isFailedToTransactAsset);17591760 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1761 expect(targetAccountBalance).to.be.equal(0n);17621763 // But Astar still can send the correct amount1764 const validTransferAmount = astarBalance / 2n;1765 const validXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(1766 targetAccount.addressRaw,1767 {1768 Concrete: {1769 parents: 0,1770 interior: 'Here',1771 },1772 },1773 validTransferAmount,1774 );17751776 await usingAstarPlaygrounds(astarUrl, async (helper) => {1777 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, validXcmProgram);1778 });17791780 await helper.wait.newBlocks(maxWaitBlocks);17811782 targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);1783 expect(targetAccountBalance).to.be.equal(validTransferAmount);1784 });17851786 itSub('Should not accept reserve transfer of UNQ from Astar', async ({helper}) => {1787 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);1788 const [targetAccount] = await helper.arrange.createAccounts([0n], alice);17891790 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(1791 targetAccount.addressRaw,1792 uniqueAssetId,1793 testAmount,1794 );17951796 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(1797 targetAccount.addressRaw,1798 {1799 Concrete: {1800 parents: 0,1801 interior: 'Here',1802 },1803 },1804 testAmount,1805 );18061807 let maliciousXcmProgramFullIdSent: any;1808 let maliciousXcmProgramHereIdSent: any;1809 const maxWaitBlocks = 3;18101811 // Try to trick Unique using full UNQ identification1812 await usingAstarPlaygrounds(astarUrl, async (helper) => {1813 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramFullId);18141815 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1816 });18171818 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramFullIdSent.messageHash1819 && event.outcome.isUntrustedReserveLocation);18201821 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);1822 expect(accountBalance).to.be.equal(0n);18231824 // Try to trick Unique using shortened UNQ identification1825 await usingAstarPlaygrounds(astarUrl, async (helper) => {1826 await helper.getSudo().xcm.send(alice, uniqueVersionedMultilocation, maliciousXcmProgramHereId);18271828 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);1829 });18301831 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == maliciousXcmProgramHereIdSent.messageHash1832 && event.outcome.isUntrustedReserveLocation);18331834 accountBalance = await helper.balance.getSubstrate(targetAccount.address);1835 expect(accountBalance).to.be.equal(0n);1836 });1837});