difftreelog
fix remove deprecated helpers from unique xcm test
in: master
1 file changed
tests/src/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 {Keyring} from '@polkadot/api';18import {IKeyringPair} from '@polkadot/types/types';19import {generateKeyringPair, bigIntToDecimals} from '../deprecated-helpers/helpers';20import {blake2AsHex} from '@polkadot/util-crypto';21import {XcmV2TraitsError, XcmV2TraitsOutcome} from '../interfaces';22import {itSub, expect, describeXcm, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds} from '../util/playgrounds';2324const UNIQUE_CHAIN = 2037;25const ACALA_CHAIN = 2000;26const MOONBEAM_CHAIN = 2004;2728const RELAY_PORT = 9844;29const ACALA_PORT = 9946;30const MOONBEAM_PORT = 9947;3132const relayUrl = 'ws://127.0.0.1:' + RELAY_PORT;33const acalaUrl = 'ws://127.0.0.1:' + ACALA_PORT;34const moonbeamUrl = 'ws://127.0.0.1:' + MOONBEAM_PORT;3536const ACALA_DECIMALS = 12;3738const TRANSFER_AMOUNT = 2000000000000000000000000n;3940describeXcm('[XCM] Integration test: Exchanging tokens with Acala', () => {41 let alice: IKeyringPair;42 let randomAccount: IKeyringPair;4344 let balanceUniqueTokenInit: bigint;45 let balanceUniqueTokenMiddle: bigint;46 let balanceUniqueTokenFinal: bigint;47 let balanceAcalaTokenInit: bigint;48 let balanceAcalaTokenMiddle: bigint;49 let balanceAcalaTokenFinal: bigint;50 let balanceUniqueForeignTokenInit: bigint;51 let balanceUniqueForeignTokenMiddle: bigint;52 let balanceUniqueForeignTokenFinal: bigint;5354 before(async () => {55 await usingPlaygrounds(async (_helper, privateKey) => {56 const keyringSr25519 = new Keyring({type: 'sr25519'});5758 alice = privateKey('//Alice');59 randomAccount = generateKeyringPair(keyringSr25519);60 });6162 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {63 const destination = {64 V0: {65 X2: [66 'Parent',67 {68 Parachain: UNIQUE_CHAIN,69 },70 ],71 },72 };7374 const metadata = {75 name: 'UNQ',76 symbol: 'UNQ',77 decimals: 18,78 minimalBalance: 1n,79 };8081 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);82 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);83 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);84 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});85 });8687 await usingPlaygrounds(async (helper) => {88 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);89 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);90 });91 });9293 itSub('Should connect and send UNQ to Acala', async ({helper}) => {9495 const destination = {96 V0: {97 X2: [98 'Parent',99 {100 Parachain: ACALA_CHAIN,101 },102 ],103 },104 };105106 const beneficiary = {107 V0: {108 X1: {109 AccountId32: {110 network: 'Any',111 id: randomAccount.addressRaw,112 },113 },114 },115 };116117 const assets = {118 V1: [119 {120 id: {121 Concrete: {122 parents: 0,123 interior: 'Here',124 },125 },126 fun: {127 Fungible: TRANSFER_AMOUNT,128 },129 },130 ],131 };132133 const feeAssetItem = 0;134 const weightLimit = 5000000000;135136 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);137138 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);139140 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;141 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', bigIntToDecimals(unqFees));142 expect(unqFees > 0n).to.be.true;143144 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {145 await helper.wait.newBlocks(3);146147 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});148 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);149150 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;151 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;152153 console.log(154 '[Unique -> Acala] transaction fees on Acala: %s ACA',155 bigIntToDecimals(acaFees, ACALA_DECIMALS),156 );157 console.log('[Unique -> Acala] income %s UNQ', bigIntToDecimals(unqIncomeTransfer));158 expect(acaFees == 0n).to.be.true;159 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;160 });161 });162163 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {164 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {165 const destination = {166 V1: {167 parents: 1,168 interior: {169 X2: [170 {Parachain: UNIQUE_CHAIN},171 {172 AccountId32: {173 network: 'Any',174 id: randomAccount.addressRaw,175 },176 },177 ],178 },179 },180 };181182 const id = {183 ForeignAsset: 0,184 };185186 const destWeight = 50000000;187188 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);189190 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);191 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);192193 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;194 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;195196 console.log(197 '[Acala -> Unique] transaction fees on Acala: %s ACA',198 bigIntToDecimals(acaFees, ACALA_DECIMALS),199 );200 console.log('[Acala -> Unique] outcome %s UNQ', bigIntToDecimals(unqOutcomeTransfer));201202 expect(acaFees > 0).to.be.true;203 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;204 });205206 await helper.wait.newBlocks(3);207208 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);209 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;210 expect(actuallyDelivered > 0).to.be.true;211212 console.log('[Acala -> Unique] actually delivered %s UNQ', bigIntToDecimals(actuallyDelivered));213214 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;215 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', bigIntToDecimals(unqFees));216 expect(unqFees == 0n).to.be.true;217 });218});219220// These tests are relevant only when the foreign asset pallet is disabled221describeXcm('[XCM] Integration test: Unique rejects non-native tokens', () => {222 let alice: IKeyringPair;223224 before(async () => {225 await usingPlaygrounds(async (_helper, privateKey) => {226 alice = privateKey('//Alice');227 });228 });229230 itSub('Unique rejects tokens from the Relay', async ({helper}) => {231 await usingRelayPlaygrounds(relayUrl, async (helper) => {232 const destination = {233 V1: {234 parents: 0,235 interior: {X1: {236 Parachain: UNIQUE_CHAIN,237 },238 },239 }};240241 const beneficiary = {242 V1: {243 parents: 0,244 interior: {X1: {245 AccountId32: {246 network: 'Any',247 id: alice.addressRaw,248 },249 }},250 },251 };252253 const assets = {254 V1: [255 {256 id: {257 Concrete: {258 parents: 0,259 interior: 'Here',260 },261 },262 fun: {263 Fungible: 50_000_000_000_000_000n,264 },265 },266 ],267 };268269 const feeAssetItem = 0;270 const weightLimit = 5_000_000_000;271272 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);273 });274275 const maxWaitBlocks = 3;276277 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');278279 expect(280 dmpQueueExecutedDownward != null,281 '[Relay] dmpQueue.ExecutedDownward event is expected',282 ).to.be.true;283284 const event = dmpQueueExecutedDownward!.event;285 const outcome = event.data[1] as XcmV2TraitsOutcome;286287 expect(288 outcome.isIncomplete,289 '[Relay] The outcome of the XCM should be `Incomplete`',290 ).to.be.true;291292 const incomplete = outcome.asIncomplete;293 expect(294 incomplete[1].toString() == 'AssetNotFound',295 '[Relay] The XCM error should be `AssetNotFound`',296 ).to.be.true;297 });298299 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {300 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {301 const destination = {302 V1: {303 parents: 1,304 interior: {305 X2: [306 {Parachain: UNIQUE_CHAIN},307 {308 AccountId32: {309 network: 'Any',310 id: alice.addressRaw,311 },312 },313 ],314 },315 },316 };317318 const id = {319 Token: 'ACA',320 };321322 const destWeight = 50000000;323324 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);325 });326327 const maxWaitBlocks = 3;328329 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');330331 expect(332 xcmpQueueFailEvent != null,333 '[Acala] xcmpQueue.FailEvent event is expected',334 ).to.be.true;335336 const event = xcmpQueueFailEvent!.event;337 const outcome = event.data[1] as XcmV2TraitsError;338339 expect(340 outcome.isUntrustedReserveLocation,341 '[Acala] The XCM error should be `UntrustedReserveLocation`',342 ).to.be.true;343 });344});345346describe.only('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {347348 // Unique constants349 let uniqueAlice: IKeyringPair;350 let uniqueAssetLocation;351352 let randomAccountUnique: IKeyringPair;353 let randomAccountMoonbeam: IKeyringPair;354355 // Moonbeam constants356 let assetId: string;357358 const moonbeamKeyring = new Keyring({type: 'ethereum'});359 const alithPrivateKey = '0x5fb92d6e98884f76de468fa3f6278f8807c48bebc13595d45af5bdc4da702133';360 const baltatharPrivateKey = '0x8075991ce870b93a8870eca0c0f91913d12f47948ca0fd25b49c6fa7cdbeee8b';361 const dorothyPrivateKey = '0x39539ab1876910bbf3a223d84a29e28f1cb4e2e456503e7e91ed39b2e7223d68';362363 const alithAccount = moonbeamKeyring.addFromUri(alithPrivateKey, undefined, 'ethereum');364 const baltatharAccount = moonbeamKeyring.addFromUri(baltatharPrivateKey, undefined, 'ethereum');365 const dorothyAccount = moonbeamKeyring.addFromUri(dorothyPrivateKey, undefined, 'ethereum');366367 const councilVotingThreshold = 2;368 const technicalCommitteeThreshold = 2;369 const votingPeriod = 3;370 const delayPeriod = 0;371372 const uniqueAssetMetadata = {373 name: 'xcUnique',374 symbol: 'xcUNQ',375 decimals: 18,376 isFrozen: false,377 minimalBalance: 1n,378 };379380 let balanceUniqueTokenInit: bigint;381 let balanceUniqueTokenMiddle: bigint;382 let balanceUniqueTokenFinal: bigint;383 let balanceForeignUnqTokenInit: bigint;384 let balanceForeignUnqTokenMiddle: bigint;385 let balanceForeignUnqTokenFinal: bigint;386 let balanceGlmrTokenInit: bigint;387 let balanceGlmrTokenMiddle: bigint;388 let balanceGlmrTokenFinal: bigint;389390 before(async () => {391 await usingPlaygrounds(async (_helper, privateKey) => {392 const keyringEth = new Keyring({type: 'ethereum'});393 const keyringSr25519 = new Keyring({type: 'sr25519'});394395 uniqueAlice = privateKey('//Alice');396 randomAccountUnique = generateKeyringPair(keyringSr25519);397 randomAccountMoonbeam = generateKeyringPair(keyringEth);398399 balanceForeignUnqTokenInit = 0n;400 });401402 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {403 // >>> Sponsoring Dorothy >>>404 console.log('Sponsoring Dorothy.......');405 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);406 console.log('Sponsoring Dorothy.......DONE');407 // <<< Sponsoring Dorothy <<<408409 uniqueAssetLocation = {410 XCM: {411 parents: 1,412 interior: {X1: {Parachain: UNIQUE_CHAIN}},413 },414 };415 const existentialDeposit = 1n;416 const isSufficient = true;417 const unitsPerSecond = 1n;418 const numAssetsWeightHint = 0;419420 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({421 location: uniqueAssetLocation,422 metadata: uniqueAssetMetadata,423 existentialDeposit,424 isSufficient,425 unitsPerSecond,426 numAssetsWeightHint,427 });428 const proposalHash = blake2AsHex(encodedProposal);429430 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);431 console.log('Encoded length %d', encodedProposal.length);432 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);433434 // >>> Note motion preimage >>>435 console.log('Note motion preimage.......');436 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);437 console.log('Note motion preimage.......DONE');438 // <<< Note motion preimage <<<439440 // >>> Propose external motion through council >>>441 console.log('Propose external motion through council.......');442 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);443 const encodedMotion = externalMotion?.method.toHex() || '';444 const motionHash = blake2AsHex(encodedMotion);445 console.log('Motion hash is %s', motionHash);446447 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);448449 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;450 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);451 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);452453 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);454 console.log('Propose external motion through council.......DONE');455 // <<< Propose external motion through council <<<456457 // >>> Fast track proposal through technical committee >>>458 console.log('Fast track proposal through technical committee.......');459 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);460 const encodedFastTrack = fastTrack?.method.toHex() || '';461 const fastTrackHash = blake2AsHex(encodedFastTrack);462 console.log('FastTrack hash is %s', fastTrackHash);463464 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);465466 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;467 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);468 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);469470 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);471 console.log('Fast track proposal through technical committee.......DONE');472 // <<< Fast track proposal through technical committee <<<473474 // >>> Referendum voting >>>475 console.log('Referendum voting.......');476 await helper.democracy.referendumVote(dorothyAccount, 0, {477 balance: 10_000_000_000_000_000_000n,478 vote: {aye: true, conviction: 1},479 });480 console.log('Referendum voting.......DONE');481 // <<< Referendum voting <<<482483 // >>> Acquire Unique AssetId Info on Moonbeam >>>484 console.log('Acquire Unique AssetId Info on Moonbeam.......');485486 // Wait for the democracy execute487 await helper.wait.newBlocks(5);488489 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();490491 console.log('UNQ asset ID is %s', assetId);492 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');493 // >>> Acquire Unique AssetId Info on Moonbeam >>>494495 // >>> Sponsoring random Account >>>496 console.log('Sponsoring random Account.......');497 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);498 console.log('Sponsoring random Account.......DONE');499 // <<< Sponsoring random Account <<<500501 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);502 });503504 await usingPlaygrounds(async (helper) => {505 await helper.balance.transferToSubstrate(uniqueAlice, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);506 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);507 });508 });509510 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {511 const currencyId = {512 NativeAssetId: 'Here',513 };514 const dest = {515 V1: {516 parents: 1,517 interior: {518 X2: [519 {Parachain: MOONBEAM_CHAIN},520 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},521 ],522 },523 },524 };525 const amount = TRANSFER_AMOUNT;526 const destWeight = 850000000;527528 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, destWeight);529530 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);531 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;532533 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;534 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', bigIntToDecimals(transactionFees));535 expect(transactionFees > 0).to.be.true;536537 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {538 await helper.wait.newBlocks(3);539540 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);541542 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;543 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', bigIntToDecimals(glmrFees));544 expect(glmrFees == 0n).to.be.true;545546 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;547548 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;549 console.log('[Unique -> Moonbeam] income %s UNQ', bigIntToDecimals(unqIncomeTransfer));550 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;551 });552 });553554 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {555 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {556 const asset = {557 V1: {558 id: {559 Concrete: {560 parents: 1,561 interior: {562 X1: {Parachain: UNIQUE_CHAIN},563 },564 },565 },566 fun: {567 Fungible: TRANSFER_AMOUNT,568 },569 },570 };571 const destination = {572 V1: {573 parents: 1,574 interior: {575 X2: [576 {Parachain: UNIQUE_CHAIN},577 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},578 ],579 },580 },581 };582 const destWeight = 50000000;583584 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, destWeight);585586 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);587588 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;589 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', bigIntToDecimals(glmrFees));590 expect(glmrFees > 0).to.be.true;591592 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);593594 expect(unqRandomAccountAsset).to.be.null;595 596 balanceForeignUnqTokenFinal = 0n;597598 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;599 console.log('[Unique -> Moonbeam] outcome %s UNQ', bigIntToDecimals(unqOutcomeTransfer));600 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;601 });602603 await helper.wait.newBlocks(3);604605 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);606 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;607 expect(actuallyDelivered > 0).to.be.true;608609 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', bigIntToDecimals(actuallyDelivered));610611 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;612 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', bigIntToDecimals(unqFees));613 expect(unqFees == 0n).to.be.true;614 });615});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 {blake2AsHex} from '@polkadot/util-crypto';19import {XcmV2TraitsError, XcmV2TraitsOutcome} from '../interfaces';20import {itSub, expect, describeXcm, usingPlaygrounds, usingAcalaPlaygrounds, usingRelayPlaygrounds, usingMoonbeamPlaygrounds} from '../util/playgrounds';2122const UNIQUE_CHAIN = 2037;23const ACALA_CHAIN = 2000;24const MOONBEAM_CHAIN = 2004;2526const RELAY_PORT = 9844;27const ACALA_PORT = 9946;28const MOONBEAM_PORT = 9947;2930const relayUrl = 'ws://127.0.0.1:' + RELAY_PORT;31const acalaUrl = 'ws://127.0.0.1:' + ACALA_PORT;32const moonbeamUrl = 'ws://127.0.0.1:' + MOONBEAM_PORT;3334const ACALA_DECIMALS = 12;3536const TRANSFER_AMOUNT = 2000000000000000000000000n;3738describeXcm('[XCM] Integration test: Exchanging tokens with Acala', () => {39 let alice: IKeyringPair;40 let randomAccount: IKeyringPair;4142 let balanceUniqueTokenInit: bigint;43 let balanceUniqueTokenMiddle: bigint;44 let balanceUniqueTokenFinal: bigint;45 let balanceAcalaTokenInit: bigint;46 let balanceAcalaTokenMiddle: bigint;47 let balanceAcalaTokenFinal: bigint;48 let balanceUniqueForeignTokenInit: bigint;49 let balanceUniqueForeignTokenMiddle: bigint;50 let balanceUniqueForeignTokenFinal: bigint;5152 before(async () => {53 await usingPlaygrounds(async (helper, privateKey) => {54 alice = privateKey('//Alice');55 [randomAccount] = await helper.arrange.createAccounts([0n], alice);56 });5758 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {59 const destination = {60 V0: {61 X2: [62 'Parent',63 {64 Parachain: UNIQUE_CHAIN,65 },66 ],67 },68 };6970 const metadata = {71 name: 'UNQ',72 symbol: 'UNQ',73 decimals: 18,74 minimalBalance: 1n,75 };7677 await helper.getSudo().assetRegistry.registerForeignAsset(alice, destination, metadata);78 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10000000000000n);79 balanceAcalaTokenInit = await helper.balance.getSubstrate(randomAccount.address);80 balanceUniqueForeignTokenInit = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});81 });8283 await usingPlaygrounds(async (helper) => {84 await helper.balance.transferToSubstrate(alice, randomAccount.address, 10n * TRANSFER_AMOUNT);85 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccount.address);86 });87 });8889 itSub('Should connect and send UNQ to Acala', async ({helper}) => {9091 const destination = {92 V0: {93 X2: [94 'Parent',95 {96 Parachain: ACALA_CHAIN,97 },98 ],99 },100 };101102 const beneficiary = {103 V0: {104 X1: {105 AccountId32: {106 network: 'Any',107 id: randomAccount.addressRaw,108 },109 },110 },111 };112113 const assets = {114 V1: [115 {116 id: {117 Concrete: {118 parents: 0,119 interior: 'Here',120 },121 },122 fun: {123 Fungible: TRANSFER_AMOUNT,124 },125 },126 ],127 };128129 const feeAssetItem = 0;130 const weightLimit = 5000000000;131132 await helper.xcm.limitedReserveTransferAssets(randomAccount, destination, beneficiary, assets, feeAssetItem, weightLimit);133134 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);135136 const unqFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;137 console.log('[Unique -> Acala] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));138 expect(unqFees > 0n).to.be.true;139140 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {141 await helper.wait.newBlocks(3);142143 balanceUniqueForeignTokenMiddle = await helper.tokens.accounts(randomAccount.address, {ForeignAsset: 0});144 balanceAcalaTokenMiddle = await helper.balance.getSubstrate(randomAccount.address);145146 const acaFees = balanceAcalaTokenInit - balanceAcalaTokenMiddle;147 const unqIncomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenInit;148149 console.log(150 '[Unique -> Acala] transaction fees on Acala: %s ACA',151 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),152 );153 console.log('[Unique -> Acala] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));154 expect(acaFees == 0n).to.be.true;155 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;156 });157 });158159 itSub('Should connect to Acala and send UNQ back', async ({helper}) => {160 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {161 const destination = {162 V1: {163 parents: 1,164 interior: {165 X2: [166 {Parachain: UNIQUE_CHAIN},167 {168 AccountId32: {169 network: 'Any',170 id: randomAccount.addressRaw,171 },172 },173 ],174 },175 },176 };177178 const id = {179 ForeignAsset: 0,180 };181182 const destWeight = 50000000;183184 await helper.xTokens.transfer(randomAccount, id, TRANSFER_AMOUNT, destination, destWeight);185186 balanceAcalaTokenFinal = await helper.balance.getSubstrate(randomAccount.address);187 balanceUniqueForeignTokenFinal = await helper.tokens.accounts(randomAccount.address, id);188189 const acaFees = balanceAcalaTokenMiddle - balanceAcalaTokenFinal;190 const unqOutcomeTransfer = balanceUniqueForeignTokenMiddle - balanceUniqueForeignTokenFinal;191192 console.log(193 '[Acala -> Unique] transaction fees on Acala: %s ACA',194 helper.util.bigIntToDecimals(acaFees, ACALA_DECIMALS),195 );196 console.log('[Acala -> Unique] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));197198 expect(acaFees > 0).to.be.true;199 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;200 });201202 await helper.wait.newBlocks(3);203204 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccount.address);205 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;206 expect(actuallyDelivered > 0).to.be.true;207208 console.log('[Acala -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));209210 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;211 console.log('[Acala -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));212 expect(unqFees == 0n).to.be.true;213 });214});215216// These tests are relevant only when the foreign asset pallet is disabled217describeXcm('[XCM] Integration test: Unique rejects non-native tokens', () => {218 let alice: IKeyringPair;219220 before(async () => {221 await usingPlaygrounds(async (_helper, privateKey) => {222 alice = privateKey('//Alice');223 });224 });225226 itSub('Unique rejects tokens from the Relay', async ({helper}) => {227 await usingRelayPlaygrounds(relayUrl, async (helper) => {228 const destination = {229 V1: {230 parents: 0,231 interior: {X1: {232 Parachain: UNIQUE_CHAIN,233 },234 },235 }};236237 const beneficiary = {238 V1: {239 parents: 0,240 interior: {X1: {241 AccountId32: {242 network: 'Any',243 id: alice.addressRaw,244 },245 }},246 },247 };248249 const assets = {250 V1: [251 {252 id: {253 Concrete: {254 parents: 0,255 interior: 'Here',256 },257 },258 fun: {259 Fungible: 50_000_000_000_000_000n,260 },261 },262 ],263 };264265 const feeAssetItem = 0;266 const weightLimit = 5_000_000_000;267268 await helper.xcm.limitedReserveTransferAssets(alice, destination, beneficiary, assets, feeAssetItem, weightLimit);269 });270271 const maxWaitBlocks = 3;272273 const dmpQueueExecutedDownward = await helper.wait.event(maxWaitBlocks, 'dmpQueue', 'ExecutedDownward');274275 expect(276 dmpQueueExecutedDownward != null,277 '[Relay] dmpQueue.ExecutedDownward event is expected',278 ).to.be.true;279280 const event = dmpQueueExecutedDownward!.event;281 const outcome = event.data[1] as XcmV2TraitsOutcome;282283 expect(284 outcome.isIncomplete,285 '[Relay] The outcome of the XCM should be `Incomplete`',286 ).to.be.true;287288 const incomplete = outcome.asIncomplete;289 expect(290 incomplete[1].toString() == 'AssetNotFound',291 '[Relay] The XCM error should be `AssetNotFound`',292 ).to.be.true;293 });294295 itSub('Unique rejects ACA tokens from Acala', async ({helper}) => {296 await usingAcalaPlaygrounds(acalaUrl, async (helper) => {297 const destination = {298 V1: {299 parents: 1,300 interior: {301 X2: [302 {Parachain: UNIQUE_CHAIN},303 {304 AccountId32: {305 network: 'Any',306 id: alice.addressRaw,307 },308 },309 ],310 },311 },312 };313314 const id = {315 Token: 'ACA',316 };317318 const destWeight = 50000000;319320 await helper.xTokens.transfer(alice, id, 100_000_000_000n, destination, destWeight);321 });322323 const maxWaitBlocks = 3;324325 const xcmpQueueFailEvent = await helper.wait.event(maxWaitBlocks, 'xcmpQueue', 'Fail');326327 expect(328 xcmpQueueFailEvent != null,329 '[Acala] xcmpQueue.FailEvent event is expected',330 ).to.be.true;331332 const event = xcmpQueueFailEvent!.event;333 const outcome = event.data[1] as XcmV2TraitsError;334335 expect(336 outcome.isUntrustedReserveLocation,337 '[Acala] The XCM error should be `UntrustedReserveLocation`',338 ).to.be.true;339 });340});341342describeXcm('[XCM] Integration test: Exchanging UNQ with Moonbeam', () => {343344 // Unique constants345 let uniqueDonor: IKeyringPair;346 let uniqueAssetLocation;347348 let randomAccountUnique: IKeyringPair;349 let randomAccountMoonbeam: IKeyringPair;350351 // Moonbeam constants352 let assetId: string;353354 const councilVotingThreshold = 2;355 const technicalCommitteeThreshold = 2;356 const votingPeriod = 3;357 const delayPeriod = 0;358359 const uniqueAssetMetadata = {360 name: 'xcUnique',361 symbol: 'xcUNQ',362 decimals: 18,363 isFrozen: false,364 minimalBalance: 1n,365 };366367 let balanceUniqueTokenInit: bigint;368 let balanceUniqueTokenMiddle: bigint;369 let balanceUniqueTokenFinal: bigint;370 let balanceForeignUnqTokenInit: bigint;371 let balanceForeignUnqTokenMiddle: bigint;372 let balanceForeignUnqTokenFinal: bigint;373 let balanceGlmrTokenInit: bigint;374 let balanceGlmrTokenMiddle: bigint;375 let balanceGlmrTokenFinal: bigint;376377 before(async () => {378 await usingPlaygrounds(async (helper, privateKey) => {379 uniqueDonor = privateKey('//Alice');380 [randomAccountUnique] = await helper.arrange.createAccounts([0n], uniqueDonor);381382 balanceForeignUnqTokenInit = 0n;383 });384385 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {386 const alithAccount = helper.account.alithAccount();387 const baltatharAccount = helper.account.baltatharAccount();388 const dorothyAccount = helper.account.dorothyAccount();389390 randomAccountMoonbeam = helper.account.create();391392 // >>> Sponsoring Dorothy >>>393 console.log('Sponsoring Dorothy.......');394 await helper.balance.transferToEthereum(alithAccount, dorothyAccount.address, 11_000_000_000_000_000_000n);395 console.log('Sponsoring Dorothy.......DONE');396 // <<< Sponsoring Dorothy <<<397398 uniqueAssetLocation = {399 XCM: {400 parents: 1,401 interior: {X1: {Parachain: UNIQUE_CHAIN}},402 },403 };404 const existentialDeposit = 1n;405 const isSufficient = true;406 const unitsPerSecond = 1n;407 const numAssetsWeightHint = 0;408409 const encodedProposal = helper.assetManager.makeRegisterForeignAssetProposal({410 location: uniqueAssetLocation,411 metadata: uniqueAssetMetadata,412 existentialDeposit,413 isSufficient,414 unitsPerSecond,415 numAssetsWeightHint,416 });417 const proposalHash = blake2AsHex(encodedProposal);418419 console.log('Encoded proposal for registerForeignAsset & setAssetUnitsPerSecond is %s', encodedProposal);420 console.log('Encoded length %d', encodedProposal.length);421 console.log('Encoded proposal hash for batch utility after schedule is %s', proposalHash);422423 // >>> Note motion preimage >>>424 console.log('Note motion preimage.......');425 await helper.democracy.notePreimage(baltatharAccount, encodedProposal);426 console.log('Note motion preimage.......DONE');427 // <<< Note motion preimage <<<428429 // >>> Propose external motion through council >>>430 console.log('Propose external motion through council.......');431 const externalMotion = helper.democracy.externalProposeMajority(proposalHash);432 const encodedMotion = externalMotion?.method.toHex() || '';433 const motionHash = blake2AsHex(encodedMotion);434 console.log('Motion hash is %s', motionHash);435436 await helper.collective.council.propose(baltatharAccount, councilVotingThreshold, externalMotion, externalMotion.encodedLength);437438 const councilProposalIdx = await helper.collective.council.proposalCount() - 1;439 await helper.collective.council.vote(dorothyAccount, motionHash, councilProposalIdx, true);440 await helper.collective.council.vote(baltatharAccount, motionHash, councilProposalIdx, true);441442 await helper.collective.council.close(dorothyAccount, motionHash, councilProposalIdx, 1_000_000_000, externalMotion.encodedLength);443 console.log('Propose external motion through council.......DONE');444 // <<< Propose external motion through council <<<445446 // >>> Fast track proposal through technical committee >>>447 console.log('Fast track proposal through technical committee.......');448 const fastTrack = helper.democracy.fastTrack(proposalHash, votingPeriod, delayPeriod);449 const encodedFastTrack = fastTrack?.method.toHex() || '';450 const fastTrackHash = blake2AsHex(encodedFastTrack);451 console.log('FastTrack hash is %s', fastTrackHash);452453 await helper.collective.techCommittee.propose(alithAccount, technicalCommitteeThreshold, fastTrack, fastTrack.encodedLength);454455 const techProposalIdx = await helper.collective.techCommittee.proposalCount() - 1;456 await helper.collective.techCommittee.vote(baltatharAccount, fastTrackHash, techProposalIdx, true);457 await helper.collective.techCommittee.vote(alithAccount, fastTrackHash, techProposalIdx, true);458459 await helper.collective.techCommittee.close(baltatharAccount, fastTrackHash, techProposalIdx, 1_000_000_000, fastTrack.encodedLength);460 console.log('Fast track proposal through technical committee.......DONE');461 // <<< Fast track proposal through technical committee <<<462463 // >>> Referendum voting >>>464 console.log('Referendum voting.......');465 await helper.democracy.referendumVote(dorothyAccount, 0, {466 balance: 10_000_000_000_000_000_000n,467 vote: {aye: true, conviction: 1},468 });469 console.log('Referendum voting.......DONE');470 // <<< Referendum voting <<<471472 // >>> Acquire Unique AssetId Info on Moonbeam >>>473 console.log('Acquire Unique AssetId Info on Moonbeam.......');474475 // Wait for the democracy execute476 await helper.wait.newBlocks(5);477478 assetId = (await helper.assetManager.assetTypeId(uniqueAssetLocation)).toString();479480 console.log('UNQ asset ID is %s', assetId);481 console.log('Acquire Unique AssetId Info on Moonbeam.......DONE');482 // >>> Acquire Unique AssetId Info on Moonbeam >>>483484 // >>> Sponsoring random Account >>>485 console.log('Sponsoring random Account.......');486 await helper.balance.transferToEthereum(baltatharAccount, randomAccountMoonbeam.address, 11_000_000_000_000_000_000n);487 console.log('Sponsoring random Account.......DONE');488 // <<< Sponsoring random Account <<<489490 balanceGlmrTokenInit = await helper.balance.getEthereum(randomAccountMoonbeam.address);491 });492493 await usingPlaygrounds(async (helper) => {494 await helper.balance.transferToSubstrate(uniqueDonor, randomAccountUnique.address, 10n * TRANSFER_AMOUNT);495 balanceUniqueTokenInit = await helper.balance.getSubstrate(randomAccountUnique.address);496 });497 });498499 itSub('Should connect and send UNQ to Moonbeam', async ({helper}) => {500 const currencyId = {501 NativeAssetId: 'Here',502 };503 const dest = {504 V1: {505 parents: 1,506 interior: {507 X2: [508 {Parachain: MOONBEAM_CHAIN},509 {AccountKey20: {network: 'Any', key: randomAccountMoonbeam.address}},510 ],511 },512 },513 };514 const amount = TRANSFER_AMOUNT;515 const destWeight = 850000000;516517 await helper.xTokens.transfer(randomAccountUnique, currencyId, amount, dest, destWeight);518519 balanceUniqueTokenMiddle = await helper.balance.getSubstrate(randomAccountUnique.address);520 expect(balanceUniqueTokenMiddle < balanceUniqueTokenInit).to.be.true;521522 const transactionFees = balanceUniqueTokenInit - balanceUniqueTokenMiddle - TRANSFER_AMOUNT;523 console.log('[Unique -> Moonbeam] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(transactionFees));524 expect(transactionFees > 0).to.be.true;525526 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {527 await helper.wait.newBlocks(3);528529 balanceGlmrTokenMiddle = await helper.balance.getEthereum(randomAccountMoonbeam.address);530531 const glmrFees = balanceGlmrTokenInit - balanceGlmrTokenMiddle;532 console.log('[Unique -> Moonbeam] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));533 expect(glmrFees == 0n).to.be.true;534535 balanceForeignUnqTokenMiddle = (await helper.assets.account(assetId, randomAccountMoonbeam.address))!;536537 const unqIncomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenInit;538 console.log('[Unique -> Moonbeam] income %s UNQ', helper.util.bigIntToDecimals(unqIncomeTransfer));539 expect(unqIncomeTransfer == TRANSFER_AMOUNT).to.be.true;540 });541 });542543 itSub('Should connect to Moonbeam and send UNQ back', async ({helper}) => {544 await usingMoonbeamPlaygrounds(moonbeamUrl, async (helper) => {545 const asset = {546 V1: {547 id: {548 Concrete: {549 parents: 1,550 interior: {551 X1: {Parachain: UNIQUE_CHAIN},552 },553 },554 },555 fun: {556 Fungible: TRANSFER_AMOUNT,557 },558 },559 };560 const destination = {561 V1: {562 parents: 1,563 interior: {564 X2: [565 {Parachain: UNIQUE_CHAIN},566 {AccountId32: {network: 'Any', id: randomAccountUnique.addressRaw}},567 ],568 },569 },570 };571 const destWeight = 50000000;572573 await helper.xTokens.transferMultiasset(randomAccountMoonbeam, asset, destination, destWeight);574575 balanceGlmrTokenFinal = await helper.balance.getEthereum(randomAccountMoonbeam.address);576577 const glmrFees = balanceGlmrTokenMiddle - balanceGlmrTokenFinal;578 console.log('[Moonbeam -> Unique] transaction fees on Moonbeam: %s GLMR', helper.util.bigIntToDecimals(glmrFees));579 expect(glmrFees > 0).to.be.true;580581 const unqRandomAccountAsset = await helper.assets.account(assetId, randomAccountMoonbeam.address);582583 expect(unqRandomAccountAsset).to.be.null;584 585 balanceForeignUnqTokenFinal = 0n;586587 const unqOutcomeTransfer = balanceForeignUnqTokenMiddle - balanceForeignUnqTokenFinal;588 console.log('[Unique -> Moonbeam] outcome %s UNQ', helper.util.bigIntToDecimals(unqOutcomeTransfer));589 expect(unqOutcomeTransfer == TRANSFER_AMOUNT).to.be.true;590 });591592 await helper.wait.newBlocks(3);593594 balanceUniqueTokenFinal = await helper.balance.getSubstrate(randomAccountUnique.address);595 const actuallyDelivered = balanceUniqueTokenFinal - balanceUniqueTokenMiddle;596 expect(actuallyDelivered > 0).to.be.true;597598 console.log('[Moonbeam -> Unique] actually delivered %s UNQ', helper.util.bigIntToDecimals(actuallyDelivered));599600 const unqFees = TRANSFER_AMOUNT - actuallyDelivered;601 console.log('[Moonbeam -> Unique] transaction fees on Unique: %s UNQ', helper.util.bigIntToDecimals(unqFees));602 expect(unqFees == 0n).to.be.true;603 });604});