difftreelog
test(xcmUnique) switch to `uniqueAssetId` , typo
in: master
2 files changed
tests/src/xcm/lowLevelXcmUnique.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 {IKeyringPair} from '@polkadot/types/types';18import config from '../config';19import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util';20import {Event} from '../util/playgrounds/unique.dev';21import {nToBigInt} from '@polkadot/util';22import {hexToString} from '@polkadot/util';23import {ASTAR_DECIMALS, NETWORKS, SAFE_XCM_VERSION, UNIQUE_CHAIN, UNQ_DECIMALS, acalaUrl, astarUrl, expectFailedToTransact, expectUntrustedReserveLocationFail, getDevPlayground, mapToChainId, mapToChainUrl, maxWaitBlocks, moonbeamUrl, polkadexUrl, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types';242526const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;27const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;28const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;29const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;30const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;3132let balanceUniqueTokenInit: bigint;33let balanceUniqueTokenMiddle: bigint;34let balanceUniqueTokenFinal: bigint;35let unqFees: bigint;363738async function genericSendUnqTo(39 networkName: keyof typeof NETWORKS,40 randomAccount: IKeyringPair,41 randomAccountOnTargetChain = randomAccount,42) {43 const networkUrl = mapToChainUrl(networkName);44 const targetPlayground = getDevPlayground(networkName);45 await usingPlaygrounds(async (helper) => {46 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);47 const destination = {48 V2: {49 parents: 1,50 interior: {51 X1: {52 Parachain: mapToChainId(networkName),53 },54 },55 },56 };5758 const beneficiary = {59 V2: {60 parents: 0,61 interior: {62 X1: (63 networkName == 'moonbeam' ?64 {65 AccountKey20: {66 network: 'Any',67 key: randomAccountOnTargetChain.address,68 },69 }70 :71 {72 AccountId32: {73 network: 'Any',74 id: randomAccountOnTargetChain.addressRaw,75 },76 }77 ),78 },79 },80 };8182 const assets = {83 V2: [84 {85 id: {86 Concrete: {87 parents: 0,88 interior: 'Here',89 },90 },91 fun: {92 Fungible: TRANSFER_AMOUNT,93 },94 },95 ],96 };97 const feeAssetItem = 0;9899 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');100 const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);101 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);102103 unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;104 console.log('[Unique -> %s] transaction fees on Unique: %s UNQ', networkName, helper.util.bigIntToDecimals(unqFees));105 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;106107 await targetPlayground(networkUrl, async (helper) => {108 /*109 Since only the parachain part of the Polkadex110 infrastructure is launched (without their111 solochain validators), processing incoming112 assets will lead to an error.113 This error indicates that the Polkadex chain114 received a message from the Unique network,115 since the hash is being checked to ensure116 it matches what was sent.117 */118 if(networkName == 'polkadex') {119 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);120 } else {121 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);122 }123 });124125 });126}127128async function genericSendUnqBack(129 networkName: keyof typeof NETWORKS,130 sudoer: IKeyringPair,131 randomAccountOnUnq: IKeyringPair,132) {133 const networkUrl = mapToChainUrl(networkName);134135 const targetPlayground = getDevPlayground(networkName);136 await usingPlaygrounds(async (helper) => {137138 const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(139 randomAccountOnUnq.addressRaw,140 {141 Concrete: {142 parents: 1,143 interior: {144 X1: {Parachain: UNIQUE_CHAIN},145 },146 },147 },148 SENDBACK_AMOUNT,149 );150151 let xcmProgramSent: any;152153154 await targetPlayground(networkUrl, async (helper) => {155 if('getSudo' in helper) {156 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, xcmProgram);157 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);158 } else if('fastDemocracy' in helper) {159 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, xcmProgram]);160 // Needed to bypass the call filter.161 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);162 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);163 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);164 }165 });166167 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);168169 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);170171 expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees - STAYED_ON_TARGET_CHAIN);172173 });174}175176async function genericSendOnlyOwnedBalance(177 networkName: keyof typeof NETWORKS,178 sudoer: IKeyringPair,179) {180 const networkUrl = mapToChainUrl(networkName);181 const targetPlayground = getDevPlayground(networkName);182183 const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);184185 await usingPlaygrounds(async (helper) => {186 const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));187 await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);188 const moreThanTargetChainHas = 2n * targetChainBalance;189190 const targetAccount = helper.arrange.createEmptyAccount();191192 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(193 targetAccount.addressRaw,194 {195 Concrete: {196 parents: 0,197 interior: 'Here',198 },199 },200 moreThanTargetChainHas,201 );202203 let maliciousXcmProgramSent: any;204205206 await targetPlayground(networkUrl, async (helper) => {207 if('getSudo' in helper) {208 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgram);209 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);210 } else if('fastDemocracy' in helper) {211 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);212 // Needed to bypass the call filter.213 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);214 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);215 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);216 }217 });218219 await expectFailedToTransact(helper, maliciousXcmProgramSent);220221 const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);222 expect(targetAccountBalance).to.be.equal(0n);223 });224}225226async function genericReserveTransferUNQfrom(netwokrName: keyof typeof NETWORKS, sudoer: IKeyringPair) {227 const networkUrl = mapToChainUrl(netwokrName);228 const targetPlayground = getDevPlayground(netwokrName);229230 await usingPlaygrounds(async (helper) => {231 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);232 const targetAccount = helper.arrange.createEmptyAccount();233234 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(235 targetAccount.addressRaw,236 {237 Concrete: {238 parents: 1,239 interior: {240 X1: {241 Parachain: UNIQUE_CHAIN,242 },243 },244 },245 },246 testAmount,247 );248249 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(250 targetAccount.addressRaw,251 {252 Concrete: {253 parents: 0,254 interior: 'Here',255 },256 },257 testAmount,258 );259260 let maliciousXcmProgramFullIdSent: any;261 let maliciousXcmProgramHereIdSent: any;262 const maxWaitBlocks = 3;263264 // Try to trick Unique using full UNQ identification265 await targetPlayground(networkUrl, async (helper) => {266 if('getSudo' in helper) {267 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramFullId);268 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);269 }270 // Moonbeam case271 else if('fastDemocracy' in helper) {272 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);273 // Needed to bypass the call filter.274 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);275 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using path asset identification`,batchCall);276277 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);278 }279 });280281282 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);283284 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);285 expect(accountBalance).to.be.equal(0n);286287 // Try to trick Unique using shortened UNQ identification288 await targetPlayground(networkUrl, async (helper) => {289 if('getSudo' in helper) {290 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramHereId);291 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);292 }293 else if('fastDemocracy' in helper) {294 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);295 // Needed to bypass the call filter.296 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);297 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);298299 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);300 }301 });302303 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);304305 accountBalance = await helper.balance.getSubstrate(targetAccount.address);306 expect(accountBalance).to.be.equal(0n);307 });308}309310async function genericRejectNativeToknsFrom(netwokrName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {311 const networkUrl = mapToChainUrl(netwokrName);312 const targetPlayground = getDevPlayground(netwokrName);313 let messageSent: any;314315 await usingPlaygrounds(async (helper) => {316 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(317 helper.arrange.createEmptyAccount().addressRaw,318 {319 Concrete: {320 parents: 1,321 interior: {322 X1: {323 Parachain: mapToChainId(netwokrName),324 },325 },326 },327 },328 TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,329 );330 await targetPlayground(networkUrl, async (helper) => {331 if('getSudo' in helper) {332 await helper.getSudo().xcm.send(sudoerOnTargetChain, uniqueVersionedMultilocation, maliciousXcmProgramFullId);333 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);334 } else if('fastDemocracy' in helper) {335 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);336 // Needed to bypass the call filter.337 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);338 await helper.fastDemocracy.executeProposal(`${netwokrName} sending native tokens to the Unique via fast democracy`, batchCall);339340 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);341 }342 });343 await expectFailedToTransact(helper, messageSent);344 });345}346347348describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {349 let alice: IKeyringPair;350 let randomAccount: IKeyringPair;351352 before(async () => {353 await usingPlaygrounds(async (helper, privateKey) => {354 alice = await privateKey('//Alice');355 console.log(config.acalaUrl);356 randomAccount = helper.arrange.createEmptyAccount();357358 // Set the default version to wrap the first message to other chains.359 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);360 });361362 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {363 const destination = {364 V2: {365 parents: 1,366 interior: {367 X1: {368 Parachain: UNIQUE_CHAIN,369 },370 },371 },372 };373374 const metadata = {375 name: 'Unique Network',376 symbol: 'UNQ',377 decimals: 18,378 minimalBalance: 1250_000_000_000_000_000n,379 };380 const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>381 hexToString(v.toJSON()['symbol'])) as string[];382383 if(!assets.includes('UNQ')) {384 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);385 } else {386 console.log('UNQ token already registered on Acala assetRegistry pallet');387 }388 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);389 });390391 await usingPlaygrounds(async (helper) => {392 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);393 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);394 });395 });396397 itSub('Should connect and send UNQ to Acala', async () => {398 await genericSendUnqTo('acala', randomAccount);399 });400401 itSub('Should connect to Acala and send UNQ back', async () => {402 await genericSendUnqBack('acala', alice, randomAccount);403 });404405 itSub('Acala can send only up to its balance', async () => {406 await genericSendOnlyOwnedBalance('acala', alice);407 });408409 itSub('Should not accept reserve transfer of UNQ from Acala', async () => {410 await genericReserveTransferUNQfrom('acala', alice);411 });412});413414describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {415 let alice: IKeyringPair;416 let randomAccount: IKeyringPair;417418 before(async () => {419 await usingPlaygrounds(async (helper, privateKey) => {420 alice = await privateKey('//Alice');421 randomAccount = helper.arrange.createEmptyAccount();422423 // Set the default version to wrap the first message to other chains.424 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);425 });426427 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {428 const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))429 .toJSON() as [])430 .map(nToBigInt).length != 0;431 /*432 Check whether the Unique token has been added433 to the whitelist, since an error will occur434 if it is added again. Needed for debugging435 when this test is run multiple times.436 */437 if(isWhitelisted) {438 console.log('UNQ token is already whitelisted on Polkadex');439 } else {440 await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);441 }442443 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);444 });445446 await usingPlaygrounds(async (helper) => {447 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);448 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);449 });450 });451452 itSub('Should connect and send UNQ to Polkadex', async () => {453 await genericSendUnqTo('polkadex', randomAccount);454 });455456457 itSub('Should connect to Polkadex and send UNQ back', async () => {458 await genericSendUnqBack('polkadex', alice, randomAccount);459 });460461 itSub('Polkadex can send only up to its balance', async () => {462 await genericSendOnlyOwnedBalance('polkadex', alice);463 });464465 itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {466 await genericReserveTransferUNQfrom('polkadex', alice);467 });468});469470// These tests are relevant only when471// the the corresponding foreign assets are not registered472describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {473 let alice: IKeyringPair;474475 before(async () => {476 await usingPlaygrounds(async (helper, privateKey) => {477 alice = await privateKey('//Alice');478479 // Set the default version to wrap the first message to other chains.480 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);481 });482 });483484 itSub('Unique rejects ACA tokens from Acala', async () => {485 await genericRejectNativeToknsFrom('acala', alice);486 });487488 itSub('Unique rejects GLMR tokens from Moonbeam', async () => {489 await genericRejectNativeToknsFrom('moonbeam', alice);490 });491492 itSub('Unique rejects ASTR tokens from Astar', async () => {493 await genericRejectNativeToknsFrom('astar', alice);494 });495496 itSub('Unique rejects PDX tokens from Polkadex', async () => {497 await genericRejectNativeToknsFrom('polkadex', alice);498 });499});500501describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {502 // Unique constants503 let alice: IKeyringPair;504 let uniqueAssetLocation;505506 let randomAccountUnique: IKeyringPair;507 let randomAccountMoonbeam: IKeyringPair;508509 // Moonbeam constants510 let assetId: string;511512 const uniqueAssetMetadata = {513 name: 'xcUnique',514 symbol: 'xcUNQ',515 decimals: 18,516 isFrozen: false,517 minimalBalance: 1n,518 };519520521 before(async () => {522 await usingPlaygrounds(async (helper, privateKey) => {523 alice = await privateKey('//Alice');524 [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);525526527 // Set the default version to wrap the first message to other chains.528 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);529 });530531 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {532 const alithAccount = helper.account.alithAccount();533 const baltatharAccount = helper.account.baltatharAccount();534 const dorothyAccount = helper.account.dorothyAccount();535536 randomAccountMoonbeam = helper.account.create();537538 // >>> Sponsoring Dorothy >>>539 console.log('Sponsoring Dorothy.......');540 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);541 console.log('Sponsoring Dorothy.......DONE');542 // <<< Sponsoring Dorothy <<<543 uniqueAssetLocation = {544 XCM: {545 parents: 1,546 interior: {X1: {Parachain: UNIQUE_CHAIN}},547 },548 };549 const existentialDeposit = 1n;550 const isSufficient = true;551 const unitsPerSecond = 1n;552 const numAssetsWeightHint = 0;553554 if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {555 console.log('Unique asset already registered on Moonbeam');556 } else {557 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({558 location: uniqueAssetLocation,559 metadata: uniqueAssetMetadata,560 existentialDeposit,561 isSufficient,562 unitsPerSecond,563 numAssetsWeightHint,564 });565566 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);567568 await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);569 }570571 // >>> Acquire Unique AssetId Info on Moonbeam >>>572 console.log('Acquire Unique AssetId Info on Moonbeam.......');573574 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();575576 console.log('UNQ asset ID is %s', assetId);577 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');578579 // >>> Sponsoring random Account >>>580 console.log('Sponsoring random Account.......');581 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);582 console.log('Sponsoring random Account.......DONE');583 // <<< Sponsoring random Account <<<584 });585586 await usingPlaygrounds(async (helper) => {587 await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);588 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);589 });590 });591592 itSub('Should connect and send UNQ to Moonbeam', async () => {593 await genericSendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);594 });595596 itSub('Should connect to Moonbeam and send UNQ back', async () => {597 await genericSendUnqBack('moonbeam', alice, randomAccountUnique);598 });599600 itSub('Moonbeam can send only up to its balance', async () => {601 await genericSendOnlyOwnedBalance('moonbeam', alice);602 });603604 itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {605 await genericReserveTransferUNQfrom('moonbeam', alice);606 });607});608609describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {610 let alice: IKeyringPair;611 let randomAccount: IKeyringPair;612613 const UNQ_ASSET_ID_ON_ASTAR = 1;614 const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n;615616 // Unique -> Astar617 const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.618 const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours?619620 before(async () => {621 await usingPlaygrounds(async (helper, privateKey) => {622 alice = await privateKey('//Alice');623 randomAccount = helper.arrange.createEmptyAccount();624 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);625 console.log('randomAccount', randomAccount.address);626627 // Set the default version to wrap the first message to other chains.628 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);629 });630631 await usingAstarPlaygrounds(astarUrl, async (helper) => {632 if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {633 console.log('1. Create foreign asset and metadata');634 // TODO update metadata with values from production635 await helper.assets.create(636 alice,637 UNQ_ASSET_ID_ON_ASTAR,638 alice.address,639 UNQ_MINIMAL_BALANCE_ON_ASTAR,640 );641642 await helper.assets.setMetadata(643 alice,644 UNQ_ASSET_ID_ON_ASTAR,645 'Cross chain UNQ',646 'xcUNQ',647 Number(UNQ_DECIMALS),648 );649650 console.log('2. Register asset location on Astar');651 const assetLocation = {652 V2: {653 parents: 1,654 interior: {655 X1: {656 Parachain: UNIQUE_CHAIN,657 },658 },659 },660 };661662 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);663664 console.log('3. Set UNQ payment for XCM execution on Astar');665 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);666 } else {667 console.log('UNQ is already registered on Astar');668 }669 console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');670 await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);671 });672 });673674 itSub('Should connect and send UNQ to Astar', async () => {675 await genericSendUnqTo('astar', randomAccount);676 });677678 itSub('Should connect to Astar and send UNQ back', async () => {679 await genericSendUnqBack('astar', alice, randomAccount);680 });681682 itSub('Astar can send only up to its balance', async () => {683 await genericSendOnlyOwnedBalance('astar', alice);684 });685686 itSub('Should not accept reserve transfer of UNQ from Astar', async () => {687 await genericReserveTransferUNQfrom('astar', alice);688 });689});1// 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 {IKeyringPair} from '@polkadot/types/types';18import config from '../config';19import {itSub, expect, describeXCM, usingPlaygrounds, usingAcalaPlaygrounds, usingMoonbeamPlaygrounds, usingAstarPlaygrounds, usingPolkadexPlaygrounds} from '../util';20import {Event} from '../util/playgrounds/unique.dev';21import {nToBigInt} from '@polkadot/util';22import {hexToString} from '@polkadot/util';23import {ASTAR_DECIMALS, NETWORKS, SAFE_XCM_VERSION, UNIQUE_CHAIN, UNQ_DECIMALS, acalaUrl, astarUrl, expectFailedToTransact, expectUntrustedReserveLocationFail, getDevPlayground, mapToChainId, mapToChainUrl, maxWaitBlocks, moonbeamUrl, polkadexUrl, uniqueAssetId, uniqueVersionedMultilocation} from './xcm.types';242526const TRANSFER_AMOUNT = 2000000_000_000_000_000_000_000n;27const SENDER_BUDGET = 2n * TRANSFER_AMOUNT;28const SENDBACK_AMOUNT = TRANSFER_AMOUNT / 2n;29const STAYED_ON_TARGET_CHAIN = TRANSFER_AMOUNT - SENDBACK_AMOUNT;30const TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT = 100_000_000_000n;3132let balanceUniqueTokenInit: bigint;33let balanceUniqueTokenMiddle: bigint;34let balanceUniqueTokenFinal: bigint;35let unqFees: bigint;363738async function genericSendUnqTo(39 networkName: keyof typeof NETWORKS,40 randomAccount: IKeyringPair,41 randomAccountOnTargetChain = randomAccount,42) {43 const networkUrl = mapToChainUrl(networkName);44 const targetPlayground = getDevPlayground(networkName);45 await usingPlaygrounds(async (helper) => {46 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);47 const destination = {48 V2: {49 parents: 1,50 interior: {51 X1: {52 Parachain: mapToChainId(networkName),53 },54 },55 },56 };5758 const beneficiary = {59 V2: {60 parents: 0,61 interior: {62 X1: (63 networkName == 'moonbeam' ?64 {65 AccountKey20: {66 network: 'Any',67 key: randomAccountOnTargetChain.address,68 },69 }70 :71 {72 AccountId32: {73 network: 'Any',74 id: randomAccountOnTargetChain.addressRaw,75 },76 }77 ),78 },79 },80 };8182 const assets = {83 V2: [84 {85 id: {86 Concrete: {87 parents: 0,88 interior: 'Here',89 },90 },91 fun: {92 Fungible: TRANSFER_AMOUNT,93 },94 },95 ],96 };97 const feeAssetItem = 0;9899 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, 'Unlimited');100 const messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);101 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);102103 unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;104 console.log('[Unique -> %s] transaction fees on Unique: %s UNQ', networkName, helper.util.bigIntToDecimals(unqFees));105 expect(unqFees > 0n, 'Negative fees UNQ, looks like nothing was transferred').to.be.true;106107 await targetPlayground(networkUrl, async (helper) => {108 /*109 Since only the parachain part of the Polkadex110 infrastructure is launched (without their111 solochain validators), processing incoming112 assets will lead to an error.113 This error indicates that the Polkadex chain114 received a message from the Unique network,115 since the hash is being checked to ensure116 it matches what was sent.117 */118 if(networkName == 'polkadex') {119 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Fail, event => event.messageHash == messageSent.messageHash);120 } else {121 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == messageSent.messageHash);122 }123 });124125 });126}127128async function genericSendUnqBack(129 networkName: keyof typeof NETWORKS,130 sudoer: IKeyringPair,131 randomAccountOnUnq: IKeyringPair,132) {133 const networkUrl = mapToChainUrl(networkName);134135 const targetPlayground = getDevPlayground(networkName);136 await usingPlaygrounds(async (helper) => {137138 const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(139 randomAccountOnUnq.addressRaw,140 uniqueAssetId,141 SENDBACK_AMOUNT,142 );143144 let xcmProgramSent: any;145146147 await targetPlayground(networkUrl, async (helper) => {148 if('getSudo' in helper) {149 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, xcmProgram);150 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);151 } else if('fastDemocracy' in helper) {152 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, xcmProgram]);153 // Needed to bypass the call filter.154 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);155 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);156 xcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);157 }158 });159160 await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.Success, event => event.messageHash == xcmProgramSent.messageHash);161162 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountOnUnq.address);163164 expect(balanceUniqueTokenFinal).to.be.equal(balanceUniqueTokenInit - unqFees - STAYED_ON_TARGET_CHAIN);165166 });167}168169async function genericSendOnlyOwnedBalance(170 networkName: keyof typeof NETWORKS,171 sudoer: IKeyringPair,172) {173 const networkUrl = mapToChainUrl(networkName);174 const targetPlayground = getDevPlayground(networkName);175176 const targetChainBalance = 10000n * (10n ** UNQ_DECIMALS);177178 await usingPlaygrounds(async (helper) => {179 const targetChainSovereignAccount = helper.address.paraSiblingSovereignAccount(mapToChainId(networkName));180 await helper.getSudo().balance.setBalanceSubstrate(sudoer, targetChainSovereignAccount, targetChainBalance);181 const moreThanTargetChainHas = 2n * targetChainBalance;182183 const targetAccount = helper.arrange.createEmptyAccount();184185 const maliciousXcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(186 targetAccount.addressRaw,187 {188 Concrete: {189 parents: 0,190 interior: 'Here',191 },192 },193 moreThanTargetChainHas,194 );195196 let maliciousXcmProgramSent: any;197198199 await targetPlayground(networkUrl, async (helper) => {200 if('getSudo' in helper) {201 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgram);202 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);203 } else if('fastDemocracy' in helper) {204 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgram]);205 // Needed to bypass the call filter.206 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);207 await helper.fastDemocracy.executeProposal(`sending ${networkName} -> Unique via XCM program`, batchCall);208 maliciousXcmProgramSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);209 }210 });211212 await expectFailedToTransact(helper, maliciousXcmProgramSent);213214 const targetAccountBalance = await helper.balance.getSubstrate(targetAccount.address);215 expect(targetAccountBalance).to.be.equal(0n);216 });217}218219async function genericReserveTransferUNQfrom(netwokrName: keyof typeof NETWORKS, sudoer: IKeyringPair) {220 const networkUrl = mapToChainUrl(netwokrName);221 const targetPlayground = getDevPlayground(netwokrName);222223 await usingPlaygrounds(async (helper) => {224 const testAmount = 10_000n * (10n ** UNQ_DECIMALS);225 const targetAccount = helper.arrange.createEmptyAccount();226227 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(228 targetAccount.addressRaw,229 uniqueAssetId,230 testAmount,231 );232233 const maliciousXcmProgramHereId = helper.arrange.makeXcmProgramReserveAssetDeposited(234 targetAccount.addressRaw,235 {236 Concrete: {237 parents: 0,238 interior: 'Here',239 },240 },241 testAmount,242 );243244 let maliciousXcmProgramFullIdSent: any;245 let maliciousXcmProgramHereIdSent: any;246 const maxWaitBlocks = 3;247248 // Try to trick Unique using full UNQ identification249 await targetPlayground(networkUrl, async (helper) => {250 if('getSudo' in helper) {251 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramFullId);252 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);253 }254 // Moonbeam case255 else if('fastDemocracy' in helper) {256 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);257 // Needed to bypass the call filter.258 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);259 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using path asset identification`,batchCall);260261 maliciousXcmProgramFullIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);262 }263 });264265266 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramFullIdSent);267268 let accountBalance = await helper.balance.getSubstrate(targetAccount.address);269 expect(accountBalance).to.be.equal(0n);270271 // Try to trick Unique using shortened UNQ identification272 await targetPlayground(networkUrl, async (helper) => {273 if('getSudo' in helper) {274 await helper.getSudo().xcm.send(sudoer, uniqueVersionedMultilocation, maliciousXcmProgramHereId);275 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);276 }277 else if('fastDemocracy' in helper) {278 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramHereId]);279 // Needed to bypass the call filter.280 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);281 await helper.fastDemocracy.executeProposal(`${netwokrName} try to act like a reserve location for UNQ using "here" asset identification`, batchCall);282283 maliciousXcmProgramHereIdSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);284 }285 });286287 await expectUntrustedReserveLocationFail(helper, maliciousXcmProgramHereIdSent);288289 accountBalance = await helper.balance.getSubstrate(targetAccount.address);290 expect(accountBalance).to.be.equal(0n);291 });292}293294async function genericRejectNativeToknsFrom(networkName: keyof typeof NETWORKS, sudoerOnTargetChain: IKeyringPair) {295 const networkUrl = mapToChainUrl(networkName);296 const targetPlayground = getDevPlayground(networkName);297 let messageSent: any;298299 await usingPlaygrounds(async (helper) => {300 const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(301 helper.arrange.createEmptyAccount().addressRaw,302 {303 Concrete: {304 parents: 1,305 interior: {306 X1: {307 Parachain: mapToChainId(networkName),308 },309 },310 },311 },312 TARGET_CHAIN_TOKEN_TRANSFER_AMOUNT,313 );314 await targetPlayground(networkUrl, async (helper) => {315 if('getSudo' in helper) {316 await helper.getSudo().xcm.send(sudoerOnTargetChain, uniqueVersionedMultilocation, maliciousXcmProgramFullId);317 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);318 } else if('fastDemocracy' in helper) {319 const xcmSend = helper.constructApiCall('api.tx.polkadotXcm.send', [uniqueVersionedMultilocation, maliciousXcmProgramFullId]);320 // Needed to bypass the call filter.321 const batchCall = helper.encodeApiCall('api.tx.utility.batch', [[xcmSend]]);322 await helper.fastDemocracy.executeProposal(`${networkName} sending native tokens to the Unique via fast democracy`, batchCall);323324 messageSent = await helper.wait.expectEvent(maxWaitBlocks, Event.XcmpQueue.XcmpMessageSent);325 }326 });327 await expectFailedToTransact(helper, messageSent);328 });329}330331332describeXCM('[XCMLL] Integration test: Exchanging tokens with Acala', () => {333 let alice: IKeyringPair;334 let randomAccount: IKeyringPair;335336 before(async () => {337 await usingPlaygrounds(async (helper, privateKey) => {338 alice = await privateKey('//Alice');339 console.log(config.acalaUrl);340 randomAccount = helper.arrange.createEmptyAccount();341342 // Set the default version to wrap the first message to other chains.343 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);344 });345346 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {347 const destination = {348 V2: {349 parents: 1,350 interior: {351 X1: {352 Parachain: UNIQUE_CHAIN,353 },354 },355 },356 };357358 const metadata = {359 name: 'Unique Network',360 symbol: 'UNQ',361 decimals: 18,362 minimalBalance: 1250_000_000_000_000_000n,363 };364 const assets = (await (helper.callRpc('api.query.assetRegistry.assetMetadatas.entries'))).map(([_k, v] : [any, any]) =>365 hexToString(v.toJSON()['symbol'])) as string[];366367 if(!assets.includes('UNQ')) {368 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);369 } else {370 console.log('UNQ token already registered on Acala assetRegistry pallet');371 }372 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);373 });374375 await usingPlaygrounds(async (helper) => {376 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);377 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);378 });379 });380381 itSub('Should connect and send UNQ to Acala', async () => {382 await genericSendUnqTo('acala', randomAccount);383 });384385 itSub('Should connect to Acala and send UNQ back', async () => {386 await genericSendUnqBack('acala', alice, randomAccount);387 });388389 itSub('Acala can send only up to its balance', async () => {390 await genericSendOnlyOwnedBalance('acala', alice);391 });392393 itSub('Should not accept reserve transfer of UNQ from Acala', async () => {394 await genericReserveTransferUNQfrom('acala', alice);395 });396});397398describeXCM('[XCMLL] Integration test: Exchanging tokens with Polkadex', () => {399 let alice: IKeyringPair;400 let randomAccount: IKeyringPair;401402 before(async () => {403 await usingPlaygrounds(async (helper, privateKey) => {404 alice = await privateKey('//Alice');405 randomAccount = helper.arrange.createEmptyAccount();406407 // Set the default version to wrap the first message to other chains.408 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);409 });410411 await usingPolkadexPlaygrounds(polkadexUrl, async (helper) => {412 const isWhitelisted = ((await helper.callRpc('api.query.xcmHelper.whitelistedTokens', []))413 .toJSON() as [])414 .map(nToBigInt).length != 0;415 /*416 Check whether the Unique token has been added417 to the whitelist, since an error will occur418 if it is added again. Needed for debugging419 when this test is run multiple times.420 */421 if(isWhitelisted) {422 console.log('UNQ token is already whitelisted on Polkadex');423 } else {424 await helper.getSudo().xcmHelper.whitelistToken(alice, uniqueAssetId);425 }426427 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);428 });429430 await usingPlaygrounds(async (helper) => {431 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);432 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);433 });434 });435436 itSub('Should connect and send UNQ to Polkadex', async () => {437 await genericSendUnqTo('polkadex', randomAccount);438 });439440441 itSub('Should connect to Polkadex and send UNQ back', async () => {442 await genericSendUnqBack('polkadex', alice, randomAccount);443 });444445 itSub('Polkadex can send only up to its balance', async () => {446 await genericSendOnlyOwnedBalance('polkadex', alice);447 });448449 itSub('Should not accept reserve transfer of UNQ from Polkadex', async () => {450 await genericReserveTransferUNQfrom('polkadex', alice);451 });452});453454// These tests are relevant only when455// the the corresponding foreign assets are not registered456describeXCM('[XCMLL] Integration test: Unique rejects non-native tokens', () => {457 let alice: IKeyringPair;458459 before(async () => {460 await usingPlaygrounds(async (helper, privateKey) => {461 alice = await privateKey('//Alice');462463 // Set the default version to wrap the first message to other chains.464 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);465 });466 });467468 itSub('Unique rejects ACA tokens from Acala', async () => {469 await genericRejectNativeToknsFrom('acala', alice);470 });471472 itSub('Unique rejects GLMR tokens from Moonbeam', async () => {473 await genericRejectNativeToknsFrom('moonbeam', alice);474 });475476 itSub('Unique rejects ASTR tokens from Astar', async () => {477 await genericRejectNativeToknsFrom('astar', alice);478 });479480 itSub('Unique rejects PDX tokens from Polkadex', async () => {481 await genericRejectNativeToknsFrom('polkadex', alice);482 });483});484485describeXCM('[XCMLL] Integration test: Exchanging UNQ with Moonbeam', () => {486 // Unique constants487 let alice: IKeyringPair;488 let uniqueAssetLocation;489490 let randomAccountUnique: IKeyringPair;491 let randomAccountMoonbeam: IKeyringPair;492493 // Moonbeam constants494 let assetId: string;495496 const uniqueAssetMetadata = {497 name: 'xcUnique',498 symbol: 'xcUNQ',499 decimals: 18,500 isFrozen: false,501 minimalBalance: 1n,502 };503504505 before(async () => {506 await usingPlaygrounds(async (helper, privateKey) => {507 alice = await privateKey('//Alice');508 [randomAccountUnique] = await helper.arrange.createAccounts([0n], alice);509510511 // Set the default version to wrap the first message to other chains.512 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);513 });514515 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {516 const alithAccount = helper.account.alithAccount();517 const baltatharAccount = helper.account.baltatharAccount();518 const dorothyAccount = helper.account.dorothyAccount();519520 randomAccountMoonbeam = helper.account.create();521522 // >>> Sponsoring Dorothy >>>523 console.log('Sponsoring Dorothy.......');524 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);525 console.log('Sponsoring Dorothy.......DONE');526 // <<< Sponsoring Dorothy <<<527 uniqueAssetLocation = {528 XCM: {529 parents: 1,530 interior: {X1: {Parachain: UNIQUE_CHAIN}},531 },532 };533 const existentialDeposit = 1n;534 const isSufficient = true;535 const unitsPerSecond = 1n;536 const numAssetsWeightHint = 0;537538 if((await helper.assetManager.assetTypeId(uniqueAssetLocation)).toJSON()) {539 console.log('Unique asset already registered on Moonbeam');540 } else {541 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({542 location: uniqueAssetLocation,543 metadata: uniqueAssetMetadata,544 existentialDeposit,545 isSufficient,546 unitsPerSecond,547 numAssetsWeightHint,548 });549550 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);551552 await helper.fastDemocracy.executeProposal('register UNQ foreign asset', encodedProposal);553 }554555 // >>> Acquire Unique AssetId Info on Moonbeam >>>556 console.log('Acquire Unique AssetId Info on Moonbeam.......');557558 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();559560 console.log('UNQ asset ID is %s', assetId);561 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');562563 // >>> Sponsoring random Account >>>564 console.log('Sponsoring random Account.......');565 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);566 console.log('Sponsoring random Account.......DONE');567 // <<< Sponsoring random Account <<<568 });569570 await usingPlaygrounds(async (helper) => {571 await helper.balance.transferToSubstrate(alice, randomAccountUnique.address, SENDER_BUDGET);572 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);573 });574 });575576 itSub('Should connect and send UNQ to Moonbeam', async () => {577 await genericSendUnqTo('moonbeam', randomAccountUnique, randomAccountMoonbeam);578 });579580 itSub('Should connect to Moonbeam and send UNQ back', async () => {581 await genericSendUnqBack('moonbeam', alice, randomAccountUnique);582 });583584 itSub('Moonbeam can send only up to its balance', async () => {585 await genericSendOnlyOwnedBalance('moonbeam', alice);586 });587588 itSub('Should not accept reserve transfer of UNQ from Moonbeam', async () => {589 await genericReserveTransferUNQfrom('moonbeam', alice);590 });591});592593describeXCM('[XCMLL] Integration test: Exchanging tokens with Astar', () => {594 let alice: IKeyringPair;595 let randomAccount: IKeyringPair;596597 const UNQ_ASSET_ID_ON_ASTAR = 1;598 const UNQ_MINIMAL_BALANCE_ON_ASTAR = 1n;599600 // Unique -> Astar601 const astarInitialBalance = 1n * (10n ** ASTAR_DECIMALS); // 1 ASTR, existential deposit required to actually create the account on Astar.602 const unitsPerSecond = 228_000_000_000n; // This is Phala's value. What will be ours?603604 before(async () => {605 await usingPlaygrounds(async (helper, privateKey) => {606 alice = await privateKey('//Alice');607 randomAccount = helper.arrange.createEmptyAccount();608 await helper.balance.transferToSubstrate(alice, randomAccount.address, SENDER_BUDGET);609 console.log('randomAccount', randomAccount.address);610611 // Set the default version to wrap the first message to other chains.612 await helper.getSudo().xcm.setSafeXcmVersion(alice, SAFE_XCM_VERSION);613 });614615 await usingAstarPlaygrounds(astarUrl, async (helper) => {616 if(!(await helper.callRpc('api.query.assets.asset', [UNQ_ASSET_ID_ON_ASTAR])).toJSON()) {617 console.log('1. Create foreign asset and metadata');618 // TODO update metadata with values from production619 await helper.assets.create(620 alice,621 UNQ_ASSET_ID_ON_ASTAR,622 alice.address,623 UNQ_MINIMAL_BALANCE_ON_ASTAR,624 );625626 await helper.assets.setMetadata(627 alice,628 UNQ_ASSET_ID_ON_ASTAR,629 'Cross chain UNQ',630 'xcUNQ',631 Number(UNQ_DECIMALS),632 );633634 console.log('2. Register asset location on Astar');635 const assetLocation = {636 V2: {637 parents: 1,638 interior: {639 X1: {640 Parachain: UNIQUE_CHAIN,641 },642 },643 },644 };645646 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.registerAssetLocation', [assetLocation, UNQ_ASSET_ID_ON_ASTAR]);647648 console.log('3. Set UNQ payment for XCM execution on Astar');649 await helper.getSudo().executeExtrinsic(alice, 'api.tx.xcAssetConfig.setAssetUnitsPerSecond', [assetLocation, unitsPerSecond]);650 } else {651 console.log('UNQ is already registered on Astar');652 }653 console.log('4. Transfer 1 ASTR to recipient to create the account (needed due to existential balance)');654 await helper.balance.transferToSubstrate(alice, randomAccount.address, astarInitialBalance);655 });656 });657658 itSub('Should connect and send UNQ to Astar', async () => {659 await genericSendUnqTo('astar', randomAccount);660 });661662 itSub('Should connect to Astar and send UNQ back', async () => {663 await genericSendUnqBack('astar', alice, randomAccount);664 });665666 itSub('Astar can send only up to its balance', async () => {667 await genericSendOnlyOwnedBalance('astar', alice);668 });669670 itSub('Should not accept reserve transfer of UNQ from Astar', async () => {671 await genericReserveTransferUNQfrom('astar', alice);672 });673});tests/src/xcm/xcmUnique.test.tsdiffbeforeafterboth--- a/tests/src/xcm/xcmUnique.test.ts
+++ b/tests/src/xcm/xcmUnique.test.ts
@@ -728,16 +728,7 @@
const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- },
+ uniqueAssetId,
testAmount,
);
@@ -900,14 +891,7 @@
const xcmProgram = helper.arrange.makeXcmProgramWithdrawDeposit(
randomAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {Parachain: UNIQUE_CHAIN},
- },
- },
- },
+ uniqueAssetId,
TRANSFER_AMOUNT,
);
@@ -978,16 +962,7 @@
const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- },
+ uniqueAssetId,
testAmount,
);
@@ -1477,16 +1452,7 @@
const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
targetAccount.addressRaw,
- {
- Concrete: {
- parents: 0,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- },
+ uniqueAssetId,
testAmount,
);
@@ -1821,16 +1787,7 @@
const maliciousXcmProgramFullId = helper.arrange.makeXcmProgramReserveAssetDeposited(
targetAccount.addressRaw,
- {
- Concrete: {
- parents: 1,
- interior: {
- X1: {
- Parachain: UNIQUE_CHAIN,
- },
- },
- },
- },
+ uniqueAssetId,
testAmount,
);